From 32eeb3aeda1519acbc15c120693aebc95cbd5c38 Mon Sep 17 00:00:00 2001 From: tv Date: Thu, 12 Nov 2026 20:25:15 +0000 Subject: krops writeDeploy: deploy every flake by a URL Nix can't misread nixos-rebuild gets generated flakes as path: URLs, but other flakes by their bare paths, which Nix takes for the enclosing Git work tree, if the target directory lies in one. A file source there fails to deploy, because the work tree doesn't track it. Every flake gets deployed by a URL: a Git work tree as git+file:, with submodules if it has any, like populate refers to it, and anything else as path:. The path gets resolved on the build target, because Nix refuses URLs with symlinks on the way, which the target directory may be, and percent-encoded. --build-host and --target-host name no user if the target has none, instead of failing to evaluate. The deploy test also deploys flakes from file and git sources. Its scenarios evaluate without LOGNAME. --- tests/scenarios.nix | 60 +++++++++++++++++++++++++++++++---------------------- 1 file changed, 35 insertions(+), 25 deletions(-) (limited to 'tests') 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" ''; }; }); -- cgit v1.3.1