fix typo in »mkSystemsFlake«,

make system's $out/config optional,
don't use patches by default
This commit is contained in:
Niklas Gollenstede 2022-05-18 16:06:27 +02:00
parent df3fa46b3c
commit 9ef807877e
8 changed files with 49 additions and 40 deletions

6
.vscode/extensions.json vendored Normal file
View File

@ -0,0 +1,6 @@
{
"recommendations": [
"jnoortheen.nix-ide",
"streetsidesoftware.code-spell-checker",
],
}

View File

@ -51,6 +51,7 @@
"mountpoint", // program / function
"namespacing", // word
"netbootxyz", // option
"niklas", // name
"nixos", // (duh)
"nixpkgs", // nix
"noatime", // mount option

View File

@ -13,13 +13,13 @@
}; outputs = inputs: let patches = {
nixpkgs = [
./patches/nixpkgs-test.patch # after »nix build«, check »result/inputs/nixpkgs/patched!« to see that these patches were applied
./patches/nixpkgs-fix-systemd-boot-install.patch
# ./patches/nixpkgs-test.patch # after »nix build«, check »result/inputs/nixpkgs/patched!« to see that these patches were applied
# ./patches/nixpkgs-fix-systemd-boot-install.patch
];
}; in (import "${./.}/lib/flakes.nix" "${./.}/lib" inputs).patchFlakeInputsAndImportRepo inputs patches ./. (inputs@ { self, nixpkgs, ... }: repo@{ overlays, lib, ... }: let
systemsFlake = lib.wip.mkSystemsFalke (rec {
systemsFlake = lib.wip.mkSystemsFlake (rec {
#systems = { dir = "${./.}/hosts"; exclude = [ ]; };
inherit inputs;
scripts = [ ./example/install.sh.md ] ++ (lib.attrValues lib.wip.setup-scripts);

View File

@ -22,7 +22,7 @@ in rec {
# A non-flake has only the attrs of »sourceInfo«.
# A flake has »{ inputs; outputs; sourceInfo; } // outputs // sourceInfo«, where »inputs« is what's passed to the outputs function without »self«, and »outputs« is the result of calling the outputs function. Don't know the merge priority.
if (!input?sourceInfo) then sourceInfo else (let
outputs = (import "${patched.outPath}/flake.nix").outputs ({ self = outputs; } // input.inputs);
outputs = (import "${patched.outPath}/flake.nix").outputs ({ self = sourceInfo // outputs; } // input.inputs);
in { inherit (input) inputs; inherit outputs; inherit sourceInfo; } // outputs // sourceInfo)
)) else input) inputs);
@ -58,11 +58,13 @@ in rec {
) then (props) else throw "File ${entryPath} must fulfill the structure: dirname: inputs: { ... }: { imports = [ { preface = { hardware = str; ... } } ]; }";
# Builds the System Configuration for a single host. Since each host depends on the context of all other host (in the same "network"), this is essentially only callable through »mkNixosConfigurations«.
# See »mkSystemsFalke« for documentation of the arguments.
# See »mkSystemsFlake« for documentation of the arguments.
mkNixosConfiguration = args@{ name, entryPath, peers, inputs, overlays, modules, nixosSystem, localSystem ? null, ... }: let
preface = (getSystemPreface inputs entryPath ({ inherit lib; } // specialArgs));
targetSystem = "${preface.hardware}-linux"; buildSystem = if localSystem != null then localSystem else targetSystem;
specialArgs = (args.specialArgs or { }) // { # make these available in the attrSet passed to the modules
specialArgs = { # make these available in the attrSet passed to the modules
inherit inputs; # These are global and passed by the caller of this function (or not), so avoid using these (in favor of the own flakes inputs) where possible!
} // (args.specialArgs or { }) // {
inherit name; nodes = peers; # NixOPS
};
in { inherit preface; } // (nixosSystem {
@ -84,8 +86,6 @@ in rec {
system.extraSystemBuilderCmds = (if !config.boot.initrd.enable then "" else ''
ln -sT ${builtins.unsafeDiscardStringContext config.system.build.bootStage1} $out/boot-stage-1.sh # (this is super annoying to locate otherwise)
'') + (if !inputs?self then "" else ''
ln -sT ${inputs.self.outPath} $out/config # (build input for reference)
'');
}) ];
@ -94,7 +94,7 @@ in rec {
# Given either a list (or attr set) of »files« (paths to ».nix« or ».nix.md« files for dirs with »default.nix« files in them) or a »dir« path (and optionally a list of file names to »exclude« from it), this builds the NixOS configuration for each host (per file) in the context of all configs provided.
# If »files« is an attr set, exactly one host with the attribute's name as hostname is built for each attribute. Otherwise the default is to build for one host per configuration file, named as the file name without extension or the sub-directory name. Setting »preface.instances« can override this to build the same configuration for those multiple names instead (the specific »name« is passed as additional »specialArgs« to the modules and can thus be used to adjust the config per instance).
# All other arguments are as specified by »mkSystemsFalke« and are passed to »mkNixosConfiguration«.
# All other arguments are as specified by »mkSystemsFlake« and are passed to »mkNixosConfiguration«.
mkNixosConfigurations = args: let # { files, dir, exclude, ... }
files = args.files or (getNixFiles args.dir (args.exclude or [ ]));
files' = if builtins.isAttrs files then files else (builtins.listToAttrs (map (entryPath: let
@ -121,7 +121,7 @@ in rec {
# Builds a system of NixOS hosts and exports them plus managing functions as flake outputs.
# All arguments are optional, as long as the default can be derived from the other arguments as passed.
mkSystemsFalke = args@{
mkSystemsFlake = args@{
# An attrset of imported Nix flakes, for example the argument(s) passed to the flake »outputs« function. All other arguments are optional (and have reasonable defaults) if this is provided and contains »self« and the standard »nixpkgs«. This is also the second argument passed to the individual host's top level config files.
inputs ? { },
# Root path of the NixOS configuration. »./.« in the »flake.nix«
@ -208,23 +208,22 @@ in rec {
}) // {
packages.all-systems = pkgs.stdenv.mkDerivation { # dummy that just pulls in all system builds
name = "all-systems"; src = ./.; installPhase = ''
mkdir -p $out/systems
${lib.concatStringsSep "\n" (lib.mapAttrsToList (name: system: (
"ln -sT ${system.config.system.build.toplevel} $out/systems/${name}"
)) nixosConfigurations)}
${lib.optionalString (scripts != [ ]) ''
mkdir -p $out/scripts
${lib.concatStringsSep "\n" (lib.mapAttrsToList (name: _: "ln -sT ${outputs.apps.${localSystem}.${name}.program} $out/scripts/${name}") nixosConfigurations)}
''}
${lib.optionalString (inputs != { }) ''
mkdir -p $out/inputs
${lib.concatStringsSep "\n" (lib.mapAttrsToList (name: { outPath, ... }: "ln -sT ${outPath} $out/inputs/${name}") inputs)}
''}
${lib.optionalString (configPath != null) "ln -sT ${configPath} $out/config"}
'';
};
# dummy that just pulls in all system builds
packages.all-systems = pkgs.runCommandLocal "all-systems" { } ''
mkdir -p $out/systems
${lib.concatStringsSep "\n" (lib.mapAttrsToList (name: system: (
"ln -sT ${system.config.system.build.toplevel} $out/systems/${name}"
)) nixosConfigurations)}
${lib.optionalString (scripts != [ ]) ''
mkdir -p $out/scripts
${lib.concatStringsSep "\n" (lib.mapAttrsToList (name: _: "ln -sT ${outputs.apps.${localSystem}.${name}.program} $out/scripts/${name}") nixosConfigurations)}
''}
${lib.optionalString (inputs != { }) ''
mkdir -p $out/inputs
${lib.concatStringsSep "\n" (lib.mapAttrsToList (name: { outPath, ... }: "ln -sT ${outPath} $out/inputs/${name}") inputs)}
''}
${lib.optionalString (configPath != null) "ln -sT ${configPath} $out/config"}
'';
})); in outputs;

View File

@ -74,14 +74,14 @@ in rec {
names = builtins.concatLists (map (overlay: builtins.attrNames (overlay { } { })) (builtins.attrValues overlays));
in mapMerge (name: { ${name} = pkgs.${name}; }) names;
## Given a path to a module in »nixpkgs/nixos/modules/« and placed in another module's »imports«, adds an option »disableModule.<path>« that defaults to being false, but when explicitly set to »true«, disables all »config« values set by the module.
## Given a path to a module in »nixpkgs/nixos/modules/«, when placed in another module's »imports«, this adds an option »disableModule.${modulePath}« that defaults to being false, but when explicitly set to »true«, disables all »config« values set by the module.
# Every module should, but not all modules do, provide such an option themselves.
# This is similar to adding the path to »disabledModules«, but:
# * leaves the module's other definitions (options, imports) untouched, preventing further breakage due to missing options
# * makes the disabling an option, i.e. it can be changed dynamically based on other config values
makeNixpkgsModuleConfigOptional = nixpkgs: specialArgs: modulePath: let
fullPath = "${nixpkgs.outPath}/nixos/modules/${modulePath}";
moduleArgs = { utils = import "${nixpkgs.outPath}/nixos/lib/utils.nix" { inherit (specialArgs) lib config pkgs; }; } // specialArgs;
makeNixpkgsModuleConfigOptional = specialArgs: modulePath: let
fullPath = "${specialArgs.inputs.nixpkgs.outPath}/nixos/modules/${modulePath}";
moduleArgs = { utils = import "${specialArgs.inputs.nixpkgs.outPath}/nixos/lib/utils.nix" { inherit (specialArgs) lib config pkgs; }; } // specialArgs;
module = import fullPath moduleArgs;
in { _file = fullPath; imports = [
{ options.disableModule.${modulePath} = lib.mkOption { description = "Disable the nixpkgs module ${modulePath}"; type = lib.types.bool; default = false; }; }
@ -93,12 +93,12 @@ in rec {
{ disabledModules = [ modulePath ]; }
]; };
## Given a path to a module and a function taking the instantiation of the original and returning a partial module as override, recursively applies that override to the original module definition.
# This allows for much more fine-grained overriding of the configuration (or even other parts) of a module than »makeNixpkgsModuleConfigOptional«, but the override function needs to be tailored to internal implementation details of the original module.
# Esp. it is important to know that »mkIf« both existing in the original module and in the return from the override results in an attrset »{ _type="if"; condition; content; }«. Accessing content from an existing »mkIf« thus requires adding ».content« to the lookup path, and the »content« of returned »mkIf«s may get merged with any existing attribute of that name.
overrideNixpkgsModule = nixpkgs: specialArgs: modulePath: override: let
fullPath = "${nixpkgs.outPath}/nixos/modules/${modulePath}";
moduleArgs = { utils = import "${nixpkgs.outPath}/nixos/lib/utils.nix" { inherit (specialArgs) lib config pkgs; }; } // specialArgs;
## Given a path to a module, and a function that takes the instantiation of the original module and returns a partial module as override, this recursively applies that override to the original module definition.
# Used as an »imports« entry, this allows for much more fine-grained overriding of the configuration (or even other parts) of a module than »makeNixpkgsModuleConfigOptional«, but the override function needs to be tailored to internal implementation details of the original module.
# Esp. it is important to know that »mkIf« both existing in the original module and in the return from the override results in an attrset »{ _type="if"; condition; content; }«. Accessing content of an existing »mkIf« thus requires adding ».content« to the lookup path, and the »content« of returned »mkIf«s will get merged with any existing attribute of that name.
overrideNixpkgsModule = specialArgs: modulePath: override: let
fullPath = "${specialArgs.inputs.nixpkgs.outPath}/nixos/modules/${modulePath}";
moduleArgs = { utils = import "${specialArgs.inputs.nixpkgs.outPath}/nixos/lib/utils.nix" { inherit (specialArgs) lib config pkgs; }; } // specialArgs;
module = import fullPath moduleArgs;
in { _file = fullPath; imports = [
(mergeAttrsRecursive [ { imports = module.imports or [ ]; options = module.options or { }; config = module.config or { }; } (override module) ])

View File

@ -31,7 +31,7 @@ in rec {
preferredRoute = from: to: (lib.findFirst ({ prefix, ip, ... }: prefix == "" || (builtins.any (fromSub: startsWith prefix fromSub) from)) { ip = ""; } to).ip;
# Given a message and any value, traces both the message and the value, and returns the value.
trace = lib: message: value: (builtins.trace (message +": "+ (lib.generators.toPretty { } value)) value);
trace = message: value: (builtins.trace (message +": "+ (lib.generators.toPretty { } value)) value);
rpoolOf = hostName: "rpool-${builtins.substring 0 8 (builtins.hashString "sha256" hostName)}";

View File

@ -3,7 +3,7 @@
This is a library of bash functions, mostly for NixOS system installation.
The (paths to these) scripts are meant to me passed in the `scripts` argument to [`mkSystemsFalke`](../flakes.nix#mkSystemsFalke), which makes their functions available in the per-host `devShells`/`apps`.
The (paths to these) scripts are meant to me passed in the `scripts` argument to [`mkSystemsFlake`](../flakes.nix#mkSystemsFlake), which makes their functions available in the per-host `devShells`/`apps`.
Host-specific nix variables are available to the bash functions as `@{...}` through [`substituteImplicit`](../scripts.nix#substituteImplicit) with the respective host as root context.
With the functions from here, adding a simple three-liner can be enough to do a completely automated NixOS installation:

View File

@ -9,7 +9,7 @@ Things that really should be (more like) this by default.
```nix
#*/# end of MarkDown, beginning of NixOS module:
dirname: inputs: { config, pkgs, lib, ... }: let inherit (inputs.self) lib; in let
dirname: inputs: specialArgs@{ config, pkgs, lib, ... }: let inherit (inputs.self) lib; in let
prefix = inputs.config.prefix;
cfg = config.${prefix}.base;
in {
@ -45,6 +45,9 @@ in {
nix.nixPath = [ "nixpkgs=/etc/nix/channels/nixpkgs" "nixos-config=/etc/nixos" ];
nix.extraOptions = "experimental-features = nix-command flakes"; # apparently, even nix 2.8 (in nixos-22.05) needs this
environment.shellAliases = { "with" = ''nix-shell --run "bash --login" -p''; };
system.extraSystemBuilderCmds = (if !specialArgs?inputs && !specialArgs.inputs?self then "" else ''
ln -sT ${specialArgs.inputs.self.outPath} $out/config # (build input for reference)
'');
}) ({