#!/bin/bash # play save set -e set -u # version of this script backports_dsc_version=0.2 ############ # Defaults # ############ bp_distribution=${BACKPORT_DISTRIBUTION:-squeeze-backports} bp_version_prefix=${BACKPORT_VERSION_PREFIX:-\~} bp_version_suffix=${BACKPORT_VERSION_SUFFIX:-bpo60} bp_maintainer_name=${DEBFULLNAME:-unamed} bp_maintainer_email=${DEBEMAIL:-unknown} bp_update_maintainer=1 # whether or not to apply backport patches found in a package bp_apply_patches=1 # produce fancy colored output bp_color_output=1 # enables additional status message if set to true bp_verbose=0 # sed expressions to modify debian/control bp_mod_control="" # source config files if [ -f /etc/backport-dsc ]; then . /etc/backport-dsc fi # source user config files if [ -f "$HOME/.backport-dsc" ]; then . $HOME/.backport-dsc fi print_version() { cat << EOT backport-dsc $backports_dsc_version Copyright (C) 2010-2012 Michael Hanke Licensed under GNU Public License version 2 or later. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Written by Michael Hanke for the NeuroDebian project. EOT } print_short_description() { cat << EOT Helper to aid backporting a Debian source package to an arbitrary distribution release. backport-dsc aids backporting by appropriately mangling the source package version, adjusting the maintainer of a package and compiling an informative changelog entry. Moreover, it supports distribution specific patches (plain, or for format 3.0 (quilt) source packages) and allow modification of debian/control via arbitrary 'sed' expressions. Backport relevant patches can be embedded in source packages for use with backport-dsc. The distribution name (see --target-distribution) serves as an identifier to search for patches in the source package that shall be applied for a particular distribution. For packages using format the 3.0 (quilt), backport-dsc will look for debian/patches/series- and append it to the main patch series. Moreover, backport-dsc will also look for patches matching /debian/patches/-dsc-patch* and apply them to the source package. The latter patches, unlike the former quilt series, can also be used to modify the debian/ directory itself. EOT } print_help() { cat << EOT Usage: backport-dsc [OPTIONS] Options: -d , --target-distribution Arbitrary distribution name (e.g. squeeze-backports). This will be the target distribution used for the backport changelog entry. The distribution name also serves as an identifier to search for backport patches in the source package. -h, --help Print short description, usage summary and option list. --maint-email Specify the backport maintainer's email address. Alternatively, backport-dsc will use the DEBEMAIL environment setting. --maint-name Specify the backport maintainer's real name. Alternatively, backport-dsc will use the DEBFULLNAME environment setting. --mod-control sed expression to modify debian/control. The option can be given multiple times and all expressions will be passed to sed in the order of appearance. This can be used to, e.g. change build or runtime dependencies. --no-backport-patches If set, potentially existing backport patches will not be applied/activated. --no-colored If set, backport-dsc won't colorize its status and error messages. --no-maintainer-update If set, the orginal maintainer is preserved in the backported source package. This should only be done if original maintainer and backporter are identical. Otherwise the porter should take responsibility for the source package backport and identify herself as the maintainer. -s , --version-suffix Version suffix that will be appended to the original source package version, ideally indicating the backport target distribution. The resulting package version will follow this schema: + e.g.: 1.2.3-4~bpo60+1 with default =~ -p , --version-prefix Version prefix that will be prepended to the backport version. By default it is ~ but want to be changed (e.g. to +) for forward-porting to next releases. --verbose Enable additional status messages. --verbose-help Print all available help. --version Print version information and exit. EOT } print_additional_description() { cat << EOT Examples: backport-dsc examplepkg_1.2.3-4.dsc Create backport suitable for backports.org backport-dsc -d myown-backports -v mo2010 examplepkg_1.2.3-4.dsc Create backport for some custom distribution with custom version suffix. backport-dsc -d ubuntu-lucid -v myppa --mod-control "-e 's/iceweasel/firefox/g'" examplepkg_1.2.3-4.dsc Create a backport for a fake Ubuntu PPA repository, replacing all occurrences of iceweasel in debian/control with firefox. Files: backport-dsc reads configuration from two files: system-wide from /etc/backports-dsc and per user settings from \$HOME/.backport-dsc (in that order). Both files have to be valid bash scripts that will be sourced by backport-dsc. The following variables (each shown with an example setting) can be used to pre-configure backport-dsc: bp_distribution="squeeze-backports" Backport target distribution (see --backport-distribution) bp_version_prefix="~" Version prefix (see --version-prefix) bp_version_suffix="bpo60" Version suffix (see --version-suffix) bp_maintainer_name="Unknown fellow" Name of the backport maintainer (see --maint-name) bp_maintainer_email="user@example.net" Email address of backport maintainer (see --maint-email) bp_apply_patches=1 Whether or not to apply backport patches found in a source package. (see --no-backport-patches) bp_color_output=1 Enable or disable colored status output (see --no-color) bp_verbose=0 Enable verbose status output (see --verbose) bp_mod_control="--mod-control 's/^Depends:.*$/&, mypackage/'" sed expressions to modify debian/control, for example to add dependencies (see --mod-control) bp_update_maintainer=1 Whether or not to replace the original maintainer in the backported source package (see --no-maintainer-update) Environment: backport-dsc acknowledges the common environment variables DEBFULLNAME and DEBEMAIL to specify the maintainer. Report bugs to . EOT } ################################ # Commandline options handling # ################################ # Parse commandline options (taken from the getopt examples from the Debian util-linux package) # Note that we use `"$@"' to let each command-line parameter expand to a # separate word. The quotes around `$@' are essential! # We need CLOPTS as the `eval set --' would nuke the return value of getopt. CLOPTS=`getopt -o h,d:,s:,p: --long help,verbose-help,version,target-distribution:,version-suffix:,version-prefix:,maint-name:,maint-email:,no-color,no-backport-patches,verbose,mod-control:,no-maintainer-update, -n 'backport-dsc' -- "$@"` if [ $? != 0 ] ; then echo "Terminating..." >&2 exit 1 fi # Note the quotes around `$CLOPTS': they are essential! eval set -- "$CLOPTS" while true ; do case "$1" in -d|--target-distribution) shift; bp_distribution=$1; shift;; -s|--version-suffix) shift; bp_version_suffix=$1; shift;; -p|--version-prefix) shift; bp_version_prefix=$1; shift;; --maint-name) shift; bp_maintainer_name=$1; shift;; --maint-email) shift; bp_maintainer_email=$1; shift;; --no-maintainer-update) bp_update_maintainer=0; shift;; --no-backport-patches) apply_patches=0; shift;; --no-color) bp_color_output=0; shift;; --verbose) bp_verbose=1; shift;; --mod-control) shift; bp_mod_control="$bp_mod_control -e '$1'"; shift;; -h|--help) print_short_description; print_help; exit 0;; --verbose-help) print_short_description; print_help; print_additional_description; exit 0;; --version) print_version; exit 0;; --) shift ; break ;; *) echo "Internal error! ($1)"; exit 1;; esac done # colorful output requested? if [ "$bp_color_output" = 1 ]; then black='\e[0;30m'; Black='\e[1;30m' red='\e[0;31m'; Red='\e[1;31m' green='\e[0;32m'; Green='\e[1;32m' yellow='\e[0;33m'; Yellow='\e[1;33m' blue='\e[0;34m'; Blue='\e[1;34m' cyan='\e[0;36m'; Cyan='\e[1;36m' white='\e[0;37m'; White='\e[1;37m' NC='\e[0m' #no color else black=''; Black='' red=''; Red='' green=''; Green='' yellow=''; Yellow='' blue=''; Blue='' cyan=''; Cyan='' white=''; White='' NC='' #no color fi if [ $# -ne 1 ]; then printf "${Red}Error: This command needs exactly one positional argument.\n${NC}" exit 1 fi # to be processed source package dsc_file=$1 if [ ! -f "$dsc_file" ]; then printf "${Red}Error: Cannot find DSC file at '$dsc_file'.\n${NC}" exit 1 fi # determine basic DSC properties src_name=$(basename "${dsc_file%%_*}") src_version=${dsc_file#*_} src_version=${src_version%%.dsc} wdir=$(mktemp -d -t backport-dsc.XXXXXX) sdir=$wdir/${src_name}-${src_version} bp_version="${bp_version_prefix}${bp_version_suffix}+" # setup environment for dpkg DEBEMAIL="$bp_maintainer_email" DEBFULLNAME="$bp_maintainer_name" export DEBEMAIL DEBFULLNAME if [ "$bp_verbose" = 1 ]; then printf "${green}DSC name: '$src_name'\nDSC version: '$src_version'\n${NC}" printf "${green}Backporting to '$bp_distribution', version suffix '$bp_version'\n${NC}" printf "${green}Extracting source package to '$sdir'\n${NC}" fi # common debchange call bp_dch_cmd="dch --noconf --force-distribution --force-bad-version -c $sdir/debian/changelog" # extract the original source package dpkg-source -x $dsc_file $sdir # note backport in changelog # This will create a new changelog entry # All subsequent calls to dch should use -a to assure that those entries # are appended to the existing entry (otherwise with wheezy new entries will be added) $bp_dch_cmd -D ${bp_distribution} -l "${bp_version}" "Backported for ${bp_distribution}." if [ "$bp_update_maintainer" = 1 ]; then if [ "$bp_verbose" = 1 ]; then printf "${green}Set backport maintainer to: '$bp_maintainer_name <$bp_maintainer_email>'\n${NC}" fi bp_mod_control="$bp_mod_control -e 's/^Maintainer:.*$/Maintainer: $bp_maintainer_name <$bp_maintainer_email>\nX-Original-&/'" fi # handle patches if desired if [ "$bp_apply_patches" = 1 ]; then dsc_format=$(dpkg-source --print-format $sdir) # per each supported source package format if [ "$dsc_format" = "3.0 (quilt)" -a -f "$sdir/debian/patches/series-$bp_distribution" ]; then if [ "$bp_verbose" = 1 ]; then printf "${green}Enabling additional quilt patch series for $bp_distribution.\n${NC}" fi cat $sdir/debian/patches/series-$bp_distribution >> $sdir/debian/patches/series $bp_dch_cmd -a "Added 'series-$bp_distribution' in quilt patch series." fi # look for backport patches for p in $(ls -1 $sdir/debian/patches/$bp_distribution-dsc-patch* 2> /dev/null || true); do if [ "$bp_verbose" = 1 ]; then printf "${green}Applying additional patch $(basename "$p").\n${NC}" fi patch -p1 --directory=$sdir < "$p" $bp_dch_cmd -a "Applied additional patch from debian/patches/$(basename "$p")." done fi # modify control file if [ -n "$bp_mod_control" ]; then if [ "$bp_verbose" = 1 ]; then printf "${green}Modifying debian/control with given instructions.\n${NC}" fi bash -c "sed -i $bp_mod_control $sdir/debian/control" $bp_dch_cmd -a "Used following sed expression to modify debian/control:$bp_mod_control." fi # extract final version final_version=$(dpkg-parsechangelog -l$sdir/debian/changelog | egrep '^Version: ' | cut -d ' ' -f 2,2) # build backported source package bash -c "cd $wdir && dpkg-source -b $sdir" # remove extracted source tree rm -rf $sdir # move generated source package into working dir mv $wdir/* . # cleanup rm -rf $wdir if [ "$bp_verbose" = 1 ]; then printf "${green}Backported source package is at '${src_name}_$final_version.dsc'\n${NC}" fi