|
#!/bin/bash |
|
# https://gist.github.com/smoser/d3dbf2b8a073675e0700472e12513e0a |
|
|
|
VERBOSITY=0 |
|
TEMP_D="" |
|
|
|
error() { echo "$@" 1>&2; } |
|
fail() { local r=$?; [ $r -eq 0 ] && r=1; failrc "$r" "$@"; } |
|
failrc() { local r=$1; shift; [ $# -eq 0 ] || error "$@"; exit $r; } |
|
|
|
Usage() { |
|
cat <<EOF |
|
Usage: ${0##*/} [ options ] <<ARGUMENTS>> |
|
|
|
build-upstream-pkg <upstream-commitish> <packaging-commitish> |
|
|
|
options: |
|
--version VERSION make the upstream version VERSION |
|
default is to use git-describe |
|
--output DIR put created files in DIR |
|
-v | --verbose increase verbosity |
|
|
|
If you have the following remotes: |
|
upstream with 'master' branch |
|
pkg with 'ubuntu/devel' |
|
then you'd do: |
|
|
|
$ build-upstream-pkg upstream/master ubuntu/devel |
|
EOF |
|
} |
|
|
|
bad_Usage() { Usage 1>&2; [ $# -eq 0 ] || error "$@"; return 1; } |
|
|
|
cleanup(){ |
|
[ ! -d "$TEMP_D" ] || rm -Rf "$TEMP_D"; |
|
git worktree prune |
|
} |
|
|
|
debug() { |
|
local level=${1}; shift; |
|
[ "${level}" -gt "${VERBOSITY}" ] && return |
|
error "${@}" |
|
} |
|
|
|
get_version() { |
|
# get version if not provided |
|
local ref=$1 match="" out="" version="" |
|
for match in "" "[0-9]*" "v[0-9]*"; do |
|
out=$(git describe --abbrev=8 ${match:+"--match=$match"} $ref 2>&1) && |
|
[ -n "$out" ] && break |
|
out="" |
|
done |
|
|
|
if [ -z "$out" ]; then |
|
# try with --tags |
|
for match in "" "[0-9]*" "v[0-9]*"; do |
|
out=$(git describe --abbrev=8 --tags ${match:+"--match=$match"} $ref 2>&1) && |
|
[ -n "$out" ] && break |
|
done |
|
fi |
|
|
|
case "$out" in |
|
"") fail "failed to git-describe anything";; |
|
[a-z][a-z]*-[0-9.]*) version=${out#*-};; # lxc-4.0.0-123-gxxx |
|
[a-z]*[0-9.]*) |
|
version=$out |
|
while [ "${version}" != "${version#[a-z]}" ]; do |
|
version=${version#[a-z]} |
|
done |
|
;; |
|
[0-9]*-[0-9]*-g[a-f0-9]*) version=$out;; |
|
esac |
|
debug 1 "version now $version from $out" |
|
case "$version" in |
|
[0-9]*-[0-9]*-g[a-f0-9]*) :;; |
|
*) fail "git describe got us '$out'" \ |
|
"not sure how to turn that into X.Y.Z-<number>-<gHASH>" |
|
esac |
|
_RET=$version |
|
} |
|
|
|
main() { |
|
local short_opts="ho:vV:" |
|
local long_opts="help,output:,version:,verbose" |
|
local getopt_out="" |
|
getopt_out=$(getopt --name "${0##*/}" \ |
|
--options "${short_opts}" --long "${long_opts}" -- "$@") && |
|
eval set -- "${getopt_out}" || |
|
{ bad_Usage; return; } |
|
|
|
local cur="" next="" out_d="../out" version="" |
|
|
|
while [ $# -ne 0 ]; do |
|
cur="$1"; next="$2"; |
|
case "$cur" in |
|
-h|--help) Usage ; exit 0;; |
|
-o|--output) out_d=$next; shift;; |
|
-V|--version) version=$next; shift;; |
|
-v|--verbose) VERBOSITY=$((${VERBOSITY}+1));; |
|
--) shift; break;; |
|
esac |
|
shift; |
|
done |
|
|
|
[ $# -ge 2 ] || { bad_Usage "got $# args, expected 2"; return; } |
|
local up_cish="$1" pkg_cish="$2" |
|
shift 2 |
|
|
|
local build_cmd="" |
|
if [ $# -eq 0 ]; then |
|
build_cmd=( debuild -d -S -nc ) |
|
else |
|
build_cmd=( "$@" ) |
|
fi |
|
|
|
# check both commitish |
|
local up_hash="" pkg_hash="" |
|
up_hash=$(git rev-parse "$up_cish") || |
|
fail "failed to get hash for $up_cish" |
|
|
|
pkg_hash=$(git rev-parse "$pkg_cish") || |
|
fail "failed to get hash for $pkg_cish" |
|
|
|
local user="" email="" |
|
user=$(git config user.name) && |
|
email=$(git config user.email) || |
|
fail "failed to get user or email" |
|
|
|
local start_d="$PWD" out_d_in="$out_d" |
|
[ -d "$out_d" ] || mkdir -p "$out_d" || |
|
fail "failed to create $out_d" |
|
|
|
out_d=$(cd "$out_d" && pwd) || { |
|
fail "failed to get full path to $out_d_in" |
|
} |
|
|
|
TEMP_D=$(mktemp -d "${TMPDIR:-/tmp}/${0##*/}.XXXXXX") || |
|
fail "failed to make tempdir" |
|
trap cleanup EXIT |
|
|
|
local wtd="${TEMP_D}/wtd" |
|
git worktree add --force "$wtd" "$pkg_hash" || |
|
fail "failed worktree add $wtd $ref" |
|
cd "$wtd" |
|
|
|
local pkg_ver="0upstream1" pkg_name="" old_full_ver="" old_pkg_ver="" |
|
|
|
# get the pkg name from pkg commit |
|
git checkout "$pkg_hash" || |
|
fail "failed to checkout $pkg_hash" |
|
|
|
pkg_name=$(dpkg-parsechangelog --show-field Source) || |
|
fail "failed to read Source from changelog" |
|
|
|
old_full_ver=$(dpkg-parsechangelog --show-field Version) || |
|
fail "failed reading package version" |
|
|
|
local epoch="" |
|
case "$old_full_ver" in |
|
[0-9]:*) epoch=${old_full_ver%%:*};; |
|
esac |
|
|
|
if [ -f debian/source/format ] && |
|
out=$(grep "(native)" debian/source/format); then |
|
fail "debian/source/format says this is native package" |
|
fi |
|
|
|
git checkout "$up_hash" || |
|
fail "failed to checkout $up_hash" |
|
if [ -z "$version" ]; then |
|
get_version && version="$_RET" || |
|
fail "failed to get version from $up_hash" |
|
fi |
|
|
|
debug 1 "pkg_name is ${pkg_name} upstream_version=$version" |
|
|
|
local orig_tarball="${TEMP_D}/${pkg_name}_${version}.orig.tar.gz" |
|
|
|
# make an upstream tarball that does not contain debian/ |
|
tar -czf "${orig_tarball}" \ |
|
"--transform=s,^[.]/,${pkg_name}-${version}/," \ |
|
"--exclude=.git" "--exclude=debian" . || |
|
fail "failed to create upstream tarball ${pkg_name}_${version}" |
|
|
|
# checkout pkg commitish |
|
git checkout "$pkg_hash" || |
|
fail "failed to checkout $pkg_hash" |
|
|
|
# git rm anything not debian/ |
|
local f="" rms="" |
|
rms=( ) |
|
for f in * .*; do |
|
case "$f" in |
|
.git|.|..|debian) continue;; |
|
esac |
|
rms[${#rms[@]}]="$f" |
|
done |
|
|
|
local cur_hash="$pkg_hash" |
|
if [ "${#rms[@]}" -eq 0 ]; then |
|
debug 1 "pkg tree was debian-only" |
|
else |
|
git rm --quiet -r "${rms[@]}" || fail "failed to git remove files" |
|
git commit --quiet -a -m "remove non-debian files from pkg branch" || |
|
fail "failed to commit cleanup" |
|
cur_hash=$(git rev-parse HEAD) |
|
fi |
|
|
|
# add debian/changelog entry |
|
local suite="UNRELEASED" |
|
|
|
debug 1 "${pkg_name} (${epoch:+${epoch}:}$version-${pkg_ver}) $suite; urgency=medium" |
|
cat >debian/changelog <<EOF |
|
${pkg_name} (${epoch:+${epoch}:}$version-${pkg_ver}) $suite; urgency=medium |
|
|
|
* new upstream version $version. |
|
|
|
-- $user <$email> $(date -R) |
|
EOF |
|
|
|
[ $? -eq 0 ] || fail "failed to write debian/changelog" |
|
|
|
git show "$cur_hash:debian/changelog" >> debian/changelog || |
|
fail "failed to append to debian changelog" |
|
|
|
# commit |
|
git commit -m "update changelog" debian/changelog || |
|
fail "failed to commit changelog update" |
|
|
|
cur_hash=$(git rev-parse HEAD) |
|
|
|
# I think its a bug in dpkt-source, but it complains about |
|
# deleted files, so make it not have deleted files. |
|
tar --strip-components=1 -xzf "$orig_tarball" || |
|
fail "failed to extrat tarball" |
|
|
|
# invoke debuild |
|
debug 0 "building $cur_hash with: ${build_cmd[*]}" |
|
"${build_cmd[@]}" || |
|
fail "FAILED: ${build_cmd[*]}" |
|
|
|
debug 0 "built $pkg_name at $version. source tree in $cur_hash" |
|
debug 0 "wrote:" |
|
for f in "${TEMP_D}/"*; do |
|
[ -f "$f" ] || continue |
|
cp "$f" "$out_d/" && echo " ${out_d_in}/${f##*/}" || |
|
fail "failed to copy $f to $out_d" |
|
done |
|
|
|
cd "$start_d" |
|
|
|
return 0 |
|
} |
|
|
|
main "$@" |
|
# vi: ts=4 expandtab |