Open garbas opened 3 years ago
nix shell
and nix develop
are geared for debugging Nix builds. We should have a different command for just using things that doesn't even bother with stdenv
/ genericBuild
(which use/do bashism and are slow).
I was initially going to post in agreement with @Ericson2314, but after reviewing the docs I'm unsure. Clearing up messaging and managing expectations seem like preconditions for thinking this through. I have tried to keep my head in the sand on both flakes and new-style commands, so maybe I'm a good rubber duck here...
nix --help
says (with irrelevant items removed):
Main commands:
build build a derivation or fetch a store path
develop run a bash shell that provides the build environment of a derivation
repl start an interactive environment for evaluating Nix expressions
run run a Nix application
shell run a shell in which the specified packages are available
I read this as:
nix develop
(iirc briefly nix dev-shell
) seems to be intended to meet the primary ~package-development need nix-shell
was built for.
nix run
seems to be intended to meet the "I don't want this in my profile but I want to use/try it real quick" needs that have been using nix-shell -p blah --run/--command
. (aside: the short help text for run is probably not enough for a new user to figure this out)nix shell
seems to be intended to take on all of the "nix-managed development environment" needs that have attached to nix-shell
over time.
nix shell
being geared for debugging builds, so I may be misunderstanding. It may also be a sign that it's hard enough to think clearly about what nix shell
does given our history with nix-shell
that it would be better to rename this and have no nix shell
.nix-shell
, but I don't know if that's true.This conflicts with what @Ericson2314 said about nix shell being geared for debugging builds, so I may be misunderstanding. It may also be a sign that it's hard enough to think clearly about what nix shell does given our history with nix-shell that it would be better to rename this and have no nix shell.
@abathur yes, nix shell
(without the dash) is not for providing a build environment.
For that reason, what @garbas suggests should not apply for nix-shell
and nix develop
, but could for the others.
This issue has been mentioned on NixOS Discourse. There might be relevant details there:
https://discourse.nixos.org/t/always-run-my-shell-in-nix-shell-nix-develop-et-al/12077/3
So that we +- get an idea who we're talking about:
The "devshell persona" Jeff, age 37, living with his young family in Addis Ababa, Ethiopia, is a guy who is responsible for the productivity of a global team of developers, he is driven by the following:
nix
), use toml files, hide nix where possibleI guess in general there are two major use cases:
For nr. 1 (debug build), it's very simple. One wants to have an environment that is exactly the build environment with all variables and the exact same shell (bash).
(this is currently what nix develop
does given any derivation)
For nr. 2 (dev environment) it is more difficult to define. I guess we all agree that a dev environment shares things with the build environment. But how to we want to define a dev environment?
Maybe I'm biased because of frameworks/tools I like to use, but in my opinion a dev environment should not be based on the build environment. It is usually a separate environment with significantly different properties compared to the build environment.
If we agree on this, then I guess we might be better of renaming nix develop
to nix debug
. It is not useful for developing usually. According to the manual nix develop
provides the build environment of a derivation
. This is useful for debugging builds. Not for developing.
Also nix develop
/nix debug
defaulting to load the devShell
output might be wrong. Why would one ever want to debug their devShell
? Normal derivations can require debugging, but not a devShell.
Wouldn't it be better if the devShell
was meant to be loaded by nix shell
?
Recently, I've been (ab)using nix develop
with shell.nix based on this example in the wiki. By the sounds of it, this isn't the "blessed" way to do general (as opposed to nix) development, but the alternative using nix shell
with a defaultPackage
is only a TODO at the moment, so I don't know how to do that.
From my point of view, this is what I think I need in a nix shell:
For nix package development (I've never really used this sort of thing much. Trying build and looking at the output has generally been adequate for my basic nix packaging needs):
For general development:
At this stage, I'm honestly not sure whether this general development use case is supposed to be supported by nix shell
or not. If it wasn't for this bug report, I probably wouldn't have realised that I'm not supposed to use nix develop --command zsh
for this.
I'm switching my dev environments from regular shell.nix
files to flakes.
I now use nix develop
instead of nix-shell
. The thing is that nix develop
starts a bash shell instead of my current shell (fish).
In order to continue using fish, I need to do: nix develop --command fish
and everything is like before!
Is there another way and/or another recommended way to do that?
I put a shellHook
in my development flakes, where I exec
the shell. (Or to be precise: I source a global script, which does that.)
If we agree on this, then I guess we might be better of renaming nix develop to nix debug. It is not useful for developing usually.
+1 to de-confusing "I want to debug a nix-based builds" and "I want to use nix
to create a dev environment for hacking on a random project (which might not be even be built with nix)" use cases. My prefered color for the bikeshed would be nix build --interactive
for what nix develop
currently does.
This issue has been mentioned on NixOS Discourse. There might be relevant details there:
Before adding a nix command that is inevitably going to be a bad fit again, consider writing a shell runner derivation that's usable with nix run
.
By expressing the shell logic in expressions, it is easier to improve and even replace by the community. The nix package itself should remain as simple as possible, because its logic can not be pinned.
Perhaps an "alias" for nix run
with a different default attribute would be convenient, but that's about as far as we should go, until proven otherwise.
This issue has been mentioned on NixOS Discourse. There might be relevant details there:
This issue has been mentioned on NixOS Discourse. There might be relevant details there:
https://discourse.nixos.org/t/shell-nix-but-with-flakes/18775/2
To add to @Thra11's use-case:
Needs:
* Development build inputs such as headers, libs, often a compiler-with-package-set sort of thing. * Development tools: not just the minimal tools required to build a package, but also repls, IDEs, version control, a user-friendly shell such as zsh, and so on * Some environment variables from the system environment. For example GUI tools may need environment variables to be set in order to pick up the system GUI configuration and interact with system services.
As a C++ developer, my dev shell is typically a superset of my package's inputs, effectively concatenating buildInputs ++ propagatedBuildInputs ++ nativeBuildInputs ++ ...
.
That gives me all I need to build, test, and run my software in a close reproduction of a nix build
environment. I add extra inputs for additional development tools that every developer would use during development.
I also need to disable (some) hardening, so I can build and debug without optimisations. With mkShell
, I add hardeningDisable = [ "fortify" ]; }
to do this.
(This bit took me a while to figure out. NIX_DEBUG=1
helped me realise Nix's GCC is wrapped in a script which implicitly appends some hardening flags, some of which enable optimisation. I'll look to update some documentation)
Edit: I discovered that the inputsFrom
attribute of mkShell
does something very similar to what I was looking for, with taking inputs from a derivation (but for some reason checkInputs
is omitted). The hardeningDisable
override is still necessary however.
Being new to Nix and Flakes, I was confused by the distinction between nix-shell
and nix shell
. I have a local workspace/environment with some specific binary versions I want to reference for only this project. With nix-shell
and a default.nix
file, I was able to decompose it into multiple files, and do myLocalPackage = import ./somefile.nix {}
to clean it up.
But when I try the same syntax in a flake.nix
and running with nix shell
or nix develop
, it tries to import the file relative to the nix store, and throws error: getting status of '/nix/store/skk5b55sdlfmh7z68cmlfz2ff9p9n8gd-source/somefile.nix': No such file or directory
.
Apologies if this is a totally different issue, but I suspect it's related to misunderstanding of using flakes for building packages vs. for a local development environment.
I was confused by the distinction between
nix-shell
andnix shell
.
This is a known issue that we should resolve. An extensive discussion has occurred in #4715, so "all that remains" is to make a decision.
But when I try the same syntax in a
flake.nix
and running withnix shell
ornix develop
,
You probably want nix develop
, unless you want to start a relatively clean shell with a locally defined package. These commands will only load a flake.nix
and anything imported from there.
it tries to import the file relative to the nix store, and throws
error: getting status of '/nix/store/skk5b55sdlfmh7z68cmlfz2ff9p9n8gd-source/somefile.nix': No such file or directory
.
Flakes are (currently) copied to the store before evaluation. If a file is missing, often you'd have to git add
(or git add -N
) it.
With #6530 we have an opportunity to improve the error message by checking for an untracked file before throwing the error.
Flakes are (currently) copied to the store before evaluation. If a file is missing, often you'd have to git add (or git add -N) it.
That was exactly my problem - I didn't realize the connection between the Nix store and the source tree, even for local dev. Thanks for your help!
This issue has been mentioned on NixOS Discourse. There might be relevant details there:
https://discourse.nixos.org/t/defining-multiple-nix-shell-environments/25770/1
This issue has been mentioned on NixOS Discourse. There might be relevant details there:
https://discourse.nixos.org/t/nix-shell-nix-shell-and-nix-develop/25964/11
For those finding this issue via a search engine, if you're just looking to have nix-shell
run a Fish shell instead of bash, here's what I did to make it work:
Add a file at ~/.config/fish/functions/nix-shell.fish
-- this function will wrap nix-shell
:
function nix-shell --wraps nix-shell
# if `--run` was passed at the command line, run as-is
for ARG in $argv
if [ "$ARG" = --run ]
command nix-shell $argv
return $status
end
end
# otherwise, append `--run "exec fish"` to the argument list to get a Fish shell
command nix-shell $argv --run "exec fish"
end
Doesn’t work for nix develop
though unfortunately…
https://github.com/MercuryTechnologies/nix-your-shell makes nix develop
work with fish (or zsh). I found I had to set my prompt manually, see the wiki for a hint of how to do it.
I did run into https://github.com/NixOS/nix/issues/6982, which is strictly-speaking related to bash
, but did not feel light or clean. It very much affects running bash
from a nix develop
fish shell (if I wanted to run a one-off bash command).
See https://github.com/NixOS/nix/issues/6982#issuecomment-1637001855 for my ugly workaround.
Since nix develop -c zsh
already provides all environment variables, the only missing part is a way to run the build phases automatically. A trivial possibility is to create a mini bash script that runs the various phases, that you can call from any shell. I did a proof of concept there and it worked greatly, and is shell agnostic :
https://discourse.nixos.org/t/making-a-development-flake-for-bespoke-synth/29988/5
One could also add in the script a way to save and load the environment/path of the previous command, saved into a file, but this should be quite trivial to do using env
.
quite trivial to do using
env
.
Variables can be local, they can be arrays, and they can be functions. This would need something like declare -p
if not more, and you'll probably have to deal with some idiosyncrasies along the way.
I doubt that a true solution for shell interoperability should be developed as part of Nix.
Since
nix develop -c zsh
already provides all environment variables, the only missing part is a way to run the build phases automatically.
To be honest, I want the opposite. I want the ability to get into a Zsh (or even Bash for that matter) session with just things like $PATH
settings added to my normal interactive shell profile, and keep the build phase stuff completely out of it. "I want to be in the nix build environment to run nix build phases" is just not the same concept, to my mind, as "I want to be in a shell environment with a set of packages available".
If I'm actually running Nix build phases, I'm happy to do so from Bash. It's a Bash environment, and not everything you can do in Bash crosses process boundaries into other shell environments nicely. I don't know whether Nix actually uses any features that wouldn't translate well, and I don't want to have to know that in order to predict the behaviour of the resulting shell environment. I would also much prefer not having to know that there's a big list of environment variables (including generic-sounding names like name
, out
, outputs
, shell
) that I should expect, ignore, and avoid using similar names if I want to avoid clashes.
Aliases for nix <shell or develop> "$@" -c <shell-of-choice>
give me most of what I want in practice, because the stuff that nix defines doesn't tend to actually get in the way that much. But fundamentally it's a shell launched inside an environment that is a tangled mix of the environment variables for dependencies and ones for the nix build framework. If development effort were to be spent on this, I'd much rather it went into untangling the two so that it's possible to get the dependency environment variables without the build framework ones, rather than trying to make the build framework work in multiple shell languages.
To be honest, I want the opposite. I want the ability to get into a Zsh (or even Bash for that matter) session with just things like
$PATH
settings added to my normal interactive shell profile, and keep the build phase stuff completely out of it. "I want to be in the nix build environment to run nix build phases" is just not the same concept, to my mind, as "I want to be in a shell environment with a set of packages available".
Adding onto this: it may not be a bad idea to get inspired by Microsoft's DevContainers. Basically, what I want is to run an isolated, portable development environment I can configure to my liking, without necessarily having to think about packaging it for Nix. I'm looking into build-vm
to see if it more or less does what I want it to do, but it's still hacky; I also looked into developing a bwrap
-based sandbox for flakes, but shellHook is too clunky for this.
Some setting that allowed me to override the command executed (instead of bash
) would be more than enough. Something like what devenv is doing, but not as overkill.
In devenv we're exploring this: https://github.com/cachix/devenv/issues/330#issuecomment-1975018698
Proposal
Final goal is to provide better integration with other shell environments - eg. zsh, fish, ...
Depending how this will be implemented a very nice to have would be to not spawn a new process when entering shell environment. This would mean the current user shell environment would be updated in-place (like direnv does it).
Reasoning
For those who don't use bash using
nix-shell
,nix develop
ornix shell
usually means you need to runnix-shell --run $SHELL
or creating an alias.I understand there are good reasons for using bash. Using bash ensures that development environments are very predictably and running commands from
nix-shell
would act as close as it can within a sandbox.But on the other side we are forcing developers to use bash or use workarounds. As all debates around editors also debates around shell environments are a hot topic among developers (which is our audience in this case). I wouldn't expect developers switching to bash just so they can use Nix. I would actually expect the opposite, potential users being turned away from Nix due to the lack of good integration with their shell environment.
As with most of the UX decisions also this comes down to compromising one thing over the other.
Bonus
Another bonus to consider is also which environment variables we should expose inside the shell environments.
From the perspective of a developer who just wants to enter a development environments to be able to develop their project, all the extra variables that get created confuse. This "type" of developers are not interested in building a project with Nix, but rather only interested in using Nix to provide needed development environment.
From the perspective of a developer who is working on a tool that will be built later with
nix build
they want to see - especially when packaging -We already have options to ignore environment variables (via
--ignore-environment
flag). We can make this a default and maybe even improve further and provide even "cleaner" development environments.