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
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
|
#!/bin/sh
set -eu
quiet=
name="fetchdarcs"
repository=
tag=
context=
darcs_hash=
exp_hash=
usage() {
echo "Usage: nix-prefetch-darcs [options] [REPOSITORY] [FILENAME [EXPECTED-HASH]]"
echo
echo "Options:"
echo " --quiet Suppress most error messages."
echo " --name <NAME> Symbolic store path name to use for the result."
echo " --repo <REPOSITORY> URL for the Darcs repository."
echo " --tag <REGEXP> Clone specified by tag matching a regular expression."
echo " --context <FILENAME> Clone specified by context file."
echo " --darcs-hash <HASH> Clone specified by hash. WARN: hash order is fickle by design."
echo " --hash <HASH> Expected hash."
echo " --help Show this help message."
}
# Argument parsing
while [ $# -gt 0 ]; do
case "$1" in
--quiet)
quiet=1; shift 1 ;;
--name)
name="$2"; shift 2 ;;
--repo)
repository="$2"; shift 2 ;;
--tag)
tag="$2"; shift 2 ;;
--context)
context="$2"; shift 2 ;;
--darcs-hash)
darcs_hash="$2"; shift 2 ;;
--hash)
exp_hash="$2"; shift 2 ;;
--help)
usage; exit 0 ;;
*)
# Positional arguments
if [ -z "$repository" ]; then
repository="$1"
shift
elif [ -z "$context" ]; then
context="$1"
shift
elif [ -z "$exp_hash" ]; then
exp_hash="$1"
shift
else
echo "Error: Too many arguments" >&2
usage
exit 1
fi
;;
esac
done
if [ -z "$repository" ]; then
echo "Error: URL for repository is required." >&2
echo >&2
usage
exit 1
fi
state_flag_count=0
[ -n "$tag" ] && state_flag_count=$(( state_flag_count + 1 ))
[ -n "$context" ] && state_flag_count=$(( state_flag_count + 1 ))
[ -n "$darcs_hash" ] && state_flag_count=$(( state_flag_count + 1 ))
if [ "$state_flag_count" -gt 1 ]; then
echo "Error: no more than 1 of --tag, --context, --darcs-hash flags can be set. $state_flag_count were set." >&2
echo >&2
usage
exit 1
elif [ -n "$context" ]; then
if [ ! -s "$context" ]; then
echo "Error: context file must be readable & non-empty @ “$context”" >&2
echo >&2
usage
exit 1
else
context="$(realpath "$context")"
fi
fi
weak_hash=
hash=
hash_algo="${NIX_HASH_ALGO:-"sha256"}"
hash_format="${hashFormat:-"--base32"}"
final_path=
final_context=
# If the hash was given, a file with that hash may already be in the
# store.
if [ -n "$exp_hash" ]; then
final_path=$(nix-store --print-fixed-path --recursive "$hash_algo" "$exp_hash" "$name")
if ! nix-store --check-validity "$final_path" 2> /dev/null; then
final_path=""
fi
hash="$exp_hash"
fi
# If we don’t know the hash or a path with that hash doesn’t exist,
# download the file and add it to the store.
if [ -z "$final_path" ]; then
tmp_clone="$(realpath ${quiet:+--quiet} "$(mktemp ${quiet:+--quiet} -d --tmpdir darcs-clone-tmp-XXXXXXXX)")"
trap "rm -rf \"$tmp_clone\"" EXIT
clone_args="--lazy"
if [ -n "$quiet" ]; then
clone_args="$clone_args --quiet"
fi
if [ -n "$tag" ]; then
clone_args="$clone_args --tag=$tag"
elif [ -n "$context" ]; then
clone_args="$clone_args --context=$context"
elif [ -n "$darcs_hash" ]; then
clone_args="$clone_args --to-hash=$darcs_hash"
fi
cd "$tmp_clone"
# Do not print Darcs progress to stdout (else stdout isn’t parsable JSON)
darcs clone "$clone_args" "$repository" "$name" 1>&2
# Will put the current Darcs context into the store.
new_context="$tmp_clone/${name}-context.txt"
darcs log --repodir="$tmp_clone/$name" --context > "$new_context"
final_context="$(nix-store --add-fixed "$hash_algo" "$new_context")"
# Darcs has a weak hash using the XOR of the patch hashes which is useful
# for other scripts
# https://darcs.net/Internals/Hashes
weak_hash="$(darcs show repo --repodir="$tmp_clone/$name" | awk '/^[[:space:]]*Weak Hash:/ { sub(/^[[:space:]]*Weak Hash:[[:space:]]*/, "", $0); printf $0 }')"
date="$(darcs log --repodir="$tmp_clone/$name" --max-count 1 | awk '/^Date:/ { sub(/^Date:[[:space:]]*/, "", $0); printf $0 }')"
date="$(date -u -d "$date" "+%Y-%m-%dT%H:%M:%SZ")"
rm -rf "$tmp_clone/$name/_darcs"
hash="$(nix-hash --type "$hash_algo" "$hash_format" "$tmp_clone/$name")"
final_path=$(nix-store --add-fixed --recursive "$hash_algo" "$tmp_clone/$name")
if [ -n "$exp_hash" ] && [ "$exp_hash" != "$hash" ]; then
echo "Hash mismatch for “$repository”" >&2
echo "Expected: $exp_hash" >&2
echo "Got: $hash" >&2
exit 1
fi
fi
json_escape() {
printf '%s' "$1" | jq -Rs .
}
cat <<EOF
{
"repository": $(json_escape "$repository"),
EOF
if [ -n "$tag" ]; then cat <<EOF
"tag": $(json_escape "$tag"),
EOF
elif [ -n "$darcs_hash" ]; then cat <<EOF
"darcs-hash": $(json_escape "$darcs_hash"),
EOF
fi; if [ -n "$weak_hash" ]; then cat <<EOF
"weak-hash": $(json_escape "$weak_hash"),
EOF
fi; if [ -s "$final_context" ]; then cat <<EOF
"context": $(json_escape "$final_context"),
EOF
fi; cat <<EOF
"date": "$date",
"path": "$final_path",
$(json_escape "$hash_algo"): $(json_escape "$hash"),
"hash": "$(nix-hash --to-sri --type "$hash_algo" "$hash")"
}
EOF
# vim: noet ci pi sts=0
|