aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authortv <tv@krebsco.de>2026-11-12 02:33:44 +0000
committertv <tv@krebsco.de>2026-11-12 02:33:44 +0000
commit81cc4f06abc644b047e0758309cfbd982dac18ed (patch)
tree81ae9e2440212e976086ba7a8d0b4e6295c62e32
parent352dd5ce3107e2547db56802d773b919df03690f (diff)
populate pipe: deliver changed output of the same size
pipe sources get a fixed modification time, so rsync's quick check took changed output of the same size, e.g. a new commit hash or token, for unchanged, and didn't deliver it. pipe sources get synced comparing checksums now. An edge case changes a pipe source's output without changing its size.
-rw-r--r--pkgs/populate/default.nix4
-rwxr-xr-xtests/fixtures.sh8
-rw-r--r--tests/scenarios.nix26
3 files changed, 37 insertions, 1 deletions
diff --git a/pkgs/populate/default.nix b/pkgs/populate/default.nix
index 0992b0c..5939742 100644
--- a/pkgs/populate/default.nix
+++ b/pkgs/populate/default.nix
@@ -773,7 +773,9 @@ let
${quote source.command} > "$out"
${coreutils}/bin/touch -t 300001010000 "$out"
- ${rsync' target rsyncDefaultConfig /* sh */ "$out"}
+ # With the fixed modification time, only checksums tell outputs of the
+ # same size apart.
+ ${rsync' target (rsyncDefaultConfig // { useChecksum = true; }) /* sh */ "$out"}
'';
# TODO rm -fR instead of ln -f?
diff --git a/tests/fixtures.sh b/tests/fixtures.sh
index 1f6c478..1b39b45 100755
--- a/tests/fixtures.sh
+++ b/tests/fixtures.sh
@@ -244,6 +244,14 @@ cat > /fixtures/usedata/flake.nix <<'NIX'
NIX
printf hello > /fixtures/data/value
+# pipe2: a command for the pipe source type whose output the tests change.
+cat > /fixtures/pipe2 <<'SH'
+#! /bin/sh
+cat /fixtures/pipe2-data
+SH
+chmod +x /fixtures/pipe2
+echo piped > /fixtures/pipe2-data
+
# noflake: a directory without flake.nix.
mkdir /fixtures/noflake
echo noflake > /fixtures/noflake/README
diff --git a/tests/scenarios.nix b/tests/scenarios.nix
index f1a5958..0e54054 100644
--- a/tests/scenarios.nix
+++ b/tests/scenarios.nix
@@ -919,6 +919,32 @@ assert !(krops.isLocalTarget (targets.remote "/"));
'';
};
})
+ # Output of the same length, which rsync's quick check doesn't notice.
+ (s "pipe-change" {
+ prepareDeployer = ''
+ echo piped > /fixtures/pipe2-data
+ '';
+ phases = [
+ {
+ sources.x.pipe = "/fixtures/pipe2";
+ check = ''
+ expect_eq x "$(cat "$T"/x)" piped
+ '';
+ mutateDeployer = ''
+ echo PIPED > /fixtures/pipe2-data
+ '';
+ }
+ {
+ sources.x.pipe = "/fixtures/pipe2";
+ check = ''
+ expect_eq x "$(cat "$T"/x)" PIPED
+ '';
+ mutateDeployer = ''
+ echo piped > /fixtures/pipe2-data
+ '';
+ }
+ ];
+ })
] ++ lib.optional (targetKind == "local")
# The target has the path the input is locked to.
(s "uselocal" {