summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--AUTHORS35
-rw-r--r--Makefile133
-rw-r--r--README.in7
-rw-r--r--TODO96
-rwxr-xr-xbin/guards246
-rw-r--r--bin/quilt.in90
-rw-r--r--docco.txt717
-rwxr-xr-xinpatch.in143
-rwxr-xr-xlib/apatch.in114
-rw-r--r--lib/backup-files.c228
-rwxr-xr-xlib/parse-patch46
-rw-r--r--lib/patchfns.in434
-rwxr-xr-xlib/rpatch.in148
-rwxr-xr-xlib/spec2series223
-rwxr-xr-xlib/touched-by-patch69
-rw-r--r--patch-scripts.changes11
-rw-r--r--quilt.changes36
-rw-r--r--quilt.spec (renamed from patch-scripts.spec)43
-rw-r--r--[-rwxr-xr-x]quilt/add.in (renamed from patchadd.in)61
-rw-r--r--quilt/applied.in71
-rw-r--r--quilt/delete.in92
-rw-r--r--quilt/diff.in244
-rw-r--r--quilt/files.in112
-rw-r--r--[-rwxr-xr-x]quilt/import.in (renamed from importpatch.in)44
-rw-r--r--[-rwxr-xr-x]quilt/new.in (renamed from newpatch.in)42
-rw-r--r--quilt/next.in72
-rw-r--r--quilt/patches.in93
-rw-r--r--[-rwxr-xr-x]quilt/pop.in (renamed from poppatch.in)29
-rw-r--r--quilt/previous.in70
-rw-r--r--[-rwxr-xr-x]quilt/push.in (renamed from pushpatch.in)26
-rw-r--r--quilt/refresh.in201
-rw-r--r--quilt/remove.in119
-rwxr-xr-xquilt/rest.in72
-rw-r--r--quilt/series.in87
-rw-r--r--quilt/setup.in172
-rw-r--r--quilt/top.in62
-rwxr-xr-xrefpatch.in335
-rwxr-xr-xtoppatch.in138
38 files changed, 3795 insertions, 1166 deletions
diff --git a/AUTHORS b/AUTHORS
index 789c573..745db37 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -1,11 +1,32 @@
-At the begining was the void. Then Andrew Morton <akpm@digeo.com> begun a
-collection of small scripts for patch management. The contributions came of
-Stephen Cameron <steve.cameron@hp.com>, Matt Reppert <arashi@arashi.yi.org>
-and Jeremy Fitzhardinge <jeremy@digeo.com>.
+At the begining was the void. Then Andrew Morton <akpm@digeo.com> begun
+a collection of small scripts for patch management. The contributions
+came from Stephen Cameron <steve.cameron@hp.com>, Matt Reppert
+<arashi@arashi.yi.org> and Jeremy Fitzhardinge <jeremy@digeo.com>.
Then, Andreas Gruenbacher <agruen@suse.de> came to cleanup, reorganize,
-document and speed up the code. He did also package it to rpm
+document and speed up the code. He did also package it to rpm.
-Finally, Martin Quinson <Martin.Quinson@tuxfamily.org> did a debian package
-and came with several little patches.
+Finally, Martin Quinson <Martin.Quinson@tuxfamily.org> did a debian
+package and came with several little patches.
+
+Andrew Morton <akpm@digeo.com>
+ Collection of scripts for patch management (patch-scripts).
+
+Stephen Cameron <steve.cameron@hp.com>
+ Contributed pstatus.
+
+Matt Reppert <arashi@arashi.yi.org>
+Jeremy Fitzhardinge <jeremy@digeo.com>
+ Contributions to Andrew's scripts.
+
+Andreas Gruenbacher <agruen@suse.de>
+ Clean up, reorganize, speedups, documentation.
+ Package up as RPM.
+
+Gerd Knorr <kraxel@suse.de>
+ Contributed spec2series.
+
+Martin Quinson <Martin.Quinson@tuxfamily.org>
+ Several little patches.
+ Package up for Debian.
diff --git a/Makefile b/Makefile
index eb4f727..9bf5b8f 100644
--- a/Makefile
+++ b/Makefile
@@ -1,67 +1,110 @@
-SCRIPTS_IN := inpatch newpatch patchadd poppatch pushpatch refpatch toppatch \
- importpatch
-LIB_SCRIPTS_IN := apatch rpatch patchfns backup-files
-LIB_SCRIPTS := touched-by-patch parse-patch
-#LIB_LIB := patchfns
+PACKAGE := quilt
+VERSION := 0.21
-VERSION := 0.11.1
+prefix := /usr/local
+bindir := $(prefix)/bin
+datadir := $(prefix)/share
+mandir := $(datadir)/man
+docdir := $(datadir)/doc/packages
-prefix := /usr/local
-bindir := $(prefix)/bin
-datadir := $(prefix)/share
-LIB := $(datadir)/patch-scripts
-docdir := $(datadir)/doc/packages
+QUILT_DIR = $(datadir)/$(PACKAGE)
+LIB_DIR = $(datadir)/$(PACKAGE)/lib
-CFLAGS = -Wall
+CFLAGS = -g -Wall
-% : %.in
- @echo "$< -> $@"
- @sed -e "s:@LIB@:$(LIB):g" $< > $@
- @chmod --reference=$< $@
+#-----------------------------------------------------------------------
+SRC += COPYING AUTHORS TODO BUGS Makefile \
+ quilt.spec quilt.changes \
+ misc/akmp-patch-scripts-0.9.tar.gz \
+ misc/jr-quilt-0.1.0.tar.bz2 \
+ misc/test.tar.gz
+
+BIN_IN := quilt
+BIN_SRC := $(BIN_IN:%=%.in) guards
+BIN := $(BIN_IN) guards
+SRC += $(BIN_SRC:%=bin/%)
+DIRT += $(BIN_IN:%=bin/%)
+
+QUILT_IN := add applied delete diff files import new next patches \
+ pop previous push refresh remove rest series setup top
-all : scripts README
+QUILT_SRC := $(QUILT_IN:%=%.in)
+QUILT := $(QUILT_IN)
+SRC += $(QUILT_SRC:%=quilt/%)
+DIRT += $(QUILT_IN:%=quilt/%)
-scripts : $(SCRIPTS_IN) $(LIB_SCRIPTS_IN:%=lib/%)
+LIB_IN := apatch rpatch patchfns
+LIB_SRC := $(LIB_IN:%=%.in) parse-patch spec2series \
+ backup-files.c
+LIB := $(LIB_IN) parse-patch spec2series backup-files
+SRC += $(LIB_SRC:%=lib/%)
+DIRT += $(LIB_IN:%=lib/%) lib/backup-files{,.o}
+
+DOC_IN := README
+DOC_SRC := $(DOC_IN:%=%.in)
+DOC := $(DOC_IN) docco.txt
+SRC += $(DOC_SRC) docco.txt
+DIRT += $(DOC_IN)
+
+MAN1 := bin/guards.1
+#-----------------------------------------------------------------------
+
+all : scripts
+
+scripts : $(BIN:%=bin/%) $(QUILT:%=quilt/%) $(LIB:%=lib/%) \
+ $(DOC) $(MAN1)
README : README.in
- @echo "$< -> $@"
@awk '/@REFERENCE@/ { system("$(MAKE) -s reference") ; next }'$$'\n'' \
- { print }' $< > $@
+ { print }' 2>&1 $< > $@
-reference : $(SCRIPTS_IN)
- @for i in $(SCRIPTS_IN); \
+.PHONY :: reference
+reference : $(QUILT:%=quilt/%)
+ @for i in $+; \
do \
+ echo "$$i >> README" >&2; \
echo; \
- ./$$i -h; \
+ (bash -c ". lib/patchfns ; . $$i -h"); \
done | \
awk '/Usage:/ { sub(/Usage: ?/, "") ; print ; next } '$$'\n'' \
{ printf " %s\n", $$0 }'
-dist : distclean
- rm -f patch-scripts-$(VERSION)
- ln -s . patch-scripts-$(VERSION)
- tar cvfz patch-scripts-$(VERSION).tar.gz \
- --exclude=patch-scripts-$(VERSION)/patch-scripts-* \
- --exclude=CVS \
- patch-scripts-$(VERSION)/*
- rm -f patch-scripts-$(VERSION)
+bin/guards.1 : bin/guards
+ mkdir -p $$(dirname $@)
+ pod2man $< > $@
-install : all
- install -d $(BUILD_ROOT)$(LIB)
- install -m 755 $(LIB_SCRIPTS_IN:%=lib/%) \
- $(BUILD_ROOT)$(LIB)
- install -m 755 $(LIB_SCRIPTS:%=lib/%) \
- $(BUILD_ROOT)$(LIB)
- #install -m 644 $(LIB_LIB:%=lib/%) \
- # $(BUILD_ROOT)$(LIB)
+dist :
+ rm -f $(PACKAGE)-$(VERSION)
+ ln -s . $(PACKAGE)-$(VERSION)
+ tar cvfz $(PACKAGE)-$(VERSION).tar.gz \
+ $(SRC:%=$(PACKAGE)-$(VERSION)/%)
+ rm -f $(PACKAGE)-$(VERSION)
+install : all
install -d $(BUILD_ROOT)$(bindir)
- install -m 755 $(SCRIPTS_IN) \
- $(BUILD_ROOT)$(bindir)
+ install -m 755 $(BIN:%=bin/%) $(BUILD_ROOT)$(bindir)/
+
+ install -d $(BUILD_ROOT)$(QUILT_DIR)
+ install -m 755 $(QUILT:%=quilt/%) $(BUILD_ROOT)$(QUILT_DIR)/
+
+ install -d $(BUILD_ROOT)$(LIB_DIR)
+ install -m 755 $(filter-out lib/patchfns lib/backup-files, \
+ $(LIB:%=lib/%)) $(BUILD_ROOT)$(LIB_DIR)/
+ install -m 644 lib/patchfns $(BUILD_ROOT)$(LIB_DIR)/
+ install -m 755 -s lib/backup-files $(BUILD_ROOT)$(LIB_DIR)/
+
+ install -d $(BUILD_ROOT)$(docdir)/$(PACKAGE)
+ install -m 644 README $(BUILD_ROOT)$(docdir)/$(PACKAGE)/
- install -d $(BUILD_ROOT)$(docdir)/patch-scripts
- install -m 644 README needs-checking/docco.txt \
- $(BUILD_ROOT)$(docdir)/patch-scripts
+ install -d $(BUILD_ROOT)$(mandir)/man1
+ install -m 644 $(MAN1) $(BUILD_ROOT)$(mandir)/man1/
clean distclean :
- rm -f $(SCRIPTS_IN) $(LIB_SCRIPTS_IN:%=lib/%) README
+ rm -f $(DIRT)
+
+% : %.in
+ @echo "$< -> $@"
+ @sed -e "s:@LIB@:$(LIB_DIR):g" \
+ -e "s:@QUILT@:$(QUILT_DIR):g" \
+ $< > $@
+ @chmod --reference=$< $@
diff --git a/README.in b/README.in
index 872d9b0..83f252c 100644
--- a/README.in
+++ b/README.in
@@ -83,6 +83,13 @@ Command reference
=================
@REFERENCE@
+guards [--prefix=dir] [--path=dir1:dir2:...] [--default=0|1]
+ [--check] [--config=file] symbol ...
+
+ Convert a series file with conditional statements into a series
+ file as expected; see the guards(1) manual page.
+
+
Helper files/scripts
====================
diff --git a/TODO b/TODO
index 4931b51..cd9f50f 100644
--- a/TODO
+++ b/TODO
@@ -1,13 +1,93 @@
-Keep -p0 and -p1 patches, and convert -pN (N>1) to -p1 in refpatch
+This is my current list of open issues with the patch scripts. I would
+like to do the most intrusive changes before syncing up with the
+Savannah CVS. Of course, contributions are very welcome. It wouldn't
+hurt to know if you want to work on some of the issues in advance to
+avoid duplicate work, though :)
-Test Suite
+ -- Andreas Gruenbacher <agruen@suse.de>
-Support compressed files in .pc/?
-Use proper temporary files in parse-patch, so that parse-patch can be used
-multiple times in pipes!
+General:
-check if things like reading the patch file list should be done globally
-in some scripts.
+ - Test if patches/ can be moved with environment variable as
+ planned.
+
+ - Abstract backup operations to/from the .pc/ directory, so that
+ optionally something like rcs can be used instead of
+ lib/backup-files?
+
+ - Add regression test suite; the scripts were broken often enough
+ already...
+
+ - Add a ~/.quiltrc that contains default options for individual
+ commands, similar to ~/.cvsrc. Also requires some more
+ negative options so that the effects of ~/.quiltrc can be
+ reversed.
+
+ - Add something similar to cvs diff, which scans all files for
+ changes that have not been folded back into their patches,
+ similar to:
+ `for p in $(quilt series); do quilt diff -z $p; done'?
+
+ - Allow to add a directory? Then we could detect also new files
+ in the directory, without having to add them individually.
+
+ - Add option for creating hard links.
+Documentation:
+
+ - How to rediff with pushpatch -f / poppatch -f?
+
+ - How to import a new version of a patch?
+
+ - How to import a complete directory, before doing
+ wild changes? (This will also cause new files to end up in the
+ patch.)
+
+parse-patch:
+
+ - Handle SIGINT in parse-patch -u (in the part that moves the
+ temp file to the patch)?
+
+backup-files:
+
+ - Extend so that it can also copy files instead of hard linking,
+ and when hard links are not possible. Also add option to
+ disallow hard links on the original file (for patchadd).
+
+ - SIGINT handling?
+
+quilt import:
+
+ - Add option to replace the currently applied patch with a new
+ one, by backing out the topmost patch first.
+
+ - Diff -u the documentation of the old and new file, unless one
+ of them is empty. Let the user decide whether to keep the left
+ or the right documentation, or to merge them both. (-d{ona}?)
+
+quilt add:
+
+ - Add option for creating (or rather, leaving) hard links.
+
+
+quilt setup:
+
+ - spec2series also prints -p1; omit.
+
+rpatch:
+
+ - If not removing the topmost patch, add checks if any files are
+ hidden by later patches. If so, refuse to remove patch! (Note
+ that poppatch takes care of that currently.)
+
+apatch:
+
+ - Allow to add a patch in the middle of the applied series, and
+ inject the patch in its proper position in applied-patches.
+ Needs to check if any of the files in the patch are touched by
+ later patches.
+
+touched_by_patch:
+
+ - Implement more of patch's filename heuristic?
-Clean up temp file handling
diff --git a/bin/guards b/bin/guards
new file mode 100755
index 0000000..9681186
--- /dev/null
+++ b/bin/guards
@@ -0,0 +1,246 @@
+#!/usr/bin/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.
+
+use FileHandle;
+use Getopt::Long;
+use strict;
+
+# Prototypes
+sub files_in($$);
+sub parse($$);
+sub help();
+
+sub slashme($) {
+ my ($dir) = @_;
+ $dir =~ s#([^/])$#$&/#; # append a slash if necessary
+ if ($dir eq './') {
+ return '';
+ } else {
+ return $dir;
+ }
+}
+
+# Generate a list of files in a directory
+#
+sub files_in($$) {
+ my ($dir, $path) = @_;
+ my $dh = new FileHandle;
+ my (@files, $file);
+
+
+ opendir $dh, length("$dir$path") ? "$dir$path" : '.'
+ or die "$dir$path: $!\n";
+ while ($file = readdir($dh)) {
+ next if $file =~ /^(\.|\.\.|\.#.*|CVS)$/;
+ if (-d "$dir$path$file") {
+ @files = (@files, files_in($dir, "$path$file/"));
+ } else {
+ #print "[$path$file]\n";
+ push @files, "$path$file";
+ }
+ }
+ closedir $dh;
+ return @files;
+}
+
+# Parse a configuration file
+# Callback called with ($patch, @guards) arguments
+#
+sub parse($$) {
+ my ($fh, $callback) = @_;
+
+ my $mode = 0;
+
+ while (<$fh>) {
+ my @guards = ();
+ s/(^|\s+)#.*//;
+ foreach my $token (split) {
+ if ($token =~ /^[-+]/) {
+ if ($mode == 1) {
+ @guards = ();
+ $mode = 0;
+ }
+ push @guards, $token;
+ } else {
+ $mode = 1;
+ #print "[" . join(",", @guards) . "] $patch\n";
+ &$callback($token, @guards);
+ }
+ }
+ }
+}
+
+# Command line options
+#
+my ($dir, $config, $default, $check) = ('', '-', 1, 0);
+my @path;
+
+# Help text
+#
+sub help() {
+ print "$0 - select from a list of files guarded by conditions\n";
+ print "SYNOPSIS: $0 [--prefix=dir] [--path=dir1:dir2:...]\n" .
+ " [--default=0|1] [--check] [--config=file] symbol ...\n\n" .
+ " (Default values: --path='" . join(':', @path) . "', " .
+ "--default=$default)\n";
+ exit 0;
+}
+
+# Parse command line options
+#
+Getopt::Long::Configure ("bundling");
+eval {
+ unless (GetOptions (
+ 'd|prefix=s' => \$dir,
+ 'c|config=s' => \$config,
+ 'C|check' => \$check,
+ 'p|path=s' => \@path,
+ 'D|default=i' => \$default,
+ 'h|help' => sub { help(); exit 0; })) {
+ help();
+ exit 1;
+ }
+};
+if ($@) {
+ print "$@";
+ help();
+ exit 1;
+}
+
+@path = ('.')
+ unless (@path);
+@path = split(/:/, join(':', @path));
+
+my $fh = ($config eq '-') ? \*STDIN : new FileHandle($config)
+ or die "$config: $!\n";
+
+$dir = slashme($dir);
+
+if ($check) {
+ # Check for duplicate files, or for files that are not referenced by
+ # the specification.
+
+ my $problems = 0;
+ my @files;
+
+ foreach (@path) {
+ @files = (@files, files_in($dir, slashme($_)));
+ }
+ my %files = map { $_ => 0 } @files;
+
+ parse($fh, sub {
+ my ($patch, @guards) = @_;
+ if (exists $files{$patch}) {
+ $files{$patch}++;
+ } else {
+ print "Not found: $dir$patch\n";
+ $problems++;
+ }});
+
+ $fh->close();
+
+ my ($file, $ref);
+ while (($file, $ref) = each %files) {
+ next if $ref == 1;
+
+ print "Unused: $file\n" if $ref == 0;
+ print "Multiple uses: $file\n" if $ref > 1;
+ $problems++;
+ }
+ exit $problems ? 1 : 0;
+
+} else {
+ # Generate a list of patches to apply.
+
+ my %symbols = map { $_ => 1 } @ARGV;
+
+ parse($fh, sub {
+ my ($patch, @guards) = @_;
+
+ my $selected;
+ if (@guards) {
+ # If the first guard is -xxx, the patch is included by default;
+ # if it is -xxx, the patch is excluded by default.
+ $selected = ($guards[0] =~ /^-/);
+
+ foreach (@guards) {
+ /^([-+])(!?)(.*)?/
+ or die "Bad guard '$_'\n";
+
+ # Check if the guard matches
+ if (($2 eq '!' && !exists $symbols{$3}) ||
+ ($2 eq '' && ( $3 eq '' || exists $symbols{$3}))) {
+ # Include or exclude
+ $selected = ($1 eq '+');
+ }
+ }
+ } else {
+ # If there are no guards, use the specified default result.
+ $selected = $default;
+ }
+
+ print "$dir$patch\n"
+ if $selected;
+ });
+
+ $fh->close();
+
+ exit 0;
+}
+
+__END__
+
+=head1 NAME
+
+guards - select from a list of files guarded by conditions
+
+=head1 SYNOPSIS
+
+F<guards> [--prefix=F<dir>] [--path=F<dir2:dir2:...>]
+ [--default=I<0>|I<1>] [--check] [--config=F<file>]
+ I<symbol> ...
+
+=head1 DESCRIPTION
+
+The script reads a configuration file that may contain so-called guards, file
+names, and comments, and writes those file names that satisfy all guards to
+standard output. The script takes a list of symbols as its arguments. Each line
+in the ocnfiguration file is processed separately. Lines may start with a
+number of guards. The following guards are defined:
+
+=over
+
++I<xxx> Include the file(s) on this line if the symbol I<xxx> is defined.
+
+-I<xxx> Exclude the file(s) on this line if the symbol I<xxx> is defined.
+
++!I<xxx> Include the file(s) on this line if the symbol I<xxx> is not defined.
+
+-!I<xxx> Exclude the file(s) on this line if the symbol I<xxx> is not defined.
+
+- Exclude this file. Used to avoid spurious I<--check> messages.
+
+=back
+
+The guards are processed left to right. The last guard that matches determines
+if the file is included. If no guard is specified, the I<--default>
+setting determines if the file is included.
+
+If no configuration file is specified, the script reads from standard input.
+
+The I<--check> option is used to compare the specification file against the
+file system. If files are referenced in the specification that do not exist, or
+if files are not enlisted in the specification file warnings are printed. The
+I<--path> option can be used to specify which directory or directories to scan.
+Multiple directories are eparated by a colon (C<:>) character. The
+I<--prefix> option specifies the location of the files.
+
+=head1 AUTHOR
+
+Andreas Gruenbacher <agruen@suse.de> (SuSE Linux AG)
+
diff --git a/bin/quilt.in b/bin/quilt.in
new file mode 100644
index 0000000..d1a6867
--- /dev/null
+++ b/bin/quilt.in
@@ -0,0 +1,90 @@
+#!/bin/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.
+
+usage()
+{
+
+ echo "Usage: quilt command [-h] ..." >&2
+ #echo "Commands are:" $(
+ # local command
+ # for command in @QUILT@/*
+ # do
+ # if [ -f "$command" -a -x "$command" ]
+ # then
+ # echo "${command#@QUILT@/}"
+ # fi
+ # done \
+ # | sort
+ #)
+ echo "Commands are:"
+ quilt_commands \
+ | sort \
+ | column | column -t \
+ | sed -e 's/^/\t/'
+ exit 1
+}
+
+quilt_commands()
+{
+ local command
+ for command in @QUILT@/*
+ do
+ if [ -f "$command" -a -x "$command" ]
+ then
+ echo ${command##@QUILT@/}
+ fi
+ done
+}
+
+for arg in "$@"
+do
+ case $arg in
+ [^-]*)
+ if [ -z "$command" ]
+ then
+ command="$arg"
+ else
+ args[${#args[@]}]="$arg"
+ fi ;;
+ *)
+ args[${#args[@]}]="$arg" ;;
+ esac
+done
+
+if ! [ -f "@QUILT@/$command" -a -x "@QUILT@/$command" ]
+then
+ if [ -n "$command" ]
+ then
+ for arg in $(quilt_commands)
+ do
+ case "$arg" in
+ $command*)
+ commands[${#commands[@]}]="$arg"
+ ;;
+ esac
+ done
+ fi
+
+ if [ ${#commands[@]} -eq 0 ]
+ then
+ usage
+ elif [ ${#commands[@]} -eq 1 ]
+ then
+ command="${commands[0]}"
+ unset commands
+ else
+ echo "$command:" "${commands[@]}" >&2
+ exit 1
+ fi
+fi
+
+set -- "${args[@]}"
+unset arg args
+
+#. @QUILT@/$command
+bash -c ". @QUILT@/$command" "quilt ${command##*/}" "$@"
diff --git a/docco.txt b/docco.txt
new file mode 100644
index 0000000..1860f13
--- /dev/null
+++ b/docco.txt
@@ -0,0 +1,717 @@
+Patch management scripts
+Andrew Morton <akpm@digeo.com>
+18 October 2002
+
+This is a description of a bunch of shell scripts which I use for
+managing kernel patches. They are quite powerful. They can be used on
+projects other than the linux kernel. They are easy to use, and fast.
+
+You end up doing a ton of recompiling with these scripts, because
+you're pushing and popping all the time. ccache takes away the pain of
+all that. http://ccache.samba.org/ - be sure to put the cache
+directory on the same fs as where you're working so that ccache can use
+hardlinks.
+
+The key philosophical concept is that your primary output is patches.
+Not ".c" files, not ".h" files. But patches. So patches are the
+first-class object here.
+
+Installation
+============
+
+You place all the scripts somewhere in your path, or in
+/usr/lib/patch-scripts.
+
+Terminology
+===========
+
+The patch scripts require three special directories called "pc",
+"patches" and "txt".
+
+If the environment variable PATCHSCRIPTS is set, it is taken to to be
+the directory in which those three directories reside. Typically, it
+would be a relative pathname. So
+
+ setenv PATCHSCRIPTS ./i-put-them-here
+
+would tell the patch scripts to look in ./i-put-them-here/pc, etc.
+
+If PATCHSCRIPTS is not set, and the directory ./patch-scripts is
+present then the patch scripts will us ./patch-scripts/pc/,
+./patch-scripts/patches/ and ./patch-scripts/txt/.
+
+Otherwise, the patch scripts use ./pc, ./patches and ./txt.
+
+In this document, the symbol $P is used to describe the directory which
+holds the pc/, patches/ and txt/ directories, as determined by the
+above search.
+
+It is expected that $P will always expand to a relative path.
+
+Concepts
+========
+
+All work occurs with a single directory tree. All commands are invoked
+within the root of that tree. The scripts manage a "stack" of patches.
+
+Each patch is a changeset against the base tree plus the preceding patches.
+
+All patches are listed, in order, in the file ./series. You manage the
+series file. Lines in the series file which start with `#' are ignored.
+
+Any currently-applied patches are described in the file
+./applied-patches. The patch scripts manage this file.
+
+Each patch affects a number of files in the tree. These files are
+listed in a "patch control" file. These .pc files live in the
+directory $P/pc/
+
+Patches are placed in the directory $P/patches/
+
+Documentation for the patches is placed in $P/txt/
+
+So for a particular patch "my-first-patch" the following will exist:
+
+- An entry "my-first-patch.patch" in ./series
+
+- An entry "my-first-patch" in ./applied-patches (if it's currently applied)
+
+- A file $P/pc/my-first-patch.pc which contains the names of the
+ files which my-first-patch modifies, adds or removes
+
+- A file $P/txt/my-first-patch.txt which contains the patch's
+ changelog.
+
+- A file $P/patches/my-first-patch.patch, which is the output of the
+ patch scripts.
+
+Operation
+=========
+
+When a patch "my-patch" is applied with apatch, or with pushpatch
+(which calls apatch), all the affected files (from $P/pc/my-patch.pc)
+are copied to files with ~my-patch appended. So if $P/pc/my-patch.pc
+contained
+
+ kernel/sched.c
+ fs/inode.c
+
+then apatch will copy those files into kernel/sched.c~my-patch and
+fs/inode.c~my-patch. It will then apply the patch to kernel/sched.c
+and fs/inode.c
+
+When a diff is regenerated by refpatch (which calls mpatch), the diff
+is made between kernel/sched.c and kernel/sched.c~my-patch. How do the
+scripts know to use "~my-patch"? Because my-patch is the current
+topmost patch. It's the last line in ./applied-patches.
+
+In this way, the whole thing is stackable. If you have four patches
+applied, say "patch-1", "patch-2", "patch-3" and "patch-4", and if
+patch-2 and patch-4 both touch kernel/sched.c then you will have:
+
+ kernel/sched.c~patch-2 Original copy, before patch-2
+ kernel/sched.c~patch-4 Copy before patch-4. Contains changes
+ from patch-2
+ kernel/sched.c Current working copy. Contains changes
+ from patch-4.
+
+This means that your diff headers contain "~patch-name" in them, which
+is convenient documentation.
+
+Walkthrough
+===========
+
+Let's start.
+
+Go into /usr/src/linux (or wherever)
+
+ mkdir pc patches txt
+
+Now let's generate a patch
+
+ fpatch my-patch kernel/sched.c
+
+OK, we've copied kernel/sched.c to kernel/sched.c~my-patch. We've
+appended "my-patch" to ./applied-patches and we've put "kernel/sched.c"
+into the patch control file, pc/my-patch.pc.
+
+ Now edit kernel/sched.c a bit.
+
+Now we're ready to document the patch
+
+ Now write txt/my-patch.txt
+
+Now generate the patch
+
+ refpatch
+
+This will generate patches/my-patch.patch. Take a look.
+
+Now remove the patch
+
+ poppatch
+
+applied-patches is now empty, and the patch is removed.
+
+Now let's add a file to my-patch and then generate my-second-patch:
+
+ Add "my-patch.patch" to ./series (no blank lines in that file please)
+
+ pushpatch
+
+OK, the patch is applied again. Let's add another file
+
+ fpatch kernel/printk.c
+
+Note that here we gave fpatch a single argument. So rather than
+opening a new patch, it adds kernel/printk.c to the existing topmost
+patch. That's my-patch.
+
+ Edit kernel/printk.c
+
+Refresh my-patch (you end up running refpatch a lot)
+
+ refpatch
+
+Now start a second patch:
+
+ fpatch my-second-patch kernel/sched.c
+
+Now take a look at applied-patches. Also do an `ls kernel/sched*'.
+
+ Edit kernel/sched.c, to make some changes for my-second-patch
+
+Generate my-second-patch:
+
+ refpatch
+
+Take a look in patches/my-second-patch.patch
+
+Don't forget to add "my-second-patch.patch" to the series file.
+
+And remove both patches:
+
+ poppatch
+ poppatch
+
+
+That's pretty much it, really.
+
+
+Command reference
+=================
+
+Generally, where any of these commands take a "patch-name", that can be
+of the form txt/patch-name.txt, patch-name.pc, just patch-name or
+whatever. The scripts will strip off a leading "txt/", "patches/" or
+"pc/" and any trailing extension. This is so you can do
+
+ apatch patches/a<tab>
+
+to conveniently use shell tabbing to select patch names.
+
+
+
+added-by-patch
+
+ Some internal thing.
+
+apatch [-f] patch-name
+
+ This is the low-level function which adds patches. It does the
+ copying into ~-files and updates the applied-patches file. It
+ applies the actual patch.
+
+ apatch will do a patch --dry-run first and will refuse to apply the
+ patch if the dryrun fails.
+
+ So when you are getting rejects you do this:
+
+ pushpatch # This fails, due to rejects. Drat.
+ apatch -f patch-name # Force the patch
+ (or) pushpatch -f # Force the patch
+
+ OK, you've now applied patch-name, but you have rejects. Go fix
+ those up and do
+
+ refpatch
+
+ And you're ready to move on.
+
+combine-series output-file
+
+ It incrementally combinediffs all the patches in series to make a
+ complete patch for the series. Requires combinediff frmo patchutils.
+
+ See http://cyberelk.net/tim/patchutils/ (Don't download the
+ "experimental" patchutils - it seems to only have half of the
+ commands in it. Go for "stable")
+
+cvs-take-patch
+
+ I forget.
+
+export_patch
+
+ export the patches listed in ./series to a set of files which
+ are named in such a way that the sort order is the same as the
+ order of the series file.
+
+ Usage: export_patch directory [prefix]
+
+ Example:
+
+ Suppose ./series contains
+
+ mango.patch
+ orange.patch
+ banana.patch
+ apple.patch
+ pear.patch
+
+ export_patch ../mypatches fruit
+
+ The patches would be copied to
+
+ ../mypatches/p00001_fruit_mango.patch
+ ../mypatches/p00002_fruit_orange.patch
+ ../mypatches/p00003_fruit_banana.patch
+ ../mypatches/p00003_fruit_banana.patch
+ ../mypatches/p00003_fruit_banana.patch
+
+ Named in this way, someone may easily apply them:
+
+ cat mypatches/p*fruit* | patch -p1
+
+ If prefix is omitted, the patchnames will be transformed
+ such that "original.patch" becomes "pXXXXX_original.patch".
+
+fpatch [patch-name] foo.c
+
+ If patch-name is given, fpatch will start a new patch which
+ modifies (or adds, or removes) the single file foo.c. It updates
+ ./applied-patches and creates pc/patch-name.pc. fpatch will copy
+ foo.c to foo.c~patch-name in preparation for edits of foo.c.
+
+ If patch-name is not given then fpatch will add foo.c to the
+ current topmost patch. It will add "foo.c" to $P/pc/$(toppatch).pc.
+ It will copy foo.c to foo.c~$(toppatch).
+
+import_patch
+
+ Imports a set of patch files, creating $P/pc, $P/txt, $P/patches and
+ ./series as necessary. It also creates $P/txt/*.txt by stripping
+ off the top of the patches (and removes any diffstat output it finds,
+ so that it can eat refpatch output and export_patch output.) The
+ imported patch names are appended to the series file.
+
+ In creating the $P/txt/*.txt files, mail headers are stripped with
+ formail, preserving the "From:" and "Subject:" lines. "DESC" and
+ "EDESC" markers are added if they are not already present, using the
+ "From:" and "Subject:" lines for the DESC portion, if they are present.
+ (See "patchdesc" command, below, for more on these markers.)
+
+ Also, it can rename the patch file as it is imported by stripping out
+ a pattern. This is useful if, as often is the case, you have patch
+ sets with filenames designed to help sort the patches into the correct
+ order, such as "p001_xxx_funky_stuff.patch" you can have it automatically
+ renamed to funky_stuff.patch on import, and let the series file manage
+ the ordering.
+
+ Import_patch will uncompress patches (*.Z, *.bz2, *.gz) as necessary.
+
+ Usage:
+
+ import_patch [-p pattern] patchfile ...
+
+ Example:
+
+ % ls ../fruit/p*patch
+ ../fruit/p00001_northern_apple.patch
+ ../fruit/p00001_tropical_mango.patch
+ ../fruit/p00002_northern_pear.patch
+ ../fruit/p00002_tropical_orange.patch
+ ../fruit/p00003_tropical_banana.patch
+ % import_patch -p 'p[0-9]*_tropical_' ../fruit/p*tropical*
+ Recreated pc/mango.pc
+ Recreated pc/orange.pc
+ Recreated pc/banana.pc
+ % import_patch -p 'p[0-9]*_northern_' ../fruit/p*northern*
+ Recreated pc/apple.pc
+ Recreated pc/pear.pc
+
+ Then you can "pushpatch; refpatch" 5 times.
+
+inpatch
+
+ List the names of ths files which are affected by the current
+ topmost patch.
+
+ This is basically
+
+ cat pc/$(toppatch).pc
+
+join-patch patchname
+
+ "joins" the named patch to the current topmost patch.
+
+ Use this when you want to merge two patches into one. All the
+ files which `patchname' affects are added to pc/$(toppatch).pc (if
+ they are not already there) and patch `patchname' is applied. The
+ top patch remains unchanged. You'll need to run refpatch afterwards.
+
+mpatch
+
+ A low-level thing to generate patches
+
+new-kernel
+
+ Some thing I use for importing a new kernel from kernel.org
+
+p0-2-p1
+
+ Internal thing to convert patch -p0 form into patch -p1
+
+patchdesc
+
+ Generates a single-line description of a patch.
+
+ The txt/my-patch.txt files have the following format:
+
+ <start of file>
+ DESC
+ some short description
+ EDESC
+
+ The long description
+ <end of file>
+
+ I use
+
+ patchdesc $(cat series)
+
+ to generate short-form summaries of the patch series.
+
+patchfns
+
+ Internal utilities
+
+pcpatch
+
+ Standalone tool to generate a .pc file from a patch.
+
+ Say someone sends you "his-patch.diff". What you do is:
+
+ cp ~/his-patch.diff patches/his-patch.patch
+ pcpatch his-patch
+
+ This generates $P/pc/his-patch.pc and you're all set. Add
+ "his-patch.patch" to ./series in the right place and start pushing.
+
+p_diff
+
+ I forget
+
+poppatch
+
+ Remove one or more patches from the current stack. This command
+ does *not* use the series file. It works purely against
+ applied-patches.
+
+ Usage:
+
+ poppatch
+ Remove the topmost patch
+ poppatch 10
+ Remove ten patches
+ poppatch some-patch-name[.patch]
+ Remove patches until "some-patch-name" is top patch
+
+pstatus
+
+ Shows status of patches
+
+ Usage:
+ pstatus [patchfile ...]
+
+ One line per patch is output showing:
+ 1: Patch number in the series file
+ 2: Whether the patch is currently applied
+ 3: Name of patch
+ 4: Status of the patch (needs pcpatch, changelog, refpatch)
+
+ If no patchfiles are specified, $P/patches/*.patch
+ are assumed.
+
+ Caveats:
+ A patch set which contains separate patches to add a file
+ and modify that same file may give spurious "Needs refpatch"
+ status for the patch which adds the file or the topmost patch.
+
+ptkdiff
+
+ Two modes:
+
+ ptkdiff -
+
+ Run tkdiff against all the file affected
+ by $(toppatch). The diff is only for the changes made
+ by the top patch! ie: it's between "filename" and
+ "filename~toppatch-name".
+
+ ptkdiff filename
+
+ Just run tkdiff against that file,
+ showing the changes which are due to toppatch.
+
+pushpatch [-f]
+
+ Apply the next patch, from the series file.
+
+ This consults ./applied-patches to find out the top patch, then
+ consults ./series to find the next patch. And pushes it.
+
+ pushpatch
+
+ Apply the next patch
+
+ pushpatch 10
+
+ Apply the next ten patches
+
+ pushpatch some-patch-name
+
+ Keep pushing patches until "some-patch-name" is toppatch
+
+ pushpatch -f
+
+ Push the next patch, ignoring rejects.
+
+refpatch
+
+ regnerates the topmost patch. Reads all the affected files
+ from pc/$(toppatch).pc and diffs them against their tilde-files.
+
+ Also pastes into the patch your patch documentation and
+ generates a diffstat summary.
+
+removed-by-patch
+
+ Some thing.
+
+rename-patch
+
+ CVS rename for patches.
+
+rolled-up-patch
+
+ Bit of a hack. Is designed to generate a rolled-up diff of all
+ currently-applied patches. But it requires a ../linux-2.x.y tree to
+ diff against. Needs to be redone.
+
+rpatch
+
+ Internal command
+
+split-patch
+
+ Some thing someone write to split patches up. I don't use it.
+
+tag-series
+
+ Assuming you keep pc/*, patches/* and txt/* under CVS revision
+ control, tag-series allows you to tag a patchset's individual
+ components. I use
+
+ tag-series s2_5_44-mm3 pc/2.5.44-mm3-series
+
+ which will attach the cvs tag "s2_5_44-mm3" to every .pc, .patch
+ and .txt file which is mentioned in the series file
+ "pc/2.5.44-mm3-series".
+
+ It will also tag pc/2.5.44-mm3-series, which is a bit redundant
+ given that I use a different series file for each patchset release..
+
+
+toppatch
+
+ Print the name of the topmost patch. From ./applied-patches
+
+touched-by-patch patch-filename
+
+ List the names of files which are affected by a diff.
+
+unitdiff.py
+
+ Rasmus Andersen's script to convert a diff into minimum-context
+ form. This form has a better chance of applying if you're getting
+ nasty rejects. But patch can and will make mistakes when fed
+ small-context input.
+
+
+Work Practices
+==============
+
+I keep the kernel tree, the $P/pc/, $P/patches/ and $P/txt/ contents under
+CVS control. This is important...
+
+I have several "series" files. I keep these in $P/pc/foo-series and use
+
+ ln -s pc/foo-series series
+
+when I'm working on foo.
+
+If someone sends me a patch I'll do:
+
+ cp ~/whatever patches/his-patch.patch
+ pcpatch his-patch
+ apatch his-patch
+
+ If apatch fails then run `apatch -f his-patch' and fix the rejects.
+
+ refpatch
+
+ to clean up any fuzz.
+
+ poppatch
+ cvs add pc/his-patch.pc patches/his-patch.patch
+ cvs commit pc patches
+
+ Now edit ./series and place "his-patch.patch" in the appropriate place.
+
+
+If you're working on a particular patch (say, "dud-patch") and you
+balls something up, just run:
+
+ refpatch # Generate the crap patch
+ poppatch # Remove it all
+ rm patches/dud-patch.patch
+ cvs up patches/dud-patch.patch
+
+and all is well.
+
+
+Getting updates from Linus
+==========================
+
+What I do is to grab the latest -bk diff from
+http://www.kernel.org/pub/linux/kernel/people/dwmw2/bk-2.5/
+and do:
+
+ gzip -d < cs<tab> > patches/linus.patch
+ pcpatch linus
+ apatch linus | grep diff
+
+ Now fix up all the files which got deleted,
+ because there's something wrong with bitkeeper diffs:
+
+ cvs up -ko <missing files from the above diff>
+
+ apatch linus
+ $EDITOR linus/linus.txt
+
+ Add the changeset number to txt/linus.txt
+
+ refpatch
+ poppatch
+
+ Now add "linus.patch" as the first entry in your ./series file and
+ start pushing your other patches on top of that.
+
+BUGS
+====
+
+Tons and tons. The scripts are fragile, the error handling is ungraceful and
+if you do something silly you can end up in a pickle.
+
+Generally the scripts are very careful to not wreck your files or your
+patches. But they can get the ./applied-patches and ~-files into an
+awkward state.
+
+Usually you can sort it out by copying the ~-files back onto the originals
+and removing the last line from ./applied-patches. Or do a "refpatch ;
+poppatch ; rm patches/troublesome-patch.patch ; cvs up patches".
+
+If it's really bad, just blow away the entire tree and do a new CVS checkout.
+
+
+Working on non-kernel projects
+==============================
+
+Well it's the same thing. Say you've downloaded a copy of util-linux
+and you want to make a change:
+
+ cd /usr/src
+ tar xvfz ~/util-linux.tar.gz
+ cd util-linux
+ mkdir pc patches txt
+ fpatch my-patch sys-utils/rdev.c
+ fpatch sys-utils/ipcs.8
+ <edit, edit>
+ refpatch
+ <ship patches/my-patch.patch>
+
+How to balls things up
+======================
+
+Well here's one way. Suppose you have 20 patches applied, and three of
+them (say, "p1", "p6" and "p11") all modify "foo.c".
+
+Now you go and change foo.c.
+
+Well, to which patch does that change belong? You need to decide.
+Let's say you decide "p6".
+
+If you run `refpatch' when "p11" is toppatch then you lose. The diff
+went into p11.
+
+What you can do is:
+
+1:
+ poppatch p6
+ <edit>
+ refpatch
+ pushpatch p11
+ <test>
+
+ (See why ccache is looking good?)
+
+or
+
+2:
+ <edit>
+ <test>
+ poppatch p6 <hope like hell that the other patches remove cleanly>
+ refpatch
+
+
+Another good way of ballsing up is to cheat. Say "oh I just want to make
+this one-line change". And "oh, and this one".
+
+Now you're getting in a mess. It's much, much better to just use the system:
+
+ fpatch junk file1
+ fpatch file2
+ <edit>
+ <play>
+ refpatch
+ poppatch
+ rm pc/junk.pc patches/junk.patch
+
+Merging with -mm kernels
+========================
+
+Haven't tried this, but it should work:
+
+- Grab all the patches from broken-out/, place them in your $P/patches/
+
+- Copy my series file into ./series (or $P/pc/akpm-series and symlink it)
+
+- pushpatch 99
+
+And you're off and running. The nice thing about this is that you can
+send me incremental diffs to diffs which I already have.
+
+Or whatever. I'm fairly handy with diffs nowadays. Rejects are
+expected. I just prefer to have "one concept per diff".
+
diff --git a/inpatch.in b/inpatch.in
deleted file mode 100755
index f3c3526..0000000
--- a/inpatch.in
+++ /dev/null
@@ -1,143 +0,0 @@
-#! /bin/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 ! [ -r @LIB@/patchfns ]
-then
- echo "Cannot read library @LIB@/patchfns" >&2
- exit 1
-fi
-. @LIB@/patchfns
-
-usage()
-{
- echo "Usage: inpatch [patchname]"
- echo " inpatch -f filename"
- if [ x$1 = x-h ]
- then
- cat <<EOF
-
-Print the list of files that the topmost or specified patch
-changes.
-
--f Print which patches change the specified file.
-
-EOF
- exit 0
- else
- exit 1
- fi
-}
-
-options=`getopt -o f:h -- "$@"`
-
-if [ $? -ne 0 ]
-then
- usage
-fi
-
-eval set -- "$options"
-
-while true
-do
- case "$1" in
- -f)
- opt_file=$2
- shift 2 ;;
- -h)
- usage -h ;;
- --)
- shift
- break ;;
- esac
-done
-
-if [ $# -gt 1 ]
-then
- usage
-fi
-opt_patch=$1
-
-scan_patches()
-{
- local patches=$* patch
- for patch in $patches
- do
- refresh_file_list $patch
- status=$?
- if [ $status -eq 2 ]
- then
- if [ -z "$opt_quiet" ]
- then
- echo "Recreated file list for $patch" >&2
- fi
- elif [ $status -ne 0 ]
- then
- echo "Could not create file list for patch $patch" >&2
- return 1
- fi
- done
-
- grep -l -e "^$(quote_re $opt_file)\$" $(pc_file_name $patches) \
- | sed -e 's:^\.pc/::' -e 's:/\.pc$::'
-}
-
-if [ -n "$opt_patch" ]
-then
- patch=$(stripit "$opt_patch")
-else
- patch=$(top_patch)
- if [ -z "$patch" ]
- then
- echo "No patches applied" >&2
- exit 1
- fi
-fi
-
-if [ -z "$opt_file" ]
-then
- if ! is_applied $patch
- then
- if ! patch_in_series
- then
- echo "Patch $patch not in series file" >&2
- else
- echo "Patch is not applied (no old/new status)" >&2
- no_status=1
- fi
- fi
-
- for file in $(files_in_patch $patch)
- do
- if [ -n "$no_status" -o -s $(backup_file_name $patch $file) ]
- then
- echo "$file"
- else
- echo "$file (new)"
- fi
- done
-else
- #if [ -n "$opt_patch" ]
- #then
- # scan_patches $(patches_before $opt_patch) | sed -e 's/^/> /'
- # scan_patches $opt_patch | sed -e 's/^/| /'
- # scan_patches $(patches_after $opt_patch) | sed -e 's/^/< /'
- #else
- # series=$(cat_series)
- # if [ -n "$series" ]
- # then
- # scan_patches $series | sed -e 's/^/< /'
- # fi
- #fi
- series=$(cat_series)
- if [ -n "$series" ]
- then
- scan_patches $series
- #| sed -e 's/^'"$(quote_re $patch)"'$/\0 (here)/'
- fi
-fi
diff --git a/lib/apatch.in b/lib/apatch.in
index 0e0c366..76d9dc7 100755
--- a/lib/apatch.in
+++ b/lib/apatch.in
@@ -1,4 +1,4 @@
-#! /bin/bash
+#!/bin/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
@@ -6,48 +6,85 @@
#
# See the COPYING and AUTHORS files for more details.
-if ! [ -r @LIB@/patchfns ]
+# Read in library functions
+if [ "$(type -t patch_file_name)" != function ]
then
- echo "Cannot read library @LIB@/patchfns" >&2
- exit 1
+ if ! [ -r @LIB@/patchfns ]
+ then
+ echo "Cannot read library @LIB@/patchfns" >&2
+ exit 1
+ fi
+ . @LIB@/patchfns
fi
-. @LIB@/patchfns
usage()
{
- echo "Usage: apatch [-fq] patchname"
+ 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
+ rm -f $(files_in_patch $patch | sed -e 's/$/\.rej/')
+}
+
interrupt()
{
- local pc_file=$(pc_file_name $1)
- @LIB@/backup-files -s -f $pc_file -B .pc/$patch/ -r
- echo "apatch interrupted by user"
+ 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 patch_file=$(patch_file_name $patch)
local file status
- if ! [ -e "$patch_file" ]
+ trap "" SIGINT
+ if ! refresh_file_list $patch
then
- echo "No patch named $patch found."
+ echo "refresh_file_list failed"
return 1
fi
- #if is_applied "$patch"
- #then
- # echo "$patch" is already applied
- # return 1
- #fi
-
- trap "" SIGINT
- refresh_file_list $patch
+ 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
@@ -57,21 +94,20 @@ apply_patch()
return 1
fi
- if ! @LIB@/backup-files -s -f $pc_file -B .pc/$patch/
+ if ! @LIB@/backup-files $silent_unless_verbose \
+ -f $pc_file -B .pc/$patch/
then
exit 1
fi
trap "interrupt $patch" SIGINT
- # (patch -b fails if a file appears more than once in a patch!)
- #patch $(patch_args $patch) --no-backup-if-mismatch \
- # -E $silent -i $patch_file
- patch $(patch_args $patch) --no-backup-if-mismatch \
- -E $silent -i $patch_file
+
+ apply_patch $patch
status=$?
+
trap "" SIGINT
- # Remember date/time of applying so that poppatch can
+ # Remember date/time of applying so that pop can
# avoid reverse applying the patch in the usual cases.
touch $pc_file
@@ -81,20 +117,20 @@ apply_patch()
if [ $status -eq 0 ]
then
echo "Applied $patch"
- rm -f $(pc_file_name $patch)~forced
+ rm -f $pc_file~refresh
else
- touch $(pc_file_name $patch)~forced
- echo "Applied $patch (forced; needs refpatch)"
+ touch $pc_file~refresh
+ echo "Applied $patch (forced; needs refresh)"
fi
else
- @LIB@/backup-files -s -f $pc_file -B .pc/$patch/ -r
- echo "Patch $patch does not apply"
+ rollback_patch $patch
+ echo "Patch $patch does not apply (enforce with -f)"
fi
trap - SIGINT
return $status
}
-options=`getopt -o fqh -- "$@"`
+options=`getopt -o fqvh -- "$@"`
if [ $? -ne 0 ]
then
@@ -112,6 +148,9 @@ do
-q)
opt_quiet=1
shift ;;
+ -v)
+ opt_verbose=1
+ shift ;;
-h)
usage -h ;;
--)
@@ -126,16 +165,15 @@ then
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)~forced ]
+if [ -n "$top" -a -e $(pc_file_name $top)~refresh ]
then
- echo "The topmost patch $top was force applied. Please run" \
- "refpatch before applying other patches."
+ echo "The topmost patch $top needs to be refreshed first."
exit 1
fi
-apply_patch $patch
-
+apatch $patch
diff --git a/lib/backup-files.c b/lib/backup-files.c
index b9f1b21..c6e0c6d 100644
--- a/lib/backup-files.c
+++ b/lib/backup-files.c
@@ -1,14 +1,29 @@
-/* backup-files.c
- Andreas Gruenbacher, 18 January 2003
+/*
+ File: backup-files.c
+
+ Copyright (C) 2003 Andreas Gruenbacher <agruen@suse.de>
+ SuSE Labs, SuSE Linux AG
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ 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
+ Library General Public License for more details.
- `patch -b' fails to back up files correctly if a file occurs
- more than once in a patch, so we use this utility instead.
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
- - catch SIGINT
- - remove backup files and directories
-*/
+ * Create backup files of a list of files similar to GNU patch. A path
+ * name prefix and suffix for the backup file can be specified with the
+ * -B and -Z options.
+ */
#include <sys/types.h>
#include <sys/stat.h>
@@ -20,10 +35,18 @@
const char *progname;
+enum { what_backup, what_restore, what_remove };
+
+const char *opt_prefix="", *opt_suffix="", *opt_file=NULL;
+int opt_silent=0, opt_what=what_backup;
+
+#define LINE_LENGTH 1024
+
+
void
usage(void)
{
- printf("Usage: %s [-B prefix] [-z suffix] [-f filelist] [-s] [-r|-x]\n"
+ printf("Usage: %s [-B prefix] [-z suffix] [-f {filelist|-}] [-s] [-r|-x] filename ...\n"
"\n"
"\tCreate hard linked backup copies of a list of files\n"
"\tread from standard input.\n"
@@ -60,26 +83,96 @@ create_parents(char *filename)
void
remove_parents(char *filename)
{
- char *f;
+ char *f, *g = NULL;
+ f = strrchr(filename, '/');
while ((f = strrchr(filename, '/')) != NULL) {
- *f = '\0';
+ if (g != NULL)
+ *g = '/';
+ g = f;
+ *f= '\0';
+
rmdir(filename);
}
+ if (g != NULL)
+ *g = '/';
}
-enum { what_backup, what_restore, what_remove };
+int
+process_file(char *file)
+{
+ char backup[LINE_LENGTH];
-#define LINE_LENGTH 1024
+ if (strlen(opt_prefix) + strlen(file) +
+ strlen(opt_suffix) >= sizeof(backup)) {
+ perror("Line buffer too small\n");
+ return 1;
+ }
+
+ snprintf(backup, sizeof(backup), "%s%s%s",
+ opt_prefix, file, opt_suffix);
+
+ if (opt_what == what_backup) {
+ int fd;
+ create_parents(backup);
+
+ unlink(backup);
+ if (link(file, backup) == 0) {
+ if (!opt_silent)
+ printf("Copying %s\n", file);
+ } else if ((fd = creat(backup, 0666)) != -1) {
+ close(fd);
+ if (!opt_silent)
+ printf("New file %s\n", file);
+ } else {
+ perror(backup);
+ return 1;
+ }
+ return 0;
+ } else if (opt_what == what_restore) {
+ struct stat st;
+ create_parents(file);
+
+ if (stat(backup, &st) != 0) {
+ perror(backup);
+ return 1;
+ }
+ if (st.st_size == 0) {
+ if (unlink(file) == 0 || errno == ENOENT) {
+ if (!opt_silent)
+ printf("Removing %s\n", file);
+ unlink(backup);
+ remove_parents(backup);
+ } else {
+ perror(file);
+ return 1;
+ }
+ } else {
+ unlink(file);
+ if (link(backup, file) == 0) {
+ if (!opt_silent)
+ printf("Restoring %s\n", file);
+ unlink(backup);
+ remove_parents(backup);
+ } else {
+ fprintf(stderr, "Could not restore "
+ "file `%s' to `%s': %s\n",
+ backup, file, strerror(errno));
+ return 1;
+ }
+ }
+ return 0;
+ } else if (opt_what == what_remove) {
+ unlink(backup);
+ remove_parents(backup);
+ return 0;
+ } else
+ return 1;
+}
int
main(int argc, char *argv[])
{
- char orig[LINE_LENGTH], *o, backup[LINE_LENGTH];
- FILE *file;
-
- const char *opt_prefix="", *opt_suffix="", *opt_file=NULL;
- int opt_silent=0, opt_what=what_backup;
int opt, status=0;
progname = argv[0];
@@ -117,95 +210,44 @@ main(int argc, char *argv[])
}
}
- if ((*opt_prefix == '\0' && *opt_suffix == '\0') || optind != argc) {
+ if ((*opt_prefix == '\0' && *opt_suffix == '\0') ||
+ (opt_file == NULL && optind == argc)) {
usage();
return 1;
}
if (opt_file != NULL) {
- if ((file = fopen(opt_file, "r")) == NULL) {
- perror(opt_file);
- return 1;
- }
- } else {
- file = stdin;
- }
-
- while (fgets(orig, sizeof(orig), file)) {
- if (strlen(opt_prefix) + strlen(orig) + strlen(opt_suffix) >=
- sizeof(backup)) {
- perror("Line buffer too small\n");
- return 1;
- }
-
- o = strchr(orig, '\0');
- if (o > orig && *(o-1) == '\n')
- *(o-1) = '\0';
- if (*orig == '\0')
- continue;
-
- snprintf(backup, sizeof(backup), "%s%s%s",
- opt_prefix, orig, opt_suffix);
+ FILE *file;
+ char line[LINE_LENGTH];
- if (opt_what == what_backup) {
- int fd;
- create_parents(backup);
-
- if (link(orig, backup) == 0) {
- if (!opt_silent)
- printf("Copying %s\n", orig);
- } else if ((fd = creat(backup, 0666)) != -1) {
- close(fd);
- if (!opt_silent)
- printf("New file %s\n", orig);
- } else {
- perror(backup);
+ if (!strcmp(opt_file, "-")) {
+ file = stdin;
+ } else {
+ if ((file = fopen(opt_file, "r")) == NULL) {
+ perror(opt_file);
return 1;
}
- } else if (opt_what == what_restore) {
- struct stat st;
+ }
- create_parents(orig);
+ while (fgets(line, sizeof(line), file)) {
+ char *l = strchr(line, '\0');
- if (stat(backup, &st) != 0) {
- perror(backup);
- status=1;
+ if (l > line && *(l-1) == '\n')
+ *(l-1) = '\0';
+ if (*line == '\0')
continue;
- }
- if (st.st_size == 0) {
- if (unlink(orig) == 0 || errno == ENOENT) {
- if (!opt_silent)
- printf("Removing %s\n", orig);
- unlink(backup);
- remove_parents(backup);
- } else {
- if (errno != ENOENT) {
- perror(orig);
- status=1;
- }
- }
- } else {
- unlink(orig);
- if (link(backup, orig) == 0) {
- if (!opt_silent)
- printf("Restoring %s\n", orig);
- unlink(backup);
- remove_parents(backup);
- } else {
- fprintf(stderr, "Could not restore "
- "file `%s' to `%s': %s\n",
- backup, orig, strerror(errno));
- status=1;
- }
- }
- } else {
- unlink(backup);
- remove_parents(backup);
+
+ if ((status = process_file(line)) != 0)
+ return status;
}
- }
- if (file != stdin) {
- fclose(file);
+ if (file != stdin) {
+ fclose(file);
+ }
+ }
+ for (; optind < argc; optind++) {
+ if ((status = process_file(argv[optind])) != 0)
+ return status;
}
return status;
diff --git a/lib/parse-patch b/lib/parse-patch
index b4dded2..9d38e36 100755
--- a/lib/parse-patch
+++ b/lib/parse-patch
@@ -1,10 +1,17 @@
#!/usr/bin/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;
@@ -20,7 +27,9 @@ if (!GetOptions("s|select=s" => \$select,
foreach my $arg (@ARGV) {
my $fh;
- if ($arg =~ /\.gz$/) {
+ 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 |");
@@ -53,31 +62,43 @@ foreach my $arg (@ARGV) {
}
}
} elsif (defined $update) {
- my $fh2;
+ my ($fh2, $tempname) = tempfile("$arg.XXXXXX");
if ($arg =~ /\.gz$/) {
- $fh2 = new FileHandle("| gzip -c > $arg.parse");
+ $fh2->close();
+ if (! -e $tempname) {
+ die "File $tempname disappeared!\n";
+ }
+ $fh2 = new FileHandle("| gzip -c > $tempname");
} elsif ($arg =~ /\.bz2$/) {
- $fh2 = new FileHandle("| bzip2 -c > $arg.parse");
- } else {
- $fh2 = new FileHandle("$arg.parse", O_CREAT|O_WRONLY);
+ $fh2->close();
+ if (! -e $tempname) {
+ die "File $tempname disappeared!\n";
+ }
+ $fh2 = new FileHandle("| bzip2 -c > $tempname");
}
unless ($fh2) {
- die "$arg.parse: $!\n";
+ 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 (/^%(.*)/) {
@@ -93,11 +114,14 @@ foreach my $arg (@ARGV) {
die "$arg.patch: $!\n";
}
- unlink "$arg~";
- unless (rename $arg, "$arg~") {
- die "Failed to rename $arg to $arg~: $!\n";
+ if (-e $arg) {
+ unlink "$arg~";
+ unless (rename $arg, "$arg~") {
+ die "Failed to rename $arg to $arg~: $!\n";
+ }
}
- unless (rename "$arg.parse", $arg) {
+ unless (rename $tempname, $arg) {
+ rename("$arg~", $arg);
die "Failed to rename $arg.parse to $arg: $!\n";
}
}
diff --git a/lib/patchfns.in b/lib/patchfns.in
index 63fae45..17c5b56 100644
--- a/lib/patchfns.in
+++ b/lib/patchfns.in
@@ -1,8 +1,10 @@
-debug()
-{
- #echo "$@" >&2
- true
-}
+#!/bin/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.
if [ -n "$PATCHSCRIPTS" ]
then
@@ -23,20 +25,36 @@ 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?)([ \t]|$)/ \
- { printf "'"$P"'patches/%s\n", $1; exit }' \
- $SERIES
+ awk '/^'"$(quote_re $patch)"'(|\.patch|\.diff?)(|\.gz|\.bz2)([ \t]|$)/ \
+ { printf "'"$P"'patches/%s\n", $1
+ exit
+ }
+ ' $SERIES
fi
}
@@ -47,13 +65,16 @@ patch_args()
if [ -e $SERIES ]
then
- awk '/^'"$(quote_re $patch)"'(|\.patch|\.diff?)([ \t]|$)/ \
+ 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
+ print $i
+ else
+ print "-p1" ;
+ exit
+ }
+ ' $SERIES
fi
}
@@ -87,20 +108,24 @@ change_db_strip_level()
if [ -e $SERIES ]
then
- local tmp=$(mktemp /tmp/patch-scripts.XXXXXX)
- awk '/^'"$(quote_re $patch)"'(\.patch|\.diff?)([ \t]|$)/ \
- {for(i=2; i<=NF; i++)
- if ($i ~ /^-p/)
- {$i="'"$level"'" ; break}
- if (i > NF)
- $i="'"$level"'"}
- {print}' \
- $SERIES > $tmp
- if cmp $SERIES $tmp >/dev/null 2>/dev/null
+ 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 $tmp
+ rm -f $tmpfile
else
- mv -f $tmp $SERIES
+ mv -f $tmpfile $SERIES
fi
else
return 1
@@ -115,7 +140,7 @@ patch_in_series()
then
return 1
else
- grep -q '^'"$(quote_re $patch)"'\(\|\.patch\|.diff\?\)\([ \t]\|$\)' $SERIES
+ grep -q '^'"$(quote_re $patch)"'\(\|\.patch\|.diff\?\)\(\|\.gz\|\.bz2\)\([ \t]\|$\)' $SERIES
fi
}
@@ -123,31 +148,54 @@ patch_in_series()
insert_in_series()
{
local patch=$1 patch_args=$2
- local top=$(top_patch) tmp
+ local top=$(top_patch) tmpfile
if [ -n "$patch_args" ]
then
patch_args=" $patch_args"
fi
- tmp=$(mktemp /tmp/patch-scripts.XXXXXX) || return 1
+ tmpfile=$(mktemp /tmp/patch-scripts.XXXXXX) || return 1
+ mkdir -p $(dirname $SERIES)
if [ -n "$top" ]
then
- awk ' { print }
- /^'"$(quote_re $top)"'(|\.patch|\.diff?)([ \t]|$)/ \
- { print "'"$patch$patch_args"'" }' \
- < $SERIES \
- > $tmp \
- || return 1
+ 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 > $tmp
+ echo $patch$patch_args > $tmpfile
if [ -e $SERIES ]
then
- cat $SERIES >> $tmp
+ cat $SERIES >> $tmpfile
fi
fi
- mkdir -p $(dirname $SERIES)
- mv -f $tmp $SERIES
+ 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()
@@ -170,34 +218,23 @@ backup_file_name()
done
}
-__cat_series()
+cat_series()
{
- local series=$1
- if [ -e $series ]
+ if [ -e $SERIES ]
then
sed -e '/^#/d' -e 's/^[ \t]*//' -e 's/[ \t].*//' \
- -e 's/\.patch$//' -e 's/\.diff\?//' $series
+ -e 's/\.gz$//' -e 's/\.bz2$//' \
+ -e 's/\.patch$//' -e 's/\.diff\?$//' $SERIES
else
return 1
fi
}
-cat_series()
-{
- __cat_series $SERIES
-}
-
top_patch()
{
[ -e $DB ] && tail -1 $DB
}
-die()
-{
- echo "error: $*"
- exit 1
-}
-
is_numeric()
{
echo $1 | grep -q -e '^[0-9]*$'
@@ -219,17 +256,30 @@ is_applied()
patches_before()
{
local patch=$1
- cat_series \
- | awk '$0 == "'"$patch"'" { exit }
- { print }'
+
+ if [ -n "$patch" ]
+ then
+ cat_series \
+ | awk '
+ $0 == "'"$patch"'" { exit }
+ { print }
+ '
+ fi
}
patches_after()
{
local patch=$1
- cat_series \
- | awk 'seen { print }
- $0 == "'"$patch"'" { seen=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
@@ -237,8 +287,10 @@ patches_on_top_of()
{
local patch=$1
[ -e $DB ] || return
- awk '$0 == "'"$patch"'" { seen=1 ; next }
- seen { print }' $DB
+ awk '
+ $0 == "'"$patch"'" { seen=1 ; next }
+ seen { print }
+ ' $DB
}
# Print the name of the patch that modified the file $2 next after
@@ -255,30 +307,106 @@ next_patch_for_file()
| head -1 \
| sed -e 's:^\.pc/::' -e 's:/\.pc$::'
fi
+
+ #modified_files $file -- $patches_on_top \
+ #| cut -d $'\t' -f2 \
+ #| cut -d ' ' -f1
}
-can_apply()
+# Create a list of files and the patches that modify them.
+refresh_patches_per_file()
{
- local silent
- if [ "x$1" == "x-s" ]
+ local pc_files=$(pc_file_name $(cat_series))
+ local ex_pc_files pc_file
+
+ if [ -e .pc/patches-per-file ]
then
- silent=-s
- shift
+ 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
- local patch=$1
- patch -p1 --dry-run -f $silent -i $(patch_file_name $patch) < /dev/null
-}
-can_remove()
-{
- local silent
- if [ "x$1" == "x-s" ]
+ 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
- silent=-s
- shift
+ rm -f .pc/patches-per-file
+ return 0
fi
- local patch=$1
- patch -R -p1 --dry-run -f $silent -i $(patch_file_name $patch) < /dev/null
+
+ 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()
@@ -290,10 +418,13 @@ remove_from_db()
{
local patch=$1
local tmpfile
- tmpfile=$(mktemp /tmp/patch-scripts.XXXXXX)
- grep -v "^$patch\$" $DB > $tmpfile
- mv -f $tmpfile $DB
- [ -s $DB ] || rm -f $DB
+ if tmpfile=$(mktemp /tmp/patch-scripts.XXXXXX)
+ then
+ grep -v "^$(quote_re $patch)\$" $DB > $tmpfile
+ mv -f $tmpfile $DB
+ rm -f $tmpfile
+ [ -s $DB ] || rm -f $DB
+ fi
}
stripit()
@@ -303,6 +434,7 @@ stripit()
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
}
@@ -322,15 +454,19 @@ files_in_patch()
fi
}
-install_file_in_patch()
+touched_by_patch()
{
- local file=$1 patch=$2 bup_file=$(backup_file_name $patch $file)
-
- if ! echo $file  @LIB@/backup-file -s -B .pc/$patch/ || \
- ! echo $file >> $(pc_file_name $patch)
- then
- return 1
- fi
+ 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()
@@ -341,40 +477,103 @@ refresh_file_list()
if ! [ -e "$patch_file" ]
then
- echo "Patch file $patch_file does not exist"
- return 1
+ return 0
fi
- if [ ! -e $pc_file -o $pc_file -ot $patch_file ]
+ if [ ! -e $pc_file -o \
+ $pc_file -ot $patch_file -o \
+ $pc_file -ot $SERIES ]
then
- mkdir -p $(dirname $pc_file)
- echo "touched-by-patch $(patch_strip_level $patch) $patch_file > $pc_file" >&2
- @LIB@/touched-by-patch -p$(patch_strip_level $patch) \
- $patch_file > $pc_file
- if [ $? -ne 0 ]
+ 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
- return 2
+ sort $tmpfile | uniq > $pc_file
+ rm $tmpfile
+ return 0
fi
}
-directory_names()
+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()
{
- echo "$@" \
- | awk 'BEGIN {RS=" "}
- {sub(/\/?[^\/]*$/, "") ; printf "[%s]\n", $0}
- {if (last != $0)
- print last
- last = $0}
- END {print last}'
+ local from=$1 to=$2
+ sed -e 's:^--- [^ \t]*:--- '"$from"':' \
+ -e 's:^+++ [^ \t]*:+++ '"$to"':'
}
-need_file_there()
+cat_file()
{
- if [ ! -e $1 ]
+ 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
- echo "File $1 does not exist"
- exit 1
+ cat
+ else
+ case "$filename" in
+ *.gz|*.tgz)
+ gzip -c > "$filename" ;;
+ *.bz2)
+ bzip2 -c > "$filename" ;;
+ *)
+ cat > "$filename" ;;
+ esac
fi
}
@@ -384,10 +583,15 @@ patch_description()
if [ -e "$patch_file" ]
then
- awk '/^--- / {exit}
- diff {print diff ; diff=""}
- /^diff / {diff=$0 ; next}
- {print}' \
- $patch_file
+ awk '
+ /^--- / { exit }
+ diff_line { print diff_line
+ diff_line=""
+ }
+ /^diff / { diff_line=$0
+ next
+ }
+ { print }
+ ' $patch_file
fi
}
diff --git a/lib/rpatch.in b/lib/rpatch.in
index 3c05c0a..85e8408 100755
--- a/lib/rpatch.in
+++ b/lib/rpatch.in
@@ -1,4 +1,4 @@
-#! /bin/bash
+#!/bin/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
@@ -6,16 +6,20 @@
#
# See the COPYING and AUTHORS files for more details.
-if ! [ -r @LIB@/patchfns ]
+# Read in library functions
+if [ "$(type -t patch_file_name)" != function ]
then
- echo "Cannot read library @LIB@/patchfns" >&2
- exit 1
+ if ! [ -r @LIB@/patchfns ]
+ then
+ echo "Cannot read library @LIB@/patchfns" >&2
+ exit 1
+ fi
+ . @LIB@/patchfns
fi
-. @LIB@/patchfns
usage()
{
- echo "Usage: rpatch [-fRq] patchname"
+ echo "Usage: $0 [-fRq] patchname"
exit 1
}
@@ -52,10 +56,17 @@ verify_removal()
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 [ $pc_file -ot $(patch_file_name $patch) ]
+ if [ -e "$patch_file" -a $pc_file -ot "$patch_file" ]
then
return 0
fi
@@ -76,25 +87,60 @@ files_may_have_changed()
return 1
}
-abort_patch()
+rollback_patch()
{
- local pc_file=$(pc_file_name $1)
- @LIB@/backup-files -s -f $pc_file -z ~rpatch -r
- exit 1
+ 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
- abort_patch $patch
- echo "rpatch interrupted by user"
+ rollback_patch $patch
+ echo "Interrupted by user; patch $patch was not removed."
exit 1
}
-do_remove()
+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 )
@@ -106,44 +152,53 @@ do_remove()
@LIB@/backup-files $silent -f $pc_file -B .pc/$patch/ -r
status=$?
remove_from_db $patch
- rm -f $(pc_file_name $patch)~forced
- return $status
+ rm -f $pc_file~refresh
+ if [ $status != 0 ]
+ then
+ exit $status
+ fi
else
- local patch_file=$(patch_file_name $patch)
- if ! [ -e "$patch_file" ]
+ if ! @LIB@/backup-files $silent_unless_verbose \
+ -f $pc_file -z ~rpatch
then
- echo "No patch named $patch found."
+ echo "Failed to create temporary files" >&2
return 1
fi
trap "interrupt $patch" SIGINT
- #if [ ! -e $patch_file ] || grep -q '^%patch$' $patch_file
- #then
- # @LIB@/parse-patch -s patch $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
+
+ reverse_patch $patch
status=$?
+
trap "" SIGINT
+
if [ $status -eq 0 ] && verify_removal $patch
then
- @LIB@/backup-files -s -f $pc_file -z ~rpatch -x
- @LIB@/backup-files -s -f $pc_file -B .pc/$patch/ -x
+ @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
- @LIB@/backup-files -s -f $pc_file -z ~rpatch -r
- echo "Patch $patch does not remove cleanly"
+ 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 fRqh -- "$@"`
+options=`getopt -o fRqvh -- "$@"`
if [ $? -ne 0 ]
then
@@ -165,6 +220,9 @@ do
-q)
opt_quiet=1
shift ;;
+ -v)
+ opt_verbose=1
+ shift ;;
-h)
usage -h ;;
--)
@@ -180,29 +238,13 @@ 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)~forced -a -z "$opt_force" ]
+if [ -n "$top" -a -e $(pc_file_name $top)~refresh -a -z "$opt_force" ]
then
- echo "The topmost patch $top was force applied. Please run" \
- "refpatch before removing it."
+ echo "The topmost patch $top needs to be refreshed first."
exit 1
fi
-#if is_applied "$patch"
-#then
- do_remove "$patch" || exit 1
-#else
-# echo "Patch $patch is not applied"
-# exit 1
-#fi
-
-top=$(top_patch)
-if [ -z "$top" ]
-then
- where="no patches applied"
-else
- where="now at $top"
-fi
-echo "Removed $patch, $where"
-
+rpatch "$patch" || exit 1
diff --git a/lib/spec2series b/lib/spec2series
new file mode 100755
index 0000000..685f8e0
--- /dev/null
+++ b/lib/spec2series
@@ -0,0 +1,223 @@
+#!/bin/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
+)
diff --git a/lib/touched-by-patch b/lib/touched-by-patch
deleted file mode 100755
index bdfc296..0000000
--- a/lib/touched-by-patch
+++ /dev/null
@@ -1,69 +0,0 @@
-#! /bin/bash
-# Extract names of new files from a patch, print them out
-
-# 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.
-
-usage()
-{
- echo "Usage: touched-by-patch [-p num] patchname"
- exit 1
-}
-
-options=`getopt -o p:h -- "$@"`
-
-if [ $? -ne 0 ]
-then
- usage
-fi
-
-eval set -- "$options"
-
-while true
-do
- case "$1" in
- -p)
- opt_p=$2
- shift 2 ;;
- -h)
- usage ;;
- --)
- shift
- break ;;
- esac
-done
-
-if [ $# -ne 1 ]
-then
- usage
-fi
-
-patch_file=$1
-[ -z "$opt_p" ] && opt_p=1
-
-case "$patch_file" in
-*.bz2)
- command="bzip2 -cd $patch_file";;
-*.gz)
- command="gzip -cd $patch_file";;
-*)
- command="cat $patch_file";;
-esac
-
-# Neither `+++' nor `---' works for all patches; patch looks at the
-# file system to determine which file name to use.
-
-eval $command \
-| awk '/^\+\+\+[ \t]/ {
- sub(/^\+\+\+[ \t]/, "")
- sub(/[ \t].*/, "")
- sub(/^\/dev\/null/, "")
- for (i=0; i<'$opt_p'; i++)
- sub(/^[^\/]*\//, "")
- print
- }' \
-| sort \
-| uniq
diff --git a/patch-scripts.changes b/patch-scripts.changes
deleted file mode 100644
index f78a580..0000000
--- a/patch-scripts.changes
+++ /dev/null
@@ -1,11 +0,0 @@
--------------------------------------------------------------------
-Tue Jan 14 10:02:50 CET 2003 - agruen@suse.de
-
-- Move library files to /usr/share/lib/patch-scripts
-- Try to recover from keyboard interrupt (^C)
-
--------------------------------------------------------------------
-Mon Jan 13 13:04:27 CET 2003 - agruen@suse.de
-
-- Initial package
-
diff --git a/quilt.changes b/quilt.changes
new file mode 100644
index 0000000..584d212
--- /dev/null
+++ b/quilt.changes
@@ -0,0 +1,36 @@
+-------------------------------------------------------------------
+Tue Jan 21 16:49:18 CET 2003 - agruen@suse.de
+
+- NOTE: The scripts are in so much a state of flux that keeping
+ a real changelog at this moment doesn't make sense...
+
+-------------------------------------------------------------------
+Mon Jan 20 20:12:58 CET 2003 - agruen@suse.de
+
+- Add Gerd Knorr's scripts for generating series files from RPM
+ sources to contrib/
+- Write an initial initseries script that sets up a source tree
+ from a spec file. This version still sucks.
+
+-------------------------------------------------------------------
+Mon Jan 20 02:34:40 CET 2003 - agruen@suse.de
+
+- Add -r options to newpatch and patchadd.
+- Improve backup-files slightly.
+
+-------------------------------------------------------------------
+Sat Jan 18 21:11:21 CET 2003 - agruen@suse.de
+
+- Initial release 0.11
+- Fix a few bugs; 0.12
+
+-------------------------------------------------------------------
+Tue Jan 14 10:02:50 CET 2003 - agruen@suse.de
+
+- Move library files to /usr/share/lib/patch-scripts
+- Try to recover from keyboard interrupt (^C)
+
+-------------------------------------------------------------------
+Mon Jan 13 13:04:27 CET 2003 - agruen@suse.de
+
+- Initial package
diff --git a/patch-scripts.spec b/quilt.spec
index a5eda6c..d260730 100644
--- a/patch-scripts.spec
+++ b/quilt.spec
@@ -1,27 +1,26 @@
#
-# spec file for patch scripts
+# spec file for quilt - patch management scripts
#
-# Copyright (c) 2002 SuSE Linux AG, Nuernberg, Germany.
+# Copyright (c) 2003 SuSE Linux AG, Nuernberg, Germany.
# This file and all modifications and additions to the pristine
# package are under the same license as the package itself.
#
# Please submit bugfixes or comments via http://www.suse.de/feedback/
#
-# neededforbuild fileutils make sed
+# neededforbuild sh-utils
# usedforbuild
-Name: patch-scripts
+Name: quilt
Summary: Scripts for working with series of patches
License: GPL
Group: Productivity/Text/Utilities
-Version: 0.11
+Version: 0.21
Release: 1
Requires: textutils diffutils patch gzip bzip2 perl mktemp
Autoreqprov: off
-Source: patch-scripts-%{version}.tar.gz
+Source: quilt-%{version}.tar.gz
BuildRoot: %{_tmppath}/%{name}-%{version}-build
-BuildArchitectures: noarch
%description
The scripts allow to manage a series of patches by keeping
@@ -37,6 +36,9 @@ Authors:
Andreas Gruenbacher <agruen@suse.de>
%prep
+if [ "${RPM_BUILD_ROOT%/}" != "" ]; then
+ rm -rf $RPM_BUILD_ROOT
+fi
%setup
%build
@@ -47,25 +49,14 @@ make install prefix=/usr BUILD_ROOT=$RPM_BUILD_ROOT
%files
%defattr(-, root, root)
-/usr/bin/newpatch
-/usr/bin/patchadd
-/usr/bin/pushpatch
-/usr/bin/poppatch
-/usr/bin/refpatch
-/usr/bin/importpatch
-/usr/bin/toppatch
-/usr/bin/inpatch
+/usr/bin/guards
+/usr/bin/quilt
-/usr/share/patch-scripts/patchfns
-/usr/share/patch-scripts/apatch
-/usr/share/patch-scripts/rpatch
-/usr/share/patch-scripts/touched-by-patch
-/usr/share/patch-scripts/parse-patch
-/usr/share/patch-scripts/backup-files
+/usr/share/quilt/
-%doc /usr/share/doc/packages/patch-scripts/README
-%doc /usr/share/doc/packages/patch-scripts/docco.txt
+%doc /usr/share/man/man1/guards.1.gz
+%doc README
+
+%changelog
+# The changelog is kept in %{name}.changes
-%changelog -n star
-* Mon Jan 13 2002 - agruen
-- Initial package
diff --git a/patchadd.in b/quilt/add.in
index de2d6b2..39e1a36 100755..100644
--- a/patchadd.in
+++ b/quilt/add.in
@@ -1,4 +1,4 @@
-#! /bin/bash
+#!/bin/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
@@ -7,16 +7,19 @@
# See the COPYING and AUTHORS files for more details.
# Read in library functions
-if ! [ -r @LIB@/patchfns ]
+if [ "$(type -t patch_file_name)" != function ]
then
- echo "Cannot read library @LIB@/patchfns" >&2
- exit 1
+ if ! [ -r @LIB@/patchfns ]
+ then
+ echo "Cannot read library @LIB@/patchfns" >&2
+ exit 1
+ fi
+ . @LIB@/patchfns
fi
-. @LIB@/patchfns
usage()
{
- echo "Usage: patchadd [-p patchname] filename ..."
+ echo "Usage: quilt add [-p patch] {file} ..."
if [ x$1 = x-h ]
then
cat <<EOF
@@ -26,7 +29,7 @@ Files must be added to the patch before being modified.
Files that are modified by patches on top of the specified
patch cannot be added.
--p patchname
+-p patch
Patch to add files to.
EOF
@@ -71,7 +74,7 @@ then
fi
if [ -z "$patch" ]
then
- echo "No patches seem to be applied"
+ echo "No patches applied"
fi
if ! is_applied $patch
@@ -80,22 +83,46 @@ then
exit 1
fi
+status=0
for file in $*
do
if file_in_patch $file $patch
then
echo "File $file is already in patch $patch"
- else
- next_patch=$(next_patch_for_file $patch $file)
- if [ -n "$next_patch" ]
- then
- echo "File $file shadowed by patch $next_patch"
- exit 1
- fi
+ status=1
+ continue
+ fi
+ next_patch=$(next_patch_for_file $patch $file)
+ if [ -n "$next_patch" ]
+ then
+ echo "File $file modified by patch $next_patch"
+ status=1
+ continue
+ fi
- if install_file_in_patch $file $patch
+ if ! @LIB@/backup-files -s -B .pc/$patch/ $file || \
+ ! echo $file >> $(pc_file_name $patch)
+ then
+ echo "Failed to back up file $file" >&2
+ status=1
+ continue
+ fi
+
+ if [ -e $file ]
+ then
+ if [ "$(ls -dl $file | awk '{print $2}')" -gt 1 ]
then
- echo "File $file added to patch $patch"
+ # We have a file with several hard links.
+ # As the file may likely be modified by hand
+ # now, create a copy to make sure nothing
+ # happens to the original file.
+ tmpfile=$(mktemp $file.XXXXXX) &&
+ cp -f $file $tmpfile &&
+ mv -f $tmpfile $file
+ rm -f $tmpfile
fi
fi
+
+ echo "File $file added to patch $patch"
done
+exit $status
diff --git a/quilt/applied.in b/quilt/applied.in
new file mode 100644
index 0000000..cbefdca
--- /dev/null
+++ b/quilt/applied.in
@@ -0,0 +1,71 @@
+#!/bin/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 @LIB@/patchfns ]
+ then
+ echo "Cannot read library @LIB@/patchfns" >&2
+ exit 1
+ fi
+ . @LIB@/patchfns
+fi
+
+usage()
+{
+ echo "Usage: quilt applied [patch]"
+ if [ x$1 = x-h ]
+ then
+ cat <<EOF
+
+Print a list of applied patches, or all patches up to and including the
+specified patch in the file series.
+
+EOF
+ exit 0
+ else
+ exit 1
+ fi
+}
+
+options=`getopt -o h -- "$@"`
+
+if [ $? -ne 0 ]
+then
+ usage
+fi
+
+eval set -- "$options"
+
+while true
+do
+ case "$1" in
+ -h)
+ usage -h ;;
+ --)
+ shift
+ break ;;
+ esac
+done
+
+if [ $# -gt 1 ]
+then
+ usage
+elif [ $# -eq 1 ]
+then
+ patch=$(stripit $1)
+else
+ patch=$(top_patch)
+fi
+
+if [ -n "$patch" ]
+then
+ patches_before $patch
+ echo $patch
+fi
diff --git a/quilt/delete.in b/quilt/delete.in
new file mode 100644
index 0000000..3c5cb91
--- /dev/null
+++ b/quilt/delete.in
@@ -0,0 +1,92 @@
+#!/bin/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 @LIB@/patchfns ]
+ then
+ echo "Cannot read library @LIB@/patchfns" >&2
+ exit 1
+ fi
+ . @LIB@/patchfns
+fi
+
+usage()
+{
+ echo "Usage: quilt delete [patch]"
+ if [ x$1 = x-h ]
+ then
+ cat <<EOF
+
+Remove the specified or topmost patchfrom the series file. If the patch
+is applied, it is first tried to remove it. (Only the topmost patch can
+be removed right now.)
+
+EOF
+ exit 0
+ else
+ exit 1
+ fi
+}
+
+options=`getopt -o h -- "$@"`
+
+if [ $? -ne 0 ]
+then
+ usage
+fi
+
+eval set -- "$options"
+
+while true
+do
+ case "$1" in
+ -h)
+ usage -h ;;
+ --)
+ shift
+ break ;;
+ esac
+done
+
+if [ $# -gt 1 ]
+then
+ usage
+fi
+
+patch=$(stripit $1)
+
+if [ -z "$patch" ]
+then
+ patch="$(top_patch)"
+ if [ -z "$patch" ]
+ then
+ echo "No patches applied"
+ exit 1
+ fi
+else
+ if ! patch_in_series $patch
+ then
+ echo "Patch $patch does not exist"
+ exit 1
+ fi
+fi
+if is_applied $patch
+then
+ if [ "$patch" != "$(top_patch)" ] || \
+ ! @LIB@/rpatch -fq "$patch"
+ then
+ echo "Patch $patch is currently applied"
+ exit 1
+ fi
+fi
+if ! remove_from_series $patch
+then
+ echo "Failed to remove patch $patch"
+fi
diff --git a/quilt/diff.in b/quilt/diff.in
new file mode 100644
index 0000000..a114f8a
--- /dev/null
+++ b/quilt/diff.in
@@ -0,0 +1,244 @@
+#!/bin/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 @LIB@/patchfns ]
+ then
+ echo "Cannot read library @LIB@/patchfns" >&2
+ exit 1
+ fi
+ . @LIB@/patchfns
+fi
+
+usage()
+{
+ local redirect
+ if [ x$1 != x-h ]
+ then
+ redirect='>&2'
+ fi
+ echo "Usage: quilt diff [-p n] [-c patch|-z] [patch]" $redirect
+
+ if [ x$1 = x-h ]
+ then
+ cat <<EOF
+
+Produce a diff of the specified patch, or the topmost patch
+by default.
+
+-p n Create a -p n style patch (-p0 or -p1 supported).
+
+-c patch
+ Create a combined diff for all patches between this
+ patch and the specified or topmost patch.
+
+-z Write to standard output the changes that have been
+ made relative to the topmost or specified patch.
+
+EOF
+ exit 0
+ else
+ exit 1
+ fi
+}
+
+die ()
+{
+ local status=$1
+ [ -n "$workdir" ] && rm -rf $workdir
+ exit $status
+}
+
+options=`getopt -o c:p:zh -- "$@"`
+
+if [ $? -ne 0 ]
+then
+ usage
+fi
+
+eval set -- "$options"
+
+while true
+do
+ case "$1" in
+ -p)
+ opt_strip_level=$2
+ shift 2 ;;
+ -c)
+ opt_combine=$2
+ shift 2 ;;
+ -z)
+ opt_relative=1
+ shift ;;
+ -h)
+ usage -h ;;
+ --)
+ shift
+ break ;;
+ esac
+done
+
+if [ -n "$opt_combine" -a -n "$opt_relative" ]
+then
+ echo "Options \`-c patch' and \`-z' cannot be combined."
+ die 1
+fi
+
+if [ $# -eq 1 ]
+then
+ last_patch=$(stripit $1)
+elif [ $# -gt 1 ]
+then
+ usage
+fi
+
+if [ -z "$last_patch" ]
+then
+ last_patch=$(top_patch)
+ if [ -z "$last_patch" ]
+ then
+ echo "No patches seem to be applied" >&2
+ die 1
+ fi
+fi
+
+if ! is_applied "$last_patch"
+then
+ echo "Patch $last_patch is not applied" >&2
+ die 1
+fi
+
+if [ -z "$opt_strip_level" ]
+then
+ opt_strip_level=$(patch_strip_level $last_patch)
+fi
+if [ $opt_strip_level -lt 0 -o $opt_strip_level -gt 1 ]
+then
+ echo "Cannot diff patches with -p$opt_strip_level," \
+ "please specify -p0 or -p1 instead" >&2
+ die 1
+fi
+
+if [ -n "$opt_combine" ]
+then
+ if ! refresh_patches_per_file
+ then
+ echo "refresh_patches_per_file failed."
+ die 1
+ fi
+
+ set -- $(patches_before $last_patch) $last_patch
+ if [ "x$opt_combine" != "x-" ]
+ then
+ while [ $# -ge 1 -a "$1" != "$opt_combine" ]
+ do
+ shift
+ done
+ if [ $# -eq 0 ]
+ then
+ echo "Patch $opt_combine not applied" \
+ "before $last_patch."
+ die 1
+ fi
+ fi
+
+ while read file first garbage
+ do
+ patches[${#patches[@]}]="$first"
+ files[${#files[@]}]="$file"
+ done \
+ < <(modified_files -- "$@")
+else
+ files=( $(files_in_patch $last_patch) )
+fi
+
+trap "die 1" SIGTERM
+
+if [ -n "$opt_relative" ]
+then
+ patch_file=$(patch_file_name $last_patch)
+ patch_args=$(patch_args $last_patch)
+ workdir=$(mktemp -d patch-scripts.XXXXXX)
+ pwd=$PWD
+
+ if ! cd .pc/$last_patch
+ then
+ echo "Cannot change into .pc/$last_patch"
+ die 1
+ fi
+ if ! cp -l --parents "${files[@]}" $pwd/$workdir/
+ then
+ echo "Failed to copy files to temporary directory"
+ die 1
+ fi
+ if ! cd $pwd/$workdir
+ then
+ echo "Cannot change to temporary directory"
+ die 1
+ fi
+
+ if [ -s $pwd/$patch_file ]
+ then
+ if ! cat_file $pwd/$patch_file \
+ | patch $patch_args --no-backup-if-mismatch \
+ -E >/dev/null 2>/dev/null
+ then
+ echo "Failed to patch temporary files"
+ die 1
+ fi
+ fi
+ if ! cd $pwd
+ then
+ echo "Cannot change to source directory"
+ die 1
+ fi
+fi
+
+for ((i=0; i<${#files[@]}; i++))
+do
+ file="${files[$i]}"
+ first_patch=${patches[$i]:-$last_patch}
+
+ next_patch=$(next_patch_for_file $last_patch $file)
+ if [ -z "$next_patch" ]
+ then
+ new_file="$file"
+ else
+ new_file="$(backup_file_name $next_patch $file)"
+ files_were_shadowed=1
+ fi
+
+ if [ -z "$opt_relative" ]
+ then
+ if [ -z "$opt_combine" ]
+ then
+ suffix="~${last_patch//\//_}"
+ else
+ suffix=".orig"
+ fi
+ old_file=$(backup_file_name $first_patch $file)
+ diff_file $file $suffix $old_file $new_file
+ else
+ diff_file $file ".orig" "$workdir/$file" $new_file
+ fi
+
+ if [ $? -ne 0 ]
+ then
+ echo "Diff failed, aborting." >&2
+ die 1
+ fi
+done
+
+if [ -n "$files_were_shadowed" ]
+then
+ echo "More recent patches modify the same files."
+ die 1
+fi
+die 0
diff --git a/quilt/files.in b/quilt/files.in
new file mode 100644
index 0000000..6ea95d2
--- /dev/null
+++ b/quilt/files.in
@@ -0,0 +1,112 @@
+#!/bin/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 @LIB@/patchfns ]
+ then
+ echo "Cannot read library @LIB@/patchfns" >&2
+ exit 1
+ fi
+ . @LIB@/patchfns
+fi
+
+usage()
+{
+ echo "Usage: quilt files [-v] [patch]"
+ if [ x$1 = x-h ]
+ then
+ cat <<EOF
+
+Print the list of files that the topmost or specified patch
+changes.
+
+-v Verbose, more user friendly output.
+
+EOF
+ exit 0
+ else
+ exit 1
+ fi
+}
+
+options=`getopt -o vh -- "$@"`
+
+if [ $? -ne 0 ]
+then
+ usage
+fi
+
+eval set -- "$options"
+
+while true
+do
+ case "$1" in
+ -v)
+ opt_verbose=1
+ shift ;;
+ -h)
+ usage -h ;;
+ --)
+ shift
+ break ;;
+ esac
+done
+
+if [ $# -gt 1 ]
+then
+ usage
+fi
+opt_patch=$1
+
+if [ -n "$opt_patch" ]
+then
+ patch=$(stripit "$opt_patch")
+else
+ patch=$(top_patch)
+ if [ -z "$patch" ]
+ then
+ echo "No patches applied" >&2
+ exit 1
+ fi
+fi
+
+if ! is_applied $patch
+then
+ if [ -n "$opt_verbose" ]
+ then
+ echo "Patch is not applied (no verbose output)" >&2
+ opt_verbose=0
+ else
+ echo "Patch is not applied" >&2
+ fi
+fi
+
+if [ -z "$opt_verbose" ]
+then
+ files_in_patch $patch
+else
+ for file in $(files_in_patch $patch)
+ do
+ status=" "
+ if [ -s $(backup_file_name $patch $file) ]
+ then
+ if ! [ -s $file ]
+ then
+ status="-"
+ fi
+ else
+ if [ -s $file ]
+ then
+ status="+"
+ fi
+ fi
+ echo "$status $file"
+ done
+fi
diff --git a/importpatch.in b/quilt/import.in
index 2e0c8cf..0f3df93 100755..100644
--- a/importpatch.in
+++ b/quilt/import.in
@@ -1,4 +1,4 @@
-#! /bin/bash
+#!/bin/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
@@ -7,16 +7,19 @@
# See the COPYING and AUTHORS files for more details.
# Read in library functions
-if ! [ -r @LIB@/patchfns ]
+if [ "$(type -t patch_file_name)" != function ]
then
- echo "Cannot read library @LIB@/patchfns" >&2
- exit 1
+ if ! [ -r @LIB@/patchfns ]
+ then
+ echo "Cannot read library @LIB@/patchfns" >&2
+ exit 1
+ fi
+ . @LIB@/patchfns
fi
-. @LIB@/patchfns
usage()
{
- echo "Usage: importpatch [-f] [-p num] [-n patchname] [patchfile]"
+ echo "Usage: quilt import [-f] [-p num] [-n patch] [patchfile]"
if [ x$1 = x-h ]
then
cat <<EOF
@@ -29,7 +32,7 @@ used as the patch name.
-p num
Number of directory levels to strip when aplying (default=1)
--n patchfile
+-n patch
File name relative to patches/ to use.
-f Overwite/update existing patches.
@@ -111,29 +114,32 @@ fi
case "$input_file" in
'')
- tmp=$(mktemp /tmp/patch-scripts.XXXXXX)
- if ! cat > $tmp
+ tmpfile=$(mktemp /tmp/patch-scripts.XXXXXX)
+ if ! cat > $tmpfile
then
echo "Cannot read from standard input."
+ rm -f $tmpfile
exit 1
fi
- input_file=$tmp ;;
+ input_file=$tmpfile ;;
*.gz)
- tmp=$(mktemp /tmp/patch-scripts.XXXXXX)
- if ! gzip -cd "$input_file" > $tmp
+ tmpfile=$(mktemp /tmp/patch-scripts.XXXXXX)
+ if ! gzip -cd "$input_file" > $tmpfile
then
echo "Cannot decompress file $input_file"
+ rm -f $tmpfile
exit 1
fi
- input_file=$tmp ;;
+ input_file=$tmpfile ;;
*.bz2)
- tmp=$(mktemp /tmp/patch-scripts.XXXXXX)
- if ! bzip2 -cd "$input_file" > $tmp
+ tmpfile=$(mktemp /tmp/patch-scripts.XXXXXX)
+ if ! bzip2 -cd "$input_file" > $tmpfile
then
echo "Cannot decompress file $input_file"
+ rm -f $tmpfile
exit
fi
- input_file=$tmp ;;
+ input_file=$tmpfile ;;
*)
if ! [ -r "$input_file" ]
then
@@ -154,7 +160,7 @@ then
! grep -q '^%patch$' "$input_file"
then
echo "Updating %patch section of patch $patch"
- if ! @LIB@/parse-patch -u patch $patch_file< "$input_file"
+ if ! @LIB@/parse-patch -u patch $patch_file < "$input_file"
then
echo "Failed to update %patch section of patch $patch"
exit 1
@@ -188,7 +194,7 @@ then
echo "Failed to insert $patch in file series."
fi
-if [ -n "$tmp" ]
+if [ -n "$tmpfile" ]
then
- rm -f $tmp
+ rm -f $tmpfile
fi
diff --git a/newpatch.in b/quilt/new.in
index 34242f9..f04c47e 100755..100644
--- a/newpatch.in
+++ b/quilt/new.in
@@ -1,4 +1,4 @@
-#! /bin/bash
+#!/bin/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
@@ -7,22 +7,25 @@
# See the COPYING and AUTHORS files for more details.
# Read in library functions
-if ! [ -r @LIB@/patchfns ]
+if [ "$(type -t patch_file_name)" != function ]
then
- echo "Cannot read library @LIB@/patchfns" >&2
- exit 1
+ if ! [ -r @LIB@/patchfns ]
+ then
+ echo "Cannot read library @LIB@/patchfns" >&2
+ exit 1
+ fi
+ . @LIB@/patchfns
fi
-. @LIB@/patchfns
usage()
{
- echo "Usage: newpatch patchname"
+ echo "Usage: quilt new {patchname}"
if [ x$1 = x-h ]
then
cat <<EOF
- Create a new patch, and insert it after the topmost patch
- in the patch series file.
+Create a new patch with the specified file name, and insert
+it after the topmost patch in the patch series file.
EOF
exit 0
@@ -56,12 +59,8 @@ then
usage
fi
-patch_file=$(echo $1 | sed -e 's:^'"$P"'patches/::' -e 's:^\.pc/::')
+patch_file=$(echo $1 | sed -e 's:^'"$P"'patches/::')
patch=$(stripit $patch_file)
-if [ -z "$patch" ]
-then
- usage
-fi
if patch_in_series $patch
then
@@ -69,11 +68,14 @@ then
exit 1
fi
-pc_file=$(pc_file_name $patch)
-mkdir -p $(dirname $pc_file)
-touch $pc_file
-
-insert_in_series $patch_file || exit 1
-add_to_db $patch || exit 1
+mkdir -p $(dirname $(pc_file_name $patch))
+rm -f $(pc_file_name $patch)
-echo "Patch $patch is now on top"
+if ! insert_in_series $patch_file || \
+ ! add_to_db $patch
+then
+ echo "Failed to create patch $patch"
+ exit 1
+else
+ echo "Patch $patch is now on top"
+fi
diff --git a/quilt/next.in b/quilt/next.in
new file mode 100644
index 0000000..74ba4d2
--- /dev/null
+++ b/quilt/next.in
@@ -0,0 +1,72 @@
+#!/bin/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 @LIB@/patchfns ]
+ then
+ echo "Cannot read library @LIB@/patchfns" >&2
+ exit 1
+ fi
+ . @LIB@/patchfns
+fi
+
+usage()
+{
+ echo "Usage: quilt next [patch]"
+ if [ x$1 = x-h ]
+ then
+ cat <<EOF
+
+Print the name of the next patch after the specified or topmost patch in
+the series file.
+
+EOF
+ exit 0
+ else
+ exit 1
+ fi
+}
+
+options=`getopt -o h -- "$@"`
+
+if [ $? -ne 0 ]
+then
+ usage
+fi
+
+eval set -- "$options"
+
+while true
+do
+ case "$1" in
+ -h)
+ usage -h ;;
+ --)
+ shift
+ break ;;
+ esac
+done
+
+if [ $# -gt 1 ]
+then
+ usage
+elif [ $# -eq 1 ]
+then
+ patch=$(stripit $1)
+else
+ patch=$(top_patch)
+fi
+
+if [ -z "$patch" ]
+then
+ cat_series | head -1
+else
+ patches_after $patch | head -1
+fi
diff --git a/quilt/patches.in b/quilt/patches.in
new file mode 100644
index 0000000..6e1834b
--- /dev/null
+++ b/quilt/patches.in
@@ -0,0 +1,93 @@
+#!/bin/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 @LIB@/patchfns ]
+ then
+ echo "Cannot read library @LIB@/patchfns" >&2
+ exit 1
+ fi
+ . @LIB@/patchfns
+fi
+
+usage()
+{
+ echo "Usage: quilt contains {file}"
+ if [ x$1 = x-h ]
+ then
+ cat <<EOF
+
+Print the list of patches that modify the specified file.
+
+-v Verbose, more user friendly output.
+
+EOF
+ exit 0
+ else
+ exit 1
+ fi
+}
+
+scan_patches()
+{
+ local prefix=$1 file=$2
+ shift 2
+ local patch
+
+ for patch in $(modified_files $file -- "$@" \
+ | cut -d $'\t' -f2)
+ do
+ echo "$prefix$patch"
+ done
+}
+
+options=`getopt -o vh -- "$@"`
+
+if [ $? -ne 0 ]
+then
+ usage
+fi
+
+eval set -- "$options"
+
+while true
+do
+ case "$1" in
+ -v)
+ opt_verbose=1
+ shift ;;
+ -h)
+ usage -h ;;
+ --)
+ shift
+ break ;;
+ esac
+done
+
+if [ $# -ne 1 ]
+then
+ usage
+fi
+opt_file=$1
+
+if ! refresh_patches_per_file
+then
+ exit 1
+fi
+
+if [ -n "$opt_verbose" ]
+then
+ top=$(top_patch)
+ scan_patches "+ " $opt_file $(patches_before $top)
+ scan_patches "= " $opt_file $top
+ scan_patches " " $opt_file $(patches_after $top)
+else
+ scan_patches "" $opt_file
+fi
diff --git a/poppatch.in b/quilt/pop.in
index ff0b563..3ab2fac 100755..100644
--- a/poppatch.in
+++ b/quilt/pop.in
@@ -1,4 +1,4 @@
-#! /bin/bash
+#!/bin/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
@@ -7,16 +7,19 @@
# See the COPYING and AUTHORS files for more details.
# Read in library functions
-if ! [ -r @LIB@/patchfns ]
+if [ "$(type -t patch_file_name)" != function ]
then
- echo "Cannot read library @LIB@/patchfns" >&2
- exit 1
+ if ! [ -r @LIB@/patchfns ]
+ then
+ echo "Cannot read library @LIB@/patchfns" >&2
+ exit 1
+ fi
+ . @LIB@/patchfns
fi
-. @LIB@/patchfns
usage()
{
- echo "Usage: poppatch [-afRq] [npatches|patchname]"
+ echo "Usage: quilt pop [-afRqv] [num|patch]"
if [ x$1 = x-h ]
then
cat <<EOF
@@ -37,6 +40,8 @@ name is specified, remove the next patch.
-q Quiet operation.
+-v Verbose operation.
+
EOF
exit 0
else
@@ -68,11 +73,11 @@ list_patches()
fi
n=$[$n+1]
fi
- echo $patch
if [ $patch = "$stop_at_patch" ]
then
break
fi
+ echo $patch
done
if [ -n "$stop_at_patch" -a "$patch" != "$stop_at_patch" ]
then
@@ -82,7 +87,7 @@ list_patches()
fi
}
-options=`getopt -o fRqah -- "$@"`
+options=`getopt -o fRqvah -- "$@"`
if [ $? -ne 0 ]
then
@@ -105,6 +110,9 @@ do
-q)
opt_quiet=1
shift ;;
+ -v)
+ opt_verbose=1
+ shift ;;
-a)
opt_all=1
shift ;;
@@ -139,6 +147,8 @@ fi
rpatch_options="$rpatch_options -R"
[ -n "$opt_quiet" ] &&
rpatch_options="$rpatch_options -q"
+[ -n "$opt_verbose" ] &&
+ rpatch_options="$rpatch_options -v"
if [ -n "$stop_at_patch" ]
then
@@ -164,12 +174,11 @@ for patch in $patches
do
if ! @LIB@/rpatch $rpatch_options $patch
then
- echo Still at patch $patch
exit 1
fi
if [ -n "$interrupted" ]
then
- echo "poppatch interrupted by user"
+ echo "Interrupted by user"
exit 1
fi
[ -z "$opt_quiet" ] && echo
diff --git a/quilt/previous.in b/quilt/previous.in
new file mode 100644
index 0000000..45d4ce8
--- /dev/null
+++ b/quilt/previous.in
@@ -0,0 +1,70 @@
+#!/bin/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 @LIB@/patchfns ]
+ then
+ echo "Cannot read library @LIB@/patchfns" >&2
+ exit 1
+ fi
+ . @LIB@/patchfns
+fi
+
+usage()
+{
+ echo "Usage: quilt previous [patch]"
+ if [ x$1 = x-h ]
+ then
+ cat <<EOF
+
+Print the name of the previous patch before the specified or topmost
+patch in the series file.
+
+EOF
+ exit 0
+ else
+ exit 1
+ fi
+}
+
+options=`getopt -o h -- "$@"`
+
+if [ $? -ne 0 ]
+then
+ usage
+fi
+
+eval set -- "$options"
+
+while true
+do
+ case "$1" in
+ -h)
+ usage -h ;;
+ --)
+ shift
+ break ;;
+ esac
+done
+
+if [ $# -gt 1 ]
+then
+ usage
+elif [ $# -eq 1 ]
+then
+ patch=$(stripit $1)
+else
+ patch=$(top_patch)
+fi
+
+if [ -n "$patch" ]
+then
+ patches_before $patch | tail -1
+fi
diff --git a/pushpatch.in b/quilt/push.in
index d8fcab9..d488c7e 100755..100644
--- a/pushpatch.in
+++ b/quilt/push.in
@@ -1,4 +1,4 @@
-#! /bin/bash
+#!/bin/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
@@ -7,16 +7,19 @@
# See the COPYING and AUTHORS files for more details.
# Read in library functions
-if ! [ -r @LIB@/patchfns ]
+if [ "$(type -t patch_file_name)" != function ]
then
- echo "Cannot read library @LIB@/patchfns" >&2
- exit 1
+ if ! [ -r @LIB@/patchfns ]
+ then
+ echo "Cannot read library @LIB@/patchfns" >&2
+ exit 1
+ fi
+ . @LIB@/patchfns
fi
-. @LIB@/patchfns
usage()
{
- echo "Usage: pushpatch [-afq] [npatches|patchname]"
+ echo "Usage: quilt push [-afqv] [num|patch]"
if [ x$1 = x-h ]
then
cat <<EOF
@@ -33,6 +36,8 @@ specified, apply the next patch.
-q Quiet operation.
+-v Verbose operation.
+
EOF
exit 0
else
@@ -77,7 +82,7 @@ list_patches()
fi
}
-options=`getopt -o fqah -- "$@"`
+options=`getopt -o fqvah -- "$@"`
if [ $? -ne 0 ]
then
@@ -95,6 +100,9 @@ do
-q)
opt_quiet=1
shift ;;
+ -v)
+ opt_verbose=1
+ shift ;;
-a)
opt_all=1
shift ;;
@@ -127,6 +135,8 @@ fi
apatch_options="$apatch_options -f"
[ -n "$opt_quiet" ] &&
apatch_options="$apatch_options -q"
+[ -n "$opt_verbose" ] &&
+ apatch_options="$apatch_options -v"
if [ -n "$stop_at_patch" ]
then
@@ -162,7 +172,7 @@ do
fi
if [ -n "$interrupted" ]
then
- echo "pushpatch interrupted by user"
+ echo "Interrupted by user"
exit 1
fi
[ -z "$opt_quiet" ] && echo
diff --git a/quilt/refresh.in b/quilt/refresh.in
new file mode 100644
index 0000000..a7e5064
--- /dev/null
+++ b/quilt/refresh.in
@@ -0,0 +1,201 @@
+#!/bin/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 @LIB@/patchfns ]
+ then
+ echo "Cannot read library @LIB@/patchfns" >&2
+ exit 1
+ fi
+ . @LIB@/patchfns
+fi
+
+usage()
+{
+ local redirect
+ if [ x$1 != x-h ]
+ then
+ redirect='>&2'
+ fi
+ echo "Usage: quilt refresh [-p n] [-f] [patch]" $redirect
+
+ if [ x$1 = x-h ]
+ then
+ cat <<EOF
+
+Refresh an applied patch. Refreshes the specified patch, or
+the topmost patch by default. Documentation on top of the
+actual patch is retained.
+
+It is possible to refresh patches that are not on top. If
+any patches on top of the patch to refresh modify the same
+files, this script prints out the file and patch names. If
+there are any such conflicts, patches can still be refreshed
+with -f. In that case this script will print a warning for
+each shadowed file, changes by more recent patches will be
+ignored, and only changes in files that have not been
+modified by any more recent patches will end up in the
+specified patch.
+
+-p n Create a -pn style patch (-p0 or -p1 supported).
+
+-f Force refresh, even if more recent patches modify
+ some of the same files.
+
+EOF
+ exit 0
+ else
+ exit 1
+ fi
+}
+
+die ()
+{
+ local status=$1
+ [ -n "$tmpfile" ] && rm -f $tmpfile
+ [ -n "$tmpfile2" ] && rm -f $tmpfile2
+ exit $status
+}
+
+options=`getopt -o p:fh -- "$@"`
+
+if [ $? -ne 0 ]
+then
+ usage
+fi
+
+eval set -- "$options"
+
+while true
+do
+ case "$1" in
+ -p)
+ opt_strip_level=$2
+ shift 2 ;;
+ -f)
+ opt_force=1
+ shift ;;
+ -h)
+ usage -h ;;
+ --)
+ shift
+ break ;;
+ esac
+done
+
+if [ $# -eq 1 ]
+then
+ opt_patch=$1
+elif [ $# -gt 1 ]
+then
+ usage
+fi
+
+if [ -n "$opt_patch" ]
+then
+ patch=$(stripit $opt_patch)
+else
+ patch=$(top_patch)
+ if [ -z "$patch" ]
+ then
+ echo "No patches seem to be applied" >&2
+ exit 1
+ fi
+fi
+
+if ! is_applied "$patch"
+then
+ echo "Patch $patch is not applied" >&2
+ exit 1
+fi
+
+if [ -z "$opt_strip_level" ]
+then
+ opt_strip_level=$(patch_strip_level $patch)
+fi
+if [ $opt_strip_level -gt 1 ]
+then
+ echo "Cannot refresh patches with -p$opt_strip_level," \
+ "please specify -p0 or -p1 instead" >&2
+ exit 1
+fi
+
+trap "die 1" SIGTERM
+
+tmpfile=$(mktemp /tmp/patch-scripts.XXXXXX)
+
+for file in $(files_in_patch $patch)
+do
+ old_file=$(backup_file_name $patch $file)
+ next_patch=$(next_patch_for_file $patch $file)
+ if [ -z "$next_patch" ]
+ then
+ new_file=$file
+ else
+ new_file=$(backup_file_name $next_patch $file)
+ files_were_shadowed=1
+ fi
+ if ! diff_file $file "~${patch//\//_}" $old_file $new_file >> $tmpfile
+ then
+ echo "Diff failed, aborting." >&2
+ die 1
+ fi
+
+ if [ -n "$files_were_shadowed" -a -z "$opt_force" ]
+ then
+ echo "More recent patches modify the same files." \
+ "Enforce refresh with -f." >&2
+ die 1
+ fi
+done
+
+if ! [ -s $tmpfile ]
+then
+ echo "Nothing in patch $patch" >&2
+ die 1
+fi
+
+patch_file=$(patch_file_name $patch)
+
+trap "" SIGINT
+
+if [ -e $patch_file ] && grep -q '^%patch$' $patch_file
+then
+ if [ -x "$DIFFSTAT" ]
+ then
+ $DIFFSTAT $tmpfile 2>/dev/null \
+ | @LIB@/parse-patch -u diffstat $patch_file
+ fi
+ cat $tmpfile \
+ | @LIB@/parse-patch -u patch $patch_file
+else
+ if ! tmpfile2=$(mktemp /tmp/patch-scripts.XXXXXX)
+ then
+ die 1
+ fi
+
+ if ! cat_file $patch_file \
+ | patch_description > $tmpfile2 || \
+ ! cat $tmpfile >> $tmpfile2 || \
+ ! cat $tmpfile2 \
+ | cat_to_file $patch_file
+ then
+ die 1
+ fi
+fi
+status=$?
+
+rm -f $(pc_file_name $patch)~refresh
+echo "Refreshed patch $patch"
+if ! change_db_strip_level -p$opt_strip_level $patch
+then
+ die 1
+fi
+die 0
diff --git a/quilt/remove.in b/quilt/remove.in
new file mode 100644
index 0000000..bea9baf
--- /dev/null
+++ b/quilt/remove.in
@@ -0,0 +1,119 @@
+#!/bin/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 @LIB@/patchfns ]
+ then
+ echo "Cannot read library @LIB@/patchfns" >&2
+ exit 1
+ fi
+ . @LIB@/patchfns
+fi
+
+usage()
+{
+ echo "Usage: quilt remove [-p patch] {file} ..."
+ if [ x$1 = x-h ]
+ then
+ cat <<EOF
+
+Remove one or more files to the topmost or named patch.
+Files that are modified by patches on top of the specified
+patch cannot be removed.
+
+-p patch
+ Patch to add files to.
+
+EOF
+ exit 0
+ else
+ exit 1
+ fi
+}
+
+options=`getopt -o p:h -- "$@"`
+
+if [ $? -ne 0 ]
+then
+ usage
+fi
+
+eval set -- "$options"
+
+while true
+do
+ case "$1" in
+ -p)
+ opt_patch=$2
+ shift 2 ;;
+ -h)
+ usage -h ;;
+ --)
+ shift
+ break ;;
+ esac
+done
+
+if [ $# -lt 1 ]
+then
+ usage
+fi
+
+patch=$(stripit $opt_patch)
+if [ -z "$patch" ]
+then
+ patch=$(top_patch)
+fi
+if [ -z "$patch" ]
+then
+ echo "No patches applied"
+fi
+
+if ! is_applied $patch
+then
+ echo "Patch $patch is not applied"
+ exit 1
+fi
+
+status=0
+for file in $*
+do
+ if ! file_in_patch $file $patch
+ then
+ echo "File $file is not in patch $patch"
+ status=1
+ continue
+ fi
+
+ next_patch=$(next_patch_for_file $patch $file)
+ if [ -n "$next_patch" ]
+ then
+ echo "File $file modified by patch $next_patch"
+ status=1
+ continue
+ fi
+
+ # Restore file from backup
+ if ! @LIB@/backup-files -s -B .pc/$patch/ -r $file
+ then
+ echo "Failed to remove file $file from patch $patch"
+ status=1
+ continue
+ fi
+
+ pc_file=$(pc_file_name $patch)
+ tmpfile=$(mktemp /tmp/patch-scripts.XXXXXX) &&
+ grep -v '^'"$(quote_re $file)"'$' $pc_file > $tmpfile &&
+ mv -f $tmpfile $pc_file
+ rm -f $tmpfile
+
+ echo "File $file removed from patch $patch"
+done
+exit $status
diff --git a/quilt/rest.in b/quilt/rest.in
new file mode 100755
index 0000000..6642fbb
--- /dev/null
+++ b/quilt/rest.in
@@ -0,0 +1,72 @@
+#!/bin/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 @LIB@/patchfns ]
+ then
+ echo "Cannot read library @LIB@/patchfns" >&2
+ exit 1
+ fi
+ . @LIB@/patchfns
+fi
+
+usage()
+{
+ echo "Usage: quilt rest [patch]"
+ if [ x$1 = x-h ]
+ then
+ cat <<EOF
+
+Print a list of patches that are not applied, or all patches that follow
+the specified patch in the series file.
+
+EOF
+ exit 0
+ else
+ exit 1
+ fi
+}
+
+options=`getopt -o h -- "$@"`
+
+if [ $? -ne 0 ]
+then
+ usage
+fi
+
+eval set -- "$options"
+
+while true
+do
+ case "$1" in
+ -h)
+ usage -h ;;
+ --)
+ shift
+ break ;;
+ esac
+done
+
+if [ $# -gt 1 ]
+then
+ usage
+elif [ $# -eq 1 ]
+then
+ patch=$(stripit $1)
+else
+ patch=$(top_patch)
+fi
+
+if [ -z "$patch" ]
+then
+ cat_series
+else
+ patches_after $patch
+fi
diff --git a/quilt/series.in b/quilt/series.in
new file mode 100644
index 0000000..7c10fad
--- /dev/null
+++ b/quilt/series.in
@@ -0,0 +1,87 @@
+#!/bin/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 @LIB@/patchfns ]
+ then
+ echo "Cannot read library @LIB@/patchfns" >&2
+ exit 1
+ fi
+ . @LIB@/patchfns
+fi
+
+usage()
+{
+ echo "Usage: quilt series [-v]"
+ if [ x$1 = x-h ]
+ then
+ cat <<EOF
+
+Print the names of all patches in the file series.
+
+-v Verbose, more user friendly output
+EOF
+ exit 0
+ else
+ exit 1
+ fi
+}
+
+cat_patches()
+{
+ local prefix=$1
+ shift
+ local patch
+
+ for patch in "$@"
+ do
+ echo "$prefix$patch"
+ done
+}
+
+options=`getopt -o vh -- "$@"`
+
+if [ $? -ne 0 ]
+then
+ usage
+fi
+
+eval set -- "$options"
+
+opt_what=here
+
+while true
+do
+ case "$1" in
+ -v)
+ opt_verbose=1
+ shift ;;
+ -h)
+ usage -h ;;
+ --)
+ shift
+ break ;;
+ esac
+done
+
+if [ $# -ne 0 ]
+then
+ usage
+fi
+
+if [ -n "$opt_verbose" ]
+then
+ top=$(top_patch)
+ cat_patches "+ " $(patches_before $top)
+ [ -n "$top" ] && cat_patches "= " $top
+ cat_patches " " $(patches_after $top)
+else
+ cat_series
+fi
diff --git a/quilt/setup.in b/quilt/setup.in
new file mode 100644
index 0000000..3d2bee0
--- /dev/null
+++ b/quilt/setup.in
@@ -0,0 +1,172 @@
+#!/bin/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 @LIB@/patchfns ]
+ then
+ echo "Cannot read library @LIB@/patchfns" >&2
+ exit 1
+ fi
+ . @LIB@/patchfns
+fi
+
+usage()
+{
+ echo "Usage: quilt setup [-d sourcedir] {seriesfile|specfile}"
+ if [ x$1 = x-h ]
+ then
+ cat <<EOF
+
+Initializes a source tree from a patch series file. The
+patch series file must contain the name of the relevant
+tar archive, in addition to the list of patches.
+
+EOF
+ exit 0
+ else
+ exit 1
+ fi
+}
+
+parse_series()
+{
+ local series="$1"
+
+ perl -e '
+ while(<>) {
+ if (/^#\s*[Ss]ource:\s*(\S+)\s*(-C\s*(\S+))?/) {
+ print "S $1 ", ($3 ? $3 : "."), "\n";
+ } elsif (/^#\s*[Pp]atchdir:\s*(\S+)/) {
+ print "D $1\n";
+ } elsif (/^([^#\s]+)/) {
+ print "P $1\n";
+ }
+ }
+ ' $series
+ echo "I $series"
+}
+
+options=`getopt -o d:h -- "$@"`
+
+if [ $? -ne 0 ]
+then
+ usage
+fi
+
+eval set -- "$options"
+
+while true
+do
+ case "$1" in
+ -d)
+ opt_source=$2
+ shift 2 ;;
+ -h)
+ usage -h ;;
+ --)
+ shift
+ break ;;
+ esac
+done
+
+if [ $# -ne 1 ]
+then
+ usage
+fi
+
+case "$1" in
+*.spec)
+ spec_file="$1"
+ tmpfile=$(mktemp /tmp/patch-scripts.XXXXXX)
+ series_file=$tmpfile
+ if ! @LIB@/spec2series "$spec_file" > $tmpfile
+ then
+ exit 1
+ fi
+ ;;
+*)
+ series_file=$1
+ if ! [ -e "$series_file" ]
+ then
+ echo "Series file $series_file not found"
+ exit 1
+ fi
+ ;;
+esac
+
+if [ -n "$opt_source" ]
+then
+ source="$opt_source"
+elif [ -n "$spec_file" ]
+then
+ source="$(dirname "$spec_file")"
+else
+ source="$(dirname "$series_file")"
+fi
+
+status=0
+packagedir=.
+while read cmd arg arg2 && \
+ [ $status -eq 0 ]
+do
+ case $cmd in
+ D)
+ # Base directory for package
+ packagedir="$arg"
+ if [ -d "$packagedir" ]
+ then
+ echo "Directory $packagedir exists already."
+ status=1
+ break
+ elif [ -e "$packagedir" ]
+ then
+ echo "File $packagedir exists."
+ status=1
+ break
+ fi
+ ;;
+ S)
+ echo "Unpacking archive $source/$arg"
+ mkdir -p "$arg2" && \
+ cat_file "$source/$arg" \
+ | tar xf - -C "${arg2:-.}"
+ ;;
+ P)
+ echo "Copying patch $source/$arg"
+ mkdir -p "$packagedir/patches/" && \
+ cp "$source/$arg" "$packagedir/patches/" \
+ ;;
+ I)
+ echo "Copying series file"
+ cp "$arg" "$packagedir/patches/series"
+ ;;
+ *)
+ status=1
+ break
+ ;;
+ esac
+ status=$?
+done \
+< <(parse_series "$series_file")
+
+if [ -n "$tmpfile" ]
+then
+ rm -f $tmpfile
+fi
+
+if [ $status -ne 0 ]
+then
+ exit 1
+fi
+
+if [ "$packagedir" != "." ]
+then
+ echo "Directory $packagedir set up."
+fi
diff --git a/quilt/top.in b/quilt/top.in
new file mode 100644
index 0000000..84f6ba7
--- /dev/null
+++ b/quilt/top.in
@@ -0,0 +1,62 @@
+#!/bin/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 @LIB@/patchfns ]
+ then
+ echo "Cannot read library @LIB@/patchfns" >&2
+ exit 1
+ fi
+ . @LIB@/patchfns
+fi
+
+usage()
+{
+ echo "Usage: quilt top"
+ if [ x$1 = x-h ]
+ then
+ cat <<EOF
+
+Print the name of the topmost patch on the current stack of applied
+patches.
+
+EOF
+ exit 0
+ else
+ exit 1
+ fi
+}
+
+options=`getopt -o h -- "$@"`
+
+if [ $? -ne 0 ]
+then
+ usage
+fi
+
+eval set -- "$options"
+
+while true
+do
+ case "$1" in
+ -h)
+ usage -h ;;
+ --)
+ shift
+ break ;;
+ esac
+done
+
+if [ $# -ne 0 ]
+then
+ usage
+fi
+
+top_patch
diff --git a/refpatch.in b/refpatch.in
deleted file mode 100755
index f1a95b3..0000000
--- a/refpatch.in
+++ /dev/null
@@ -1,335 +0,0 @@
-#! /bin/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 ! [ -r @LIB@/patchfns ]
-then
- echo "Cannot read library @LIB@/patchfns" >&2
- exit 1
-fi
-. @LIB@/patchfns
-
-usage()
-{
- local redirect
- if [ x$1 != x-h ]
- then
- redirect='>&2'
- fi
- echo "Usage: refpatch [-cfz] [patchname]" $redirect
-
- if [ x$1 = x-h ]
- then
- cat <<EOF
-
-Refresh an applied patch. Refreshes the specified patch, or
-the topmost patch by default. Documentation on top of the
-actual patch is retained.
-
-It is possible to refresh patches that are not on top.
-If any patches on top of the patch to refresh modify the
-same files, refpatch prints out the file and patch names.
-If there are any such conflicts, patches can still be
-refreshed with -f. In that case refpatch will print a
-warning for each thus shadowed file, changes by more
-recent patches will be ignored, and only changes in files
-that have not been modified by any more recent patches
-will end up in the specified patch.
-
--c Write to standard output only; don't update the patch.
-
--f Force refresh, even if more recent patches modify
- some of the same files.
-
--z Write to standard output the changes that have been
- made relative to the topmost or specified patch.
-
-EOF
- exit 0
- else
- exit 1
- fi
-}
-
-fix_diff_header()
-{
- local from=$1 to=$2
- sed -e 's:^--- [^ \t]*:--- '"$from"':' \
- -e 's:^+++ [^ \t]*:+++ '"$to"':'
-}
-
-diff_file()
-{
- local file=$1 patch=$2 status=0
- local next_patch=$(next_patch_for_file $patch $file)
- local old_file=$(backup_file_name $patch $file)
- local new_file file_was_shadowed
- if [ -n "$next_patch" ]
- then
- new_file=$(backup_file_name $next_patch $file)
- file_was_shadowed=1
- else
- new_file=$file
- fi
-
- if [ ! -e $old_file -a ! -e $new_file ]
- then
- echo "File $new_file does not exist" >&2
- return 0
- fi
- local dir=$(basename $PWD) suffix=${patch//\//_} old_hdr new_hdr
- if [ $opt_strip -eq 0 ]
- then
- old_hdr=$file~$suffix
- new_hdr=$file
- else
- old_hdr=$dir~$suffix/$file
- new_hdr=$dir/$file
- fi
-
- if [ -z "$opt_post" ]
- then
- echo diff -Nu $DIFF_OPTS $old_file $new_file >&2
- diff -Nu $DIFF_OPTS $old_file $new_file |
- fix_diff_header $old_hdr $new_hdr
- status=$?
-
- if [ $status -eq 0 -a -n "$file_was_shadowed" ]
- then
- status=2
- fi
- elif [ -n "$file_was_shadowed" ]
- then
- return 0
- else
- local tmp=$(mktemp /tmp/patch-scripts.XXXXXX)
- if ! filterdiff $(patch_args $patch) -i $file \
- $(patch_file_name $patch) \
- | patch -s -o $tmp $old_file --no-backup-if-mismatch
- then
- echo "Failed to patch temporary file" >&2
- return 1
- fi
-
- echo diff -Nu $DIFF_OPTS $new_file.orig $new_file >&2
- diff -Nu $DIFF_OPTS $tmp $new_file |
- fix_diff_header $new_file.orig $new_hdr
- status=$?
- rm -f $tmp
- fi
- return $status
-}
-
-die ()
-{
- local status=$1
- [ -n "$tmp" ] && rm -f $tmp
- [ -n "$tmp2" ] && rm -f $tmp2
- [ -n "$workdir" ] && rm -rf $workdir
- exit $status
-}
-
-options=`getopt -o p:fczh -- "$@"`
-
-if [ $? -ne 0 ]
-then
- usage
-fi
-
-eval set -- "$options"
-
-while true
-do
- case "$1" in
- -p)
- opt_strip=$2
- shift 2 ;;
- -c)
- opt_stdout=1
- shift ;;
- -f)
- opt_force=1
- shift ;;
- -z)
- opt_post=1
- opt_stdout=1
- shift ;;
- -h)
- usage -h ;;
- --)
- shift
- break ;;
- esac
-done
-
-if [ $# -eq 1 ]
-then
- opt_patch=$1
-elif [ $# -gt 1 ]
-then
- usage
-fi
-
-if [ -n "$opt_patch" ]
-then
- patch=$(stripit $opt_patch)
-else
- patch=$(top_patch)
- if [ -z "$patch" ]
- then
- echo "No patches seem to be applied" >&2
- exit 1
- fi
-fi
-
-if ! is_applied "$patch"
-then
- echo "Patch $patch is not applied" >&2
- exit 1
-fi
-
-if [ -z "$opt_strip" ]
-then
- opt_strip=$(patch_strip_level $patch)
-fi
-if [ $opt_strip -gt 1 ]
-then
- echo "Cannot refresh patches with -p$opt_strip," \
- "please specify -p0 or -p1 instead" >&2
- exit 1
-fi
-
-trap "die 1" SIGTERM
-
-if [ -z "$opt_stdout" ]
-then
- tmp=$(mktemp /tmp/patch-scripts.XXXXXX)
-fi
-
-if [ -n "$opt_post" ]
-then
- patch_file=$(patch_file_name $patch)
- files=$(files_in_patch $patch)
- workdir=$(mktemp -d patch-scripts.XXXXXX)
- pwd=$PWD
-
- if ! cd .pc/$patch
- then
- echo "Cannot change into .pc/$patch"
- die 1
- fi
- if ! cp -l --parents $files $pwd/$workdir/
- then
- echo "Failed to copy files to temporary directory"
- die 1
- fi
- if ! cd $pwd/$workdir
- then
- echo "Cannot change to temporary directory"
- die 1
- fi
- if ! patch $(patch_args $patch) --no-backup-if-mismatch \
- -E -i $pwd/$patch_file >/dev/null 2>/dev/null
- then
- echo "Failed to patch temporary files"
- die 1
- fi
- if ! cd $pwd
- then
- echo "Cannot change to source directory"
- die 1
- fi
-
- for file in $(files_in_patch $patch)
- do
- suffix=${patch//\//_}
- if [ $opt_strip -eq 0 ]
- then
- old_hdr=$file.orig
- new_hdr=$file
- else
- dir=$(basename $PWD)
- old_hdr=$dir.orig/$file
- new_hdr=$dir/$file
- fi
- echo diff -Nu $DIFF_OPTS $new_hdr.orig $new_hdr >&2
- diff -Nu $DIFF_OPTS $workdir/$file $file \
- | fix_diff_header $old_hdr $new_hdr
- if [ $? -ne 0 ]
- then
- status=1
- fi
- done
- die $status
-else
- for file in $(files_in_patch $patch)
- do
- diff_file $file $patch
- status=$?
- if [ $status -eq 2 ]
- then
- files_were_shadowed=1
- elif [ $status -ne 0 ]
- then
- echo "Diff failed, aborting." >&2
- die 1
- fi
-
- if [ -n "$files_were_shadowed" -a -z "$opt_force" ]
- then
- echo "More recent patches modify the same files." \
- "Enforce refresh with -f." >&2
- die 1
- fi
- done
-fi \
-| if [ -z "$opt_stdout" ]
-then
- cat > $tmp
-else
- cat
-fi
-
-if [ -z "$opt_stdout" ]
-then
- if ! [ -s $tmp ]
- then
- echo "Nothing in patch $patch" >&2
- die 1
- fi
-
- patch_file=$(patch_file_name $patch)
-
- trap "" SIGINT
-
- if [ ! -e $patch_file ] || grep -q '^%patch$' $patch_file
- then
- touch $patch_file
- cat $tmp \
- | @LIB@/parse-patch -u patch $patch_file
- else
- tmp2=$(mktemp /tmp/patch-scripts.XXXXXX) &&
- patch_description $patch_file > $tmp2 &&
- cat $tmp >> $tmp2 &&
- mv $tmp2 $patch_file
- fi
- status=$?
-
- rm -f $tmp $tmp2
- if [ $status -ne 0 ]
- then
- die 1
- fi
-
- rm -f $(pc_file_name $patch)~forced
- echo "Refreshed patch $patch"
- if ! change_db_strip_level -p$opt_strip $patch
- then
- die 1
- fi
-fi
diff --git a/toppatch.in b/toppatch.in
deleted file mode 100755
index e65dc9d..0000000
--- a/toppatch.in
+++ /dev/null
@@ -1,138 +0,0 @@
-#! /bin/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 ! [ -r @LIB@/patchfns ]
-then
- echo "Cannot read library @LIB@/patchfns" >&2
- exit 1
-fi
-. @LIB@/patchfns
-
-usage()
-{
- echo "Usage: toppatch [-bpnfa] [patchname]"
- if [ x$1 = x-h ]
- then
- cat <<EOF
-
-Print the name of the topmost patch on the current stack
-of applied patches, or the names of one or more patches
-relative to this patch.
-
--b Print the names of all patches before the
- topmost or specified patch.
-
--p Print the name of the previous patch in the
- series.
-
--n Print the name of the next patch in the series.
-
--f Print the names of all patches following the
- topmost or specified patch.
-
--a Print the names of all patches in the file series.
-
-EOF
- exit 0
- else
- exit 1
- fi
-}
-
-options=`getopt -o bpnfah -- "$@"`
-
-if [ $? -ne 0 ]
-then
- usage
-fi
-
-eval set -- "$options"
-
-opt_what=here
-
-while true
-do
- case "$1" in
- -b)
- opt_what=before
- shift ;;
- -p)
- opt_what=previous
- shift ;;
- -n)
- opt_what=next
- shift ;;
- -f)
- opt_what=follow
- shift ;;
- -a)
- opt_what=all
- shift ;;
- -h)
- usage -h ;;
- --)
- shift
- break ;;
- esac
-done
-
-if [ $# -gt 1 ]
-then
- usage
-elif [ $# -eq 1 ]
-then
- opt_patch=$1
-fi
-
-if [ -n "$opt_patch" ]
-then
- patch=$(stripit $opt_patch)
-else
- patch=$(top_patch)
-fi
-
-case $opt_what in
-before)
- if [ -n "$patch" ]
- then
- patches_before $patch
- fi
- ;;
-previous)
- if [ -n "$patch" ]
- then
- patches_before $patch | tail -1
- fi
- ;;
-here)
- if [ -n "$patch" ]
- then
- echo $patch
- fi
- ;;
-next)
- if [ -z "$patch" ]
- then
- cat_series | head -1
- else
- patches_after $patch | head -1
- fi
- ;;
-follow)
- if [ -z "$patch" ]
- then
- cat_series
- else
- patches_after $patch
- fi
- ;;
-all)
- cat_series
- ;;
-esac