-
Notifications
You must be signed in to change notification settings - Fork 42
/
Copy pathmirror.sh
executable file
·186 lines (163 loc) · 5.25 KB
/
mirror.sh
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
182
183
184
185
186
#!/bin/sh
# This script is intentionally written in POSIX sh to be cross-platform.
#
# SPDX-License-Identifier: GPL-3.0-or-later
# SPDX-FileCopyrightText: 2025 fosslinux <[email protected]>
set -e
# Check arguments, etc
if [ "$#" -lt 1 ] || [ "$#" -gt 2 ]; then
echo "Usage: $0 <destination> [state]"
exit 1
fi
dest=$1
if [ ! -d "${dest}" ]; then
echo "${dest} must be a directory"
exit 1
fi
if [ ! -w "${dest}" ]; then
echo "you must be able to write to ${dest}"
exit 1
fi
dest=$(realpath "${dest}")
state=$2
if [ "${state}" = "" ]; then
state="${PWD}/mirrorstate"
fi
state="$(realpath "${state}")"
#######
# Download a HTTP file
download_file() {
url=${1}
out=${2}
# Download the file
continue_arg=""
if [ -e "${out}" ]; then
continue_arg="-C -"
fi
# shellcheck disable=SC2086
curl -L ${continue_arg} -o "${out}" "${url}"
}
# Check if a git reference exists in a given repository
git_ref_exists() {
repo=${1}
ref=${2}
# change this to git show-ref once it is sufficiently not-new
( cd "${repo}" || exit && git cat-file -t "${ref}" >/dev/null 2>&1 )
return $?
}
checksum_file() {
sha256sum "${1}" | cut -d' ' -f1
}
do_file() {
uri=${1}
echo "${uri}"
if echo "${uri}" | grep -qE "^https?://"; then
# HTTP file
checksum=${2}
filename=${3}
if [ "${filename}" = "" ]; then
filename=$(basename "${uri}")
fi
# Check if the file is already downloaded & the checksum is the same
dest_file=${dest}/${filename}
if [ -e "${dest_file}" ]; then
existing_checksum=$(checksum_file "${dest_file}")
if [ "${checksum}" = "${existing_checksum}" ]; then
# There is nothing we need to do here
return
fi
fi
# Attempt up to 3 times
retries=3
matching=no
while [ "${retries}" -gt 0 ]; do
download_file "${uri}" "${dest}/${filename}"
my_checksum=$(checksum_file "${dest_file}")
if [ "${checksum}" = "${my_checksum}" ]; then
matching="yes"
break
fi
retries=$((retries - 1))
if [ "${retries}" -gt 0 ]; then
echo "${uri}: checksum did not match, trying again"
rm "${dest}/${filename}"
fi
sleep 1
done
if [ "${matching}" = "no" ]; then
echo "${uri}: checksums do not match"
exit 1
fi
elif echo "${uri}" | grep -qE "^git://"; then
# Creating a tarball from a git repository
# Very unfortunately, different sites have different rules.
uri_path=${uri#git://}
# GitHub does not have git:// protocol support
if echo "${uri}" | grep -Eq "^git://github.com"; then
uri=https://${uri_path}
fi
repo=${uri%~*}
outdir=${state}/git/${repo#*://}
reference=${uri##*~}
http_src=${2}
checksum=${3}
tarball=${4:-$(basename "${http_src}")}
if [ "${tarball}" = "_" ]; then
echo "${uri}: ERROR! Must have tarball name if no http source."
exit 1
fi
tarball=${dest}/${tarball}
# Check if tarball already generated + matches checksum
checksum=${3}
if [ -e "${tarball}" ]; then
existing_checksum=$(checksum_file "${tarball}")
if [ "${existing_checksum}" = "${checksum}" ]; then
return
fi
rm "${tarball}"
fi
# Clone the repository, or update it if needed
if [ ! -e "${outdir}" ]; then
mkdir -p "$(dirname "${outdir}")"
git clone "${repo}" "${outdir}"
elif ! git_ref_exists "${outdir}" "${reference}" ; then
(
cd "${outdir}" || exit
git pull
)
fi
# Sanity check: the reference we want exists
if ! git_ref_exists "${outdir}" "${reference}"; then
echo "${reference} not found in ${repo} (${outdir})"
exit 1
fi
# Generate the prefix for the tarball
prefix_ref=${reference}
# All git repositories we already use remove "v"s from the beginning
# of branch/tag names in the tarball prefix
if echo "${reference}" | grep -Eq "^v[0-9]"; then
prefix_ref=$(echo "${reference}" | sed "s/^v//")
fi
prefix=$(basename "${repo}" | sed "s/.git$//")-${prefix_ref}
(
cd "${outdir}" || exit
git config tar.tar.gz.command gzip
# -T1 avoids non-determinism due to threading
# This may not be correct for forges other than Savannah
git config tar.tar.xz.command "xz -T1"
git archive "${reference}" -o "${tarball}" --prefix "${prefix}/"
)
my_checksum=$(sha256sum "${tarball}" | cut -d' ' -f1)
if [ "${my_checksum}" != "${checksum}" ]; then
echo "${uri}: generated tarball does not match checksum"
exit 1
fi
fi
}
for src in steps/*/sources; do
while read -r line; do
# shellcheck disable=SC2086
do_file ${line}
uri=$(echo "${line}" | cut -d' ' -f1)
done < "${src}"
done