Closed stessaris closed 7 months ago
I am inclined to say that I don't want to implement another use flake
variant based on this (very valid) critique. However, I want to let this simmer for a bit to make sure that's my actual stance.
Current justification for my stance is that bash code is inherently pretty bad to maintain and I don't want more code paths. A fork could address this easily, I suspect, and would not have to be burdened by (what I consider to be) legacy "use nix" implementation at all. (All I would ask is to rename the entry point away from use flake
. There's enough difficulty in figuring out which implementation is in use now between the builtin direnv use flake
and ours - adding another would be frustrating.)
I just realised that a strong reason for changing the current behaviour is that the following .envrc
file
# .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 flake 'nixpkgs#cowsay'
doesn't provide a shell where cowsay
is available:
~/temp/direnv_nix_test via ❄️ impure (cowsay-3.7.0-env)
❯ cowsay help
bash: command not found: cowsay
~
❯ nix shell nixpkgs#cowsay
~ via ❄️
↕️ 2 ❯ cowsay help
______
< help >
------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
Our focus has been on local flakes with tailored mkShell
invocations intended to provide a meaningful dev shell. The current behavior is certainly surprising, but not out of line with what we are trying to show off. You ended up in the devshell for cowsay and you could resolve the problem with a local flake that adds cowsay to your devShell (and an update to your .envrc
).
I want to continue to make clear that I see the critique, but I'm not sure what to do.
Is your goal to avoid a local flake?
I understand the reasons for the current behaviour of use flake
, but since the use of a remote flake is supported, I think that it would be useful to support also the nix shell
behaviour (with a different layout, e.g., use flakeshell
).
My understanding is that, even by using a local flake I'd end up with a development shell that is bringing in the packages for nix development and not just the packages I need, as with nix shell
.
Would be possible to use the current caching technique that makes nix-direnv
better than the default layout with nix shell ... --command direnv dump bash
instead of nix print-dev-env
?
Would be possible to use the current caching technique that makes nix-direnv better than the default layout with
nix shell ... --command direnv dump bash
instead ofnix print-dev-env
?
Not really. Your proposed approach breaks current usage expectations as shown below:
Given the following flake.nix
:
{
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixpkgs";
flake-utils.url = "github:numtide/flake-utils";
};
outputs = { self, nixpkgs, flake-utils }: flake-utils.lib.eachDefaultSystem (system:
let pkgs = nixpkgs.legacyPackages.${system};
in
{
packages = { };
devShell = pkgs.mkShell {
packages = with pkgs; [
coreutils
gawk
];
};
});
}
This is the behavior you see:
$ nix shell . --command direnv dump bash
error: flake 'path:.../testflake' does not provide attribute 'packages.x86_64-linux.default' or 'defaultPackage.x86_64-linux'
$ nix print-dev-env . >/dev/null; echo $?
0
The thing you'd have to do here is to move the packages you want into a meta-derivation that creates a symlink farm and expose that as packages.x86_64-linux.default
. This behavior is surprising to current users and arbitrarily different from what we have. Current understanding is that the devShell
sets up this project to be workable. You put your dependencies in devShell.packages
(or any of the equivalents for such) - this flies in the face of that understanding.
Frankly, creating the symlink farm is an extra step that I don't ever want to do and I'm not sure it is any better than the current approach in any meaningful way. Your proposed approach would also fail to set up paths required for libraries.
Lets use Ocaml development as an example. To expose an Ocaml library to a nix builder, you need to add ocamlPackages.dune3
(a build tool for ocaml), ocamlPackages.findlib
(sort of pkgconfig for Ocaml) and your Ocaml library (we'll pretend it is ocamlPackages.re
- a regex implementation - for this discussion) to the set of devShell inputs. findlib
has a hook that sets OCAMLPATH
to all of the ocamlPackages
members paths, which allows dune
to find re
when you open Re
in your code. nix shell
only wires up PATH
, so OCAMLPATH
never gets set and suddenly your builds fail.
I think we're really talking about two related things here:
use flake nixpkgs#cowsay
doesn't ACTUALLY install a cowsay
environmentuse flake nixpkgs#cowsay
exports a bunch of "unrelated" environment variables.The first part is somewhat by design and the fact that you can use remote packages is - imo - an implementation detail. nix print-dev-env
accepts the flake specifier that you provided as valid and so you can do it. I have never actually wanted to do this particular thing and I have yet to be convinced that it is actually useful for real-world scenarios. I am open to being proven wrong though.
The second point is somewhat unfortunate and we do work around the "worst" of them by caching their values and resetting them after sourcing the print-dev-env
output. I'm not entirely sure "intentional" is the right word for this, but it does come with the implementation we have chosen.
If any of this is wrong, please do not hesitate to correct me. I have now put enough thought into this that I am a solid "no" without correction or further clarification that substantially changes my understanding of this scenario and request.
My understanding is that, even by using a local flake I'd end up with a development shell that is bringing in the packages for nix development and not just the packages I need, as with nix shell.
This is only true if you are expecting to set up a remote flake as your source. If you simply do what is shown above (a local flake that uses nixpkgs provided packages as devshell inputs), you end up with exactly what you specified. You get to define your flake devShell, which is what we're relying on currently.
And I never addressed this from your first post:
Moreover, I think that the shell behaviour would be more intuitive, because direnv doesn't support the functions the user would expect in a nix develop subshell.
I don't understand this statement. The thing that does the subshell spawning is direnv, not nix develop
or nix print-dev-env
. Because of this, we still are in a subshell when invoked in either your proposed path or our current one, as direnv
spawns the shell, calls nix-direnv
(which sets up the new environment in the subshell), and then tears down the subshell while keeping track of the changed environment variables. We still can't export functions or aliases with this change.
I don't understand this statement. The thing that does the subshell spawning is direnv, not nix develop or nix print-dev-env. Because of this, we still are in a subshell when invoked in either your proposed path or our current one, as direnv spawns the shell, calls nix-direnv (which sets up the new environment in the subshell), and then tears down the subshell while keeping track of the changed environment variables. We still can't export functions or aliases with this change.
Probably I wasn't clear enough; what I was trying to say is that use flake
put you in an nix develop
like environment, but without the buildPhase
, etc. commands that you'd have in there. I know that the reason is that direnv
doesn't track functions and aliases, so it's not a surprise.
Anyway, I think I can modify my remote flakes following your example in order to get the behaviour I'm looking for.
Since
use flake
function uses thenix print-dev-env
command, the result is roughly equivalent to entering a subshell withnix develop
command (minus the additional functions). See the output ofHowever, it's often the case that flakes are used via the
nix shell
command, and right now this is not supported bynix-direnv
. The difference is substantial, becausenix develop
brings in a lot of tools that might not be desirable or even clashing with the actual environment; e.g., the barebonebash
command that replaces the default one, or setting environment variables likeSOURCE_DATE_EPOCH
orCC
. See the output ofThis issue is related to #324, but it'd be useful to enable both
develop
andshell
. Moreover, I think that theshell
behaviour would be more intuitive, becausedirenv
doesn't support the functions the user would expect in anix develop
subshell.Unfortunately, it doesn't seem that
nix
is providing aprint-env
command, so I guess that the alternative would be to use something like the abovenix shell 'nixpkgs#cowsay' --command direnv dump