summaryrefslogtreecommitdiffstats
path: root/krebs/populate.nix
blob: 9994fda8289db90410ce64f96245caf759c7a24b (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
{ source
, target-user ? "root"
, target-host
, target-path ? "/var/src"
}:
with import <nixpkgs/lib>;
with import ~/stockholm/krebs/4lib {
  lib = import <nixpkgs/lib>;
};
with builtins;
let
  out = ''
    #! /bin/sh
    set -efu

    echo ${shell.escape git-script} \
      | ssh ${shell.escape "${target-user}@${target-host}"} -T

    tmpdir=$(mktemp -dt stockholm.XXXXXXXX)
    trap '
      set +f
      rm "$tmpdir"/*
      rmdir "$tmpdir"
      trap - EXIT INT QUIT
    '        EXIT INT QUIT
    ${concatStringsSep "\n"
      (mapAttrsToList
        (name: spec: let dst = removePrefix "symlink:" (get-url spec); in
          "ln -s ${shell.escape dst} $tmpdir/${shell.escape name}")
        symlink-specs)}

    proot \
        -b $tmpdir:${shell.escape target-path} \
        ${concatStringsSep " \\\n    "
          (mapAttrsToList
            (name: spec:
              "-b ${shell.escape "${get-url spec}:${target-path}/${name}"}")
            file-specs)} \
        rsync \
            -f ${shell.escape "P /*"} \
            ${concatMapStringsSep " \\\n        "
              (name: "-f ${shell.escape "R /${name}"}")
              (attrNames file-specs)} \
            --delete \
            -vFrlptD \
            ${shell.escape target-path}/ \
            ${shell.escape "${target-user}@${target-host}:${target-path}"}
  '';

  get-schema = uri:
    if substring 0 1 uri == "/"
      then "file"
      else head (splitString ":" uri);

  has-schema = schema: uri: get-schema uri == schema;

  get-url = spec: {
    string = spec;
    path = toString spec;
    set = get-url spec.url;
  }.${typeOf spec};

  git-specs =
    filterAttrs (_: spec: has-schema "https" (get-url spec)) source //
    filterAttrs (_: spec: has-schema "http" (get-url spec)) source //
    filterAttrs (_: spec: has-schema "git" (get-url spec)) source;

  file-specs =
    filterAttrs (_: spec: has-schema "file" (get-url spec)) source;

  symlink-specs =
    filterAttrs (_: spec: has-schema "symlink" (get-url spec)) source;

  git-script = ''
    fetch_git() {(
      dst_dir=$1
      src_url=$2
      src_ref=$3

      if ! test -e "$dst_dir"; then
        git clone "$src_url" "$dst_dir"
      fi

      cd "$dst_dir"

      if ! url=$(git config remote.origin.url); then
        git remote add origin "$src_url"
      elif test "$url" != "$src_url"; then
        git remote set-url origin "$src_url"
      fi

      # TODO resolve src_ref to commit hash
      hash=$src_ref

      if ! test "$(git log --format=%H -1)" = "$hash"; then
        git fetch origin
        git checkout "$hash" -- "$dst_dir"
        git checkout "$hash"
      fi

      git clean -dxf
    )}

    ${concatStringsSep "\n"
      (mapAttrsToList
        (name: spec: toString (map shell.escape [
          "fetch_git"
          "${target-path}/${name}"
          spec.url
          spec.rev
        ]))
        git-specs)}
  '';

in out