summaryrefslogtreecommitdiffstats
path: root/scripts
diff options
context:
space:
mode:
Diffstat (limited to 'scripts')
-rwxr-xr-xscripts/apatch.in189
-rw-r--r--scripts/parse-patch.in129
-rw-r--r--scripts/patchfns.in614
-rwxr-xr-xscripts/rpatch.in254
-rwxr-xr-xscripts/spec2series.in227
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