aboutsummaryrefslogtreecommitdiffstats
path: root/pkgs/populate
diff options
context:
space:
mode:
Diffstat (limited to 'pkgs/populate')
-rw-r--r--pkgs/populate/default.nix98
1 files changed, 97 insertions, 1 deletions
diff --git a/pkgs/populate/default.nix b/pkgs/populate/default.nix
index 221ba6e..fc577cf 100644
--- a/pkgs/populate/default.nix
+++ b/pkgs/populate/default.nix
@@ -1,7 +1,7 @@
with import ../../lib;
with shell;
-{ coreutils, dash, findutils, git, jq, openssh, pass, passage, rsync, writers }:
+{ coreutils, dash, findutils, git, jq, nix, openssh, pass, passage, rsync, writers }:
let
check = { force, target }: let
@@ -61,6 +61,93 @@ let
in
rsync' target config sourcePath;
+ pop.flake = target: source: let
+ nix' = "${nix}/bin/nix --extra-experimental-features ${quote "nix-command flakes"}";
+ input = source.input or null;
+ # jq filter selecting the flake or input in nix flake archive's output.
+ node =
+ if input == null then "."
+ else concatMapStrings (name: ".inputs[${toJSON name}]") (splitString "/" input);
+ sentinel = "${dirOf target.path}/.populate";
+ # Directory of garbage collector roots for the input's own inputs.
+ inputsRoots = "${sentinel}/flake-inputs/${baseNameOf target.path}";
+ # Reads store paths from stdin, links the first one at the target path, and
+ # registers it and the remaining ones as garbage collector roots. Roots
+ # get added before obsolete ones get removed, so the inputs stay rooted.
+ link = /* sh */ ''
+ set -efu
+ read -r path
+ if test -e ${quote target.path} && ! test -L ${quote target.path}; then
+ rm -fR ${quote target.path}
+ fi
+ nix-store --realise "$path" --add-root ${quote target.path} --indirect >/dev/null
+
+ # The sentinel only needs to exist, so it can become a directory.
+ if test -f ${quote sentinel}; then
+ rm ${quote sentinel}
+ mkdir ${quote sentinel}
+ fi
+ mkdir -p ${quote inputsRoots}
+ roots=
+ while read -r path; do
+ root=$(basename "$path")
+ if test "$(readlink ${quote inputsRoots}/"$root")" != "$path"; then
+ nix-store --realise "$path" \
+ --add-root ${quote inputsRoots}/"$root" --indirect \
+ >/dev/null
+ fi
+ roots="$roots $root"
+ done
+ ls -A ${quote inputsRoots} | while read -r root; do
+ case " $roots " in
+ *" $root "*) ;;
+ *) rm ${quote inputsRoots}/"$root" ;;
+ esac
+ done
+ # An input without own inputs leaves the directory empty.
+ if test -z "$roots"; then
+ rmdir ${quote inputsRoots}
+ fi
+ '';
+ in
+ if target.sudo then
+ throw "krops: flake source ${target.path}: targets with sudo are not supported"
+ else /* sh */ ''
+ set -efu
+
+ # Archive each flake only once, even if several sources use it.
+ archive=$TMPDIR/flake-archive.$(
+ printf %s ${quote source.flake} |
+ ${coreutils}/bin/sha256sum |
+ ${coreutils}/bin/cut -c-32
+ ).json
+ if ! test -e "$archive"; then
+ ${nix'} flake archive --json --no-update-lock-file ${quote source.flake} \
+ > "$archive"
+ fi
+
+ if ! ${jq}/bin/jq -e ${quote "${node} | .path"} "$archive" >/dev/null; then
+ >&2 printf 'error: flake %s has no input %s\n' \
+ ${quote source.flake} ${quote (toString input)}
+ exit 1
+ fi
+
+ # The input followed by its own inputs, which flakes evaluated on the
+ # target need as well.
+ paths=$(${jq}/bin/jq -r ${quote "${node} | .. | .path? | strings"} "$archive")
+
+ ${optionalString (!isLocalTarget target) /* sh */ ''
+ mkdir -p "$PWD"/bin
+ ln -fns ${sshNix' target} "$PWD"/bin/ssh
+ PATH=$PWD/bin:$PATH \
+ ${nix'} copy --to ${quote "ssh://${target.host}"} $paths >&2
+ ''}
+
+ printf '%s\n' "$paths" | {
+ ${runShell target link}
+ }
+ '';
+
pop.git = target: source: runShell target /* sh */ ''
set -efu
# Remove target path if it doesn't look like a git worktree.
@@ -268,6 +355,15 @@ let
${ssh' target} ${quote target.host} ${quote command}
'';
+ # ssh for Nix's ssh:// store. Without the control socket, because Nix waits
+ # for its LocalCommand, which may not run over a multiplexed connection.
+ sshNix' = target: writers.writeDash "ssh-nix-wrapper" ''
+ exec ${openssh}/bin/ssh \
+ ${concatMapStringsSep " " quote (mkUserPortSSHOpts target)} \
+ ${concatMapStringsSep " " quote target.extraOptions} \
+ "$@"
+ '';
+
ssh' = target: writers.writeDash "ssh-wrapper" ''
exec ${openssh}/bin/ssh \
${concatMapStringsSep " " quote (mkUserPortSSHOpts target)} \