Hello. I want to create a flake so that anyone who takes my flake as input can add my program in either environment.systemPackages or home.packages simply by just adding its name into the list, or at least something that is simpler than what I currently have.
and this would work. niri-adv-rules is now available on my desktop. But this seems rather ugly, and it would be a lot better if the system can automatically pick the correct one out of inputs.niri-adv-rules.packages.* depending on the environment. I want to update the flake in niri-adv-rules/flake.nix at 8c7a14fcf066ba81927013b5f28675cdfec04902 · MangoCubes/niri-adv-rules · GitHub so that anyone who takes my flake as input can just do this:
home.packages = [
niri-adv-rules
...
]
Or at least without the .x86_64-linux.default part. How can I do this? I want to create options for this program so that the program is installed if program.niri-adv-rules.enable = true, but I can’t just include with x86_64-linux part since I can’t assume the system in which this program will run. Thank you.
It’s not guaranteed to be defined, especially on nixpkgs instances that have disallowAliases, and it’s also just “less correct”. That’s why I always provide the full path.
But how would I get the variable pkgs? The variable itself is defined as pkgs = nixpkgs.legacyPackages.${system};, meaning I already know the environment in which this program is installed.
The ultimate goal of this is so that anyone who wants to install my program can just add this to their config:
imports = [
inputs.niri-adv-rules.homeManager
];
In other words, they don’t need to add x86_64-linux or ${pkgs.stdenv.hostPlatform.system} into their own config because my flake is handling the “choosing the correct system” part. I want to add that into my project’s flake:
Create and expose a nixos/HM module and have them add that to imports in their config (since you’ll have {pkgs, ...}: and such at the top, pkgs is now available)
Create and expose an overlay and have them add it to nixpkgs.overlays in their config. Overlays are functions of the form final: prev: { ... }; and you would use final.callPackage to package your nix expression. Overlays will modify the existing nixpkgs instance when applied via said option.
In either case, flake-utils does not need to come into the picture, as you’re not applying system.
I believe a good way to show you this would be to show you some examples and you should get the answers you are looking for. These are two polished and known examples that do modifications similar to what you seem to be aiming for (from what I gather).
determinate-nix
Users of this flake just have to do the following to use this flake:
{
inputs.determinate.url = ...;
inputs.determinate.inputs.nixpkgs.follows = "nixpkgs" # optional
outputs = { determinate, nixpkgs, ... }@inputs: {
nixosConfigurations.my-workstation = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = [
# Load the Determinate module
determinate.nixosModules.default
# You can do this, or pass `inputs` into `specialArgs`
# and then just add `inputs.determinate.nixosModules.default`
# as an import anywhere. They will both work.
];
};
};
}
The modules (NixOS module or Home Manager module) here don’t add the agenix utility to system nor home packages. That has to be explicitly done by users. The procedure is similar to the above, but now you have to add it yourself. Something like this:
This essentially exposes ./nix/homeManager.nix as a “sample” config, which is basically like writing this into user’s config when imported:
{
config,
pkgs,
inputs,
...
}:
let
cfg = config.niri-adv-rules;
in
{
home.packages = [
inputs.niri-adv-rules.packages."${pkgs.stdenv.hostPlatform.system}".default
];
}
Since this has the ${pkgs.stdenv.hostPlatform.system}, user’s computer automatically determines which package to install. This worked!
One last question though, this assumes that the user included my flake with the name niri-adv-rules (since I’m using inputs.niri-adv-rules.*). It’s not much of an issue since I can just tell the users to include it under this name, but I’m guessing this has to be hardcoded?
Either way, thank you. Now I know how to write importable programs.
Written this way, unfortunately, yes. That’s why I personally tend towards overlays, because then the end-user just needs to write pkgs.niri-adv-rules (or whatever you want to call it). In fact you could even provide both a module and an overlay, and use the overlay in the module Then you yourself only have to write pkgs.niri-adv-rules.
EDIT: just as a rough example, this is what your flake could provide:
Just be aware that the nixpkgs.overlays line won’t work in their hm config if they have home-manager.useGlobalPkgs set to true (because then they need to add that overlay in their NixOS config instead).
Maybe I don’t understand your question, but I’ll try to answer.
Those two are not related. config and inputs are entirely unrelated. The label through inputs is whatever you named the flake input in flake.nix in inputs. The definition in config is whatever you defined through options in your modules, which are being imported (That is all this really is. This is just a bunch of fancy stuff to make re-usable imports, but in reality at the core you are just importing modules just like an imports = [ ... ]; in your system or home configuration. It is no different.). The label under config will be what you defined. The user can label the input bobsburgers and it won’t be relevant at all, since they will still import it through that label.
For further context which may or may not be needed from you, I’ll briefly cover what is happening “under the hood”. What you are importing is really the store path in the store for the flake input.
When you add an input to your flake and then evaluate it, here is what happens.
The flake input is downloaded by Nix and stored in the Nix store.
The actually “input” reference in flake.nix that gets passed to the outputs function is an attribute set containing some metadata about the flake, such as this. What matter here is the outPath, which is the path where the downloaded flake source lives in the Nix store on your machine. Here you can see that everything for the flake is exposed, including packages, nixosModules, or homeManagerModules. This is how the flake module contents make it to users. This is what the outputs function in your flake generates (along some other metadata is injected as well). They are just Nix expressions just like anything else. When you import a module, you are really importing the outPath + (subpath of the module in that flake directory), such as outPath + ./modules/nixos/default.nix for example. The full path is evaluated and is what is imported.