Writing One Shell script to first enter nix shell, then enter the python virtual environment
Asked Answered
E

2

5

I want to schedule a job from wsl. The job will need to be run in the nix-shell and then in the python virtual environment under Nix-shell. I try to do this by writing a shell script, run ./enter.sh.

#!/bin/bash
nix-shell -p python38Full python38Packages.virtualenv;
source .venv/bin/activate

However, it doesn't enter the

(virt)
[nix-shell:xxx] 

after I run ./enter.sh. I need to first run the first line, then run the second line separately. It would be super helpful if someone knows a way to write a shell script that can do these two steps by running one script.

Ellmyer answered 29/10, 2020 at 20:29 Comment(0)
H
5

Shell scripts are a bit different from interactive sessions in the terminal.

When you run nix-shell in your terminal, the original shell process creates a nix-shell process and lets it read your input until nix-shell exits, returning control to the original shell.

In a shell script on the other hand, the shell will read all lines by itself and will not delegate the processing of the shell script to other executables like nix-shell. *

If you want to run all commands in the nix-shell, you can use a special shebang at the top of the file. For example:

#!/usr/bin/env nix-shell
#!nix-shell -p python38Full -p python38Packages.virtualenv
#!nix-shell -i bash
source .venv/bin/activate

# insert commands to be run here

/usr/bin/env is just a helper to look up nix-shell without an absolute path. nix-shell is run as a script interpreter that will parse #!nix-shell lines for its own options. The -i bash option tells it to invoke bash as the actual interpreter for this script. bash ignores the shebang and #!nix-shell lines, because they're comments. nix-shell has set the right environment variables in advance. It continues to source the activate file.

You might want to generate the activate script before running source, but I suppose that depends on your workflow.

Alternatively, you could use the --run COMMAND option of nix-shell to run single commands in the context provided by Nix.


*: commands in parentheses do run in a separate process, but this is mostly an implementation detail. It won't let other programs take over the execution of the script.

Hallock answered 29/10, 2020 at 21:48 Comment(3)
Hi Robert, thanks for the answer. I am still a little confused, so do?es it mean after the line #!nix-shell -i bash, I can write the command for nix-shell? Since I ran the script you posted, and I didn't enter either nix shell or the virtual env. In your suggestion, shall I generate a script with only source .venv/bin/activate in it ? Additionally, I was trying to have --run python start.py , but it was showing line 5: --run: command not found. Did I do something wrong here?Ellmyer
The way I understood it is that you want to write a shell script, so not interactive. If you want to enter a Nix shell in the terminal that automatically loads virtualenv, you could write a shell.nix file with a shellHook that loads the virtualenv. See nixos.org/manual/nix/stable/#description-13Hallock
Thank you. This solves the exact problem we were looking for.Ellmyer
B
3

Ran into this issue today, looked at what nix-shell docs had to say as suggested in the comments, and came up with a solution. I found NixOS Wiki helpful as well (see: https://nixos.wiki/wiki/Development_environment_with_nix-shell).

You can either enter the environment automatically with direnv (see: https://nix.dev/guides/recipes/direnv.html and https://github.com/nix-community/nix-direnv?tab=readme-ov-file#direnv-source_url) or use a one liner flow:

  • Seamlessly initialize with direnv, by following the nix-direnv install steps above and adding a file like the example below named .envrc:
if ! has nix_direnv_version || ! nix_direnv_version 3.0.4; then
  source_url "https://raw.githubusercontent.com/nix-community/nix-direnv/3.0.4/direnvrc" "sha256-DzlYZ33mWF/Gs8DDeyjr8mnVmQGx7ASYqA5WlxwvBG4="
fi
use_nix
  • Or initialize virtualenv with nix-shell:
# nix-shell looks for shell.nix
nix-shell
# You are now using virtualenv
(venv)
[nix-shell:~/example-repo]$ python --version
Python 3.9.16

Below is an example shell.nix file:

{ pkgs ? import <nixpkgs> { } }:
pkgs.mkShell {
  # nativeBuildInputs is usually what you want -- tools you need to run
  nativeBuildInputs = with pkgs.buildPackages; [
    python39Full
    python39Packages.virtualenv
  ];
  shellHook = ''
    virtualenv --python="${pkgs.python39Full}/bin/python" ./venv
    source ./venv/bin/activate
  '';
}
Berniecebernier answered 28/2 at 0:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.