#!/bin/sh # # Copyright (C) 2009 Canonical # # Authors: # Michael Vogt # Daniel Holbach # David Futcher # # 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; version 3. # # 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, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA set -e PROGNAME=${0##*/} PATCHSYSTEM="unknown" PATCHNAME="no-patch-name" PREFIX="debian/patches" PATCH_DESC=$(cat<&2 exit 1 } # check if the given binary is installed and give an error if not # arg1: binary # arg2: error message require_installed() { if ! which "$1" >/dev/null; then fatal_error "$2" fi } ensure_debian_dir() { if [ ! -e debian/control ] || [ ! -e debian/rules ]; then fatal_error "Can not find debian/rules or debian/control. Not in a debian dir?" fi } detect_patchsystem() { CDBS_PATCHSYS="^[^#]*simple-patchsys.mk" if grep -q "$CDBS_PATCHSYS" debian/rules; then PATCHSYSTEM="cdbs" require_installed cdbs-edit-patch "no cdbs-edit-patch found, is 'cdbs' installed?" elif [ -e debian/patches/00list ]; then PATCHSYSTEM="dpatch" require_installed dpatch-edit-patch "no dpatch-edit-patch found, is 'dpatch' installed?" elif [ -e debian/patches/series -o \ "$(cat debian/source/format 2> /dev/null)" = "3.0 (quilt)" ]; then PATCHSYSTEM="quilt" require_installed quilt "no quilt found, is 'quilt' installed?" else PATCHSYSTEM="none" PREFIX="debian/applied-patches" fi } # remove full path if given normalize_patch_path() { PATCHNAME=${PATCHNAME##*/} echo "Normalizing patch path to $PATCHNAME" } # ensure (for new patches) that: # - dpatch ends with .dpatch # - cdbs/quilt with .patch normalize_patch_extension() { # check if we have a patch already if [ -e $PREFIX/$PATCHNAME ]; then echo "Patch $PATCHNAME exists, not normalizing" return fi # normalize name for new patches PATCHNAME=${PATCHNAME%.*} if [ "$PATCHSYSTEM" = "quilt" ]; then PATCHNAME="${PATCHNAME}.patch" elif [ "$PATCHSYSTEM" = "cdbs" ]; then PATCHNAME="${PATCHNAME}.patch" elif [ "$PATCHSYSTEM" = "dpatch" ]; then PATCHNAME="${PATCHNAME}.dpatch" elif [ "$PATCHSYSTEM" = "none" ]; then PATCHNAME="${PATCHNAME}.patch" fi echo "Normalizing patch name to $PATCHNAME" } edit_patch_cdbs() { cdbs-edit-patch $PATCHNAME vcs_add debian/patches/$1 } edit_patch_dpatch() { dpatch-edit-patch $PATCHNAME # add if needed if ! grep -q $1 $PREFIX/00list; then echo "$1" >> $PREFIX/00list fi vcs_add $PREFIX/00list $PREFIX/$1 } edit_patch_quilt() { export QUILT_PATCHES=debian/patches if [ -e $QUILT_PATCHES ]; then top_patch=$(quilt top) echo "Top patch: $top_patch" fi if [ -e $PREFIX/$1 ]; then # if it's an existing patch and we are at the end of the stack, # go back at the beginning if ! quilt unapplied; then quilt pop -a fi quilt push $1 else # if it's a new patch, make sure we are at the end of the stack if quilt unapplied >/dev/null; then quilt push -a fi quilt new $1 fi # use a sub-shell quilt shell quilt refresh if [ -n $top_patch ]; then echo "Reverting quilt back to $top_patch" quilt pop $top_patch fi vcs_add $PREFIX/$1 $PREFIX/series } edit_patch_none() { # Dummy edit-patch function, just display a warning message echo "No patchsystem could be found so the patch was applied inline and a copy \ stored in debian/patches-applied. Please remember to mention this in your changelog." } add_patch_quilt() { # $1 is the original patchfile, $2 the normalized name # FIXME: use quilt import instead? cp $1 $PREFIX/$2 if ! grep -q $2 $PREFIX/series; then echo "$2" >> $PREFIX/series fi vcs_add $PREFIX/$2 $PREFIX/series } add_patch_cdbs() { # $1 is the original patchfile, $2 the normalized name cp $1 $PREFIX/$2 vcs_add $PREFIX/$2 } add_patch_dpatch() { # $1 is the original patchfile, $2 the normalized name cp $1 $PREFIX if ! grep -q $2 $PREFIX/00list; then echo "$2" >> $PREFIX/00list fi vcs_add $PREFIX/$2 $PREFIX/00list } add_patch_none() { # $1 is the original patchfile, $2 the normalized name cp $1 $PREFIX/$2 vcs_add $PREFIX/$2 } vcs_add() { if [ -d .bzr ]; then bzr add $@ elif [ -d .git ];then git add $@ else echo "Remember to add $@ to a VCS if you use one" fi } vcs_commit() { # check if debcommit is happy if ! debcommit --noact 2>/dev/null; then return fi # commit (if the user confirms) debcommit --confirm } add_changelog() { S="$PREFIX/$1: [DESCRIBE CHANGES HERE]" if head -n1 debian/changelog|grep UNRELEASED; then dch --append "$S" else dch --increment "$S" fi # let the user edit it dch --edit } add_patch_tagging() { # check if we have a description already if grep "## Description:" $PREFIX/$1; then return fi # if not, add one RANGE=1,1 # make sure we keep the first line (for dpatch) if head -n1 $PREFIX/$1|grep -q '^#'; then RANGE=2,2 fi sed -i ${RANGE}i"$PATCH_DESC" $PREFIX/$1 } detect_patch_location() { # Checks whether the specified patch exists in debian/patches or on the filesystem FILENAME=${PATCHNAME##*/} if [ -f "$PREFIX/$FILENAME" ]; then PATCHTYPE="debian" elif [ -f "$PATCHNAME" ]; then PATCHTYPE="file" PATCHORIG="$PATCHNAME" else if [ "$PATCHSYSTEM" = "none" ]; then fatal_error "No patchsystem detected, cannot create new patch (no dpatch/quilt/cdbs?)" else PATCHTYPE="new" fi fi } handle_file_patch() { if [ "$PATCHTYPE" = "file" ]; then [ -f "$PATCHORIG" ] || fatal_error "No patch detected" if [ "$PATCHSYSTEM" = "none" ]; then # If we're supplied a file and there is no patchsys we apply it directly # and store it in debian/applied patches [ -d $PREFIX ] || mkdir $PREFIX patch -p0 < "$PATCHORIG" cp "$PATCHORIG" "$PREFIX/$PATCHNAME" else # Patch type is file but there is a patchsys present, so we add it # correctly cp "$PATCHORIG" "$PREFIX/$PATCHNAME" if [ "$PATCHSYSTEM" = "quilt" ]; then echo "$PATCHNAME" >> $PREFIX/series elif [ "$PATCHSYSTEM" = "dpatch" ]; then echo "$PATCHNAME" >> $PREFIX/00list # Add the dpatch header to files that don't already have it if ! grep -q "@DPATCH@" "$PREFIX/$PATCHNAME"; then sed -i '1i#! /bin/sh /usr/share/dpatch/dpatch-run\n@DPATCH@' $PREFIX/$PATCHNAME fi fi echo "Copying and applying new patch. You can now edit the patch or exit the subshell to save." fi fi } # TODO: # - edit-patch --remove implementieren # - dbs patch system main() { # parse args if [ $# -ne 1 ]; then fatal_error "Need exactly one patch name" fi PATCHNAME="$1" # do the work ensure_debian_dir detect_patchsystem detect_patch_location normalize_patch_path normalize_patch_extension handle_file_patch if [ "${PROGNAME%.sh}" = edit-patch ]; then edit_patch_$PATCHSYSTEM $PATCHNAME elif [ "${PROGNAME%.sh}" = add-patch ]; then add_patch_$PATCHSYSTEM $1 $PATCHNAME else fatal_error "Unknown script name: $0" fi add_patch_tagging $PATCHNAME add_changelog $PATCHNAME vcs_commit } main $@