Either turn the package into a flake and add it to your flake inputs, or make it part of your flake and import the file relatively instead of via an absolute path.
“impure” in this context means that, for the same inputs, a function might not always produce the same output.
In the context of a nix flake this would mean that your configuration isn’t reproducible, which is generally something worth avoiding - ideally, using just your flake, you should be able to spin up the same system regardless of when or where you try.
import-ing a file from an untracked place on your computer is obviously impure. That file likely doesn’t exist on other computers, and if it does, might not have the same contents - so nix might not be able to build your config, or produce unexpected outputs. You’ve snuck in an extra input that isn’t properly tracked, basically.
Nix used to not be very strict about this, which was a source of reproducibility problems. Flakes are more explicit about when your configuration might not actually be reproducible.
Flake inputs are permitted to not be inside your project because their hashes are tracked in flake.lock, so nix is able to assert that your inputs didn’t change without your knowledge, and because they are explicit inputs aren’t treated as part of the flake “function”, so it’s still considered “pure”.
For this, I would definitely recommend adding the package to your flake, perhaps even as part of the packages output. You don’t want to be left without this package if you ever need to reinstall your system with just your flake, and keeping it as an external flake that only lives on your drive at least makes the backup story more complex.
If this package is in your home directory because you prefer editing without sudo, consider moving your whole system configuration into your home directory and building using nixos-rebuild build --flake ~/my-config#.
nix build .
error: anonymous function at /nix/store/qpbqdrahv5ayilxjwffq380pf4wcba8j-source/default.nix:1:1 called without required argument 'lib'
at /nix/store/qpbqdrahv5ayilxjwffq380pf4wcba8j-source/flake.nix:9:21:
8| {
9| packages = (import ./default.nix)
| ^
10| {
(use '--show-trace' to show detailed location information)
I commented out the lib input and entire meta section in the default.nix which gave me the same error but this time for fetchFromGitHub. I’ve tried a few things but am not quite sure how to pass the required inputs to satisfy the import requirements.
Will substitute the contents of default.nix, which defines a function that takes an attrset with 3 named arguments:
You then give it this argument, an attrset containing pkgs, which the function doesn’t ask for:
So you get an error, because you didn’t give it any of the arguments it was asking for (and it fails before telling you it has no idea what to do with that pkgs argument).
pkgs.callPackage is a function that automatically figures out what things from nixpkgs a function asks for, and then calls the function with exactly those arguments (and any extra ones you add). It’s always used when building packages written in the style that you wrote yours.
Alternatively, you could take those arguments out of nixpkgs by hand:
# Note the brackets around `import x` are actually unnecessary in your case
packages.swaynagmode = import ./default.nix {
# inherit (x) y; means "take attribute y out of x and put it in this attrset with the same name"
inherit (nixpkgs.legacyPackages.${system}) fetchFromGitHub stdenv lib;
};
The nix pills explain callPackage really well: Nix Pills. They’re a good read in general if this stuff still confuses you.
Also note that you actually need to give your package a name in that attrset. Nix is only not complaining because so far it’s been unable to see whether the function would return an appropriate attrset. I’ve taken the liberty in the above snippets of calling your package output swaynagmode.
You could also name it “default”, in which case some nix commands would use that package by default if you don’t specify anything else.
And since I’m already reviewing your code, you might want to know that rec is an antipattern (as is with, but frankly, I don’t think it’s too bad when used in meta like you do here).
It’s a minor nit, and I’m still guilty of using it for version like you do sometimes. There’s a cool new package definition function that makes the use of rec for this obsolete, though: Nixpkgs 22.05 manual.
True, although my usual method for bringing a system back up is to rsync my nixos folder from another machine. I hadn’t actually gotten this far into a rebuild from scratch yet, so consolidating everything into my nixos folder makes sense.
Thanks for all of the help so far! This all makes perfect sense. I read nix pills when I was first learning nix, although it made less and less sense as I progressed through it. Now that I’ve used nix and nixos for most nearly a year, I should probably go back through it.
I currently have a working build. My /etc/nixos is moved to my syncthing folder, and the swaynagmode folder is within syncthing/scripts/nixos/swaynagmode.
I’m inputting the folder in flake.nix
inputs.swaynagmode.url = "path:swaynagmode";
I import my sway.nix in flake.nix (in part)
modules = [
./sway.nix
and within their I have (in part)
{ config, pkgs, lib, swaynagmode, ... }:
{
programs.sway = {
enable = true;
wrapperFeatures.gtk = true; # so that gtk works properly
extraPackages = with pkgs; [
#swaynagmode
In that directory, I tested that everything is working as expected by running:
# nixos-rebuild test --flake .#
When I comment out the swaynagmode, I get the error
# nixos-rebuild test --flake .#
building the system configuration...
error: attribute 'swaynagmode' missing
at /nix/store/8gwzhqn67qm8r5biakx2hxsqiy3jfqmz-source/lib/modules.nix:496:28:
495| builtins.addErrorContext (context name)
496| (args.${name} or config._module.args.${name})
| ^
497| ) (lib.functionArgs f);
(use '--show-trace' to show detailed location information)
I’ve tried a few different things after searching around and looking at others’ nixos configurations I could find, but I don’t see how to get this to recognize.
I didn’t really mean that you should do both of these things One is enough; either make swaynagmode an explicit flake, or have it part of your general flake.
Part of the general flake (easy)
The latter is much simpler, if you just add your swaynagmode.nix to that folder as you already have, you can just use it as you probably did before, e.g.:
{ config, pkgs, lib, ... }:
{
programs.sway = {
enable = true;
wrapperFeatures.gtk = true; # so that gtk works properly
extraPackages = with pkgs; [
(callPackage ./swaynagmode { })
Assuming syncthing/scripts/nixos has your sway.nix file, and swaynagmode/ is also in the same directory, and your actual swaynagmode package is called default.nix.
You don’t need another flake for swaynagmode if you’re happy with having them all in the same flake.
Part of a separate flake (harder)
If you did want to have your swaynagmode in a directory that is not a subdirectory of the directory with flake.nix in it still, you could create a flake for it, exactly like you did, and you wouldn’t need to move your files at all.
But you would need to also actually use it correctly. Just having the input present in flake.nix is not enough to expose it to the NixOS module system. You need to glue it in yourself.
Part of the problem is that there is no single way of achieving this. We need to use the furnishings of lib.nixosSystem, which are partially deprecated and before flakes were clearly not intended to be a public interface. It’s simple in practice, but confusing and more complex than it needs to be.
There are basically two options (you might see some other suggestions such as specialArgs and extraArgs, but these are deprecated):
Typically I would recommend an overlay, but in this case you already added swaynagmode as a module arg to sway.nix and we just need to tell it where to actually get the argument. In your flake.nix, you should have something like this:
Note that the outputs function has two arguments, nixpkgs and swaynagmode. This is why those inputs can be used - nix will take the inputs, and put the correctly named attributes into arguments for the outputs function.
The nixpkgs.lib.nixosSystem isn’t given swaynagmode, though, so NixOS doesn’t know anything about the other input. It is implicitly given nixpkgs, because we call it through nixpkgs.
To give NixOS access to the other argument, what we can do is add swaynagmode to the arguments each of your modules takes using _module.args in an inline module like so:
{
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-22.05";
swaynagmode.url = "path:swaynagmode";
};
outputs = { nixpkgs, swaynagmode }: {
nixosConfigurations.my-system = nixpkgs.lib.nixosSystem {
inherit system;
modules = [
# This is an inline module - looks exactly like e.g.
# `configuration.nix`, but it isn't a separate file,
# and therefore retains full access to the outer
# scope (which includes `swaynagmode`).
({...}: {
_module.args = {
inherit swaynagmode;
};
})
(import ./configuration.nix)
];
};
};
}
swaynagmode is in scope because it’s an argument of outputs. Adding it to the _module.args in a module means that now whenever nix evaluates another module, it will be available in the arguments for that module.
So your sway.nix will have it available in {pkgs, lib, swaynagmode, ...}. It will also be available in configuration.nix, for that matter.
The alternative of using an overlay would make it available through pkgs.swaynagmode instead, but I’m sure I’ve already given you far too much detail, so I’ll leave that explanation for another day.
Personally, I think this is all black magic, and unnecessarily so. We really need a better way of doing this, but it’s the current state of flakes. Maybe it will get better when it’s not just a hack to have experimental flake support.
I had already put these in, so I took them out and cleaned up my other experiments and all is well. I agree that there’s some black magic here. Hopefully discussions like this can help inform documentation.