]> git.proxmox.com Git - mirror_frr.git/commitdiff
tools: add new tarsource.sh helper
authorDavid Lamparter <equinox@diac24.net>
Wed, 24 Oct 2018 15:01:11 +0000 (17:01 +0200)
committerDavid Lamparter <equinox@diac24.net>
Tue, 18 Dec 2018 00:55:51 +0000 (01:55 +0100)
It cleans your house and cooks dinner.  Or maybe it creates a clean dist
tarball for you, plus a Debian .dsc if you have dpkg installed - and
GPG-signs the result appropriately if requested.

In any case the resulting tarball should be distributed for our
releases.

Signed-off-by: David Lamparter <equinox@diac24.net>
tools/tarsource.sh [new file with mode: 0755]

diff --git a/tools/tarsource.sh b/tools/tarsource.sh
new file mode 100755 (executable)
index 0000000..a40a597
--- /dev/null
@@ -0,0 +1,324 @@
+#!/bin/bash
+# 2018 by David Lamparter, placed in the Public Domain
+
+help() {
+       cat <<EOF
+FRR tarball/dsc helper, intended to run from a git checkout
+
+Usage:
+       ./tarsource.sh [-dDn] [-i GITPATH] [-o OUTDIR] [-S KEYID]
+                       [-C COMMIT] [-e EXTRAVERSION] [-z gz|xz]
+
+options:
+    -i GITPATH         path to git working tree or bare repository.
+                       - default: parent directory containing this script
+    -o OUTDIR          path to place the generated output files in.
+                       - default: current directory
+    -C COMMIT          build tarball for specified git commit
+                       - default: current HEAD
+    -e EXTRAVERSION    override automatic package extraversion
+                       - default "-YYYYMMDD-NN-gGGGGGGGGGGGG", but the script
+                         autodetects if a release tag is checked out
+    -z gz|xz           compression format to use
+                       - default: xz
+    -S KEYID           sign the output with gpg key
+    -d                 use dirty git tree with local changes
+    -D                 generate Debian .dsc and .debian.tar.xz too
+                       (note: output files are moved to parent directory)
+    -l                 remove Debian auto-build changelog entry
+                       (always done for releases)
+    -V                 write version information to config.version and exit
+    -n                 allow executing from non-git source (NOT RECOMMENDED)
+    -h                 show this help text
+
+Note(1) that this script tries very hard to generate a deterministic,
+reproducible tarball by eliminating timestamps and similar things.  However,
+since the tarball includes autoconf/automake files, the versions of these
+tools need to be _exactly_ identical to get the same tarball.
+
+Note(2) the debian ".orig" tarball is always identical to the "plain" tarball
+generated without the -D option.
+
+Note(3) if you want the tool to identify github PRs, you need to edit your
+.git/config to fetch PRs from github like this:
+
+       [remote "origin"]
+               url = git@github.com:frrouting/frr.git
+               fetch = +refs/heads/*:refs/remotes/origin/*
+ADD:           fetch = +refs/pull/*/head:refs/remotes/origin/pull/*
+EOF
+}
+
+set -e
+
+options=`getopt -o 'hi:o:C:S:e:z:DdnlV' -l help -- "$@"`
+debian=false
+dirty=false
+nongit=false
+zip=xz
+adjchangelog=false
+writeversion=false
+extraset=false
+set - $options
+while test $# -gt 0; do
+       arg="$1"; shift; optarg=$1
+       case "$arg" in
+       -h|--help)      help; exit 0;;
+       -d)             dirty=true;;
+       -D)             debian=true;;
+       -n)             nongit=true;;
+       -i)             eval src=$optarg; shift;;
+       -C)             eval commit=$optarg; shift;;
+       -o)             eval outdir=$optarg; shift;;
+       -e)             eval extraver=$optarg; extraset=true; shift;;
+       -z)             eval zip=$optarg; shift;;
+       -S)             eval keyid=$optarg; shift;;
+       -l)             adjchangelog=true;;
+       -V)             writeversion=true;;
+       --)             break;;
+       *)              echo something went wrong with getopt >&2
+                       exit 1
+                       ;;
+       esac
+done
+
+cwd="`pwd`"
+outdir="${outdir:-$cwd}"
+
+if test -e "$outdir" -a \! -d "$outdir"; then
+       echo "output $outdir must be a directory" >&2
+       exit 1
+elif test \! -d "$outdir"; then
+       mkdir -p "$outdir"
+fi
+
+cd "$outdir"
+outdir="`pwd`"
+cd "$cwd"
+cd "`dirname $0`/.."
+selfdir="`pwd`"
+src="${src:-$selfdir}"
+
+if $writeversion; then
+       if $nongit; then
+               echo "The -V option cannot be used without a git tree" >&2
+               exit 1
+       fi
+       dirty=true
+fi
+
+case "$zip" in
+gz)    ziptarget=dist-gzip; ziptool="gzip -n -9"; unzip="gzip -k -c";;
+xz)    ziptarget=dist-xz;   ziptool="xz -z -e";   unzip="xz -d -k -c";;
+*)     echo "unknown compression format $zip" >&2
+       exit 1
+esac
+
+# always overwrite file ownership in tars
+taropt="--owner=root --group=root"
+
+onexit() {
+       rv="$?"
+       set +e
+       test -n "$tmpdir" -a -d "$tmpdir" && rm -rf "$tmpdir"
+
+       if test "$rv" -ne 0; then
+               echo -e "\n\033[31;1mfailed\n" >&2
+               if test "$dirty" = true; then
+                       echo please try running the script without the -d option.>&2
+               fi
+       fi
+       exit $rv
+}
+trap onexit EXIT
+tmpdir="`mktemp -d -t frrtar.XXXXXX`"
+
+if test -d "$src/.git"; then
+       commit="`git -C \"$src\" rev-parse \"${commit:-HEAD}\"`"
+
+       if $dirty; then
+               cd "$src"
+               echo -e "\033[31;1mgit: using dirty worktree in $src\033[m" >&2
+       else
+               echo -e "\033[33;1mgit: preparing a clean clone of $src\033[m"
+               branch="${tmpdir##*/}"
+               cd "$tmpdir"
+
+               git -C "$src" branch "$branch" "$commit"
+               git clone --single-branch -s -b "$branch" "$src" source
+               git -C "$src" branch -D "$branch"
+               cd source
+       fi
+
+       # if we're creating a tarball from git, force the timestamps inside
+       # the tar to match the commit date - this makes the tarball itself
+       # reproducible
+       gitts="`TZ=UTC git show -s --format=%cd --date=local $commit`"
+       gitts="`TZ=UTC date -d "$gitts" '+%Y-%m-%dT%H:%M:%SZ'`"
+       taropt="--mtime=$gitts $taropt"
+
+       # check if we're on a release tag
+       gittag="`git -C \"$src\" describe --tags --match 'frr-*' --first-parent --long $commit`"
+       gittag="${gittag%-g*}"
+       gittag="${gittag%-*}"
+
+       # if there have been changes to packaging or tests, it's still the
+       # same release
+       changes="`git diff --name-only "$gittag" $commit | \
+               egrep -v '\.git|^m4/|^config|^README|^alpine/|^debianpkg/|^pkgsrc/|^ports/|^redhat/|^snapcraft/|^solaris/|^tests/|^gdb/|^docker/|^\.' | \
+               wc -l`"
+       if test "$changes" -eq 0; then
+               adjchangelog=true
+               echo "detected release build for tag $gittag" >&2
+               $extraset || extraver=""
+       elif ! $adjchangelog; then
+               gitdate="`TZ=UTC date -d "$gitts" '+%Y%m%d'`"
+               gitrev="`git rev-parse --short $commit`"
+               dayseq="`git rev-list --since \"${gitts%T*} 00:00:00 +0000\" $commit | wc -l`"
+               dayseq="`printf '%02d' $(( $dayseq - 1 ))`"
+
+               $extraset || extraver="-$gitdate-$dayseq-g$gitrev"
+
+               git -C "$src" remote -v | grep fetch | sed -e 's% (fetch)$%%' \
+                       | egrep -i '\b(git@github\.com:frrouting/frr\.git|https://github\.com/FRRouting/frr\.git)$' \
+                       | while read remote; do
+                       remote="${remote%%      *}"
+
+                       git -C "$src" var -l | egrep "^remote.$remote.fetch=" \
+                               | while read fetch; do
+                               fetch="${fetch#*=}"
+                               from="${fetch%:*}"
+                               to="${fetch#*:}"
+                               if test "$from" = "+refs/pull/*/head"; then
+                                       name="`git -C \"$src\" name-rev --name-only --refs \"$to\" $commit`"
+                                       test "$name" = "undefined" && continue
+                                       realname="${name%~*}"
+                                       realname="${realname%%^*}"
+                                       realname="${realname%%@*}"
+                                       if test "$realname" = "$name"; then
+                                               echo "${name##*/}" > "$tmpdir/.gitpr"
+                                               break
+                                       fi
+                               fi
+                       done || true
+                       test -n "$gitpr" && break
+               done || true
+               test $extraset = false -a -f "$tmpdir/.gitpr" && extraver="-PR`cat \"$tmpdir/.gitpr\"`$extraver"
+       fi
+
+       debsrc="( git ls-files debianpkg/; echo debianpkg/changelog )"
+else
+       if $nongit; then
+               echo -e "\033[31;1mWARNING: this script should be executed from a git tree\033[m" >&2
+       else
+               echo -e "\033[31;1mERROR: this script should be executed from a git tree\033[m" >&2
+               exit 1
+       fi
+       debsrc="echo debianpkg"
+fi
+
+if $writeversion; then
+       pkgver="`egrep ^AC_INIT configure.ac`"
+       pkgver="${pkgver#*,}"
+       pkgver="${pkgver%,*}"
+       pkgver="`echo $pkgver`" # strip whitespace
+
+       echo -e "\033[32;1mwriting version ID \033[36;1mfrr-$pkgver$extraver\033[m"
+
+       cat > config.version <<EOF
+# config.version override by tarsource.sh
+EXTRAVERSION="$extraver"
+DIST_PACKAGE_VERSION="$pkgver$extraver"
+gitts="$gitts"
+taropt="$taropt"
+EOF
+       exit 0
+fi
+
+echo -e "\033[33;1mpreparing source tree\033[m"
+
+# config.version will also overwrite gitts and taropt when tarsource.sh
+# was used to write the config.version file before - but configure will
+# overwrite config.version down below!
+if test -f config.version; then
+       # never executed for clean git build
+       . ./config.version
+fi
+if test \! -f configure; then
+       # always executed for clean git build
+       ./bootstrap.sh
+fi
+if test "$EXTRAVERSION" != "$extraver" -o \! -f config.status; then
+       # always executed for clean git build
+       # options don't matter really - we just want to make a dist tarball
+       ./configure --with-pkg-extra-version=$extraver
+fi
+
+. ./config.version
+PACKAGE_VERSION="$DIST_PACKAGE_VERSION"
+
+echo -e "\033[33;1mpacking up \033[36;1mfrr-$PACKAGE_VERSION\033[m"
+
+make GZIP_ENV="--best -n" am__tar="tar -chof - $taropt \"\$\$tardir\"" $ziptarget
+mv frr-${PACKAGE_VERSION}.tar.$zip "$outdir" || true
+lsfiles="frr-${PACKAGE_VERSION}.tar.$zip"
+
+if $debian; then
+       mkdir -p "$tmpdir/debian/source"
+       cp debianpkg/changelog "$tmpdir/debian/changelog"
+       if $adjchangelog; then
+               if grep -q 'autoconf changelog entry' debianpkg/changelog; then
+                       tail -n +9 debianpkg/changelog > "$tmpdir/debian/changelog"
+               fi
+       fi
+       echo '3.0 (quilt)' > "$tmpdir/debian/source/format"
+       DEBVER="`dpkg-parsechangelog -l\"$tmpdir/debian/changelog\" -SVersion`"
+
+       # rename debianpkg to debian while tar'ing
+       eval $debsrc | tar -cho $taropt \
+               --exclude-vcs --exclude debianpkg/source/format \
+               --exclude debianpkg/changelog \
+               --exclude debianpkg/changelog.in \
+               --exclude debianpkg/subdir.am \
+               --transform 's%^debianpkg%debian%' \
+               -T - -f ../frr_${DEBVER}.debian.tar
+       # add specially prepared files from above
+       tar -uf ../frr_${DEBVER}.debian.tar $taropt -C "$tmpdir" debian/source/format debian/changelog
+
+       test -f ../frr_${DEBVER}.debian.tar.$zip && rm -f ../frr_${DEBVER}.debian.tar.$zip
+       $ziptool ../frr_${DEBVER}.debian.tar
+
+       # pack up debian files proper
+       ln -s "$outdir/frr-${PACKAGE_VERSION}.tar.$zip" ../frr_${PACKAGE_VERSION}.orig.tar.$zip
+       dpkg-source -l"$tmpdir/debian/changelog" -c"`pwd`/debianpkg/control" \
+               --format='3.0 (custom)' --target-format='3.0 (quilt)' \
+               -b . frr_${PACKAGE_VERSION}.orig.tar.$zip frr_${DEBVER}.debian.tar.$zip
+
+       mv ../frr_${DEBVER}.dsc "$outdir" || true
+       mv ../frr_${DEBVER}.debian.tar.$zip "$outdir" || true
+       if test -h ../frr_${PACKAGE_VERSION}.orig.tar.$zip; then
+               rm ../frr_${PACKAGE_VERSION}.orig.tar.$zip || true
+       fi
+       ln -s frr-${PACKAGE_VERSION}.tar.$zip "$outdir/frr_${PACKAGE_VERSION}.orig.tar.$zip" || true
+
+       cd "$outdir"
+       test -n "$keyid" && debsign -k "$keyid" "frr_${DEBVER}.dsc"
+
+       lsfiles="$lsfiles \
+               frr_${DEBVER}.dsc \
+               frr_${DEBVER}.debian.tar.$zip \
+               frr_${PACKAGE_VERSION}.orig.tar.$zip"
+fi
+
+cd "$outdir"
+if test -n "$keyid"; then
+       $unzip frr-${PACKAGE_VERSION}.tar.$zip > frr-${PACKAGE_VERSION}.tar
+       test -f frr-${PACKAGE_VERSION}.tar.asc && rm frr-${PACKAGE_VERSION}.tar.asc
+       if gpg -a --detach-sign -u "$keyid" frr-${PACKAGE_VERSION}.tar; then
+               lsfiles="$lsfiles frr-${PACKAGE_VERSION}.tar.asc"
+       fi
+       rm frr-${PACKAGE_VERSION}.tar
+fi
+
+echo -e "\n\033[32;1mdone: \033[36;1mfrr-$PACKAGE_VERSION\033[m\n"
+ls -l $lsfiles