chiark / gitweb /
git-debpush: new script
authorSean Whitton <spwhitton@spwhitton.name>
Fri, 5 Jul 2019 17:11:20 +0000 (18:11 +0100)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Sat, 6 Jul 2019 20:12:45 +0000 (21:12 +0100)
Signed-off-by: Sean Whitton <spwhitton@spwhitton.name>
Signed-off-by: Ian Jackson <ijackson@chiark.greenend.org.uk>
git-debpush [new file with mode: 0755]

diff --git a/git-debpush b/git-debpush
new file mode 100755 (executable)
index 0000000..4725eab
--- /dev/null
@@ -0,0 +1,276 @@
+#!/bin/bash
+
+# git-debpush -- create & push a git tag with metadata for an ftp-master upload
+#
+# Copyright (C) 2019 Sean Whitton
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+set -e${DGIT_TEST_DEBPUSH_DEBUG-x}
+set -o pipefail
+
+# DEBUG
+
+# Principles of operation
+
+# - do not invoke dgit, anything involving any tarballs, no network
+#   except `git push`
+
+# - do not look at the working tree, like `git push` `git tag`, and so
+#   we can later add functionality to debpush any branch
+
+# - we are always in split brain mode, because this means the push won't
+#   fail because dgit needs to append commits
+
+# - if there is no previous tag created by this script, require a quilt
+#   mode; if there is a previous tag, and no quilt mode provided, assume
+#   same quilt mode
+
+# Other notes (which should be converted to a manpage/usage)
+
+# - arguments after '--' passed to `git push`
+
+# ---- Helper functions
+
+cleanup() {
+    if [ -d "$TEMP" ]; then
+        rm -rf "$TEMP"
+    fi
+}
+
+# ---- Parse command line
+
+us="$(basename $0)"
+
+fail () { echo >&2 "$us: $*"; exit 127; }
+badusage () { fail "bad usage: $*"; }
+
+getopt=$(getopt -s bash -o 'nfu:' \
+              -l 'no-push,force,branch:,remote:,distro:,quilt:,gbp,dpm,baredebian,\
+baredebian+git,baredebian+tarball,linear' \
+              -n "$us" -- "$@")
+eval "set - $getopt"
+set -e${DGIT_TEST_DEBPUSH_DEBUG-x}
+
+git_tag_opts=()
+pushing=true
+distro=debian
+
+quilt_mode=""
+while true; do
+    case "$1" in
+        '-n'|'--no-push')
+            pushing=false
+            shift
+            continue
+            ;;
+       '-u')
+            git_tag_opts+=(-u "$2")
+           shift 2
+           continue
+           ;;
+        '-f'|'--force')
+            force='yes'
+            shift
+            continue
+            ;;
+        '--gbp')
+            quilt_mode='gbp'
+            shift
+            continue
+            ;;
+        '--dpm')
+            quilt_mode='dpm'
+            shift
+            continue
+            ;;
+        '--baredebian'|'--baredebian+git')
+            quilt_mode=baredebian
+            shift
+            continue
+            ;;
+        '--baredebian+tarball')
+            quilt_mode=baredebian+tarball
+            shift
+            continue
+            ;;
+        '--branch') branch=$2;     shift 2; continue ;;
+        '--remote') remote=$2;     shift 2; continue ;;
+        '--distro') distro=$2;     shift 2; continue ;;
+        '--quilt')  quilt_mode=$2; shift 2; continue ;;
+        '--')
+           shift
+           break
+           ;;
+       *)
+           badusage "unknown option $1"
+           ;;
+
+    esac
+done
+
+if [ $# != 0 ]; then badusage 'no positional arguments allowed'; fi
+
+case "$quilt_mode" in
+    'linear'|'auto'|'smash'|'nofix'|'gbp'|'dpm'|'unapplied'|'baredebian'|'baredebian+tarball')
+       ;;
+    'baredebian+git')
+       quilt_mode="baredebian"
+       ;;
+    *)
+       badusage " invalid quilt mode: $quilt_mode"
+       ;;
+esac
+
+remoteconfigs=()
+push_branch=()
+
+if [ ! "$branch" ]; then
+    branch=HEAD
+    branchref="$(git symbolic-ref -q HEAD || test $? = 1)"
+    case "$branchref" in
+       refs/heads/*)
+           b=${branchref#refs/heads/}
+           remoteconfigs+=( branch.$b.pushRemote branch.$b.remote )
+           push_branch+=("$b")
+       ;;
+    esac
+fi
+
+remoteconfigs+=(remote.pushDefault)
+
+if $pushing && [ ! "$remote" ]; then
+    for c in "${remoteconfigs[@]}"; do
+       remote=$(git config "$c" || test $? = 1)
+       if [ "x$remote" ]; then break; fi
+    done
+    if [ ! "$remote" ]; then
+       fail "pushing, but could not determine remote, so need --remote="
+    fi
+fi
+
+# ---- Gather source package information
+
+TEMP=$(mktemp -d)
+trap cleanup EXIT
+mkdir "$TEMP/debian"
+git cat-file blob HEAD:debian/changelog >"$TEMP/debian/changelog"
+version=$(cd $TEMP; dpkg-parsechangelog -SVersion)
+source=$(cd $TEMP; dpkg-parsechangelog -SSource)
+target=$(cd $TEMP; dpkg-parsechangelog -SDistribution)
+rm -rf "$TEMP"
+trap - EXIT
+
+# ---- Useful sanity checks
+
+if [ "$force" != "yes" ]; then
+
+    if [ "$target" = "UNRELEASED" ]; then
+        fail "UNRELEASED changelog"
+    fi
+
+    # TODO additional checks we might do:
+    #
+    # - are we uploading to a different suite from the last tag
+    #   (e.g. unstable after experimental)?  user should pass option to
+    #   confirm
+    #
+    # - walking backwards from $branch, if there is an archive/ strictly
+    #   before we reach most recent debian/ tag, error, this might be a
+    #   push of the dgit view to the maintainer branch
+    #
+    # - check for UNRELEASED changelog
+
+fi
+
+# ---- Create the git tag
+
+get_file_from_ref () {
+    local path=$1
+    if git ls-tree --name-only -r "$branch" \
+            | grep -Eq "^$path$"; then
+       git cat-file blob $branch:$path
+    fi
+}
+
+format="$(get_file_from_ref debian/source/format)"
+case "$format" in
+    '3.0 (quilt)') upstream=true ;;
+    '3.0 (native)') upstream=false ;;
+    '1.0'|'')
+       if get_file_from_ref debian/source/options | grep '^-sn *$'; then
+           upstream=false
+        elif get_file_from_ref debian/source/options | grep '^-sk *$'; then
+           upstream=true
+       else
+           fail 'xxxx see sn /sk docs'
+       fi
+       ;;
+    *)
+       fail "unsupported debian/source/format $format"
+       ;;
+esac
+
+if $upstream; then
+    upstream_tag=$(git deborig --just-print --version="$version" \
+                       | head -n1)
+    upstream_committish=$(git rev-parse ${upstream_tag}^{})
+    upstream_info=" upstream-tag=$upstream_tag upstream=$upstream_committish"
+fi
+
+# convert according to DEP-14 rules
+git_version=$(echo $version | tr ':~' '%_' | sed 's/\.(?=\.|$|lock$)/.#/g')
+
+debian_tag="$distro/$git_version"
+
+if [ "x$quilt_mode" = "x" ] && [ "$format" = "3.0 (quilt)" ]; then
+    set +o pipefail             # perl will SIGPIPE git-log here
+    tag=$(git log --pretty=format:'%D' --decorate=full "$branch" \
+        | perl -wne 'use Dpkg::Version;
+               @pieces = split /, /, $_;
+               @debian_tag_vs = sort {version_compare($b, $a)}
+                    map { m|tag: refs/tags/debian/(.+)| ? $1 : () } @pieces;
+               if (@debian_tag_vs) { print "debian/$debian_tag_vs[0]\n"; exit }')
+    if [ "x$tag" != "x" ]; then
+        quilt_mode=$(git cat-file -p $(git rev-parse "$tag") \
+                         | perl -wne \
+                                'm/^\[dgit.*--quilt=([a-z+]+).*\]$/;
+                                 if ($1) { print "$1\n"; exit }')
+    fi
+    set -o pipefail
+fi
+
+quilt_mode_text=""
+if [ "$format" = "3.0 (quilt)" ]; then
+    if [ "x$quilt_mode" = "x" ]; then
+        echo >&2 "$us: could not determine the git branch layout"
+        echo >&2 "$us: please supply a --quilt= argument"
+        exit 1
+    else
+        quilt_mode_text=" --quilt=$quilt_mode"
+    fi
+fi
+
+git tag "${git_tag_opts[@]}" -s -F- "$debian_tag" "$branch" <<EOF
+$source release $version for $target
+
+[dgit distro=$distro split$quilt_mode_text]
+[dgit please-upload$upstream_info]
+EOF
+
+# ---- Do a git push
+
+if $pushing; then
+    git push "$remote" "${push_branch[@]}" "$upstream_tag" "$debian_tag"
+fi