From b76d1994a63690251e5f521bdefb4a2d4a06a9cc Mon Sep 17 00:00:00 2001 From: Sean Whitton Date: Fri, 5 Jul 2019 18:11:20 +0100 Subject: git-debpush: new script Signed-off-by: Sean Whitton Signed-off-by: Ian Jackson --- git-debpush | 276 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 276 insertions(+) create mode 100755 git-debpush diff --git a/git-debpush b/git-debpush new file mode 100755 index 0000000..4725eab --- /dev/null +++ b/git-debpush @@ -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 . + +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" <