Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow nix develop to run shell code directly, similar to nix-shell --run #6908

Closed
jonringer opened this issue Aug 15, 2022 · 13 comments
Closed

Comments

@jonringer
Copy link
Contributor

Is your feature request related to a problem? Please describe.
The nix develop --command command allows you to execute some commands, however, it requires that the first arguments is a valid target for exec. This means that usage such as nix develop --command cd somedir/ && mkdir build && cd build && cmake .. && make will fail with something like line 1886: exec: cd: not found. Which is a bit odd, but makes sense if you're aware that the expected behavior is that nix will call exec on the first argument.

Describe the solution you'd like
Provide a way to run an inline script. (e.g. nix develop --run "cd somedir/ && mkdir build ....")

Describe alternatives you've considered
For single command executions, you can just re-orient the sequences of actions: cd somedir/ && nix develop --command ...

Or you can call bash:

nix develop --command bash -c  "cd somedir/ && mkdir build && cd build && cmake .. && make"

Additional context
This would be similar to nix-shell --run

@lheckemann
Copy link
Member

I much prefer the invoke-a-shell-yourself variant. Running a shell implicitly can be so much more painful in terms of quoting, variable scope, and such. And if this were introduced as a separate mode of operation (e.g. nix develop --shell 'cmake . && make'), is the benefit over nix develop --command bash -c 'cmake . && make' that significant?

@jonringer
Copy link
Contributor Author

I'm more concerned that nix develop --command cd somedir/ is a very suprising experience for users. nix develop --command would more accurately be described as nix develop --exec, which is a bit more up-front about the process being passed to what follows.

And if this were introduced as a separate mode of operation (e.g. nix develop --shell 'cmake . && make'), is the benefit over nix develop --command bash -c 'cmake . && make' that significant?

I agree that it's not a deal breaker. It's just that this awkwardness compounds when doing stuff like CI workflows, where the noise escalates quickly

  commands:
    - 'nix develop --command bash -c "cmake . && make"'

This also assumes that the user made the connection that their inlined bash was the issue, and needed to pass their script explicitly to the shell interpreter.

@jonringer
Copy link
Contributor Author

jonringer commented Aug 16, 2022

I would also be pretty happy with doing something like:

nix develop --bash "cmake . && make"

However, this likely isn't possible, as then we are making assumptions that nix (independent of nixpkgs) is able to know what a "bash" is.

But I also agree that nix develop --shell "..." and deferring to the current shell isn't great either, as now we are introducing environment-sensitive tooling into a "fully reproducible" nix workflow.

@FRidh
Copy link
Member

FRidh commented Aug 21, 2022

I find it important that nix develop will be able to support any shell, so I don't think we should make bash a default. I do agree that -exec is a better name. Maybe -command could be supported as well if the user would specify say a devShell = "bash -c" in their ~/.config/nix.conf?

@jonringer
Copy link
Contributor Author

I do agree that -exec is a better name

Thanks :)

Maybe -command could be supported as well if the user would specify say a devShell = "bash -c" in their ~/.config/nix.conf?

I'm not a big fan of that as many people will have differing opinions around what shell they want to use. Especially since some shells like zsh will have issues with flake urls with extended glob enabled.

@FRidh
Copy link
Member

FRidh commented Aug 24, 2022

Maybe -command could be supported as well if the user would specify say a devShell = "bash -c" in their ~/.config/nix.conf?

I'm not a big fan of that as many people will have differing opinions around what shell they want to use. Especially since some shells like zsh will have issues with flake urls with extended glob enabled.

Right, that is indeed an issue. Actually, why I suggested such an option is that I want to have a solution that supports derivation that uses a different shell as builder, e.g. python. But using nix.conf isn't great then either. In that case it is probably better to have an attribute for describing the devshell "builder". Downside is that, if you want to keep that pure, you would get a build-time dependency on your interactive shell, something we don't want either.

@romanofski
Copy link

I actually stumbled over this ticket because I was so used to nix-shell as well and it's implied bash interactive shell. Personally, I think just an example in the nix develop man page would have already cleared things up for me. Not sure how many would have been satisfied with a documentation entry, but it would have helped me enough to move on :)

@jonringer
Copy link
Contributor Author

Wrote a PR #7008 to provide a documentation sample, and going to move the --exec argument over to #7009

thufschmitt pushed a commit that referenced this issue Sep 8, 2022
Add example of nix develop being used to execuate a series of script
commands. This is common when doing things like CI/CD, and should be
represented in the official documentation.

Also useful for people looking for the 'nix develop' equivalent of
'nix-shell --run'.

Related:
 - #6908
 - #6908 (comment)
@mkoura
Copy link

mkoura commented Feb 1, 2023

With the current behavior it is not possible to use nix develop -c for e.g. starting services. The launching process control system (like supervisord) gets PID of nix develop instead of PID of the launched process. This was possible with nix-shell.

@thufschmitt
Copy link
Member

@mkoura not sure I get what you mean. Do you mean that when running nix develop --command sh -c "blah'" then supervisord only sees the PID of sh and not the one of blah? Or something else?

@mkoura
Copy link

mkoura commented Feb 3, 2023

@thufschmitt Yes. More specifically with a script run_service.sh with nix develop shebang like:

#! /usr/bin/env -S nix develop --accept-flake-config .#base -c bash

exec the_service

and supervisor config like

[program:the_service]
command=./run_service.sh

the supervisord sees only the PID of bash, instead of the_service.

@thufschmitt
Copy link
Member

That's weird, since you exec eventually the PIDs should be the same, right? (I guess the chain is that env execs nix which execs bash which execs the_service, with everything reusing the same PID).

Just tried with /usr/bin/env -S nix develop --accept-flake-config p#hello -c bash -c "exec cat", and htop only shows me one cat process in the end:

image

@mkoura
Copy link

mkoura commented Feb 6, 2023

This is weird indeed. I observe the same behavior as you described above, unless I'm in nix shell of a project where I've ran into this issue.

nix develop .#devops
nix develop --accept-flake-config .#devops -c bash -c "exec cat"

results in

martink     9591    9513  0 23:43 pts/6    00:00:00 /nix/store/p7bpdnxqd3i5hwm92mrscf7mvxk66404-bash-5.1-p16/bin/bash /nix/store/3lsckhv4zkl5wvzwfcryrndv4s3y30aq-nix/bin/nix develop --accept-flake-config .#devops -c bash -c exec cat
martink     9592    9591 60 23:43 pts/6    00:00:06 cat

Why is nix ran by bash? It turned out that nix is a shell script for some reason:

$ type nix
nix is /nix/store/3lsckhv4zkl5wvzwfcryrndv4s3y30aq-nix/bin/nix
$ cat /nix/store/3lsckhv4zkl5wvzwfcryrndv4s3y30aq-nix/bin/nix
#!/nix/store/p7bpdnxqd3i5hwm92mrscf7mvxk66404-bash-5.1-p16/bin/bash
find_up() {
  while [[ $PWD != / ]] ; do
    if [[ -e "$1" ]]; then
      echo "$PWD"
      return
    fi
    if [[ -e "nix/$1" ]]; then
      echo "$PWD/nix"
      return
    fi
    cd ..
  done
}
if [[ "$@" == *"flake"*" "*"show"* ]] || [[ "$@" == *"flake"*" "*"check"* ]]; then
  >&2 echo 'Temporary override `supported-systems.nix` original content to be able to use `nix flake show|check` on dev machines (workaround for https://github.com/NixOS/nix/issues/4265)'
  nixdir=$(find_up "supported-systems.nix")
  SYSTEMS="$nixdir/supported-systems.nix"
  BACKUP="$(mktemp)"
  mv "$SYSTEMS" "$BACKUP"
  echo '[ "x86_64-linux" ]' > "$SYSTEMS"
  function atexit() {
      mv "$BACKUP" "$SYSTEMS"
  }
  trap atexit EXIT
fi
GC_DONT_GC=1 /nix/store/3h985ga4wbpnpvi0llvbamhva69wl2k2-nix-2.11.0/bin/nix --experimental-features "nix-command flakes" "$@"

I don't know where this comes from, in any case it doesn't exec, so here is the reason for the unexpected behavior 😥

Minion3665 pushed a commit to Minion3665/nix that referenced this issue Feb 23, 2023
Add example of nix develop being used to execuate a series of script
commands. This is common when doing things like CI/CD, and should be
represented in the official documentation.

Also useful for people looking for the 'nix develop' equivalent of
'nix-shell --run'.

Related:
 - NixOS#6908
 - NixOS#6908 (comment)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants