diff options
author | Andreas Gruenbacher <agruen@suse.de> | 2003-01-31 12:45:37 +0000 |
---|---|---|
committer | Andreas Gruenbacher <agruen@suse.de> | 2003-01-31 12:45:37 +0000 |
commit | 21a15e55a81ea4bd2bc21729ceebe6be6a9ccd9b (patch) | |
tree | 150f25f9add7ecb5ae144ab63a62c3b43d25f378 /scripts | |
parent | f07f43d191fe23209876061b7a31b5cb1e9a219d (diff) | |
download | quilt-21a15e55a81ea4bd2bc21729ceebe6be6a9ccd9b.tar.gz |
Install binary backup-files into /usr/lib/quilt and the remaining scripts under /usr/share/quilt/scripts.
Diffstat (limited to 'scripts')
-rwxr-xr-x | scripts/apatch.in | 189 | ||||
-rw-r--r-- | scripts/parse-patch.in | 129 | ||||
-rw-r--r-- | scripts/patchfns.in | 614 | ||||
-rwxr-xr-x | scripts/rpatch.in | 254 | ||||
-rwxr-xr-x | scripts/spec2series.in | 227 |
5 files changed, 1413 insertions, 0 deletions
diff --git a/scripts/apatch.in b/scripts/apatch.in new file mode 100755 index 0000000..d225bde --- /dev/null +++ b/scripts/apatch.in @@ -0,0 +1,189 @@ +#! @BASH@ + +# This script is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# See the COPYING and AUTHORS files for more details. + +# Read in library functions +if [ "$(type -t patch_file_name)" != function ] +then + if ! [ -r @SCRIPTS@/patchfns ] + then + echo "Cannot read library @SCRIPTS@/patchfns" >&2 + exit 1 + fi + . @SCRIPTS@/patchfns +fi + +usage() +{ + echo "Usage: $0 [-fqv] patchname" + exit 1 +} + +rollback_patch() +{ + local patch=$1 pc_file=$(pc_file_name $patch) + @LIB@/backup-files $silent_unless_verbose \ + -f $pc_file -B .pc/$patch/ -r + if [ -z "$opt_leave_rejects" ] + then + rm -f $(files_in_patch $patch | sed -e 's/$/\.rej/') + fi +} + +interrupt() +{ + rollback_patch $1 + echo "Interrupted by user; patch $patch was not applied." + exit 1 +} + +apply_patch() +{ + local patch=$1 + local patch_file=$(patch_file_name $patch) + + if ! [ -s $patch_file ] + then + echo "Patch file $patch_file appears to be empty" + return 0 + fi + + if [ "x${patch_file:(-3)}" = "x.gz" ] + then + gzip -cd $patch_file \ + | @PATCH@ $(patch_args $patch) --no-backup-if-mismatch \ + -E $silent + elif [ "x${patch_file:(-4)}" = "x.bz2" ] + then + bzip2 -cd $patch_file \ + | @PATCH@ $(patch_args $patch) --no-backup-if-mismatch \ + -E $silent + else + @PATCH@ $(patch_args $patch) --no-backup-if-mismatch \ + -E $silent -i $patch_file + fi +} + +apatch() +{ + local patch=$(stripit $1) + local pc_file=$(pc_file_name $patch) + local file status + + trap "" SIGINT + if ! refresh_file_list $patch + then + echo "refresh_file_list failed" + return 1 + fi + + if ! [ -e $pc_file ] + then + echo "Patch $patch appears to be empty, applied" + add_to_db $patch + return 0 + fi + + status=$? + if [ $status -eq 2 ] + then + [ -z "$opt_quiet" ] && echo "Recreated file list for $patch" + elif [ $status -ne 0 ] + then + return 1 + fi + + if ! @LIB@/backup-files $silent_unless_verbose \ + -f $pc_file -B .pc/$patch/ + then + exit 1 + fi + + trap "interrupt $patch" SIGINT + + apply_patch $patch + status=$? + + trap "" SIGINT + + # Remember date/time of applying so that pop can + # avoid reverse applying the patch in the usual cases. + touch $pc_file + + if [ $status -eq 0 -o -n "$opt_force" ] + then + add_to_db $patch + if [ $status -eq 0 ] + then + echo "Applied $patch" + rm -f $pc_file~refresh + else + touch $pc_file~refresh + echo "Applied $patch (forced; needs refresh)" + fi + else + rollback_patch $patch + echo "Patch $patch does not apply (enforce with -f)" + fi + trap - SIGINT + return $status +} + +options=`getopt -o fqvh --long leave-rejects -- "$@"` + +if [ $? -ne 0 ] +then + usage +fi + +eval set -- "$options" + +while true +do + case "$1" in + -f) + opt_force=1 + shift ;; + -q) + opt_quiet=1 + shift ;; + -v) + opt_verbose=1 + shift ;; + --leave-rejects) + opt_leave_rejects=1 + shift ;; + -h) + usage -h ;; + --) + shift + break ;; + esac +done + +if [ $# -ne 1 ] +then + usage +fi + +[ -n "$opt_quiet" ] && silent=-s +[ -z "$opt_verbose" ] && silent_unless_verbose=-s + +patch=$(stripit $1) + +top=$(top_patch) +if [ -n "$top" -a -e $(pc_file_name $top)~refresh ] +then + echo "The topmost patch $top needs to be refreshed first." + exit 1 +fi + +apatch $patch +### Local Variables: +### mode: shell-script +### End: +# vim:filetype=sh diff --git a/scripts/parse-patch.in b/scripts/parse-patch.in new file mode 100644 index 0000000..56c3c55 --- /dev/null +++ b/scripts/parse-patch.in @@ -0,0 +1,129 @@ +#!@PERL@ -w + +# This script is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# See the COPYING and AUTHORS files for more details. + +# Extract or update a section from a combined patch + documentation + +# meta information file. + +use FileHandle; +use Getopt::Long; +use File::Temp qw(tempfile); +use strict; + +my $select; +my $update; + +if (!GetOptions("s|select=s" => \$select, + "u|update=s" => \$update) || + (!defined $select && !defined $update)) { + print STDERR "USAGE: $0 {-s|-u} section file [< replacement]\n"; + exit 1; +} + +foreach my $arg (@ARGV) { + my $fh; + + if (! -e $arg) { + $fh = new FileHandle("/dev/null"); + } elsif ($arg =~ /\.gz$/) { + $fh = new FileHandle("gzip -cd $arg |"); + } elsif ($arg =~ /\.bz2$/) { + $fh = new FileHandle("bzip2 -cd $arg |"); + } else { + $fh = new FileHandle("< $arg"); + } + + unless ($fh) { + print STDERR "$arg: $!\n"; + next; + } + + if (defined $select) { + my $section = "head"; + my $newline = ""; + while (<$fh>) { + if (/^%(.*)/) { + last if $section eq $select; + $section = $1; + next; + } + if ($section eq $select) { + print $newline; + if ($_ eq "\n") { + $newline = $_; + } else { + $newline=""; + print; + } + } + } + } elsif (defined $update) { + my ($fh2, $tempname) = tempfile("$arg.XXXXXX"); + if ($arg =~ /\.gz$/) { + $fh2->close(); + if (! -e $tempname) { + die "File $tempname disappeared!\n"; + } + $fh2 = new FileHandle("| gzip -c > $tempname"); + } elsif ($arg =~ /\.bz2$/) { + $fh2->close(); + if (! -e $tempname) { + die "File $tempname disappeared!\n"; + } + $fh2 = new FileHandle("| bzip2 -c > $tempname"); + } + unless ($fh2) { + die "$tempname: $!\n"; + } + + # Copy things before updated section + my $last_was_newline=1; # start first section in first line + while (<$fh>) { + if (/^%(.*)/ && $1 eq $update) { + last; + } + $last_was_newline = ($_ eq "\n"); + print $fh2 $_; + } + print $fh2 "\n" + unless ($last_was_newline); + + # Create/replace updated section + print $fh2 "%$update\n"; + while (<STDIN>) { + print $fh2 $_; + } + print $fh2 "\n"; + + # Skip obsolete section + while (<$fh>) { + if (/^%(.*)/) { + print $fh2 $_; + last; + } + } + # Copy things after updated section + while (<$fh>) { + print $fh2 $_; + } + unless (close $fh2) { + die "$arg.patch: $!\n"; + } + + if (-e $arg) { + unlink "$arg~"; + unless (rename $arg, "$arg~") { + die "Failed to rename $arg to $arg~: $!\n"; + } + } + unless (rename $tempname, $arg) { + rename("$arg~", $arg); + die "Failed to rename $arg.parse to $arg: $!\n"; + } + } + close $fh; +} diff --git a/scripts/patchfns.in b/scripts/patchfns.in new file mode 100644 index 0000000..e17d164 --- /dev/null +++ b/scripts/patchfns.in @@ -0,0 +1,614 @@ +# This file contains the common functions used in all quilt script +# It is meant to be sourced by bash scripts. + +# This script is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# See the COPYING and AUTHORS files for more details. + +if [ -n "$PATCHSCRIPTS" ] +then + P=$PATCHSCRIPTS/ +else + unset P +fi + +if [ -e .pc/series ] +then + SERIES=.pc/series +elif [ -e series ] +then + SERIES=series +else + SERIES=${P}patches/series +fi + +DB=".pc/applied-patches" + +# Define where diffstat lives (may be missing) +DIFFSTAT=/usr/bin/diffstat + +quote_re() +{ + echo "$1" | sed -e 's:\([\^\$/.+*\[\\]\):\\\1:g' +} + +#basename() +#{ +# local path=${1%/} +# echo "${path/*\/}" +#} + +#dirname() +#{ +# local path=${1%/} +#} + +patch_file_name() +{ + local patch=$1 + + if [ -e $SERIES ] + then + awk '/^'"$(quote_re $patch)"'(|\.patch|\.diff?)(|\.gz|\.bz2)([ \t]|$)/ \ + { printf "'"$P"'patches/%s\n", $1 + exit + } + ' $SERIES + fi +} + +# The -pN option and possibly others that should be passed to patch. +patch_args() +{ + local patch=$1 + + if [ -e $SERIES ] + then + awk ' + /^'"$(quote_re $patch)"'(|\.patch|\.diff?)(|\.gz|\.bz2)([ \t]|$)/ \ + { if (NF >= 2) + for (i=2; i <= NF; i++) + print $i + else + print "-p1" ; + exit + } + ' $SERIES + fi +} + +patch_strip_level() +{ + local patch=$1 i + for i in $(patch_args $patch) + do + case $i in + -p) + echo $2 + return ;; + -p*) + echo ${i:2} + return ;; + esac + done + echo "1" +} + +change_db_strip_level() +{ + local level=$1 patch=$2 + + if [ x$level != x-p1 ] + then + level="$level" + else + level="" + fi + + if [ -e $SERIES ] + then + local tmpfile=$(@MKTEMP@ /tmp/patch-scripts.XXXXXX) + awk ' + /^'"$(quote_re $patch)"'(\.patch|\.diff?)(|\.gz|\.bz2)([ \t]|$)/ \ + { for(i=2; i<=NF; i++) + if ($i ~ /^-p/) { + $i="'"$level"'" + break + } + if (i > NF) + $i="'"$level"'" + } + { print } + ' $SERIES > $tmpfile + if cmp $SERIES $tmpfile >/dev/null 2>/dev/null + then + rm -f $tmpfile + else + mv -f $tmpfile $SERIES + fi + else + return 1 + fi +} + +patch_in_series() +{ + local patch=$1 + + if ! [ -e $SERIES ] + then + return 1 + else + grep -q -E '^'"$(quote_re $patch)"'(|\.patch|\.diff?)(|\.gz|\.bz2)([ \t]|$)' $SERIES + fi +} + +# Insert new patch after topmost patch +insert_in_series() +{ + local patch=$1 patch_args=$2 + local top=$(top_patch) tmpfile + + if [ -n "$patch_args" ] + then + patch_args=" $patch_args" + fi + + tmpfile=$(@MKTEMP@ /tmp/patch-scripts.XXXXXX) || return 1 + mkdir -p $(dirname $SERIES) + if [ -n "$top" ] + then + awk ' + { print } + /^'"$(quote_re $top)"'(|\.patch|\.diff?)(|\.gz|\.bz2)([ \t]|$)/ \ + { print "'"$patch$patch_args"'" } + ' $SERIES > $tmpfile + status=$? + if [ $status -ne 0 ] + then + rm -f $tmpfile + return 1 + fi + else + echo $patch$patch_args > $tmpfile + if [ -e $SERIES ] + then + cat $SERIES >> $tmpfile + fi + fi + mv -f $tmpfile $SERIES +} + +remove_from_series() +{ + local patch=$1 + + tmpfile=$(@MKTEMP@ /tmp/patch-scripts.XXXXXX) || return 1 + awk ' + ! /^'"$(quote_re $patch)"'(|\.patch|\.diff?)(|\.gz|\.bz2)([ \t]|$)/ \ + { print } + ' $SERIES > $tmpfile + if [ $? -eq 0 ] + then + mv -f $tmpfile $SERIES + else + rm -f $tmpfile + return 1 + fi +} + +pc_file_name() +{ + while [ $# -gt 0 ] + do + echo ".pc/$1/.pc" + shift + done + +} + +backup_file_name() +{ + local patch=$1 + while [ $# -gt 1 ] + do + echo ".pc/$patch/$2" + shift + done +} + +cat_series() +{ + if [ -e $SERIES ] + then + sed -e '/^#/d' -e 's/^[ \t]*//' -e 's/[ \t].*//' \ + -e 's/\.gz$//' -e 's/\.bz2$//' \ + -e 's/\.patch$//' -e 's/\.diff\?$//' $SERIES + else + return 1 + fi +} + +top_patch() +{ + [ -e $DB ] && tail -1 $DB +} + +is_numeric() +{ + echo $1 | grep -q '^[0-9]*$' +} + +is_applied_last() +{ + local patch=$1 + [ "$(top_patch)" == $patch ] +} + +is_applied() +{ + local patch=$1 + [ -e $DB ] || return 1 + grep -q -E "^$(quote_re $patch)\$" $DB +} + +patches_before() +{ + local patch=$1 + + if [ -n "$patch" ] + then + cat_series \ + | awk ' + $0 == "'"$patch"'" { exit } + { print } + ' + fi +} + +patches_after() +{ + local patch=$1 + if [ -n "$patch" ] + then + cat_series \ + | awk ' + seen { print } + $0 == "'"$patch"'" { seen=1 } + ' + else + cat_series + fi +} + +# List all patches that have been applied on top of patch $1 +patches_on_top_of() +{ + local patch=$1 + [ -e $DB ] || return + awk ' + $0 == "'"$patch"'" { seen=1 ; next } + seen { print } + ' $DB +} + +# Print the name of the patch that modified the file $2 next after +# patch $1, or print nothing if patch $1 is on top. +next_patch_for_file() +{ + local patch=$1 file=$2 + local patches_on_top=$(patches_on_top_of $patch) + + if [ -n "$patches_on_top" ] + then + grep -l -E "^$(quote_re $file)\$" \ + $(pc_file_name $patches_on_top) \ + | head -1 \ + | sed -e 's:^\.pc/::' -e 's:/\.pc$::' + fi + + #modified_files $file -- $patches_on_top \ + #| cut -d $'\t' -f2 \ + #| cut -d ' ' -f1 +} + +# Create a list of files and the patches that modify them. +refresh_patches_per_file() +{ + local pc_files=$(pc_file_name $(cat_series)) + local ex_pc_files pc_file + + if [ -e .pc/patches-per-file ] + then + local needs_refresh + for pc_file in pc_files + do + if [ .pc/patches-per-file -ot $pc_file ] + then + needs_refresh=1 + break + fi + done + if [ -z "$needs_refresh" ] + then + return 0 + fi + fi + + for pc_file in $pc_files + do + if [ -e $pc_file ] + then + ex_pc_files[${#ex_pc_files[@]}]=$pc_file + fi + done + + if [ ${#ex_pc_files[@]} -eq 0 ] + then + rm -f .pc/patches-per-file + return 0 + fi + + awk ' + ARGIND!=saved { sub(/^.pc\//, "", FILENAME) + sub(/\/\.pc/, "", FILENAME) + saved=ARGIND + } + { if (files[$0]) + files[$0]=files[$0] " " FILENAME + else + files[$0]=FILENAME + } + END { for (file in files) + printf "%s\t%s\n", file, files[file] + } + ' "${ex_pc_files[@]}" > .pc/patches-per-file +} + +# For a lists of patches and a list of files, compute which patches +# modify which files. Invoked as +# modified_files file ... [-- patch ...] +# +modified_files() +{ + if ! refresh_patches_per_file + then + return 1 + fi + + awk ' + BEGIN { no_files=1 + no_patches=1 + for (i=1; i<ARGC; i++) { + if (ARGV[i]=="--") + break + files[ARGV[i]]=1 + no_files=0 + } + for (i++; i<ARGC; i++) { + patches[ARGV[i]]=1 + no_patches=0 + } + split("", ARGV) # read from standard input + } + no_files || files[$1] { + if (no_patches) { + print + next + } + for (i=2; i<=NF; i++) + if ($i in patches) { + printf "%s\t%s", $1, $i + for (i++; i<=NF; i++) + if ($i in patches) + printf " %s", $i + printf "\n" + } + } + ' "$@" < .pc/patches-per-file +} + +add_to_db() +{ + echo $1 >> $DB +} + +remove_from_db() +{ + local patch=$1 + local tmpfile + if tmpfile=$(@MKTEMP@ /tmp/patch-scripts.XXXXXX) + then + grep -v -E "^$(quote_re $patch)\$" $DB > $tmpfile + mv -f $tmpfile $DB + rm -f $tmpfile + [ -s $DB ] || rm -f $DB + fi +} + +stripit() +{ + if [ -n "$1" ] + then + echo $1 | + sed -e 's/^\(\.\/\)*//' \ + -e 's/^'"$P"'patches\///' -e 's/^\.pc\///' \ + -e 's/\.gz$//' -e 's/\.bz2$//' \ + -e 's/\.patch$//' -e 's/\.diff\?$//' + fi +} + +file_in_patch() +{ + local file=$1 patch=$2 + files_in_patch $patch \ + | grep -q -E "^$(quote_re $file)\$" +} + +files_in_patch() +{ + local pc_file=$(pc_file_name $1) + if [ -e "$pc_file" ] + then + cat $pc_file + fi +} + +touched_by_patch() +{ + local strip=$1 patch=$2 + cat_file $(patch_file_name $patch) \ + | awk ' + /^\+\+\+[ \t]/ { + sub(/^\+\+\+[ \t]/, "") + sub(/[ \t].*/, "") + sub(/^\/dev\/null/, "") + for (i=0; i<'$strip'; i++) + sub(/^[^\/]*\//, "") + print + }' +} + +refresh_file_list() +{ + local patch=$1 + local pc_file=$(pc_file_name $patch) + local patch_file=$(patch_file_name $patch) + + if ! [ -e "$patch_file" ] + then + return 0 + fi + if [ ! -e $pc_file -o \ + $pc_file -ot $patch_file -o \ + $pc_file -ot $SERIES ] + then + local tmpfile status + if ! mkdir -p $(dirname $pc_file) || \ + ! tmpfile=$(@MKTEMP@ /tmp/patch-scripts.XXXXXX) + then + return 1 + fi + + if [ -e $pc_file ] + then + cat $pc_file >> $tmpfile + fi + if ! touched_by_patch $(patch_strip_level $patch) \ + $patch >> $tmpfile + then + return 1 + fi + sort $tmpfile | uniq > $pc_file + rm $tmpfile + return 0 + fi +} + +diff_file() +{ + local file=$1 suffix=$2 old_file=$3 new_file=$4 + local old_file new_file + + if [ ! -e "$old_file" -a ! -e "$new_file" ] + then + echo "File $file does not exist" >&2 + return 0 + fi + local old_hdr new_hdr + if [ $opt_strip_level -eq 0 ] + then + old_hdr=$file$suffix + new_hdr=$file + else + local dir=$(basename $PWD) + old_hdr=$dir$suffix/$file + new_hdr=$dir/$file + fi + + echo Index: $new_hdr + @DIFF@ -Nu $DIFF_OPTS $old_file $new_file | + fix_diff_header $old_hdr $new_hdr +} + +fix_diff_header() +{ + local from=$1 to=$2 + sed -e 's:^--- [^ \t]*:--- '"$from"':' \ + -e 's:^+++ [^ \t]*:+++ '"$to"':' +} + +cat_file() +{ + local filename + + for filename in "$@" + do + if [ -e "$filename" ] + then + case "$filename" in + *.gz|*.tgz) + gzip -cd "$filename" ;; + *.bz2) + bzip2 -cd "$filename" ;; + *) + cat "$filename" ;; + esac + fi + done +} + +cat_to_file() +{ + local filename="$1" + + if [ -z "$filename" ] + then + cat + else + case "$filename" in + *.gz|*.tgz) + gzip -c > "$filename" ;; + *.bz2) + bzip2 -c > "$filename" ;; + *) + cat > "$filename" ;; + esac + fi +} + +patch_description() +{ + local patch_file=$1 + + if [ -e "$patch_file" -o -z "$patch_file" ] + then + awk ' + $1 == "---" { exit } + $1 == "Index:" { eat = eat $0 + next } + $1 == "diff" { eat = eat $0 + next } + eat { print eat + eat="" } + { print } + ' $patch_file + fi +} + +in_array() +{ + local a=$1 + while [ $# -gt 1 ] + do + shift + [ "$a" = "$1" ] && return 0 + done + return 1 +} +### Local Variables: +### mode: shell-script +### End: +# vim:filetype=sh diff --git a/scripts/rpatch.in b/scripts/rpatch.in new file mode 100755 index 0000000..afdf230 --- /dev/null +++ b/scripts/rpatch.in @@ -0,0 +1,254 @@ +#! @BASH@ + +# This script is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# See the COPYING and AUTHORS files for more details. + +# Read in library functions +if [ "$(type -t patch_file_name)" != function ] +then + if ! [ -r @SCRIPTS@/patchfns ] + then + echo "Cannot read library @SCRIPTS@/patchfns" >&2 + exit 1 + fi + . @SCRIPTS@/patchfns +fi + +usage() +{ + echo "Usage: $0 [-fRq] patchname" + exit 1 +} + +verify_removal() +{ + local patch=$1 + local bup file status=0 + local dir=$(basename $PWD) suffix=${patch//\//_} + + # Check if all changes of the patch are undone + for file in $(files_in_patch $patch) + do + bup=$(backup_file_name $patch $file) + if ! [ -s $file -o -s $bup ] || \ + cmp $file $bup > /dev/null 2> /dev/null + then + continue + fi + + if [ $status -eq 0 ] + then + echo "Patch does not remove changes:" + fi + + @DIFF@ -Nu $DIFF_OPTS $bup $file \ + | sed -e 's:^--- [^ \t]*:--- '"$dir/$file.orig"':' \ + -e 's:^+++ [^ \t]*:+++ '"$dir/$file"':' + + status=1 + done + return $status +} + +files_may_have_changed() +{ + local patch=$1 file + local patch_file=$(patch_file_name $patch) + local pc_file=$(pc_file_name $patch) + + if ! [ -e $pc_file ] + then + return 1 + fi + + local apply_ts=$(date -r $pc_file '+%s') ts + + if [ -e "$patch_file" -a $pc_file -ot "$patch_file" ] + then + return 0 + fi + + for file in $(files_in_patch $patch) + do + if ! [ -e $file ] + then + return 0 # file is missing + fi + + ts=$(date -r $file '+%s') + if [ $? -ne 0 -o $ts -gt $apply_ts ] + then + return 0 # file has changed + fi + done + return 1 +} + +rollback_patch() +{ + local patch=$1 pc_file=$(pc_file_name $patch) + @LIB@/backup-files $silent_unless_verbose \ + -f $pc_file -z ~rpatch -r + rm -f $(files_in_patch $patch | sed -e 's/$/\.rej/') +} + +interrupt() +{ + local patch=$1 + rollback_patch $patch + echo "Interrupted by user; patch $patch was not removed." + exit 1 +} + +reverse_patch() +{ + local patch=$1 + local patch_file=$(patch_file_name $patch) + + if ! [ -s $patch_file ] + then + echo "Patch file $patch_file appears to be empty" + return 0 + fi + + if [ "x${patch_file:(-3)}" = "x.gz" ] + then + gzip -cd $patch_file \ + | @PATCH@ $(patch_args $patch) --no-backup-if-mismatch \ + -R -E $silent + elif [ "x${patch_file:(-4)}" = "x.bz2" ] + then + bzip2 -cd $patch_file \ + | @PATCH@ $(patch_args $patch) --no-backup-if-mismatch \ + -R -E $silent + else + @PATCH@ $(patch_args $patch) --no-backup-if-mismatch \ + -R -E $silent -i $patch_file + fi +} + +rpatch() +{ + local patch=$1 pc_file=$(pc_file_name $patch) + + if ! [ -e $pc_file ] + then + echo "Patch $patch appears to be empty, removed" + remove_from_db $patch + return 0 + fi + + trap "" SIGINT + if [ -n "$opt_force" ] || \ + ( [ -z "$opt_remove" ] && ! files_may_have_changed $patch ) + then + # Optimize: Force remove if the patch has not been + # modified since it was applied. (Forced remove is + # faster!) + + @LIB@/backup-files $silent -f $pc_file -B .pc/$patch/ -r + status=$? + remove_from_db $patch + rm -f $pc_file~refresh + if [ $status != 0 ] + then + exit $status + fi + else + if ! @LIB@/backup-files $silent_unless_verbose \ + -f $pc_file -z ~rpatch + then + echo "Failed to create temporary files" >&2 + return 1 + fi + + trap "interrupt $patch" SIGINT + + reverse_patch $patch + status=$? + + trap "" SIGINT + + if [ $status -eq 0 ] && verify_removal $patch + then + @LIB@/backup-files $silent_unless_verbose \ + -f $pc_file -z ~rpatch -x + @LIB@/backup-files $silent_unless_verbose \ + -f $pc_file -B .pc/$patch/ -x + + remove_from_db $patch + else + rollback_patch $patch + echo "Patch $patch does not remove (enforce with -f)" + return 1 + fi + fi + trap - SIGINT + + local top=$(top_patch) where + if [ -z "$top" ] + then + where="no patches applied" + else + where="now at $top" + fi + echo "Removed $patch, $where" +} + +options=`getopt -o fRqvh -- "$@"` + +if [ $? -ne 0 ] +then + usage +fi + +eval set -- "$options" + +while true +do + case "$1" in + -f) + opt_force=1 + shift ;; + -R) + opt_remove=1 # remove properly with patch -R; no tricks + unset opt_force + shift ;; + -q) + opt_quiet=1 + shift ;; + -v) + opt_verbose=1 + shift ;; + -h) + usage -h ;; + --) + shift + break ;; + esac +done + +if [ $# -ne 1 ] +then + usage +fi + +patch=$(stripit $1) +[ -n "$opt_quiet" ] && silent=-s +[ -z "$opt_verbose" ] && silent_unless_verbose=-s + +top=$(top_patch) +if [ -n "$top" -a -e $(pc_file_name $top)~refresh -a -z "$opt_force" ] +then + echo "The topmost patch $top needs to be refreshed first." + exit 1 +fi + +rpatch "$patch" || exit 1 +### Local Variables: +### mode: shell-script +### End: +# vim:filetype=sh diff --git a/scripts/spec2series.in b/scripts/spec2series.in new file mode 100755 index 0000000..63aa50b --- /dev/null +++ b/scripts/spec2series.in @@ -0,0 +1,227 @@ +#! @BASH@ + +# This script is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# See the COPYING and AUTHORS files for more details. + +# defaults +debug=0 +specfile="" +outfile="" + +function usage() { +cat <<EOF +Usage: quilt spec2series [ options ] specfile + +-h print this text +-d debug mode (prints lots additional info + as comments into the output file) +-o <file> + specify output file, stdout if unspecified + +EOF +} + +# parse args +while test "$1" != ""; do + case "$1" in + -h | --help) + usage; exit 0 + ;; + -d | --debug) + debug=1; shift + ;; + -o | --outfile) + outfile="$2"; shift; shift + ;; + *) + specfile="$1" + break; + ;; + esac +done + +if test ! -f "$specfile"; then + usage + exit 1 +fi + +# get absolute patch for specfile location +specdir=`dirname $specfile` +specfile=`basename $specfile` +case "$specdir" in + .) specdir="`pwd`" + ;; + /*) # nothing + ;; + *) specdir="`pwd`/$specdir" + ;; +esac + +# create tmp work dir +WORK="${TMPDIR-/tmp}/rpmlog-$$" +mkdir -p "$WORK" || exit 1 +trap 'rm -rf "$WORK"' EXIT +mkdir -p "$WORK/build" +mkdir -p "$WORK/bin" + +# create md5 sums, also for uncompressed files +echo -n "### md5: " >&2 +(cd $specdir; for file in /dev/null *; do + case "$file" in + ready | bigpack | MD5SUMS | MD5SUMS.meta | *.spec | *.changes) + continue + ;; + esac + type="`file -b $file | cut -d" " -f1`" + case "$type" in + compress*) + echo -n "z" >&2 + set -- `zcat $file | md5sum` + echo "$1 zcat ${file}" + ;; + gzip) + echo -n "g" >&2 + set -- `zcat $file | md5sum` + echo "$1 zcat ${file}" + ;; + bzip2) + echo -n "b" >&2 + set -- `bzcat $file | md5sum` + echo "$1 bzcat ${file}" + ;; + esac + echo -n "." >&2 + set -- `md5sum < $file` + echo "$1 cat ${file}" +done) > $WORK/md5sum +echo " done" >&2 + +# prepare rpm dir fixups and hooks +RPM="rpm --rcfile=/usr/lib/rpm/rpmrc:$WORK/rpmrc" +PATH="$WORK/bin:$PATH" +grep ^macrofiles /usr/lib/rpm/rpmrc \ + | sed -e "/macrofiles/s|$|:$WORK/rpmmacros|" \ + > $WORK/rpmrc +cat <<-EOF > "$WORK/rpmmacros" + %_sourcedir $specdir + %_specdir $specdir + %_builddir $WORK/build +EOF + +# wrapper script for patch and tar +cat <<-'EOF' > "$WORK/bin/patch" + #!/bin/sh + + # save stuff for log + unpackcmd=`basename $0` + unpackdir=`pwd` + unpackargs="$*" + uncompress="false" + unpackfile="[oops]" + + # sort of progress bar + case $unpackcmd in + tar) echo -n "t" >&2;; + patch) echo -n "p" >&2;; + *) echo -n "?" >&2;; + esac + + # find real binary + realcmd="" + test -x "/bin/$unpackcmd" && realcmd="/bin/$unpackcmd" + test -x "/usr/bin/$unpackcmd" && realcmd="/usr/bin/$unpackcmd" + test "$realcmd" = "" && exit 1 + + # put data into tmpfile, exec real cmd, return on failure + WORK=`dirname $RPM_BUILD_DIR` + cat > "$WORK/data" + if test -x /bin/$unpackcmd; then + cmddir="/bin" + fi + $realcmd $* < "$WORK/data" + retval="$?" + test "$retval" != "0" && exit $retval + + # find original data file by md5sum + set -- `md5sum < "$WORK/data"` + unpackfile="[$1]" + set -- `cat "$WORK/md5sum"` + while test "$1" != ""; do + if test "[$1]" = "$unpackfile"; then + uncompress="$2" + unpackfile="$3" + break + fi + shift + done + + # print results + unpackdir=`echo $unpackdir | sed -e "s|$RPM_BUILD_DIR|BUILD|"` + echo -n "# log: [$unpackdir] $uncompress $unpackfile" >>$WORK/cmdlog + echo " | $unpackcmd $unpackargs" >>$WORK/cmdlog + if test "$unpackcmd" = "patch" -a \ + -f "$RPM_SOURCE_DIR/$unpackfile"; then + patchdir="${unpackdir#BUILD/}" + if test ! -f "$WORK/patchdir"; then + echo -n $patchdir > $WORK/patchdir + fi + if test "`cat $WORK/patchdir`" = "$patchdir"; then + level=`echo $unpackargs | tr " " "\n" | grep ^-p` + echo "$unpackfile $level" >> $WORK/patchlog + fi + fi + if test "$unpackcmd" = "tar" -a \ + -f "$RPM_SOURCE_DIR/$unpackfile"; then + echo -n "# Source: $unpackfile" >>$WORK/tarlog + if test "$unpackdir" != "BUILD"; then + echo -n " -C ${unpackdir#BUILD/}" >>$WORK/tarlog + fi + echo "" >>$WORK/tarlog + fi +EOF +chmod 755 "$WORK/bin/patch" +ln -s patch "$WORK/bin/tar" + +# let rpm do all the dirty specfile stuff ... +echo -n "### rpm: " >&2 +touch $WORK/patchlog +$RPM --nodeps --quiet -bp "$specdir/$specfile" </dev/null +echo " done" >&2 + +# print results saved by the wrapper script +( + # header + echo "# Patch series file for quilt, created by $0" + echo "#" + echo "# Sourcedir: $specdir" + echo "# Specfile: $specfile" + if test -f $WORK/patchdir; then + echo "# Patchdir: `cat $WORK/patchdir`" + fi + echo "#" + + # additional info for trouble shooting + if test "$debug" = "1"; then + cat $WORK/md5sum | sed -e 's/^/# md5: /' + echo "#" + + test -f $WORK/cmdlog && cat $WORK/cmdlog && echo "#" + fi + + # list tarballs + patches + test -f $WORK/tarlog && cat $WORK/tarlog && echo "#" + test -f $WORK/patchlog && cat $WORK/patchlog +)|( + if test "$outfile" != ""; then + cat > "$outfile" + else + cat + fi +) +### Local Variables: +### mode: shell-script +### End: +# vim:filetype=sh |