1{
2 lib,
3 writeShellApplication,
4 coreutils,
5 git,
6 nix,
7 common-updater-scripts,
8}:
9
10# This is an updater for unstable packages that should always use the latest
11# commit.
12# To use this updater, add the following to your package set:
13# passthru.updateScript = unstableGitUpdater { };
14# relevant attributes can be passed as below:
15
16{
17 url ? null, # The git url, if empty it will be set to src.gitRepoUrl
18 branch ? null,
19 hardcodeZeroVersion ? false, # Use a made-up version "0" instead of latest tag. Use when the project's tagging system is incompatible with what we expect from versions
20 tagFormat ? "*", # A `git describe --tags --match '<format>'` pattern that tags must match to be considered
21 tagPrefix ? null, # strip this prefix from a tag name
22 tagConverter ? null, # A command to convert more complex tag formats. It receives the git tag via stdin and should convert it into x.y.z format to stdout
23 shallowClone ? true,
24}:
25
26assert lib.asserts.assertMsg (
27 tagPrefix == null || tagConverter == null
28) "Can only use either tagPrefix or tagConverter!";
29
30let
31 updateScript = writeShellApplication {
32 name = "unstable-update-script";
33 runtimeInputs = [
34 common-updater-scripts
35 coreutils
36 git
37 nix
38 ];
39 text = ''
40 set -ex
41
42 url=""
43 branch=""
44 hardcode_zero_version=""
45 tag_format=""
46 tag_prefix=""
47 tag_converter=""
48 shallow_clone=""
49 : "''${systemArg:=}"
50
51 while (( $# > 0 )); do
52 flag="$1"
53 shift 1
54 case "$flag" in
55 --url=*)
56 url="''${flag#*=}"
57 ;;
58 --branch=*)
59 branch="''${flag#*=}"
60 ;;
61 --hardcode-zero-version)
62 hardcode_zero_version=1
63 ;;
64 --tag-format=*)
65 tag_format="''${flag#*=}"
66 ;;
67 --tag-prefix=*)
68 tag_prefix="''${flag#*=}"
69 ;;
70 --tag-converter=*)
71 tag_converter="''${flag#*=}"
72 ;;
73 --shallow-clone)
74 shallow_clone=1
75 ;;
76 *)
77 echo "$0: unknown option ‘''${flag}’"
78 exit 1
79 ;;
80 esac
81 done
82
83 # By default we set url to src.gitRepoUrl
84 if [[ -z "$url" ]]; then
85 # system argument cannot be passed as 1 argument
86 # shellcheck disable=SC2086
87 url="$(nix-instantiate $systemArg --eval -E \
88 "with import ./. {}; $UPDATE_NIX_ATTR_PATH.src.gitRepoUrl" \
89 | tr -d '"')"
90 fi
91
92 # Get info about HEAD from a shallow git clone
93 tmpdir="$(mktemp -d)"
94
95 cloneArgs=()
96
97 if [[ "$shallow_clone" == "1" ]]; then
98 cloneArgs+=(--depth=1)
99 fi
100
101 if [[ -n "$branch" ]]; then
102 cloneArgs+=(--branch="$branch")
103 fi
104
105 git clone "''${cloneArgs[@]}" "$url" "$tmpdir"
106 getLatestVersion() {
107 git describe --tags --abbrev=0 --match "''${tag_format}" 2> /dev/null || true
108 }
109
110 pushd "$tmpdir"
111 commit_date="$(git show -s --pretty='format:%cs')"
112 commit_sha="$(git show -s --pretty='format:%H')"
113 last_tag=""
114 if [[ -z "$hardcode_zero_version" ]]; then
115 if [[ "$shallow_clone" == "1" ]]; then
116 depth=100
117 while (( depth < 10000 )); do
118 last_tag="$(getLatestVersion)"
119 if [[ -n "$last_tag" ]]; then
120 break
121 fi
122 git fetch --depth="$depth" --tags
123 depth=$(( depth * 2 ))
124 done
125
126 if [[ -z "$last_tag" ]]; then
127 # To be extra sure, check if full history helps with finding a tag
128 git fetch --tags
129 last_tag="$(getLatestVersion)"
130 fi
131 else
132 last_tag="$(getLatestVersion)"
133 fi
134 if [[ -z "$last_tag" ]]; then
135 last_tag="0"
136 fi
137 if [[ -n "$tag_prefix" ]]; then
138 echo "Stripping prefix '$tag_prefix' from tag '$last_tag'"
139 last_tag="''${last_tag#"''${tag_prefix}"}"
140 fi
141 if [[ -n "$tag_converter" ]]; then
142 echo "Running '$last_tag' through: $tag_converter"
143 last_tag="$(echo "''${last_tag}" | ''${tag_converter})"
144 fi
145 else
146 last_tag="0"
147 fi
148 if [[ ! "$last_tag" =~ ^[[:digit:]] ]]; then
149 echo "Last tag '$last_tag' does not start with a digit" > /dev/stderr
150 exit 1
151 fi
152 new_version="$last_tag-unstable-$commit_date"
153 popd
154 # rm -rf "$tmpdir"
155
156 # update the nix expression
157 update-source-version \
158 "$UPDATE_NIX_ATTR_PATH" \
159 "$new_version" \
160 --rev="$commit_sha"
161 '';
162 };
163
164in
165[
166 (lib.getExe updateScript)
167 "--url=${builtins.toString url}"
168 "--tag-format=${tagFormat}"
169]
170++ lib.optionals (branch != null) [
171 "--branch=${branch}"
172]
173++ lib.optionals (tagPrefix != null) [
174 "--tag-prefix=${tagPrefix}"
175]
176++ lib.optionals (tagConverter != null) [
177 "--tag-converter=${tagConverter}"
178]
179++ lib.optionals hardcodeZeroVersion [
180 "--hardcode-zero-version"
181]
182++ lib.optionals shallowClone [
183 "--shallow-clone"
184]