]>
Commit | Line | Data |
---|---|---|
2013e82a QY |
1 | #!/bin/bash |
2 | # 2018 by David Lamparter, placed in the Public Domain | |
3 | ||
4 | help() { | |
5 | cat <<EOF | |
6 | FRR tarball/dsc helper, intended to run from a git checkout | |
7 | ||
8 | Usage: | |
9 | ./tarsource.sh [-dDn] [-i GITPATH] [-o OUTDIR] [-S KEYID] | |
10 | [-C COMMIT] [-e EXTRAVERSION] [-z gz|xz] | |
11 | ||
12 | options: | |
13 | -i GITPATH path to git working tree or bare repository. | |
14 | - default: parent directory containing this script | |
15 | -o OUTDIR path to place the generated output files in. | |
16 | - default: current directory | |
17 | -C COMMIT build tarball for specified git commit | |
18 | - default: current HEAD | |
19 | -e EXTRAVERSION override automatic package extraversion | |
20 | - default "-YYYYMMDD-NN-gGGGGGGGGGGGG", but the script | |
21 | autodetects if a release tag is checked out | |
22 | -z gz|xz compression format to use | |
23 | - default: xz | |
24 | -S KEYID sign the output with gpg key | |
25 | -d use dirty git tree with local changes | |
26 | -D generate Debian .dsc and .debian.tar.xz too | |
27 | (note: output files are moved to parent directory) | |
28 | -l remove Debian auto-build changelog entry | |
29 | (always done for releases) | |
30 | -V write version information to config.version and exit | |
31 | -n allow executing from non-git source (NOT RECOMMENDED) | |
32 | -h show this help text | |
33 | ||
34 | Note(1) that this script tries very hard to generate a deterministic, | |
35 | reproducible tarball by eliminating timestamps and similar things. However, | |
36 | since the tarball includes autoconf/automake files, the versions of these | |
37 | tools need to be _exactly_ identical to get the same tarball. | |
38 | ||
39 | Note(2) the debian ".orig" tarball is always identical to the "plain" tarball | |
40 | generated without the -D option. | |
41 | ||
42 | Note(3) if you want the tool to identify github PRs, you need to edit your | |
43 | .git/config to fetch PRs from github like this: | |
44 | ||
45 | [remote "origin"] | |
46 | url = git@github.com:frrouting/frr.git | |
47 | fetch = +refs/heads/*:refs/remotes/origin/* | |
48 | ADD: fetch = +refs/pull/*/head:refs/remotes/origin/pull/* | |
49 | EOF | |
50 | } | |
51 | ||
52 | set -e | |
53 | ||
54 | options=`getopt -o 'hi:o:C:S:e:z:DdnlV' -l help -- "$@"` | |
55 | debian=false | |
56 | dirty=false | |
57 | nongit=false | |
58 | zip=xz | |
59 | adjchangelog=false | |
60 | writeversion=false | |
61 | extraset=false | |
62 | set - $options | |
63 | while test $# -gt 0; do | |
64 | arg="$1"; shift; optarg=$1 | |
65 | case "$arg" in | |
66 | -h|--help) help; exit 0;; | |
67 | -d) dirty=true;; | |
68 | -D) debian=true;; | |
69 | -n) nongit=true;; | |
70 | -i) eval src=$optarg; shift;; | |
71 | -C) eval commit=$optarg; shift;; | |
72 | -o) eval outdir=$optarg; shift;; | |
73 | -e) eval extraver=$optarg; extraset=true; shift;; | |
74 | -z) eval zip=$optarg; shift;; | |
75 | -S) eval keyid=$optarg; shift;; | |
76 | -l) adjchangelog=true;; | |
77 | -V) writeversion=true;; | |
78 | --) break;; | |
79 | *) echo something went wrong with getopt >&2 | |
80 | exit 1 | |
81 | ;; | |
82 | esac | |
83 | done | |
84 | ||
85 | cwd="`pwd`" | |
86 | outdir="${outdir:-$cwd}" | |
87 | ||
88 | if test -e "$outdir" -a \! -d "$outdir"; then | |
89 | echo "output $outdir must be a directory" >&2 | |
90 | exit 1 | |
91 | elif test \! -d "$outdir"; then | |
92 | mkdir -p "$outdir" | |
93 | fi | |
94 | ||
95 | cd "$outdir" | |
96 | outdir="`pwd`" | |
97 | cd "$cwd" | |
98 | cd "`dirname $0`/.." | |
99 | selfdir="`pwd`" | |
100 | src="${src:-$selfdir}" | |
101 | ||
102 | if $writeversion; then | |
103 | if $nongit; then | |
104 | echo "The -V option cannot be used without a git tree" >&2 | |
105 | exit 1 | |
106 | fi | |
107 | dirty=true | |
108 | fi | |
109 | ||
110 | case "$zip" in | |
111 | gz) ziptarget=dist-gzip; ziptool="gzip -n -9"; unzip="gzip -k -c";; | |
112 | xz) ziptarget=dist-xz; ziptool="xz -z -e"; unzip="xz -d -k -c";; | |
113 | *) echo "unknown compression format $zip" >&2 | |
114 | exit 1 | |
115 | esac | |
116 | ||
117 | # always overwrite file ownership in tars | |
118 | taropt="--owner=root --group=root" | |
119 | ||
120 | onexit() { | |
121 | rv="$?" | |
122 | set +e | |
123 | test -n "$tmpdir" -a -d "$tmpdir" && rm -rf "$tmpdir" | |
124 | ||
125 | if test "$rv" -ne 0; then | |
126 | echo -e "\n\033[31;1mfailed\n" >&2 | |
127 | if test "$dirty" = true; then | |
128 | echo please try running the script without the -d option.>&2 | |
129 | fi | |
130 | fi | |
131 | exit $rv | |
132 | } | |
133 | trap onexit EXIT | |
134 | tmpdir="`mktemp -d -t frrtar.XXXXXX`" | |
135 | ||
136 | if test -e "$src/.git"; then | |
137 | commit="`git -C \"$src\" rev-parse \"${commit:-HEAD}\"`" | |
138 | ||
139 | if $dirty; then | |
140 | cd "$src" | |
141 | echo -e "\033[31;1mgit: using dirty worktree in $src\033[m" >&2 | |
142 | else | |
143 | echo -e "\033[33;1mgit: preparing a clean clone of $src\033[m" | |
144 | branch="${tmpdir##*/}" | |
145 | cd "$tmpdir" | |
146 | ||
147 | git -C "$src" branch "$branch" "$commit" | |
148 | git clone --single-branch -s -b "$branch" "$src" source | |
149 | git -C "$src" branch -D "$branch" | |
150 | cd source | |
151 | fi | |
152 | ||
153 | # if we're creating a tarball from git, force the timestamps inside | |
154 | # the tar to match the commit date - this makes the tarball itself | |
155 | # reproducible | |
156 | gitts="`TZ=UTC git show -s --format=%cd --date=local $commit`" | |
157 | gitts="`TZ=UTC date -d "$gitts" '+%Y-%m-%dT%H:%M:%SZ'`" | |
158 | taropt="--mtime=$gitts $taropt" | |
159 | ||
160 | # check if we're on a release tag | |
161 | gittag="`git -C \"$src\" describe --tags --match 'frr-*' --first-parent --long $commit`" | |
162 | gittag="${gittag%-g*}" | |
163 | gittag="${gittag%-*}" | |
164 | ||
165 | # if there have been changes to packaging or tests, it's still the | |
166 | # same release | |
167 | changes="`git diff --name-only "$gittag" $commit | \ | |
168 | egrep -v '\.git|^m4/|^config|^README|^alpine/|^debian/|^pkgsrc/|^ports/|^redhat/|^snapcraft/|^solaris/|^tests/|^tools/|^gdb/|^docker/|^\.' | \ | |
169 | wc -l`" | |
170 | if test "$changes" -eq 0; then | |
171 | adjchangelog=true | |
172 | echo "detected release build for tag $gittag" >&2 | |
173 | $extraset || extraver="" | |
174 | elif ! $adjchangelog; then | |
175 | gitdate="`TZ=UTC date -d "$gitts" '+%Y%m%d'`" | |
176 | gitrev="`git rev-parse --short $commit`" | |
177 | dayseq="`git rev-list --since \"${gitts%T*} 00:00:00 +0000\" $commit | wc -l`" | |
178 | dayseq="`printf '%02d' $(( $dayseq - 1 ))`" | |
179 | ||
180 | $extraset || extraver="-$gitdate-$dayseq-g$gitrev" | |
181 | ||
182 | git -C "$src" remote -v | grep fetch | sed -e 's% (fetch)$%%' \ | |
183 | | egrep -i '\b(git@github\.com:frrouting/frr\.git|https://github\.com/FRRouting/frr\.git)$' \ | |
184 | | while read remote; do | |
185 | remote="${remote%% *}" | |
186 | ||
187 | git -C "$src" var -l | egrep "^remote.$remote.fetch=" \ | |
188 | | while read fetch; do | |
189 | fetch="${fetch#*=}" | |
190 | from="${fetch%:*}" | |
191 | to="${fetch#*:}" | |
192 | if test "$from" = "+refs/pull/*/head"; then | |
193 | name="`git -C \"$src\" name-rev --name-only --refs \"$to\" $commit`" | |
194 | test "$name" = "undefined" && continue | |
195 | realname="${name%~*}" | |
196 | realname="${realname%%^*}" | |
197 | realname="${realname%%@*}" | |
198 | if test "$realname" = "$name"; then | |
199 | echo "${name##*/}" > "$tmpdir/.gitpr" | |
200 | break | |
201 | fi | |
202 | fi | |
203 | done || true | |
204 | test -n "$gitpr" && break | |
205 | done || true | |
206 | test $extraset = false -a -f "$tmpdir/.gitpr" && extraver="-PR`cat \"$tmpdir/.gitpr\"`$extraver" | |
207 | fi | |
208 | ||
209 | debsrc="git ls-files debian/" | |
210 | else | |
211 | if $nongit; then | |
212 | echo -e "\033[31;1mWARNING: this script should be executed from a git tree\033[m" >&2 | |
213 | else | |
214 | echo -e "\033[31;1mERROR: this script should be executed from a git tree\033[m" >&2 | |
215 | exit 1 | |
216 | fi | |
217 | debsrc="echo debian" | |
218 | fi | |
219 | ||
220 | if $writeversion; then | |
221 | pkgver="`egrep ^AC_INIT configure.ac`" | |
222 | pkgver="${pkgver#*,}" | |
223 | pkgver="${pkgver%,*}" | |
224 | pkgver="`echo $pkgver`" # strip whitespace | |
225 | pkgver="${pkgver#[}" | |
226 | pkgver="${pkgver%]}" | |
227 | ||
228 | echo -e "\033[32;1mwriting version ID \033[36;1mfrr-$pkgver$extraver\033[m" | |
229 | ||
230 | cat > config.version <<EOF | |
231 | # config.version override by tarsource.sh | |
232 | EXTRAVERSION="$extraver" | |
233 | DIST_PACKAGE_VERSION="$pkgver$extraver" | |
234 | gitts="$gitts" | |
235 | taropt="$taropt" | |
236 | EOF | |
439be082 QY |
237 | sed -e "s%@VERSION@%$pkgver$extraver%" \ |
238 | < changelog-auto.in \ | |
239 | > changelog-auto | |
2013e82a QY |
240 | exit 0 |
241 | fi | |
242 | ||
243 | echo -e "\033[33;1mpreparing source tree\033[m" | |
244 | ||
245 | # config.version will also overwrite gitts and taropt when tarsource.sh | |
246 | # was used to write the config.version file before - but configure will | |
247 | # overwrite config.version down below! | |
248 | if test -f config.version; then | |
249 | # never executed for clean git build | |
250 | . ./config.version | |
251 | if $nongit; then | |
252 | $extraset || extraver="$EXTRAVERSION" | |
253 | fi | |
254 | fi | |
255 | if test \! -f configure; then | |
256 | # always executed for clean git build | |
257 | ./bootstrap.sh | |
258 | fi | |
259 | if test "$EXTRAVERSION" != "$extraver" -o \! -f config.status; then | |
260 | # always executed for clean git build | |
261 | # options don't matter really - we just want to make a dist tarball | |
262 | ./configure --with-pkg-extra-version=$extraver | |
263 | fi | |
264 | ||
265 | . ./config.version | |
266 | PACKAGE_VERSION="$DIST_PACKAGE_VERSION" | |
267 | ||
268 | echo -e "\033[33;1mpacking up \033[36;1mfrr-$PACKAGE_VERSION\033[m" | |
269 | ||
270 | make GZIP_ENV="-n9" am__tar="tar -chof - $taropt \"\$\$tardir\"" $ziptarget | |
271 | mv frr-${PACKAGE_VERSION}.tar.$zip "$outdir" || true | |
272 | lsfiles="frr-${PACKAGE_VERSION}.tar.$zip" | |
273 | ||
274 | if $debian; then | |
439be082 QY |
275 | mkdir -p "$tmpdir/debian/source" |
276 | cat debian/changelog > "$tmpdir/debian/changelog" | |
277 | if $adjchangelog; then | |
278 | if grep -q 'autoconf changelog entry' debian/changelog; then | |
279 | tail -n +9 debian/changelog > "$tmpdir/debian/changelog" | |
280 | fi | |
2013e82a | 281 | fi |
439be082 | 282 | echo '3.0 (quilt)' > "$tmpdir/debian/source/format" |
2013e82a QY |
283 | DEBVER="`dpkg-parsechangelog -l\"$tmpdir/debian/changelog\" -SVersion`" |
284 | ||
285 | eval $debsrc | tar -cho $taropt \ | |
439be082 | 286 | --exclude-vcs --exclude debian/source/format \ |
fb0b3592 | 287 | --exclude debian/changelog \ |
439be082 QY |
288 | --exclude debian/changelog-auto \ |
289 | --exclude debian/changelog-auto.in \ | |
fb0b3592 | 290 | --exclude debian/subdir.am \ |
2013e82a QY |
291 | -T - -f ../frr_${DEBVER}.debian.tar |
292 | # add specially prepared files from above | |
439be082 | 293 | tar -uf ../frr_${DEBVER}.debian.tar $taropt -C "$tmpdir" debian/source/format debian/changelog |
2013e82a QY |
294 | |
295 | test -f ../frr_${DEBVER}.debian.tar.$zip && rm -f ../frr_${DEBVER}.debian.tar.$zip | |
296 | $ziptool ../frr_${DEBVER}.debian.tar | |
297 | ||
298 | # pack up debian files proper | |
299 | ln -s "$outdir/frr-${PACKAGE_VERSION}.tar.$zip" ../frr_${PACKAGE_VERSION}.orig.tar.$zip | |
300 | dpkg-source -l"$tmpdir/debian/changelog" \ | |
301 | --format='3.0 (custom)' --target-format='3.0 (quilt)' \ | |
302 | -b . frr_${PACKAGE_VERSION}.orig.tar.$zip frr_${DEBVER}.debian.tar.$zip | |
303 | ||
304 | dpkg-genchanges -sa -S > ../frr_${DEBVER}_source.changes | |
305 | ||
306 | test -n "$keyid" && debsign ../frr_${DEBVER}_source.changes -k"$keyid" | |
307 | ||
308 | mv ../frr_${DEBVER}_source.changes "$outdir" || true | |
309 | mv ../frr_${DEBVER}.dsc "$outdir" || true | |
310 | mv ../frr_${DEBVER}.debian.tar.$zip "$outdir" || true | |
311 | if test -h ../frr_${PACKAGE_VERSION}.orig.tar.$zip; then | |
312 | rm ../frr_${PACKAGE_VERSION}.orig.tar.$zip || true | |
313 | fi | |
314 | ln -s frr-${PACKAGE_VERSION}.tar.$zip "$outdir/frr_${PACKAGE_VERSION}.orig.tar.$zip" || true | |
315 | ||
316 | cd "$outdir" | |
317 | ||
318 | lsfiles="$lsfiles \ | |
319 | frr_${DEBVER}.dsc \ | |
320 | frr_${DEBVER}.debian.tar.$zip \ | |
321 | frr_${PACKAGE_VERSION}.orig.tar.$zip \ | |
322 | frr_${DEBVER}_source.changes" | |
323 | fi | |
324 | ||
325 | cd "$outdir" | |
326 | if test -n "$keyid"; then | |
327 | $unzip frr-${PACKAGE_VERSION}.tar.$zip > frr-${PACKAGE_VERSION}.tar | |
328 | test -f frr-${PACKAGE_VERSION}.tar.asc && rm frr-${PACKAGE_VERSION}.tar.asc | |
329 | if gpg -a --detach-sign -u "$keyid" frr-${PACKAGE_VERSION}.tar; then | |
330 | lsfiles="$lsfiles frr-${PACKAGE_VERSION}.tar.asc" | |
331 | fi | |
332 | rm frr-${PACKAGE_VERSION}.tar | |
333 | fi | |
334 | ||
335 | echo -e "\n\033[32;1mdone: \033[36;1mfrr-$PACKAGE_VERSION\033[m\n" | |
336 | ls -l $lsfiles |