Currently I’m using bash aliases as a short-hand for kicking off a development environment. E.g. I can write rust-dev
which is an alias for nix-shell /long/path/to/rust-dev.nix
where rust-dev-env.nix
is a derivation producing an environment with all the tools I need for rust development.
I’m wondering if there’s a way I can replace my bash alias with a small personal rust-dev
nix package instead? I figure this would be more portable across machines than bash aliases, as even though I have my bash alias in my home-manager config, the /long/path/to/rust-dev-env.nix
path won’t always be the same across machines.
I’m thinking of doing something like this:
{ writeShellScriptBin, ... }:
writeShellScriptBin "rust-dev" ''
nix-shell ${path/to/rust-dev-env.nix}
''
But I’m not sure what the best way of going about getting that path in there is? I know that there is builtins.readFile
, so I thought maybe I could do something like:
{ writeShellScriptBin, ... }:
writeShellScriptBin "rust-dev" ''
nix-shell -E ${(builtins.readFile path/to/rust-dev-env.nix)}
''
but I don’t think the -E
argument is designed to handle a nix expr as an entire multi-line string, which itself could also contain multi-line strings.
I think I need some way to copy the file from /path/to/rust-dev-env.nix
at the time of evaluation so that it is accessible to the nix-shell
call when the bash script is executed.
I guess this might be possible by not using writeShellScriptBin
and instead using mkDerivation
where I could manually copy the file to $out
by overriding installPhase
, but I was wondering if there might be a more concise approach?
What hinders you to make the dev env package to be part of your home-manager configuration files and just use the initial version? It feels the question you’re really asking is how to manage impure dependencies, and my gut reaction to that is „try not to if you can avoid it“.
What hinders you to make the dev env package to be part of your home-manager configuration files and just use the initial version?
It actually is a part of my home-manager configuration repository - maybe that makes this easier? Edit: Apologies if there’s an obvious solution I’m missing, I’m still fairly new to Nix-land!
Huh, it turns out I appear to be able to achieve this just fine with my original example! To clarify, this does actually work in my case:
{ writeShellScriptBin, ... }:
writeShellScriptBin "rust-dev" ''
nix-shell ${../env/rust-dev.nix}
''
I think I expected that the resulting rust-dev
package might break if the /env/rust-dev.nix
file was moved or something along those lines, as I thought of it as just a naiive bash script. Instead, it looks like during evaluation the file at that relative path appears to get copied to the nix store and the actual path used points to the copy in the store?
Either way this appears work!
1 Like
Exactly. Great that you have what you needed!
Weird, the manual does not even prominently mention this behavior. The best I could find are these side notes:
Nix manual builtins.toFile:
Note that ${configFile}
is an antiquotation (see Section 15.1, “Values”), so the result of the expression configFile
(i.e., a path like /nix/store/m7p7jfny445k...-foo.conf
) will be spliced into the resulting string.
Nix manual Release notes 1.6.1 (2013-10-28)
Previously, Nix optimised expressions such as "${expr
}" to expr
. Thus it neither checked whether expr
could be coerced to a string, nor applied such coercions. This meant that "${123}"
evaluatued to 123
, and "${./foo}"
evaluated to ./foo
(even though "${./foo} "
evaluates to "/nix/store/hash
-foo "). Nix now checks the type of antiquoted expressions and applies coercions.
This stuff is used everywhere, it must have been explained well enough somewhere else.
1 Like