Expose the config in the passthru and move values into the config.

This commit is contained in:
r-vdp 2023-06-29 22:29:55 +02:00
parent 1454525760
commit 46ecaad91e
No known key found for this signature in database
2 changed files with 158 additions and 121 deletions

View file

@ -26,6 +26,7 @@ in
utils = import "${nixos}/lib/utils.nix" { utils = import "${nixos}/lib/utils.nix" {
inherit lib config pkgs; inherit lib config pkgs;
}; };
inherit (self.packages.${config.nixpkgs.hostPlatform}) system-manager;
}; };
}; };
@ -40,7 +41,6 @@ in
# Get the system as it was defined in the modules. # Get the system as it was defined in the modules.
system = config.nixpkgs.hostPlatform; system = config.nixpkgs.hostPlatform;
pkgs = nixpkgs.legacyPackages.${system}; pkgs = nixpkgs.legacyPackages.${system};
inherit (self.packages.${system}) system-manager;
returnIfNoAssertions = drv: returnIfNoAssertions = drv:
let let
@ -50,143 +50,45 @@ in
then throw "\nFailed assertions:\n${lib.concatStringsSep "\n" (map (x: "- ${x}") failedAssertions)}" then throw "\nFailed assertions:\n${lib.concatStringsSep "\n" (map (x: "- ${x}") failedAssertions)}"
else lib.showWarnings config.warnings drv; else lib.showWarnings config.warnings drv;
services =
lib.mapAttrs'
(unitName: unit:
lib.nameValuePair unitName {
storePath =
''${unit.unit}/${unitName}'';
})
(lib.filterAttrs (_: unit: unit.enable)
config.systemd.units);
servicesPath = pkgs.writeTextFile { servicesPath = pkgs.writeTextFile {
name = "services"; name = "services";
destination = "/services.json"; destination = "/services.json";
text = lib.generators.toJSON { } services; text = lib.generators.toJSON { } config.build.services;
}; };
# TODO: handle globbing
etcFiles =
let
addToStore = name: file: pkgs.runCommandLocal "${name}-etc-link" { } ''
mkdir -p "$out/$(dirname "${file.target}")"
ln -s "${file.source}" "$out/${file.target}"
if [ "${file.mode}" != symlink ]; then
echo "${file.mode}" > "$out/${file.target}.mode"
echo "${file.user}" > "$out/${file.target}.uid"
echo "${file.group}" > "$out/${file.target}.gid"
fi
'';
filteredEntries = lib.filterAttrs
(_name: etcFile: etcFile.enable)
config.environment.etc;
srcDrvs = lib.mapAttrs addToStore filteredEntries;
entries = lib.mapAttrs
(name: file: file // { source = "${srcDrvs.${name}}"; })
filteredEntries;
staticEnv = pkgs.buildEnv {
name = "etc-static-env";
paths = lib.attrValues srcDrvs;
};
in
{ inherit entries staticEnv; };
etcPath = pkgs.writeTextFile { etcPath = pkgs.writeTextFile {
name = "etcFiles"; name = "etcFiles";
destination = "/etcFiles.json"; destination = "/etcFiles.json";
text = lib.generators.toJSON { } etcFiles; text = lib.generators.toJSON { } { inherit (config.build.etc) entries staticEnv; };
}; };
registerProfileScript = pkgs.writeShellScript "register-profile" ''
${system-manager}/bin/system-manager register \
--store-path "$(dirname $(realpath $(dirname ''${0})))" \
"$@"
'';
activationScript = pkgs.writeShellScript "activate" ''
${system-manager}/bin/system-manager activate \
--store-path "$(dirname $(realpath $(dirname ''${0})))" \
"$@"
'';
prepopulateScript = pkgs.writeShellScript "prepopulate" ''
${system-manager}/bin/system-manager pre-populate \
--store-path "$(dirname $(realpath $(dirname ''${0})))" \
"$@"
'';
deactivationScript = pkgs.writeShellScript "deactivate" ''
${system-manager}/bin/system-manager deactivate "$@"
'';
preActivationAssertionScript =
let
mkAssertion = { name, script, ... }: ''
# ${name}
echo -e "Evaluating pre-activation assertion ${name}...\n"
(
set +e
${script}
)
assertion_result=$?
if [ $assertion_result -ne 0 ]; then
failed_assertions+=${name}
fi
'';
mkAssertions = assertions:
lib.concatStringsSep "\n" (
lib.mapAttrsToList (name: mkAssertion) (
lib.filterAttrs (name: cfg: cfg.enable)
assertions
)
);
in
pkgs.writeShellScript "preActivationAssertions" ''
set -ou pipefail
declare -a failed_assertions=()
${mkAssertions config.system-manager.preActivationAssertions}
if [ ''${#failed_assertions[@]} -ne 0 ]; then
for failed_assertion in ''${failed_assertions[@]}; do
echo "Pre-activation assertion $failed_assertion failed."
done
echo "See the output above for more details."
exit 1
else
echo "All pre-activation assertions succeeded."
exit 0
fi
'';
linkFarmNestedEntryFromDrv = dirs: drv: { linkFarmNestedEntryFromDrv = dirs: drv: {
name = lib.concatStringsSep "/" (dirs ++ [ "${drv.name}" ]); name = lib.concatStringsSep "/" (dirs ++ [ "${drv.name}" ]);
path = drv; path = drv;
}; };
linkFarmEntryFromDrv = linkFarmNestedEntryFromDrv [ ]; linkFarmEntryFromDrv = linkFarmNestedEntryFromDrv [ ];
linkFarmBinEntryFromDrv = linkFarmNestedEntryFromDrv [ "bin" ]; linkFarmBinEntryFromDrv = linkFarmNestedEntryFromDrv [ "bin" ];
toplevel =
let
scripts = lib.mapAttrsToList
(_: script: linkFarmBinEntryFromDrv script)
config.build.scripts;
entries = [
(linkFarmEntryFromDrv servicesPath)
(linkFarmEntryFromDrv etcPath)
] ++ scripts;
addPassthru = drv: drv.overrideAttrs (prevAttrs: {
passthru = (prevAttrs.passthru or { }) // {
inherit config;
};
});
in
addPassthru (pkgs.linkFarm "system-manager" entries);
in in
returnIfNoAssertions ( returnIfNoAssertions toplevel;
pkgs.linkFarm "system-manager" [
(linkFarmEntryFromDrv servicesPath)
(linkFarmEntryFromDrv etcPath)
(linkFarmBinEntryFromDrv activationScript)
(linkFarmBinEntryFromDrv prepopulateScript)
(linkFarmBinEntryFromDrv deactivationScript)
(linkFarmBinEntryFromDrv registerProfileScript)
(linkFarmBinEntryFromDrv preActivationAssertionScript)
]
);
# TODO: put these in an external JSON file that we can automatically update # TODO: put these in an external JSON file that we can automatically update
images.ubuntu = { images.ubuntu = {

View file

@ -1,5 +1,7 @@
{ lib { lib
, config , config
, pkgs
, system-manager
, ... , ...
}: }:
{ {
@ -109,6 +111,28 @@
default = { }; default = { };
}; };
}; };
build = {
scripts = lib.mkOption {
type = lib.types.attrsOf lib.types.package;
};
etc = {
staticEnv = lib.mkOption {
type = lib.types.package;
};
entries = lib.mkOption {
# TODO: better type
type = lib.types.attrsOf lib.types.raw;
};
};
services = lib.mkOption {
# TODO: better type
type = lib.types.attrsOf lib.types.raw;
};
};
}; };
config = { config = {
@ -132,5 +156,116 @@
''; '';
}; };
}; };
build = {
scripts = {
registerProfileScript = pkgs.writeShellScript "register-profile" ''
${system-manager}/bin/system-manager register \
--store-path "$(dirname $(realpath $(dirname ''${0})))" \
"$@"
'';
activationScript = pkgs.writeShellScript "activate" ''
${system-manager}/bin/system-manager activate \
--store-path "$(dirname $(realpath $(dirname ''${0})))" \
"$@"
'';
prepopulateScript = pkgs.writeShellScript "prepopulate" ''
${system-manager}/bin/system-manager pre-populate \
--store-path "$(dirname $(realpath $(dirname ''${0})))" \
"$@"
'';
deactivationScript = pkgs.writeShellScript "deactivate" ''
${system-manager}/bin/system-manager deactivate "$@"
'';
preActivationAssertionScript =
let
mkAssertion = { name, script, ... }: ''
# ${name}
echo -e "Evaluating pre-activation assertion ${name}...\n"
(
set +e
${script}
)
assertion_result=$?
if [ $assertion_result -ne 0 ]; then
failed_assertions+=${name}
fi
'';
mkAssertions = assertions:
lib.concatStringsSep "\n" (
lib.mapAttrsToList (name: mkAssertion) (
lib.filterAttrs (name: cfg: cfg.enable)
assertions
)
);
in
pkgs.writeShellScript "preActivationAssertions" ''
set -ou pipefail
declare -a failed_assertions=()
${mkAssertions config.system-manager.preActivationAssertions}
if [ ''${#failed_assertions[@]} -ne 0 ]; then
for failed_assertion in ''${failed_assertions[@]}; do
echo "Pre-activation assertion $failed_assertion failed."
done
echo "See the output above for more details."
exit 1
else
echo "All pre-activation assertions succeeded."
exit 0
fi
'';
};
# TODO: handle globbing
etc =
let
addToStore = name: file: pkgs.runCommandLocal "${name}-etc-link" { } ''
mkdir -p "$out/$(dirname "${file.target}")"
ln -s "${file.source}" "$out/${file.target}"
if [ "${file.mode}" != symlink ]; then
echo "${file.mode}" > "$out/${file.target}.mode"
echo "${file.user}" > "$out/${file.target}.uid"
echo "${file.group}" > "$out/${file.target}.gid"
fi
'';
filteredEntries = lib.filterAttrs
(_name: etcFile: etcFile.enable)
config.environment.etc;
srcDrvs = lib.mapAttrs addToStore filteredEntries;
entries = lib.mapAttrs
(name: file: file // { source = "${srcDrvs.${name}}"; })
filteredEntries;
staticEnv = pkgs.buildEnv {
name = "etc-static-env";
paths = lib.attrValues srcDrvs;
};
in
{ inherit entries staticEnv; };
services =
lib.mapAttrs'
(unitName: unit:
lib.nameValuePair unitName {
storePath =
''${unit.unit}/${unitName}'';
})
(lib.filterAttrs (_: unit: unit.enable)
config.systemd.units);
};
}; };
} }