{ system-name , rsync-target ? null , deploy-target ? null }: # TODO assert that only one of rsync-target or deploy-target is not null with builtins; assert (typeOf system-name == "string"); with import ; let paths-file = toPath "${dirOf __curPos.file}/modules/${system-name}/paths.nix"; paths = import paths-file; prefetch.file = '' echo "$prefetch_in_url" ''; prefetch.git = '' ${concatMapStringsSep "\n" (attr-name: '' case ''${prefetch_in_${escapeShellArg attr-name}-?} in \?) printf '%s: %s: missing attribute: %s' \ ${escapeShellArg paths-file} \ "$prefetch_name" \ ${escapeShellArg attr-name} \ >&2 return 1 esac '') [ "rev" "url" "cache" ]} git_rev=$prefetch_in_rev git_url=$prefetch_in_url # cache_dir points to a (maybe non-existent) directory, where a shared cache of # the repository should be maintained. The shared cache is used to create # multiple working trees of the repository. cache_dir=$prefetch_in_cache/$(echo "$git_url" | urlencode) cache_git() { git --git-dir="$cache_dir" "$@" } # work_dir points to a (maybe non-existent) directory, where a specific # revision of the repository is checked out. # XXX this is probably a bad idea if git_rev is not a commit work_dir=$cache_dir-$(cache_git rev-parse --verify "$git_rev" | urlencode) work_git() { git -C "$work_dir" "$@" } is_up_to_date() { test -d "$cache_dir" && test -d "$work_dir" && test "$(cache_git rev-parse --verify "$git_rev")" = "$git_rev" && test "$(work_git rev-parse --verify HEAD)" = "$git_rev" } # Notice how the remote name "origin" has been chosen arbitrarily, but must be # kept in sync with the default value of nixpkgs.rev. if ! is_up_to_date; then if ! test -d "$cache_dir"; then mkdir -p "$cache_dir" cache_git init --bare fi if ! cache_git_url=$(cache_git config remote.origin.url); then cache_git remote add origin "$git_url" elif test "$cache_git_url" != "$git_url"; then cache_git remote set-url origin "$git_url" fi cache_git fetch origin if ! test -d "$work_dir"; then git clone -n --shared "$cache_dir" "$work_dir" fi commit_name=$(cache_git rev-parse --verify "$git_rev") work_git checkout "$commit_name" -- "$(readlink -f "$work_dir")" work_git checkout -q "$commit_name" work_git submodule init work_git submodule update fi work_git clean -dxf echo "$work_dir" ''; f = pkg-name: pkg-spec: let types = attrNames pkg-spec; type = elemAt types 0; in assert (length types == 1); # there can be only one source type '' out=$(${concatStringsSep " \\\n" (mapAttrsToList (k: v: "prefetch_in_${escapeShellArg k}=${escapeShellArg (toString v)}") pkg-spec.${type})} \ prefetch_name=${escapeShellArg pkg-name} \ __prefetch_${escapeShellArg type}) printf '%s=%s\n' \ ${escapeShellArg pkg-name} \ "$out" ''; in '' #! /bin/sh set -euf PATH=${toString ./.}/bin:$PATH export PATH __prefetch_file() { ${prefetch.file} } __prefetch_git() { ${prefetch.git} } # TODO make sure x contains only sane chars x=$(${concatStrings (mapAttrsToList f paths)}) ${optionalString (rsync-target != null) '' proot $(echo "$x" | sed -n 's@^\([^=]\+\)=\(.*\)@-b \2:/shitment/\1@p') \ rsync --delete --delete-excluded \ --filter='- /*/.git' \ --rsync-path='mkdir -p -m 0700 /shitment/ && rsync' \ -vaz \ --no-owner \ --no-group \ '/shitment/' \ ${escapeShellArg rsync-target} ''} ${optionalString (deploy-target != null) '' system_path=$(proot $(echo "$x" | sed -n 's@^\([^=]\+\)=\(.*\)@-b \2:/shitment/\1@p') \ env \ NIX_PATH=/shitment \ NIXOS_CONFIG=/shitment/modules/${escapeShellArg system-name} \ nix-build -A system --no-out-link '') system_name=${escapeShellArg system-name} target=${escapeShellArg deploy-target} nix-copy-closure --gzip --to "$target" "$system_path" secrets_root=${toString ./.}/secrets \ config_root=${toString ./.} \ copy-secrets "$system_name" "$target" ssh ''${NIX_SSHOPTS-} "$target" "$system_path/bin/switch-to-configuration" switch ''} ''