Merge pull request #124 from numtide/nixfmt

Switch to nixfmt
This commit is contained in:
Ramses 2024-09-30 12:01:40 +02:00 committed by GitHub
commit 2690eea57a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 837 additions and 674 deletions

View file

@ -1,6 +1,4 @@
(import (import (fetchTarball {
(fetchTarball {
url = "https://github.com/edolstra/flake-compat/archive/99f1c2157fba4bfe6211a321fd0ee43199025dbf.tar.gz"; url = "https://github.com/edolstra/flake-compat/archive/99f1c2157fba4bfe6211a321fd0ee43199025dbf.tar.gz";
sha256 = "0x2jn3vrawwv9xp15674wjz9pixwjyj3j771izayl962zziivbx2"; sha256 = "0x2jn3vrawwv9xp15674wjz9pixwjyj3j771izayl962zziivbx2";
}) }) { src = ./.; }).defaultNix
{ src = ./.; }).defaultNix

View file

@ -1,4 +1,5 @@
{ lib, pkgs, ... }: { { lib, pkgs, ... }:
{
config = { config = {
nixpkgs.hostPlatform = "x86_64-linux"; nixpkgs.hostPlatform = "x86_64-linux";
@ -56,11 +57,10 @@
}; };
}; };
systemd.services = systemd.services = lib.listToAttrs (
lib.listToAttrs lib.flip lib.genList 10 (
(lib.flip lib.genList 10 (ix: ix:
lib.nameValuePair "service-${toString ix}" lib.nameValuePair "service-${toString ix}" {
{
enable = true; enable = true;
description = "service-${toString ix}"; description = "service-${toString ix}";
wants = [ "network-online.target" ]; wants = [ "network-online.target" ];
@ -76,7 +76,8 @@
script = '' script = ''
sleep ${if ix > 5 then "2" else "1"} sleep ${if ix > 5 then "2" else "1"}
''; '';
}) }
)
); );
systemd.tmpfiles.rules = [ "D /var/tmp/system-manager 0755 root root -" ]; systemd.tmpfiles.rules = [ "D /var/tmp/system-manager 0755 root root -" ];
}; };

110
flake.nix
View file

@ -39,15 +39,16 @@
}; };
outputs = outputs =
{ self {
, nixpkgs self,
, flake-utils nixpkgs,
, rust-overlay flake-utils,
, crane rust-overlay,
, devshell crane,
, treefmt-nix devshell,
, pre-commit-hooks treefmt-nix,
, ... pre-commit-hooks,
...
}@inputs: }@inputs:
{ {
lib = import ./nix/lib.nix { lib = import ./nix/lib.nix {
@ -60,17 +61,20 @@
modules = [ ./examples/example.nix ]; modules = [ ./examples/example.nix ];
}; };
} }
// // (flake-utils.lib.eachSystem
(flake-utils.lib.eachSystem
[ [
flake-utils.lib.system.x86_64-linux flake-utils.lib.system.x86_64-linux
flake-utils.lib.system.aarch64-linux flake-utils.lib.system.aarch64-linux
] ]
(system: (
system:
let let
pkgs = import nixpkgs { pkgs = import nixpkgs {
inherit system; inherit system;
overlays = [ (import rust-overlay) devshell.overlays.default ]; overlays = [
(import rust-overlay)
devshell.overlays.default
];
}; };
# TODO Pin the version for release # TODO Pin the version for release
rust = pkgs.rust-bin.stable.latest; rust = pkgs.rust-bin.stable.latest;
@ -78,7 +82,9 @@
craneLib = (crane.mkLib pkgs).overrideToolchain rust.default; craneLib = (crane.mkLib pkgs).overrideToolchain rust.default;
# Common derivation arguments used for all builds # Common derivation arguments used for all builds
commonArgs = { dbus, pkg-config }: { commonArgs =
{ dbus, pkg-config }:
{
src = craneLib.cleanCargoSource ./.; src = craneLib.cleanCargoSource ./.;
buildInputs = [ buildInputs = [
dbus dbus
@ -91,26 +97,35 @@
}; };
# Build only the cargo dependencies # Build only the cargo dependencies
cargoArtifacts = { dbus, pkg-config }: cargoArtifacts =
craneLib.buildDepsOnly ((commonArgs { inherit dbus pkg-config; }) // { { dbus, pkg-config }:
craneLib.buildDepsOnly (
(commonArgs { inherit dbus pkg-config; })
// {
pname = "system-manager"; pname = "system-manager";
}); }
);
system-manager-unwrapped = system-manager-unwrapped =
{ dbus {
, pkg-config dbus,
pkg-config,
}: }:
craneLib.buildPackage ((commonArgs { inherit dbus pkg-config; }) // { craneLib.buildPackage (
(commonArgs { inherit dbus pkg-config; })
// {
pname = "system-manager"; pname = "system-manager";
cargoArtifacts = cargoArtifacts { inherit dbus pkg-config; }; cargoArtifacts = cargoArtifacts { inherit dbus pkg-config; };
}); }
);
system-manager = system-manager =
{ dbus {
, makeBinaryWrapper dbus,
, nix makeBinaryWrapper,
, pkg-config nix,
, runCommand pkg-config,
runCommand,
}: }:
let let
unwrapped = system-manager-unwrapped { inherit dbus pkg-config; }; unwrapped = system-manager-unwrapped { inherit dbus pkg-config; };
@ -127,27 +142,35 @@
''; '';
system-manager-clippy = system-manager-clippy =
{ dbus {
, pkg-config dbus,
pkg-config,
}: }:
craneLib.cargoClippy ((commonArgs { inherit dbus pkg-config; }) // { craneLib.cargoClippy (
(commonArgs { inherit dbus pkg-config; })
// {
cargoArtifacts = cargoArtifacts { inherit dbus pkg-config; }; cargoArtifacts = cargoArtifacts { inherit dbus pkg-config; };
cargoClippyExtraArgs = "--all-targets -- --deny warnings"; cargoClippyExtraArgs = "--all-targets -- --deny warnings";
}); }
);
system-manager-test = system-manager-test =
{ dbus {
, pkg-config dbus,
pkg-config,
}: }:
craneLib.cargoTest ((commonArgs { inherit dbus pkg-config; }) // { craneLib.cargoTest (
(commonArgs { inherit dbus pkg-config; })
// {
cargoArtifacts = cargoArtifacts { inherit dbus pkg-config; }; cargoArtifacts = cargoArtifacts { inherit dbus pkg-config; };
}); }
);
# treefmt-nix configuration # treefmt-nix configuration
treefmt.config = { treefmt.config = {
projectRootFile = "flake.nix"; projectRootFile = "flake.nix";
programs = { programs = {
nixpkgs-fmt.enable = true; nixfmt.enable = true;
rustfmt = { rustfmt = {
enable = true; enable = true;
package = rust.rustfmt; package = rust.rustfmt;
@ -219,7 +242,8 @@
value = "1"; value = "1";
} }
]; ];
devshell.startup.pre-commit.text = (pre-commit-hooks.lib.${system}.run { devshell.startup.pre-commit.text =
(pre-commit-hooks.lib.${system}.run {
src = ./.; src = ./.;
hooks = { hooks = {
check-format = { check-format = {
@ -247,14 +271,18 @@
# Build the crate as part of `nix flake check` for convenience # Build the crate as part of `nix flake check` for convenience
system-manager system-manager
system-manager-clippy system-manager-clippy
system-manager-test; system-manager-test
} // ;
pkgs.lib.optionalAttrs enableVmTests (import ./test/nix/modules { }
// pkgs.lib.optionalAttrs enableVmTests (
import ./test/nix/modules {
inherit system; inherit system;
inherit (pkgs) lib; inherit (pkgs) lib;
inherit (inputs) nix-vm-test; inherit (inputs) nix-vm-test;
system-manager = self; system-manager = self;
}); }
}) );
}
)
); );
} }

View file

@ -1,7 +1,7 @@
{ nixpkgs # The nixpkgs flake {
, self # The system-manager flake nixpkgs, # The nixpkgs flake
, nixos # The path to the nixos dir from nixpkgs self, # The system-manager flake
, nixos, # The path to the nixos dir from nixpkgs
}: }:
let let
inherit (nixpkgs) lib; inherit (nixpkgs) lib;
@ -11,15 +11,29 @@ in
# reporting in module-system errors. # reporting in module-system errors.
# Usage example: # Usage example:
# { _file = "${printAttrPos (builtins.unsafeGetAttrPos "a" { a = null; })}: inline module"; } # { _file = "${printAttrPos (builtins.unsafeGetAttrPos "a" { a = null; })}: inline module"; }
printAttrPos = { file, line, column }: "${file}:${toString line}:${toString column}"; printAttrPos =
{
file,
line,
column,
}:
"${file}:${toString line}:${toString column}";
makeSystemConfig = makeSystemConfig =
{ modules {
, extraSpecialArgs ? { } modules,
extraSpecialArgs ? { },
}: }:
let let
# Module that sets additional module arguments # Module that sets additional module arguments
extraArgsModule = { lib, config, pkgs, ... }: { extraArgsModule =
{
lib,
config,
pkgs,
...
}:
{
_file = "${self.lib.printAttrPos (builtins.unsafeGetAttrPos "a" { a = null; })}: inline module"; _file = "${self.lib.printAttrPos (builtins.unsafeGetAttrPos "a" { a = null; })}: inline module";
_module.args = { _module.args = {
pkgs = nixpkgs.legacyPackages.${config.nixpkgs.hostPlatform}; pkgs = nixpkgs.legacyPackages.${config.nixpkgs.hostPlatform};
@ -31,8 +45,11 @@ in
}; };
}; };
config = (lib.evalModules { config =
specialArgs = { nixosModulesPath = "${nixos}/modules"; } // extraSpecialArgs; (lib.evalModules {
specialArgs = {
nixosModulesPath = "${nixos}/modules";
} // extraSpecialArgs;
modules = [ modules = [
extraArgsModule extraArgsModule
./modules ./modules
@ -43,13 +60,15 @@ in
system = config.nixpkgs.hostPlatform; system = config.nixpkgs.hostPlatform;
pkgs = nixpkgs.legacyPackages.${system}; pkgs = nixpkgs.legacyPackages.${system};
returnIfNoAssertions = drv: returnIfNoAssertions =
drv:
let let
failedAssertions = map (x: x.message) (lib.filter (x: !x.assertion) config.assertions); failedAssertions = map (x: x.message) (lib.filter (x: !x.assertion) config.assertions);
in in
if failedAssertions != [ ] if failedAssertions != [ ] then
then throw "\nFailed assertions:\n${lib.concatStringsSep "\n" (map (x: "- ${x}") failedAssertions)}" throw "\nFailed assertions:\n${lib.concatStringsSep "\n" (map (x: "- ${x}") failedAssertions)}"
else lib.showWarnings config.warnings drv; else
lib.showWarnings config.warnings drv;
servicesPath = pkgs.writeTextFile { servicesPath = pkgs.writeTextFile {
name = "services"; name = "services";
@ -72,16 +91,16 @@ in
toplevel = toplevel =
let let
scripts = lib.mapAttrsToList scripts = lib.mapAttrsToList (_: script: linkFarmBinEntryFromDrv script) config.build.scripts;
(_: script: linkFarmBinEntryFromDrv script)
config.build.scripts;
entries = [ entries = [
(linkFarmEntryFromDrv servicesPath) (linkFarmEntryFromDrv servicesPath)
(linkFarmEntryFromDrv etcPath) (linkFarmEntryFromDrv etcPath)
] ++ scripts; ] ++ scripts;
addPassthru = drv: drv.overrideAttrs (prevAttrs: { addPassthru =
drv:
drv.overrideAttrs (prevAttrs: {
passthru = (prevAttrs.passthru or { }) // { passthru = (prevAttrs.passthru or { }) // {
inherit config; inherit config;
}; };
@ -92,25 +111,30 @@ in
returnIfNoAssertions toplevel; returnIfNoAssertions toplevel;
mkTestPreamble = mkTestPreamble =
{ node {
, profile node,
, action profile,
}: '' action,
}:
''
${node}.succeed("${profile}/bin/${action} 2>&1 | tee /tmp/output.log") ${node}.succeed("${profile}/bin/${action} 2>&1 | tee /tmp/output.log")
${node}.succeed("! grep -F 'ERROR' /tmp/output.log") ${node}.succeed("! grep -F 'ERROR' /tmp/output.log")
''; '';
activateProfileSnippet = { node, profile }: activateProfileSnippet =
{ node, profile }:
self.lib.mkTestPreamble { self.lib.mkTestPreamble {
inherit node profile; inherit node profile;
action = "activate"; action = "activate";
}; };
deactivateProfileSnippet = { node, profile }: deactivateProfileSnippet =
{ node, profile }:
self.lib.mkTestPreamble { self.lib.mkTestPreamble {
inherit node profile; inherit node profile;
action = "deactivate"; action = "deactivate";
}; };
prepopulateProfileSnippet = { node, profile }: prepopulateProfileSnippet =
{ node, profile }:
self.lib.mkTestPreamble { self.lib.mkTestPreamble {
inherit node profile; inherit node profile;
action = "prepopulate"; action = "prepopulate";

View file

@ -1,8 +1,9 @@
{ lib {
, config lib,
, pkgs config,
, system-manager pkgs,
, ... system-manager,
...
}: }:
{ {
imports = [ imports = [
@ -31,7 +32,12 @@
type = types.listOf types.unspecified; type = types.listOf types.unspecified;
internal = true; internal = true;
default = [ ]; default = [ ];
example = [{ assertion = false; message = "you can't enable this for that reason"; }]; example = [
{
assertion = false;
message = "you can't enable this for that reason";
}
];
description = lib.mdDoc '' description = lib.mdDoc ''
This option allows modules to express conditions that must This option allows modules to express conditions that must
hold for the evaluation of the system configuration to hold for the evaluation of the system configuration to
@ -95,7 +101,12 @@
allowAnyDistro = lib.mkEnableOption "the usage of system-manager on untested distributions"; allowAnyDistro = lib.mkEnableOption "the usage of system-manager on untested distributions";
preActivationAssertions = lib.mkOption { preActivationAssertions = lib.mkOption {
type = with lib.types; attrsOf (submodule ({ name, ... }: { type =
with lib.types;
attrsOf (
submodule (
{ name, ... }:
{
options = { options = {
enable = lib.mkEnableOption "the assertion"; enable = lib.mkEnableOption "the assertion";
@ -108,7 +119,9 @@
type = types.str; type = types.str;
}; };
}; };
})); }
)
);
default = { }; default = { };
}; };
}; };
@ -140,17 +153,22 @@
system-manager.preActivationAssertions = { system-manager.preActivationAssertions = {
osVersion = osVersion =
let let
supportedIds = [ "nixos" "ubuntu" ]; supportedIds = [
"nixos"
"ubuntu"
];
in in
{ {
enable = !config.system-manager.allowAnyDistro; enable = !config.system-manager.allowAnyDistro;
script = '' script = ''
source /etc/os-release source /etc/os-release
${lib.concatStringsSep "\n" (lib.flip map supportedIds (supportedId: '' ${lib.concatStringsSep "\n" (
lib.flip map supportedIds (supportedId: ''
if [ $ID = "${supportedId}" ]; then if [ $ID = "${supportedId}" ]; then
exit 0 exit 0
fi fi
''))} '')
)}
echo "This OS is not currently supported." echo "This OS is not currently supported."
echo "Supported OSs are: ${lib.concatStringsSep ", " supportedIds}" echo "Supported OSs are: ${lib.concatStringsSep ", " supportedIds}"
exit 1 exit 1
@ -184,7 +202,9 @@
preActivationAssertionScript = preActivationAssertionScript =
let let
mkAssertion = { name, script, ... }: '' mkAssertion =
{ name, script, ... }:
''
# ${name} # ${name}
echo -e "Evaluating pre-activation assertion ${name}...\n" echo -e "Evaluating pre-activation assertion ${name}...\n"
@ -199,12 +219,10 @@
fi fi
''; '';
mkAssertions = assertions: mkAssertions =
assertions:
lib.concatStringsSep "\n" ( lib.concatStringsSep "\n" (
lib.mapAttrsToList (name: mkAssertion) ( lib.mapAttrsToList (name: mkAssertion) (lib.filterAttrs (name: cfg: cfg.enable) assertions)
lib.filterAttrs (name: cfg: cfg.enable)
assertions
)
); );
in in
pkgs.writeShellScript "preActivationAssertions" '' pkgs.writeShellScript "preActivationAssertions" ''
@ -230,7 +248,9 @@
# TODO: handle globbing # TODO: handle globbing
etc = etc =
let let
addToStore = name: file: pkgs.runCommandLocal "${name}-etc-link" { } '' addToStore =
name: file:
pkgs.runCommandLocal "${name}-etc-link" { } ''
mkdir -p "$out/$(dirname "${file.target}")" mkdir -p "$out/$(dirname "${file.target}")"
ln -s "${file.source}" "$out/${file.target}" ln -s "${file.source}" "$out/${file.target}"
@ -241,32 +261,27 @@
fi fi
''; '';
filteredEntries = lib.filterAttrs filteredEntries = lib.filterAttrs (_name: etcFile: etcFile.enable) config.environment.etc;
(_name: etcFile: etcFile.enable)
config.environment.etc;
srcDrvs = lib.mapAttrs addToStore filteredEntries; srcDrvs = lib.mapAttrs addToStore filteredEntries;
entries = lib.mapAttrs entries = lib.mapAttrs (name: file: file // { source = "${srcDrvs.${name}}"; }) filteredEntries;
(name: file: file // { source = "${srcDrvs.${name}}"; })
filteredEntries;
staticEnv = pkgs.buildEnv { staticEnv = pkgs.buildEnv {
name = "etc-static-env"; name = "etc-static-env";
paths = lib.attrValues srcDrvs; paths = lib.attrValues srcDrvs;
}; };
in in
{ inherit entries staticEnv; }; {
inherit entries staticEnv;
};
services = services = lib.mapAttrs' (
lib.mapAttrs' unitName: unit:
(unitName: unit:
lib.nameValuePair unitName { lib.nameValuePair unitName {
storePath = storePath = ''${unit.unit}/${unitName}'';
''${unit.unit}/${unitName}''; }
}) ) (lib.filterAttrs (_: unit: unit.enable) config.systemd.units);
(lib.filterAttrs (_: unit: unit.enable)
config.systemd.units);
}; };
}; };
} }

View file

@ -1,4 +1,9 @@
{ lib, config, pkgs, ... }: {
lib,
config,
pkgs,
...
}:
{ {
options.environment = { options.environment = {
@ -24,8 +29,7 @@
]; ];
etc = { etc = {
"profile.d/system-manager-path.sh".source = "profile.d/system-manager-path.sh".source = pkgs.writeText "system-manager-path.sh" ''
pkgs.writeText "system-manager-path.sh" ''
export PATH=${pathDir}/bin/:''${PATH} export PATH=${pathDir}/bin/:''${PATH}
''; '';

View file

@ -1,6 +1,7 @@
{ lib {
, pkgs lib,
, ... pkgs,
...
}: }:
{ {
options = { options = {
@ -18,8 +19,14 @@
Set of files that have to be linked in {file}`/etc`. Set of files that have to be linked in {file}`/etc`.
''; '';
type = lib.types.attrsOf (lib.types.submodule ( type = lib.types.attrsOf (
{ name, config, options, ... }: lib.types.submodule (
{
name,
config,
options,
...
}:
{ {
options = { options = {
@ -105,12 +112,15 @@
config = { config = {
target = lib.mkDefault name; target = lib.mkDefault name;
source = lib.mkIf (config.text != null) ( source = lib.mkIf (config.text != null) (
let name' = "etc-" + baseNameOf name; let
in lib.mkDerivedConfig options.text (pkgs.writeText name') name' = "etc-" + baseNameOf name;
in
lib.mkDerivedConfig options.text (pkgs.writeText name')
); );
}; };
} }
)); )
);
}; };
}; };
} }

View file

@ -1,8 +1,9 @@
{ lib {
, config lib,
, pkgs config,
, utils pkgs,
, ... utils,
...
}: }:
let let
@ -19,14 +20,28 @@ in
# We could consider copying the systemd lib from NixOS and removing the bits # We could consider copying the systemd lib from NixOS and removing the bits
# that are not relevant to us, like this option. # that are not relevant to us, like this option.
package = lib.mkOption { package = lib.mkOption {
type = lib.types.oneOf [ lib.types.str lib.types.path lib.types.package ]; type = lib.types.oneOf [
lib.types.str
lib.types.path
lib.types.package
];
default = pkgs.systemdMinimal; default = pkgs.systemdMinimal;
}; };
globalEnvironment = lib.mkOption { globalEnvironment = lib.mkOption {
type = with lib.types; attrsOf (nullOr (oneOf [ str path package ])); type =
with lib.types;
attrsOf (
nullOr (oneOf [
str
path
package
])
);
default = { }; default = { };
example = { TZ = "CET"; }; example = {
TZ = "CET";
};
description = lib.mdDoc '' description = lib.mdDoc ''
Environment variables passed to *all* systemd units. Environment variables passed to *all* systemd units.
''; '';
@ -104,7 +119,9 @@ in
generators = lib.mkOption { generators = lib.mkOption {
type = lib.types.attrsOf lib.types.path; type = lib.types.attrsOf lib.types.path;
default = { }; default = { };
example = { systemd-gpt-auto-generator = "/dev/null"; }; example = {
systemd-gpt-auto-generator = "/dev/null";
};
description = lib.mdDoc '' description = lib.mdDoc ''
Definition of systemd generators. Definition of systemd generators.
For each `NAME = VALUE` pair of the attrSet, a link is generated from For each `NAME = VALUE` pair of the attrSet, a link is generated from
@ -129,14 +146,10 @@ in
wantedBy = [ "default.target" ]; wantedBy = [ "default.target" ];
}; };
timers = timers = lib.mapAttrs (name: service: {
lib.mapAttrs
(name: service:
{
wantedBy = [ "timers.target" ]; wantedBy = [ "timers.target" ];
timerConfig.OnCalendar = service.startAt; timerConfig.OnCalendar = service.startAt;
}) }) (lib.filterAttrs (name: service: service.enable && service.startAt != [ ]) cfg.services);
(lib.filterAttrs (name: service: service.enable && service.startAt != [ ]) cfg.services);
units = units =
lib.mapAttrs' (n: v: lib.nameValuePair "${n}.path" (systemd-lib.pathToUnit v)) cfg.paths lib.mapAttrs' (n: v: lib.nameValuePair "${n}.path" (systemd-lib.pathToUnit v)) cfg.paths
@ -145,16 +158,24 @@ in
// lib.mapAttrs' (n: v: lib.nameValuePair "${n}.socket" (systemd-lib.socketToUnit v)) cfg.sockets // lib.mapAttrs' (n: v: lib.nameValuePair "${n}.socket" (systemd-lib.socketToUnit v)) cfg.sockets
// lib.mapAttrs' (n: v: lib.nameValuePair "${n}.target" (systemd-lib.targetToUnit v)) cfg.targets // lib.mapAttrs' (n: v: lib.nameValuePair "${n}.target" (systemd-lib.targetToUnit v)) cfg.targets
// lib.mapAttrs' (n: v: lib.nameValuePair "${n}.timer" (systemd-lib.timerToUnit v)) cfg.timers // lib.mapAttrs' (n: v: lib.nameValuePair "${n}.timer" (systemd-lib.timerToUnit v)) cfg.timers
// lib.listToAttrs (map // lib.listToAttrs (
(v: map (
let n = utils.escapeSystemdPath v.where; v:
in lib.nameValuePair "${n}.mount" (systemd-lib.mountToUnit v)) let
cfg.mounts) n = utils.escapeSystemdPath v.where;
// lib.listToAttrs (map in
(v: lib.nameValuePair "${n}.mount" (systemd-lib.mountToUnit v)
let n = utils.escapeSystemdPath v.where; ) cfg.mounts
in lib.nameValuePair "${n}.automount" (systemd-lib.automountToUnit v)) )
cfg.automounts); // lib.listToAttrs (
map (
v:
let
n = utils.escapeSystemdPath v.where;
in
lib.nameValuePair "${n}.automount" (systemd-lib.automountToUnit v)
) cfg.automounts
);
}; };
environment.etc = environment.etc =
@ -164,7 +185,8 @@ in
enabledUnits = lib.filterAttrs (_: unit: unit.enable) cfg.units; enabledUnits = lib.filterAttrs (_: unit: unit.enable) cfg.units;
in in
{ {
"systemd/system".source = pkgs.runCommand "system-manager-units" "systemd/system".source =
pkgs.runCommand "system-manager-units"
{ {
preferLocalBuild = true; preferLocalBuild = true;
allowSubstitutes = false; allowSubstitutes = false;
@ -178,13 +200,18 @@ in
if [ "$(readlink -f $i/$fn)" = /dev/null ]; then if [ "$(readlink -f $i/$fn)" = /dev/null ]; then
ln -sfn /dev/null $out/$fn ln -sfn /dev/null $out/$fn
else else
${if allowCollisions then '' ${
if allowCollisions then
''
mkdir -p $out/$fn.d mkdir -p $out/$fn.d
ln -s $i/$fn $out/$fn.d/overrides.conf ln -s $i/$fn $out/$fn.d/overrides.conf
'' else '' ''
else
''
echo "Found multiple derivations configuring $fn!" echo "Found multiple derivations configuring $fn!"
exit 1 exit 1
''} ''
}
fi fi
else else
ln -fs $i/$fn $out/ ln -fs $i/$fn $out/
@ -192,20 +219,24 @@ in
done done
${lib.concatStrings ( ${lib.concatStrings (
lib.mapAttrsToList (name: unit: lib.mapAttrsToList (
name: unit:
lib.concatMapStrings (name2: '' lib.concatMapStrings (name2: ''
mkdir -p $out/'${name2}.wants' mkdir -p $out/'${name2}.wants'
ln -sfn '../${name}' $out/'${name2}.wants'/ ln -sfn '../${name}' $out/'${name2}.wants'/
'') (unit.wantedBy or []) '') (unit.wantedBy or [ ])
) enabledUnits)} ) enabledUnits
)}
${lib.concatStrings ( ${lib.concatStrings (
lib.mapAttrsToList (name: unit: lib.mapAttrsToList (
name: unit:
lib.concatMapStrings (name2: '' lib.concatMapStrings (name2: ''
mkdir -p $out/'${name2}.requires' mkdir -p $out/'${name2}.requires'
ln -sfn '../${name}' $out/'${name2}.requires'/ ln -sfn '../${name}' $out/'${name2}.requires'/
'') (unit.requiredBy or []) '') (unit.requiredBy or [ ])
) enabledUnits)} ) enabledUnits
)}
''; '';
}; };
}; };

View file

@ -1,11 +1,14 @@
{ nixosModulesPath {
, lib nixosModulesPath,
, ... lib,
...
}: }:
{ {
imports = [ imports =
[
./nginx.nix ./nginx.nix
] ++ ]
++
# List of imported NixOS modules # List of imported NixOS modules
# TODO: how will we manage this in the long term? # TODO: how will we manage this in the long term?
map (path: nixosModulesPath + path) [ map (path: nixosModulesPath + path) [
@ -14,7 +17,6 @@
"/services/web-servers/nginx/" "/services/web-servers/nginx/"
]; ];
options = options =
# We need to ignore a bunch of options that are used in NixOS modules but # We need to ignore a bunch of options that are used in NixOS modules but
# that don't apply to system-manager configs. # that don't apply to system-manager configs.

View file

@ -5,4 +5,3 @@ let
}; };
in in
(import compat { src = ./.; }).shellNix.default (import compat { src = ./.; }).shellNix.default

View file

@ -1,42 +1,55 @@
{ lib {
, system-manager lib,
, system system-manager,
, nix-vm-test system,
nix-vm-test,
}: }:
let let
forEachUbuntuImage = forEachUbuntuImage =
name: name:
{ modules {
, testScriptFunction modules,
, extraPathsToRegister ? [ ] testScriptFunction,
, projectTest ? test: test.sandboxed extraPathsToRegister ? [ ],
projectTest ? test: test.sandboxed,
}: }:
let let
ubuntu = nix-vm-test.lib.${system}.ubuntu; ubuntu = nix-vm-test.lib.${system}.ubuntu;
in in
lib.listToAttrs (lib.flip map (lib.attrNames ubuntu.images) lib.listToAttrs (
(imageVersion: lib.flip map (lib.attrNames ubuntu.images) (
imageVersion:
let let
toplevel = (system-manager.lib.makeSystemConfig { toplevel = (
system-manager.lib.makeSystemConfig {
modules = modules ++ [ modules = modules ++ [
({ lib, pkgs, ... }: { (
options.hostPkgs = lib.mkOption { type = lib.types.raw; readOnly = true; }; { lib, pkgs, ... }:
{
options.hostPkgs = lib.mkOption {
type = lib.types.raw;
readOnly = true;
};
config.hostPkgs = pkgs; config.hostPkgs = pkgs;
}) }
)
]; ];
}); }
);
inherit (toplevel.config) hostPkgs; inherit (toplevel.config) hostPkgs;
in in
lib.nameValuePair "ubuntu-${imageVersion}-${name}" lib.nameValuePair "ubuntu-${imageVersion}-${name}" (
(projectTest projectTest (
(ubuntu.${imageVersion} { ubuntu.${imageVersion} {
testScript = testScriptFunction { inherit toplevel hostPkgs; }; testScript = testScriptFunction { inherit toplevel hostPkgs; };
extraPathsToRegister = extraPathsToRegister ++ [ extraPathsToRegister = extraPathsToRegister ++ [
toplevel toplevel
]; ];
sharedDirs = { }; sharedDirs = { };
})) }
)
)
) )
); );
@ -44,7 +57,10 @@ let
# and one that cannot. # and one that cannot.
# The id parameter is a string that can be used to force reloading the services # The id parameter is a string that can be used to force reloading the services
# between two configs by changing their contents. # between two configs by changing their contents.
testModule = id: { lib, pkgs, ... }: { testModule =
id:
{ lib, pkgs, ... }:
{
systemd.services = { systemd.services = {
has-reload = { has-reload = {
enable = true; enable = true;
@ -78,7 +94,9 @@ let
newConfig = system-manager.lib.makeSystemConfig { newConfig = system-manager.lib.makeSystemConfig {
modules = [ modules = [
(testModule "new") (testModule "new")
({ lib, pkgs, ... }: { (
{ lib, pkgs, ... }:
{
config = { config = {
nixpkgs.hostPlatform = system; nixpkgs.hostPlatform = system;
@ -107,27 +125,32 @@ let
RemainAfterExit = true; RemainAfterExit = true;
ExecReload = "${lib.getBin pkgs.coreutils}/bin/true"; ExecReload = "${lib.getBin pkgs.coreutils}/bin/true";
}; };
wantedBy = [ "system-manager.target" "default.target" ]; wantedBy = [
"system-manager.target"
"default.target"
];
script = '' script = ''
sleep 2 sleep 2
''; '';
}; };
}; };
}; };
}) }
)
]; ];
}; };
in in
forEachUbuntuImage "example" forEachUbuntuImage "example" {
{
modules = [ modules = [
(testModule "old") (testModule "old")
../../../examples/example.nix ../../../examples/example.nix
]; ];
extraPathsToRegister = [ newConfig ]; extraPathsToRegister = [ newConfig ];
testScriptFunction = { toplevel, ... }: '' testScriptFunction =
{ toplevel, ... }:
''
# Start all machines in parallel # Start all machines in parallel
start_all() start_all()
@ -138,7 +161,10 @@ forEachUbuntuImage "example"
vm.succeed("grep -F 'Error while creating file in /etc: Unmanaged path already exists in filesystem, please remove it and run system-manager again: /etc/foo_test' /tmp/output.log") vm.succeed("grep -F 'Error while creating file in /etc: Unmanaged path already exists in filesystem, please remove it and run system-manager again: /etc/foo_test' /tmp/output.log")
vm.succeed("rm /etc/foo_test") vm.succeed("rm /etc/foo_test")
${system-manager.lib.activateProfileSnippet { node = "vm"; profile = toplevel; }} ${system-manager.lib.activateProfileSnippet {
node = "vm";
profile = toplevel;
}}
vm.wait_for_unit("system-manager.target") vm.wait_for_unit("system-manager.target")
vm.succeed("systemctl status service-9.service") vm.succeed("systemctl status service-9.service")
@ -150,7 +176,10 @@ forEachUbuntuImage "example"
vm.succeed("test -d /var/tmp/system-manager") vm.succeed("test -d /var/tmp/system-manager")
${system-manager.lib.activateProfileSnippet { node = "vm"; profile = newConfig; }} ${system-manager.lib.activateProfileSnippet {
node = "vm";
profile = newConfig;
}}
vm.succeed("systemctl status new-service.service") vm.succeed("systemctl status new-service.service")
vm.fail("systemctl status service-9.service") vm.fail("systemctl status service-9.service")
vm.fail("test -f /etc/a/nested/example/foo3") vm.fail("test -f /etc/a/nested/example/foo3")
@ -177,28 +206,36 @@ forEachUbuntuImage "example"
vm.fail("test -f /etc/baz/bar/foo2") vm.fail("test -f /etc/baz/bar/foo2")
vm.succeed("test -f /etc/foo_new") vm.succeed("test -f /etc/foo_new")
${system-manager.lib.deactivateProfileSnippet { node = "vm"; profile = newConfig; }} ${system-manager.lib.deactivateProfileSnippet {
node = "vm";
profile = newConfig;
}}
vm.fail("systemctl status new-service.service") vm.fail("systemctl status new-service.service")
vm.fail("test -f /etc/foo_new") vm.fail("test -f /etc/foo_new")
#vm.fail("test -f /var/tmp/system-manager/foo1") #vm.fail("test -f /var/tmp/system-manager/foo1")
''; '';
} }
// //
forEachUbuntuImage "prepopulate" { forEachUbuntuImage "prepopulate" {
modules = [ modules = [
(testModule "old") (testModule "old")
../../../examples/example.nix ../../../examples/example.nix
]; ];
extraPathsToRegister = [ newConfig ]; extraPathsToRegister = [ newConfig ];
testScriptFunction = { toplevel, ... }: '' testScriptFunction =
{ toplevel, ... }:
''
# Start all machines in parallel # Start all machines in parallel
start_all() start_all()
vm.wait_for_unit("default.target") vm.wait_for_unit("default.target")
${system-manager.lib.prepopulateProfileSnippet { node = "vm"; profile = toplevel; }} ${system-manager.lib.prepopulateProfileSnippet {
node = "vm";
profile = toplevel;
}}
vm.systemctl("daemon-reload") vm.systemctl("daemon-reload")
# Simulate a reboot, to check that the services defined with # Simulate a reboot, to check that the services defined with
@ -218,28 +255,36 @@ forEachUbuntuImage "prepopulate" {
vm.succeed("grep -F 'launch_the_rockets = true' /etc/foo.conf") vm.succeed("grep -F 'launch_the_rockets = true' /etc/foo.conf")
vm.fail("grep -F 'launch_the_rockets = false' /etc/foo.conf") vm.fail("grep -F 'launch_the_rockets = false' /etc/foo.conf")
${system-manager.lib.activateProfileSnippet { node = "vm"; profile = newConfig; }} ${system-manager.lib.activateProfileSnippet {
node = "vm";
profile = newConfig;
}}
vm.succeed("systemctl status new-service.service") vm.succeed("systemctl status new-service.service")
vm.fail("systemctl status service-9.service") vm.fail("systemctl status service-9.service")
vm.fail("test -f /etc/a/nested/example/foo3") vm.fail("test -f /etc/a/nested/example/foo3")
vm.fail("test -f /etc/baz/bar/foo2") vm.fail("test -f /etc/baz/bar/foo2")
vm.succeed("test -f /etc/foo_new") vm.succeed("test -f /etc/foo_new")
${system-manager.lib.deactivateProfileSnippet { node = "vm"; profile = newConfig; }} ${system-manager.lib.deactivateProfileSnippet {
node = "vm";
profile = newConfig;
}}
vm.fail("systemctl status new-service.service") vm.fail("systemctl status new-service.service")
vm.fail("test -f /etc/foo_new") vm.fail("test -f /etc/foo_new")
''; '';
} }
// //
forEachUbuntuImage "system-path" { forEachUbuntuImage "system-path" {
modules = [ modules = [
(testModule "old") (testModule "old")
../../../examples/example.nix ../../../examples/example.nix
]; ];
extraPathsToRegister = [ newConfig ]; extraPathsToRegister = [ newConfig ];
testScriptFunction = { toplevel, hostPkgs, ... }: '' testScriptFunction =
{ toplevel, hostPkgs, ... }:
''
# Start all machines in parallel # Start all machines in parallel
start_all() start_all()
vm.wait_for_unit("default.target") vm.wait_for_unit("default.target")
@ -247,7 +292,10 @@ forEachUbuntuImage "system-path" {
vm.fail("bash --login -c '$(which rg)'") vm.fail("bash --login -c '$(which rg)'")
vm.fail("bash --login -c '$(which fd)'") vm.fail("bash --login -c '$(which fd)'")
${system-manager.lib.activateProfileSnippet { node = "vm"; profile = toplevel; }} ${system-manager.lib.activateProfileSnippet {
node = "vm";
profile = toplevel;
}}
vm.wait_for_unit("system-manager.target") vm.wait_for_unit("system-manager.target")
vm.wait_for_unit("system-manager-path.service") vm.wait_for_unit("system-manager-path.service")
@ -256,10 +304,13 @@ forEachUbuntuImage "system-path" {
vm.succeed("bash --login -c 'realpath $(which rg) | grep -F ${hostPkgs.ripgrep}/bin/rg'") vm.succeed("bash --login -c 'realpath $(which rg) | grep -F ${hostPkgs.ripgrep}/bin/rg'")
vm.succeed("bash --login -c 'realpath $(which fd) | grep -F ${hostPkgs.fd}/bin/fd'") vm.succeed("bash --login -c 'realpath $(which fd) | grep -F ${hostPkgs.fd}/bin/fd'")
${system-manager.lib.activateProfileSnippet { node = "vm"; profile = newConfig; }} ${system-manager.lib.activateProfileSnippet {
node = "vm";
profile = newConfig;
}}
vm.fail("bash --login -c '$(which rg)'") vm.fail("bash --login -c '$(which rg)'")
vm.fail("bash --login -c '$(which fd)'") vm.fail("bash --login -c '$(which fd)'")
vm.succeed("bash --login -c 'realpath $(which fish) | grep -F ${hostPkgs.fish}/bin/fish'") vm.succeed("bash --login -c 'realpath $(which fish) | grep -F ${hostPkgs.fish}/bin/fish'")
''; '';
} }