summaryrefslogtreecommitdiffstats
path: root/default.nix
blob: 8415348246bbf6c623e9d9c34550af949947c846 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
{ 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 <nixpkgs/lib>;
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 '<nixpkgs/nixos>')

  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
''}

''