I want to run a nix-shell with the following packages installed:
I can't simply do: nix-shell -p aspell aspellDicts.en hello --pure
as this will not correctly install the aspell dictionaries. Nix provides a aspellWithDict
function that can be used to build aspell with dictionaries:
nix-build -E 'with import <nixpkgs> {}; aspellWithDicts (d: [d.en])'
I want to use the result of this build as a dependency in another local package (foo). This is how I'm currently achieving this:
./pkgs/aspell-with-dicts/default.nix:
with import <nixpkgs> {};
aspellWithDicts (d: [d.en])
./pkgs/foo/default.nix:
{stdenv, aspellWithDicts, hello}:
stdenv.mkDerivation rec {
name = "foo";
buildInputs = [ aspellWithDicts hello ];
}
./custom-packages.nix:
{ system ? builtins.currentSystem }:
let
pkgs = import <nixpkgs> { inherit system; };
in
rec {
aspellWithDicts = import ./pkgs/aspell-with-dicts;
foo = import ./pkgs/foo {
aspellWithDicts = aspellWithDicts;
hello = pkgs.hello;
stdenv = pkgs.stdenv;
};
}
Running the shell works as expected: nix-shell ./custom-packages.nix -A foo --pure
So my solution works, but could this outcome be achieved in a more succinct idiomatic way?
To make this code more idiomatic, I have the following suggestions:
callPackage
Use the pkgs.callPackage
function. It will take care of passing the arguments that your derivation needs. This is why many files in NixPkgs look like { dependency, ...}: something
. The first argument is the function you want to inject dependencies into and the second argument is an attribute set that you can use to pass some dependencies manually.
By using callPackage
you do not need to import <nixpkgs> {}
, so your code will be easier to use in new contexts <nixpkgs>
can't be used and it will evaluate a bit faster because it has to evaluate the NixPkgs fix-point only once.
(Of course you have to import <nixpkgs>
once to get started, but after that, there should be no need.)
with
In pkgs/aspell-with-dicts/default.nix
you use a with
keyword, which is ok, but in this case it does not really add value. I prefer to refer to variables explicitly, so prefer to read pkgs.something
when it's used once or twice, or inherit (pkgs) something
if it's use more often. This way the reader can easily determine where a variable comes from.
I do use it when experimenting with unfamiliar packages or functions, because maintenance is not an issue then.
pkgs/aspell-with-dicts/default.nix
Unless you expect that your instantiation of aspell is something you want to reuse, it's probably easier to just construct it where you use it.
If you do expect to reuse a specific configuration of a package, you might want to make it a first class package by constructing it in an overlay.
That's it. I think the most important point is avoiding <nixpkgs>
and apart from that it's already pretty idiomatic.
I don't know what your mysterious foo
is, but if it's open source, please consider upstreaming it into NixPkgs. Nix has a very welcoming community in my experience.