]> git.proxmox.com Git - mirror_frr.git/blob - tools/tarsource.sh
debian: cleanly split off from dist tarball
[mirror_frr.git] / tools / tarsource.sh
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 -d "$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
226 echo -e "\033[32;1mwriting version ID \033[36;1mfrr-$pkgver$extraver\033[m"
227
228 cat > config.version <<EOF
229 # config.version override by tarsource.sh
230 EXTRAVERSION="$extraver"
231 DIST_PACKAGE_VERSION="$pkgver$extraver"
232 gitts="$gitts"
233 taropt="$taropt"
234 EOF
235 sed -e "s%@VERSION@%$pkgver$extraver%" \
236 < changelog-auto.in \
237 > changelog-auto
238 exit 0
239 fi
240
241 echo -e "\033[33;1mpreparing source tree\033[m"
242
243 # config.version will also overwrite gitts and taropt when tarsource.sh
244 # was used to write the config.version file before - but configure will
245 # overwrite config.version down below!
246 if test -f config.version; then
247 # never executed for clean git build
248 . ./config.version
249 fi
250 if test \! -f configure; then
251 # always executed for clean git build
252 ./bootstrap.sh
253 fi
254 if test "$EXTRAVERSION" != "$extraver" -o \! -f config.status; then
255 # always executed for clean git build
256 # options don't matter really - we just want to make a dist tarball
257 ./configure --with-pkg-extra-version=$extraver
258 fi
259
260 . ./config.version
261 PACKAGE_VERSION="$DIST_PACKAGE_VERSION"
262
263 echo -e "\033[33;1mpacking up \033[36;1mfrr-$PACKAGE_VERSION\033[m"
264
265 make GZIP_ENV="--best -n" am__tar="tar -chof - $taropt \"\$\$tardir\"" $ziptarget
266 mv frr-${PACKAGE_VERSION}.tar.$zip "$outdir" || true
267 lsfiles="frr-${PACKAGE_VERSION}.tar.$zip"
268
269 if $debian; then
270 mkdir -p "$tmpdir/debian/source"
271 cat debian/changelog > "$tmpdir/debian/changelog"
272 if $adjchangelog; then
273 if grep -q 'autoconf changelog entry' debian/changelog; then
274 tail -n +9 debian/changelog > "$tmpdir/debian/changelog"
275 fi
276 fi
277 echo '3.0 (quilt)' > "$tmpdir/debian/source/format"
278 DEBVER="`dpkg-parsechangelog -l\"$tmpdir/debian/changelog\" -SVersion`"
279
280 eval $debsrc | tar -cho $taropt \
281 --exclude-vcs --exclude debian/source/format \
282 --exclude debian/changelog \
283 --exclude debian/changelog-auto \
284 --exclude debian/changelog-auto.in \
285 --exclude debian/subdir.am \
286 -T - -f ../frr_${DEBVER}.debian.tar
287 # add specially prepared files from above
288 tar -uf ../frr_${DEBVER}.debian.tar $taropt -C "$tmpdir" debian/source/format debian/changelog
289
290 test -f ../frr_${DEBVER}.debian.tar.$zip && rm -f ../frr_${DEBVER}.debian.tar.$zip
291 $ziptool ../frr_${DEBVER}.debian.tar
292
293 # pack up debian files proper
294 ln -s "$outdir/frr-${PACKAGE_VERSION}.tar.$zip" ../frr_${PACKAGE_VERSION}.orig.tar.$zip
295 dpkg-source -l"$tmpdir/debian/changelog" \
296 --format='3.0 (custom)' --target-format='3.0 (quilt)' \
297 -b . frr_${PACKAGE_VERSION}.orig.tar.$zip frr_${DEBVER}.debian.tar.$zip
298
299 mv ../frr_${DEBVER}.dsc "$outdir" || true
300 mv ../frr_${DEBVER}.debian.tar.$zip "$outdir" || true
301 if test -h ../frr_${PACKAGE_VERSION}.orig.tar.$zip; then
302 rm ../frr_${PACKAGE_VERSION}.orig.tar.$zip || true
303 fi
304 ln -s frr-${PACKAGE_VERSION}.tar.$zip "$outdir/frr_${PACKAGE_VERSION}.orig.tar.$zip" || true
305
306 cd "$outdir"
307 test -n "$keyid" && debsign -k "$keyid" "frr_${DEBVER}.dsc"
308
309 lsfiles="$lsfiles \
310 frr_${DEBVER}.dsc \
311 frr_${DEBVER}.debian.tar.$zip \
312 frr_${PACKAGE_VERSION}.orig.tar.$zip"
313 fi
314
315 cd "$outdir"
316 if test -n "$keyid"; then
317 $unzip frr-${PACKAGE_VERSION}.tar.$zip > frr-${PACKAGE_VERSION}.tar
318 test -f frr-${PACKAGE_VERSION}.tar.asc && rm frr-${PACKAGE_VERSION}.tar.asc
319 if gpg -a --detach-sign -u "$keyid" frr-${PACKAGE_VERSION}.tar; then
320 lsfiles="$lsfiles frr-${PACKAGE_VERSION}.tar.asc"
321 fi
322 rm frr-${PACKAGE_VERSION}.tar
323 fi
324
325 echo -e "\n\033[32;1mdone: \033[36;1mfrr-$PACKAGE_VERSION\033[m\n"
326 ls -l $lsfiles