diff options
| -rw-r--r-- | pkgs/krops/default.nix | 54 | ||||
| -rw-r--r-- | tests/scenarios.nix | 60 |
2 files changed, 74 insertions, 40 deletions
diff --git a/pkgs/krops/default.nix b/pkgs/krops/default.nix index 3aa68cf..ac2d9a2 100644 --- a/pkgs/krops/default.nix +++ b/pkgs/krops/default.nix @@ -8,22 +8,41 @@ in flake ? null, useNixOutputMonitor }: - args: target: + args: target: let + # The flake's directory in the target directory, and the name of the + # NixOS configuration with its #, if any. + flakeDir = lib.head (lib.splitString "#" flake); + flakeAttr = lib.removePrefix flakeDir flake; + in runShell target {} (withNixOutputMonitor target useNixOutputMonitor /* sh */ '' - ${lib.optionalString (flake != null) - (lib.shell.requireFlakes "deploying a flake")} + ${lib.optionalString (flake != null) /* sh */ '' + ${lib.shell.requireFlakes "deploying a flake"} + ${lib.shell.urlPath} + # A Git work tree gets deployed as such. Anything else gets + # deployed as path:, not just by its path, which Nix takes for the + # enclosing Git work tree, if any. Nix refuses URLs with symlinks + # on the way, which the target directory may be, or the source. + flake=$(readlink -f ${lib.escapeShellArg "${target.path}/${flakeDir}"}) + if test -e "$flake"/.git; then + if test -e "$flake"/.gitmodules; then + flake=git+file:$(url_path "$flake")?submodules=1 + else + flake=git+file:$(url_path "$flake") + fi + else + flake=path:$(url_path "$flake") + fi + ''} NIX_PATH=${lib.escapeShellArg target.path} \ - nixos-rebuild ${lib.escapeShellArgs (args ++ lib.optionals (flake != null) [ - "--flake" - # Generated flakes as path:, not just their paths, which Nix takes - # for the enclosing Git work tree, if any. - (lib.optionalString (lib.hasPrefix ".populate/flakes/" flake) "path:" + - "${target.path}/${flake}") - ])} ${lib.optionalString (flake == null) - # nixos-rebuild deploys /etc/nixos/flake.nix if it exists. Any - # nixos-rebuild doing so supports --no-flake. - "$(test -e /etc/nixos/flake.nix && echo --no-flake)"} + nixos-rebuild ${lib.escapeShellArgs args} ${ + if flake != null then + ''--flake "$flake"${lib.escapeShellArg flakeAttr}'' + else + # nixos-rebuild deploys /etc/nixos/flake.nix if it exists. Any + # nixos-rebuild doing so supports --no-flake. + "$(test -e /etc/nixos/flake.nix && echo --no-flake)" + } ''); runShell = target: { @@ -117,6 +136,11 @@ in then target' else lib.mkTarget buildTarget; target' = lib.mkTarget target; + # A host as nixos-rebuild takes it. Without a user, ssh decides. + userHost = target: + lib.optionalString (target.user != null && target.user != "") + "${target.user}@" + + target.host; # The source's generated flake, if it draws inputs from other sources. flake' = let name = lib.head (lib.splitString "#" flake); @@ -140,8 +164,8 @@ in ] ++ lib.optionals crossDeploy [ "--no-build-nix" ] ++ lib.optionals (buildTarget' != target') [ - "--build-host" "${buildTarget'.user}@${buildTarget'.host}" - "--target-host" "${target'.user}@${target'.host}" + "--build-host" (userHost buildTarget') + "--target-host" (userHost target') ] ++ lib.optionals (buildTarget' != target' && target'.sudo) [ # nixos-rebuild runs on the target itself via sudo otherwise. "--use-remote-sudo" diff --git a/tests/scenarios.nix b/tests/scenarios.nix index 849d3e3..a7dff66 100644 --- a/tests/scenarios.nix +++ b/tests/scenarios.nix @@ -585,29 +585,33 @@ assert !(krops.isLocalTarget (targets.remote "/")); }); # writeDeploy's arguments to nixos-rebuild, which a stand-in records. + # flake is what gets deployed: nothing, or a flake from a file, git, or + # flake source, or one whose inputs get drawn from a source, by rewriting + # its lock file or through a generated flake. deploy = matrix "deploy" { - flake = [ "none" "source" "rewrite" "generated" ]; + flake = [ "none" "file" "git" "source" "rewrite" "generated" ]; etcFlake = [ false true ]; buildTarget = [ false true ]; } (flags: ctx: let target = targets.${ctx.targetKind} ctx.path; buildTarget = targets.local "${ctx.path}-build"; build = if flags.buildTarget then buildTarget else target; + # Without a user, ssh decides. + userHost = target: + optionalString (target.user != null && target.user != "") "${target.user}@" + + target.host; expected = [ "switch" ] ++ optionals flags.buildTarget [ - "--build-host" "${buildTarget.user}@${buildTarget.host}" - "--target-host" "${target.user}@${target.host}" + "--build-host" (userHost buildTarget) + "--target-host" (userHost target) ] - ++ optional (flags.buildTarget && target.sudo) "--use-remote-sudo" - ++ { - none = []; - source = [ "--flake" "${build.path}/x" ]; - rewrite = [ "--flake" "${build.path}/x" ]; - # Generated flakes as path:, which an enclosing Git work tree doesn't - # capture. - generated = [ "--flake" "path:${build.path}/.populate/flakes/x" ]; - }.${flags.flake} - ++ optional (flags.etcFlake && flags.flake == "none") "--no-flake"; + ++ optional (flags.buildTarget && target.sudo) "--use-remote-sudo"; + # The flake's directory, which gets deployed by its resolved path, as + # path:, so no enclosing Git work tree captures it, or as the Git work + # tree it is. + flakeDir = + if flags.flake == "generated" then ".populate/flakes/x" else "x"; + scheme = if flags.flake == "git" then "git+file" else "path"; in # The local target can't have another build target. if flags.buildTarget && ctx.targetKind == "local" then null else { @@ -623,17 +627,18 @@ assert !(krops.isLocalTarget (targets.remote "/")); ''} ''; phases = twice { - sources = - if flags.flake == "none" then { - x.file = "/fixtures/alt"; - } else alt // { - x.flake = { - url = "/fixtures/top"; - fetchOnTarget = ctx.targetKind == "sudo"; - } // drawInputs (if flags.flake == "source" then "none" else flags.flake) { - dep.follows = "alt"; - }; + sources = { + none.x.file = "/fixtures/alt"; + file.x.file = "/fixtures/alt"; + git.x.git = { url = gitUrl; ref = gitHead; }; + }.${flags.flake} or (alt // { + x.flake = { + url = "/fixtures/top"; + fetchOnTarget = ctx.targetKind == "sudo"; + } // drawInputs (if flags.flake == "source" then "none" else flags.flake) { + dep.follows = "alt"; }; + }); deploy = { flake = if flags.flake == "none" then null else "x"; } // optionalAttrs flags.buildTarget { @@ -642,8 +647,13 @@ assert !(krops.isLocalTarget (targets.remote "/")); check = '' expect_eq user "$(sed -n 1p /tmp/nixos-rebuild.log)" 0 expect_eq NIX_PATH "$(sed -n 2p /tmp/nixos-rebuild.log)" ${build.path} - expect_eq arguments "$(sed -n 3p /tmp/nixos-rebuild.log)" \ - ${lib.escapeShellArg (concatStringsSep " " expected)} + expected=${lib.escapeShellArg (concatStringsSep " " expected)} + ${if flags.flake == "none" then optionalString flags.etcFlake '' + expected="$expected --no-flake" + '' else '' + expected="$expected --flake ${scheme}:$(readlink -f ${build.path}/${flakeDir})" + ''} + expect_eq arguments "$(sed -n 3p /tmp/nixos-rebuild.log)" "$expected" ''; }; }); |
