diff options
Diffstat (limited to 'scripts/edit-patch.sh')
-rwxr-xr-x | scripts/edit-patch.sh | 313 |
1 files changed, 313 insertions, 0 deletions
diff --git a/scripts/edit-patch.sh b/scripts/edit-patch.sh new file mode 100755 index 0000000..8adfb67 --- /dev/null +++ b/scripts/edit-patch.sh @@ -0,0 +1,313 @@ +#!/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<<EOF +## Description: add some description\ +\n## Origin/Author: add some origin or author\ +\n## Bug: bug URL +EOF +) + +fatal_error() { + echo "$@" >&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 $@ |