Import Upstream version 0.66

This commit is contained in:
luoyaoming 2022-12-06 14:41:56 +08:00
commit 4f66d04872
136 changed files with 33552 additions and 0 deletions

42
AUTHORS Normal file
View File

@ -0,0 +1,42 @@
Quilt started as a series of scripts written by Andrew Morton
(patch-scripts). Based on Andrew's ideas, Andreas Gruenbacher
completely rewrote the scripts, with the help of several other
contributors (see below).
Please report bugs to the quilt-dev mailing list,
<http://mail.nongnu.org/mailman/listinfo/quilt-dev>.
Quilt
=====
Andreas Gruenbacher <agruen@suse.de>
Clean up, reorganize, speedups, documentation.
Package up as RPM.
Gerd Knorr <kraxel@suse.de>
Contributed spec2series (which is inspect now).
Martin Quinson (martin.quinson#debian.org)
Several little patches and improvements.
Internationalization.
Debian packaging.
Peter Braam <braam@clusterfs.com>
Tom Wang <wangdi@clusterfs.com>
Fix pop logic if series file changes.
Pre-quilt (patch-scripts)
=========================
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.

340
COPYING Normal file
View File

@ -0,0 +1,340 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

454
Makefile.in Normal file
View File

@ -0,0 +1,454 @@
PACKAGE := @PACKAGE_NAME@
VERSION := @PACKAGE_VERSION@
RELEASE := @PACKAGE_RELEASE@
PACKAGE_TARNAME := @PACKAGE_TARNAME@
PACKAGE_BUGREPORT := @PACKAGE_BUGREPORT@
prefix := @prefix@
exec_prefix := @exec_prefix@
bindir := @bindir@
datarootdir := @datarootdir@
datadir := @datadir@
docdir := @docdir@
mandir := @mandir@
localedir := $(datadir)/locale
emacsdir := $(datadir)/emacs/site-lisp
etcdir := @sysconfdir@
INSTALL := @INSTALL@
POD2MAN := @POD2MAN@
COLUMN := @COLUMN@
GETOPT := @GETOPT@
CP := @CP@
DATE := @DATE@
PERL := @PERL@
BASH := @BASH@
SHELL:= @BASH@ # It does not work if dash is used as a shell, for example
GREP := @GREP@
TAIL := @TAIL@
TR := @TR@
SED := @SED@
AWK := @AWK@
FIND := @FIND@
XARGS := @XARGS@
DIFF := @DIFF@
PATCH := @PATCH@
MKTEMP := @MKTEMP@
MSGMERGE := @MSGMERGE@
MSGFMT := @MSGFMT@
XGETTEXT := @XGETTEXT@
MSGUNIQ := @MSGUNIQ@
MSGCAT := @MSGCAT@
DIFFSTAT := @DIFFSTAT@
RPMBUILD := @RPMBUILD@
SENDMAIL := @SENDMAIL@
MD5SUM := @MD5SUM@
7Z := @P7ZIP@
USE_NLS := @USE_NLS@
STAT_HARDLINK := @STAT_HARDLINK@
PATCH_WRAPPER := @PATCH_WRAPPER@
COMPAT_SYMLINKS := @COMPAT_SYMLINKS@
COMPAT_PROGRAMS := @COMPAT_PROGRAMS@
default: all
#-----------------------------------------------------------------------
DIRT += $(shell $(FIND) . -name '*~')
DIRT += $(shell $(FIND) . -name '.\#*')
SRC += COPYING AUTHORS TODO Makefile.in configure.ac \
config/install-sh quilt.spec.in NEWS \
bash_completion quilt.quiltrc aclocal.m4 git-desc
DIRT += quilt.spec
DIRT += $(PACKAGE)-*.tar.gz
DIRT += $(PACKAGE)-*.tar.gz.sig
DIRT += $(PACKAGE)-*.tar.bz2
BIN_IN := quilt guards
BIN_SRC := $(BIN_IN:%=%.in)
BIN := $(BIN_IN)
SRC += $(BIN_SRC:%=bin/%) bin/patch-wrapper.in
DIRT += $(BIN_IN:%=bin/%) bin/patch-wrapper
QUILT_IN := $(patsubst quilt/%.in,%,$(wildcard quilt/*.in))
QUILT_SRC := $(QUILT_IN:%=%.in)
QUILT := $(QUILT_IN)
SRC += $(QUILT_SRC:%=quilt/%)
DIRT += $(QUILT_IN:%=quilt/%)
SCRIPTS_IN := patchfns inspect-wrapper dependency-graph edmail \
remove-trailing-ws backup-files
SCRIPTS_SRC := $(SCRIPTS_IN:%=%.in)
SCRIPTS := $(SCRIPTS_IN)
SRC += $(SCRIPTS_SRC:%=quilt/scripts/%)
SRC += quilt/scripts/utilfns
DIRT += $(SCRIPTS_IN:%=quilt/scripts/%)
COMPAT := $(COMPAT_PROGRAMS:%=compat/%) $(COMPAT_SYMLINKS:%=compat/%)
SRC += $(wildcard compat/*.in) $(wildcard compat/*.sh)
DIRT += $(patsubst %.in,%,$(wildcard compat/*.in)) $(COMPAT_SYMLINKS:%=compat/%)
LIB_SRC := quilt.el
SRC += $(LIB_SRC:%=lib/%)
DOC_IN := README quilt.1
DOC_SRC := $(DOC_IN:%=doc/%.in)
DOC := $(DOC_IN)
SRC += $(DOC_SRC)
SRC += doc/main.tex doc/quilt.pdf doc/Makefile \
doc/README.MAIL doc/README.EMACS
DIRT += $(DOC_IN:%=doc/%) doc/reference
MAN1 := doc/quilt.1
ifneq ($(POD2MAN),)
MAN1 += doc/guards.1
DIRT += doc/guards.1
endif
LINGUAS := fr de ja ru
PO := quilt.pot $(LINGUAS:%=%.po)
SRC += $(PO:%=po/%)
DIRT += po/*.mo po/*~
SRC += $(wildcard test/*.test) test/run test/test.quiltrc
NON_EXEC_IN := doc/quilt.1 doc/README quilt/scripts/patchfns quilt/scripts/utilfns
GIT_DESC := $(shell ./git-desc | sed -e 's:^v::')
# Tests are sorted to make it easier to compare the results between runs
TESTS := $(sort $(wildcard test/*.test))
ifeq ($(PATCH_WRAPPER),)
TESTS := $(filter-out test/patch-wrapper.test,$(TESTS))
endif
DIRT += test/.depend $(wildcard test/.*.ok)
# Settings for running the uninstalled version of quilt in the source tree:
PATH := $(CURDIR)/bin:$(CURDIR)/compat:$(PATH)
QUILT_DIR := $(CURDIR)/quilt
QUILTRC := $(CURDIR)/test/test.quiltrc
export QUILT_DIR QUILTRC
#-----------------------------------------------------------------------
all : configure scripts compat $(DOC:%=doc/%) $(MAN1) mofiles
ifeq ($(USE_NLS),yes)
mofiles : $(LINGUAS:%=po/%.mo)
else
mofiles :
endif
%.mo : %.po
$(MSGFMT) --statistics -o $@ $<
%.po : po/quilt.pot
$(MSGMERGE) -o $@ $@ $^
updatepo : $(PO:%=po/%)
scripts : $(BIN:%=bin/%) $(QUILT:%=quilt/%) \
$(SCRIPTS:%=quilt/scripts/%) \
$(if $(PATCH_WRAPPER),bin/patch-wrapper)
dist : clean $(PACKAGE)-$(VERSION).tar.gz
publish : dist
gpg --detach-sign --use-agent $(PACKAGE)-$(VERSION).tar.gz
scp $(PACKAGE)-$(VERSION).tar.gz{,.sig} \
dl.sv.nongnu.org:/releases/quilt/
snapshot : $(PACKAGE)-$(GIT_DESC).tar.bz2
rpm rpmbuild : $(PACKAGE)-$(VERSION).tar.gz
$(RPMBUILD) -ta $<
po/quilt.pot: $(filter-out doc/quilt.1.in doc/README.in, \
$(wildcard */*.in) $(wildcard */*/*.in))
rm -f po/quilt.pot; touch po/quilt.pot
for file in $+ ; do \
if test -n "`$(SED) -ne '1{ /@BASH''@/p }' $$file`" \
-o "$$file" = quilt/scripts/patchfns.in; then \
$(BASH) --dump-po-strings $$file ; \
elif test -n "`$(SED) -ne '1{ /@PERL''@/p }' $$file`"; then \
$(XGETTEXT) --from-code=UTF-8 --omit-header --language=Perl \
--keyword=_ -o - $$file; \
else \
echo "Don't know how to handle $$file" >&2 ; \
exit 1; \
fi \
done \
|$(MSGUNIQ) \
|$(MSGCAT) --force-po -F - $@ -o $@
doc/README : doc/README.in doc/reference
@echo "README.in -> README"
@while read line; do \
case "$$line" in \
'@REFERENCE''@') \
cat doc/reference \
;; \
*) \
echo $$line \
;; \
esac ; \
done 2>&1 < $< > $@
doc/quilt.1: doc/quilt.1.in doc/reference $(COMPAT)
@echo "quilt.1.in -> quilt.1"
@while read line; do \
case "$$line" in \
'@REFERENCE''@') \
$(SED) -e 's/^quilt \([^ ]*\)\(.*\)/.IP "\\fB\1\\fP\2 " 4/' \
-e $$'s/^ \\(-[^\t]*\\)\t\\?/.IP " \\1" 8\\\n/' \
-e $$'s/^ \t\\?//' \
< doc/reference \
;; \
*@DOCSUBDIR@*) \
echo "$$line" | \
$(SED) -e 's:@DOCSUBDIR''@:$(docdir):g' \
;; \
*) \
echo "$$line" \
;; \
esac; \
done < $< 2>&1 > $@
doc/reference : bin/quilt $(QUILT:%=quilt/%) quilt/scripts/patchfns quilt/scripts/utilfns $(COMPAT)
@unset LANG LC_MESSAGES LC_CTYPE LC_ALL; \
for i in $(sort $(QUILT)); \
do \
echo; \
QUILT_PC=.fake_pc quilt $$i -h; \
echo; \
done | \
$(SED) -e 's/\$$EDITOR ([^)]*)/$$EDITOR/' \
-e '/^$$/!s/^/ /' \
-e 's/^ Usage: *//' > $@
doc/guards.1 : bin/guards
$(POD2MAN) $< > $@
$(PACKAGE)-$(VERSION).tar.gz : $(SRC) configure $(PACKAGE).spec
rm -f $(PACKAGE)-$(VERSION) $@
ln -s . $(PACKAGE)-$(VERSION)
tar chf - $(+:%=$(PACKAGE)-$(VERSION)/%) | gzip -9 > $@
rm -f $(PACKAGE)-$(VERSION)
@echo "File $@ created."
$(PACKAGE)-$(GIT_DESC).tar.bz2 : $(SRC) configure $(PACKAGE).spec
rm -f $(PACKAGE)-$(GIT_DESC) $@
ln -s . $(PACKAGE)-$(GIT_DESC)
tar chf - $(+:%=$(PACKAGE)-$(GIT_DESC)/%) | bzip2 -9 > $@
rm -f $(PACKAGE)-$(GIT_DESC)
@echo "File $@ created."
$(PACKAGE).spec : $(PACKAGE).spec.in NEWS Makefile
@echo "Generating spec file" ; \
set -e ; \
changelog="`sed \
-e 's/^Version \([0-9.]*\) (\(.*\))/* \2 - upstream\n- Update to version \1/' \
-e 's/^ -/ +/' < NEWS`" ; \
$(AWK) '{ gsub(/@VERSION''@/, "$(VERSION)") ; \
gsub(/@RELEASE''@/, "$(RELEASE)") ; \
gsub(/@CHANGELOG''@/, changelog) ; \
print }' changelog="$$changelog" $< > $@
$(patsubst %.in,%,$(wildcard bin/*.in quilt/*.in quilt/scripts/*.in)) :: Makefile
% :: %.in
@echo "$< -> $@" >&2
@$(SED) -e 's:@QUILT_DIR''@:$(datadir)/$(PACKAGE):g' \
-e 's:@PERL''@:$(PERL):g' \
-e 's:@BASH''@:$(BASH):g' \
-e 's:@PATCH''@:$(PATCH):g' \
-e 's:@STAT_HARDLINK''@:$(STAT_HARDLINK):g' \
-e 's:@VERSION''@:$(VERSION):g' \
-e 's:@ETCDIR''@:$(etcdir):g' \
-e 's:@LOCALEDIR''@:$(localedir):g' \
-e 's:@DOCSUBDIR''@:$(docdir):g' \
-e '/^### Local Variables:/Q' \
$< > $@
@$(if $(filter $@,$(NON_EXEC_IN)),,chmod +x $@)
configure : configure.ac aclocal.m4
autoconf
@echo "Please run ./configure"
@false
Makefile : Makefile.in configure
@echo "Please run ./configure"
@false
compat_leftover := $(filter-out $(COMPAT),$(shell $(FIND) compat -type f -perm -0100))
.PHONY :: compat
compat :: $(COMPAT)
$(if $(compat_leftover),rm -f $(compat_leftover))
# VIRTUAL_SYMLINKS creates a shell script that operates similar to
# a symbolic link. It is used to workaround the way make treats
# symlinks as targets.
# Usage: $(call VIRTUAL_SYMLINK, source, target)
define VIRTUAL_SYMLINK
@echo "Generating $(strip $(1)) wrapper" >&2;
@printf "#!%s\nexec %s "'"$$@"'"\n" $(BASH) $(strip $(1)) > $(2);
endef
# Rule to create compat/<binary> for each binary in $(COMPAT_SYMLINKS)
$(COMPAT_SYMLINKS:%=compat/%) :: Makefile
$(call VIRTUAL_SYMLINK, \
$($(shell echo $@ | $(AWK) '{split($$1, ar, "/"); print toupper(ar[2])}')), \
$(strip $@))
@chmod +x $(strip $@)
install-main :: scripts
$(INSTALL) -d $(BUILD_ROOT)$(bindir)
$(INSTALL) -m 755 $(BIN:%=bin/%) $(BUILD_ROOT)$(bindir)/
$(INSTALL) -d $(BUILD_ROOT)$(datadir)/$(PACKAGE)
$(INSTALL) -m 755 $(QUILT:%=quilt/%) $(BUILD_ROOT)$(datadir)/$(PACKAGE)/
$(INSTALL) -d $(BUILD_ROOT)$(datadir)/$(PACKAGE)/scripts
$(INSTALL) -m 755 $(patsubst %,quilt/scripts/%, \
$(filter-out patchfns,$(SCRIPTS))) \
$(BUILD_ROOT)$(datadir)/$(PACKAGE)/scripts
$(INSTALL) -m 644 quilt/scripts/patchfns quilt/scripts/utilfns \
$(BUILD_ROOT)$(datadir)/$(PACKAGE)/scripts
ifneq ($(PATCH_WRAPPER),)
$(INSTALL) -d $(BUILD_ROOT)$(datadir)/$(PACKAGE)/wrapper
$(INSTALL) -m 755 bin/patch-wrapper \
$(BUILD_ROOT)$(datadir)/$(PACKAGE)/wrapper/patch
endif
$(INSTALL) -d $(BUILD_ROOT)$(docdir)/
$(INSTALL) -m 644 doc/README \
$(BUILD_ROOT)$(docdir)/
$(INSTALL) -m 644 doc/quilt.pdf doc/README.MAIL \
$(BUILD_ROOT)$(docdir)/
$(INSTALL) -d $(BUILD_ROOT)$(mandir)/man1
$(INSTALL) -m 644 $(MAN1) $(BUILD_ROOT)$(mandir)/man1/
$(INSTALL) -d $(BUILD_ROOT)$(etcdir)
$(INSTALL) -d $(BUILD_ROOT)$(etcdir)/bash_completion.d
$(INSTALL) -m 644 bash_completion \
$(BUILD_ROOT)$(etcdir)/bash_completion.d/quilt
$(INSTALL) -m 644 quilt.quiltrc $(BUILD_ROOT)$(etcdir)/
$(INSTALL) -d $(BUILD_ROOT)$(emacsdir)/
$(INSTALL) -m 644 lib/quilt.el $(BUILD_ROOT)$(emacsdir)/
install-compat: install-compat1 $(COMPAT_SYMLINKS:%=install-compat-symlink-%)
install-compat-symlink-% :: install-compat1
ln -sf $($(shell echo $* | $(AWK) '{print toupper($$1)}')) \
$(BUILD_ROOT)$(datadir)/$(PACKAGE)/compat/$*
install-compat1:
rm -rf $(BUILD_ROOT)$(datadir)/$(PACKAGE)/compat
ifneq ($(COMPAT_PROGRAMS)$(COMPAT_SYMLINKS),)
$(INSTALL) -d $(BUILD_ROOT)$(datadir)/$(PACKAGE)/compat
ifneq ($(COMPAT_PROGRAMS),)
$(INSTALL) -m 755 $(COMPAT_PROGRAMS:%=compat/%) \
$(BUILD_ROOT)$(datadir)/$(PACKAGE)/compat
endif
endif
install: install-main install-compat
uninstall ::
rm -rf $(BIN:%=$(BUILD_ROOT)$(bindir)/%) \
$(BUILD_ROOT)$(datadir)/$(PACKAGE) \
$(patsubst %,$(BUILD_ROOT)$(mandir)/man1/%, \
$(notdir $(MAN1))) \
$(BUILD_ROOT)$(etcdir)/bash_completion.d/quilt \
$(BUILD_ROOT)$(etcdir)/quilt.quiltrc \
$(BUILD_ROOT)$(docdir)/ \
$(BUILD_ROOT)$(emacsdir)/quilt.el
check: $(TESTS:test/%.test=test/.%.ok)
check-all: $(TESTS:test/%.test=check-%)
check-% : test/.%.ok
@/bin/true
# Only include the test suite dependencies when required
ifneq ($(findstring test,$(MAKECMDGOALS))$(findstring check,$(MAKECMDGOALS)),)
-include test/.depend
endif # (test|check)
test/.patch-wrapper.ok : bin/patch-wrapper
# Include a run-time generated list of dependencies for each test case
test/.depend : Makefile $(TESTS)
@( printf "%s : bin/quilt quilt/scripts/patchfns quilt/scripts/utilfns quilt/scripts/backup-files $(COMPAT)\n" $(TESTS); \
$(AWK) 'sub(/.*\$$ *quilt /, "") \
{ print FILENAME, ":", "quilt/"$$1}' $(TESTS); \
$(AWK) 'sub(/.*\<quilt_command /, "") && ($$1 !~ /[^a-z]/) \
{ print FILENAME, ":", "quilt/"$$1 }' quilt/*.in; \
$(AWK) 'sub(/.*\$$ *%{QUILT_DIR}\/scripts\//, "") \
{ print FILENAME, ":", "quilt/scripts/"$$1 }' $(TESTS); \
) | sort -u | $(SED) -re 's:^test/(.*)\.test:test/.\1.ok:' \
-e 's:quilt/graph:quilt/graph quilt/scripts/dependency-graph:' \
-e 's:quilt/mail:quilt/mail quilt/scripts/edmail:' \
-e 's:quilt/refresh:quilt/refresh quilt/scripts/remove-trailing-ws:' \
-e 's:quilt/setup:quilt/setup quilt/scripts/inspect-wrapper:' \
> $@
ifneq ($(shell . $(QUILTRC) ; echo $$QUILT_PATCHES_PREFIX),)
CHECK_ENV := P=patches/; _P=../patches/; export P _P;
endif
CHECK_ENV += QUILT_PC=.pc; export QUILT_PC;
# Each tests dependencies are stored in test/.depend
ifneq ($(findstring check-,$(MAKECMDGOALS)),)
test/.%.ok : test/%.test test/run test/test.quiltrc FORCE
else
test/.%.ok : test/%.test test/run test/test.quiltrc
endif
@LANG=C; LC_ALL=C; \
export LANG LC_ALL; \
unset POSIXLY_CORRECT; \
$(CHECK_ENV) \
cd $(@D); \
./run -q $(<F)
@touch $@
clean :
rm -f $(DIRT)
distclean : clean
rm -f config.log config.status Makefile
rm -rf autom4te.cache/
ifeq ($(USE_NLS),yes)
install-main ::
for lang in $(LINGUAS) ; do \
dir=$(BUILD_ROOT)$(localedir)/$$lang/LC_MESSAGES; \
$(INSTALL) -d $$dir; \
$(INSTALL) -m 644 po/$$lang.mo \
$$dir/quilt.mo ; \
done
uninstall ::
for lang in $(LINGUAS) ; do \
dir=$(BUILD_ROOT)$(localedir)/$$lang/LC_MESSAGES; \
rm -f $$dir/quilt.mo ; \
done
endif
.PHONY :: all install uninstall clean distclean updatepo
# Clear the suffix list
.SUFFIXES:
.SUFFIXES: .c .o .in
# Bad gmake, never *ever* try to get a file out of source control by yourself.
%: %,v
%: RCS/%,v
%: RCS/%
%: s.%
%: SCCS/s.%
FORCE:

214
NEWS Normal file
View File

@ -0,0 +1,214 @@
Version 0.66 (Thu Mar 28 2019)
- Add support for lzip archives and patches (#54570)
- Document QUILT_PC as user-settable
- configure: Don't require md5sum
- Test suite: Allow keeping the working directory on failure
- Test suite: Fix regex for recent versions of perl
- Test suite: Fix /bin/sh filtering
- Test suite: Run tests again if test.quiltrc changes
- Test suite: Handle alternative QUILT_PATCHES values
- Test suite: Increase code path coverage
- Test suite: Be verbose on directory error
- Test suite: Clean up when interrupted
- Test suite: Prevent test cases from escaping
- fold: Fix German translation
- diff: Add missing quotes in basename call (#50862)
- header: Fix corruption when trailing newline is missing (#50841)
- mail: Fix patch set threading (#50775)
- mail: Fix French translation
- mail: Remove Content-Disposition headers
- mail: Complain when a patch doesn't exist
- new: Fix corruption when trailing newline is missing (#54295)
- refresh: Add missing quotes in basename call (#50862)
- setup: Add basic support for p7zip (.7z) archives (#49754)
- setup: Align --fast on --slow for series files
- quilt.el: Define quilt-edit-top-only before it's used
- quilt.el: Stop using deprecated toggle-read-only
- quilt.el: Don't strip directory in quilt-top-patch
- quilt.el: Fix emacs compatibility issue (#51977)
- quilt.el: Read QUILT_PC from config file
- quiltrc: Support all patch formats by default
- guards: Mention it in quilt manual page
- compat/getopt: Handle a second separator (#54772)
- compat/getopt: Allow non-digit parameter embedded in short option (#54772)
Version 0.65 (Wed Oct 09 2016)
- Translation fixes
- Project settings have priority
- Reject binary files in patches
- Fix a race condition in diff_file
- Performance: Optimizations to the setup command
- Performance: Optimizations to the bash completion script
- Test suite: Improve the edit test case
- Test suite: Make the symlink test more robust
- Test suite: Test backup failure
- Test suite: Test the header command with hard links
- diff: Report diff failures
- edit: Fix a corner case bug
- mail: Fix the help text
- push: Fix the synopsis
- refresh: Do not remove symlinks
- refresh: Break links to read-only patch files
- refresh: Always preserve modification time
- setup: Report failed look-ups in inspect-wrapper
- quilt.el: Fix quilt-editable when patches are stored in subdirs
- bash_completion: Handle spaces in file names
- bash_completion: Update the list of commands
- bash_completion: Add new command options
- bash_completion: Fix handling of mail, new, push options
- guards: Simplify the help text
- guards: Include the file name also in the "Not found" case
- guards: Add support for an external filelist in --check mode
- guards: Report which config file has problem in --check mode
- guards: Documentation update
- guards: Clarify a user message
Version 0.64 (Mon Feb 09 2015)
- Check for series file consistency
- Performance: Several optimizations
- Test suite: Several fixes and coverage improvements
- Test suite: Run the tests in predictable order
- files: Add support for unapplied patches
- graph: Check for graphviz availability
- mail: Remove procmail dependency
- mail: Don't include the release number in User-Agent
- pop: Add --refresh option
- push: Add --refresh option
- push: Do not use interactive mode with -f
- setup: Skip version check
- setup: Check for rpmbuild availability
- setup: Handle long options passed to tar
- setup: Several cleanups and minor fixes
- setup: Major performance optimizations
- setup: Fix path to extra patches in series file
- setup: Trace calls earlier
- setup: Add --fast option
- setup: Fix link creation
- quilt.el: Fix tramp support
- quilt.el: Fix patch select completion
Version 0.63 (Sun May 25 2014)
- New NEWS file, containing a human-readable changelog
- Option -E is no longer passed to patch by default
- Huge performance improvement (e.g., for commands series, applied and
unapplied)
- configure: Add compat symlinks for md5sum
- Return 2 when there is nothing to do, contrasting with errors (ret=1)
- Exit with an error when diff's retcode=2 (error) on patch refresh
- bash_completion: cleanups and performance improvement (Savannah's #27111)
- test/run: Use perl module Text::ParseWords (+ performance improvement)
- Add some tests to our testsuite, for a better coverage
- Fix heuristic for unapplied patches with timestamps
- Bug fix: Patches emptying files should work now
- Bug fix: Check for duplicate patch in series (Savannah's #20628)
- Portability fixes for older Bash and GNU patch
Version 0.62 (Wed May 07 2014)
- Was a buggy release, with an incomplete tarfile
Version 0.61 (Sun Dec 08 2013)
- Almost two years of fixes and minor improvements
- Fix support for ./configure --with-xargs
- Parameter quoting fixes to many commands
- Various fixes to the pop, push, refresh and patches commands
- Translation fixes
- setup: Many fixes and improvements
- remove-trailing-ws: Several fixes and improvements
- remove-trailing-ws: Add a dedicated test case
- quilt.el: Many fixes and improvements (emacs integration)
Version 0.60 (Wed Feb 29 2012)
- BSD compatibility improvements
- grep: Support file names which include spaces
- import: Fix import of relative patches
- mail: Several fixes
- setup: Support directory and archive names which include spaces
- backup-files: rewritten from C to bash
- backup-files: Add a dedicated test case
Version 0.51 (Sat Jan 28 2012)
- Fix support for ./configure --docdir
- Various $TMPDIR fixes
- mail: Fix delivery address checking
- mail: CC people in more common patch headers
- push: Fix bash completion
- inspect: Complain if wrapper script can't be executed
Version 0.50 (Mon Dec 5 2011)
- 34 months of fixes and improvements, too many to list them all
- Fix detection of the patch version
- Avoid error messages when building due to missing git-desc file
- Add support for lzma and xz compression formats
- import: Fix confusing French translation
- mail: Stop using =~ for older versions of bash
- mail: Fix a temporary directory leak
- revert: Stop using cp -l
- revert: Add bash completion support
- setup: Add --fuzz parameter
- setup: Add support for reverse patches
- inspect: Fix shell syntax errors
- Fix error in test case create-delete
Version 0.48 (Thu Jan 29 2009)
- fold: Fix bash completion
- mail: Don't use GNU awk extensions
- mail: Check for formail
- setup: Fix for rpm 4.6
- Fix error in test case import
Version 0.47 (Thu Aug 21 2008)
- Change summary not available
Version 0.46 (Thu Oct 19 2006)
- Change summary not available
Version 0.45 (Mon Apr 24 2006)
- Change summary not available
Version 0.44 (Tue Feb 14 2006)
- Change summary not available
Version 0.43 (Wed Feb 01 2006)
- Change summary not available
Version 0.42 (Tue Jul 26 2005)
- Change summary not available
Version 0.40 (Fri Apr 29 2005)
- Change summary not available
Version 0.39 (Thu Feb 10 2005)
- Change summary not available
Version 0.37 (Sun Oct 17 2004)
- Change summary not available
Version 0.36 (Wed Sep 22 2004)
- Change summary not available
Version 0.35 (Thu Jul 15 2004)
- Change summary not available
Version 0.34 (Thu Jun 10 2004)
- Change summary not available
Version 0.33 (Sun Jun 06 2004)
- Change summary not available
Version 0.32 (Sat Mar 13 2004)
- Change summary not available
Version 0.30 (Wed Jan 28 2004)
- Change summary not available
Version 0.29 (Wed Nov 12 2003)
- Change summary not available
Version 0.28 (Fri Oct 31 2003)
- Change summary not available
Version 0.27 (Tue Oct 28 2003)
- Change summary not available
Version 0.26 (Tue Oct 21 2003)
- Change summary not available

126
TODO Normal file
View File

@ -0,0 +1,126 @@
General:
- Abstract backup operations to/from the .pc/ directory, so that
optionally something like rcs can be used instead of
scripts/backup-files?
- 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.
- Support different diff/patch options for different patches.
(By specifying them in the series file?)
- Add command that generates a summary (patch names + descriptions).
- Add more long-form options, and add some nagative options so that
defaults from .quiltrc can easily be overruled.
- series.conf: Allow to specify options like -R, -u, -Unum, -c,
-Cnum per patch.
- Whenever the contents of the QUILT_PATCHES directory change,
optionally call a trigger so that another tool can keep track of
the patches directory history (e.g., CVS, RCS). Also call the
trigger when the series file changes?
- Check if we can somehow support -p0 style patches that are
applied in subdirectories (patch -d option): There are problems
with relative $QUILT_PATCHES, and likely with several commands.
- wrapper scripts: check with [ -ef ] if the wrapper is the same
as the default binary found to avoid wrappers like awk -> gawk.
- Add some more colors.
- Add the same kind of (optional) pager handling that git has.
Documentation:
- How to import a complete directory before doing wild changes?
- Describe how to work with hard-linked trees
- /etc/quilt.quiltrc and ~/.quiltrc
- diff/refresh: C -c -N -n options
- Subdirectory support
quilt new:
- Prevent spaces in patch names.
quilt push:
- Add option to print the reject to stdout
- If push fails, check if patch can be reversed.
- Add -l option to ignore whitespace changes.
- Check if there are any .orig or .rej files and barf if so.
quilt pop:
- The timestamp comparison logic is broken; need to track
last-known timestamps per file.
quilt diff:
- Error message when a file is specified that isn't in the
patch(es).
- When a directory is specified, diff all files below it.
quilt refresh:
- Add an -m option similar to `cvs commit -m "..."' to simplify
keeping a change log in the patch documentation?
- Add option to log the updates of each patch (e.g., append the
output of ``quilt diff -zR'' to patch.log on each update).
- Remove existing diffstat if --diffstat is not specified?
- Improve whitespace stripping
quilt import:
- Add option to replace the currently applied patch with a new
one, by backing out the topmost patch first.
quilt setup:
- Also recognize other uses of tar and patch (with options in the
command line), etc.
quit edit:
- Check for actual changes, and remove files again that haven't been
changed.
quilt files:
- Print filenames relative to the working directory.
quilt mail:
- Improve recipient handling (quote special characters automatically;
encode 8-bit characters).
- Character set handling is missing, too.
- Too many passes of edmail make it a bit slow.
- If someone adds a References header to the intro, the References
header added to patch messages for threading do not append to that
header. They probably should; not sure if duplicate References
headers are valid.
quilt fold:
- Add an -R option for reverse-applying a patch.

119
aclocal.m4 vendored Normal file
View File

@ -0,0 +1,119 @@
dnl Allow configure to specify a specific binary
dnl 1: Environment variable
dnl 2: binary name
dnl 3: optional list of alternative binary names
dnl 4: optional list of additional search directories
AC_DEFUN([QUILT_COMPAT_PROG_PATH],[
m4_define([internal_$2_cmd],[esyscmd(ls compat/$2.in 2>/dev/null)])
AC_ARG_WITH($2, AC_HELP_STRING(
[--with-$2], [name of the $2 executable to use]
m4_if(internal_$2_cmd,[],[],[ (use --without-$2
to use an internal mechanism)])),
[
if test x"$withval" = xnone; then
AC_MSG_ERROR([Invalid configure argument. use --without-$2])
fi
if test x"$withval" != xno; then
AC_MSG_CHECKING(for $2)
$1="$withval"
if test -e "$$1"; then
if test ! -f "$$1" -a ! -h "$$1" || test ! -x "$$1"; then
AC_MSG_ERROR([$$1 is not an executable file])
fi
fi
AC_MSG_RESULT([$$1])
if test ! -e "$$1"; then
AC_MSG_WARN([$$1 does not exist])
fi
COMPAT_SYMLINKS="$COMPAT_SYMLINKS $2"
fi
],[
m4_if([$3],[],[
AC_PATH_PROG($1,$2,,$PATH:$4)
],[
AC_PATH_PROGS($1,$3,,$PATH:$4)
if test -n "$$1" -a "`expr "$$1" : '.*/\([[^/]]*\)$'`" != "$2"; then
COMPAT_SYMLINKS="$COMPAT_SYMLINKS $2"
fi
])
m4_if([$4],[],[],[
if test -n "$$1"; then
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for dir in "$4"; do
if test "`dirname $$1`" = "$dir"; then
COMPAT_SYMLINKS="$COMPAT_SYMLINKS $2"
break
fi
done
IFS="$as_save_IFS"
fi
])
])
if test -z "$$1"; then
m4_if(internal_$2_cmd,[],[
AC_MSG_ERROR([Please specify the location of $2 with the option '--with-$2'])
],[
AC_MSG_WARN([Using internal $2 mechanism. Use option '--with-$2' to override])
COMPAT_PROGRAMS="$COMPAT_PROGRAMS $2"
$1=$2
INTERNAL_$1=1
])
fi
AC_SUBST($1)
])
dnl Allow configure to specify a specific binary
dnl This variant is for optional binaries.
dnl 1: Environment variable
dnl 2: binary name
dnl 3: optional list of alternative binary names
dnl 4: optional list of additional search directories
AC_DEFUN([QUILT_COMPAT_PROG_PATH_OPT],[
AC_ARG_WITH($2, AC_HELP_STRING(
[--with-$2], [name of the $2 executable to use]),
[
if test x"$withval" != xno; then
AC_MSG_CHECKING(for $2)
$1="$withval"
if test -e "$$1"; then
if test ! -f "$$1" -a ! -h "$$1" || test ! -x "$$1"; then
AC_MSG_ERROR([$$1 is not an executable file])
fi
fi
AC_MSG_RESULT([$$1])
if test ! -e "$$1"; then
AC_MSG_WARN([$$1 does not exist])
fi
COMPAT_SYMLINKS="$COMPAT_SYMLINKS $2"
fi
],[
m4_if([$3],[],[
AC_PATH_PROG($1,$2,,$PATH:$4)
],[
AC_PATH_PROGS($1,$3,,$PATH:$4)
if test -n "$$1" -a "`expr "$$1" : '.*/\([[^/]]*\)$'`" != "$2"; then
COMPAT_SYMLINKS="$COMPAT_SYMLINKS $2"
fi
])
m4_if([$4],[],[],[
if test -n "$$1"; then
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for dir in "$4"; do
if test "`dirname $$1`" = "$dir"; then
COMPAT_SYMLINKS="$COMPAT_SYMLINKS $2"
break
fi
done
IFS="$as_save_IFS"
fi
])
if test -z "$$1"; then
AC_MSG_WARN([$2 not found, some optional functionalities will be missing])
fi
])
if test -z "$$1"; then
$1=$2
fi
AC_SUBST($1)
])

274
bash_completion Normal file
View File

@ -0,0 +1,274 @@
#-*- mode: shell-script;-*-
# Programmed completion for bash to use quilt
# Copyright 2003-2004 Martin Quinson (martin quinson#debian org)
# This file is part of the distribution of quilt, and is distributed under
# the same licence than quilt itself
# WARNING: This script doesn't read user or system quiltrc files, and assumes
# that QUILT_PC is left unchanged. If you have changed QUILT_PC and want
# completion to work then you must set QUILT_PC in your global environment
# (for example in ~/.profile) and not just in your quiltrc file.
# Complete on files (by default) or directories (with -d)
#
_quilt_comfile()
{
local IFS=$'\t\n'
COMPREPLY=( "${COMPREPLY[@]}" $( compgen ${1:--f} -- "$cur" ) )
}
_quilt_completion()
{
local cur prev cmds command_matches
COMPREPLY=()
cur=${COMP_WORDS[COMP_CWORD]}
prev=${COMP_WORDS[COMP_CWORD-1]}
# quilt sub commands
cmds='add annotate applied delete diff edit files fold fork graph \
grep header import mail new next patches pop previous push refresh \
remove rename revert series setup snapshot top unapplied upgrade'
# if no command were given, complete on commands
if [[ $COMP_CWORD -eq 1 ]] ; then
COMPREPLY=( $( compgen -W "$cmds -h" -- $cur ) )
return 0
fi
# if we're completing for 'quilt -h', then just
# complete on any valid command
if [ ${COMP_WORDS[1]} == -h ] ; then
COMPREPLY=( $( compgen -W "$cmds" -- $cur ) )
return 0
fi
# Accept a partial command if it's unique, because quilt will accept it.
command_matches=( $(compgen -W "$cmds" -- ${COMP_WORDS[1]}) )
if [ ${#command_matches[@]} -ne 1 ] ; then
return 0
fi
# Complete depending on options
case ${command_matches[0]} in
add)
case $prev in
-P)
COMPREPLY=( $( compgen -W "$(quilt --quiltrc - applied 2>/dev/null)" -- $cur ) )
;;
*)
_quilt_comfile
COMPREPLY=( "${COMPREPLY[@]}" $( compgen -W "-P -h" -- $cur ) )
;;
esac
;;
annotate)
case $prev in
-P)
COMPREPLY=( $( compgen -W "$(quilt --quiltrc - applied 2>/dev/null)" -- $cur ) )
;;
*)
_quilt_comfile
COMPREPLY=( "${COMPREPLY[@]}" $( compgen -W "-P -h" -- $cur ) )
;;
esac
;;
applied)
COMPREPLY=( $( compgen -W "-h $(quilt --quiltrc - applied 2>/dev/null)" -- $cur ) )
;;
delete)
COMPREPLY=( $( compgen -W "-n -r -h --backup $(quilt --quiltrc - series)" -- $cur ) )
;;
diff)
case $prev in
-p)
COMPREPLY=( $( compgen -W "0 1 ab" -- $cur ) )
;;
-P|--combine)
COMPREPLY=( $( compgen -W "$(quilt --quiltrc - applied 2>/dev/null)" -- $cur ) )
;;
--diff|-U|-C)
;;
*)
_quilt_comfile
COMPREPLY=( "${COMPREPLY[@]}" $( compgen -W "-p -P -u -U -c -C -R -z -h --snapshot --diff --no-timestamps --no-index --combine --color --sort" -- $cur ) )
;;
esac
;;
edit)
_quilt_comfile
COMPREPLY=( "${COMPREPLY[@]}" $( compgen -W "-h" -- $cur ) )
;;
files)
case $prev in
--combine)
COMPREPLY=( $( compgen -W "$(quilt --quiltrc - applied 2>/dev/null)" -- $cur ) )
;;
*)
COMPREPLY=( $( compgen -W "-a -l -v -h --combine $(quilt --quiltrc - applied 2>/dev/null)" -- $cur ) )
;;
esac
;;
fold)
case $prev in
-p)
COMPREPLY=( $( compgen -W "0 1 2 3 4 5 6 7 8 9 10" -- $cur ) )
;;
*)
_quilt_comfile
COMPREPLY=( "${COMPREPLY[@]}" $( compgen -W "-R -q -f -p -h" -- $cur ) )
;;
esac
;;
graph)
case $prev in
-T)
COMPREPLY=( $( compgen -W "ps" -- $cur ) )
;;
--edge-labels)
COMPREPLY=( $( compgen -W "files" -- $cur ) )
;;
*)
COMPREPLY=( $( compgen -W "-T -h --all --reduce --lines --edge-labels $(quilt --quiltrc - applied 2>/dev/null)" -- $cur ) )
;;
esac
;;
grep)
type _longopt &> /dev/null && _longopt grep
COMPREPLY=( "${COMPREPLY[@]}" $( compgen -W "-h" -- $cur ) )
;;
header)
COMPREPLY=( $( compgen -W "-a -e -h -r --backup --strip-diffstat --strip-trailing-whitespace $(quilt --quiltrc - series)" -- $cur ) )
;;
import)
case $prev in
-p)
COMPREPLY=( $( compgen -W "0 1 2 3 4 5 6 7 8 9 10" -- $cur ) )
;;
-P)
;;
-d)
COMPREPLY=( $( compgen -W "o a n" -- $cur ) )
;;
*)
_quilt_comfile
COMPREPLY=( "${COMPREPLY[@]}" $( compgen -W "-p -R -P -f -d -h" -- $cur ) )
;;
esac
;;
mail)
case $prev in
--mbox|-M)
_quilt_comfile
;;
--signature)
_quilt_comfile
COMPREPLY=( "${COMPREPLY[@]}" - )
;;
--prefix|--sender|--from|--subject|--to|--cc|--bcc|--charset|--reply-to)
;;
*)
COMPREPLY=( $( compgen -W "-m -M --prefix --mbox --send --sender --from --subject --to --cc --bcc --charset --signature --reply-to -h" -- $cur ) )
;;
esac
;;
new)
case $prev in
-p)
COMPREPLY=( $( compgen -W "0 1 ap" -- $cur ) )
;;
*)
COMPREPLY=( $( compgen -W "-p -h" -- $cur ) )
;;
esac
;;
next|previous)
COMPREPLY=( $( compgen -W "$(quilt --quiltrc - series) -h" -- $cur ) )
;;
patches)
_quilt_comfile
COMPREPLY=( "${COMPREPLY[@]}" $( compgen -W "-v --color -h" -- $cur ) )
;;
pop)
COMPREPLY=( $( compgen -W "-a -f -R -q -v --refresh -h $(quilt --quiltrc - applied 2>/dev/null)" -- $cur ) )
;;
push)
case $prev in
--fuzz)
;;
*)
COMPREPLY=( $( compgen -W "-a -f -q -v -h --fuzz -m --merge --leave-rejects --color --refresh $(quilt --quiltrc - unapplied 2>/dev/null)" -- $cur ) )
;;
esac
;;
refresh)
case $prev in
-p)
COMPREPLY=( $( compgen -W "0 1 ap" -- $cur ) )
;;
-U|-C)
;;
*)
COMPREPLY=( $( compgen -W "-p -u -U -c -C -z -f -h $(quilt --quiltrc - applied 2>/dev/null) --no-timestamps --no-index --diffstat --sort --backup --strip-trailing-whitespace" -- $cur ) )
;;
esac
;;
remove|revert)
case $prev in
-P)
COMPREPLY=( $( compgen -W "$(quilt --quiltrc - applied 2>/dev/null)" -- $cur ) )
;;
*)
_quilt_comfile
COMPREPLY=( "${COMPREPLY[@]}" $( compgen -W "-P -h" -- $cur ) )
;;
esac
;;
rename)
case $prev in
-P)
COMPREPLY=( $( compgen -W "$(quilt --quiltrc - series)" -- $cur ) )
;;
*)
COMPREPLY=( $( compgen -W "-P -h" -- $cur ) )
;;
esac
;;
series)
COMPREPLY=( $( compgen -W "-v -h --color" -- $cur ) )
;;
setup)
case $prev in
-d|--sourcedir)
_quilt_comfile -d
;;
--fuzz)
;;
*)
_quilt_comfile
COMPREPLY=( "${COMPREPLY[@]}" $( compgen -W "-d -v -h --sourcedir --fuzz --slow --fast" -- $cur ) )
;;
esac
;;
snapshot)
COMPREPLY=( $( compgen -W "-d -h" -- $cur ) )
;;
unapplied)
COMPREPLY=( $( compgen -W "-h $(quilt --quiltrc - series)" -- $cur ) )
;;
fork|top|upgrade)
;;
esac
return 0
}
# With option "filenames", directories are shown in completion with their
# trailing / so that the user can go in them.
#
[ ${BASH_VERSINFO[0]} '>' 2 -o \
${BASH_VERSINFO[0]} = 2 -a ${BASH_VERSINFO[1]} '>' 04 ] \
&& _quilt_complete_opt="-o filenames"
complete -F _quilt_completion $_quilt_complete_opt quilt
unset -v _quilt_complete_opt

301
bin/guards.in Normal file
View File

@ -0,0 +1,301 @@
#!@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.
#
# Guards:
#
# +xxx include if xxx is defined
# -xxx exclude if xxx is defined
# +!xxx include if xxx is not defined
# -!xxx exclude if xxx is not defined
#
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);
# @<file> syntax
if ($path =~ s/^@//) {
my $fh;
open($fh, '<', $path) or die "$path: $!\n";
@files = <$fh>;
close($fh);
chomp(@files);
s:^$dir:: for @files;
return @files;
}
$path = slashme($path);
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 $line = "";
while (<$fh>) {
chomp;
s/(^|\s+)#.*//;
if (s/\\$/ /) {
$line .= $_;
next;
}
$line .= $_;
my @guards = ();
foreach my $token (split /[\s\t\n]+/, $line) {
next if $token eq "";
if ($token =~ /^[-+]/) {
push @guards, $token;
} else {
#print "[" . join(",", @guards) . "] $token\n";
&$callback($token, @guards);
}
}
$line = "";
}
}
# Command line options
#
my ($dir, $config, $default, $check, $list, $invert_match, $with_guards) =
( '', '-', 1, 0, 0, 0, 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|--list] [--invert-match]\n" .
" [--with-guards] [--config=file] symbol ...\n\n" .
" Defaults: --default=$default\n" .
" Use --path=\@<file> to read the list of entries from <file>\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,
'l|list' => \$list,
'w|with-guards' => \$with_guards,
'p|path=s' => \@path,
'D|default=i' => \$default,
'v|invert-match' => \$invert_match,
'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, $_));
}
my %files = map { $_ => 0 } @files;
parse($fh, sub {
my ($patch, @guards) = @_;
if (exists $files{$patch}) {
$files{$patch}++;
} else {
if ($config eq '-') {
print "Not found: $dir$patch\n";
} else {
print "In $config but not found: $dir$patch\n";
}
$problems++;
}});
$fh->close();
my ($file, $ref);
while (($file, $ref) = each %files) {
next if $ref == 1;
if ($ref == 0) {
if ($config eq '-') {
print "Unused: $file\n";
} else {
print "Not in $config: $file\n";
}
$problems++;
}
if ($ref > 1) {
print "Warning: multiple uses";
print " in $config" if $config ne '-';
print ": $file\n";
# This is not an error if the entries are mutually exclusive...
}
}
exit $problems ? 1 : 0;
} elsif ($list) {
parse($fh, sub {
my ($patch, @guards) = @_;
print join(' ', @guards), ' '
if (@guards && $with_guards);
print "$dir$patch\n";
});
} 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 ^ $invert_match;
});
$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<dir1:dir2:...>] [--default=<0|1>]
[--check|--list] [--invert-match] [--with-guards] [--config=<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 configuration 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 separated by a colon (C<:>) character. The
I<--prefix> option specifies the location of the files. Alternatively, the
I<--path=@E<lt>fileE<gt>> syntax can be used to specify a file from which the
file names will be read.
Use I<--list> to list all files independent of any rules. Use I<--invert-match>
to list only the excluded patches. Use I<--with-guards> to also include all
inclusion and exclusion rules.
=head1 AUTHOR
Andreas Gruenbacher <agruen@suse.de>, SUSE Labs

265
bin/patch-wrapper.in Executable file
View File

@ -0,0 +1,265 @@
#! @BASH@
# This is a wrapper to GNU patch that recognizes the most common
# options and mimics GNU patch's behavior and output, and creates the
# quilt metadata as if quilt push was used to apply the patches. When
# options are used that this wrapper does not recognize, GNU patch is
# used directly, and no quilt metadata will get created.
PATCH=@PATCH@
original_options=("$@")
# GNU patch recognizes these environment variables
if [ -n "$SIMPLE_BACKUP_SUFFIX" ]
then
set -- --suffix "$SIMPLE_BACKUP_SUFFIX" "$@"
fi
if [ -n "$PATCH_VERSION_CONTROL" ]
then
set -- --version-control "$PATCH_VERSION_CONTROL" "$@"
elif [ -n "$VERSION_CONTROL" ]
then
set -- --version-control "$VERSION_CONTROL" "$@"
fi
if [ -n "$POSIXLY_CORRECT" ]
then
set -- --posix "$@"
fi
backup_files()
{
declare dir=${QUILT_PC:-.pc}/$name
if [ "$backup_mode" = --backup-if-mismatch ]
then
awk '
/^patching file / \
{ file=$0
sub(/^patching file /, "", file)
}
/^Hunk #[0-9]* / \
{ if (!(file in backup)) {
backup[file] = 1
#print "ln -f "dir"/"file" "prefix file suffix > "/dev/stderr"
system("ln -f "dir"/"file" "prefix file suffix)
}
}
{ if (!silent)
print
}
' dir="${dir//\\/\\\\}" \
prefix="${opt_prefix//\\/\\\\}" \
suffix="${opt_suffix//\\/\\\\}" \
silent="${opt_silent:+1}"
elif [ -n "$opt_silent" ]; then
cat > /dev/null
fi
if [ "$backup_mode" = --backup -a -d "$dir" ]
then
for file in $(find "$dir" -type f -a ! -path "$path/.timestamp")
do
dest=$opt_prefix${file#$dir/}$opt_suffix
mkdir -p $(dirname "$dest")
ln -f $file $dest
done
fi
}
find_pipe_patch()
{
declare patch=$1
patch=${patch//\[/\\[}
patch=${patch//\]/\\]}
set -- $(stat -c $'%a %N\n' /proc/*/fd/* 2>/dev/null \
| sed -nre "s,^300 \`(/proc/.*/fd)/.*' -> \`$patch'$,\\1,p")
set -- $(stat -c $'%a %N\n' $1/* 2>/dev/null \
| sed -nre "s,^500 \`.*' -> \`(.*)',\\1,p")
[ $# -eq 1 ] || set -- "$patch"
echo "$1"
}
options=`getopt -q -o bsB:z:i:p:d: \
--long quiet,silent,backup,backup-if-mismatch \
--long no-backup-if-mismatch,prefix: \
--long suffix:,posix,input:,strip:,directory: -- "$@"`
if [ $? -ne 0 ]
then
cannot_handle=1
else
case "${LC_ALL:-${LC_MESSAGES:-${LANG}}}" in
''|C|POSIX|en*)
;;
*) cannot_handle=1
;;
esac
fi
if [ -z "$cannot_handle" ]; then
eval set -- "$options"
backup_mode=--backup-if-mismatch
opt_prefix=
opt_suffix=
opt_silent=
opt_input=
opt_strip=
opt_directory=$PWD
while :
do
case "$1" in
-b|--backup)
backup_mode=--backup
;;
--backup-if-mismatch)
backup_mode=--backup-if-mismatch
;;
-d|--directory)
cd "$2" || exit 1
shift
;;
-i|--input)
opt_input=$2
new_options[${#new_options[@]}]=$1
new_options[${#new_options[@]}]=$2
shift
;;
--no-backup-if-mismatch)
backup_mode=--no-backup-if-mismatch
;;
-B|--prefix)
opt_prefix=$2
new_options[${#new_options[@]}]=$1
new_options[${#new_options[@]}]=$2
shift
;;
-s|--silent|--quiet)
opt_silent=--silent
;;
-p|--strip)
opt_strip=-p$2
new_options[${#new_options[@]}]=-p$2
shift
;;
-z|--suffix)
opt_suffix=$2
new_options[${#new_options[@]}]=$1
new_options[${#new_options[@]}]=$2
shift
;;
--posix)
backup_mode=--no-backup-if-mismatch
new_options[${#new_options[@]}]=$1
;;
--)
shift
break
;;
*)
new_options[${#new_options[@]}]=$1
;;
esac
shift
done
[ -n "$opt_prefix$opt_suffix" ] || opt_suffix=.orig
if [ -z "$opt_strip" -o $# -ne 0 ]
then
cannot_handle=1
fi
fi
if [ -z "$cannot_handle" ]
then
if [ -n "$opt_input" ]
then
patch=$opt_input
elif [ ! -e /proc/self ]
then
echo "patch-wrapper: /proc not mounted!" >&2
exit 1
elif [ -e /proc/self/fd/0 ]
then
patch=$(readlink /proc/self/fd/0)
case "$patch" in
pipe:*)
patch=$(find_pipe_patch "$patch")
;;
esac
fi
patch=${patch#$PWD/}
if [ ! -e "$patch" ]
then
cannot_handle=1
fi
fi
if [ -n "$cannot_handle" ]
then
$PATCH "${original_options[@]}"
exit
fi
quilt_patches=${QUILT_PATCHES:-patches}
if [ "${patch#$RPM_SOURCE_DIR}" != "$patch" ]
then
name=SOURCES/${patch#$RPM_SOURCE_DIR/}
if [ ! -e "$quilt_patches/SOURCES" ]
then
mkdir -p "$quilt_patches"
ln -s $RPM_SOURCE_DIR "$quilt_patches/SOURCES"
fi
elif [ "${patch#$RPM_BUILD_DIR}" != "$patch" ]
then
name=BUILD/${patch#$RPM_BUILD_DIR/}
if [ ! -e "$quilt_patches/BUILD" ]
then
mkdir -p "$quilt_patches"
ln -s $RPM_BUILD_DIR "$quilt_patches/BUILD"
fi
else
name=${patch#/}
dir=$(dirname "$quilt_patches/$name")
mkdir -p "$dir"
if [ "${patch:0:1}" = / ]
then
ln -s "$patch" "$quilt_patches/${name#/}"
else
while ! [ "$dir/$updir$name" -ef "$patch" ]
do
updir=$updir../
[ ${#updir} -gt 96 ] && break
done
if [ "$dir/$updir$name" -ef "$patch" ]
then
ln -s "$updir$patch" "$quilt_patches/$name"
fi
fi
fi
if [ "$opt_strip" = -p1 ]; then
echo "$name"
else
echo "$name $opt_strip"
fi >> $quilt_patches/series
$PATCH "${new_options[@]}" --backup --prefix "${QUILT_PC:-.pc}/$name/" \
| backup_files
status=${PIPESTATUS[0]}
if [ $status -eq 0 ]
then
dir=${QUILT_PC:-.pc}/$name
if [ ! -e "$dir" ]
then
mkdir -p "$dir"
fi
echo -n "" > $dir/.timestamp
if [ ! -e ${QUILT_PC:-.pc}/.version ]
then
echo 2 > ${QUILT_PC:-.pc}/.version
fi
echo "$name" >> "${QUILT_PC:-.pc}/applied-patches"
fi
exit $status

157
bin/quilt.in Normal file
View File

@ -0,0 +1,157 @@
#! @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.
# unset posix strict conformance variable since patch cannot be run
# non-interactively when it's set.
unset POSIXLY_CORRECT
# unset GREP_OPTIONS as it's quite easy to break quilt with uncommon options
# see http://bugs.debian.org/715563
unset GREP_OPTIONS
export TEXTDOMAIN=quilt
export TEXTDOMAINDIR=@LOCALEDIR@
: ${QUILT_DIR=@QUILT_DIR@}
export QUILT_DIR
if [ -z "$QUILTRC" ]
then
for QUILTRC in $HOME/.quiltrc @ETCDIR@/quilt.quiltrc; do
[ -e $QUILTRC ] && break
done
export QUILTRC
fi
# Support compatibility layer
if [ -d $QUILT_DIR/compat ]
then
export PATH="$QUILT_DIR/compat:$PATH"
fi
usage()
{
echo $"Usage: quilt [--trace[=verbose]] [--quiltrc=XX] command [-h] ..."
echo $" quilt --version"
echo $"Commands are:"
quilt_commands \
| sort \
| column | column -t \
| sed -e $'s/^/\t/'
printf $"
Global options:
--trace
Runs the command in bash trace mode (-x). For internal debugging.
--quiltrc file
Use the specified configuration file instead of ~/.quiltrc (or
%s/quilt.quiltrc if ~/.quiltrc does not exist). See the pdf
documentation for details about its possible contents. The
special value \"-\" causes quilt not to read any configuration
file.
--version
Print the version number and exit immediately.\n" "@ETCDIR@"
exit 1
}
quilt_commands()
{
local command
for command in $QUILT_DIR/*
do
if [ -f "$command" -a -x "$command" ]
then
echo ${command##$QUILT_DIR/}
fi
done
}
if [ $# -eq 1 -a "$1" == "--version" ]
then
echo '@VERSION@'
exit
fi
BASH_OPTS=
while [ $# -ne 0 ]
do
case $1 in
[^-]*)
if [ -z "$command" ]
then
command=$1
else
args[${#args[@]}]=$1
fi ;;
# Use a resource file other than ~/.quiltrc
--quiltrc=*)
QUILTRC=${1#--quiltrc=}
[ "$QUILTRC" = - ] && unset QUILTRC ;;
--quiltrc)
QUILTRC=$2
[ "$QUILTRC" = - ] && unset QUILTRC
shift ;;
# Trace execution of commands
--trace*)
BASH_OPTS="${BASH_OPTS:+$BASH_OPTS }-x"
case "${1:7}" in
'')
;;
=verbose)
BASH_OPTS="${BASH_OPTS:+$BASH_OPTS }-v" ;;
*)
command=
break ;;
esac ;;
*)
args[${#args[@]}]=$1 ;;
esac
shift
done
if ! [ -f "$QUILT_DIR/$command" -a -x "$QUILT_DIR/$command" ]
then
if [ -n "$command" ]
then
for arg in $(quilt_commands)
do
case "$arg" in
$command*)
commands[${#commands[@]}]=$arg
;;
esac
done
unset arg
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 args
export QUILT_COMMAND="${command##*/}"
bash $BASH_OPTS -c ". $QUILT_DIR/$command" "quilt ${command##*/}" "$@"
### Local Variables:
### mode: shell-script
### End:
# vim:filetype=sh

3
compat/column.in Normal file
View File

@ -0,0 +1,3 @@
#! @BASH@
cat

59
compat/date.in Normal file
View File

@ -0,0 +1,59 @@
#! @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 strict;
use POSIX qw(strftime);
use Getopt::Long qw(:config gnu_getopt prefix_pattern=(--|-));
use Date::Parse;
my $spec = '%a %b %e %H:%M:%S %Z %Y';
my $now = time();
my $utc = 0;
sub usage() {
print "Usage: date [OPTION]... [+FORMAT]
Display the current time in the given FORMAT.
-d, --date=STRING display time described by STRING, not `now'
-f, --file=DATEFILE like --date once for each line of DATEFILE
-R, --rfc-822 output RFC-822 compliant date string
-u, --utc, --universal print or set Coordinated Universal Time
--help display this help and exit
";
exit 1;
}
sub parse_utc_secs($) {
my ($now) = @_;
if ($now =~ / UTC ([0-9]+) seconds$/) {
# This is an heuristic specifically for quilts mail.in invocation:
# date --rfc-822 -d "1970/01/01 UTC nnnnnnnn seconds"
return $1;
}
else {
return str2time($now);
}
}
GetOptions('rfc-822|R' => sub() { $spec = '%a, %d %b %Y %H:%M:%S %z' },
'utc|universal|u' => \$utc,
'date|d=s' => sub() { $now = parse_utc_secs($_[1]) },
'reference|r=s' => sub() { my @filestats = stat($_[1]); $now = parse_utc_secs('1970/01/01 UTC ' . $filestats[9] . ' seconds') },
'help|h' => sub() { usage })
or usage;
if (@ARGV == 1 && $ARGV[0] =~ /^\+/) {
$spec = substr($ARGV[0], 1);
} elsif (@ARGV > 1) {
usage;
}
my @now = $utc ? gmtime($now) : localtime($now);
print strftime($spec, @now) . "\n";

136
compat/getopt.in Normal file
View File

@ -0,0 +1,136 @@
#! @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 strict;
my $opts = '';
my @words;
my $found_sep = 0;
foreach my $arg (@ARGV) {
if (!$found_sep && $arg eq '--') {
$found_sep = 1;
}
else {
if (!$found_sep) {
$opts .= ' ' . $arg;
}
else {
push @words, $arg;
}
}
}
# there is no reason to parse
# the opts if there are no args.
if (!@words) {
print " --\n";
exit;
}
my $short_opts = '';
my @long_opts;
# nothing fancy to see here; this script provides minimal compatibility
# with the getopt from util-linux until a cross platform binary exists.
# We silently ignore option -q.
if ($opts =~ /^\s*(?:-q\s+)?-o ([a-zA-Z:]*)?(\s+--long .*)*/) {
$short_opts = $1;
if ($2) {
my $long_opts = $2;
$long_opts =~ s/^\s*--long //g;
$long_opts =~ s/ --long /,/g;
@long_opts = split(/,/,$long_opts);
}
}
my @barewords = ('--');
my @options;
# set the previous option name when a param is required
my $need_param;
sub quote_word
{
my $word = shift;
$word =~ s/'/'\\''/;
return "'$word'";
}
# there can be a second separator, to inhibit processing following arguments
# as options
$found_sep = 0;
foreach my $word (@words) {
if ($word eq '--') {
$found_sep = 1;
next;
}
# allow '-' to be an option value
if ($found_sep || (!$need_param && $word !~ /^-./)) {
push @barewords, quote_word($word);
next;
}
if ($need_param) {
die "expecting param for $need_param" if $word =~ /^-./;
push @options, quote_word($word);
$need_param = undef;
next;
}
# process short options
if ($word =~ s/^-([^-])/$1/) {
my @letters = reverse(split(//,$word));
while (@letters) {
my $letter = pop @letters;
my $found = grep(/$letter/, $short_opts);
push @options, '-'.$letter;
die "illegal option: $letter" if !$found;
# handle options with optional parameters
if (grep(/${letter}::/, $short_opts)) {
if (scalar(@letters) == 0) {
push @options, quote_word('');
} else {
# what looked like more short options
# are in fact the optional parameters
push @options, quote_word(join('', reverse @letters));
}
last;
}
# handle options with mandatory parameters
if (grep(/$letter:/, $short_opts)) {
if (scalar(@letters) == 0) {
$need_param = $letter;
} else {
# short options can have args
# embedded in the short option list
push @options, quote_word(join('', reverse @letters));
@letters = ();
}
}
}
}
# process long options
if ($word =~ s/^--//) {
my $param = '';
if ($word =~ /(.*)=(.*)/) {
$word = $1;
$param = $2;
}
my ($found) = grep(/^$word:{0,2}$/,@long_opts);
die "illegal option: $word" if !$found;
die "$word: unexpected paramater $param" if $found !~ /:$/ && $param ne '';
$need_param = $word if $found =~ /[^:]:$/ && $param eq '';
push @options, "--$word";
push @options, quote_word($param) if $param || $found =~ /::$/;
}
}
print " @options @barewords\n"

27
compat/mktemp.in Normal file
View File

@ -0,0 +1,27 @@
#! @BASH@
if [ x"$1" = x"-d" ]
then
for ((n=0 ; $n<100 ; n++))
do
try=${2%XXXXXX}$RANDOM
mkdir -m 700 "$try" 2>/dev/null && break
done
else
user_mask=$(umask)
umask 077
set -o noclobber
for ((n=0 ; $n<100 ; n++))
do
try=${1%XXXXXX}$RANDOM
echo -n "" 2> /dev/null > "$try" && break
done
set +o noclobber
umask $user_mask
fi
if [ $n -lt 100 ]
then
echo "$try"
else
exit 1
fi

4
compat/sendmail.in Normal file
View File

@ -0,0 +1,4 @@
#! @BASH@
echo "No mail transfer agent configured for \`quilt mail'" >&2
exit 1

276
config/install-sh Normal file
View File

@ -0,0 +1,276 @@
#!/bin/sh
#
# install - install a program, script, or datafile
# This comes from X11R5 (mit/util/scripts/install.sh).
#
# Copyright 1991 by the Massachusetts Institute of Technology
#
# Permission to use, copy, modify, distribute, and sell this software and its
# documentation for any purpose is hereby granted without fee, provided that
# the above copyright notice appear in all copies and that both that
# copyright notice and this permission notice appear in supporting
# documentation, and that the name of M.I.T. not be used in advertising or
# publicity pertaining to distribution of the software without specific,
# written prior permission. M.I.T. makes no representations about the
# suitability of this software for any purpose. It is provided "as is"
# without express or implied warranty.
#
# Calling this script install-sh is preferred over install.sh, to prevent
# `make' implicit rules from creating a file called install from it
# when there is no Makefile.
#
# This script is compatible with the BSD install script, but was written
# from scratch. It can only install one file at a time, a restriction
# shared with many OS's install programs.
# set DOITPROG to echo to test this script
# Don't use :- since 4.3BSD and earlier shells don't like it.
doit="${DOITPROG-}"
# put in absolute paths if you don't have them in your path; or use env. vars.
mvprog="${MVPROG-mv}"
cpprog="${CPPROG-cp}"
chmodprog="${CHMODPROG-chmod}"
chownprog="${CHOWNPROG-chown}"
chgrpprog="${CHGRPPROG-chgrp}"
stripprog="${STRIPPROG-strip}"
rmprog="${RMPROG-rm}"
mkdirprog="${MKDIRPROG-mkdir}"
transformbasename=""
transform_arg=""
instcmd="$mvprog"
chmodcmd="$chmodprog 0755"
chowncmd=""
chgrpcmd=""
stripcmd=""
rmcmd="$rmprog -f"
mvcmd="$mvprog"
src=""
dst=""
dir_arg=""
while [ x"$1" != x ]; do
case $1 in
-c) instcmd=$cpprog
shift
continue;;
-d) dir_arg=true
shift
continue;;
-m) chmodcmd="$chmodprog $2"
shift
shift
continue;;
-o) chowncmd="$chownprog $2"
shift
shift
continue;;
-g) chgrpcmd="$chgrpprog $2"
shift
shift
continue;;
-s) stripcmd=$stripprog
shift
continue;;
-t=*) transformarg=`echo $1 | sed 's/-t=//'`
shift
continue;;
-b=*) transformbasename=`echo $1 | sed 's/-b=//'`
shift
continue;;
*) if [ x"$src" = x ]
then
src=$1
else
# this colon is to work around a 386BSD /bin/sh bug
:
dst=$1
fi
shift
continue;;
esac
done
if [ x"$src" = x ]
then
echo "$0: no input file specified" >&2
exit 1
else
:
fi
if [ x"$dir_arg" != x ]; then
dst=$src
src=""
if [ -d "$dst" ]; then
instcmd=:
chmodcmd=""
else
instcmd=$mkdirprog
fi
else
# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
# might cause directories to be created, which would be especially bad
# if $src (and thus $dsttmp) contains '*'.
if [ -f "$src" ] || [ -d "$src" ]
then
:
else
echo "$0: $src does not exist" >&2
exit 1
fi
if [ x"$dst" = x ]
then
echo "$0: no destination specified" >&2
exit 1
else
:
fi
# If destination is a directory, append the input filename; if your system
# does not like double slashes in filenames, you may need to add some logic
if [ -d "$dst" ]
then
dst=$dst/`basename "$src"`
else
:
fi
fi
## this sed command emulates the dirname command
dstdir=`echo "$dst" | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
# Make sure that the destination directory exists.
# this part is taken from Noah Friedman's mkinstalldirs script
# Skip lots of stat calls in the usual case.
if [ ! -d "$dstdir" ]; then
defaultIFS='
'
IFS="${IFS-$defaultIFS}"
oIFS=$IFS
# Some sh's can't handle IFS=/ for some reason.
IFS='%'
set - `echo "$dstdir" | sed -e 's@/@%@g' -e 's@^%@/@'`
IFS=$oIFS
pathcomp=''
while [ $# -ne 0 ] ; do
pathcomp=$pathcomp$1
shift
if [ ! -d "$pathcomp" ] ;
then
$mkdirprog "$pathcomp"
else
:
fi
pathcomp=$pathcomp/
done
fi
if [ x"$dir_arg" != x ]
then
$doit $instcmd "$dst" &&
if [ x"$chowncmd" != x ]; then $doit $chowncmd "$dst"; else : ; fi &&
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd "$dst"; else : ; fi &&
if [ x"$stripcmd" != x ]; then $doit $stripcmd "$dst"; else : ; fi &&
if [ x"$chmodcmd" != x ]; then $doit $chmodcmd "$dst"; else : ; fi
else
# If we're going to rename the final executable, determine the name now.
if [ x"$transformarg" = x ]
then
dstfile=`basename "$dst"`
else
dstfile=`basename "$dst" $transformbasename |
sed $transformarg`$transformbasename
fi
# don't allow the sed command to completely eliminate the filename
if [ x"$dstfile" = x ]
then
dstfile=`basename "$dst"`
else
:
fi
# Make a couple of temp file names in the proper directory.
dsttmp=$dstdir/#inst.$$#
rmtmp=$dstdir/#rm.$$#
# Trap to clean up temp files at exit.
trap 'status=$?; rm -f "$dsttmp" "$rmtmp" && exit $status' 0
trap '(exit $?); exit' 1 2 13 15
# Move or copy the file name to the temp name
$doit $instcmd "$src" "$dsttmp" &&
# and set any options; do chmod last to preserve setuid bits
# If any of these fail, we abort the whole thing. If we want to
# ignore errors from any of these, just make sure not to ignore
# errors from the above "$doit $instcmd $src $dsttmp" command.
if [ x"$chowncmd" != x ]; then $doit $chowncmd "$dsttmp"; else :;fi &&
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd "$dsttmp"; else :;fi &&
if [ x"$stripcmd" != x ]; then $doit $stripcmd "$dsttmp"; else :;fi &&
if [ x"$chmodcmd" != x ]; then $doit $chmodcmd "$dsttmp"; else :;fi &&
# Now remove or move aside any old file at destination location. We try this
# two ways since rm can't unlink itself on some systems and the destination
# file might be busy for other reasons. In this case, the final cleanup
# might fail but the new file should still install successfully.
{
if [ -f "$dstdir/$dstfile" ]
then
$doit $rmcmd -f "$dstdir/$dstfile" 2>/dev/null ||
$doit $mvcmd -f "$dstdir/$dstfile" "$rmtmp" 2>/dev/null ||
{
echo "$0: cannot unlink or rename $dstdir/$dstfile" >&2
(exit 1); exit
}
else
:
fi
} &&
# Now rename the file to the real destination.
$doit $mvcmd "$dsttmp" "$dstdir/$dstfile"
fi &&
# The final little trick to "correctly" pass the exit status to the exit trap.
{
(exit 0); exit
}

5712
configure vendored Executable file

File diff suppressed because it is too large Load Diff

429
configure.ac Normal file
View File

@ -0,0 +1,429 @@
dnl Process this file with autoconf to produce a configure script.
AC_INIT([quilt],[0.66],[quilt-dev@nongnu.org])
AC_CONFIG_AUX_DIR(config)
AC_PREREQ(2.53)
PACKAGE_RELEASE=1
AC_SUBST(PACKAGE_RELEASE)
AC_SUBST(PACKAGE_TARNAME)
AC_PROG_INSTALL
AC_SYS_INTERPRETER
if test "$interpval" != yes ; then
AC_MSG_WARN([no
bash/perl scripts may not be invoked correctly due to problems with your
systems implementation of #! being either broken or non-existant.
])
fi
dnl Check for Bourne-Again Shell
unset BASH # bash sets this itself!
QUILT_COMPAT_PROG_PATH(BASH, bash)
# It would be nice not to have to use backticks, but too many retarded sh
# implementations still don't support $( )
# BEWARE: There is a distinct possibility that we are currently running under
# bash in this configure script (/bin/sh being a symlink to /bin/bash). Even
# though the result /could/ be available to us directly as $BASH_VERSION we
# don't want to use, or trust it, incase the user is specifying a different
# bash executable.
if `$BASH -c '[[ "$BASH_VERSION" \< "3.0" ]]'` ; then
AC_MSG_ERROR([
$PACKAGE_NAME requires at least version 3.0 of bash, you can download a current
version of bash from ftp.gnu.org
])
fi
AC_MSG_CHECKING(whether $BASH quoting works)
if test `$BASH -c "echo \"\\\$(set -- \\\$'a b'; echo \\\$#)\"" 2>/dev/null` = "1"; then
AC_MSG_RESULT(yes)
else
AC_MSG_RESULT(no)
AC_MSG_ERROR([
You have a version of `bash' which suffers from a quoting bug.
This is a known bug of bash 3.1, which was fixed by patch bash31-011.
You can get this patch at ftp://ftp.gnu.org/gnu/bash/
])
fi
QUILT_COMPAT_PROG_PATH(CP, cp, [gcp cp])
QUILT_COMPAT_PROG_PATH(DATE, date, [gdate date])
if test -z "$INTERNAL_DATE"; then
AC_MSG_CHECKING([whether $DATE --rfc-822 works])
if $DATE --rfc-822 >/dev/null 2>/dev/null; then
AC_MSG_RESULT(yes)
else
AC_MSG_ERROR([no
If you don't have a version of `date' that supports --rfc-822, you
can specify '--without-date' and $PACKAGE_NAME will use its own
internal date.
])
fi
fi
QUILT_COMPAT_PROG_PATH(PERL, perl, [perl perl5])
QUILT_COMPAT_PROG_PATH(GREP, grep)
AC_MSG_CHECKING([whether $GREP -q works])
if echo first | $GREP -q first 2>/dev/null; then
AC_MSG_RESULT(yes)
else
AC_MSG_RESULT(no)
AC_MSG_ERROR([
Sorry, you have a version of grep which doesn't understand -q.
$PACKAGE_NAME needs it. If you have access to a version of grep which does
understand -q, you can supply its path with the '--with-grep=' option.
])
fi
AC_MSG_CHECKING([whether $GREP understands (foo|bar)])
if echo first | $GREP '^\(fir\|las\)' >/dev/null 2>&1; then
AC_MSG_RESULT(yes)
else
AC_MSG_RESULT(no)
AC_MSG_ERROR([
Sorry, you have a version of grep which doesn't understand constructs
of the form (foo|bar). $PACKAGE_NAME needs it. If you have access to
a version of grep which does understand such constructs, you can supply
its path with the '--with-grep=' option.
])
fi
QUILT_COMPAT_PROG_PATH(TAIL, tail)
# Solaris' /usr/bin/tail doesn't understand -n.
AC_MSG_CHECKING([whether $TAIL -n works])
if test "`(echo first; echo second) | $TAIL -n 1 2>/dev/null`" = "second"; then
AC_MSG_RESULT(yes)
else
AC_MSG_RESULT(no)
AC_MSG_ERROR([
Sorry, you have a version of tail which doesn't understand -n.
$PACKAGE_NAME needs it. If you have access to a version of tail which does
understand -n, you can supply its path with the '--with-tail=' option.
Solaris users can use /usr/xpg4/bin/tail.
])
fi
QUILT_COMPAT_PROG_PATH(TR, tr)
AC_MSG_CHECKING([whether $TR understands a-z ])
if test "`echo first | $TR a-z A-Z 2>/dev/null`" = "FIRST"; then
AC_MSG_RESULT(yes)
else
AC_MSG_RESULT(no)
AC_MSG_ERROR([
Sorry, you have a version of tr which doesn't understand constructs
of the form a-z. $PACKAGE_NAME needs it. If you have access to
a version of tr which does understand such constructs, you can supply
its path with the '--with-tr=' option.
Solaris users can use /usr/xpg4/bin/tr.
])
fi
QUILT_COMPAT_PROG_PATH(STAT, stat)
AC_MSG_CHECKING([whether $STAT -c '%h' works])
if $STAT -c '%h' /dev/null >/dev/null 2>/dev/null; then
AC_MSG_RESULT(yes)
STAT_HARDLINK="-c '%h'"
else
AC_MSG_RESULT(no)
AC_MSG_CHECKING([whether $STAT -f '%l' works])
if $STAT -f '%l' /dev/null >/dev/null 2>/dev/null; then
AC_MSG_RESULT(yes)
STAT_HARDLINK="-f '%l'"
else
AC_MSG_RESULT(no)
AC_MSG_ERROR([
Sorry, you have a version of stat which understands neither -c nor -f.
$PACKAGE_NAME needs it. If you have access to a version of stat which does
understand -c or -f, you can supply its path with the '--with-stat=' option.
])
fi
fi
AC_SUBST(STAT_HARDLINK)
QUILT_COMPAT_PROG_PATH(SED, sed)
AC_MSG_CHECKING([whether $SED understands (foo|bar)])
if test "`echo first | $SED -e 's/\(fir\|lo\)/la/' 2>/dev/null`" = "last"; then
AC_MSG_RESULT(yes)
else
AC_MSG_RESULT(no)
AC_MSG_ERROR([
Sorry, you have a version of sed which doesn't understand constructs
of the form (foo|bar). $PACKAGE_NAME needs it. If you have access to
a version of sed which does understand such constructs, you can supply
its path with the '--with-sed=' option.
])
fi
QUILT_COMPAT_PROG_PATH(AWK, awk, [gawk awk])
AC_MSG_CHECKING([whether $AWK supports sub])
if test "`echo first | $AWK 'sub(/first/, "last")' 2>/dev/null`" = "last"; then
AC_MSG_RESULT(yes)
else
AC_MSG_RESULT(no)
AC_MSG_ERROR([
Sorry, you have a version of awk which doesn't understand sub( ).
$PACKAGE_NAME needs it. If you have access to a version of awk
which does understand such constructs, you can supply its path
with the '--with-awk=' option.
Solaris users can use /usr/xpg4/bin/awk.
])
fi
AC_ARG_WITH(pod2man, AC_HELP_STRING(
[--with-pod2man],
[name of the pod2man executable to use (use --without-pod2man to disable)]),
[
if test x"$withval" = xno; then
POD2MAN=
else
POD2MAN=$withval
fi],[
AC_PATH_PROG(POD2MAN, pod2man)
]
)
AC_SUBST(POD2MAN)
QUILT_COMPAT_PROG_PATH(COLUMN, column)
QUILT_COMPAT_PROG_PATH(GETOPT, getopt)
if test -z "$INTERNAL_GETOPT"; then
AC_MSG_CHECKING(for getopt --long syntax)
dnl check GNU syntax
$GETOPT -o t --long test -- --test | grep 'illegal option' >/dev/null
getopt_long_errors=$?
$GETOPT -o t --long test -- --test | grep '^ *--test *--' >/dev/null
getopt_long_works=$?
if test $getopt_long_errors -eq 1 -a $getopt_long_works -eq 0; then
AC_MSG_RESULT(yes)
else
AC_MSG_RESULT(no)
AC_MSG_ERROR([
$GETOPT does not support the --long option.
If you don't have a version of getopt that supports long options, you
can specify '--without-getopt' and $PACKAGE_NAME will use its own
internal getopt.
])
fi
fi
QUILT_COMPAT_PROG_PATH(MKTEMP, mktemp)
if test -z "$INTERNAL_MKTEMP" ; then
AC_MSG_CHECKING(whether $MKTEMP -d works)
if tempdir=`$MKTEMP -d ${TMPDIR:-/tmp}/$PACKAGE_NAME.XXXXXX 2>/dev/null` && \
rmdir "$tempdir" ; then
AC_MSG_RESULT(yes)
else
AC_MSG_RESULT(no)
AC_MSG_ERROR([
'$MKTEMP -d' does not create temporary directories.
If you don't have a version of mktemp that can create directories, you
can specify '--without-mktemp' and $PACKAGE_NAME will use its own
internal tempfile generation mechanism.
])
fi
fi
QUILT_COMPAT_PROG_PATH(DIFF, diff)
QUILT_COMPAT_PROG_PATH(PATCH, patch)
# Sun diff and others will not work because GNU patch options are used.
AC_MSG_CHECKING([the version of $DIFF])
if $DIFF --version 2>/dev/null | grep GNU >/dev/null; then
set -- `$DIFF --version 2>/dev/null | $AWK '{ print $NF; exit }'`
diff_version=$1
AC_MSG_RESULT($diff_version)
saved_IFS=$IFS; IFS='.'
set -- $diff_version
IFS=$saved_IFS
set -- `echo $1 | $TR -cd 0-9` `echo $2 | $TR -cd 0-9`
if test 0$1 -lt 2 || test 0$1 -eq 2 -a 0$2 -lt 7 ; then
diff_version=
fi
else
AC_MSG_RESULT(no GNU diff)
fi
if test -z "$diff_version" ; then
AC_MSG_ERROR([
$PACKAGE_NAME requires at least version 2.7 of GNU diffutils. You can
download a current version of patch from ftp.gnu.org, or if you already
have GNU diff then you can supply its path with the '--with-diff=' option.
])
fi
# Sun's patch, and others, do not work because GNU patch options are used.
AC_MSG_CHECKING([the version of $PATCH])
if $PATCH --version 2> /dev/null | grep GNU >/dev/null; then
set -- `$PATCH --version 2> /dev/null`
if test x$1 = xGNU ; then
patch_version=$3
else
patch_version=$2
fi
AC_MSG_RESULT($patch_version)
saved_IFS=$IFS; IFS='.'
set -- $patch_version
IFS=$saved_IFS
set -- `echo $1 | $TR -cd 0-9` `echo $2 | $TR -cd 0-9`
if test 0$1 -lt 2 || test 0$1 -eq 2 -a 0$2 -lt 5 ; then
patch_version=
fi
else
AC_MSG_RESULT(no GNU patch)
fi
if test -z "$patch_version" ; then
AC_MSG_ERROR([
$PACKAGE_NAME requires at least version 2.5 of GNU patch. You can download a
current version of patch from ftp.gnu.org, or if you already have GNU patch
then you can supply its path with the '--with-patch=' option.
])
fi
QUILT_COMPAT_PROG_PATH(FIND, find)
AC_MSG_CHECKING([whether $FIND -path works])
if $FIND . -path '*' >/dev/null 2>&1; then
AC_MSG_RESULT(yes)
else
AC_MSG_RESULT(no)
AC_MSG_ERROR([
Sorry, you have a version of find which doesn't understand -path.
$PACKAGE_NAME needs it. If you have access to a version of find which
does understand -path, you can supply its path with the
'--with-find=' option.
])
fi
AC_MSG_CHECKING([whether $FIND -print0 works])
if $FIND . -path '*' -print0 >/dev/null 2>&1; then
AC_MSG_RESULT(yes)
else
AC_MSG_RESULT(no)
AC_MSG_ERROR([
Sorry, you have a version of find which doesn't understand -print0.
$PACKAGE_NAME needs it. If you have access to a version of find which
does understand -print0, you can supply its path with the
'--with-find=' option.
])
fi
QUILT_COMPAT_PROG_PATH(XARGS, xargs)
AC_MSG_CHECKING([whether $XARGS -0 works])
if echo | $XARGS -0 echo >/dev/null 2>&1; then
AC_MSG_RESULT(yes)
else
AC_MSG_RESULT(no)
AC_MSG_ERROR([
Sorry, you have a version of xargs which doesn't understand -0.
$PACKAGE_NAME needs it. If you have access to a version of xargs which
does understand -0, you can supply its path with the
'--with-xargs=' option.
])
fi
QUILT_COMPAT_PROG_PATH_OPT(DIFFSTAT, diffstat)
if test "$DIFFSTAT" != "diffstat"; then
# We need diffstat version 1.32 or better, else quilt refresh --diffstat
# will show progress data we don't want to see. This is only a warning
# and we continue even if version is older, as this is only a minor
# annoyance.
AC_MSG_CHECKING([for diffstat version])
diffstat_version=`$DIFFSTAT -V 2>/dev/null | \
sed 's/^[[^0-9]]*\([[0-9]]*\)\.\([[0-9]]*\).*/\1 \2/'`
eval set -- "$diffstat_version"
diffstat_major_version="$1"
diffstat_minor_version="$2"
if test -z "$diffstat_major_version" -o -z "$diffstat_minor_version"; then
AC_MSG_RESULT(unknown)
AC_MSG_WARN([
diffstat utility version couldn't be checked; chances are good that the
--diffstat option of the refresh command will not work properly.
])
else
AC_MSG_RESULT($diffstat_major_version.$diffstat_minor_version)
if test "$diffstat_major_version" -lt 1 \
-o \( "$diffstat_major_version" -eq 1 -a "$diffstat_minor_version" -lt 32 \); then
AC_MSG_WARN([
diffstat utility is too old; the --diffstat option of the refresh command
will not work correctly until a newer version (>= 1.32) is installed.
])
fi
fi
fi
QUILT_COMPAT_PROG_PATH(SENDMAIL, sendmail, [], [/usr/sbin])
AC_PATH_PROG(MSGMERGE, [msgmerge])
AC_PATH_PROG(MSGFMT, [msgfmt])
AC_PATH_PROG(XGETTEXT, [xgettext])
AC_PATH_PROG(MSGUNIQ, [msguniq])
AC_PATH_PROG(MSGCAT, [msgcat])
if test -n "$MSGFMT" -a -n "$MSGMERGE" -a -n "$XGETTEXT" -a -n "$MSGUNIQ" -a -n "$MSGCAT" ; then
HAVE_NLS=yes
else
HAVE_NLS=no
fi
USE_NLS=no
AC_ARG_ENABLE(nls, AC_HELP_STRING(
[--disable-nls], [exclude natural language support]),
[USE_NLS=$enableval],[USE_NLS=$HAVE_NLS])
if test $USE_NLS = yes -a $HAVE_NLS = no ; then
AC_MSG_ERROR([
You do not appear to have msgfmt, which is part of the GNU Gettext package. It
is a required package as you chose the '--enable-nls' option to configure.
You can download GNU Gettext from ftp.gnu.org
])
fi
PATCH_WRAPPER=
AC_ARG_WITH(patch-wrapper, AC_HELP_STRING(
[--with-patch-wrapper], [include GNU patch wrapper]), [
if test "$withval" = yes ; then
PATCH_WRAPPER=$withval
fi
])
AC_SUBST(PATCH_WRAPPER)
if test $USE_NLS = no ; then
AC_MSG_NOTICE([Building without natural language support])
fi
AC_SUBST(USE_NLS)
AC_SUBST(docdir)
dnl Check for rpmbuild (v4) vs. rpm (v3)
QUILT_COMPAT_PROG_PATH_OPT(RPMBUILD, rpmbuild, [rpmbuild rpm])
QUILT_COMPAT_PROG_PATH_OPT(MD5SUM, md5sum, [gmd5sum md5sum])
QUILT_COMPAT_PROG_PATH_OPT(P7ZIP, 7z, [7zr 7za 7z])
AC_SUBST(COMPAT_SYMLINKS)
AC_SUBST(COMPAT_PROGRAMS)
AC_CONFIG_FILES(Makefile)
AC_OUTPUT
dnl Print results
AC_MSG_RESULT([])
AC_MSG_RESULT([$PACKAGE_NAME version $PACKAGE_VERSION configured.])
AC_MSG_RESULT([])
AC_MSG_RESULT([Using '$prefix' for installation prefix.])
AC_MSG_RESULT([])
AC_MSG_RESULT([Report bugs to $PACKAGE_BUGREPORT])

27
doc/Makefile Normal file
View File

@ -0,0 +1,27 @@
all : quilt.pdf quilt-rus.pdf
quilt.ps : quilt.dvi
dvips -t letter -o $@ $<
quilt.pdf: main.tex
pdflatex --jobname=quilt -t letter $<
quilt.dvi : main.tex
latex $< && \
mv main.dvi $@
quilt-rus.ps : quilt-rus.dvi
dvips -t letter -o $@ $<
quilt-rus.pdf: main-rus.tex
pdflatex --jobname=quilt-rus -t letter $<
quilt-rus.dvi : main-rus.tex
latex $< && \
mv main-rus.dvi $@
clean:
rm -f {main,quilt}.{dvi,log,aux} {main,quilt}-rus.{dvi,log,aux}
distclean: clean
rm -f quilt.{ps,pdf,dvi} quilt-rus.{ps,pdf,dvi}

19
doc/README.EMACS Normal file
View File

@ -0,0 +1,19 @@
Introduction
============
quilt-el minor mode (lib/quilt.el) is toggled by `M-x quilt-mode'. It
provides the following features:
- You can issue many quilt sub-commands by shortcut keys. By using
these keys, quilt-el can also detect moving the patch stack and
can refresh corresponding buffers automatically.
- If a buffer is associated with the file which is not included in
the topmost patch, the buffer becomes read-only. So you can avoid
editing wrong files accidentally.
- After quilt-el is once enabled, all files which you open are checked
whether it is in a quilt hierarchy or not. If so, corresponding buffer
becomes quilt-mode automatically.
-- Satoru Takeuchi <nqm08501@nifty.com>, Sun, 14 Jan 2007 23:57:29 +0900

82
doc/README.MAIL Normal file
View File

@ -0,0 +1,82 @@
QUILT MAIL COMMAND
==================
The mail command starts up the system editor ($EDITOR, or vi if $EDITOR
is undefined) with an template in Internet Message Format (RFC 2822).
This template is used to generate an introduction, as well as one
message for each patch in the selected range of the series file. The
template is used as follows: The headers are used in each message
generated, and modified as required. The template body is used only for
the introduction.
In the template, the headers can be modified, additional headers added,
and unneeeded headers can be removed. The template header also contains
a special Subject-Prefix header which defines a prefix for each subject
header. The @num@ and @total@ macros in the Subject-Prefix header are
replaced with the patch number and the total number of patches,
respectively. The patch number @num@ is zero-padded to the same width
that @total@ has.
Each message is assigned a unique Message-Id header, and all messages
other than the introduction are made to refer to the introduction (using
a References header) for proper message threading in mail clients. The
message timestamps in Date headers in each message is incremented by one
second per message, starting with the timestamp of the introduction.
If a ~/.signature file exists, this file is appended to each message
generated.
Recipients and headers can be added, and existing headers can be
replaced, individually in each message based on the headers in the
introduction. Quilt does not enforce a specific patch file format. The
mail command has a built-in heuristic for extracting subjects from
patches, though:
* if the patch starts with something that looks like a mail
header, and there is a Subject header, use this as the subject,
or else
* if the patch has DESC a line followed by an EDESC line, use
the text in between as the subject, or else
* if the first paragraph is short enough to serve as a subject
(150 characters or less), use the first paragraph as the
subject.
All bracketed fields and Fwd:, Fw:, Re:, Aw: are stripped from subject
headers as well.
If no subject can be extracted from a patch, or there are duplicate
subjects, the mail command will print an error message and abort.
In case a patch header contains a line starting with `Cc:', `Acked-by:',
or `Signed-off-by:', the email address specified is added to the
CC header for this patch. If a patch header contains a line starting
with `To:', the email address specified is added to To header for this
patch.
If the user specified in `To:', `Cc:', `Acked-by:', or `Signed-off-by:'
equals the current user's name ($LOGNAME or $(whoami) if LOGNAME is
undefined), this does not add a recipient.
Each recipient will occur in the resulting message only once. Duplicates
are filtered out. This happens as the headers are read, so the relative
order of the To, Cc, and Bcc headers should not be changed.
Recipients are checked for RFC 2822 conformance (at least that is the
intention; actually the checks are not perfect). This means that special
characters must be quoted, and 8-bit characters must be encoded. In
practice it probably makes little sense to use anything fancy right now;
this area still needs some work. Character set recognition and proper
qualifying is also still missing.
The heuristic can be overridden by defining a quilt_mail_patch_filter
function in ~/.quiltrc or /etc/quilt.quiltrc. This function is passed
the patch name as argument (without the $QUILT_PATCHES prefix). It
shall read the patch from standard input, and write a RFC 2822 message
header and the patch to standard output. Headers of the form
``Recipient-$X: ...'' denote recipients to be added to the $X header
(for example, ``Recipient-Cc: agruen@suse.de''). Headers of the form
``Replace-$X: ...'' specify that header $X is to be replaced by this
header (for eaxmple, ``Replace-Subject: Patch description''). All other
headers are appended to the existing headers.

117
doc/README.in Normal file
View File

@ -0,0 +1,117 @@
The scripts in this package simplify working with a series of patches.
The usual tasks like applying, refreshing and reversing are supported.
Please see the paper "How To Survive With Many Patches /or/
Introduction to Quilt" for an introduction.
Command reference
=================
@REFERENCE@
Typical Usages: New patches; Importing patches; Patch management
======================================================================
Add new patches:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1. create a new patch: quilt new {patchname, e.g., sysctl_fix.patch}
2. add/edit file(s): quilt edit filepath
or:
2a. add file(s) to patch: quilt add {filepath}
2b. manual edit file(s) use your $editor
3. update the patch: quilt refresh
3b. list the patch description: quilt header [patch]
3c. update the patch description: quilt header -e [patch]
4. list files in the patch: quilt files
5. show current patch contents: quilt diff
6. apply current, ready for next: quilt push
7. remove file(s) from patch: quilt remove {filepath}
Importing patches:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1. import a patch: quilt import patchfile
2. apply it: quilt push
3. update the patch: quilt refresh
3b. list the patch description: quilt header [patch]
3c. update the patch description: quilt header -e [patch]
4. list files in the patch: quilt files
5. show current patch contents: quilt diff
Import/Apply a series file + patches to a tree:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1. cp(1) the patches directory ('series' file + all patch files) to
the expected patches location (as specified in your .quiltrc file)
2. apply all of series: quilt push -a
Other patch management:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1. remove files from a patch: quilt remove {filepath}
2. remove unapplied patch: quilt delete {patchname}
3. list all patch names: quilt series
4. list all applied/unapplied: quilt applied | unapplied
5. list top/previous/next patch name: quilt top | previous | next
6. list patches modifying file: quilt patches {filepath}
7. rename a patch: quilt rename {patchname}
8. duplicate a patch: quilt fork {patchname}
9. prepare or send mails: quilt mail ...
10. search in source files: quilt grep ...
11. create snapshot: quilt snapshot
12. init from RPM spec or series file: quilt setup
13. distribution of patches: quilt diff --combine
and distribute the combined diff file,
or distribute the patches/ directory content
Helper files/scripts
====================
backup-files
A simple utility that creates / restores / removes
backup files.
dependency-graph
A utility to compute patch dependencies from the QUILT_PC
metadata.
edmail
A utility to manipulate the headers of an Internet mail message.
guards
Convert a series file with conditional statements into a series
file as expected; see the guards(1) manual page.
inspect
A script to create a series file from an rpm spec file (including
a list of tar files).
patchfns
utilfns
Collections of functions.
remove-trailing-ws
A utility to report trailing whitespace, and remove trailing
whitespace from files.

794
doc/main.tex Normal file
View File

@ -0,0 +1,794 @@
%\documentclass[a4paper]{article}
\documentclass{article}
\usepackage{graphicx}
\usepackage{subfigure}
\usepackage{fancyvrb}
%\usepackage{times}
\usepackage[latin1]{inputenc}
\usepackage{url}
%\usepackage{lineno}
%\linenumbers
%\renewcommand{\baselinestretch}{1.5}
% Change url font to textsf (and check what breaks in PDF/HTML/...)
\fvset{xleftmargin=3em,commandchars=\\\{\}}
\newcommand{\quilt}[1]{\textsf{quilt #1}}
\newcommand{\sh}[1]{\textsl{#1}}
\newcommand{\prog}[1]{\textit{#1}}
\title{How To Survive With Many Patches\\
{\Large or}\\
Introduction to Quilt\footnote{
Quilt is a GPL licensed project hosted on GNU Savannah. Some ideas
for this document were taken from \textit{docco.txt} in
Andrew Morton's patch management scripts package~\cite{akpm02}.
The text in the examples was taken from \textit{A Midsummer
Night's Dream} by William Shakespeare.
}}
\author{Andreas Grünbacher, SuSE Labs \\
%\em{SUSE Labs, SUSE LINUX AG} \\
{\normalsize agruen@suse.de}
}
%\date{}
\begin{document}
\maketitle
\thispagestyle{empty}
\begin{abstract}
After looking at different strategies for dealing with software packages
that consist of a base software package on top of which a number of
patches are applied, this document introduces the script collection
\textit{quilt,} which was specifically written to help deal with
multiple patches and common patch management tasks.
\end{abstract}
\section{Introduction}
% Prerequisites: UNIX, patches, using GNU diff and GNU patch.
% Why patches in the first place?
In the old days, vendor specific software packages in the open source
world consisted of a file with the official version of the software,
plus a patch file with the additional changes needed to adapt the
package to specific needs. The official software package was usually
contained in a \textsf{package.tar.gz} file, while the patch was found
in \textsf{package.diff.} Instead of modifying the official
package sources, local changes were kept separate. When building the
software package, the tar archive was extracted, and the patch was
applied.
Over time, the patch file ended up containing several independent
changes. Of those changes, some were integrated into later versions of
the software, while other add-ons or adaptations remain external. Whenever
a new official version was integrated, the patch needed to be revised:
changes that were already integrated in the official version needed to
be split from changes that were not.
A big improvement was to allow multiple patches in a vendor package,
and this is also how patches are handled today: a number of
patches is applied on top of each other. Each patch usually consists of
a logically related set of changes. When some patches get integrated
upstream, those patches can simply be removed from the vendor specific
package. The remaining patches frequently continue to apply cleanly.
Some of the remaining patches may have to be maintained across a range
of upstream versions because they are too specific for the upstream
software package, etc. These patches often get out of sync, and need to
be updated.
For the majority of packages, the number of patches remains relatively
low, so maintaining those patches without tools is feasible. A number of
packages have dozens of patches, however. At the extreme end is the
kernel source package (kernel-source-\textit{2.4.x}) with more than
1\,000 patches. The difficulty of managing such a vast number of
patches without tools can easily be imagined.
This document discusses different strategies of dealing with large sets
of patches. Patches are usually generated by the \prog{diff} utility,
and applied with the \prog{patch} utility. Different patch file formats are
defined as part of the specification of the \prog{diff} utility in
POSIX.1~\cite{posix-2001-diff}. The most commonly used format today,
\textit{unified diff,} is not covered by POSIX.1, however. A good
description of patch file formats is found in the \prog{GNU diff} info
pages~\cite{info-diff}.
The question we try to answer in this document is how patches are best kept
up to date in face of changes both to the upstream software package, and
to the patches that precede them. After looking at some existing
approaches, a collection of patch management scripts known as
\textit{quilt} is described~\cite{quilt}, starting with basic concepts,
and progressing towards more advanced tasks.
% - quilt
% (wet people's mouths about the features)
% How exactly does this relate to many patches?
\section{Existing Approaches}
\label{sec:existing}
The minimal solution for updating a patch is to apply all preceding
patches.
%\footnote{ In the kernel CVS, we have a a script called
%\textit{sequence-patch} that simply applies all patches up to a
%specified patch. }
Then, a copy of the resulting source tree is created.\footnote{
The two copies can also be hard-linked with each other, which
significantly speeds up both the copying and the final
``diffing''. If hard links are used, care must be taken that the
tools used to update one copy of the source tree will create new
files, and will not overwrite shared files. Editors like
\prog{emacs} and \prog{vi}, and utilities like \prog{patch},
support this.
} The next patch in the sequence of patches (which is the one to be
updated) is applied to only one of these source trees. This source tree
is then modified until it reflects the desired result. The new version of
the patch is distilled by comparing the two source trees with
\prog{diff}, and writing the result into a file.
This simple approach is rather error prone, and leaves much to be
desired. Several people have independently written scripts that
automate and improve upon this process.
A version control system like \prog{CVS} or \prog{RCS} may be a
reasonable alternative in some cases. The version control system is
brought in the state of the working tree with a number of patches
applied. Then the next patch is applied. After the working tree is
updated as required, a diff between the repository copy and the working
tree is created (with \prog{cvs diff}, etc). In this scenario the
version control system is used to store and compare against the old
repository version only. The full version control overhead is paid,
while only a small fraction of its functionality is needed. Switching
between different patches is not simplified.
% TODO: Mention some approaches here; RCS and CVS ...
One of the most advanced approaches is Andrew Morton's patch management
scripts~\cite{akpm02}. The author of this document found that none of
the available solutions would scale up to the specific requirements of
the SUSE kernel-source package, and started to improve Andrew Morton's
scripts until they became what they are now~\cite{quilt}.
% - Re and Rd scripts (Czech scripts using RCS, replaces the
% now-obsolete rpmpatch that supports one .dif only).
% - Werner's scripts
% What couldn't be done:
% - Patches in sub-directories
% - Many patches
% - Retaining documentation (akpm's scripts do part of this)
% Actually merging rejects is not handled; use tools like:
% - wiggle
% - Other merge tools (e.g., graphical ones)
\section{Quilt: Basic Concepts and Operation}
\label{sec:basic}
The remainder of this document discusses the script collection
\textit{quilt.}
With quilt, all work occurs within a single directory tree. Since
version 0.30, commands can be invoked from anywhere within the source
tree (the directory tree is scanned upwards until either the
\textsf{.pc} or the \textsf{patches} directory is found).
Commands are of the form ``\quilt{cmd}'', similar to CVS
commands. They can be abbreviated as long as the specified part of the
command is unique. All commands print some help text with ``\quilt{cmd
-h}''.
Quilt manages a stack of patches. Patches are applied incrementally on
top of the base tree plus all preceding patches. They can be pushed
on top of the stack (\quilt{push}), and popped off the stack
(\quilt{pop}). Commands are available for querying the contents of the
series file (\quilt{series}, see below), the contents of the stack
(\quilt{applied}, \quilt{previous}, \quilt{top}), and the patches that
are not applied at a particular moment (\quilt{next}, \quilt{unapplied}).
By default, most commands apply to the topmost patch on the stack.
When files in the working directory are changed, those changes become
part of the working state of the topmost patch, provided that those
files are part of the patch. Files that are not part of a patch must be
added before modifying them so that quilt is aware of the original
versions of the files. The \quilt{refresh} command regenerates a patch.
After the refresh, the patch and the working state are the same.
Patch files are located in the \textsf{patches} sub-directory of the
source tree (see Figure~\ref{fig:dir-layout}). The \textsf{QUILT\_PATCHES}
environment variable can be used to override this location and quilt
will remember this location by storing its value in the
\textsf{.pc/.quilt\_patches} file. The \textsf{patches} directory may contain
sub-directories, which is useful for grouping related patches together.
\textsf{patches} may also be a symbolic link instead of a directory.
A file called \textsf{series} contains a list of patch file names that
defines the order in which patches are applied. Unless there are means
by which series files can be generated automatically (see
Section~\ref{sec:rpm}), they are usually provided along with a set of
patches. In \textsf{series}, each patch file name is on a separate line.
Patch files are identified by pathnames that are relative to the
\textsf{patches} directory; patches may be in sub-directories below the
\textsf{patches} directory. Lines in the series file that start with a
hash character (\texttt{\#}) are ignored. When quilt adds, removes, or
renames patches, it automatically updates the series file. Users of
quilt can modify series files while some patches are applied, as long as
the applied patches remain in their original order.
Different series files can be used to assemble patches in different ways,
corresponding for example to different development branches.
\begin{figure}
\begin{center}
\begin{minipage}{6cm}
\begin{small}
\begin{Verbatim}
work/ -+- ...
|- patches/ -+- series
| |- patch2.diff
| |- patch1.diff
| +- ...
+- .pc/ -+- applied-patches
|- patch1.diff/ -+- ...
|- patch2.diff/ -+- ...
+- ...
\end{Verbatim}
\end{small}
\end{minipage}
\caption{Quilt files in a source tree.}
\label{fig:dir-layout}
\end{center}
\end{figure}
Before a patch is applied (or ``pushed on the stack''), copies of all
files the patch modifies are saved to the \textsf{.pc/\textit{patch}}
directory.\footnote{
The patch name with extensions stripped is used as the name of
the sub-directory below the \textsf{.pc} directory. \prog{GNU patch},
which quilt uses internally to apply patches, creates backup
files and applies the patch in one step.
} The patch is added to the list of
currently applied patches (\textsf{.pc/applied-patches}). Later when a patch is regenerated
(\quilt{refresh}), the backup copies in \textsf{.pc/\textit{patch}} are
compared with the current versions of the files in the source tree
using \prog{GNU diff}.
Documentation related to a patch can be put at the beginning of a patch
file. Quilt is careful to preserve all text that precedes the actual
patch when doing a refresh.
The series file is looked up in the root of the source tree, in the
patches directory, and in the \textsf{.pc} directory. The first series
file that is found is used. This may also be a symbolic link, or a file
with multiple hard links. Usually, only one series file is used for a
set of patches, so the \textsf{patches} sub-directory is a convenient
location.
While patches are applied to the source tree, the \textsf{.pc} directory
is essential for many operations, including taking patches off the stack
(\quilt{pop}), and refreshing patches (\quilt{refresh}). Files in the
\textsf{.pc} directory are automatically removed when they are no longer
needed, so usually there is no need to clean up manually. The
\textsf{QUILT\_PC} environment variable can be used to override the
location of the \textsf{.pc} directory.
\section{An Example}
This section demonstrates how new patches are created and updated, and
how conflicts are resolved. Let's start with a short text file:
\begin{small}
\begin{Verbatim}
Yet mark'd I where the bolt of Cupid fell:
It fell upon a little western flower,
Before milk-white, now purple with love's wound,
And girls call it love-in-idleness.
\end{Verbatim}
\end{small}
New patches are created with \quilt{new}. A new patch automatically
becomes the topmost patch on the stack. Files must be added
with \quilt{add} before they are modified. Note that this is slightly
different from the CVS style of interaction: with CVS, files are in the
repository, and adding them before committing (but after modifying them)
is enough. Files are usually added and immediately modified. The
command \quilt{edit} adds a file and loads it into the default editor.
(The environment variable \textsf{EDITOR} specifies which is the default
editor. If \textsf{EDITOR} is not set, \prog{vi} is used.)
\begin{small}
\begin{Verbatim}
\sh{$ quilt new flower.diff}
Patch flower.diff is now on top
\sh{$ quilt edit Oberon.txt}
File Oberon.txt added to patch flower.diff
\end{Verbatim}
\end{small}
Let's assume that the following lines were added to \textsf{Oberon.txt}
during editing:
\begin{small}
\begin{Verbatim}
The juice of it on sleeping eye-lids laid
Will make a man or woman madly dote
Upon the next live creature that it sees.
\end{Verbatim}
\end{small}
The actual patch file is created (and later updated) with
\quilt{refresh}. The result is as follows:\footnote{
Timestamps in patches are omitted from the output in the examples.
}
\begin{small}
\begin{Verbatim}
\sh{$ quilt refresh}
\sh{$ cat patches/flower.diff}
Index: example1/Oberon.txt
===================================================================
--- example1.orig/Oberon.txt
+++ example1/Oberon.txt
@@ -2,3 +2,6 @@
It fell upon a little western flower,
Before milk-white, now purple with love's wound,
And girls call it love-in-idleness.
+The juice of it on sleeping eye-lids laid
+Will make a man or woman madly dote
+Upon the next live creature that it sees.
\end{Verbatim}
\end{small}
Now let's assume that a line in the text has been overlooked, and must
be inserted. The file \textsf{Oberon.txt} is already part of the patch
\textsf{flower.diff}, so it can immediately be modified in an editor.
Alternatively, \quilt{edit} can be used; it simply opens up the default
editor if the file is already part of the patch.
After the line is added, we use \quilt{diff -z} to see a diff of the
changes we made:
\begin{small}
\begin{Verbatim}
\sh{$ quilt diff -z}
Index: example1/Oberon.txt
===================================================================
--- example1.orig/Oberon.txt
+++ example1/Oberon.txt
@@ -2,6 +2,7 @@
It fell upon a little western flower,
Before milk-white, now purple with love's wound,
And girls call it love-in-idleness.
+Fetch me that flower; the herb I shew'd thee once:
The juice of it on sleeping eye-lids laid
Will make a man or woman madly dote
Upon the next live creature that it sees.
\end{Verbatim}
\end{small}
A diff of the topmost patch can be generated with \quilt{diff} without
arguments. This does not modify the actual patch file. The changes are
only added to the patch file by updating it with \quilt{refresh}. Then
we remove the patch from the stack with \quilt{pop}:
\begin{small}
\begin{Verbatim}
\sh{$ quilt refresh}
Refreshed patch flower.diff
\sh{$ quilt pop}
Removing flower.diff
Restoring Oberon.txt
No patches applied
\end{Verbatim}
\end{small}
Next, let's assume that \textsf{Oberon.txt} was modified ``upstream'':
The word \textit{girl} did not fit very well, and so it was replaced
with \textit{maiden.} \textsf{Oberon.txt} now contains:
\begin{small}
\begin{Verbatim}
Yet mark'd I where the bolt of Cupid fell:
It fell upon a little western flower,
Before milk-white, now purple with love's wound,
And maidens call it love-in-idleness.
\end{Verbatim}
\end{small}
This causes \textsf{flower.diff} to no longer apply cleanly. When we
try to push \textsf{flower.diff} on the stack with \quilt{push}, we get
the following result:
\begin{small}
\begin{Verbatim}
\sh{$ quilt push}
Applying flower.diff
patching file Oberon.txt
Hunk #1 FAILED at 2.
1 out of 1 hunk FAILED -- rejects in file Oberon.txt
Patch flower.diff does not apply (enforce with -f)
\end{Verbatim}
\end{small}
Quilt does not automatically apply patches that have rejects. Patches
that do not apply cleanly can be ``force-applied'' with \quilt{push -f},
which leaves reject files in the source tree for each file that has
conflicts. Those conflicts must be resolved manually, after which the
patch can be updated (\quilt{refresh}). Quilt remembers when a patch has
been force-applied. It refuses to push further patches on top of such
patches, and it does not remove them from the stack. A force-applied
patch may be ``force-removed'' from the stack with \quilt{pop -f},
however. Here is what happens when force-applying \textsf{flower.diff}:
\begin{small}
\begin{Verbatim}
\sh{$ quilt push -f}
Applying flower.diff
patching file Oberon.txt
Hunk #1 FAILED at 2.
1 out of 1 hunk FAILED -- saving rejects to file Oberon.txt.rej
Applied flower.diff (forced; needs refresh)
\end{Verbatim}
\end{small}
After re-adding the lines of verse from \textsf{flower.diff} to
\textsf{Oberon.txt}, we update the patch with \quilt{refresh}.
\begin{small}
\begin{Verbatim}
\sh{$ quilt edit Oberon.txt}
\sh{$ quilt refresh}
Refreshed patch flower.diff
\end{Verbatim}
\end{small}
Our final version of \textsf{Oberon.txt} contains:
\begin{small}
\begin{Verbatim}
Yet mark'd I where the bolt of Cupid fell:
It fell upon a little western flower,
Before milk-white, now purple with love's wound,
And maidens call it love-in-idleness.
Fetch me that flower; the herb I shew'd thee once:
The juice of it on sleeping eye-lids laid
Will make a man or woman madly dote
Upon the next live creature that it sees.
\end{Verbatim}
\end{small}
\section{Further Commands and Concepts}
This section introduces a few more basic commands, and then describes
additional concepts that may not be immediately obvious. We do not
describe all of the features of quilt here since many quilt commands are
quite intuitive; furthermore, help text that describes the available
options for each command is available via \quilt{\textit{cmd} -h}.
The \quilt{top} command shows the name of the topmost patch. The
\quilt{files} command shows which files a patch contains. The
\quilt{patches} command shows which patches modify a specified file.
With our previous example, we get the following results:
\begin{small}
\begin{Verbatim}
\sh{$ quilt top}
flower.diff
\sh{$ quilt files}
Oberon.txt
\sh{$ quilt patches Oberon.txt}
flower.diff
\end{Verbatim}
\end{small}
The \quilt{push} and \quilt{pop} commands optionally take a number or
a patch name as argument. If a number is given, the specified number of
patches is added (\quilt{push}) or removed (\quilt{pop}). If a patch
name is given, patches are added (\quilt{push}) or removed (\quilt{pop})
until the specified patch is on top of the stack. With the \textsf{-a}
option, all patches in the series file are added (\quilt{push}), or all
applied patches are removed from the stack (\quilt{pop}).
\subsection{Patch Strip Levels}
Quilt assumes that patches are applied with a strip level of one (the
\textsf{-p1} option of \prog{GNU patch}) by default: the topmost directory
level of file names in patches is stripped off. Quilt remembers the
strip level of each patch in the \textsf{series} file. When generating a
diff (\quilt{diff}) or updating a patch (\quilt{refresh}), a different
strip level can be specified, and the series file will be updated
accordingly. Quilt can apply patches with an arbitrary strip level, and
produces patches with a strip level of zero or one. With a strip level
of one, the name of the directory that contains the working tree is used
as the additional path component. (So in our example,
\textsf{Oberon.txt} is contained in directory \textsf{example1}.)
\subsection{Importing Patches}
The \quilt{import} command automates the importing of patches into the
quilt system. The command copies a patch into the \textsf{patches}
directory and adds it to the \textsf{series} file. For patch strip
levels other than one, the strip level is added after the patch file
name. (An entry for \textsf{a.diff} with strip level zero might read
``{\small \verb|a.diff -p0|}''.)
Another common operation is to incorporate a fix or similar that comes
as a patch into the topmost patch. This can be done by hand by first
adding all the files contained in the additional patch to the topmost
patch with \quilt{add},\footnote{
The \prog{lsdiff} utility, which is part of the \textit{patchutils}
package, generates a list of files affected by a patch.
} and then applying the patch to the working tree. The \quilt{fold}
command combines these steps.
\subsection{Sharing patches with others}
For sharing a set of patches with someone else, the series file which
contains the list of patches and how they are applied, and the patches
themselves are all that's needed. The \textsl{.pc} directory only
contains quilt's working state, and should not be distributed. Make sure
that all the patches are up-to-date, and refresh patches when
necessary. The \textsf{--combine} option of \quilt{diff} can be used for
generating a single patch out of all the patches in the series file.
\subsection{Merging with upstream}
The concept of merging your patches with upstream is identical to applying
your patches on a more recent version of the software.
Before merging, make sure to pop all your patches using \quilt{pop -a}.
Then, update your codebase. Finally, remove obsoleted patches
from the series file and \quilt{push} the remaining ones, resolve
conflicts and refresh patches as needed.
\subsection{Forking}
\label{sec:forking}
There are situations in which updating a patch in-place is not ideal:
the same patch may be used in more than one series file. It may also
serve as convenient documentation to retain old versions of patches, and
create new ones under different names. This can be done by hand by
creating a copy of a patch (which must not be applied), and updating the
patch name in the series file.
The \quilt{fork} command simplifies this: it creates a copy of the
topmost patch in the series, and updates the series file. Unless a patch
name is explicitly specified, \quilt{fork} will generate the following
sequence of patch names: \textsf{patch.diff}, \textsf{patch-2.diff},
\textsf{patch-3.diff},\dots
\subsection{Dependencies}
\label{sec:dependencies}
When the number of patches in a project grows large, it becomes
increasingly difficult to find the right place for adding a new patch in
the patch series. At a certain point, patches will get inserted at the
end of the patch series, because finding the right place has become too
complicated. In the long run, a mess accumulates.
To help avoid this by keeping the big picture, the \quilt{graph} command
generates \textit{dot} graphs showing the dependencies between
patches.\footnote{
The \quilt{graph} command computes dependencies based on
which patches modify which files, and optionally will also
check for overlapping changes in the files. While the former
approach will often result in false positives, the latter
approach may result in false negatives (that is, \quilt{graph}
may overlook dependencies).
} The output of this command can be visualized using the tools from AT\&T
Research's Graph Visualization Project (GraphViz,
\url{http://www.graphviz.org/}). The \quilt{graph} command supports
different kinds of graphs.
\subsection{Advanced Diffing}
Quilt allows us to diff and refresh patches that are applied, but are not
on top of the stack (\quilt{diff -P \textit{patch}} and \quilt{refresh
\textit{patch}}). This is useful in several cases, for example, when
%\begin{itemize}
%
%\item When the topmost patch has been modified but the changes are not
%yet completed, refreshing the patch would leave a patch file that is in
%an inconsistent state. Without that, the patch cannot be removed from
%the stack, or else the changes would be lost.
%
%\item Popping patches and then pushing them again results in modified
%time stamps. This may trigger time consuming recompiles.
%
%\item It is simply convenient to be able to fix small bugs in patches
%further down in the stack without much ado.
%
%\end{itemize}
%
patches applied higher on the stack modify some of the files that this
patch modifies. We can picture this as a shadow which the patches higher
on the stack throw on the files they modify. When refreshing a patch,
changes to files that are not shadowed (and thus were last modified by
the patch that is being refreshed) are taken into account. The
modifications that the patch contains for shadowed files will not be
updated.
The \quilt{diff} command allows us to merge multiple patches into one by
optionally specifying the range of patches to include (see \quilt{diff
-h}). The combined patch will only modify each file contained in these
patches once. The result of applying the combined patch is the same as
applying all the patches in the specified range in sequence.
Sometimes it is convenient to use a tool other than \prog{GNU diff} for
comparing files (for example, a graphical diff replacement like
\prog{tkdiff}). Quilt will not use tools other than \prog{GNU diff} when
updating patches (\quilt{refresh}), but \quilt{diff} can be passed the
\textsf{-{}-diff=\textit{utility}} argument. With this argument, the
specified utility is invoked for each file that is being modified with
the original file and new file as arguments. For new files, the first
argument will be \textsf{/dev/null}. For removed files, the second
argument will be \textsf{/dev/null}.
When \quilt{diff} is passed a list of file names, the diff will be
limited to those files. With the \textsf{-R} parameter, the original and
new files are swapped, which results in a reverse diff.
Sometimes it is useful to create a diff between an arbitrary state of
the working tree and the current version. This can be used to create a
diff between different versions of a patch (see
Section~\ref{sec:forking}), etc. To this end, quilt allows us to take a
snapshot of the working directory (\quilt{snapshot}). Later, a diff
against this state of the working tree can be created with \quilt{diff
-{}-snapshot}.
Currently, only a single snapshot is supported. It is stored in the
\textsf{.pc/.snap} directory. To recover the disk space the snapshot
occupies, it can be removed with \quilt{snapshot -d}, or by removing the
\textsf{.pc/.snap} directory manually.
\subsection{Working with RPM Packages}
\label{sec:rpm}
Several Linux distributions are based on the RPM Package
Manager~\cite{max-rpm}. RPM packages consist of a spec that defines how
packages are built, and a number of additional files like tar archives,
patches, etc. Most RPM packages contain an official software package
plus a number of patches. Before these patches can be manipulated with
quilt, a series file must be created that lists the patches along with
their strip levels.
The \quilt{setup} command automates this for most RPM packages. When
given a spec file as its argument, it performs the \textsf{\%prep}
section of the spec file, which is supposed to extract the official
software package, and apply the patches. In this run, quilt remembers
the tar archives and the patches that are applied, and creates a series
file. Based on that series file, \quilt{setup} extracts the archives,
and copies the patches into the \textsf{patches} sub-directory. Some
meta-information like the archive names are stored as comments in the
series file. \quilt{setup} also accepts a series file as argument (which
must contain some meta-information), and sets up the working tree from
the series file in this case.
\section{Customizing Quilt}
Upon startup, quilt evaluates the file \textsf{.quiltrc} in the user's
home directory, or the file specified with the \textsf{--quiltrc} option.
This file is a regular bash script. Default options can be passed to
any command by defining a \textsf{QUILT\_\textit{COMMAND}\_ARGS} variable
(for example, \textsf{QUILT\_DIFF\_ARGS="--color=auto"} causes the output
of \quilt{diff} to be syntax colored when writing to a terminal).
In addition to that, quilt recognizes the following variables:
\begin{description}
\item[\textsf{QUILT\_DIFF\_OPTS}]
Additional options that quilt shall pass to \prog{GNU diff} when
generating patches. A useful setting for C source code is
``\textsf{-p}'', which causes \prog{GNU diff} to show in the resulting
patch which function a change is in.
\item[\textsf{QUILT\_PATCH\_OPTS}]
Additional options that quilt shall pass to \prog{GNU patch} when
applying patches. (For example, recent versions of \prog{GNU patch}
support the ``\textsf{--reject-format=unified}'' option for generating
reject files in unified diff style (older versions used
``\textsf{--unified-reject-files}'' for that).
\item[\textsf{QUILT\_PATCHES}]
The location of patch files (see Section~\ref{sec:basic}). This setting
defaults to ``\textsf{patches}''.
\end{description}
\section{Pitfalls and Known Problems}
As mentioned earlier, files must be added to patches before they can be
modified. If this step is overlooked, one of the following problems will
occur: If the file is included in a patch further below on the stack,
the changes will appear in that patch when it is refreshed, and for that
patch the \quilt{pop} command will fail before it is refreshed. If the
file is not included in any applied patch, the original file in the
working tree is modified.
Patch files may modify the same file more than once. \prog{GNU patch}
has a bug that corrupts backup files in this case. A fix is available,
and will be integrated in a later version of \textit{GNU patch}. The fix has
already been integrated into the SUSE version of \textit{GNU patch}.
There are some packages that assume that it's a good idea to remove all
empty files throughout a working tree, including the \textsf{.pc}
directory. The \textit{make clean} target in the linux kernel sources
is an example. Quilt uses zero-length files in \textsf{.pc} to mark
files added by patches, so such packages may corrupt the \textsf{.pc}
directory. A workaround is to create a symbolic link \textsf{.pc} in the
working tree that points to a directory outside.
It may happen that the files in the \textsf{patches} directory gets out of
sync with the working tree (e.g., they may accidentally get updated by
CVS or similar). Files in the \textsf{.pc} directory may also become
inconsistent, particularly if files are not added before modifying them
(\quilt{add} / \quilt{edit}). If this happens, it may be possible to
repair the source tree, but often the best solution is to start over
with a scratch working directory and the \textsf{patches} sub-directory.
There is no need to keep any files from the \textsf{.pc} directory in
this case.
% - Patches cannot automatically be reverse applied (?)
% - Does not auto-detect is a patch has been cleanly integrated
% - Speed
% - Push a patch that is not in the series file (after changing
% applied-patches to include the full patch name)?
% - Other back-ends (RCS etc.)
% - Pop and push modify file timestamps, which causes recompiles.
% Ccache ameliorates this.
% - patchutils: Very useful: lsdiff, filterdiff, etc.
\section{Summary}
We have shown how the script collection \textit{quilt} solves various
problems that occur when dealing with patches to software packages.
Quilt is an obvious improvement over directly using the underlying tools
(\prog{GNU patch}, \prog{GNU diff}, etc.), and offers many features not
available with competing solutions. Join the club!
The quilt project homepage is
\url{http://savannah.nongnu.org/projects/quilt/}. There is a development
mailing list at \url{http://mail.nongnu.org/mailman/listinfo/quilt-dev}.
Additional features that fit into quilt's mode of operation are always
welcome, of course.
\begin{thebibliography}{XX}
\bibitem{akpm02}
Andrew Morton: Patch Management Scripts,
\url{http://lwn.net/Articles/13518/} and
\url{http://userweb.kernel.org/~akpm/stuff/patch-scripts.tar.gz}.
\bibitem{quilt}
Andreas Grünbacher et al.: Patchwork Quilt,
\url{http://savannah.nongnu.org/projects/quilt}.
\bibitem{posix-2001-diff}
IEEE Std. 1003.1-2001: Standard for Information Technology, Portable
Operating System Interface (POSIX), Shell and Utilities, diff
command, pp.~317. Online version available from the The Austin Common
Standards Revision Group, \url{http://www.opengroup.org/austin/}.
\bibitem{info-diff}
\textit{GNU diff} info pages (\textsf{info Diff}), section \textit{Output
Formats.}
\bibitem{max-rpm}
Edward C. Bailey: Maximum RPM: Taking the Red Hat Package Manager to the
Limit, \url{http://www.rpm.org/max-rpm/}.
\end{thebibliography}
% Add a "quick-reference card"?
\end{document}

351
doc/quilt.1.in Normal file
View File

@ -0,0 +1,351 @@
.\\" Created by Martin Quinson from the tex documentation
.\\"
.TH quilt 1 "Dec 17, 2013" "quilt"
.SH NAME
quilt \\- tool to manage series of patches
.SH SYNOPSIS
.B quilt
[-h] command [options]
.SH DESCRIPTION
Quilt is a tool to manage large sets of patches by keeping track of the
changes each patch makes. Patches can be applied, un-applied, refreshed,
etc. The key philosophical concept is that your primary output is patches.
With quilt, all work occurs within a single directory tree. Commands can be
invoked from anywhere within the source tree. They are of the form
.B quilt cmd
similar to CVS, svn or git commands. They can be abbreviated as long as the specified
part of the command is unique. All commands print some help text with
.B quilt cmd -h.
Quilt manages a stack of patches. Patches are applied incrementally on top
of the base tree plus all preceding patches. They can be pushed on top of
the stack
.RB ( "quilt push" ),
and popped off the stack
.RB ( "quilt pop" ).
Commands are available for querying the contents of the series file
.RB ( "quilt series" ,
see below), the contents of the stack
.RB ( "quilt applied" , " quilt previous" , " quilt top" ),
and the patches that are not applied at a particular moment
.RB ( "quilt next" , " quilt unapplied" ).
By default, most commands apply to the topmost patch on the stack.
Patch files are located in the
.I patches
sub-directory of the source tree (see EXAMPLE OF WORKING TREE below). The
.I QUILT_PATCHES
environment variable can be used to override this location. When not
found in the current directory, that subdirectory is searched
recursively in the parent directories (this is similar to the way
.I git
searches for its configuration files). The
.I patches
directory may contain sub-directories. It may also be a symbolic link
instead of a directory.
A file called
.I series
contains a list of patch file names that defines the order in which patches
are applied. Unless there are means by which series files can be generated
automatically, it is usually provided along with a set of patches. In this
file, each patch file name is on a separate line. Patch files are identified
by path names that are relative to the
.I patches
directory; patches may be in sub-directories below this directory. Lines
in the series file that start with a hash character (#) are ignored.
You can also add a comment after each patch file name, introduced by a
space followed by a hash character. When
quilt adds, removes, or renames patches, it automatically updates the series
file. Users of quilt can modify series files while some patches are
applied, as long as the applied patches remain in their original order.
Different series files can be used to assemble patches in different ways,
corresponding for example to different development branches.
Before a patch is applied (or ``pushed on the stack''), copies of all files
the patch modifies are saved to the
.RI .pc/ patch
directory. The patch is added to the list of currently applied patches
(.pc/applied-patches). Later when a patch is regenerated
.RB ( "quilt refresh" ),
the backup copies in
.RI .pc/ patch
are compared with the current versions of the files in the source tree using
GNU diff.
Documentation related to a patch can be put at the beginning of a patch
file. Quilt is careful to preserve all text that precedes the actual patch
when doing a refresh. (This is limited to patches in unified format; see
.B diff
documentation).
The series file is looked up in the .pc directory, in the root of the source
tree, and in the patches directory. The first series file that is found is
used. This may also be a symbolic link, or a file with multiple hard links.
Usually, only one series file is used for a set of patches, so the
patches sub-directory is a convenient location.
The .pc directory and its sub-directories cannot be relocated, but it can be
a symbolic link. While patches are applied to the source tree, this
directory is essential for many operations, including taking patches off the
stack
.RB ( "quilt pop" ),
and refreshing patches
.RB ( "quilt refresh" ).
Files in the .pc directory are automatically removed when they are
no longer needed, so there is no need to clean up manually.
.SH QUILT COMMANDS REFERENCE
@REFERENCE@
.SH COMMON OPTIONS TO ALL COMMANDS
.IP \"\\fB--trace\\fP\" 8
Runs the command in bash trace mode (-x). For internal debugging.
.IP \"\\fB--quiltrc\\fP file\" 8
Use the specified configuration file instead of ~/.quiltrc (or
/etc/quilt.quiltrc if ~/.quiltrc does not exist). See the pdf
documentation for details about its possible contents. The
special value \"-\" causes quilt not to read any configuration
file.
.IP \"\\fB--version\\fP\" 8
Print the version number and exit immediately.
.SH EXIT STATUS
The exit status is 0 if the sub-command was successfully executed, and
1 in case of error.
An exit status of 2 denotes that quilt did not do anything to complete
the command. This happens in particular when asking to push when the
whole stack is already pushed, or asking to pop when the whole stack
is already popped. This behavior is intended to ease the scripting
around quilt.
.SH EXAMPLE OF WORKING TREE
.fam C
.RS
.nf
work/
├── patches/
│ ├── series (list of patches to apply)
│ ├── patch1.diff (one particular patch)
│ ├── patch2.diff
│ └── ...
├── .pc/
│ ├── .quilt_patches (content of QUILT_PATCHES)
│ ├── .quilt_series (content of QUILT_SERIES)
│ ├── patch1.diff/ (copy of patched files)
│ │ └── ...
│ ├── patch2.diff/
│ │ └── ...
│ └── ...
└── ...
.fi
.RE
.fam T
The patches/ directory is precious as it contains all your patches as
well as the order in which it should be applied.
The .pc/ directory contains some metadata about the current state of
your patch serie. Changing its content is not advised. This directory
can usually be regenerated from the initial files and the
content of the patches/ directory (provided that all patches were
regenerated before the removal).
.SH EXAMPLE
Please refer to the pdf documentation for a full example of use.
.SH CONFIGURATION FILE
Upon startup, quilt evaluates the file .quiltrc in the user's home
directory, or the file specified with the --quiltrc option. This file
is a regular bash script. Default options can be passed to any COMMAND
by defining a QUILT_${COMMAND}_ARGS variable. For example,
QUILT_DIFF_ARGS="--color=auto" causes the output of quilt diff to be
syntax colored when writing to a terminal.
In addition to that, quilt recognizes the following variables:
.IP EDITOR 4
The program to run to edit files. If it isn't redefined in the
configuration file, $EDITOR as defined in the environment will be used.
.IP LESS 4
The arguments used to invoke the pager. Inherits the existing value
of $LESS if LESS is already set in the environment, otherwise defaults
to "-FRSX".
.IP QUILT_DIFF_OPTS 4
Additional options that quilt shall pass to GNU diff when generating
patches. A useful setting for C source code is "-p", which causes GNU diff
to show in the resulting patch which function a change is in.
.IP QUILT_PATCH_OPTS 4
Additional options that quilt shall pass to GNU patch when applying
patches. For example, recent versions of GNU patch support the
"--reject-format=unified" option for generating reject files in unified
diff style (older patch versions used "--unified-reject-files" for that).
You may also want to add the "-E" option if you have issues with quilt
not deleting empty files when you think it should. The documentation of
GNU patch says that "normally this option is unnecessary", but when patch
is in POSIX mode or if the patch format doesn't allow to distinguish
empty files from deleted files, patch deletes empty files only if the
-E option is given. Beware that when passing -E to patch, quilt will
no longer be able to deal with empty files, which is why using -E is
no longer the default.
.IP QUILT_DIFFSTAT_OPTS 4
Additional options that quilt shall pass to diffstat when generating
patch statistics. For example, "-f0" can be used for an alternative output
format. Recent versions of diffstat also support alternative rounding
methods ("-r1", "-r2").
.IP QUILT_PC 4
The location of backup files and any other data relating to the current
state of the working directory from quilt's perspective. Defaults to ".pc".
.IP QUILT_PATCHES 4
The location of patch files, defaulting to "patches".
.IP QUILT_SERIES 4
The name of the series file, defaulting to "series". Unless an absolute path
is used, the search algorithm described above applies.
.IP QUILT_PATCHES_PREFIX 4
If set to anything, quilt will prefix patch names it prints with their
directory (QUILT_PATCHES).
.IP QUILT_NO_DIFF_INDEX 4
By default, quilt prepends an Index: line to the patches it generates.
If this variable is set to anything, no line is prepended. This is
a shortcut to adding --no-index to both QUILT_DIFF_ARGS and
QUILT_REFRESH_ARGS.
.IP QUILT_NO_DIFF_TIMESTAMPS 4
By default, quilt includes timestamps in headers when generating patches.
If this variable is set to anything, no timestamp will be included. This
is a shortcut to adding --no-timestamps to both QUILT_DIFF_ARGS and
QUILT_REFRESH_ARGS.
.IP QUILT_PAGER 4
The pager quilt shall use for commands which produce paginated output. If
unset, the values of GIT_PAGER or PAGER is used. If none of these variables
is set, "less -R" is used. An empty value indicates that no pager should be
used.
.IP QUILT_COLORS 4
By default, quilt uses its predefined color set in order to be more
comprehensible when distiguishing various types of patches, eg.
applied/unapplied, failed, etc.
To override one or more color settings, set the QUILT_COLORS variable in
following syntax - colon (:) separated list of elements, each being of the
form <format name>=<foreground color>[;<background color>]
Format names with their respective default values are listed below,
along with their usage(s).
Color codes(values) are standard bash coloring escape codes.
See more at http://tldp.org/LDP/abs/html/colorizing.html#AEN20229
.RS 4
.IP \\fBdiff_hdr\\fP 10
Used in 'quilt diff' to color the index line. Defaults to 32 (green).
.IP \\fBdiff_add\\fP 10
Used in 'quilt diff' to color added lines. Defaults to 36 (azure).
.IP \\fBdiff_mod\\fP 10
Used in 'quilt diff' to color modified lines. Defaults to 35 (purple).
.IP \\fBdiff_rem\\fP 10
Used in 'quilt diff' to color removed lines. Defaults to 35 (purple).
.IP \\fBdiff_hunk\\fP 10
Used in 'quilt diff' to color hunk header. Defaults to 33 (brown/orange).
.IP \\fBdiff_ctx\\fP 10
Used in 'quilt diff' to color the text after end of hunk header (diff --show-c-function generates this). Defaults to 35 (purple).
.IP \\fBdiff_cctx\\fP 10
Used in 'quilt diff' to color the 15-asterisk sequence before or after a hunk. Defaults to 33 (brown/orange).
.IP \\fBpatch_fuzz\\fP 10
Used in 'quilt push' to color the patch fuzz information. Defaults to 35 (purple).
.IP \\fBpatch_fail\\fP 10
Used in 'quilt push' to color the fail message. Defaults to 31 (red).
.IP \\fBseries_app\\fP 10
Used in 'quilt series' and 'quilt patches' to color the applied patch names. Defaults to 32 (green).
.IP \\fBseries_top\\fP 10
Used in 'quilt series' and 'quilt patches' to color the top patch name. Defaults to 33 (brown/orange).
.IP \\fBseries_una\\fP 10
Used in 'quilt series' and 'quilt patches' to color unapplied patch names. Defaults to 0 (no special color).
.RE
.RS 4
In addition, the \\fBclear\\fP format name is used to turn off special
coloring. Its value is 0; it is not advised to modify it.
The content of QUILT_COLORS supersedes default values. So the value
diff_hdr=35;44 will get you the diff headers in magenta over blue
instead of the default green over unchanged background. For that, add
the following content to ~/.quiltrc (or /etc/quilt.quiltrc):
.nf
QUILT_DIFF_ARGS="--color"
QUILT_COLORS='diff_hdr=35;44'
.fi
.RE 4
.SH AUTHORS
Quilt started as a series of scripts written by Andrew Morton
(patch-scripts). Based on Andrew's ideas, Andreas Gruenbacher completely
rewrote the scripts, with the help of several other contributors (see
AUTHORS file in the distribution).
This man page was written by Martin Quinson, based on information found in
the pdf documentation, and in the help messages of each commands.
.SH SEE ALSO
The pdf documentation, which should be under @DOCSUBDIR@/quilt.pdf.
Note that some distributors compress this file.
.BR zxpdf ( 1 )
can be used to display compressed pdf files.
.BR diff ( 1 ),
.BR patch ( 1 ),
.BR guards ( 1 ).

BIN
doc/quilt.pdf Normal file

Binary file not shown.

11
git-desc Executable file
View File

@ -0,0 +1,11 @@
#! /bin/sh
if git rev-parse --show-cdup > /dev/null 2> /dev/null; then
tag=$(git describe --tags HEAD 2> /dev/null || \
git rev-parse --short HEAD)
dirty=$(git update-index --refresh --unmerged > /dev/null
if git diff-index --name-only HEAD | read dummy; then
echo -dirty
fi)
echo $tag$dirty
fi

591
lib/quilt.el Normal file
View File

@ -0,0 +1,591 @@
;;; quilt.el --- a minor mode for working with files in quilt
;; Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
;; Satoru Takeuchi <satoru.takeuchi@gmail.com> took over this package
;; from Matt Mackall.
;; Author: Saotru takeuchi <satoru.takeuchi@gmail.com>
;;
;; This software may be used and distributed according to the terms
;; of the GNU General Public License, incorporated herein by reference.
;;; Commentary:
;;
;; Add (load "~/quilt.el") to your .emacs file
;;; History:
;;
;;; Code:
(defun quilt-buffer-file-name-safe ()
"Return buffer file name. If buffer is not associated with any file, return nil."
(let ((fn buffer-file-name))
(if (and fn (file-exists-p fn))
fn)))
(defun quilt-bottom-p ()
"Return t if there is on the bottom of patch stack, return nil if otherwise."
(if (> (call-process "quilt" nil nil nil "applied") 0) 1))
(defun quilt-patches-directory ()
"Return the location of patch files."
(or (with-current-buffer (generate-new-buffer " *cmd")
(shell-command
(concat "test -f ~/.quiltrc && . ~/.quiltrc ;"
"echo -n $QUILT_PATCHES")
t)
(unwind-protect
(let ((v (buffer-string)))
(if (string= "" (buffer-string))
nil
v))
(kill-buffer (current-buffer))))
(or (getenv "QUILT_PATCHES")
"patches")))
(defun quilt-pc-directory ()
"Return the location of patch files."
(or (with-current-buffer (generate-new-buffer " *cmd")
(shell-command
(concat "test -f ~/.quiltrc && . ~/.quiltrc ;"
"echo -n $QUILT_PC")
t)
(unwind-protect
(let ((v (buffer-string)))
(if (string= "" (buffer-string))
nil
v))
(kill-buffer (current-buffer))))
(or (getenv "QUILT_PC")
".pc")))
(defun quilt-find-dir (fn &optional prefn)
"Return the top level dir of quilt from FN."
(if (or (not fn) (equal fn "/") (equal fn prefn))
nil
(let ((d (file-name-directory fn)))
(if (file-accessible-directory-p (concat d "/" (quilt-pc-directory)))
d
(quilt-find-dir (directory-file-name d) d)))))
(defun quilt-dir (&optional fn)
"Return the top level dir of quilt from FN. FN is just a hint and find from other way if FN is nil."
(quilt-find-dir (if fn fn
(let ((fn2 (quilt-buffer-file-name-safe)))
(if fn2 fn2
(if default-directory
(expand-file-name default-directory)))))))
(defun quilt-drop-dir (fn)
"Return the relative path of FN based on quilt top directory."
(let ((d (quilt-find-dir fn)))
(substring fn (length d) (length fn))))
(defun quilt-p (&optional fn)
"Check if FN is in a quilt tree."
(if (quilt-dir fn) 't nil))
(defun quilt-save ()
"Save all buffers associated with current quilt tree."
(save-some-buffers nil 'quilt-p))
(defun quilt-owned-p (fn)
"Check if FN is a file which quilt handles."
(if (not fn)
nil
(let ((pd (file-name-nondirectory
(directory-file-name (file-name-directory fn)))))
(and
(not (string-match "\\(~$\\|\\.rej$\\)" fn))
(not (equal pd (quilt-patches-directory)))
(not (equal pd (quilt-pc-directory)))
(quilt-p fn)))))
(defun quilt-cmd (cmd &optional buf)
"Execute CMD, a quilt subcommand, at the top of quilt tree associated with BUF."
(let ((d default-directory)
(qd (quilt-dir)))
(if (not qd)
(shell-command (concat "quilt " cmd) buf)
(cd qd)
(unwind-protect ; make sure to cd back even if an erro occurs.
(shell-command (concat "quilt " cmd) buf)
(cd d)))))
(defun quilt-cmd-to-string (cmd)
"Execute CMD, a quilt subcommand, at the top of quilt tree associated with BUF and return its output string."
(let ((d default-directory)
(qd (quilt-dir)))
(if (not qd)
nil
(cd qd)
(unwind-protect ; make sure to cd back even if an error occurs.
(shell-command-to-string (concat "quilt " cmd))
(cd d)))))
(defun quilt-cmd-to-list (cmd)
"Execute CMD, a quilt sumcommand at the top of quilt tree associated with BUF.."
"Return the lines of the command output as elements of a list."
(let ((s (quilt-cmd-to-string cmd)))
(if s
(split-string s "\n" t))))
(defun quilt-applied-list ()
"Return the list of the applied patch names."
(quilt-cmd-to-list "applied"))
(defun quilt-file-list ()
"Return the list of the file names associated with current patch."
(quilt-cmd-to-list "files"))
(defun quilt-patch-list ()
"Return the list of the name of patches."
(quilt-cmd-to-list "series"))
(defun quilt-files-affected (&optional first last)
"Return the file names which modified from FIRST to LAST."
"Omitted args are considered as current patch."
(let ((qd (quilt-dir))
files fp)
(when qd
(setq files (quilt-cmd-to-list
(if last
(if (equal first last)
(concat "files " first)
(concat "files --combine " first last))
(if first
(concat "files --combine " first)
"files"))))
(setq fp files)
(while fp
(setcar fp (concat qd (car fp)))
(setq fp (cdr fp)))
files)))
(defun quilt-top-patch ()
"Return the top patch name. return nil if there is the bottom of patch stack."
(if (quilt-bottom-p)
nil
(substring (quilt-cmd-to-string "top") 0 -1)))
(defun quilt-complete-list (p l)
"Call 'completing-read' with prompt P and list L."
"Convert L to an alist using indices as keys. Note that this function modifies L."
(let ((list l)
(n 0))
(while list
(setcar list (cons (car list) n))
(setq list (cdr list))
(setq n (1+ n))))
(completing-read p l nil t))
(defvar quilt-edit-top-only 't)
(defun quilt-editable (f)
"Return t if F is editable in terms of current patch. Return nil if otherwise."
(let ((qd (quilt-dir))
(fn (quilt-drop-dir f))
dirs result)
(if qd
(if (quilt-bottom-p)
(quilt-cmd "applied") ; to print error message
(setq dirs (if quilt-edit-top-only
(list (substring (quilt-cmd-to-string "top") 0 -1))
(cdr (cdr (directory-files (concat qd (quilt-pc-directory) "/"))))))
(while (and (not result) dirs)
(if (file-exists-p (concat qd (quilt-pc-directory) "/" (car dirs) "/" fn))
(setq result t)
(setq dirs (cdr dirs))))
result))))
(defun quilt-short-patchname ()
"Return shortened name of top patch. Return \"none\" when on the bottom patch stack."
(let ((p (quilt-top-patch)))
(if (not p)
"none"
(let ((p2 (file-name-sans-extension (file-name-nondirectory p))))
(if (< (length p2) 10)
p2
(concat (substring p2 0 8) ".."))))))
(defvar quilt-mode-line nil)
(make-variable-buffer-local 'quilt-mode-line)
(defun quilt-update-modeline ()
"Update mode line."
(interactive)
(setq quilt-mode-line
(concat " Q:" (quilt-short-patchname)))
(force-mode-line-update))
(defun quilt-revert (filelist)
"Refresh contents, editability and modeline of FILESIT.
FILELIST won't be touched unless their file is a child of the
current quilt directory. Each elements in FILELIST should be the absolute
file names of those files affected by the latest quilt
operation. Associated buffers get reverted to update their
contents. Other buffers will only get their modeline and
editability adjusted."
(let ((qd (quilt-dir))
fn)
(dolist (buf (buffer-list))
(if (not (string-match "^ " (buffer-name buf)))
(with-current-buffer buf
(setq fn (quilt-buffer-file-name-safe))
(when (string-equal qd (quilt-dir))
(quilt-update-modeline)
(when (and (not (buffer-modified-p))
(quilt-owned-p fn))
;; If the file doesn't exist on disk it can't be reverted, but we
;; need the revert hooks to run anyway so that the buffer's
;; editability will update. Files not affected by the latest change
;; (as listed in filelist) don't need to get reverted either.
(if (and (file-exists-p buffer-file-name)
(member fn filelist))
(progn
(revert-buffer t t t))
(run-hooks 'after-revert-hook)))))))))
(defun quilt-push (arg)
"Push next patch. It is forced if ARG is specified."
(interactive "P")
(quilt-save)
(if arg
(quilt-cmd "push -f" "*quilt*")
(quilt-cmd "push -q"))
(quilt-revert (quilt-files-affected)))
(defun quilt-pop (arg)
"Pop top patch. It is forced if ARG is specified."
(interactive "P")
(quilt-save)
(if arg
(quilt-cmd "pop -f")
(quilt-cmd "pop -q"))
(quilt-revert (quilt-files-affected)))
(defun quilt-push-all (arg)
"Push all remaining patches. It is forced if ARG is specified."
(interactive "P")
(quilt-save)
(let ((next (car (quilt-cmd-to-list "next"))))
(if arg
(quilt-cmd "push -f" "*quilt*")
(quilt-cmd "push -qa"))
(quilt-revert (quilt-files-affected next))))
(defun quilt-pop-all (arg)
"Pop all applied patches. It is forced if ARG is specified."
(interactive "P")
(quilt-save)
(let ((fa (quilt-files-affected "-")))
(if arg
(quilt-cmd "pop -af")
(quilt-cmd "pop -qa"))
(quilt-revert fa)))
(defun quilt-goto ()
"Go to a specified patch."
(interactive)
(let ((qd (quilt-dir)))
(if (not qd)
(quilt-cmd "push") ; to print error message
(let ((arg (quilt-complete-list "Goto patch: " (quilt-patch-list))))
(if (string-equal arg "")
(message "no patch name is supplied")
(quilt-save)
(let (cmd first last)
(if (file-exists-p (concat qd (quilt-pc-directory) "/" arg))
(progn
(setq cmd "pop")
(setq first (car (quilt-cmd-to-list (concat "next " arg))))
(setq last (quilt-top-patch)))
(setq cmd "push")
(setq last arg)
(setq first (if (quilt-bottom-p)
"-"
(car (quilt-cmd-to-list "next")))))
(quilt-cmd (concat cmd " -q " arg) "*quilt*")
(quilt-revert (quilt-files-affected first last))))))))
(defun quilt-top ()
"Display topmost patch."
(interactive)
(quilt-cmd "top"))
(defun quilt-find-file ()
"Find a file in the topmost patch."
(interactive)
(let ((qd (quilt-dir)))
(if (not qd)
(quilt-cmd "push") ; to print error message
(if (quilt-bottom-p)
(quilt-cmd "applied") ; to print error message
(let ((l (quilt-file-list)))
(if (not l)
(message "no file is existed in this patch")
(let ((f (quilt-complete-list "File: " l)))
(if (string-equal f "")
(message "file name is not specified")
(find-file (concat qd f))))))))))
(defun quilt-files ()
"Display files in topmost patch."
(interactive)
(quilt-cmd "files"))
(defun quilt-import (fn pn)
"Import external patch FN as PN.patch."
(interactive "fPatch to import: \nsPatch name: ")
(if (not pn)
(message "no patch name supplied")
(quilt-cmd (concat "import -p " pn ".patch " (if fn fn pn)))))
(defun quilt-diff ()
"Display the diff of current change."
(interactive)
(quilt-save)
(quilt-cmd "diff" "*diff*"))
(defun quilt-new (f)
"Create a new patch F.patch."
(interactive "sPatch name: ")
(if (string-equal f "")
(message "no patch name is supplied")
(quilt-save)
(quilt-cmd (concat "new " f ".patch"))
(quilt-revert nil)))
(defun quilt-applied ()
"Show applied patches."
(interactive)
(quilt-cmd "applied" "*quilt*"))
(defun quilt-add (arg)
"Add ARG to the current patch."
(interactive "b")
(with-current-buffer arg
(let ((fn (quilt-buffer-file-name-safe)))
(cond
((not fn)
(message "buffer %s is not associated with any buffer" (buffer-name)))
((not (quilt-dir))
(quilt-cmd (concat "push"))) ; to print error message
(t
(quilt-cmd (concat "add " (quilt-drop-dir fn)))
(quilt-revert (list fn)))))))
(defun quilt-edit-patch ()
"Edit the topmost patch."
(interactive)
(let ((qd (quilt-dir)))
(if (not qd)
(quilt-cmd "push") ; to print error message
(let ((patch (quilt-top-patch)))
(if (not patch)
(quilt-cmd "applied") ; to print error message
(quilt-save)
(let ((pf (concat qd
(format "/%s/" (quilt-patches-directory))
patch)))
(if (file-exists-p pf)
(progn (find-file pf)
(read-only-mode 0))
(message (format "%s doesn't exist yet." pf)))))))))
(defun quilt-patches ()
"Show which patches modify the current buffer."
(interactive)
(let ((fn (quilt-buffer-file-name-safe)))
(cond
((not fn)
(message "buffer %s is not associated with any buffer" (buffer-name)))
((not (quilt-dir))
(quilt-cmd "push")) ; to print error message
(t
(quilt-cmd (concat "patches " (quilt-drop-dir fn)))))))
(defun quilt-unapplied ()
"Display unapplied patch list."
(interactive)
(quilt-cmd "unapplied" "*quilt*"))
(defun quilt-refresh ()
"Refresh the current patch."
(interactive)
(quilt-save)
(quilt-cmd "refresh"))
(defun quilt-remove ()
"Remove a file from the current patch and revert it."
(interactive)
(let ((f (quilt-buffer-file-name-safe)))
(cond
((not f)
(message "buffer %s is not associated with any patch" (buffer-name)))
((not (quilt-dir))
(quilt-cmd "push")) ; to print error message
(t
(if (quilt-bottom-p)
(quilt-cmd "applied") ; to print error message
(let ((dropped (quilt-drop-dir f)))
(if (y-or-n-p (format "Really drop %s? " dropped))
(progn
(quilt-cmd (concat "remove " dropped))
(quilt-revert (list f))))))))))
(defun quilt-edit-series ()
"Edit the patch series file."
(interactive)
(let ((qd (quilt-dir)))
(if (not qd)
(quilt-cmd "push") ; to print error message
(let ((series (concat qd
(format "/%s/series" (quilt-patches-directory)))))
(if (file-exists-p series)
(find-file series)
(message (quilt-top-patch)))))))
(defun quilt-header (arg)
"Print the header of ARG."
(interactive "P")
(let ((qd (quilt-dir)))
(if (not qd)
(quilt-cmd "push") ; to print error message
(if (not arg)
(quilt-cmd "header")
(let ((p (quilt-complete-list "Patch: " (quilt-patch-list))))
(if (string-equal p "")
(message "no patch name is supplied")
(quilt-cmd (concat "header " p))))))))
(defun quilt-delete (arg)
"Delete ARG from the series file."
(interactive "P")
(let ((qd (quilt-dir)))
(if (not qd)
(quilt-cmd "push") ; to print error message
(let ((p (if arg
(quilt-complete-list "Delete patch: " (quilt-patch-list))
(quilt-top-patch))))
(if (string-equal p "")
(message "no patch name is supplied")
(if (not p)
(quilt-cmd "applied") ; to print error message
(if (y-or-n-p (format "Really delete %s? " p))
(let ((fa (quilt-files-affected p p)))
(quilt-save)
(quilt-cmd (concat "delete " p))
(quilt-revert fa)))))))))
(defvar quilt-header-directory nil)
(defun quilt-header-commit ()
"Commit to change patch header."
(interactive)
(let ((tmp (make-temp-file "quilt-header-")))
(set-visited-file-name tmp)
(basic-save-buffer)
(cd quilt-header-directory)
(shell-command (concat "EDITOR=cat quilt -r header <" tmp))
(kill-buffer (current-buffer))
(delete-file tmp)))
(defvar quilt-header-mode-map (make-keymap))
(define-key quilt-header-mode-map "\C-c\C-c" 'quilt-header-commit)
(defun quilt-edit-header (arg)
"Edit the header of ARG."
(interactive "P")
(let ((qd (quilt-dir)))
(if (not qd)
(quilt-cmd "push") ; to print error message
(let ((p (if arg
(quilt-complete-list "Edit patch: " (quilt-patch-list))
(quilt-top-patch))))
(if (string-equal p "")
(message "no patch name is supplied")
(if (not p)
(quilt-cmd "applied") ; to print error message
(let ((qb (get-buffer-create (format " *quilt-header(%s)*" p))))
(switch-to-buffer-other-window qb)
(erase-buffer)
(kill-all-local-variables)
(make-local-variable 'quilt-header-directory)
(setq quilt-header-directory default-directory)
(use-local-map quilt-header-mode-map)
(setq major-mode 'quilt-header-mode)
(call-process "quilt" nil qb nil "header" p)
(goto-char 0))))))))
(defun quilt-series (arg)
"Show patche series. It can be verbose mode if ARG is specified."
(interactive "P")
(if arg
(quilt-cmd "series -v")
(quilt-cmd "series")))
(defvar quilt-mode-map (make-sparse-keymap))
(define-key quilt-mode-map "\C-c.t" 'quilt-top)
(define-key quilt-mode-map "\C-c.f" 'quilt-find-file)
(define-key quilt-mode-map "\C-c.F" 'quilt-files)
(define-key quilt-mode-map "\C-c.d" 'quilt-diff)
(define-key quilt-mode-map "\C-c.p" 'quilt-push)
(define-key quilt-mode-map "\C-c.o" 'quilt-pop)
(define-key quilt-mode-map "\C-c.P" 'quilt-push-all)
(define-key quilt-mode-map "\C-c.O" 'quilt-pop-all)
(define-key quilt-mode-map "\C-c.g" 'quilt-goto)
(define-key quilt-mode-map "\C-c.A" 'quilt-applied)
(define-key quilt-mode-map "\C-c.n" 'quilt-new)
(define-key quilt-mode-map "\C-c.i" 'quilt-import)
(define-key quilt-mode-map "\C-c.a" 'quilt-add)
(define-key quilt-mode-map "\C-c.e" 'quilt-edit-patch)
(define-key quilt-mode-map "\C-c.m" 'quilt-patches)
(define-key quilt-mode-map "\C-c.u" 'quilt-unapplied)
(define-key quilt-mode-map "\C-c.r" 'quilt-refresh)
(define-key quilt-mode-map "\C-c.R" 'quilt-remove)
(define-key quilt-mode-map "\C-c.s" 'quilt-series)
(define-key quilt-mode-map "\C-c.S" 'quilt-edit-series)
(define-key quilt-mode-map "\C-c.h" 'quilt-header)
(define-key quilt-mode-map "\C-c.H" 'quilt-edit-header)
(define-key quilt-mode-map "\C-c.D" 'quilt-delete)
(defvar quilt-mode nil)
(make-variable-buffer-local 'quilt-mode)
(defun quilt-mode (&optional arg)
"Toggle 'quilt-mode'. Enable 'quilt-mode' if ARG is positive.
\\{quilt-mode-map}"
(interactive "P")
(setq quilt-mode
(if (null arg)
(not quilt-mode)
(> (prefix-numeric-value arg) 0)))
(if quilt-mode
(let ((f (quilt-buffer-file-name-safe)))
(if (quilt-owned-p f)
(if (not (quilt-editable f))
(read-only-mode 1)
(read-only-mode 0)))
(quilt-update-modeline))))
(defun quilt-hook ()
"Enable quilt mode for quilt-controlled files."
(if (quilt-p) (quilt-mode 1)))
(add-hook 'find-file-hooks 'quilt-hook)
(add-hook 'after-revert-hook 'quilt-hook)
(or (assq 'quilt-mode minor-mode-alist)
(setq minor-mode-alist
(cons '(quilt-mode quilt-mode-line) minor-mode-alist)))
(or (assq 'quilt-mode-map minor-mode-map-alist)
(setq minor-mode-map-alist
(cons (cons 'quilt-mode quilt-mode-map) minor-mode-map-alist)))
(provide 'quilt)
;;; quilt.el ends here

1807
po/de.po Normal file

File diff suppressed because it is too large Load Diff

1806
po/fr.po Normal file

File diff suppressed because it is too large Load Diff

1754
po/ja.po Normal file

File diff suppressed because it is too large Load Diff

1236
po/quilt.pot Normal file

File diff suppressed because it is too large Load Diff

1760
po/ru.po Normal file

File diff suppressed because it is too large Load Diff

35
quilt.quiltrc Normal file
View File

@ -0,0 +1,35 @@
# Example /etc/quilt.quiltrc
# Options passed to GNU diff when generating patches
QUILT_DIFF_OPTS="--show-c-function"
# Options passed to GNU patch when applying patches
#QUILT_PATCH_OPTS="--ignore-whitespace"
# Options passed to diffstat when generating patch statistics
#QUILT_DIFFSTAT_OPTS="-f0"
# Options to pass to commands (QUILT_${COMMAND}_ARGS)
QUILT_PUSH_ARGS="--color=auto"
QUILT_DIFF_ARGS="--no-timestamps --color=auto"
QUILT_REFRESH_ARGS="--no-timestamps --backup"
QUILT_SERIES_ARGS="--color=auto"
QUILT_PATCHES_ARGS="--color=auto"
# When non-default less options are used, add the -R option so that less outputs
# ANSI color escape codes "raw".
[ -n "$LESS" -a -z "${QUILT_PAGER+x}" ] && QUILT_PAGER="less -FRX"
# (Add "-p ab" to QUILT_DIFF_ARGS and QUILT_REFRESH_ARGS to get
# -p1 style diffs with a/file and b/file filenams in headers
# instead of dir.orig/file and dir/file.)
# The directory in which patches are found (defaults to "patches").
#QUILT_PATCHES=patches
# Prefix all patch names with the relative path to the patch?
QUILT_PATCHES_PREFIX=yes
# Use a specific editor for quilt (defaults to the value of $EDITOR before
# sourcing this configuration file, or vi if $EDITOR wasn't set).
#EDITOR=nedit

304
quilt.spec Normal file
View File

@ -0,0 +1,304 @@
#
# spec file for quilt - patch management scripts
#
Name: quilt
Summary: Scripts for working with series of patches
License: GPL
Group: Productivity/Text/Utilities
Version: 0.66
Release: 1
Requires: coreutils diffutils findutils patch gzip bzip2 perl mktemp gettext
Autoreqprov: off
Source: quilt-%{version}.tar.gz
BuildRoot: %{_tmppath}/%{name}-%{version}-build
%description
The scripts allow to manage a series of patches by keeping
track of the changes each patch makes. Patches can be
applied, un-applied, refreshed, etc.
The scripts are heavily based on Andrew Morton's patch scripts
found at http://userweb.kernel.org/~akpm/stuff/patch-scripts.tar.gz.
Authors:
--------
Andrew Morton <akpm@digeo.com>
Andreas Gruenbacher <agruen@suse.de>
%prep
%setup
%build
CFLAGS="$RPM_OPT_FLAGS" \
./configure --prefix=/usr \
--mandir=%_mandir \
--docdir=%_docdir/%{name}-%{version}
make RELEASE=%release
%install
rm -rf $RPM_BUILD_ROOT
make install prefix=/usr BUILD_ROOT=$RPM_BUILD_ROOT
%{find_lang} %{name}
%clean
rm -rf $RPM_BUILD_ROOT
%files -f %{name}.lang
%defattr(-, root, root)
/usr/bin/guards
/usr/bin/quilt
/usr/share/quilt/
/usr/share/emacs/
/etc/bash_completion.d/quilt
%config(noreplace) /etc/quilt.quiltrc
%doc %{_mandir}/man1/guards.1*
%doc %{_mandir}/man1/quilt.1*
%doc %{_docdir}/%{name}-%{version}/README
%doc %{_docdir}/%{name}-%{version}/README.MAIL
%doc %{_docdir}/%{name}-%{version}/quilt.pdf
%changelog
* Thu Mar 28 2019 - upstream
- Update to version 0.66
+ Add support for lzip archives and patches (#54570)
+ Document QUILT_PC as user-settable
+ configure: Don't require md5sum
+ Test suite: Allow keeping the working directory on failure
+ Test suite: Fix regex for recent versions of perl
+ Test suite: Fix /bin/sh filtering
+ Test suite: Run tests again if test.quiltrc changes
+ Test suite: Handle alternative QUILT_PATCHES values
+ Test suite: Increase code path coverage
+ Test suite: Be verbose on directory error
+ Test suite: Clean up when interrupted
+ Test suite: Prevent test cases from escaping
+ fold: Fix German translation
+ diff: Add missing quotes in basename call (#50862)
+ header: Fix corruption when trailing newline is missing (#50841)
+ mail: Fix patch set threading (#50775)
+ mail: Fix French translation
+ mail: Remove Content-Disposition headers
+ mail: Complain when a patch doesn't exist
+ new: Fix corruption when trailing newline is missing (#54295)
+ refresh: Add missing quotes in basename call (#50862)
+ setup: Add basic support for p7zip (.7z) archives (#49754)
+ setup: Align --fast on --slow for series files
+ quilt.el: Define quilt-edit-top-only before it's used
+ quilt.el: Stop using deprecated toggle-read-only
+ quilt.el: Don't strip directory in quilt-top-patch
+ quilt.el: Fix emacs compatibility issue (#51977)
+ quilt.el: Read QUILT_PC from config file
+ quiltrc: Support all patch formats by default
+ guards: Mention it in quilt manual page
+ compat/getopt: Handle a second separator (#54772)
+ compat/getopt: Allow non-digit parameter embedded in short option (#54772)
* Wed Oct 09 2016 - upstream
- Update to version 0.65
+ Translation fixes
+ Project settings have priority
+ Reject binary files in patches
+ Fix a race condition in diff_file
+ Performance: Optimizations to the setup command
+ Performance: Optimizations to the bash completion script
+ Test suite: Improve the edit test case
+ Test suite: Make the symlink test more robust
+ Test suite: Test backup failure
+ Test suite: Test the header command with hard links
+ diff: Report diff failures
+ edit: Fix a corner case bug
+ mail: Fix the help text
+ push: Fix the synopsis
+ refresh: Do not remove symlinks
+ refresh: Break links to read-only patch files
+ refresh: Always preserve modification time
+ setup: Report failed look-ups in inspect-wrapper
+ quilt.el: Fix quilt-editable when patches are stored in subdirs
+ bash_completion: Handle spaces in file names
+ bash_completion: Update the list of commands
+ bash_completion: Add new command options
+ bash_completion: Fix handling of mail, new, push options
+ guards: Simplify the help text
+ guards: Include the file name also in the "Not found" case
+ guards: Add support for an external filelist in --check mode
+ guards: Report which config file has problem in --check mode
+ guards: Documentation update
+ guards: Clarify a user message
* Mon Feb 09 2015 - upstream
- Update to version 0.64
+ Check for series file consistency
+ Performance: Several optimizations
+ Test suite: Several fixes and coverage improvements
+ Test suite: Run the tests in predictable order
+ files: Add support for unapplied patches
+ graph: Check for graphviz availability
+ mail: Remove procmail dependency
+ mail: Don't include the release number in User-Agent
+ pop: Add --refresh option
+ push: Add --refresh option
+ push: Do not use interactive mode with -f
+ setup: Skip version check
+ setup: Check for rpmbuild availability
+ setup: Handle long options passed to tar
+ setup: Several cleanups and minor fixes
+ setup: Major performance optimizations
+ setup: Fix path to extra patches in series file
+ setup: Trace calls earlier
+ setup: Add --fast option
+ setup: Fix link creation
+ quilt.el: Fix tramp support
+ quilt.el: Fix patch select completion
* Sun May 25 2014 - upstream
- Update to version 0.63
+ New NEWS file, containing a human-readable changelog
+ Option -E is no longer passed to patch by default
+ Huge performance improvement (e.g., for commands series, applied and
unapplied)
+ configure: Add compat symlinks for md5sum
+ Return 2 when there is nothing to do, contrasting with errors (ret=1)
+ Exit with an error when diff's retcode=2 (error) on patch refresh
+ bash_completion: cleanups and performance improvement (Savannah's #27111)
+ test/run: Use perl module Text::ParseWords (+ performance improvement)
+ Add some tests to our testsuite, for a better coverage
+ Fix heuristic for unapplied patches with timestamps
+ Bug fix: Patches emptying files should work now
+ Bug fix: Check for duplicate patch in series (Savannah's #20628)
+ Portability fixes for older Bash and GNU patch
* Wed May 07 2014 - upstream
- Update to version 0.62
+ Was a buggy release, with an incomplete tarfile
* Sun Dec 08 2013 - upstream
- Update to version 0.61
+ Almost two years of fixes and minor improvements
+ Fix support for ./configure --with-xargs
+ Parameter quoting fixes to many commands
+ Various fixes to the pop, push, refresh and patches commands
+ Translation fixes
+ setup: Many fixes and improvements
+ remove-trailing-ws: Several fixes and improvements
+ remove-trailing-ws: Add a dedicated test case
+ quilt.el: Many fixes and improvements (emacs integration)
* Wed Feb 29 2012 - upstream
- Update to version 0.60
+ BSD compatibility improvements
+ grep: Support file names which include spaces
+ import: Fix import of relative patches
+ mail: Several fixes
+ setup: Support directory and archive names which include spaces
+ backup-files: rewritten from C to bash
+ backup-files: Add a dedicated test case
* Sat Jan 28 2012 - upstream
- Update to version 0.51
+ Fix support for ./configure --docdir
+ Various $TMPDIR fixes
+ mail: Fix delivery address checking
+ mail: CC people in more common patch headers
+ push: Fix bash completion
+ inspect: Complain if wrapper script can't be executed
* Mon Dec 5 2011 - upstream
- Update to version 0.50
+ 34 months of fixes and improvements, too many to list them all
+ Fix detection of the patch version
+ Avoid error messages when building due to missing git-desc file
+ Add support for lzma and xz compression formats
+ import: Fix confusing French translation
+ mail: Stop using =~ for older versions of bash
+ mail: Fix a temporary directory leak
+ revert: Stop using cp -l
+ revert: Add bash completion support
+ setup: Add --fuzz parameter
+ setup: Add support for reverse patches
+ inspect: Fix shell syntax errors
+ Fix error in test case create-delete
* Thu Jan 29 2009 - upstream
- Update to version 0.48
+ fold: Fix bash completion
+ mail: Don't use GNU awk extensions
+ mail: Check for formail
+ setup: Fix for rpm 4.6
+ Fix error in test case import
* Thu Aug 21 2008 - upstream
- Update to version 0.47
+ Change summary not available
* Thu Oct 19 2006 - upstream
- Update to version 0.46
+ Change summary not available
* Mon Apr 24 2006 - upstream
- Update to version 0.45
+ Change summary not available
* Tue Feb 14 2006 - upstream
- Update to version 0.44
+ Change summary not available
* Wed Feb 01 2006 - upstream
- Update to version 0.43
+ Change summary not available
* Tue Jul 26 2005 - upstream
- Update to version 0.42
+ Change summary not available
* Fri Apr 29 2005 - upstream
- Update to version 0.40
+ Change summary not available
* Thu Feb 10 2005 - upstream
- Update to version 0.39
+ Change summary not available
* Sun Oct 17 2004 - upstream
- Update to version 0.37
+ Change summary not available
* Wed Sep 22 2004 - upstream
- Update to version 0.36
+ Change summary not available
* Thu Jul 15 2004 - upstream
- Update to version 0.35
+ Change summary not available
* Thu Jun 10 2004 - upstream
- Update to version 0.34
+ Change summary not available
* Sun Jun 06 2004 - upstream
- Update to version 0.33
+ Change summary not available
* Sat Mar 13 2004 - upstream
- Update to version 0.32
+ Change summary not available
* Wed Jan 28 2004 - upstream
- Update to version 0.30
+ Change summary not available
* Wed Nov 12 2003 - upstream
- Update to version 0.29
+ Change summary not available
* Fri Oct 31 2003 - upstream
- Update to version 0.28
+ Change summary not available
* Tue Oct 28 2003 - upstream
- Update to version 0.27
+ Change summary not available
* Tue Oct 21 2003 - upstream
- Update to version 0.26
+ Change summary not available

62
quilt.spec.in Normal file
View File

@ -0,0 +1,62 @@
#
# spec file for quilt - patch management scripts
#
Name: quilt
Summary: Scripts for working with series of patches
License: GPL
Group: Productivity/Text/Utilities
Version: @VERSION@
Release: @RELEASE@
Requires: coreutils diffutils findutils patch gzip bzip2 perl mktemp gettext
Autoreqprov: off
Source: quilt-%{version}.tar.gz
BuildRoot: %{_tmppath}/%{name}-%{version}-build
%description
The scripts allow to manage a series of patches by keeping
track of the changes each patch makes. Patches can be
applied, un-applied, refreshed, etc.
The scripts are heavily based on Andrew Morton's patch scripts
found at http://userweb.kernel.org/~akpm/stuff/patch-scripts.tar.gz.
Authors:
--------
Andrew Morton <akpm@digeo.com>
Andreas Gruenbacher <agruen@suse.de>
%prep
%setup
%build
CFLAGS="$RPM_OPT_FLAGS" \
./configure --prefix=/usr \
--mandir=%_mandir \
--docdir=%_docdir/%{name}-%{version}
make RELEASE=%release
%install
rm -rf $RPM_BUILD_ROOT
make install prefix=/usr BUILD_ROOT=$RPM_BUILD_ROOT
%{find_lang} %{name}
%clean
rm -rf $RPM_BUILD_ROOT
%files -f %{name}.lang
%defattr(-, root, root)
/usr/bin/guards
/usr/bin/quilt
/usr/share/quilt/
/usr/share/emacs/
/etc/bash_completion.d/quilt
%config(noreplace) /etc/quilt.quiltrc
%doc %{_mandir}/man1/guards.1*
%doc %{_mandir}/man1/quilt.1*
%doc %{_docdir}/%{name}-%{version}/README
%doc %{_docdir}/%{name}-%{version}/README.MAIL
%doc %{_docdir}/%{name}-%{version}/quilt.pdf
%changelog
@CHANGELOG@

144
quilt/add.in Normal file
View File

@ -0,0 +1,144 @@
#! @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 $QUILT_DIR/scripts/patchfns ]
then
echo "Cannot read library $QUILT_DIR/scripts/patchfns" >&2
exit 1
fi
. $QUILT_DIR/scripts/patchfns
fi
usage()
{
printf $"Usage: quilt add [-P patch] {file} ...\n"
if [ x$1 = x-h ]
then
printf $"
Add one or more files to the topmost or named patch. Files must be
added to the patch before being modified. Files that are modified by
patches already applied on top of the specified patch cannot be added.
-P patch
Patch to add files to.
"
exit 0
else
exit 1
fi
}
in_valid_dir()
{
local p=$1 path
path=${p%/*}
while [ "$p" != "$path" ]
do
if [ "$path" -ef "$QUILT_PATCHES" ]
then
printf $"File %s is located below %s\n" \
"$1" "$QUILT_PATCHES/"
return 1
fi
if [ "$path" -ef "$QUILT_PC" ]
then
printf $"File %s is located below %s\n" \
"$1" "$QUILT_PC/"
return 1
fi
p=$path
path=${path%/*}
done
}
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=$(find_applied_patch "$opt_patch") || exit 1
status=0
for file in "$@"
do
if ! in_valid_dir "$SUBDIR$file"
then
status=1
continue
fi
if file_in_patch "$SUBDIR$file" $patch
then
printf $"File %s is already in patch %s\n" \
"$SUBDIR$file" "$(print_patch $patch)" >&2
[ $status -ne 1 ] && status=2
continue
fi
next_patch=$(next_patch_for_file $patch "$SUBDIR$file")
if [ -n "$next_patch" ]
then
printf $"File %s modified by patch %s\n" \
"$SUBDIR$file" "$(print_patch $next_patch)" >&2
status=1
continue
fi
if [ -L "$SUBDIR$file" ]
then
printf $"Cannot add symbolic link %s\n" "$SUBDIR$file" >&2
status=1
continue
fi
if ! $QUILT_DIR/scripts/backup-files -b -s -L -B $QUILT_PC/$patch/ "$SUBDIR$file"
then
printf $"Failed to back up file %s\n" "$SUBDIR$file" >&2
status=1
continue
fi
if [ -e "$SUBDIR$file" ]
then
# The original tree may be read-only.
chmod u+w "$SUBDIR$file"
fi
printf $"File %s added to patch %s\n" \
"$SUBDIR$file" "$(print_patch $patch)"
done
exit $status
### Local Variables:
### mode: shell-script
### End:
# vim:filetype=sh

182
quilt/annotate.in Normal file
View File

@ -0,0 +1,182 @@
#! @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 $QUILT_DIR/scripts/patchfns ]
then
echo "Cannot read library $QUILT_DIR/scripts/patchfns" >&2
exit 1
fi
. $QUILT_DIR/scripts/patchfns
fi
usage()
{
printf $"Usage: quilt annotate [-P patch] {file}\n"
if [ x$1 = x-h ]
then
printf $"
Print an annotated listing of the specified file showing which
patches modify which lines. Only applied patches are included.
-P patch
Stop checking for changes at the specified rather than the
topmost patch.
"
exit 0
else
exit 1
fi
}
empty_file()
{
local file=$1
[ -s "$file" ] \
&& sed -e 's:.*::' "$file"
}
annotation_for()
{
local old_file=$1 new_file=$2 annotation=$3
[ -s "$old_file" ] || old_file=/dev/null
[ -s "$new_file" ] || new_file=/dev/null
diff -e "$old_file" "$new_file" \
| perl -e '
while (<>) {
if (/^\d+(?:,\d+)?[ac]$/) {
print;
while (<>) {
last if /^\.$/;
print "'"$annotation"'\n";
}
print;
next;
}
print;
}
'
}
merge_files()
{
local a b saved_IFS="$IFS"
local template=$1 file=$2
[ -e "$file" ] || file=/dev/null
exec 3< "$template"
exec 4< "$file"
IFS=
while read -r a <&3
do
read -r b <&4
echo "$a"$'\t'"$b"
done
IFS="$saved_IFS"
exec 3<&-
exec 4<&-
}
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 [ $# -ne 1 ]
then
usage
fi
opt_file="$SUBDIR$1"
opt_patch=$(find_applied_patch "$opt_patch") || exit 1
for patch in $(applied_patches); do
old_file="$(backup_file_name "$patch" "$opt_file")"
if [ -f "$old_file" ]
then
patches[${#patches[@]}]="$patch"
files[${#files[@]}]="$old_file"
fi
if [ "$opt_patch" = "$patch" ]
then
# We also need to know the next patch, if any
next_patch="$(next_patch_for_file "$opt_patch" "$opt_file")"
break
fi
done
if [ -z "$next_patch" ]
then
files[${#files[@]}]="$opt_file"
else
files[${#files[@]}]="$(backup_file_name "$next_patch" "$opt_file")"
fi
if [ ${#patches[@]} = 0 ]
then
sed -e 's:^:'$'\t'':' "${files[${#files[@]}-1]}"
exit 0
fi
template=$(gen_tempfile)
add_exit_handler "rm -f $template"
# The annotated listing is generated as follows: A file of annotations
# is created based on a file that contains the same number of lines as
# the source file, but all lines are empty.
#
# Then, for each patch that modifies the source file, an ed-style diff
# (which has no context, and removes lines that are removed without
# caring for the line's contents) is generated. In that diff, all line
# additions are replaced with the identifier of the patch (1, 2, ...).
# These patches are then applied to the empty file.
#
# Finally, the annotations listing is merged with the source file line
# by line.
setup_pager
empty_file ${files[0]} > $template
for ((n = 0; n < ${#patches[@]}; n++))
do
annotation_for "${files[n]}" "${files[n+1]}" $((n+1))
done \
| patch $template
merge_files $template "${files[${#files[@]}-1]}"
echo
for ((n = 0; n < ${#patches[@]}; n++))
do
echo "$((n+1))"$'\t'"$(print_patch ${patches[n]})"
done
### Local Variables:
### mode: shell-script
### End:
# vim:filetype=sh

68
quilt/applied.in Normal file
View File

@ -0,0 +1,68 @@
#! @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 $QUILT_DIR/scripts/patchfns ]
then
echo "Cannot read library $QUILT_DIR/scripts/patchfns" >&2
exit 1
fi
. $QUILT_DIR/scripts/patchfns
fi
usage()
{
printf $"Usage: quilt applied [patch]\n"
if [ x$1 = x-h ]
then
printf $"
Print a list of applied patches, or all patches up to and including the
specified patch in the file series.
"
exit 0
else
exit 1
fi
}
options=`getopt -o nh -- "$@"`
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=$(find_applied_patch "$1") || exit 1
setup_pager
printf "$(patch_format)\n" $(applied_before "$patch") "$patch"
### Local Variables:
### mode: shell-script
### End:
# vim:filetype=sh

143
quilt/delete.in Normal file
View File

@ -0,0 +1,143 @@
#! @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 $QUILT_DIR/scripts/patchfns ]
then
echo "Cannot read library $QUILT_DIR/scripts/patchfns" >&2
exit 1
fi
. $QUILT_DIR/scripts/patchfns
fi
usage()
{
printf $"Usage: quilt delete [-r] [--backup] [patch|-n]\n"
if [ x$1 = x-h ]
then
printf $"
Remove the specified or topmost patch from the series file. If the
patch is applied, quilt will attempt to remove it first. (Only the
topmost patch can be removed right now.)
-n Delete the next patch after topmost, rather than the specified
or topmost patch.
-r Remove the deleted patch file from the patches directory as well.
--backup
Rename the patch file to patch~ rather than deleting it.
Ignored if not used with \`-r'.
"
exit 0
else
exit 1
fi
}
options=`getopt -o nrh --long backup -- "$@"`
if [ $? -ne 0 ]
then
usage
fi
eval set -- "$options"
while true
do
case "$1" in
-n)
opt_next=1
shift ;;
-r)
opt_remove=1
shift ;;
-h)
usage -h ;;
--backup)
QUILT_BACKUP=1
shift ;;
--)
shift
break ;;
esac
done
if [ $# -gt 1 -o \( -n "$opt_next" -a $# -gt 0 \) ]
then
usage
fi
if [ -n "$1" ]; then
patch=$(find_patch "$1") || exit 1
else
patch=$(top_patch)
fi
if [ -n "$opt_next" ]
then
if ! patch=$(patch_after "$patch")
then
printf $"No next patch\n" >&2
exit 1
fi
fi
if [ -z "$patch" ]
then
# find_top_patch will display the proper error message for us
find_top_patch > /dev/null
exit 1
fi
if is_applied "$patch"; then
if [ "$patch" != "$(top_patch)" ]
then
printf $"Patch %s is currently applied\n" \
"$(print_patch "$patch")" >&2
exit 1
fi
if ! quilt_command pop -fq
then
exit 1
fi
fi
if remove_from_series "$patch"
then
printf $"Removed patch %s\n" "$(print_patch "$patch")"
else
printf $"Failed to remove patch %s\n" "$(print_patch "$patch")" >&2
exit 1
fi
patch_file=$(patch_file_name "$patch")
if [ "$opt_remove" -a -e "$patch_file" ]
then
if [ "$QUILT_BACKUP" ]
then
if ! mv -f "$patch_file" "$patch_file~"
then
printf $"Failed to backup patch file %s\n" \
"$patch_file" >&2
exit 1
fi
else
if ! rm -f "$patch_file"
then
printf $"Failed to remove patch file %s\n" \
"$patch_file" >&2
exit 1
fi
fi
fi
### Local Variables:
### mode: shell-script
### End:
# vim:filetype=sh

384
quilt/diff.in Normal file
View File

@ -0,0 +1,384 @@
#! @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 $QUILT_DIR/scripts/patchfns ]
then
echo "Cannot read library $QUILT_DIR/scripts/patchfns" >&2
exit 1
fi
. $QUILT_DIR/scripts/patchfns
fi
setup_colors
usage()
{
printf $"Usage: quilt diff [-p n|-p ab] [-u|-U num|-c|-C num] [--combine patch|-z] [-R] [-P patch] [--snapshot] [--diff=utility] [--no-timestamps] [--no-index] [--sort] [--color[=always|auto|never]] [file ...]\n"
if [ x$1 = x-h ]
then
printf $"
Produces a diff of the specified file(s) in the topmost or specified
patch. If no files are specified, all files that are modified are
included.
-p n Create a -p n style patch (-p0 or -p1 are supported).
-p ab Create a -p1 style patch, but use a/file and b/file as the
original and new filenames instead of the default
dir.orig/file and dir/file names.
-u, -U num, -c, -C num
Create a unified diff (-u, -U) with num lines of context. Create
a context diff (-c, -C) with num lines of context. The number of
context lines defaults to 3.
--no-timestamps
Do not include file timestamps in patch headers.
--no-index
Do not output Index: lines.
-z Write to standard output the changes that have been made
relative to the topmost or specified patch.
-R Create a reverse diff.
-P patch
Create a diff for the specified patch. (Defaults to the topmost
patch.)
--combine patch
Create a combined diff for all patches between this patch and
the patch specified with -P. A patch name of \`-' is equivalent
to specifying the first applied patch.
--snapshot
Diff against snapshot (see \`quilt snapshot -h').
--diff=utility
Use the specified utility for generating the diff. The utility
is invoked with the original and new file name as arguments.
--color[=always|auto|never]
Use syntax coloring (auto activates it only if the output is a tty).
--sort Sort files by their name instead of preserving the original order.
"
exit 0
else
exit 1
fi
}
colorize()
{
if [ -n "$opt_color" ]
then
sed -e '
s/^\(Index:\|---\|+++\|\*\*\*\) .*/'$color_diff_hdr'&'$color_clear'/
t ; s/^+.*/'$color_diff_add'&'$color_clear'/
t ; s/^-.*/'$color_diff_rem'&'$color_clear'/
t ; s/^!.*/'$color_diff_mod'&'$color_clear'/
t ; s/^\(@@ \-[0-9]\+\(,[0-9]\+\)\? +[0-9]\+\(,[0-9]\+\)\? @@\)\([ \t]*\)\(.*\)/'$color_diff_hunk'\1'$color_clear'\4'$color_diff_ctx'\5'$color_clear'/
t ; s/^\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*.*/'$color_diff_cctx'&'$color_clear'/
'
else
cat
fi
}
do_diff()
{
local file=$1 old_file=$2 new_file=$3 status
if [ -n "$opt_reverse" ]
then
local f=$new_file
new_file=$old_file
old_file=$f
fi
if [ -n "$opt_diff" ]
then
[ -s "$old_file" ] || old_file=/dev/null
[ -s "$new_file" ] || new_file=/dev/null
if ! diff -q "$old_file" "$new_file" >/dev/null
then
export LANG=$ORIGINAL_LANG
$opt_diff "$old_file" "$new_file"
export LANG=POSIX
true
fi
else
diff_file "$file" "$old_file" "$new_file" | colorize
# Test the return value of diff, and propagate the error if any
status=${PIPESTATUS[0]}
if [ $status != 0 ]
then
die $status
fi
fi
}
die()
{
local status=$1
[ -e "$tmp_files" ] && rm -f $tmp_files
[ -n "$workdir" ] && rm -rf $workdir
exit $status
}
options=`getopt -o p:P:RuU:cC:zh --long diff:,snapshot,no-timestamps \
--long no-index,combine:,color:: \
--long sort -- "$@"`
if [ $? -ne 0 ]
then
usage
fi
eval set -- "$options"
opt_format=-u
while true
do
case "$1" in
-p)
opt_strip_level=$2
shift 2 ;;
-P)
last_patch=$2
shift 2 ;;
--combine)
opt_combine=1
if [ "$2" = - ]
then
first_patch=-
else
first_patch=$(find_applied_patch "$2") || exit 1
fi
shift 2 ;;
-R)
opt_reverse=1
shift ;;
-z)
opt_relative=1
shift ;;
-u|-c)
opt_format=$1
shift ;;
-U|-C)
opt_format="$1 $2"
shift 2 ;;
-h)
usage -h ;;
--snapshot)
opt_snapshot=1
snap_subdir=.snap
shift ;;
--diff)
opt_diff=$2
shift 2 ;;
--no-timestamps)
QUILT_NO_DIFF_TIMESTAMPS=1
shift ;;
--no-index)
QUILT_NO_DIFF_INDEX=1
shift ;;
--sort)
opt_sort=1
shift ;;
--color)
case "$2" in
"" | always)
opt_color=1 ;;
auto | tty)
opt_color=
[ -t 1 ] && opt_color=1 ;;
never)
opt_color= ;;
*)
usage ;;
esac
shift 2 ;;
--)
shift
break ;;
esac
done
QUILT_DIFF_OPTS="$QUILT_DIFF_OPTS $opt_format"
opt_files=( $(for file in "$@"; do echo "$SUBDIR${file#./}" ; done) )
if [ $[0$opt_combine + 0$opt_snapshot + 0$opt_relative] -gt 1 ]
then
printf $"Options \`--combine', \`--snapshot', and \`-z' cannot be combined.\n" >&2
die 1
fi
last_patch=$(find_applied_patch "$last_patch") || exit 1
if [ -z "$opt_strip_level" ]
then
opt_strip_level=$(patch_strip_level "$last_patch")
fi
case "$opt_strip_level" in
0 | 1 | ab)
;;
*)
printf $"Cannot diff patches with -p%s, please specify -p0, -p1, or -pab instead\n" \
"$opt_strip_level" >&2
die 1
;;
esac
# If diffing against snapshot, ensure that snapshot is actually present
if [ -n "$opt_snapshot" ] && [ ! -d "$QUILT_PC/$snap_subdir" ]
then
printf $"No snapshot to diff against\n" >&2
die 1
fi
trap "die 1" SIGTERM
tmp_files=$(gen_tempfile)
exec 4> $tmp_files # open $tmp_files
if [ -n "$opt_snapshot" -a ${#opt_files[@]} -eq 0 ]
then
# Add all files in the snapshot into the file list (they may all
# have changed).
files=( $(find $QUILT_PC/$snap_subdir -type f \
| sed -e "s/^$(quote_bre $QUILT_PC/$snap_subdir/)//" \
| sort) )
printf "%s\n" "${files[@]}" >&4
unset files
# Also look at all patches that are currently applied.
opt_combine=1
first_patch=$(applied_patches | head -n 1)
fi
if [ -n "$opt_combine" ]
then
set -- $(patches_before "$last_patch") "$last_patch"
if [ "$first_patch" != "-" ]
then
while [ $# -ge 1 -a "$1" != "$first_patch" ]
do
shift
done
if [ $# -eq 0 ]
then
printf $"Patch %s not applied before patch %s\n" \
"$(print_patch "$first_patch")" \
"$(print_patch "$last_patch")" >&2
die 1
fi
fi
patches=( "$@" )
else
patches=( "$last_patch" )
fi
# Properly handle spaces in file names
saved_IFS=$IFS
IFS=$'\n'
for patch in ${patches[@]}
do
for file in $(files_in_patch_ordered "$patch")
do
if [ ${#opt_files[@]} -gt 0 ] && \
! in_array "$file" "${opt_files[@]}"
then
continue
fi
echo "$file" >&4
done
done
exec 4>&- # close $tmp_files
if [ -z "$opt_sort" ]
then
files=( $(
awk '
{ if ($0 in seen)
next
seen[$0]=1
print
}
' $tmp_files) )
else
files=( $(sort -u $tmp_files) )
fi
IFS=$saved_IFS
if [ -n "$opt_relative" ]
then
workdir=$(gen_tempfile -d $PWD/quilt)
apply_patch_temporarily "$workdir" "$last_patch" "${files[@]}" \
|| die 1
fi
setup_pager
for file in "${files[@]}"
do
if [ -n "$opt_snapshot" -a -e "$QUILT_PC/$snap_subdir/$file" ]
then
old_file="$QUILT_PC/$snap_subdir/$file"
elif [ -n "$opt_relative" ]
then
old_file="$workdir/$file"
else
patch=$(first_modified_by "$file" "${patches[@]}")
if [ -z "$patch" ]
then
[ -z "$opt_snapshot" ] \
&& printf $"File %s is not being modified\n" "$file" >&2
continue
fi
old_file=$(backup_file_name "$patch" "$file")
fi
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
do_diff "$file" "$old_file" "$new_file"
if [ $? -ne 0 ]
then
printf $"Diff failed, aborting\n" >&2
die 1
fi
done
if [ -n "$files_were_shadowed" ]
then
printf $"Warning: more recent patches modify files in patch %s\n" \
"$(print_patch "$last_patch")" >&2
fi
die 0
### Local Variables:
### mode: shell-script
### End:
# vim:filetype=sh

85
quilt/edit.in Normal file
View File

@ -0,0 +1,85 @@
#! @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.
: ${EDITOR:=vi}
# Read in library functions
if [ "$(type -t patch_file_name)" != function ]
then
if ! [ -r $QUILT_DIR/scripts/patchfns ]
then
echo "Cannot read library $QUILT_DIR/scripts/patchfns" >&2
exit 1
fi
. $QUILT_DIR/scripts/patchfns
fi
usage()
{
printf $"Usage: quilt edit file ...\n"
if [ x$1 = x-h ]
then
printf $"
Edit the specified file(s) in \$EDITOR (%s) after adding it (them) to
the topmost patch.
" "$EDITOR"
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 [ $# -eq 0 ]
then
usage
fi
quilt_command add "$@"
status=$?
if [ $status -ne 0 -a $status -ne 2 ]
then
exit $status
fi
LANG=$ORIGINAL_LANG $EDITOR "${@/#/$SUBDIR}"
status=$?
patch=$(top_patch)
for file in "$@"
do
if [ ! -e "$SUBDIR$file" -a ! -s "$QUILT_PC/$patch/$file" ]
then
quilt_command remove "$file"
status=1
fi
done
exit $status
### Local Variables:
### mode: shell-script
### End:
# vim:filetype=sh

181
quilt/files.in Normal file
View File

@ -0,0 +1,181 @@
#! @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 $QUILT_DIR/scripts/patchfns ]
then
echo "Cannot read library $QUILT_DIR/scripts/patchfns" >&2
exit 1
fi
. $QUILT_DIR/scripts/patchfns
fi
usage()
{
printf $"Usage: quilt files [-v] [-a] [-l] [--combine patch] [patch]\n"
if [ x$1 = x-h ]
then
printf $"
Print the list of files that the topmost or specified patch changes.
-a List all files in all applied patches.
-l Add patch name to output.
-v Verbose, more user friendly output.
--combine patch
Create a listing for all patches between this patch and
the topmost or specified patch. A patch name of \`-' is
equivalent to specifying the first applied patch.
"
exit 0
else
exit 1
fi
}
options=`getopt -o vhal --long combine: -- "$@"`
if [ $? -ne 0 ]
then
usage
fi
eval set -- "$options"
while true
do
case "$1" in
-v)
opt_verbose=1
shift ;;
-a)
opt_all=1
shift ;;
-l)
opt_labels=1
shift ;;
-h)
usage -h ;;
--combine)
opt_all=1
if [ "$2" = - ]
then
:
else
first_patch=$(find_patch_in_series "$2") || exit 1
fi
shift 2 ;;
--)
shift
break ;;
esac
done
if [ $# -gt 1 ]
then
usage
fi
last_patch=$(find_patch_in_series "$1") || exit 1
if [ -n "$opt_all" -a -z "$first_patch" ]
then
first_patch=$(applied_patches | head -n 1)
fi
if [ -n "$opt_all" ]
then
set -- $(patches_before "$last_patch") "$last_patch"
while [ $# -ge 1 -a "$1" != "$first_patch" ]
do
shift
done
if [ $# -eq 0 ]
then
printf $"Patch %s not applied before patch %s\n" \
"$(print_patch "$first_patch")" \
"$(print_patch "$last_patch")" >&2
exit 1
fi
patches=( "$@" )
else
patches=( "$last_patch" )
fi
list_files_in_patch()
{
local patch=$1
local status
local saved_IFS=$IFS
if [ -n "$opt_all" ] && [ -n "$opt_verbose" ] && [ -z "$opt_labels" ]
then
echo "$patch"
fi
if [ -n "$opt_verbose" ] && [ -z "$opt_labels" ]
then
use_status=yes
fi
# Note: If opt_labels is set, then use_status is not set.
IFS=
if is_applied "$patch"
then
files_in_patch "$patch"
else
filenames_in_patch "$patch"
fi |
sort |
while read file
do
if [ -n "$opt_labels" ]
then
if [ -n "$opt_verbose" ]
then
echo -n "[$patch] "
else
echo -n "$patch "
fi
fi
if [ -z "$use_status" ]
then
echo "$file"
else
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"
fi
done
IFS=$saved_IFS
}
setup_pager
for patch in "${patches[@]}"
do
list_files_in_patch "$patch"
done
### Local Variables:
### mode: shell-script
### End:
# vim:filetype=sh

144
quilt/fold.in Normal file
View File

@ -0,0 +1,144 @@
#! @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 $QUILT_DIR/scripts/patchfns ]
then
echo "Cannot read library $QUILT_DIR/scripts/patchfns" >&2
exit 1
fi
. $QUILT_DIR/scripts/patchfns
fi
usage()
{
printf $"Usage: quilt fold [-R] [-q] [-f] [-p strip-level]\n"
if [ x$1 = x-h ]
then
printf $"
Integrate the patch read from standard input into the topmost patch:
After making sure that all files modified are part of the topmost
patch, the patch is applied with the specified strip level (which
defaults to 1).
-R Apply patch in reverse.
-q Quiet operation.
-f Force apply, even if the patch has rejects. Unless in quiet mode,
apply the patch interactively: the patch utility may ask questions.
-p strip-level
The number of pathname components to strip from file names
when applying patchfile.
"
exit 0
else
exit 1
fi
}
options=`getopt -o Rp:qfh -- "$@"`
if [ $? -ne 0 ]
then
usage
fi
eval set -- "$options"
while true
do
case "$1" in
-R)
opt_reverse=1
shift ;;
-f)
opt_force=1
shift ;;
-p)
opt_strip_level=$2
shift 2 ;;
-q)
opt_quiet=1
shift ;;
-h)
usage -h ;;
--)
shift
break ;;
esac
done
if [ $# -ne 0 ]
then
usage
fi
: ${opt_strip_level:=1}
[ -n "$opt_quiet" ] && patch_args="$patch_args -s"
[ -z "$opt_force" -o -n "$opt_quiet" ] && patch_args="$patch_args -f"
[ -n "$opt_reverse" ] && patch_args="$patch_args -R"
top=$(find_top_patch) || exit 1
trap "failed=1" SIGINT
workdir=$(gen_tempfile -d $PWD)
patch -d ${SUBDIR:-.} $QUILT_PATCH_OPTS -p$opt_strip_level \
--backup --prefix="$workdir/$SUBDIR" $patch_args \
|| failed=1
[ -n "$opt_force" ] && failed=
saved_IFS=$IFS
IFS=$'\n'
if [ -z "$failed" ]
then
# Copy additional files from workdir to the backup directory
# For this patch
for file in $(find $workdir -type f -a ! -path "$workdir/.timestamp")
do
file="${file:${#workdir}+1}"
backup_file="$(backup_file_name $top "$file")"
if ! [ -e "$backup_file" ]
then
if ! mkdir -p "$(dirname "$backup_file")" ||
! ln "$workdir/$file" "$backup_file"
then
failed=1
break
fi
fi
done
fi
if [ -n "$failed" ]
then
# Restore all files to the state from before applying the patch
for file in $(find $workdir -type f -a ! -path "$workdir/.timestamp")
do
file="${file:${#workdir}+1}"
if ! mv -f "$workdir/$file" "$file"
then
printf $"File %s may be corrupted\n" "$file" >&2
fi
done
rm -rf $workdir
exit 1
fi
IFS=$saved_IFS
rm -rf $workdir
exit 0
### Local Variables:
### mode: shell-script
### End:
# vim:filetype=sh

108
quilt/fork.in Normal file
View File

@ -0,0 +1,108 @@
#! @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 $QUILT_DIR/scripts/patchfns ]
then
echo "Cannot read library $QUILT_DIR/scripts/patchfns" >&2
exit 1
fi
. $QUILT_DIR/scripts/patchfns
fi
usage()
{
printf $"Usage: quilt fork [new_name]\n"
if [ x$1 = x-h ]
then
printf $"
Fork the topmost patch. Forking a patch means creating a verbatim copy
of it under a new name, and use that new name instead of the original
one in the current series. This is useful when a patch has to be
modified, but the original version of it should be preserved, e.g.
because it is used in another series, or for the history. A typical
sequence of commands would be: fork, edit, refresh.
If new_name is missing, the name of the forked patch will be the current
patch name, followed by \`-2'. If the patch name already ends in a
dash-and-number, the number is further incremented (e.g., patch.diff,
patch-2.diff, patch-3.diff).
"
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
top_patch=$(find_top_patch) || exit 1
if [ $# -eq 1 ]
then
new_patch="$1"
else
new_patch="$(next_filename "$top_patch")"
fi
new_patch=${new_patch#$QUILT_PATCHES/}
if patch_in_series $new_patch || \
[ -d "$QUILT_PC/$new_patch" ] || \
[ -e "$(patch_file_name $new_patch)" ]
then
printf $"Patch %s exists already, please choose a new name\n" \
"$(print_patch $new_patch)" >&2
exit 1
fi
if ! rename_in_db "$top_patch" "$new_patch" || \
! rename_in_series "$top_patch" "$new_patch" || \
! mv "$QUILT_PC/$top_patch" "$QUILT_PC/$new_patch" || \
( [ -e "$(patch_file_name $top_patch)" ] && \
! cp -p "$(patch_file_name $top_patch)" \
"$(patch_file_name $new_patch)" )
then
printf $"Fork of patch %s to patch %s failed\n" \
"$(print_patch $top_patch)" \
"$(print_patch $new_patch)" >&2
exit 1
fi
printf $"Fork of patch %s created as %s\n" \
"$(print_patch $top_patch)" \
"$(print_patch $new_patch)"
### Local Variables:
### mode: shell-script
### End:
# vim:filetype=sh

135
quilt/graph.in Normal file
View File

@ -0,0 +1,135 @@
#! @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 $QUILT_DIR/scripts/patchfns ]
then
echo "Cannot read library $QUILT_DIR/scripts/patchfns" >&2
exit 1
fi
. $QUILT_DIR/scripts/patchfns
fi
usage()
{
printf $"Usage: quilt graph [--all] [--reduce] [--lines[=num]] [--edge-labels=files] [-T ps] [patch]\n"
if [ x$1 = x-h ]
then
printf $"
Generate a dot(1) directed graph showing the dependencies between
applied patches. A patch depends on another patch if both touch the same
file or, with the --lines option, if their modifications overlap. Unless
otherwise specified, the graph includes all patches that the topmost
patch depends on.
When a patch name is specified, instead of the topmost patch, create a
graph for the specified patch. The graph will include all other patches
that this patch depends on, as well as all patches that depend on this
patch.
--all Generate a graph including all applied patches and their
dependencies. (Unapplied patches are not included.)
--reduce
Eliminate transitive edges from the graph.
--lines[=num]
Compute dependencies by looking at the lines the patches modify.
Unless a different num is specified, two lines of context are
included.
--edge-labels=files
Label graph edges with the file names that the adjacent patches
modify.
-T ps Directly produce a PostScript output file.
"
exit 0
else
exit 1
fi
}
options=`getopt -o T:h --long all,reduce,lines::,edge-labels: -- "$@"`
if [ $? -ne 0 ]
then
usage
fi
eval set -- "$options"
while true
do
case "$1" in
-T) if [ "$2" != ps ]; then
usage
fi
opt_format=ps
shift 2 ;;
--all)
opt_all=1
shift ;;
--reduce)
opt_reduce=1
shift ;;
--lines)
opt_lines=${2:-2}
shift 2 ;;
--edge-labels)
if [ "$2" != files ]
then
usage
fi
opt_edge_labels=$2
shift 2 ;;
-h)
usage -h ;;
--)
shift
break ;;
esac
done
if [ $# -gt 1 -o \( $# -ne 0 -a -n "$opt_all" \) ]
then
usage
fi
[ "$opt_format" = "ps" ] && check_external_tool dot graphviz -T
[ -n "$opt_reduce" ] && check_external_tool tred graphviz --reduce
if [ -z "$opt_all" ]
then
patch=$(find_applied_patch "$1") || exit 1
fi
options=
[ -n "$patch" ] && options="--select-patch $patch"
[ -n "$opt_reduce" ] && options="$options --reduce"
[ "$opt_edge_labels" = files ] && options="$options --edge-files"
[ -n "$opt_lines" ] && options="$options --lines=$opt_lines"
pipe=
[ -n "$opt_format" ] && pipe="| dot -T$opt_format"
export QUILT_PC
applied_patches \
| eval $QUILT_DIR/scripts/dependency-graph $options - $pipe
### Local Variables:
### mode: shell-script
### End:
# vim:filetype=sh

133
quilt/grep.in Normal file
View File

@ -0,0 +1,133 @@
#! @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 $QUILT_DIR/scripts/patchfns ]
then
echo "Cannot read library $QUILT_DIR/scripts/patchfns" >&2
exit 1
fi
. $QUILT_DIR/scripts/patchfns
fi
usage()
{
printf $"Usage: quilt grep [-h|options] {pattern}\n"
if [ x$1 = x-h ]
then
printf $"
Grep through the source files, recursively, skipping patches and quilt
meta-information. If no filename argument is given, the whole source
tree is searched. Please see the grep(1) manual page for options.
-h Print this help. The grep -h option can be passed after a
double-dash (--). Search expressions that start with a dash
can be passed after a second double-dash (-- --).
"
exit 0
else
exit 1
fi
}
get_options()
{
getopt -o EFGPe:f:iwxzsvVm:bHnhqoaId:D:RrlLcB:ZA:C:Uu \
--long extended-regexp,fixed-strings,basic-regexp,perl-regexp \
--long regexp:,file:,ignore-case,word-regexp \
--long line-regexp,null-data,no-messages,invert-match,version \
--long help,mmap,max-count:,byte-offset,line-number \
--long line-buffered,with-filename,no-filename,label: \
--long only-matching,quiet,silent,binary-files:,text, \
--long directories:,devices:,recursive,include:,exclude: \
--long exclude-from:,files-without-match,files-with-matches \
--long count,null,before-context:,after-context:,context: \
--long color::,colour::,binary,unix-byte-offsets \
-- "$@"
}
shift_myargs()
{
set -- "${myargs[@]}"
shift
myargs=( "$@" )
}
shift_args()
{
while true
do
case "${myargs[0]}" in
--)
shift_myargs
return ;;
-h)
opt_h=1 ;;
-e|-f|--regexp|--file)
has_pattern=1
args=( "${args[@]}" "${myargs[0]}" )
shift_myargs ;;
-m|-d|-D|-B|-A|-C|\
--max-count|--label|--binary-files|\
--directories|--devices|--include|--exclude|--exclude-from|\
--before-context|--after-context|--context|--color|--colour)
args=( "${args[@]}" "${myargs[0]}" )
shift_myargs ;;
esac
args=( "${args[@]}" "${myargs[0]}" )
shift_myargs
done
}
options=$(get_options "$@")
[ $? -ne 0 ] && usage
eval set -- "$options"
myargs=( "$@" )
args=()
opt_h=
has_pattern=
shift_args
[ -n "$opt_h" ] && usage -h
case "${myargs[0]}" in
-*)
options=$(get_options "${myargs[@]}")
[ $? -ne 0 ] && usage
eval set -- "$options"
myargs=( "$@" )
shift_args ;;
esac
if [ -z "$has_pattern" ]
then
[ ${#myargs[@]} -eq 0 ] && usage
args=( "${args[@]}" -- "${myargs[0]}" )
shift_myargs
fi
# Print the filename for each match, unless -h is given. Otherwise, xargs
# may pass a single filename to grep and cause it to omit the file name.
[ -z "$opt_h" ] && opt_H=-H
find "${myargs[@]:-.}" \( \
-path "./$QUILT_PATCHES/*" -o \
-path "./$QUILT_PC/*" \) -prune -o \
-type f -print0 \
| xargs -0 grep $opt_H "${args[@]}" \
| if [ ${#myargs[@]} -eq 0 ]; then
sed -e 's,^./,,'
else
cat
fi
### Local Variables:
### mode: shell-script
### End:
# vim:filetype=sh

182
quilt/header.in Normal file
View File

@ -0,0 +1,182 @@
#! @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 $QUILT_DIR/scripts/patchfns ]
then
echo "Cannot read library $QUILT_DIR/scripts/patchfns" >&2
exit 1
fi
. $QUILT_DIR/scripts/patchfns
fi
: ${EDITOR:=vi}
usage()
{
printf $"Usage: quilt header [-a|-r|-e] [--backup] [--strip-diffstat] [--strip-trailing-whitespace] [patch]\n"
if [ x$1 = x-h ]
then
printf $"
Print or change the header of the topmost or specified patch.
-a, -r, -e
Append to (-a) or replace (-r) the exiting patch header, or
edit (-e) the header in \$EDITOR (%s). If none of these options is
given, print the patch header.
--strip-diffstat
Strip diffstat output from the header.
--strip-trailing-whitespace
Strip trailing whitespace at the end of lines of the header.
--backup
Create a backup copy of the old version of a patch as patch~.
" "$EDITOR"
exit 0
else
exit 1
fi
}
maybe_strip_trailing_whitespace()
{
if [ -n "$opt_strip_trailing_whitespace" ]
then
sed -e 's:[ '$'\t'']*$::'
else
cat
fi
}
maybe_strip_diffstat()
{
if [ -n "$opt_strip_diffstat" ]
then
strip_diffstat
else
cat
fi
}
options=`getopt -o areh --long backup,strip-trailing-whitespace,strip-diffstat -- "$@"`
if [ $? -ne 0 ]
then
usage
fi
eval set -- "$options"
while true
do
case "$1" in
-a)
opt_append=1
shift ;;
-r)
opt_replace=1
shift ;;
-e)
opt_edit=1
shift ;;
--backup)
QUILT_BACKUP=1
shift ;;
--strip-diffstat)
opt_strip_diffstat=1
shift ;;
--strip-trailing-whitespace)
opt_strip_trailing_whitespace=1
shift ;;
-h)
usage -h ;;
--)
shift
break ;;
esac
done
case "$opt_append$opt_replace$opt_edit"
in
''|1) ;;
*) usage ;;
esac
if [ $# -gt 1 ]
then
usage
fi
patch=$(find_patch_in_series "$1") || exit 1
patch_file=$(patch_file_name $patch)
if [ -z "$opt_replace" -a -z "$opt_append" -a -z "$opt_edit" ]
then
[ -e "$patch_file" ] || exit 0
setup_pager
cat_file "$patch_file" \
| patch_header \
| maybe_strip_diffstat \
| maybe_strip_trailing_whitespace
else
patch_file_or_null=/dev/null
[ -e "$patch_file" ] && patch_file_or_null=$patch_file
tmp=$(gen_tempfile) || exit 1
tmp2=$(gen_tempfile) || exit 1
add_exit_handler "rm -f $tmp $tmp2"
( if [ -z "$opt_replace" ]
then
cat_file $patch_file_or_null | patch_header
fi
if [ -n "$opt_append" -o -n "$opt_replace" ]
then
cat
fi
) > $tmp
if [ -n "$opt_edit" ]
then
LANG=$ORIGINAL_LANG $EDITOR "$tmp" || exit 1
fi
# Ensure there is a trailing newline before we append the rest
ensure_trailing_newline $tmp
maybe_strip_diffstat < $tmp \
| maybe_strip_trailing_whitespace > $tmp2
cat_file "$patch_file_or_null" | patch_body >> $tmp2 || exit 1
if cat_to_new_file $patch_file $QUILT_BACKUP < $tmp2
then
if [ -z "$opt_append" ]
then
printf \
$"Replaced header of patch %s\n" "$(print_patch $patch)"
else
printf \
$"Appended text to header of patch %s\n" "$(print_patch $patch)"
fi
else
exit 1
fi
fi
### Local Variables:
### mode: shell-script
### End:
# vim:filetype=sh

258
quilt/import.in Normal file
View File

@ -0,0 +1,258 @@
#! @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 $QUILT_DIR/scripts/patchfns ]
then
echo "Cannot read library $QUILT_DIR/scripts/patchfns" >&2
exit 1
fi
. $QUILT_DIR/scripts/patchfns
fi
usage()
{
printf $"Usage: quilt import [-p num] [-R] [-P patch] [-f] [-d {o|a|n}] patchfile ...\n"
if [ x$1 = x-h ]
then
printf $"
Import external patches. The patches will be inserted following the
current top patch, and must be pushed after import to apply them.
-p num
Number of directory levels to strip when applying (default=1)
-R
Apply patch in reverse.
-P patch
Patch filename to use inside quilt. This option can only be
used when importing a single patch.
-f Overwrite/update existing patches.
-d {o|a|n}
When overwriting in existing patch, keep the old (o), all (a), or
new (n) patch header. If both patches include headers, this option
must be specified. This option is only effective when -f is used.
"
exit 0
else
exit 1
fi
}
find_patch_file()
{
local name="$1"
if [ ${name:0:1} = / ]
then
# Patch has absolute path
if [ -r "$name" ]
then
echo "$name"
return
fi
else
# Patch has a relative path
if [ -r "$SUBDIR$name" ]
then
echo "$SUBDIR$name"
return
fi
fi
printf $"Patch %s does not exist\n" "$name" >&2
return 1
}
merge_patches()
{
local old="$1" new="$2"
local old_desc=$(gen_tempfile) new_desc=$(gen_tempfile)
cat_file "$old" | patch_header | strip_diffstat > $old_desc
cat_file "$new" | patch_header | strip_diffstat > $new_desc
if [ -z "$opt_desc" ]
then
[ -s $old_desc ] || opt_desc=n
[ -z "$opt_desc" -a ! -s $new_desc ] && opt_desc=o
if [ -z "$opt_desc" ]
then
local diff=$(diff -u $old_desc $new_desc \
| sed -e '1,2d')
if [ -n "$diff" ]
then
printf $"Patch headers differ:\n" >&2
echo "$diff" >&2
printf \
$"Please use -d {o|a|n} to specify which patch header(s) to keep.\n" >&2
rm -f $old_desc $new_desc
return 1
fi
fi
fi
[ "$opt_desc" = n ] || cat "$old_desc"
[ "$opt_desc" = a ] && echo '---'
if [ "$opt_desc" = o ]
then
cat_file "$new" | patch_body
else
cat_file "$new"
fi
rm -f $old_desc $new_desc
}
die()
{
local status=$1
[ "$merged_patch_file" != "$patch_file" ] && rm -f "$merged_patch_file"
exit $status
}
options=`getopt -o P:d:fp:Rh -- "$@"`
if [ $? -ne 0 ]
then
usage
fi
eval set -- "$options"
while true
do
case "$1" in
-P)
opt_patch=${2#$QUILT_PATCHES/}
shift 2 ;;
-p)
opt_strip=$2
shift 2 ;;
-R)
opt_reverse=1
shift ;;
-d)
case "$2" in
o|n|a) opt_desc=$2 ;;
*) usage ;;
esac
shift 2 ;;
-f)
opt_force=1
shift ;;
-h)
usage -h ;;
--)
shift
break ;;
esac
done
if [ $# -gt 1 -a -n "$opt_patch" ]
then
printf $"Option \`-P' can only be used when importing a single patch\n" >&2
exit 1
fi
[ -n "$opt_strip" ] && patch_args="-p$opt_strip"
if [ -n "$opt_reverse" ]
then
if [ -n "$patch_args" ]
then
patch_args="$patch_args -R"
else
patch_args="-R"
fi
fi
before=$(patch_after "$(top_patch)")
for orig_patch_file in "$@"
do
if [ -n "$opt_patch" ]
then
patch=$opt_patch
else
patch=${orig_patch_file##*/}
fi
patch_file=$(find_patch_file "$orig_patch_file") || exit 1
merged_patch_file="$patch_file"
if is_applied $patch
then
printf $"Patch %s is applied\n" "$(print_patch $patch)" >&2
exit 1
fi
dest=$(patch_file_name $patch)
if patch_in_series "$patch"
then
if [ "$patch_file" = "$dest" ]
then
printf $"Patch %s already exists in series.\n" \
"$(print_patch $patch)" >&2
exit 1
fi
if [ -z "$opt_force" ]
then
printf $"Patch %s exists. Replace with -f.\n" \
"$(print_patch $patch)" >&2
exit 1
fi
if [ "$opt_desc" != n ]
then
merged_patch_file=$(gen_tempfile)
merge_patches "$dest" "$patch_file" \
> $merged_patch_file \
|| die 1
fi
printf $"Replacing patch %s with new version\n" \
"$(print_patch $patch)" >&2
elif [ -e "$dest" ]
then
printf $"Importing patch %s\n" "$(print_patch $patch)"
else
printf $"Importing patch %s (stored as %s)\n" \
"$orig_patch_file" \
"$(print_patch $patch)"
mkdir -p "${dest%/*}"
fi
if [ "$merged_patch_file" != "$dest" ] && \
(( [ "$merged_patch_file" != "$patch_file" ] && \
! cat_to_new_file "$dest" < "$merged_patch_file" ) || \
( [ "$merged_patch_file" = "$patch_file" ] && \
! cp "$merged_patch_file" "$dest" ))
then
printf $"Failed to import patch %s\n" "$(print_patch $patch)" >&2
die 1
fi
[ "$merged_patch_file" != "$patch_file" ] && rm -f "$merged_patch_file"
if ! patch_in_series $patch &&
! insert_in_series $patch "$patch_args" "$before"
then
printf $"Failed to insert patch %s into file series\n" \
"$(print_patch $patch)" >&2
exit 1
fi
rm -rf $QUILT_PC/$patch
done
### Local Variables:
### mode: shell-script
### End:
# vim:filetype=sh

700
quilt/mail.in Normal file
View File

@ -0,0 +1,700 @@
#! @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.
: ${EDITOR:=vi}
# Read in library functions
if [ "$(type -t patch_file_name)" != function ]
then
if ! [ -r $QUILT_DIR/scripts/patchfns ]
then
echo "Cannot read library $QUILT_DIR/scripts/patchfns" >&2
exit 1
fi
. $QUILT_DIR/scripts/patchfns
fi
usage()
{
printf $"Usage: quilt mail {--mbox file|--send} [-m text] [-M file] [--prefix prefix] [--sender ...] [--from ...] [--to ...] [--cc ...] [--bcc ...] [--subject ...] [--reply-to message] [--charset ...] [--signature file] [first_patch [last_patch]]\n"
if [ x$1 = x-h ]
then
printf $"
Create mail messages from a specified range of patches, or all patches in
the series file, and either store them in a mailbox file, or send them
immediately. The editor is opened with a template for the introduction.
Please see %s for details.
When specifying a range of patches, a first patch name of \`-' denotes the
first, and a last patch name of \`-' denotes the last patch in the series.
-m text
Text to use as the text in the introduction. When this option is
used, the editor will not be invoked, and the patches will be
processed immediately.
-M file
Like the -m option, but read the introduction from file.
--prefix prefix
Use an alternate prefix in the bracketed part of the subjects
generated. Defaults to \`patch'.
--mbox file
Store all messages in the specified file in mbox format. The mbox
can later be sent using formail, for example.
--send
Send the messages directly.
--sender
The envelope sender address to use. The address must be of the form
\`user@domain.name'. No display name is allowed.
--from, --subject
The values for the From and Subject headers to use. If no --from
option is given, the value of the --sender option is used.
--to, --cc, --bcc
Append a recipient to the To, Cc, or Bcc header.
--charset
Specify a particular message encoding on systems which don't use
UTF-8 or ISO-8859-15. This character encoding must match the one
used in the patches.
--signature file
Append the specified signature to messages (defaults to ~/.signature
if found; use \`-' for no signature).
--reply-to message
Add the appropriate headers to reply to the specified message.
" "@DOCSUBDIR@/README.MAIL"
exit 0
else
exit 1
fi
}
msgid()
{
local timestamp=$(date --utc "+%Y%m%d%H%M%S.%N")
echo "$timestamp@${opt_sender_address#*@}"
}
# Extract RFC 2822 compliant header values, including Long Header Fields,
# from messages
extract_header_value()
{
local header=$1
# Long Header Fields may span multiple lines, in which case CRLF
# is followed by space or tab (RFC 2822)
sed -ne "/^${header}/I,/^[^[:blank:]]/ { /^${header}/I { s/^${header}//I; p; n; }; /^[^[:blank:]]/q; /^$/q; p; }"
}
# See RFC 2822 Internet Message Format for how the In-Reply-To and
# References headers are generated...
in_reply_to_header()
{
local message=$1 message_id
message_id=$(extract_header_value Message-ID: < "$message")
message_id=${message_id# }
[ -n "$message_id" ] && echo "In-Reply-To: $message_id"
}
references_header()
{
local message=$1 message_id references in_reply_to
message_id=$(extract_header_value Message-ID: < "$message")
message_id=${message_id# }
references=$(extract_header_value References: < "$message")
references=${references# }
if [ -z "$references" ]
then
in_reply_to=$(extract_header_value In-Reply-To: < "$message")
in_reply_to=${in_reply_to# }
if [ -n "$in_reply_to" ]
then
case "$in_reply_to" in
*@*@*)
;;
*) references=$in_reply_to
;;
esac
fi
fi
if [ -z "$references" ]
then
references=$message_id
elif [ -n "$message_id" ]
then
references="$references"$'\n '"$message_id"
fi
[ -n "$references" ] && echo "References: $references"
}
process_mail()
{
local tmpfile=$(gen_tempfile)
cat > $tmpfile
set -- $($QUILT_DIR/scripts/edmail --charset $opt_charset \
--extract-recipients To \
--extract-recipients Cc \
--extract-recipients Bcc \
< $tmpfile)
if [ -n "$opt_send" ]
then
echo ${QUILT_SENDMAIL:-sendmail} \
${QUILT_SENDMAIL_ARGS--f "$opt_sender"} "$@"
$QUILT_DIR/scripts/edmail --charset $opt_charset \
--remove-header Bcc < $tmpfile \
| ${QUILT_SENDMAIL:-sendmail} \
${QUILT_SENDMAIL_ARGS--f "$opt_sender"} "$@"
else
local from_date=$(LC_ALL=POSIX date "+%a %b %e %H:%M:%S %Y")
echo "From $opt_sender_address $from_date"
sed -e 's/^From />From /' $tmpfile
echo
fi
rm -f $tmpfile
}
join_lines()
{
awk '
BEGIN { RS="\n\n" }
{ gsub(/[ \t\n]+/, " ")
sub(/ $/, "")
sub(/^ /, "")
print }
'
}
options=`getopt -o m:M:h \
--long from:,to:,cc:,bcc:,subject: \
--long send,mbox:,charset:,sender: \
--long prefix:,reply-to:,signature: -- "$@"`
if [ $? -ne 0 ]
then
usage
fi
eval set -- "$options"
opt_prefix=patch
if [ -r $HOME/.signature ]
then
opt_signature="$(< $HOME/.signature)"
fi
while true
do
case "$1" in
-m)
if [ -n "$opt_message" ]
then
echo $"Introduction message already specified" >&2
exit 1
fi
opt_message=$2
shift 2 ;;
-M)
if [ -n "$opt_message" ]
then
echo $"Introduction message already specified" >&2
exit 1
fi
opt_message=$(< "$2")
shift 2 ;;
--sender)
opt_sender=$2
shift 2 ;;
--from)
opt_from=$2
shift 2 ;;
--to)
opt_to[${#opt_to[@]}]=$2
shift 2 ;;
--cc)
opt_cc[${#opt_cc[@]}]=$2
shift 2 ;;
--bcc)
opt_bcc[${#opt_bcc[@]}]=$2
shift 2 ;;
--subject)
opt_subject=$2
shift 2 ;;
--prefix)
opt_prefix=$2
shift 2 ;;
--send)
opt_send=1
shift ;;
--mbox)
opt_mbox=$2
shift 2 ;;
--charset)
opt_charset=$2
shift 2 ;;
--reply-to)
opt_reply_to=$2
shift 2 ;;
--signature)
if [ "$2" = - ]
then
opt_signature=
else
opt_signature=$(< "$2")
fi
shift 2 ;;
-h)
usage -h ;;
--)
shift
break ;;
esac
done
if [ $# -gt 2 -o \( -z "$opt_send" -a -z "$opt_mbox" \) ]
then
usage
fi
if [ $# -ge 1 ]
then
if [ "$1" = - ]
then
first_patch="$(find_first_patch)" || exit 1
else
first_patch="$(find_patch "$1")" || exit 1
fi
if [ $# -ge 2 ]
then
if [ "$2" = - ]
then
last_patch="$(find_last_patch)" || exit 1
else
last_patch="$(find_patch "$2")" || exit 1
fi
else
last_patch=$first_patch
fi
fi
if [ -z "$opt_sender" ]
then
if [ -e /etc/mailname ]
then
hostname=$(< /etc/mailname)
else
hostname=$(hostname -f 2>/dev/null)
fi
if [ "$hostname" = "${hostname/.}" ]
then
hostname=$(hostname)
fi
opt_sender="${LOGNAME:-$(whoami)}@$hostname"
case "$opt_sender" in
*@*.*) ;;
*)
echo $"\
Could not determine the envelope sender address. Please use --sender." >&2
exit 1
;;
esac
fi
opt_sender_address=$(echo "$opt_sender" | sed -re 's:.*<([^<>]+)>.*:\1:')
if [ -z "$opt_charset" ]
then
case "${LC_ALL:-$ORIGINAL_LANG}" in
*.UTF-8)
opt_charset=UTF-8
;;
*)
opt_charset=ISO-8859-15
;;
esac
fi
if [ "$(type -t quilt_mail_patch_filter 2> /dev/null)" != function ]
then
quilt_mail_patch_filter()
{
local tmpdir=$(gen_tempfile -d)
cat > $tmpdir/patch
patch_header < $tmpdir/patch > $tmpdir/header
local subject
local -a mh
# Does this patch have a Subject: line?
subject=$(extract_header_value Subject: < $tmpdir/header)
if [ -n "$subject" ]
then
awk '
in_body { print }
/^$/ { in_body = 1 }
' $tmpdir/patch > $tmpdir/body
fi
# Does this patch have DESC // subject // EDESC?
if [ -z "$subject" ]
then
local desc=$(awk '
/^EDESC/ { desc = 0 }
desc { print }
/^DESC/ { desc = 1 }
' $tmpdir/header)
if [ -n "$desc" ]
then
subject=$(echo "$desc" | join_lines)
awk '
/^DESC/ { desc = 1 }
! desc { print }
/^EDESC/ { desc = 0 }
' $tmpdir/patch > $tmpdir/body
fi
fi
# Is the first paragraph short enough to be used as the subject?
if [ -z "$subject" ]
then
local para=$(sed -e $'/^[ \t]*$/q' $tmpdir/header)
if [ ${#para} -gt 0 -a ${#para} -lt 150 ]
then
subject=$(echo "$para" | join_lines)
awk '
in_body { print }
/^[ \t]*$/ { in_body = 1 }
' $tmpdir/patch > $tmpdir/body
fi
fi
if [ -z "$subject" ]
then
rm -rf $tmpdir
return 1
fi
subject=$(echo "$subject" \
| sed -e $'s/^\\(\\(\\[[^]]*\\]\\|fwd:\\|fw:\\|re:\\|aw:\\|tr:\\)[ \t]*\\)*//i')
echo "Replace-Subject: $subject"
# Add recipients defined by some recognized keywords
# In Signed-off-by: and Acked-by: lines, try to recognize email
# addresses that contain commas and add quotes, e.g.,
# Last, First <email> => "Last, First" <email>
set -- Signed-off-by Acked-by Suggested-by Reviewed-by Requested-by Reported-by Tested-by Cc
set -- "$*"
set -- ${*// /\\|}
sed -n -e "/\<${LOGNAME:-$(whoami)}@/d" \
-e 's/^\(\(To\|'"$*"'\):[ '$'\t'']*\)\([^"]*\(,[^"]*\)\+[^" '$'\t'']\)\([ '$'\t'']*<.*>\)/\1"\3"\5/I' \
-e 's/^To:\(.*@.*\)/Recipient-To:\1/Ip' \
-e 's/^\('"$*"'\):\(.*@.*\)/Recipient-Cc:\2/Ip' \
$tmpdir/header
echo
cat $tmpdir/body
rm -rf $tmpdir
}
fi
if [ -n "$first_patch" ]
then
if [ -n "$last_patch" ]
then
set -- $(patches_before "$last_patch") "$last_patch"
while [ $# -ne 0 ]
do
[ "$1" = "$first_patch" ] && break
shift
done
if [ $# -eq 0 ]
then
printf $"Patch %s not applied before patch %s\n" \
"$(print_patch $first_patch)" \
"$(print_patch $last_patch)" >&2
exit 1
fi
patches=( "$@" )
else
patches=( "$first_patch" $(patches_after "$first_patch") )
fi
else
patches=( $(cat_series) )
fi
total=${#patches[@]}
tmpdir=$(gen_tempfile -d)
add_exit_handler "rm -rf $tmpdir"
for patch in "${patches[@]}"
do
patch_file="$(patch_file_name "$patch")"
mkdir -p "$tmpdir/$(dirname "$patch")"
cat_file "$patch_file" \
| quilt_mail_patch_filter "$patch" > "$tmpdir/$patch"
status=${PIPESTATUS[1]}
subject=$(extract_header_value Replace-Subject: < "$tmpdir/$patch" | join_lines)
if [ $status -ne 0 -o -z "$subject" ]
then
if [ ! -r "$patch_file" ]
then
printf \
$"Patch %s does not exist\n" "$(print_patch "$patch")" >&2
else
printf \
$"Unable to extract a subject header from %s\n" "$(print_patch "$patch")" >&2
fi
rm -rf $tmpdir
exit 1
fi
subjects[${#subjects[@]}]="$patch"$'\t'"$subject"
done
dup_subjects=( $(
printf "%s\n" "${subjects[@]}" \
| sort -k2 \
| awk '{ patch = $1 ; sub(/^[^\t]+\t/, "");
if ($0 in subjects) {
if (subjects[$0] != "")
print subjects[$0];
print patch;
subjects[$0] = "";
}
else subjects[$0] = patch }' \
| while read patch; do
print_patch $patch
done
) )
if [ ${#dup_subjects[@]} -ne 0 ]
then
printf $"Patches %s have duplicate subject headers.\n" \
"$(array_join ", " "${dup_subjects[@]}")"
exit 1
fi
if [ -n "$opt_reply_to" ]
then
if [ ! -e "$opt_reply_to" ]
then
printf $"File %s does not exist\n" "$opt_reply_to"
exit 1
fi
if [ -z "$opt_subject" ]
then
opt_subject="Re: $(extract_header_value Subject: < "$opt_reply_to" \
| sed -e 's/^ *\([rR][eE]: *\)*//')"
fi
fi
introduction="$(gen_tempfile)"
(
cat <<-EOF
Message-ID: <$(msgid)>
User-Agent: quilt/@VERSION@
Date: $(date --rfc-822)
From: ${opt_from:-$opt_sender}
To: $(IFS=,; echo "${opt_to[*]}")
Cc: $(IFS=,; echo "${opt_cc[*]}")
Bcc: $(IFS=,; echo "${opt_bcc[*]}")
EOF
if [ -n "$opt_reply_to" ]
then
in_reply_to_header "$opt_reply_to"
references_header "$opt_reply_to"
fi
cat <<-EOF
Subject-Prefix: [$opt_prefix @num@/@total@]
Subject: $opt_subject
EOF
if [ -n "$opt_message" ]
then
echo "$opt_message"
echo
fi
if [ -n "$opt_signature" ]
then
echo "-- "
echo "$opt_signature"
fi
) | $QUILT_DIR/scripts/edmail --charset $opt_charset > $introduction
if [ -z "$opt_message" ]
then
if ! LANG=$ORIGINAL_LANG $EDITOR $introduction
then
rm -f $introduction
exit 1
fi
fi
subject=$(extract_header_value Subject: < $introduction | join_lines)
if [ -z "$subject" ]
then
if [ -z "$opt_message" ]
then
printf $"Introduction has no subject header (saved as %s)\n" \
"$introduction" >&2
else
printf $"Introduction has no subject header\n"
rm -f $introduction
fi
exit 1
fi
if [ -n "$opt_mbox" ]
then
exec 1> $opt_mbox
fi
subject_prefix=$(extract_header_value Subject-Prefix: < $introduction | join_lines)
[ -n "$subject_prefix" ] && subject_prefix="$subject_prefix "
subject_prefix=${subject_prefix//\'/\'\'}
subject_prefix=${subject_prefix//\//\\\/}
p=${subject_prefix//@num@/$(printf %0*d ${#total} 0)}
p=${p//@total@/$total}
sed -e $'s/^\\(Subject:[ \t]\\)/\\1'"$p"'/' \
-e '/^Subject-Prefix:/d' \
$introduction \
| $QUILT_DIR/scripts/edmail --charset $opt_charset \
--remove-empty-headers To Cc Bcc \
| process_mail
if [ -n "$opt_mbox" ]
then
exec 1>> $opt_mbox
fi
# Remember the timestamp of the last message sent. For each message,
# increment the timestamp by one second and wait with sending until
# that time has arrived. This allows MUAs to show the messages in the
# correct order.
last_ts=$(date '+%s' -d "$(sed -ne $'s/^Date:[ \t]*//p' $introduction)")
num=1
for patch in "${patches[@]}"; do
body=$tmpdir/$patch
#echo -n '.' >&2
# Timestamps that are a few seconds in the future don't hurt usually
#while [ $(date '+%s') -le $last_ts ]; do
# sleep 1
#done
((last_ts++))
new_date="$(date --rfc-822 -d "1970/01/01 UTC $last_ts seconds")"
modify="$(awk '
in_header { if (/^[ \t]/) {
headers[n] = headers[n] "\n" $0
next }
in_header = 0 }
sub(/^Recipient-/, "") { headers[++n] = $0
options[n] = "--add-good-recipient"
in_header = 1
next }
sub(/^Replace-/, "") { headers[++n] = $0
options[n] = "--replace-header"
in_header = 1
next }
END { for(n = 1; n in headers; n++) {
r = headers[n]
sub(/:.*/, "", r)
s = headers[n]
sub(/^[^:]*:[ \t]*/, "", s)
gsub(/'\''/, "'\'\''", s)
print options[n] " " r "='\''" s "'\'' \\" } }
' $body)"
# echo "$modify" | sed -e 's/^/>> /' >&2
p=${subject_prefix//@num@/$(printf %0*d ${#total} $num)}
p=${p//@total@/$total}
# Make pipes fail if any of their commands fail (requires bash 3):
set -o pipefail
( ( echo "Message-ID: <$(msgid)>"
awk '
/^$/ { exit }
tolower($0) !~ /^(message-id|references|in-reply-to):/ \
{ print }
' $introduction
references_header $introduction
echo "MIME-Version: 1.0"
echo "Content-Type: text/plain; charset=$opt_charset"
awk '
kill_header { if (/^[ \t]/) next ; kill_header = 0 }
!in_body && tolower($0) ~ /^(recipient|replace)-.*:/ \
{ kill_header = 1 ; next }
/^$/ { in_body = 1 }
{ print }
' $body
echo
#if [ -n "$opt_signature" ]
#then
# echo '-- '
# echo "$opt_signature"
#fi
) | eval $QUILT_DIR/scripts/edmail --charset $opt_charset \
--replace-header Date="\"$new_date\"" \
To Cc Bcc \
"$modify" \
| sed -e $'s/^\\(Subject:[ \t]\\)/\\1'"$p"'/' \
-e '/^Subject-Prefix:/d' \
| $QUILT_DIR/scripts/edmail --remove-empty-headers \
| process_mail ) 2> $tmpdir/err
status=$?
if [ -s $tmpdir/err ]
then
sed -e "s/^/${patch//\//\\/}: /" < $tmpdir/err >&2
fi
if [ $status -ne 0 ]
then
printf $"Introduction saved as %s\n" "$introduction" >&2
exit 1
fi
# If the character set is UTF-8, check for invalid byte
# sequences.
#content_length=${#body}
#if [ -n "$(echo "$body" | tr -d '\0-\177')" ]
#then
# charset=UTF-8
#fi
# Content-Transfer-Encoding: 7bit
# Content-Transfer-Encoding: 8bit
# Content-Type: text/plain; charset=ISO-8859-1
# Content-Type: text/plain; charset=UTF-8
((num++))
done
rm -f $introduction
### Local Variables:
### mode: shell-script
### End:
# vim:filetype=sh

116
quilt/new.in Normal file
View File

@ -0,0 +1,116 @@
#! @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 $QUILT_DIR/scripts/patchfns ]
then
echo "Cannot read library $QUILT_DIR/scripts/patchfns" >&2
exit 1
fi
. $QUILT_DIR/scripts/patchfns
fi
usage()
{
printf $"Usage: quilt new [-p n|-p ab] {patchname}\n"
if [ x$1 = x-h ]
then
printf $"
Create a new patch with the specified file name, and insert it after the
topmost patch. The name can be prefixed with a sub-directory name, allowing
for grouping related patches together.
-p n Create a -p n style patch (-p0 or -p1 are supported).
-p ab Create a -p1 style patch, but use a/file and b/file as the
original and new filenames instead of the default
dir.orig/file and dir/file names.
Quilt can be used in sub-directories of a source tree. It determines the
root of a source tree by searching for a %s directory above the
current working directory. Create a %s directory in the intended root
directory if quilt chooses a top-level directory that is too high up
in the directory tree.
" "$QUILT_PATCHES" "$QUILT_PATCHES"
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_strip_level=$2
shift 2 ;;
-h)
usage -h ;;
--)
shift
break ;;
esac
done
case "$opt_strip_level" in
'' | 1)
opt_strip_level= ;;
0 | ab)
;;
*)
printf $"Cannot create patches with -p%s, please specify -p0, p1, or -pab instead\n" \
"$opt_strip_level" >&2
exit 1
;;
esac
if [ $# -ne 1 ]
then
usage
fi
if [ "$QUILT_PATCHES" = "$QUILT_PC" ]
then
printf $"QUILT_PATCHES(%s) must differ from QUILT_PC(%s)\n" "$QUILT_PATCHES" "$QUILT_PC"
exit 1
fi
patch=${1#$QUILT_PATCHES/}
if patch_in_series $patch
then
printf $"Patch %s exists already\n" "$(print_patch $patch)" >&2
exit 1
fi
create_db
rm -rf "$QUILT_PC/$patch"
mkdir -p "$QUILT_PC/$patch"
if insert_in_series $patch ${opt_strip_level:+-p$opt_strip_level} && \
add_to_db $patch
then
printf $"Patch %s is now on top\n" "$(print_patch $patch)"
else
printf $"Failed to create patch %s\n" "$(print_patch $patch)" >&2
exit 1
fi
### Local Variables:
### mode: shell-script
### End:
# vim:filetype=sh

71
quilt/next.in Normal file
View File

@ -0,0 +1,71 @@
#! @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 $QUILT_DIR/scripts/patchfns ]
then
echo "Cannot read library $QUILT_DIR/scripts/patchfns" >&2
exit 1
fi
. $QUILT_DIR/scripts/patchfns
fi
usage()
{
printf $"Usage: quilt next [patch]\n"
if [ x$1 = x-h ]
then
printf $"
Print the name of the next patch after the specified or topmost patch in
the series file.
"
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
next=$(find_unapplied_patch "$1") || exit
if [ -n "$next" ]
then
print_patch $next
else
exit 2
fi
### Local Variables:
### mode: shell-script
### End:
# vim:filetype=sh

163
quilt/patches.in Normal file
View File

@ -0,0 +1,163 @@
#! @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 $QUILT_DIR/scripts/patchfns ]
then
echo "Cannot read library $QUILT_DIR/scripts/patchfns" >&2
exit 1
fi
. $QUILT_DIR/scripts/patchfns
fi
declare -a opt_files=()
usage()
{
printf $"Usage: quilt patches [-v] [--color[=always|auto|never]] {file} [files...]\n"
if [ x$1 = x-h ]
then
printf $"
Print the list of patches that modify any of the specified files. (Uses a
heuristic to determine which files are modified by unapplied patches.
Note that this heuristic is much slower than scanning applied patches.)
-v Verbose, more user friendly output.
--color[=always|auto|never]
Use syntax coloring (auto activates it only if the output is a tty).
"
exit 0
else
exit 1
fi
}
# Uses global variable opt_files
scan_applied()
{
local color=$1 prefix=$2
shift 2
local patch file
for patch in "$@"
do
for file in "${opt_files[@]}"
do
if file_in_patch "$file" $patch
then
echo "$color$prefix$(print_patch $patch)$color_clear"
break
fi
done
done
}
# Uses global variable opt_files
scan_unapplied()
{
local color=$1 prefix=$2
shift 2
local patch file
local -a files_bre
# Quote each file name only once
for file in "${opt_files[@]}"
do
files_bre[${#files_bre[@]}]=$(quote_bre "$file")
done
# "Or" all files in a single pattern
file=\\\($(array_join \\\| "${files_bre[@]}")\\\)
for patch in "$@"
do
if filenames_in_patch "$patch" \
| grep -q "^$file\$"
then
echo "$color$prefix$(print_patch $patch)$color_clear"
fi
done
}
options=`getopt -o vh --long color:: -- "$@"`
if [ $? -ne 0 ]
then
usage
fi
eval set -- "$options"
while true
do
case "$1" in
-v)
opt_verbose=1
shift ;;
--color)
case "$2" in
"" | always)
opt_color=1 ;;
auto | tty)
opt_color=
[ -t 1 ] && opt_color=1 ;;
never)
opt_color= ;;
*)
usage ;;
esac
shift 2 ;;
-h)
usage -h ;;
--)
shift
break ;;
esac
done
if [ $# -lt 1 ]
then
usage
fi
while [ $# -ge 1 ]
do
opt_files[${#opt_files[@]}]="$SUBDIR$1"
shift
done
top=$(top_patch)
if [ -n "$opt_verbose" ]
then
applied="+ "
current="= "
unapplied=" "
else
applied=""
current=""
unapplied=""
fi
[ -n "$opt_color" ] && setup_colors
setup_pager
scan_applied "$color_series_app" "$applied" \
$(patches_before $top)
[ -n "$top" ] && \
scan_applied "$color_series_top" "$current" \
$top
scan_unapplied "$color_series_una" "$unapplied" \
$(patches_after $top)
### Local Variables:
### mode: shell-script
### End:
# vim:filetype=sh

286
quilt/pop.in Normal file
View File

@ -0,0 +1,286 @@
#! @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 $QUILT_DIR/scripts/patchfns ]
then
echo "Cannot read library $QUILT_DIR/scripts/patchfns" >&2
exit 1
fi
. $QUILT_DIR/scripts/patchfns
fi
usage()
{
printf $"Usage: quilt pop [-afRqv] [--refresh] [num|patch]\n"
if [ x$1 = x-h ]
then
printf $"
Remove patch(es) from the stack of applied patches. Without options,
the topmost patch is removed. When a number is specified, remove the
specified number of patches. When a patch name is specified, remove
patches until the specified patch end up on top of the stack. Patch
names may include the patches/ prefix, which means that filename
completion can be used.
-a Remove all applied patches.
-f Force remove. The state before the patch(es) were applied will
be restored from backup files.
-R Always verify if the patch removes cleanly; don't rely on
timestamp checks.
-q Quiet operation.
-v Verbose operation.
--refresh
Automatically refresh every patch before it gets unapplied.
"
exit 0
else
exit 1
fi
}
list_patches()
{
local n patches
patches=( $(applied_patches) )
for ((n=${#patches[@]}-1; n>=0; n--))
do
if [ -n "$number" ]
then
(( number-- > 0 )) || break
fi
[ "${patches[n]}" = "$stop_at_patch" ] && break
echo "${patches[n]}"
done
}
files_may_have_changed()
{
local patch=$1 file
local patch_file=$(patch_file_name "$patch")
if [ $? -ne 0 -o ! -e "$patch_file" \
-o ! -e "$QUILT_PC/$patch/.timestamp" \
-o ! "$QUILT_PC/$patch/.timestamp" -nt "$patch_file" ]
then
return 0
fi
for file in $(files_in_patch "$patch")
do
[ ! "$QUILT_PC/$patch/.timestamp" -nt "$file" ] && return 0
done
return 1
}
# Check if all changes have been folded back into the patch (quilt refresh),
# and report any pending changes.
check_for_pending_changes()
{
local patch=$1
local patch_file=$(patch_file_name "$patch")
local workdir=$(gen_tempfile -d quilt) status=0
if [ -d "$QUILT_PC/$patch" ]
then
local prefix=$QUILT_PC/$patch/
[ ${prefix:0:1} == / ] || prefix=$PWD/$prefix
if ! ( cd $workdir && \
$QUILT_DIR/scripts/backup-files -B "$prefix" -r -k -s - )
then
printf $"Failed to copy files to temporary directory\n" >&2
rm -rf $workdir
return 1
fi
fi
if [ -s "$patch_file" ]
then
cat_file "$patch_file" \
| patch -d $workdir $QUILT_PATCH_OPTS \
$(patch_args "$patch") --no-backup-if-mismatch \
-f >/dev/null 2>/dev/null
fi
local file file2 failed
for file2 in $(files_in_patch "$patch")
do
file=$workdir/$file2
[ -e "$file" ] || file=/dev/null
[ -e "$file2" ] || file2=/dev/null
diff -q "$file" "$file2" > /dev/null || failed=1
done
if [ -n "$failed" ]
then
printf $"Patch %s does not remove cleanly (refresh it or enforce with -f)\n" \
"$(print_patch "$patch")" >&2
status=1
fi
rm -rf $workdir
return $status
}
remove_patch()
{
local patch=$1 status=0
trap "status=1" SIGINT
if [ -z "$opt_force" ] && \
( [ -n "$opt_remove" ] || files_may_have_changed "$patch" )
then
check_for_pending_changes "$patch" || status=1
fi
if [ $status -eq 0 ]
then
rm -f "$QUILT_PC/$patch/.timestamp"
if [ -z "$(shopt -s nullglob ; echo "$QUILT_PC/$patch/"*)" ]
then
printf $"Patch %s appears to be empty, removing\n" \
"$(print_patch "$patch")"
rmdir "$QUILT_PC/$patch"
status=$?
else
printf $"Removing patch %s\n" "$(print_patch "$patch")"
$QUILT_DIR/scripts/backup-files $silent -r -t -B "$QUILT_PC/$patch/" -
status=$?
fi
remove_from_db "$patch"
rm -f "$QUILT_PC/$patch~refresh"
fi
trap - SIGINT
return $status
}
options=`getopt -o fRqvah --long refresh -- "$@"`
if [ $? -ne 0 ]
then
usage
fi
eval set -- "$options"
while true
do
case "$1" in
-f)
opt_force=1
unset opt_remove
shift ;;
-R)
opt_remove=1
unset opt_force
shift ;;
-q)
opt_quiet=1
shift ;;
-v)
opt_verbose=1
shift ;;
-a)
opt_all=1
shift ;;
-h)
usage -h ;;
--refresh)
opt_refresh=1
shift ;;
--)
shift
break ;;
esac
done
if [ $# -gt 1 -o \( -n "$opt_all" -a $# -ne 0 \) ]
then
usage
fi
if [ -n "$opt_force" -a -n "$opt_refresh" ]
then
printf $"Options %s and %s are mutually exclusive\n" "-f" "--refresh"
exit 1
fi
if [ $# -eq 1 ]
then
if is_numeric "$1"
then
number=$1
else
stop_at_patch=$(find_applied_patch "$1") || exit 1
fi
else
[ -n "$opt_all" ] || number=1
fi
[ -n "$opt_quiet" ] && silent=-s
[ -z "$opt_verbose" ] && silent_unless_verbose=-s
top=$(top_patch)
if [ -n "$top" -a -e "$QUILT_PC/$top~refresh" -a -z "$opt_force" ]
then
printf $"Patch %s needs to be refreshed first.\n" \
"$(print_patch "$top")" >&2
exit 1
fi
if ! patches=$(list_patches) 2>&1
then
exit 1
elif [ -z "$patches" ]
then
printf $"No patch removed\n" >&2
exit 2
fi
# We will update the list of applied patches, which in turn will disable the
# consistency check. Enable it again if needed.
if [ -z "$opt_all" -a ! "$DB" -nt "$SERIES" ] && ! consistency_check
then
rearm_check=1
fi
for patch in $patches
do
[ -z "$opt_refresh" ] || quilt_command refresh $QUILT_REFRESH_ARGS
if ! remove_patch "$patch"
then
exit 1
fi
[ -z "$opt_quiet" ] && echo
done
patch="$(top_patch)"
if [ -z "$patch" ]
then
printf $"No patches applied\n"
else
# Ensure that the files in the topmost patch have a link count
# of one: This will automatically be the case in the usual
# situations, but we don't want to risk file corruption in weird
# corner cases such as files added to a patch but not modified.
$QUILT_DIR/scripts/backup-files -L -s -B "$QUILT_PC/$patch/" -
printf $"Now at patch %s\n" "$(print_patch "$patch")"
[ -z "$rearm_check" ] || touch "$SERIES"
fi
### Local Variables:
### mode: shell-script
### End:
# vim:filetype=sh

72
quilt/previous.in Normal file
View File

@ -0,0 +1,72 @@
#! @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 $QUILT_DIR/scripts/patchfns ]
then
echo "Cannot read library $QUILT_DIR/scripts/patchfns" >&2
exit 1
fi
. $QUILT_DIR/scripts/patchfns
fi
usage()
{
printf $"Usage: quilt previous [patch]\n"
if [ x$1 = x-h ]
then
printf $"
Print the name of the previous patch before the specified or topmost
patch in the series file.
"
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=$(find_patch_in_series "$1") || exit 1
previous=$(applied_before "$patch" | tail -n 1)
if [ -n "$previous" ]
then
print_patch $previous
else
exit 2
fi
### Local Variables:
### mode: shell-script
### End:
# vim:filetype=sh

447
quilt/push.in Normal file
View File

@ -0,0 +1,447 @@
#! @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 $QUILT_DIR/scripts/patchfns ]
then
echo "Cannot read library $QUILT_DIR/scripts/patchfns" >&2
exit 1
fi
. $QUILT_DIR/scripts/patchfns
fi
setup_colors
usage()
{
printf $"Usage: quilt push [-afqvm] [--fuzz=N] [--merge[=merge|diff3]] [--leave-rejects] [--color[=always|auto|never]] [--refresh] [num|patch]\n"
if [ x$1 = x-h ]
then
printf $"
Apply patch(es) from the series file. Without options, the next patch
in the series file is applied. When a number is specified, apply the
specified number of patches. When a patch name is specified, apply
all patches up to and including the specified patch. Patch names may
include the patches/ prefix, which means that filename completion can
be used.
-a Apply all patches in the series file.
-q Quiet operation.
-f Force apply, even if the patch has rejects.
-v Verbose operation.
--fuzz=N
Set the maximum fuzz factor (default: 2).
-m, --merge[=merge|diff3]
Merge the patch file into the original files (see patch(1)).
--leave-rejects
Leave around the reject files patch produced, even if the patch
is not actually applied.
--color[=always|auto|never]
Use syntax coloring (auto activates it only if the output is a tty).
--refresh
Automatically refresh every patch after it was successfully applied.
"
exit 0
else
exit 1
fi
}
interrupt()
{
local patch=$1
rollback_patch "$patch"
printf $"Interrupted by user; patch %s was not applied.\n" \
"$(print_patch "$patch")" >&2
exit 1
}
colorize()
{
if [ -n "$opt_color" ]; then
awk '
{ if (/FAILED|hunks? ignored|can'\''t find file|file .* already exists|NOT MERGED/)
print "'$color_patch_fail'" $0 "'$color_clear'"
else if (/already applied$/)
print "'$color_patch_fuzz'" $0 "'$color_clear'"
else if (/^Hunk/) {
sub(/^Hunk .* with fuzz [0-9]*/,
"'$color_patch_fuzz'&'$color_clear'")
sub(/offset -?[0-9]* lines?/,
"'$color_patch_offs'&'$color_clear'")
print
} else
print
}'
else
cat
fi
}
push_patch_args()
{
local patch=$1
if [ -z "$opt_reverse" ]
then
patch_args "$patch"
else
set -- $(patch_args "$patch")
if [ "${*#-R}" != "$*" ]
then
echo "${*#-R}"
else
echo "$*" -R
fi
fi
}
apply_patch()
{
local patch=$1 patch_file=$2
local output
[ -s "$patch_file" ] || return 0
set -- patch $QUILT_PATCH_OPTS $(push_patch_args "$patch") \
--backup --prefix="$QUILT_PC/$patch/" -f \
$no_reject_files $more_patch_args
if [ "${patch_file:(-3)}" = ".gz" ]
then
gzip -cd "$patch_file" | "$@" 2>&1
elif [ "${patch_file:(-4)}" = ".bz2" ]
then
bzip2 -cd "$patch_file" | "$@" 2>&1
elif [ "${patch_file:(-3)}" = ".xz" ]
then
xz -cd "$patch_file" | "$@" 2>&1
elif [ "${patch_file:(-5)}" = ".lzma" ]
then
lzma -cd "$patch_file" | "$@" 2>&1
elif [ "${patch_file:(-3)}" = ".lz" ]
then
lzip -cd "$patch_file" | "$@" 2>&1
else
"$@" -i "$patch_file" 2>&1
fi
}
rollback_patch()
{
local patch=$1
$QUILT_DIR/scripts/backup-files $silent_unless_verbose -r -B "$QUILT_PC/$patch/" -
}
cleanup_patch_output()
{
if [ -z "$opt_leave_rejects" ]
then
if [ -n "$opt_quiet" ]; then
# In this case, patch does not allow us to find out
# which file contains the rejects; it only tells us
# which reject file is used. We use a single temporary
# reject file, so this does not help us.
awk '
{ gsub(/ -- saving rejects to (file )?.*/, "") }
{ print }
'
else
awk '
/^patching file / { filename = substr($0, 15) }
{ gsub(/ -- saving rejects to (file )?.*/,
" -- rejects in file " filename) }
{ print }
'
fi
else
cat
fi
}
add_patch()
{
local patch=$1
local patch_file=$(patch_file_name "$patch")
local file status tmp
printf $"Applying patch %s\n" "$(print_patch "$patch")"
trap "interrupt $patch" SIGINT
no_reject_files=
if [ -z "$opt_leave_rejects" ]; then
tmp=$(gen_tempfile)
no_reject_files="-r $tmp"
fi
apply_patch "$patch" "$patch_file"
status=$?
trap "" SIGINT
[ -n "$tmp" ] && rm -f $tmp
if [ $status -eq 0 -o -n "$opt_force" ]
then
add_to_db "$patch"
if [ $status -eq 0 ]
then
rm -f "$QUILT_PC/$patch~refresh"
else
touch "$QUILT_PC/$patch~refresh"
fi
if [ -e "$QUILT_PC/$patch" ]
then
touch "$QUILT_PC/$patch/.timestamp"
else
mkdir "$QUILT_PC/$patch"
fi
if ! [ -e "$patch_file" ]
then
printf $"Patch %s does not exist; applied empty patch\n" \
"$(print_patch "$patch")"
elif [ -z "$(shopt -s nullglob ; echo "$QUILT_PC/$patch/"*)" ]
then
printf $"Patch %s appears to be empty; applied\n" \
"$(print_patch "$patch")"
elif [ $status -ne 0 ]
then
printf $"Applied patch %s (forced; needs refresh)\n" \
"$(print_patch "$patch")"
fi
else
rollback_patch "$patch"
tmp=$(gen_tempfile)
no_reject_files="-r $tmp"
opt_reverse=1
if apply_patch "$patch" "$patch_file" > /dev/null 2> /dev/null
then
printf $"Patch %s can be reverse-applied\n" \
"$(print_patch "$patch")"
else
printf $"Patch %s does not apply (enforce with -f)\n" \
"$(print_patch "$patch")"
fi
rollback_patch "$patch"
rm -f $tmp
status=1
fi
trap - SIGINT
return $status
}
list_patches()
{
local top=$(top_patch) n=0 patch
if [ -n "$top" ]
then
patches_after "$top"
else
cat_series
fi \
| if [ -n "$opt_all" ]
then
cat
else
while read patch
do
if [ -n "$number" ]
then
if [ $n -eq $number ]
then
break
fi
n=$[$n+1]
fi
echo "$patch"
if [ -z "$number" -a "$patch" = "$stop_at_patch" ]
then
break
fi
done
fi
}
check_duplicate_patches()
{
local IFS=$'\n'
local -a duplicates
local patch
duplicates=($((applied_patches ; printf $'%s\n' "${patches[@]}") \
| awk '{ if (lines[$0]++ == 1) print }'))
[ ${#duplicates[@]} -ge 1 ] || return 0
for patch in "${duplicates[@]}"
do
printf $"Patch %s is already applied; check your series file\n" \
"$(print_patch "$patch")"
done
return 1
}
options=`getopt -o fqvam::h --long fuzz:,merge::,leave-rejects,color::,refresh -- "$@"`
if [ $? -ne 0 ]
then
usage
fi
eval set -- "$options"
while true
do
case "$1" in
-f)
opt_force=1
shift ;;
-q)
opt_quiet=1
shift ;;
-v)
opt_verbose=1
shift ;;
-a)
opt_all=1
shift ;;
-h)
usage -h
;;
--fuzz)
opt_fuzz=$2
shift 2 ;;
-m | --merge)
case "$2" in
"" | merge)
opt_merge=1
opt_merge_arg= ;;
diff3)
opt_merge=1
opt_merge_arg="=diff3" ;;
*)
usage ;;
esac
shift 2 ;;
--leave-rejects)
opt_leave_rejects=1
shift ;;
--color)
case "$2" in
"" | always)
opt_color=1 ;;
auto | tty)
opt_color=
[ -t 1 ] && opt_color=1 ;;
never)
opt_color= ;;
*)
usage ;;
esac
shift 2 ;;
--refresh)
opt_refresh=1
shift ;;
--)
shift
break ;;
esac
done
if [ $# -gt 1 -o \( -n "$opt_all" -a $# -ne 0 \) ]
then
usage
fi
if [ -n "$opt_force" -a -n "$opt_refresh" ]
then
printf $"Options %s and %s are mutually exclusive\n" "-f" "--refresh"
exit 1
fi
if [ $# -eq 1 ]
then
if is_numeric "$1"
then
number=$1
else
stop_at_patch=$1
fi
else
[ -z "$opt_all" ] && number=1
fi
stop_at_patch=$(find_unapplied_patch "$stop_at_patch") || exit
[ -z "$opt_verbose" ] && silent_unless_verbose=-s
[ -n "$opt_force" ] && opt_leave_rejects=1
more_patch_args=
[ -n "$opt_quiet" ] && more_patch_args="$more_patch_args -s"
if [ -n "$opt_merge" ]
then
more_patch_args="$more_patch_args --merge$opt_merge_arg"
fi
[ -n "$opt_fuzz" ] && more_patch_args="$more_patch_args -F$opt_fuzz"
top=$(top_patch)
if [ -n "$top" -a -e "$QUILT_PC/$top~refresh" ]
then
printf $"The topmost patch %s needs to be refreshed first.\n" \
"$(print_patch "$top")"
exit 1
fi
patches=$(list_patches)
if [ -z "$patches" ]
then
printf $"No patch applied\n" >&2
exit 2
fi
# In theory, these patches can't be already applied. However in the case
# of a generated or manually tweaked series file, this could happen and
# cause havoc, so play it safe and check.
check_duplicate_patches || exit 1
create_db
for patch in $patches
do
if ! add_patch "$patch"
then
exit 1
fi
[ -z "$opt_refresh" ] || quilt_command refresh $QUILT_REFRESH_ARGS
[ -n "$opt_quiet" ] || echo
done \
| cleanup_patch_output \
| colorize
if [ ${PIPESTATUS[0]} -eq 0 ]; then
set -- $patches
printf $"Now at patch %s\n" "$(print_patch ${!#})"
else
exit 1
fi
### Local Variables:
### mode: shell-script
### End:
# vim:filetype=sh

369
quilt/refresh.in Normal file
View File

@ -0,0 +1,369 @@
#! @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 $QUILT_DIR/scripts/patchfns ]
then
echo "Cannot read library $QUILT_DIR/scripts/patchfns" >&2
exit 1
fi
. $QUILT_DIR/scripts/patchfns
fi
usage()
{
printf $"Usage: quilt refresh [-p n|-p ab] [-u|-U num|-c|-C num] [-z[new_name]] [-f] [--no-timestamps] [--no-index] [--diffstat] [--sort] [--backup] [--strip-trailing-whitespace] [patch]\n"
if [ x$1 = x-h ]
then
printf $"
Refreshes the specified patch, or the topmost patch by default.
Documentation that comes before the actual patch in the patch file 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, the script aborts
by default. 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 -p n style patch (-p0 or -p1 supported).
-p ab Create a -p1 style patch, but use a/file and b/file as the
original and new filenames instead of the default
dir.orig/file and dir/file names.
-u, -U num, -c, -C num
Create a unified diff (-u, -U) with num lines of context. Create
a context diff (-c, -C) with num lines of context. The number of
context lines defaults to 3.
-z[new_name]
Create a new patch containing the changes instead of refreshing the
topmost patch. If no new name is specified, \`-2' is added to the
original patch name, etc. (See the fork command.)
--no-timestamps
Do not include file timestamps in patch headers.
--no-index
Do not output Index: lines.
--diffstat
Add a diffstat section to the patch header, or replace the
existing diffstat section.
-f Enforce refreshing of a patch that is not on top.
--backup
Create a backup copy of the old version of a patch as patch~.
--sort Sort files by their name instead of preserving the original order.
--strip-trailing-whitespace
Strip trailing whitespace at the end of lines.
"
exit 0
else
exit 1
fi
}
die()
{
local status=$1
[ -n "$tmp_patch" ] && rm -f $tmp_patch
[ -n "$tmp_result" ] && rm -f $tmp_result
[ -n "$workdir" ] && rm -rf $workdir
exit $status
}
options=`getopt -o p:uU:cC:fz::h --long no-timestamps,diffstat,backup,sort \
--long no-index \
--long strip-trailing-whitespace -- "$@"`
if [ $? -ne 0 ]
then
usage
fi
eval set -- "$options"
opt_format=-u
while true
do
case "$1" in
-p)
opt_strip_level=$2
shift 2 ;;
-f)
opt_force=1
shift ;;
-u|-c)
opt_format=$1
shift ;;
-U|-C)
opt_format="$1 $2"
shift 2 ;;
-z)
opt_fork=1
opt_new_name=$2
shift 2 ;;
-h)
usage -h ;;
--no-timestamps)
QUILT_NO_DIFF_TIMESTAMPS=1
shift ;;
--no-index)
QUILT_NO_DIFF_INDEX=1
shift ;;
--diffstat)
opt_diffstat=1
shift ;;
--backup)
QUILT_BACKUP=1
shift ;;
--sort)
opt_sort=1
shift ;;
--strip-trailing-whitespace)
opt_strip_whitespace=1
shift ;;
--)
shift
break ;;
esac
done
if [ $# -gt 1 ]
then
usage
fi
QUILT_DIFF_OPTS="$QUILT_DIFF_OPTS $opt_format"
patch=$(find_applied_patch "$1") || exit 1
# Properly handle spaces in file names
saved_IFS=$IFS
IFS=$'\n'
if [ -z "$opt_sort" ]
then
files=( $(files_in_patch_ordered $patch) )
else
files=( $(files_in_patch $patch | sort) )
fi
IFS=$saved_IFS
if [ -n "$opt_fork" -a $# -ne 0 ]
then
printf $"Can only refresh the topmost patch with -z currently\n" >&2
exit 1
fi
if [ -n "$opt_fork" ]; then
old_patch=$patch
old_patch_args=$(patch_args "$old_patch")
if [ -n "$opt_new_name" ]
then
patch=$opt_new_name
else
patch=$(next_filename "$patch")
fi
if [ -e "$(patch_file_name "$patch")" ]; then
printf $"Patch %s exists already\n" "$(print_patch "$patch")" >&2
exit 1
fi
fi
if [ -z "$opt_strip_level" ]
then
opt_strip_level=$(patch_strip_level "$patch")
fi
case "$opt_strip_level" in
0 | 1)
num_strip_level=$opt_strip_level
;;
ab)
num_strip_level=1
;;
*)
printf $"Cannot refresh patches with -p%s, please specify -p0, -p1, or -pab instead\n" \
"$opt_strip_level" >&2
exit 1
;;
esac
trap "die 1" SIGTERM
if [ -n "$opt_fork" ]; then
workdir=$(gen_tempfile -d $PWD/quilt)
apply_patch_temporarily "$workdir" "$old_patch" || exit 1
fi
tmp_patch=$(gen_tempfile)
for file in "${files[@]}"
do
if [ -n "$opt_fork" ]; then
old_file=$workdir/$file
new_file=$file
else
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
fi
if ! diff_file "$file" "$old_file" "$new_file"
then
die 1
fi
if [ -n "$files_were_shadowed" -a -z "$opt_force" ]
then
printf $"More recent patches modify files in patch %s. Enforce refresh with -f.\n" "$(print_patch "$patch")" >&2
die 1
fi
if [ -n "$files_were_shadowed" -a -n "$opt_strip_whitespace" ]
then
printf $"Cannot use --strip-trailing-whitespace on a patch that has shadowed files.\n" >&2
fi
done >> $tmp_patch
if [ -n "$opt_fork" -a ! -s $tmp_patch ]
then
printf $"Nothing in patch %s\n" "$(print_patch "$patch")" >&2
die 1
fi
# Check for trailing whitespace
if [ -z "$opt_strip_whitespace" ]
then
$QUILT_DIR/scripts/remove-trailing-ws -n -p$num_strip_level \
< $tmp_patch
else
tmp_patch2=$(gen_tempfile)
if $QUILT_DIR/scripts/remove-trailing-ws -p$num_strip_level \
< $tmp_patch > $tmp_patch2
then
rm -f $tmp_patch
tmp_patch=$tmp_patch2
fi
fi
# FIXME: no stripping of non-topmost patch !!!
patch_file=$(patch_file_name "$patch")
trap "" SIGINT
tmp_result=$(gen_tempfile) || die 1
prev_patch_file=$patch_file
[ -e "$prev_patch_file" ] || prev_patch_file=/dev/null
if [ -n "$opt_diffstat" ]
then
cat_file "$prev_patch_file" | patch_header \
| awk '
function print_diffstat(arr, i) {
if (system("diffstat '"$QUILT_DIFFSTAT_OPTS \
-p$num_strip_level \
$tmp_patch | sed -e s:^:"'" prefix ":"))
exit 1
}
{ prefix=""
if (index($0, "#") == 1)
prefix="#"
}
/^#? .* \| *[1-9][0-9]* / { eat = eat $0 "\n"
next }
/^#? .* files? changed(, .* insertions?\(\+\))?(, .* deletions?\(-\))?/ \
{ print_diffstat()
diffstat_printed=1
eat = ""
next }
{ print eat $0
eat = "" }
END { printf "%s", eat
if (!diffstat_printed) {
print "---"
print_diffstat()
print prefix
}
}
' > $tmp_result
else
cat_file "$prev_patch_file" | patch_header \
> $tmp_result
fi
cat $tmp_patch >> $tmp_result
mkdir -p $(dirname "$patch_file")
if [ -e "$patch_file" ] && \
diff -q "$patch_file" $tmp_result > /dev/null
then
printf $"Patch %s is unchanged\n" "$(print_patch "$patch")"
elif cat_to_new_file "$patch_file" $QUILT_BACKUP < $tmp_result
then
if [ -n "$opt_fork" ]
then
if ! insert_in_series "$patch" "$old_patch_args"
then
printf $"Failed to insert patch %s into file series\n" \
"$(print_patch "$patch")" >&2
rm -f "$patch_file"
exit 1
fi
if ! rm -rf "$QUILT_PC/$patch" || \
! mv "$workdir" "$QUILT_PC/$patch" || \
! echo "$patch" >> $QUILT_PC/applied-patches
then
printf $"Failed to create patch %s\n" \
"$(print_patch "$patch")" >&2
exit 1
fi
printf $"Fork of patch %s created as %s\n" \
"$(print_patch "$old_patch")" \
"$(print_patch "$patch")"
else
if [ -s $tmp_patch ]
then
printf $"Refreshed patch %s\n" "$(print_patch "$patch")"
else
printf $"Nothing in patch %s\n" "$(print_patch "$patch")"
fi
fi
touch "$QUILT_PC/$patch/.timestamp"
else
die 1
fi
rm -f "$QUILT_PC/$patch~refresh"
if ! change_db_strip_level -p$num_strip_level "$patch"
then
die 1
fi
die 0
### Local Variables:
### mode: shell-script
### End:
# vim:filetype=sh

112
quilt/remove.in Normal file
View File

@ -0,0 +1,112 @@
#! @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 $QUILT_DIR/scripts/patchfns ]
then
echo "Cannot read library $QUILT_DIR/scripts/patchfns" >&2
exit 1
fi
. $QUILT_DIR/scripts/patchfns
fi
usage()
{
printf $"Usage: quilt remove [-P patch] {file} ...\n"
if [ x$1 = x-h ]
then
printf $"
Remove one or more files from the topmost or named patch. Files that
are modified by patches on top of the specified patch cannot be removed.
-P patch
Remove named files from the named patch.
"
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=$(find_applied_patch "$opt_patch") || exit 1
status=0
for file in "$@"
do
if ! file_in_patch "$SUBDIR$file" "$patch"
then
printf $"File %s is not in patch %s\n" \
"$SUBDIR$file" "$(print_patch "$patch")" >&2
status=1
continue
fi
next_patch=$(next_patch_for_file "$patch" "$SUBDIR$file")
if [ -n "$next_patch" ]
then
printf $"File %s modified by patch %s\n" \
"$SUBDIR$file" "$(print_patch "$next_patch")"
status=1
continue
fi
# Restore file from backup
if ! $QUILT_DIR/scripts/backup-files -r -t -s -B "$QUILT_PC/$patch/" "$SUBDIR$file"
then
printf $"Failed to remove file %s from patch %s\n" \
"$SUBDIR$file" "$(print_patch "$patch")" >&2
status=1
continue
fi
if [ -e "$(dirname "$QUILT_PC/$patch~refresh")" -a \
-e "$(patch_file_name "$patch")" ]
then
# The patch must be refreshed in order to get rid of the
# patch permanently.
touch "$QUILT_PC/$patch~refresh"
fi
printf $"File %s removed from patch %s\n" \
"$SUBDIR$file" "$(print_patch $patch)"
done
exit $status
### Local Variables:
### mode: shell-script
### End:
# vim:filetype=sh

110
quilt/rename.in Normal file
View File

@ -0,0 +1,110 @@
#! @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 $QUILT_DIR/scripts/patchfns ]
then
echo "Cannot read library $QUILT_DIR/scripts/patchfns" >&2
exit 1
fi
. $QUILT_DIR/scripts/patchfns
fi
usage()
{
printf $"Usage: quilt rename [-P patch] new_name\n"
if [ x$1 = x-h ]
then
printf $"
Rename the topmost or named patch.
-P patch
Patch to rename.
"
exit 0
else
exit 1
fi
}
move_file()
{
local old=$1 new=$2 newdir=$(dirname "$2")
[ -d "$newdir" ] || mkdir -p "$newdir" || return 1
mv "$old" "$new" || return 1
rmdir -p "$(dirname "$old")" 2> /dev/null
return 0
}
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 [ $# -ne 1 ]
then
usage
fi
patch=$(find_patch_in_series "$opt_patch") || exit 1
new_patch=${1#$QUILT_PATCHES/}
if patch_in_series "$new_patch" || \
[ -d "$QUILT_PC/$new_patch" ] || \
[ -e "$(patch_file_name "$new_patch")" ]
then
printf $"Patch %s exists already, please choose a different name\n" \
"$(print_patch "$new_patch")" >&2
exit 1
fi
if ( is_applied "$patch" && \
( ! rename_in_db "$patch" "$new_patch" || \
! move_file "$QUILT_PC/$patch" \
"$QUILT_PC/$new_patch" ) ) || \
! rename_in_series "$patch" "$new_patch" || \
( [ -e "$(patch_file_name "$patch")" ] && \
! move_file "$(patch_file_name "$patch")" \
"$(patch_file_name "$new_patch")" )
then
printf $"Renaming of patch %s to %s failed\n" \
"$(print_patch "$patch")" \
"$(print_patch "$new_patch")" >&2
exit 1
fi
printf $"Patch %s renamed to %s\n" \
"$(print_patch "$patch")" \
"$(print_patch "$new_patch")"
### Local Variables:
### mode: shell-script
### End:
# vim:filetype=sh

132
quilt/revert.in Normal file
View File

@ -0,0 +1,132 @@
#! @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 $QUILT_DIR/scripts/patchfns ]
then
echo "Cannot read library $QUILT_DIR/scripts/patchfns" >&2
exit 1
fi
. $QUILT_DIR/scripts/patchfns
fi
usage()
{
printf $"Usage: quilt revert [-P patch] {file} ...\n"
if [ x$1 = x-h ]
then
printf $"
Revert uncommitted changes to the topmost or named patch for the specified
file(s): after the revert, 'quilt diff -z' will show no differences for those
files. Changes to files that are modified by patches on top of the specified
patch cannot be reverted.
-P patch
Revert changes in the named patch.
"
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=$(find_applied_patch "$opt_patch") || exit 1
status=0
for file in "${@/#/$SUBDIR}"
do
if ! file_in_patch "$file" $patch
then
printf $"File %s is not in patch %s\n" \
"$file" "$(print_patch $patch)" >&2
status=1
continue
fi
next_patch=$(next_patch_for_file $patch "$file")
if [ -n "$next_patch" ]
then
printf $"File %s modified by patch %s\n" \
"$file" "$(print_patch $next_patch)"
status=1
continue
fi
done
[ $status -eq 0 ] || exit $status
workdir=$(gen_tempfile -d $PWD)
add_exit_handler "rm -rf $workdir"
apply_patch_temporarily $workdir $patch "${@/#/$SUBDIR}" || exit 1
for file in ${*/#/$SUBDIR}
do
if [ -s "$workdir/$file" ]
then
if [ -e "$file" ] &&
diff -q "$workdir/$file" "$file" > /dev/null
then
printf $"File %s is unchanged\n" "$file"
continue
fi
mkdir -p "$(dirname "$file")"
cp -p "$workdir/$file" "$file"
else
if [ ! -e "$file" ]
then
printf $"File %s is unchanged\n" "$file"
continue
fi
rm -f "$file"
fi
if [ $? -ne 0 ]
then
printf $"Failed to revert changes to %s in patch %s\n" \
"$file" "$(print_patch $patch)" >&2
status=1
else
printf $"Changes to %s in patch %s reverted\n" \
"$file" "$(print_patch $patch)"
fi
done
exit $status
### Local Variables:
### mode: shell-script
### End:
# vim:filetype=sh

View File

@ -0,0 +1,370 @@
#! @BASH@
set -e
# Keep /dev/null opened as we will need it repeatedly
exec 4> /dev/null
# Copyright (C) 2006 Steve Langasek <vorlon@debian.org>
# Copyright (C) 2011 Jean Delvare <jdelvare@suse.de>
# Loosely based on C implementation by Andreas Gruenbacher <agruen@suse.de>
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; version 2 dated June, 1991.
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
# MA 02110-1301, USA.
usage ()
{
echo "Usage: $0 -B prefix {-b|-r|-c|-L} [-s] [-k] [-t] [-L] {-f {file|-}|-|file ...}
Create or restore backup copies of a list of files.
Mandatory parameters:
-B Path name prefix for backup files
Action parameters:
-b Create backup (preserve links)
-r Restore the backup
-c Create simple copy
-L Ensure that source files have a link count of 1
Common options:
-s Silent operation; only print error messages
Restore options:
-k Keep backup files
-t Touch original files after restore (update their mtimes)
Backup options:
-L Ensure that source files have a link count of 1
File list parameters:
-f Read the filenames to process from file (- = standard input)
- Read the filenames to process from backup
"
}
: ${QUILT_DIR=@QUILT_DIR@}
. $QUILT_DIR/scripts/utilfns
ensure_nolinks()
{
local filename=$1
local link_count tmpname
link_count=$(stat @STAT_HARDLINK@ "$filename")
if [ $link_count -gt 1 ]; then
tmpname=$(mktemp "$filename.XXXXXX")
cp -p "$filename" "$tmpname"
mv "$tmpname" "$filename"
fi
}
notify_action()
{
[ $ECHO != : ] || return 0
local action=$1 filename=$2
while read -d $'\0' -r
do
$ECHO "$action ${REPLY#./}"
done < "$filename"
}
backup()
{
local file=$1
local backup=$OPT_PREFIX$file
local dir
dir=$(dirname "$backup")
[ -d "$dir" ] || mkdir -p "$dir"
if [ -e "$file" ]; then
$ECHO "Copying $file"
if [ -n "$OPT_NOLINKS" -a "$(stat @STAT_HARDLINK@ "$file")" = 1 ]; then
cp -p "$file" "$backup"
else
ln "$file" "$backup" 2>&4 || cp -p "$file" "$backup"
if [ -n "$OPT_NOLINKS" ]; then
ensure_nolinks "$file"
fi
fi
else
$ECHO "New file $file"
: > "$backup"
fi
}
restore()
{
local file=$1
local backup=$OPT_PREFIX$file
if [ ! -e "$backup" ]; then
return 1
fi
if [ -s "$backup" ]; then
$ECHO "Restoring $file"
if [ -e "$file" ]; then
rm "$file"
else
mkdir -p "$(dirname "$file")"
fi
ln "$backup" "$file" 2>&4 || cp -p "$backup" "$file"
if [ -n "$OPT_TOUCH" ]; then
touch "$file"
fi
else
$ECHO "Removing $file"
if [ -e "$file" ]; then
rm "$file"
fi
fi
if [ -z "$OPT_KEEP_BACKUP" ]; then
rm "$backup"
rmdir -p "${backup%/*}" 2>&4 || true
fi
}
restore_all()
{
local EMPTY_FILES NONEMPTY_FILES
# Store the list of files to process
EMPTY_FILES=$(gen_tempfile)
NONEMPTY_FILES=$(gen_tempfile)
trap "rm -f \"$EMPTY_FILES\" \"$NONEMPTY_FILES\"" EXIT
cd "$OPT_PREFIX"
find . -type f -size 0 -print0 > "$EMPTY_FILES"
find . -type f -size +0 -print0 > "$NONEMPTY_FILES"
cd "$OLDPWD"
if [ -s "$EMPTY_FILES" ]; then
xargs -0 rm -f < "$EMPTY_FILES"
notify_action Removing "$EMPTY_FILES"
fi
if [ -s "$NONEMPTY_FILES" ]; then
# Try a mass link (or copy) first, as it is much faster.
# It is however not portable and may thus fail. If it fails,
# fallback to per-file processing, which always works.
local target_dir=$PWD
if (cd "$OPT_PREFIX" && \
xargs -0 cp -l --parents --remove-destination \
--target-directory="$target_dir" \
< "$NONEMPTY_FILES" 2>&4); then
notify_action Restoring "$NONEMPTY_FILES"
else
(cd "$OPT_PREFIX" && find . -type d -print0) \
| xargs -0 mkdir -p
xargs -0 rm -f < "$NONEMPTY_FILES"
while read -d $'\0' -r
do
local file=${REPLY#./}
local backup=$OPT_PREFIX$file
$ECHO "Restoring $file"
ln "$backup" "$file" 2>&4 || cp -p "$backup" "$file"
done < "$NONEMPTY_FILES"
fi
if [ -n "$OPT_TOUCH" ]; then
xargs -0 touch -c < "$NONEMPTY_FILES"
fi
fi
if [ -z "$OPT_KEEP_BACKUP" ]; then
rm -rf "$OPT_PREFIX"
fi
}
noop_nolinks()
{
local file=$1
if [ -e "$file" ]; then
ensure_nolinks "$file"
fi
}
copy()
{
local file=$1
local backup=$OPT_PREFIX$file
local dir
dir=$(dirname "$backup")
[ -d "$dir" ] || mkdir -p "$dir"
if [ -e "$file" ]; then
$ECHO "Copying $file"
cp -p "$file" "$backup"
else
$ECHO "New file $file"
: > "$backup"
fi
}
copy_many()
{
local NONEMPTY_FILES
# Store the list of non-empty files to process
NONEMPTY_FILES=$(gen_tempfile)
trap "rm -f \"$NONEMPTY_FILES\"" EXIT
# Keep the temporary file opened to speed up the loop
exec 3> "$NONEMPTY_FILES"
cat "$OPT_FILE" \
| while read
do
if [ -e "$REPLY" ]; then
printf '%s\0' "$REPLY" >&3
else
# This is a rare case, not worth optimizing
copy "$REPLY"
fi
done
exec 3>&-
if [ -s "$NONEMPTY_FILES" ]; then
# Try a mass copy first, as it is much faster.
# It is however not portable and may thus fail. If it fails,
# fallback to per-file processing, which always works.
if xargs -0 cp -p --parents --target-directory="$OPT_PREFIX" \
< "$NONEMPTY_FILES" 2>&4; then
notify_action Copying "$NONEMPTY_FILES"
else
while read -d $'\0' -r
do
copy "$REPLY"
done < "$NONEMPTY_FILES"
fi
fi
}
# Test if some backed up files have a link count greater than 1
some_files_have_links()
{
(cd "$OPT_PREFIX" && find . -type f -print0) \
| xargs -0 stat @STAT_HARDLINK@ 2>&4 | grep -qv '^1$'
}
ECHO=echo
while [ $# -gt 0 ]; do
case $1 in
-b) OPT_WHAT=backup
;;
-r) OPT_WHAT=restore
;;
-c) OPT_WHAT=copy
;;
-B) OPT_PREFIX=$2
shift
;;
-f) OPT_FILE=$2
shift
;;
-s) ECHO=:
;;
-k) OPT_KEEP_BACKUP=1
;;
-L) OPT_NOLINKS=1
;;
-t) OPT_TOUCH=1
;;
-?*) usage
exit 0
;;
*) break
;;
esac
shift
done
if [ -z "$OPT_PREFIX" ]; then
usage
exit 1
fi
if [ "${OPT_PREFIX:(-1)}" != / ]; then
echo "Prefix must be a directory" >&2
exit 1
fi
if [ -z "$OPT_WHAT" ]; then
if [ -n "$OPT_NOLINKS" ]; then
OPT_WHAT=noop_nolinks
else
echo "Please specify an action" >&2
exit 1
fi
fi
if [ -n "$OPT_FILE" ]; then
if [ "$OPT_WHAT" = copy ]; then
copy_many
exit
fi
cat "$OPT_FILE" \
| while read nextfile; do
$OPT_WHAT "$nextfile"
done
exit
fi
if [ "$1" = - ]; then
# No backup directory? We're done
[ -d "$OPT_PREFIX" ] || exit 0
if [ "$OPT_WHAT" = restore ]; then
restore_all
exit
fi
# We typically expect the link count of backed up files to be 1
# already, so check quickly that this is the case, and only if not,
# take the slow path and walk the file list in search of files to fix.
if [ "$OPT_WHAT" = noop_nolinks ] && ! some_files_have_links; then
exit
fi
find "$OPT_PREFIX" -type f -print \
| while read
do
$OPT_WHAT "${REPLY#$OPT_PREFIX}"
done
if [ ${PIPESTATUS[0]} != 0 ]; then
exit 1
fi
exit
fi
while [ $# -gt 0 ]; do
$OPT_WHAT "$1"
shift
done
### Local Variables:
### mode: shell-script
### End:
# vim:filetype=sh

View File

@ -0,0 +1,470 @@
#!@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.
# Generate a dot-style graph of dependencies between patches.
use Getopt::Long;
use FileHandle;
use strict;
# Constants
my $short_edge_style = "color=grey";
my $close_node_style = "color=grey";
my $highlighted_node_style = "style=bold";
# Command line arguments
my $help = 0;
my $use_patcher = 0; # Assume patcher format for metadata
my $short_edge_thresh = 0; # threshold for coloring as "short", 0 = disable
my $long_edge_thresh = 0; # threshold for coloring as "long",0 = disable
my $edge_labels; # label all edges with filenames
my $short_edge_labels; # label short edges with filenames
my $long_edge_labels; # label long edges with filenames
my $edge_length_labels; # distance between patches as edge labels
my $node_numbers; # include sequence numbers
my $show_isolated_nodes; # also include isolated nodes
my $reduce; # remove transitive edges
my $filter_patchnames; # filter for compacting filenames
my $selected_patch; # only include patches related on this patch
my $selected_distance = -1; # infinity
my @highlight_patches; # a list of patches to highlight
my $lines; # check ranges with this number of context
# lines.
unless (GetOptions(
"h|help" => \$help,
"patcher" => \$use_patcher,
"short-edge=i" => \$short_edge_thresh,
"long-edge=i" => \$long_edge_thresh,
"edge-files" => \$edge_labels,
"short-edge-files" => \$short_edge_labels,
"long-edge-files" => \$long_edge_labels,
"edge-length" => \$edge_length_labels,
"node-numbers" => \$node_numbers,
"isolated" => \$show_isolated_nodes,
"reduce" => \$reduce,
"filter-patchnames=s" => \$filter_patchnames,
"select-patch=s" => \$selected_patch,
"select-distance=i" => \$selected_distance,
"highlight=s" => \@highlight_patches,
"lines=i" => \$lines) && !$help) {
my $basename = $0;
$basename =~ s:.*/::;
my $fd = $help ? *STDOUT : *STDERR;
print $fd <<EOF;
SYNOPSIS: $basename [-h] [--patcher] [--short-edge=num] [--long-edge=num]
[--short-edge-files] [--long-edge-files] [--edge-length]
[--node-numbers] [--isolated] [--reduce] [--filter-patchnames=filter]
[--select-patch=patch] [--select-distance=num] [--highlight=patch]
[--lines=num]
--patcher
Assume patch manager is Holger Schurig's patcher script instead
of the default quilt.
--short-edge=num, --long-edge=num
Define the maximum edge length of short edges, and minimum edge
length of long edges. Short edges are de-emphasized, and long
edges are emphasized. The default is to treat all edges equally.
-edge-files, --short-edge-files, --long-edge-files
Include conflicting filenames on all edges, short edges, or long
edges.
--edge-length
Use the edge lengths as edge labels. Cannot be used together with
filename labels.
--node-numbers
Include the sequence numbers of patches in the patch series in
node labels.
--isolated
Do not suppress isolated nodes.
--reduce
Remove transitive edges.
--filter-patchnames=filter
Define a filter command for transforming patch names into node
labels. The filter is passed each patch name on a separate line,
and must return the edge label for each patch on a separate line
(example: sed -e 's/^prefix//').
--select-patch=patch
Reduce the graph to nodes that depend on the specified patch,
and nodes that the specified patch depends on (recursively).
--select-distance=num
Limit the depth of recusion for --select-patch. The default is
to recurse exhaustively.
--highlight=patch
Highlight the specified patch. This option can be specified more
than once.
--lines=num
Check the ranges of lines that the patches modify for computing
dependencies. Include up to num lines of context.
EOF
exit $help ? 0 : 1;
}
my @nodes;
sub next_patch_for_file($$)
{
my ($n, $file) = @_;
for (my $i = $n + 1; $i < @nodes; $i++) {
return $i
if (exists $nodes[$i]{files}{$file});
}
return undef;
}
# Compute the ranges of lines that a patch modifies: The patch should
# have no context lines. The return value is a list of pairs of line
# numbers, alternatingly marking the start and end of a modification.
sub ranges($) {
my ($fd) = @_;
my (@left, @right);
while (<$fd>) {
if (/^\@\@ -(\d+)(?:,(\d+)?) \+(\d+)(?:,(\d+)?) \@\@/) {
push @left, ($3, $3 + $4);
push @right, ($1, $1 + $2);
}
}
return [ [ @left ], [ @right ] ];
}
sub backup_file_name($$) {
my ($patch, $file) = @_;
if ($use_patcher) {
return $file . "~" . $patch;
} else {
return $ENV{QUILT_PC} . "/" . $patch . "/" . $file;
}
}
# Compute the lists of lines that a patch changes in a file.
sub compute_ranges($$) {
my ($n, $file) = @_;
my $file1 = backup_file_name($nodes[$n]{file}, $file);
my $file2;
my $n2 = next_patch_for_file($n, $file);
if (defined $n2) {
$file2 = backup_file_name($nodes[$n2]{file}, $file);
} else {
$file2 = $file;
}
#print STDERR "diff -U$lines \"$file1\" \"$file2\"\n";
if (-z $file1) {
$file1="/dev/null";
return [[], []]
if (-z $file2);
} else {
$file2="/dev/null"
if (-z $file2);
}
my $fd = new FileHandle("diff -U$lines \"$file1\" \"$file2\" |");
my $ranges = ranges($fd);
$fd->close();
return $ranges;
}
sub is_a_conflict($$$) {
my ($from, $to, $filename) = @_;
$nodes[$from]{files}{$filename} = compute_ranges($from, $filename)
unless @{$nodes[$from]{files}{$filename}};
$nodes[$to]{files}{$filename} = compute_ranges($to, $filename)
unless @{$nodes[$to]{files}{$filename}};
my @a = @{$nodes[$from]{files}{$filename}[1]};
my @b = @{$nodes[$to ]{files}{$filename}[0]};
while (@a && @b) {
if ($a[0] < $b[0]) {
return 1 if @b % 2;
shift @a;
} elsif ($a[0] > $b[0]) {
return 1 if @a % 2;
shift @b;
} else {
return 1 if (@a % 2) == (@b % 2);
shift @a;
shift @b;
}
}
return 0;
}
# Fetch the list of patches (all of them must be applied)
my @patches;
if (@ARGV) {
if (@ARGV == 1 && $ARGV[0] eq "-") {
@patches = map { chomp ; $_ } <STDIN>;
} else {
@patches = @ARGV;
}
} elsif ($use_patcher) {
my $fh = new FileHandle("< .patches/applied")
or die ".patches/applied: $!\n";
@patches = map { chomp; $_ } <$fh>;
$fh->close();
} else {
my $fh = new FileHandle("< $ENV{QUILT_PC}/applied-patches")
or die ".$ENV{QUILT_PC}/applied-patches: $!\n";
@patches = map { chomp; $_ } <$fh>;
$fh->close();
}
# Fetch the list of files
my $n = 0;
foreach my $patch (@patches) {
my @files;
if ($use_patcher) {
my $fh = new FileHandle("< .patches/$patch.files")
or die ".patches/$patch.files: $!\n";
@files = map { chomp; $_ } <$fh>;
$fh->close();
} else {
if (! -d "$ENV{QUILT_PC}/$patch") {
print STDERR "$ENV{QUILT_PC}/$patch does not exist; skipping\n";
next;
}
@files = split(/\n/, `cd $ENV{QUILT_PC}/$patch ; find . -type f ! -name .timestamp`);
@files = map { s:\./::; $_ } @files;
}
push @nodes, {number=>$n++, name=>$patch, file=>$patch,
files=>{ map {$_ => []} @files } };
}
my %used_nodes; # nodes to which at least one edge is attached
# If a patch is selected, limit the graph to nodes that depend on this patch,
# and nodes that are dependent on this patch.
if ($selected_patch) {
for ($n = 0; $n < @nodes; $n++) {
last if $nodes[$n]{file} eq $selected_patch;
}
die "Patch $selected_patch not included\n"
if ($n == @nodes);
$used_nodes{$n} = 1;
my $selected_node = $nodes[$n];
push @{$selected_node->{attrs}}, $highlighted_node_style;
my %sel;
map { $sel{$_} = 1 } keys %{$selected_node->{files}};
foreach my $node (@nodes) {
foreach my $file (keys %{$node->{files}}) {
unless (exists $sel{$file}) {
delete $node->{files}{$file};
}
}
}
}
# Optionally highlight a list of patches
foreach my $patch (@highlight_patches) {
for ($n = 0; $n < @nodes; $n++) {
last if $nodes[$n]{file} eq $patch;
}
die "Patch $patch not included\n"
if ($n == @nodes);
my $node = $nodes[$n];
push @{$node->{attrs}}, $highlighted_node_style;
$node->{colorized} = 1;
}
# If a patchname filter is selected, pipe all patchnames through
# it.
if ($filter_patchnames) {
local *PIPE;
my $pid = open(PIPE, "- |"); # fork a child to read from
die "fork: $!\n"
unless defined $pid;
unless ($pid) { # child
# open a second pipe to the actual filter
open(PIPE, "| $filter_patchnames")
or die "$filter_patchnames: $!\n";
map { print PIPE "$_\n" } @patches;
close(PIPE);
exit;
} else { # parent
$n = 0;
foreach my $name (<PIPE>) {
last unless $n < @nodes;
chomp $name;
if ($name eq "") {
delete $nodes[$n++]{name};
} else {
$nodes[$n++]{name} = $name;
}
}
close(PIPE)
or die "patchname filter failed.\n";
die "patchname filter returned too few lines\n"
if $n != @nodes;
}
}
my %files_seen; # remember the last patch that touched each file
my %edges;
foreach my $node (@nodes) {
my $number = $node->{number};
foreach my $file (keys %{$node->{files}}) {
if (exists $files_seen{$file}) {
my $patches = $files_seen{$file};
my $patch;
# Optionally look at the line ranges the patches touch
if (defined $lines) {
for (my $n = $#$patches; $n >= 0; $n--) {
if (is_a_conflict($number, $patches->[$n], $file)) {
$patch = $patches->[$n];
last;
}
}
} else {
$patch = $patches->[$#$patches];
}
if (defined $patch) {
push @{$edges{"$number:$patch"}{names}}, $file;
$used_nodes{$number} = 1;
$used_nodes{$patch} = 1;
}
}
push @{$files_seen{$file}}, $number;
}
}
# Create adjacency lists
foreach my $node (@nodes) {
@{$node->{to}} = ();
@{$node->{from}} = ();
}
foreach my $key (keys %edges) {
my ($from, $to) = split /:/, $key;
push @{$nodes[$from]{to}}, $to;
push @{$nodes[$to]{from}}, $from;
}
# Colorize nodes that are close to each other
foreach my $node (@nodes) {
if (!exists $node->{colorized} && !exists $used_nodes{$node->{number}}) {
$node->{colorized} = 1;
push @{$node->{attrs}}, $close_node_style;
}
}
# Colorize short and long edges
foreach my $node (@nodes) {
my $close = 1;
foreach my $node2 (map {$nodes[$_]} @{$node->{to}}) {
if (abs($node2->{number} - $node->{number}) > $short_edge_thresh) {
$close = 0
}
}
foreach my $node2 (map {$nodes[$_]} @{$node->{from}}) {
if (abs($node2->{number} - $node->{number}) > $short_edge_thresh) {
$close = 0
}
}
if (!exists $node->{colorized} && $close) {
$node->{colorized} = 1;
push @{$node->{attrs}}, $close_node_style;
}
}
# Add node labels
foreach my $node (@nodes) {
my @label = ();
push @label, $node->{number} + 1
if ($node_numbers);
push @label, $node->{name}
if exists $node->{name};
push @{$node->{attrs}}, "label=\"" . join(": ", @label) . "\"";
}
# Add edge labels
foreach my $key (keys %edges) {
my ($from, $to) = split /:/, $key;
if ($edge_length_labels) {
push @{$edges{$key}->{attrs}}, "label=\"" . abs($to - $from) . "\""
if abs($to - $from) > 1;
} elsif (abs($to - $from) < $short_edge_thresh) {
push @{$edges{$key}->{attrs}}, $short_edge_style;
if ($edge_labels || $short_edge_labels) {
push @{$edges{$key}->{attrs}},
"label=\"" . join("\\n", @{$edges{$key}{names}}) . "\"";
}
} else {
if ($long_edge_thresh && abs($to - $from) > $long_edge_thresh) {
push @{$edges{$key}->{attrs}}, "style=bold";
if ($edge_labels || $long_edge_labels) {
push @{$edges{$key}->{attrs}},
"label=\"" . join("\\n", @{$edges{$key}{names}}) . "\"";
}
} else {
if ($edge_labels) {
push @{$edges{$key}->{attrs}},
"label=\"" . join("\\n", @{$edges{$key}{names}}) . "\"";
}
}
}
# Compute a pseudo edge length so that neato works acceptably.
push @{$edges{$key}{attrs}}, "len=\"" .
sprintf("%.2f", log(abs($to - $from) + 3)) . "\"";
}
#foreach my $node (@nodes) {
# push @{$node->{attrs}}, "shape=box";
#}
# Open output file / pipe
my $out;
if ($reduce) {
$out = new FileHandle("| tred")
or die "tred: $!\n";
} else {
$out = new FileHandle("> /dev/stdout")
or die "$!\n";
}
# Write graph
print $out "digraph dependencies {\n";
#print "\tsize=\"11,8\"\n";
foreach my $node (@nodes) {
next unless $show_isolated_nodes || exists $used_nodes{$node->{number}};
print $out "\tn$node->{number}";
if (exists $node->{attrs}) {
print $out " [" .
join(",", @{$node->{attrs}}) . "]";
}
print $out ";\n";
}
sub w($) {
my @n = split /:/, shift;
return $n[0] * 10000 + $n[1];
}
foreach my $key (sort { w($a) <=> w($b) } keys %edges) {
my ($from, $to) = split /:/, $key;
print $out "\tn$to -> n$from";
if (exists $edges{$key}{attrs}) {
print $out " [" . join(",", @{$edges{$key}{attrs}}) . "]";
}
print $out ";\n";
}
print $out "}\n";

233
quilt/scripts/edmail.in Normal file
View File

@ -0,0 +1,233 @@
#! @PERL@ -w
# RFCs important for this script:
#
# RFC 2822 - Internet Message Format
# RFC 2047 - MIME (Multipurpose Internet Mail Extensions) Part Three:
# Message Header Extensions for Non-ASCII Text
use Getopt::Long;
use strict;
# This ugly trick lets the script work even if gettext support is missing.
# We did so because Locale::gettext doesn't ship with the standard perl
# distribution.
BEGIN {
if (eval { require Locale::gettext }) {
import Locale::gettext;
require POSIX;
import POSIX, qw(setlocale);
} else {
eval '
use constant LC_MESSAGES => 0;
sub setlocale($$) { }
sub bindtextdomain($$) { }
sub textdomain($) { }
sub gettext($) { shift }
'
}
}
setlocale(LC_MESSAGES, "");
bindtextdomain("quilt", "@LOCALEDIR@");
textdomain("quilt");
sub _($) {
return gettext(shift);
}
my $special = '()<>\[\]:;@\\,"'; # special characters
my $special_dot = "$special."; # special characters + dot
sub check_recipient($);
my (%append_name, %append_value, $remove_empty_headers, %remove_header,
%extract_recipients_from, %replace_name, %replace_value, $charset);
GetOptions('add-recipient=s%' =>
sub {
$append_name{lc $_[1]} = $_[1];
$append_value{lc $_[1]} .= ",\n " . $_[2];
},
'add-good-recipient=s%' =>
sub {
eval { check_recipient($_[2]) };
if ($@) {
chomp $@;
print STDERR "$@; skipping\n";
} else {
$append_name{lc $_[1]} = $_[1];
$append_value{lc $_[1]} .= ",\n " . $_[2];
}
},
'remove-header=s' => sub { $remove_header{lc $_[1]}++ },
'remove-empty-headers' => \$remove_empty_headers,
'replace-header=s%' =>
sub {
$replace_name{lc $_[1]} = $_[1];
$replace_value{lc $_[1]} = $_[2];
},
'extract-recipients=s' => sub { $extract_recipients_from{lc $_[1]} = 1 },
'charset=s' => \$charset)
or exit 1;
my %recipient_headers = map {lc $_ => 1} (@ARGV, keys %append_name);
sub encode_header($) {
my ($word) = @_;
$word =~ s{[^\t\41-\76\100-\176]}{sprintf "=%02X", ord($&)}ge;
return "=?$charset?q?$word?=";
}
# Check for a valid display name
sub check_display_name($) {
my ($display) = @_;
if ($display =~ /^"((?:[^"\\]|\\[^\n\r])*)"/) {
my $quoted = $1;
if ($quoted =~ /[^\t\40-\176]/) {
$display = $quoted;
$display =~ s/\\//;
return encode_header($display);
}
} else {
local $_ = $display;
# The value is not (properly) quoted. Check for invalid characters.
while (/\(/ or /\)/) {
die sprintf(
_("Display name `%s' contains unpaired parentheses\n"), $display)
unless s/\(([^()]*)\)/$1/;
}
if ($display =~ /[^\t\40-\176]/ || $display =~ /[$special_dot]/) {
if ($display =~ /[^\1-\10\13\14\16-\37\40\41\43-\133\135-\177]/) {
return encode_header($display);
} elsif ($display =~ /[$special_dot]/) {
return "\"$display\"";
}
}
}
return $display;
}
# Check for a valid delivery address
sub check_delivery_address($) {
my ($deliver) = @_;
die sprintf(_("Delivery address `%s' is invalid\n"), $deliver)
if $deliver =~ /[ \t]/ or
$deliver =~ /[^ \t\40-\176]/ or
$deliver !~ /^[^$special]+@(\[?)[^$special_dot]+(?:\.[^$special_dot]+)*(\]?)$/ or
(!$1) != (!$2);
return $deliver;
}
sub check_recipient($) {
my ($recipient) = @_;
if ($recipient =~ /^(.*?)\s*<(.+)>$/) {
my $deliver = check_delivery_address($2);
return ( check_display_name($1) . " <" . $deliver . ">", $deliver );
} elsif ($recipient =~ /^(\S*)\s*\((.*)\)$/) {
my $deliver = check_delivery_address($1);
return ( $deliver . " (" . check_display_name($2) . ")", $deliver );
} else {
my $deliver = check_delivery_address($recipient);
return ( $deliver, $deliver );
}
}
sub split_recipients($) {
my ($recipients) = @_;
my @list = ();
while ($recipients !~ /^\s*$/) {
my $recipient;
if ($recipients =~ s/^\s*,?\s*((?:"(?:[^"]+)"|[^",])*)//) {
$recipient = $1;
} else {
$recipient = $recipients;
$recipients = "";
}
$recipient =~ s/\s*$//;
push @list, $recipient;
}
return @list;
}
my %recipients;
sub process_header($) {
local ($_) = @_;
my ($name, $value);
return unless defined $_;
unless (($name, $value) = /^([\41-\176]+):\s*(.*)/s) {
print;
return
}
if (%extract_recipients_from) {
if (exists $extract_recipients_from{lc $name}) {
$value =~ s/^\s*//; $value =~ s/\s*$//;
foreach my $recipient (split_recipients($value)) {
my $deliver;
($recipient, $deliver) = check_recipient($recipient);
print "$deliver\n";
}
}
return;
}
return if exists $remove_header{lc $name};
if (exists $replace_name{lc $name}) {
if (exists $replace_value{lc $name}) {
print "$replace_name{lc $name}: $replace_value{lc $name}\n";
delete $replace_value{lc $name};
}
return;
}
if (exists $recipient_headers{lc $1}) {
if (exists $append_name{lc $name}) {
$value .= $append_value{lc $name};
delete $append_name{lc $name};
}
my @recipients;
# This is a recipients field. Split out all the recipients and
# check the addresses. Suppress duplicate recipients.
foreach my $recipient (split_recipients($value)) {
my $deliver;
($recipient, $deliver) = check_recipient($recipient);
unless (exists $recipients{$deliver}) {
push @recipients, $recipient;
$recipients{$deliver} = $deliver;
}
}
print "$name: ", join(",\n ", @recipients), "\n"
if @recipients || !$remove_empty_headers;
} else {
print if $value ne "" || !$remove_empty_headers;
}
}
my $header;
while (<STDIN>) {
last if (/^$/);
if (/^\S/) {
process_header $header;
undef $header;
}
$header .= $_;
}
process_header $header;
foreach my $name (keys %append_name) {
process_header $append_name{$name} . ': ' . $append_value{$name};
}
unless (%extract_recipients_from) {
# Copy the message body to standard output
# FIXME check for 7-bit clean, else assume $charset
# FIXME if UTF-8, check for invalid characters!
# FIXME must make sure that all messages are written in
# either 7-bit or $charset => mbox !!!
# Content-Transfer-Encoding: 7bit
# Content-Transfer-Encoding: 8bit
# Content-Type: text/plain; charset=ISO-8859-15
# Content-Type: text/plain; charset=UTF-8
undef $/;
print "\n", <STDIN>;
}

View File

@ -0,0 +1,339 @@
#! @BASH@
# find original data file by md5sum
original_file()
{
local md5sum=$1
if ! [ -e $tmpdir/md5sums ]
then
echo >&4
create_md5sums "$RPM_SOURCE_DIR" $tmpdir/md5sums
echo -n "### rpmbuild: " >&4
fi
while read md5sum_ file_
do
if [ "$md5sum" = "$md5sum_" ]
then
echo ${file_#\*}
return 0
fi
done < $tmpdir/md5sums
# Try harder
if ! [ -e $tmpdir/more-md5sums ]
then
( cd $RPM_BUILD_DIR
find . -type f \
| sed -e 's:^.\/::' \
| xargs md5sum \
) > $tmpdir/more-md5sums
fi
while read md5sum_ file_
do
if [ "$md5sum" = "$md5sum_" ]
then
echo $QUILT_SETUP_PREFIX${file_#\*}
return 0
fi
done < $tmpdir/more-md5sums
# Return md5sum and error if we can't match the file
echo $md5sum
return 1
}
# Extract a command line option with or without argument
cmdline_option()
{
local letter=$1 no_arg=$2
shift
while [ $# -ne 0 ]
do
if [ "${1:0:2}" = -$letter ]
then
if [ -z "$no_arg" ]
then
[ "$1" = -$letter ] && set -- "$1$2"
fi
echo $1
break
fi
shift
done
}
# Extract the -p option from the command line
strip_option()
{
set -- $(cmdline_option p "$@")
[ "$1" != -p1 ] && echo $1
}
# Extract the -R option from the command line
reverse_option()
{
set -- $(cmdline_option R no_arg "$@")
echo $1
}
patch_opt_d()
{
local subdir=$(cmdline_option d "$@")
[ -z "$subdir" ] || echo "${subdir:2}"
}
patch_input_file()
{
while [ $# -gt 0 ]
do
case "$1" in
-i|--input)
if [ $# -ge 2 ]
then
echo "$2"
return
fi
;;
-i*)
echo "${1#-i}"
return
;;
--input=*)
echo "${1#--input=}"
return
;;
esac
shift
done
return 1
}
tar_input_file()
{
case "$1" in
# Modern option format
-*)
while [ $# -gt 0 ]
do
case "$1" in
# Extract the file name (long option)
--file)
echo "$2"
return
;;
--file=*)
echo "${1#--file=}"
return
;;
# Skip other long options
--*)
shift
;;
# Extract the file name (short option)
-*f)
echo "$2"
return
;;
-f*)
echo "${1#-f}"
return
;;
# Skip other short options and parameters
*)
shift
;;
esac
done
;;
# Legacy option format (must always come first)
*C*f*)
echo "$3"
return
;;
*f*)
echo "$2"
return
;;
?*)
# Eat legacy options and try again
until [ $# -eq 0 -o "${1:0:1}" = "-" ]
do
shift
done
tar_input_file "$@"
return
;;
esac
return 1
}
unzip_input_file()
{
while [ $# -gt 0 ]
do
case "$1" in
-*)
shift
;;
*)
echo "$1"
return
;;
esac
done
return 1
}
_7z_input_file()
{
while [ $# -gt 0 ]
do
case "$1" in
-*|e|x)
shift
;;
*)
echo "$1"
return
;;
esac
done
return 1
}
tar_opt_C()
{
case "$1" in
*C*f*)
echo "$2"
return ;;
esac
}
pwd_to_dir()
{
local subdir=$1 dir
if [ -n "$subdir" ]
then
dir=$(cd "$subdir" && echo $PWD)
else
dir=$PWD
fi
dir=${dir/$RPM_BUILD_DIR}
dir=${dir##/}
dir=${dir// /\\ }
echo "$dir"
}
# Who were we called as?
command=${0##*/}
PATH=${PATH#*:}
# If we are called too early, pass through without processing
[ -n "$RPM_BUILD_DIR" ] || exec $command "$@"
tmpdir=${RPM_BUILD_DIR%/*}
case $command in
patch)
echo -n p >&4
inputfile=$(patch_input_file "$@")
;;
tar)
echo -n t >&4
[ -n "$QUILT_SETUP_FAST" ] && exec tar "$@"
inputfile=$(tar_input_file "$@")
# For tar, file - means read from stdin
[ "$inputfile" = "-" ] && inputfile=
;;
unzip)
echo -n Z >&4
[ -n "$QUILT_SETUP_FAST" ] && exec unzip "$@"
inputfile=$(unzip_input_file "$@")
;;
7z)
echo -n 7 >&4
[ -n "$QUILT_SETUP_FAST" ] && exec 7z "$@"
inputfile=$(_7z_input_file "$@")
;;
esac
# If the file was not passed as a parameter, try to identify stdin
if [ -n "$QUILT_SETUP_FAST" -a -z "$inputfile" ]
then
inputfile=$(readlink /proc/self/fd/0)
[ "${inputfile:0:1}" = / -a -f "$inputfile" ] || inputfile=
fi
if [ -n "$inputfile" ]
then
if [ "${inputfile:0:1}" = / ]
then
unpackfile=${inputfile/$RPM_SOURCE_DIR}
else
unpackfile=$QUILT_SETUP_PREFIX$(dir_to_dir "$RPM_BUILD_DIR" "$inputfile")
fi
else
if [ -n "$QUILT_SETUP_FAST" ]
then
# In fast mode we can read from stdin directly, we won't let
# patch apply the patch anyway
md5sum=$(md5sum)
else
# put data from stdin into tmpfile
cat > $tmpdir/data
md5sum=$(md5sum < $tmpdir/data)
fi
unpackfile=$(original_file $md5sum)
if [ $? -ne 0 ]
then
# Report problem to the caller
echo -n "?" >&4
printf "Warning: no match for file with md5sum %s\n" \
$unpackfile >&2
unpackfile="#$unpackfile"
fi
fi
case $command in
patch)
subdir=$(patch_opt_d "$@")
dir=$(pwd_to_dir $subdir)
echo "patch ${dir:-.} $unpackfile" \
$(strip_option "$@") $(reverse_option "$@") >&3
;;
tar)
subdir=$(tar_opt_C "$@")
dir=$(pwd_to_dir $subdir)
echo "tar ${dir:-.} $unpackfile" >&3
;;
unzip)
dir=$(pwd_to_dir)
echo "unzip ${dir:-.} $unpackfile" >&3
;;
7z)
dir=$(pwd_to_dir)
echo "7z ${dir:-.} $unpackfile" >&3
;;
esac
# In fast mode, we don't actually apply patches
[ -n "$QUILT_SETUP_FAST" ] && exit 0
if [ -n "$inputfile" ]
then
exec $command "$@"
else
exec $command "$@" < $tmpdir/data
fi
### Local Variables:
### mode: shell-script
### End:
# vim:filetype=sh

1199
quilt/scripts/patchfns.in Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,146 @@
#! @PERL@ -w
# Remove trailing whitespace from modified lines in working files.
#
# Input: diff between original and working files (unified or context
# format).
use strict;
use FileHandle;
use File::Temp qw( :mktemp );
use Getopt::Std;
use vars qw($opt_p $opt_n);
# This ugly trick lets the script work even if gettext support is missing.
# We did so because Locale::gettext doesn't ship with the standard perl
# distribution.
BEGIN {
if (eval { require Locale::gettext }) {
import Locale::gettext;
require POSIX;
import POSIX, qw(setlocale);
} else {
eval '
use constant LC_MESSAGES => 0;
sub setlocale($$) { }
sub bindtextdomain($$) { }
sub textdomain($) { }
sub gettext($) { shift }
'
}
}
setlocale(LC_MESSAGES, "");
bindtextdomain("quilt", "@LOCALEDIR@");
textdomain("quilt");
sub _($) {
return gettext(shift);
}
$opt_p = 0;
getopts('np:')
or die sprintf(_("SYNOPSIS: %s [-p num] [-n] [patch]\n"), $0);
my %files;
my $file;
while (<>) {
print unless $opt_n;
if (/^--- ./) {
# unified diff
$file = undef;
while (<>) {
print unless $opt_n;
if (/^\+\+\+ (.+?)(?:[ \t][^\t]*)?$/) {
$file = $1;
$file =~ s<^([^/]+/+){$opt_p}><>;
#print STDERR "[$file]\n";
} elsif ($file && /^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/) {
my $removed = defined $2 ? $2 : 1;
my $added = defined $4 ? $4 : 1;
my $line_number = $3;
while ($removed || $added) {
$_ = <>;
defined $_
or die sprintf(_("%s: I'm confused.\n"), $0);
if (/^\+/) {
push @{$files{$file}}, $line_number
if s/(^\+.*?)[ \t]+$/$1/;
$added--;
$line_number++;
} elsif (/^-/) {
$removed--;
} elsif (/^ / || /^$/) {
$removed--;
$added--;
$line_number++;
}
print unless $opt_n;
}
}
}
} elsif (/^\*\*\* ./) {
# context diff
$file = undef;
while (<>) {
print unless $opt_n;
if ($file && /^--- (\d+)(?:,(\d+))? ----$/) {
my $line_number = $1;
my $last_line = defined $2 ? $2 : $1;
while ($line_number <= $last_line) {
$_ = <>;
defined $_ or last;
if (s/(^[+!] .*?)[ \t]+$/$1/) {
push @{$files{$file}}, $line_number;
}
$line_number++;
print unless $opt_n;
last if (/^\*\*\*[* ]/);
}
} elsif (/^--- (.+?)(?:[ \t][^\t]*)?$/) {
$file = $1;
$file =~ s<^([^/]+/+){$opt_p}><>;
#print STDERR "[$file]\n";
}
}
}
}
foreach my $file (sort keys %files) {
my @lines = @{$files{$file}};
if ($opt_n) {
print STDERR sprintf(
_("Warning: trailing whitespace in line %s of %s\n"), $lines[0], $file)
if @lines == 1;
print STDERR sprintf(
_("Warning: trailing whitespace in lines %s of %s\n"), join(',', @lines), $file)
if @lines > 1;
} else {
print STDERR sprintf(
_("Removing trailing whitespace from line %s of %s\n"), $lines[0], $file)
if @lines == 1;
print STDERR sprintf(
_("Removing trailing whitespace from lines %s of %s\n"), join(',', @lines), $file)
if @lines > 1;
}
unless ($opt_n) {
my $fh = new FileHandle("< $file")
or die "$file: $!\n";
my ($tmp, $tmpname) = mkstemp("$file.XXXXXX")
or die "$file.*: $!\n";
while (<$fh>) {
if (@lines && $lines[0] == $.) {
s/[ \t]+$//;
shift @lines;
}
print $tmp $_;
}
$fh->close;
$tmp->close
or die "$tmpname: $!\n";
rename $tmpname, $file
or die sprintf(_("Renaming %s to %s: %s\n"), $tmpname, $file, $!);
}
}

54
quilt/scripts/utilfns Normal file
View File

@ -0,0 +1,54 @@
# This file contains the common functions used by patchfns and backup-files.
# It is meant to be sourced by bash scripts.
# This script is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 as
# published by the Free Software Foundation.
#
# See the COPYING and AUTHORS files for more details.
basename()
{
local path=$1
while [ "${path:(-1)}" = "/" ]
do
path=${path%/}
done
echo "${path##*/}"
}
dirname()
{
local path=$1
while [ "${path:(-1)}" = "/" ]
do
path=${path%/}
done
local basename="${path##*/}"
path="${path:0:${#path}-${#basename}}"
while [ "${path:(-1)}" = "/" ]
do
path=${path%/}
done
if [ -n "$path" ]
then
echo "$path"
else
if [ ${1:0:1} = "/" ]
then
echo "/"
else
echo "."
fi
fi
}
gen_tempfile()
{
if [ "$1" = -d ]
then
mktemp -d ${2:-${TMPDIR:-/tmp}/quilt.}XXXXXX
else
mktemp ${1:-${TMPDIR:-/tmp}/quilt.}XXXXXX
fi
}

110
quilt/series.in Normal file
View File

@ -0,0 +1,110 @@
#! @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 $QUILT_DIR/scripts/patchfns ]
then
echo "Cannot read library $QUILT_DIR/scripts/patchfns" >&2
exit 1
fi
. $QUILT_DIR/scripts/patchfns
fi
usage()
{
printf $"Usage: quilt series [--color[=always|auto|never]] [-v]\n"
if [ x$1 = x-h ]
then
printf $"
Print the names of all patches in the series file.
--color[=always|auto|never]
Use syntax coloring (auto activates it only if the output is a tty).
-v Verbose, more user friendly output.
"
exit 0
else
exit 1
fi
}
cat_patches()
{
local color=$1 prefix=$2
shift 2
if [ $# -ge 1 ]
then
printf "$color$prefix$(patch_format)$color_clear\n" "$@"
fi
}
options=`getopt -o vh --long color:: -- "$@"`
if [ $? -ne 0 ]
then
usage
fi
eval set -- "$options"
while true
do
case "$1" in
-v)
opt_verbose=1
shift ;;
--color)
case "$2" in
"" | always)
opt_color=1 ;;
auto | tty)
opt_color=
[ -t 1 ] && opt_color=1 ;;
never)
opt_color= ;;
*)
usage ;;
esac
shift 2 ;;
-h)
usage -h ;;
--)
shift
break ;;
esac
done
if [ $# -ne 0 ]
then
usage
fi
setup_pager
if [ -n "$opt_verbose$opt_color" ]
then
[ -n "$opt_color" ] && setup_colors
top=$(top_patch)
cat_patches "$color_series_app" \
"${opt_verbose:++ }" $(patches_before $top)
[ -n "$top" ] && cat_patches "$color_series_top" \
"${opt_verbose:+= }" $top
cat_patches "$color_series_una" \
"${opt_verbose:+ }" $(patches_after $top)
else
cat_patches "" "" $(cat_series)
fi
### Local Variables:
### mode: shell-script
### End:
# vim:filetype=sh

531
quilt/setup.in Normal file
View File

@ -0,0 +1,531 @@
#! @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.
# Version check is irrelevant to this command.
skip_version_check=1
# Read in library functions
if [ "$(type -t patch_file_name)" != function ]
then
if ! [ -r $QUILT_DIR/scripts/patchfns ]
then
echo "Cannot read library $QUILT_DIR/scripts/patchfns" >&2
exit 1
fi
. $QUILT_DIR/scripts/patchfns
if [ -n "$SUBDIR" ]
then
cd $SUBDIR
unset SUBDIR
fi
fi
check_for_existing_directories()
{
local tag dir last_dir arg status=0
while read tag dir arg
do
[ "$dir" != "." -a "$dir" != "$last_dir" ] || continue
if [ -e "$prefix$dir" ]
then
printf $"Directory %s exists\n" \
"$prefix$dir" >&2
status=1
fi
last_dir=$dir
done < $tmpfile
return $status
}
check_for_existing_files()
{
local tag dir last_dir arg status=0
while read tag dir arg
do
[ "$tag" = "patch" -a "$dir" != "$last_dir" ] || continue
if [ -e "$prefix$dir/$QUILT_PATCHES" ]
then
printf $"Directory %s exists\n" \
"$prefix$dir/$QUILT_PATCHES" >&2
status=1
fi
if [ -e "$prefix$dir/$QUILT_SERIES" ]
then
printf $"File %s exists\n" \
"$prefix$dir/$QUILT_SERIES" >&2
status=1
fi
last_dir=$dir
done < $tmpfile
return $status
}
# Resolve ".." in path and clean up double slashes and "."
normalize_path()
{
echo "$1" | sed -r -e 's://:/:g' \
-e 's:/\.(/\.)*(/|$):\2:g' \
-e ':again' \
-e 's:/[^/]+/\.\.(/|$):\1:g' \
-e 'tagain'
}
create_symlink()
{
local target=$1 link=$2 up
if [ "${target:0:1}" = / -o "${link:0:1}" = / ]
then
[ "${target:0:1}" = / ] || target=$PWD/$target
ln -s "$target" "$link"
return
fi
set -- "$(normalize_path "$PWD/$target")" \
"$(normalize_path "$PWD/$link")"
while [ "${1%%/*}" = "${2%%/*}" ]
do
set -- "${1#*/}" "${2#*/}"
done
up=$(echo "$2" | sed -r -e 's:(^|/)[^/]*$::' -e 's:[^/]+:..:g')
set -- "${up:+$up/}$1"
set -- "${1%/}"
ln -s "${1:-.}" "$link"
}
dir_to_dir()
{
local from=$1 to=$2
[ "${from:0:1}" = / ] || from=$PWD/$from
from=$(normalize_path "$from")
[ "${to:0:1}" = / ] || to=$PWD/$to
to=$(normalize_path "$to")
# If the target is a subdirectory of the origin, we can express the path
# in a relative way. Otherwise, return the absolute path.
if [ "${to:0:${#from}}" = "$from" ]
then
to=${to:${#from}}
to=${to#/}
fi
echo "$to"
}
# create md5 sums, also for uncompressed files
create_md5sums()
{
local sourcedir=$1 output=$2
local file basename filetype
echo -n "### md5sum: " >&4
shopt -s nullglob
for file in "$sourcedir"*
do
basename=${file##*/}
case "$basename" in
ready|bigpack|_constraints|_service|baselibs.conf|MD5SUMS|MD5SUMS.meta|*.spec|*.changes|*.sig|*.sign|*rpmlintrc)
continue
;;
# In fast mode, we are only interested in patches, so filter out
# archives
*.tar|*.tar.Z|*.tar.gz|*.tgz|*.tar.bz2|*.tar.xz|*.tar.lz|*.zip|*.7z)
[ -n "$QUILT_SETUP_FAST" ] && continue
;;
esac
[ -f "$file" ] || continue
echo -n "." >&4
echo "md5sum < $file" >&5
set -- $(md5sum < "$file")
echo "$1 $basename"
case "$file" in
*.lzma)
# file doesn't reliably recognize lzma-compressed files
filetype="lzma"
;;
*.xz)
# old versions of file don't know about xz-compressed
# files
filetype="xz"
;;
*)
filetype=$(file -b "$file")
;;
esac
case "$filetype" in
compress*|gzip*)
echo -n "g" >&4
echo "gzip -cd $file | md5sum" >&5
set -- $(gzip -cd "$file" | md5sum)
echo "$1 $basename"
;;
bzip2*)
echo -n "b" >&4
echo "bzip2 -cd $file | md5sum" >&5
set -- $(bzip2 -cd "$file" | md5sum)
echo "$1 $basename"
;;
xz*|XZ*)
echo -n "x" >&4
echo "xz -cd $file | md5sum" >&5
set -- $(xz -cd "$file" | md5sum)
echo "$1 $basename"
;;
lzma*)
echo -n "l" >&4
echo "lzma -cd $file | md5sum" >&5
set -- $(lzma -cd "$file" | md5sum)
echo "$1 $basename"
;;
lzip*)
echo -n "l" >&4
echo "lzip -cd $file | md5sum" >&5
set -- $(lzip -cd "$file" | md5sum)
echo "$1 $basename"
;;
esac
done > $output
echo >&4
shopt -u nullglob
}
# Uses global variables: verbose, sourcedir, targetdir
inspect()
{
local specfile=$1 specdir
local abs_sourcedir=$sourcedir tmpdir
[ "${abs_sourcedir:0:1}" = / ] || abs_sourcedir=$PWD/$abs_sourcedir
if [ "${specfile:0:1}" = / ]
then
specdir=$(dirname "$specfile")
specfile=${spec_file##*/}
else
specdir=$PWD
fi
tmpdir=$(gen_tempfile -d ${VARTMPDIR:-/var/tmp}/${0##*/})
mkdir -p $tmpdir || exit 1
add_exit_handler "rm -rf $tmpdir"
mkdir -p $tmpdir/bin
ln -s $QUILT_DIR/scripts/inspect-wrapper $tmpdir/bin/patch
ln -s $QUILT_DIR/scripts/inspect-wrapper $tmpdir/bin/tar
ln -s $QUILT_DIR/scripts/inspect-wrapper $tmpdir/bin/unzip
ln -s $QUILT_DIR/scripts/inspect-wrapper $tmpdir/bin/7z
# Redirect file descriptors
# 5 is used in verbose mode, 4 in non-verbose mode, and 2 for both (real errors)
if [ -n "$verbose" ]
then
exec 3>&1 5>&2 4>/dev/null
else
exec 3>&1 4>&2 5>/dev/null
fi
if [ -n "$QUILT_SETUP_FAST" ]
then
# Fast mode
[ -d "$targetdir" ] || mkdir -p "$targetdir" || exit 1
ln -s "$targetdir" $tmpdir/build
export -f create_md5sums
else
# Standard mode
mkdir -p $tmpdir/build
create_md5sums "$sourcedir" $tmpdir/md5sums
fi
export -f normalize_path dir_to_dir
# let rpm do all the dirty specfile stuff ...
echo -n "### rpmbuild: " >&4
PATH="$tmpdir/bin:$PATH" \
rpmbuild --eval "%define _sourcedir $abs_sourcedir" \
--eval "%define _specdir $specdir" \
--eval "%define _builddir $tmpdir/build" \
--eval "%define __patch $tmpdir/bin/patch" \
--eval "%define __tar $tmpdir/bin/tar" \
--eval "%define __unzip $tmpdir/bin/unzip" \
--eval "%define __7zip $tmpdir/bin/7z" \
--eval "$DEFINE_FUZZ" \
--nodeps \
-bp "$specdir/$specfile" < /dev/null >&5 2>&5
status=$?
echo >&4
return $status
}
usage()
{
printf $"Usage: quilt setup [-d path-prefix] [-v] [--sourcedir dir] [--fuzz=N] [--slow|--fast] {specfile|seriesfile}\n"
if [ x$1 = x-h ]
then
printf $"
Initializes a source tree from an rpm spec file or a quilt series file.
-d Optional path prefix for the resulting source tree.
--sourcedir
Directory that contains the package sources. Defaults to \`.'.
-v Verbose debug output.
--fuzz=N
Set the maximum fuzz factor (needs rpm 4.6 or later).
--slow Use the original, slow method to process the spec file. This is the
default for now, but that might change in the future. In this mode,
rpmbuild generates a working tree in a temporary directory while all
its actions are recorded, and then everything is replayed from scratch
in the target directory.
--fast Use an alternative, faster method to process the spec file. In this
mode, rpmbuild is told to generate a working tree directly in the
target directory.
"
exit 0
else
exit 1
fi
}
options=`getopt -o d:vh --long sourcedir:,fuzz:,slow,fast -- "$@"`
if [ $? -ne 0 ]
then
usage
fi
eval set -- "$options"
prefix=
sourcedir=
while true
do
case "$1" in
-d)
prefix=${2%/}/
shift 2 ;;
-h)
usage -h ;;
-v)
verbose=1
shift ;;
--sourcedir)
sourcedir=${2%/}/
shift 2 ;;
--fuzz)
# Only works with rpm 4.6 and later
DEFINE_FUZZ="%define _default_patch_fuzz $2"
shift 2 ;;
--slow)
QUILT_SETUP_FAST=
shift ;;
--fast)
export QUILT_SETUP_FAST=1
shift ;;
--)
shift
break ;;
esac
done
if [ $# -ne 1 ]
then
usage
fi
tmpfile=$(gen_tempfile)
add_exit_handler "rm -f $tmpfile"
# The patches link will point to the source directory, while extra patches
# may be available under $prefix. If the latter is a subdirectory of the former,
# a prefix can be added to fix up the path to the extra patches.
export QUILT_SETUP_PREFIX=$(dir_to_dir "$sourcedir" "$prefix")
case "$1" in
*.spec)
spec_file=$1
# check if rpmbuild is installed before running inspect
check_external_tool rpmbuild rpm-build
if [ -n "$QUILT_SETUP_FAST" ]
then
if [ "${prefix:0:1}" = / ]
then
targetdir=$prefix
else
targetdir=$PWD/$prefix
fi
fi
if ! inspect "$spec_file" 2>&1 > $tmpfile
then
printf $"The %%prep section of %s failed; results may be incomplete\n" "$spec_file"
if [ -z "$verbose" ]
then
printf $"The -v option will show rpm's output\n"
fi
fi
;;
*)
series_file=$1
# parse series file
while read line; do
set -- $line
case "$@" in
"# Sourcedir: "*)
shift 2
tar_dir="$@"
tar_dir=${tar_dir// /\\ }
;;
"# Source: "*)
shift 2
source="$@"
filetype=$(file -b "$source")
case "$filetype" in
Zip*)
echo "unzip ${tar_dir:-.} ${source// /\\ }"
;;
7z*)
echo "7z ${tar_dir:-.} ${source// /\\ }"
;;
*)
echo "tar ${tar_dir:-.} ${source// /\\ }"
;;
esac
;;
"# Patchdir: "*)
shift 2
patch_dir="$@"
patch_dir=${patch_dir// /\\ }
;;
''|'#'*)
;;
*)
echo "patch ${patch_dir:-.} $@" ;;
esac
done < "$series_file" > $tmpfile
;;
esac
# If running on a spec file in fast mode, the source tree is already unpacked;
# in all other cases, we must prepare the source tree now
if [ -z "$QUILT_SETUP_FAST" -o -n "$series_file" ]
then
# Make sure that unpacking will not overwrite anything
check_for_existing_directories || exit 1
while read tag dir arg1 arg2
do
[ "${arg1:0:1}" != '#' ] || continue
case "$tag" in
tar)
tarball=$sourcedir$arg1
if [ ! -e "$tarball" ]
then
printf $"File %s not found\n" "$tarball" >&2
exit 1
fi
printf $"Unpacking archive %s\n" "$tarball"
mkdir -p "${prefix:-.}" "$prefix$dir"
cat_file "$tarball" \
| tar xf - -C "$prefix$dir"
;;
unzip)
tarball=$sourcedir$arg1
if [ ! -e "$tarball" ]
then
printf $"File %s not found\n" "$tarball" >&2
exit 1
fi
printf $"Unpacking archive %s\n" "$tarball"
mkdir -p "${prefix:-.}" "$prefix$dir"
unzip -qqo "$tarball" -d "$prefix$dir"
;;
7z)
tarball=$sourcedir$arg1
if [ ! -e "$tarball" ]
then
printf $"File %s not found\n" "$tarball" >&2
exit 1
fi
printf $"Unpacking archive %s\n" "$tarball"
mkdir -p "${prefix:-.}" "$prefix$dir"
7z x -bd "$tarball" -o"$prefix$dir"
;;
esac
done < $tmpfile
fi
if ! check_for_existing_files
then
echo $"Trying alternative patches and series names..." >&2
QUILT_PATCHES=quilt_patches
QUILT_SERIES=quilt_series
check_for_existing_files || exit 1
fi
series_header()
{
local tar_dir=$1 tar_file=$2 dir=$3
echo "# Patch series file for quilt, created by ${0##*/}"
[ -n "$tar_dir" ] && echo "# Sourcedir: $tar_dir"
[ -n "$tar_file" ] && echo "# Source: $tar_file"
echo "# Patchdir: $dir"
echo "#"
}
while read tag dir arg1 arg2
do
case "$tag" in
tar|unzip|7z)
tar_dir=$dir
[ "$tar_dir" = . ] && tar_dir=
tar_file=$arg1
;;
patch)
if [ ! -e "$prefix$dir/$QUILT_PATCHES" ]
then
create_symlink "$sourcedir" "$prefix$dir/$QUILT_PATCHES"
(cd "$prefix$dir" && create_db)
fi
if [ -n "$series_file" ]
then
[ -e "$prefix$dir/$QUILT_SERIES" ] \
|| create_symlink "$series_file" \
"$prefix$dir/$QUILT_SERIES"
else
if ! [ -e "$prefix$dir/$QUILT_SERIES" ]
then
series_header "$tar_dir" "$tar_file" "$dir" \
> "$prefix$dir/$QUILT_SERIES"
fi
echo "$arg1" $arg2 >> "$prefix$dir/$QUILT_SERIES"
fi
;;
esac
done < $tmpfile
### Local Variables:
### mode: shell-script
### End:
# vim:filetype=sh

93
quilt/snapshot.in Normal file
View File

@ -0,0 +1,93 @@
#! @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 $QUILT_DIR/scripts/patchfns ]
then
echo "Cannot read library $QUILT_DIR/scripts/patchfns" >&2
exit 1
fi
. $QUILT_DIR/scripts/patchfns
fi
usage()
{
printf $"Usage: quilt snapshot [-d]\n"
if [ x$1 = x-h ]
then
printf $"
Take a snapshot of the current working state. After taking the snapshot,
the tree can be modified in the usual ways, including pushing and
popping patches. A diff against the tree at the moment of the
snapshot can be generated with \`quilt diff --snapshot'.
-d Only remove current snapshot.
"
exit 0
else
exit 1
fi
}
options=`getopt -o dh -- "$@"`
if [ $? -ne 0 ]
then
usage
fi
eval set -- "$options"
while true
do
case "$1" in
-d)
opt_remove=1
shift ;;
-h)
usage -h ;;
--)
shift
break ;;
esac
done
if [ $# -ne 0 ]
then
usage
fi
snap_subdir=.snap
# Clean up from previous snapshot
rm -rf $QUILT_PC/$snap_subdir
if [ -n "$opt_remove" ]
then
exit 0
fi
# Save current working state
create_db
mkdir -p $QUILT_PC/$snap_subdir
for patch in $(applied_patches); do
files_in_patch $patch
done \
| awk ' # filter out duplicates
{ if (seen[$0])
next
seen[$0] = 1
}
{ print }
' \
| $QUILT_DIR/scripts/backup-files -c -s -f - -B "$QUILT_PC/$snap_subdir/"
### Local Variables:
### mode: shell-script
### End:
# vim:filetype=sh

65
quilt/top.in Normal file
View File

@ -0,0 +1,65 @@
#! @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 $QUILT_DIR/scripts/patchfns ]
then
echo "Cannot read library $QUILT_DIR/scripts/patchfns" >&2
exit 1
fi
. $QUILT_DIR/scripts/patchfns
fi
usage()
{
printf $"Usage: quilt top\n"
if [ x$1 = x-h ]
then
printf $"
Print the name of the topmost patch on the current stack of applied
patches.
"
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=$(find_top_patch) || exit 2
print_patch $top
### Local Variables:
### mode: shell-script
### End:
# vim:filetype=sh

74
quilt/unapplied.in Normal file
View File

@ -0,0 +1,74 @@
#! @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 $QUILT_DIR/scripts/patchfns ]
then
echo "Cannot read library $QUILT_DIR/scripts/patchfns" >&2
exit 1
fi
. $QUILT_DIR/scripts/patchfns
fi
usage()
{
printf $"Usage: quilt unapplied [patch]\n"
if [ x$1 = x-h ]
then
printf $"
Print a list of patches that are not applied, or all patches that follow
the specified patch in the series file.
"
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
start=$(find_patch_in_series "$1") || exit 1
patch=$(patch_after "$start")
[ -n "$start" -a -z "$patch" ] && exit
else
patch=$(find_unapplied_patch) || exit 1
fi
setup_pager
printf "$(patch_format)\n" "$patch" $(patches_after "$patch")
### Local Variables:
### mode: shell-script
### End:
# vim:filetype=sh

111
quilt/upgrade.in Normal file
View File

@ -0,0 +1,111 @@
#! @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.
# Don't abort in version check.
skip_version_check=1
# Read in library functions
if [ "$(type -t patch_file_name)" != function ]
then
if ! [ -r $QUILT_DIR/scripts/patchfns ]
then
echo "Cannot read library $QUILT_DIR/scripts/patchfns" >&2
exit 1
fi
. $QUILT_DIR/scripts/patchfns
fi
usage()
{
printf $"Usage: quilt upgrade\n"
if [ x$1 = x-h ]
then
printf $"
Upgrade the meta-data in a working tree from an old version of quilt to the
current version. This command is only needed when the quilt meta-data format
has changed, and the working tree still contains old-format meta-data. In that
case, quilt will request to run \`quilt upgrade'.
"
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
if version_check
then
printf $"The quilt meta-data in %s are already in the version %s format; nothing to do\n" "$QUILT_PC/" "$DB_VERSION"
exit 0
fi
printf $"Converting meta-data to version %s\n" "$DB_VERSION"
# Previously we have stripped standard patch extensions (.dif .diff
# .patch .gz .bz2) of patch names; we have used the mangled names in
# .pc/applied-patches, .pc/$patch/, but not in the series file.
for patch in $(applied_patches)
do
proper_name="$(grep "^$(quote_bre $patch)"'\(\|\.patch\|\.diff?\)\(\|\.gz\|\.bz2\)\([ \t]\|$\)' $SERIES)"
proper_name=${proper_name#$QUILT_PATCHES/}
proper_name=${proper_name%% *}
if [ -z "$proper_name" ]
then
failed=1
break
fi
if [ "$patch" != "$proper_name" -a -d $QUILT_PC/$patch ] \
&& grep -q "^$(quote_bre $patch)\$" \
$QUILT_PC/applied-patches
then
mv $QUILT_PC/$patch $QUILT_PC/$proper_name \
|| failed=1
rename_in_db $patch $proper_name \
|| failed=1
[ -z "$failed" ] || break
fi
done
if [ -n "$failed" ]
then
printf $"Conversion failed\n" >&2
printf $"
Please remove all patches using \`quilt pop -a' from the quilt version used to create this working tree, or remove the %s directory and apply the patches from scratch.\n" "$QUILT_PC" >&2
exit 1
fi
echo $DB_VERSION > $QUILT_PC/.version
### Local Variables:
### mode: shell-script
### End:
# vim:filetype=sh

View File

@ -0,0 +1,14 @@
$ mkdir patches
$ quilt new test.diff
> Patch %{P}test.diff is now on top
$ echo foo > foo
$ quilt add foo
> File foo added to patch %{P}test.diff
$ quilt add patches/bar
> File patches/bar is located below patches/
$ quilt add %{QUILT_PC}/baz
> File %{QUILT_PC}/baz is located below %{QUILT_PC}/

55
test/altered-series.test Normal file
View File

@ -0,0 +1,55 @@
# Check that manual changes to the series file are detected
$ mkdir patches
$ cat > patches/series
< 01.patch
< 02.patch
< 03.patch
$ quilt push -q 2
> Applying patch %{P}01.patch
> Patch %{P}01.patch does not exist; applied empty patch
> Applying patch %{P}02.patch
> Patch %{P}02.patch does not exist; applied empty patch
> Now at patch %{P}02.patch
$ quilt series -v
> + %{P}01.patch
> = %{P}02.patch
> %{P}03.patch
# Touch the series file but preserve the order -> OK
$ touch patches/series
$ quilt series -v
> + %{P}01.patch
> = %{P}02.patch
> %{P}03.patch
# Change the order of the patch series -> complain
$ cat > patches/series
< 03.patch
< 01.patch
< 02.patch
$ quilt series -v
> The series file no longer matches the applied patches. Please run 'quilt pop -a'.
$ quilt pop
> Patch %{P}02.patch appears to be empty, removing
>
> Now at patch %{P}01.patch
# That wasn't enough, keep complaining
$ quilt series -v
> The series file no longer matches the applied patches. Please run 'quilt pop -a'.
$ quilt pop -a
> Patch %{P}01.patch appears to be empty, removing
>
> No patches applied
$ quilt series -v
> %{P}03.patch
> %{P}01.patch
> %{P}02.patch

114
test/annotate.test Normal file
View File

@ -0,0 +1,114 @@
$ mkdir patches
$ cat > foo
< foo
< bar
< baz
$ quilt new patch
> Patch %{P}patch is now on top
$ quilt add foo
> File foo added to patch %{P}patch
$ sed -e 's:b:B:' foo > foo.new
$ mv foo.new foo
$ quilt refresh
> Refreshed patch %{P}patch
$ quilt annotate foo
> foo
> 1 Bar
> 1 Baz
>
> 1 %{P}patch
$ quilt new patch2
> Patch %{P}patch2 is now on top
$ quilt add foo
> File foo added to patch %{P}patch2
$ sed -e 's:Baz:baz:' foo > foo.new
$ mv foo.new foo
$ quilt refresh
> Refreshed patch %{P}patch2
$ quilt annotate foo
> foo
> 1 Bar
> 2 baz
>
> 1 %{P}patch
> 2 %{P}patch2
$ quilt new patch3
> Patch %{P}patch3 is now on top
$ quilt add foo
> File foo added to patch %{P}patch3
$ sed -e '/Bar/d' foo > foo.new
$ mv foo.new foo
$ quilt refresh
> Refreshed patch %{P}patch3
$ quilt annotate foo
> foo
> 2 baz
>
> 1 %{P}patch
> 2 %{P}patch2
> 3 %{P}patch3
$ quilt annotate -P patch3 foo
> foo
> 2 baz
>
> 1 %{P}patch
> 2 %{P}patch2
> 3 %{P}patch3
$ quilt annotate -P patch2 foo
> foo
> 1 Bar
> 2 baz
>
> 1 %{P}patch
> 2 %{P}patch2
$ quilt annotate -P patch foo
> foo
> 1 Bar
> 1 Baz
>
> 1 %{P}patch
$ quilt new patch4
> Patch %{P}patch4 is now on top
$ cat > jkl
< abc
< def
$ quilt add jkl wrz
> File jkl added to patch %{P}patch4
> File wrz added to patch %{P}patch4
$ rm -f jkl
$ cat > wrz
< one
< two
$ quilt refresh
> Refreshed patch %{P}patch4
$ quilt annotate jkl
>
> 1 %{P}patch4
$ quilt annotate wrz
> 1 one
> 1 two
>
> 1 %{P}patch4

35
test/applied.test Normal file
View File

@ -0,0 +1,35 @@
$ mkdir patches
$ echo a > a
$ echo b > b
$ diff -u a b > patches/patch
$ echo patch -p0 > patches/series
$ rm -f b
$ quilt push -q
> Applying patch %{P}patch
> Now at patch %{P}patch
$ quilt pop -q
> Removing patch %{P}patch
> No patches applied
$ patch -s -p0 < patches/patch
$ quilt push -q
> Applying patch %{P}patch
> 1 out of 1 hunk FAILED
> Patch %{P}patch can be reverse-applied
$ echo patch -p0 -R > patches/series
$ quilt push -q
> Applying patch %{P}patch
> Now at patch %{P}patch
$ quilt pop -q
> Removing patch %{P}patch
> No patches applied
$ patch -s -p0 -R < patches/patch
$ quilt push -q
> Applying patch %{P}patch
> 1 out of 1 hunk FAILED
> Patch %{P}patch can be reverse-applied

55
test/auto-refresh.test Normal file
View File

@ -0,0 +1,55 @@
$ mkdir patches
$ echo a > a
$ echo b > b
$ quilt new a.patch
> Patch %{P}a.patch is now on top
$ quilt add a
> File a added to patch %{P}a.patch
$ echo A > a
$ quilt new b.patch
> Patch %{P}b.patch is now on top
$ quilt add b
> File b added to patch %{P}b.patch
$ echo B > b
$ quilt pop -fa --refresh
> Options -f and --refresh are mutually exclusive
$ quilt pop -a --refresh
> Refreshed patch %{P}b.patch
> Removing patch %{P}b.patch
> Restoring b
>
> Refreshed patch %{P}a.patch
> Removing patch %{P}a.patch
> Restoring a
>
> No patches applied
$ quilt push -a --refresh
> Applying patch %{P}a.patch
> patching file a
> Patch %{P}a.patch is unchanged
>
> Applying patch %{P}b.patch
> patching file b
> Patch %{P}b.patch is unchanged
>
> Now at patch %{P}b.patch
$ quilt push -fa --refresh
> Options -f and --refresh are mutually exclusive
$ quilt pop -a --refresh
> Patch %{P}b.patch is unchanged
> Removing patch %{P}b.patch
> Restoring b
>
> Patch %{P}a.patch is unchanged
> Removing patch %{P}a.patch
> Restoring a
>
> No patches applied

231
test/backup-files.test Normal file
View File

@ -0,0 +1,231 @@
Unit test of the backup-files script.
# Test backup without options; it should link, not copy
$ echo foo > foo
$ echo bar > "space bar"
$ sleep 1
$ %{QUILT_DIR}/scripts/backup-files -B backup/ -b foo
> Copying foo
$ ls -l foo | awk '{ print $2 }'
> 2
$ ls -l backup/foo | awk '{ print $2 }'
> 2
$ [ backup/foo -nt foo ] && echo "mtimes differ"
$ %{QUILT_DIR}/scripts/backup-files -B backup/ -r foo
> Restoring foo
$ ls -l foo | awk '{ print $2 }'
> 1
# Test silent backup with -L; it should copy, not link
$ %{QUILT_DIR}/scripts/backup-files -B backup/ -b -s -L foo
$ ls -l foo | awk '{ print $2 }'
> 1
$ ls -l backup/foo | awk '{ print $2 }'
> 1
$ [ backup/foo -nt foo ] && echo "mtimes differ"
# Test restore without options
$ echo modified > foo
$ sleep 1
$ %{QUILT_DIR}/scripts/backup-files -B backup/ -r foo
> Restoring foo
$ cat foo
> foo
$ [ -e backup/foo ] && echo "backup/foo not deleted"
$ [ -e backup ] && echo "backup directory not deleted"
# Test backup files with hard links
$ ln foo foo2
$ %{QUILT_DIR}/scripts/backup-files -B backup/ -b -s -L foo
$ ls -l foo | awk '{ print $2 }'
> 1
$ ls -l backup/foo | awk '{ print $2 }'
> 2
$ %{QUILT_DIR}/scripts/backup-files -B backup/ -b -s -L foo2
$ ls -l foo | awk '{ print $2 }'
> 1
$ ls -l foo2 | awk '{ print $2 }'
> 1
$ ls -l backup/foo | awk '{ print $2 }'
> 2
$ ls -l backup/foo2 | awk '{ print $2 }'
> 2
# Test restore of files with hard links
$ rm -f foo foo2
$ %{QUILT_DIR}/scripts/backup-files -B backup/ -r -s foo
$ ls -l foo | awk '{ print $2 }'
> 2
$ ls -l backup/foo2 | awk '{ print $2 }'
> 2
$ [ -e backup/foo ] && echo "backup/foo not deleted"
$ [ ! -e foo2 ] || echo "file foo2 shouldn't exist"
$ %{QUILT_DIR}/scripts/backup-files -B backup/ -r -s foo2
$ ls -l foo | awk '{ print $2 }'
> 2
$ ls -l foo2 | awk '{ print $2 }'
> 2
$ [ -e backup/foo2 ] && echo "backup/foo2 not deleted"
$ [ -e backup ] && echo "backup directory not deleted"
# Test restore with -t
$ %{QUILT_DIR}/scripts/backup-files -B backup/ -b -s foo
$ touch -r foo foo.timeref
$ %{QUILT_DIR}/scripts/backup-files -B backup/ -r -s -t foo
$ ls -l foo | awk '{ print $2 }'
> 2
$ [ foo -nt foo.timeref ] || echo "touch failed"
# Test restore with -k
$ %{QUILT_DIR}/scripts/backup-files -B backup/ -b -s -L foo "space bar"
$ touch -r "space bar" bar.timeref
$ ls -l backup/foo | awk '{ print $2 }'
> 2
$ ls -l "backup/space bar" | awk '{ print $2 }'
> 1
$ mkdir tmp
$ cd tmp
$ %{QUILT_DIR}/scripts/backup-files -B ../backup/ -r -s -k foo "space bar"
$ cd ..
$ ls -l foo | awk '{ print $2 }'
> 1
$ ls -l "space bar" | awk '{ print $2 }'
> 1
$ ls -l backup/foo | awk '{ print $2 }'
> 3
$ ls -l "backup/space bar" | awk '{ print $2 }'
> 2
$ ls -l tmp/foo | awk '{ print $2 }'
> 3
$ ls -l "tmp/space bar" | awk '{ print $2 }'
> 2
$ rm -rf tmp
# Test restore all (-)
$ rm -f foo "space bar"
$ %{QUILT_DIR}/scripts/backup-files -B backup/ -r -s -t -
$ cat foo
> foo
$ cat "space bar"
> bar
$ [ "space bar" -nt bar.timeref ] || echo "touch failed"
# Backup and restore a non-existing files
$ mkdir "dir with spaces"
$ %{QUILT_DIR}/scripts/backup-files -B backup/ -b -s -L new "dir with spaces/space file"
$ echo data > new
$ echo data2 > "dir with spaces/space file"
$ ls -l backup/new | awk '{ print $5 }'
> 0
$ ls -l "backup/dir with spaces/space file" | awk '{ print $5 }'
> 0
$ %{QUILT_DIR}/scripts/backup-files -B backup/ -r -s -
$ [ ! -e backup/new ] || echo "file backup/new shouldn't exist"
$ [ ! -e new ] || echo "file new shouldn't exist"
$ [ ! -e "backup/dir with spaces/space file" ] || echo "file backup/dir with spaces/space file shouldn't exist"
$ [ ! -e "dir with spaces/space file" ] || echo "file dir with spaces/space file shouldn't exist"
# Test restore involving a dir name with spaces
$ echo data > "dir with spaces/space file"
$ %{QUILT_DIR}/scripts/backup-files -B backup/ -b -L "dir with spaces/space file"
> Copying dir with spaces/space file
$ rm -rf "dir with spaces"
$ %{QUILT_DIR}/scripts/backup-files -B backup/ -r -
> Restoring dir with spaces/space file
$ cat "dir with spaces/space file"
> data
$ [ -e backup ] && echo "backup directory not deleted"
# Test backup reading file list from a file
$ %{QUILT_DIR}/scripts/backup-files -B backup/ -b -s -L -f -
< foo
< new
< space bar
$ echo data > new
$ echo modified > foo
$ rm -f "space bar"
$ [ -e backup/new -a ! -s backup/new ] || echo "file backup/new isn't empty"
$ ls -l backup/new | awk '{ print $5 }'
> 0
$ cat backup/foo
> foo
$ cat "backup/space bar"
> bar
$ %{QUILT_DIR}/scripts/backup-files -B backup/ -r -s -f -
< foo
< new
< space bar
$ [ ! -e backup/new ] || echo "file backup/new shouldn't exist"
$ [ ! -e new ] || echo "file new shouldn't exist"
$ cat foo
> foo
$ cat "space bar"
> bar
# Test the special -L alone case
$ %{QUILT_DIR}/scripts/backup-files -B backup/ -b -L -f -
< new
< foo
< space bar
> New file new
> Copying foo
> Copying space bar
$ ln "space bar" "linked space"
$ ls -l foo | awk '{ print $2 }'
> 1
$ ls -l "space bar" | awk '{ print $2 }'
> 2
$ %{QUILT_DIR}/scripts/backup-files -B backup/ -L -
$ ls -l foo | awk '{ print $2 }'
> 1
$ ls -l "space bar" | awk '{ print $2 }'
> 1
$ [ ! -e new ] || echo "file new shouldn't exist"
# Second call should be idempotent
$ %{QUILT_DIR}/scripts/backup-files -B backup/ -L -
$ ls -l foo | awk '{ print $2 }'
> 1
$ ls -l "space bar" | awk '{ print $2 }'
> 1
$ [ ! -e new ] || echo "file new shouldn't exist"
$ %{QUILT_DIR}/scripts/backup-files -B backup/ -r - | sort
> Removing new
> Restoring foo
> Restoring space bar
$ rm "linked space"
# Test copy (as used by quilt snapshot)
$ %{QUILT_DIR}/scripts/backup-files -B snapshot/ -c -f -
< new
< foo
< space bar
< dir with spaces/space file
> New file new
> Copying foo
> Copying space bar
> Copying dir with spaces/space file
$ ls -l foo | awk '{ print $2 }'
> 2
$ ls -l "space bar" | awk '{ print $2 }'
> 1
$ ls -l "dir with spaces/space file" | awk '{ print $2 }'
> 1
$ [ ! -e new ] || echo "file new shouldn't exist"
$ ls -l snapshot/new | awk '{ print $2 }'
> 1
$ ls -l snapshot/foo | awk '{ print $2 }'
> 1
$ ls -l snapshot/"space bar" | awk '{ print $2 }'
> 1
$ ls -l snapshot/"dir with spaces/space file" | awk '{ print $2 }'
> 1
$ [ ! -s new ] || echo "file snapshot/new should be empty"
$ rm -rf snapshot

View File

@ -0,0 +1,83 @@
# Test that patch names including special characters such as a colons,
# brackets or parentheses are properly handled by all quilt commands
$ mkdir patches
$ quilt new "patch_with:strange[name]"
> Patch %{P}patch_with:strange[name] is now on top
$ echo foo > foo
$ quilt add foo
> File foo added to patch %{P}patch_with:strange[name]
$ quilt files
> foo
$ echo bar > foo
$ quilt diff -p ab -P "patch_with:strange[name]"
> Index: b/foo
> ===================================================================
> --- a/foo
> +++ b/foo
> @@ -1 +1 @@
> -foo
> +bar
$ quilt refresh -p ab
> Refreshed patch %{P}patch_with:strange[name]
$ quilt applied
> %{P}patch_with:strange[name]
$ quilt pop -q
> Removing patch %{P}patch_with:strange[name]
> No patches applied
$ quilt next
> %{P}patch_with:strange[name]
$ quilt push -q "patch_with:strange[name]"
> Applying patch %{P}patch_with:strange[name]
> Now at patch %{P}patch_with:strange[name]
$ quilt top
> %{P}patch_with:strange[name]
$ quilt rename "another:strange(name)"
> Patch %{P}patch_with:strange[name] renamed to %{P}another:strange(name)
$ quilt new "{%'}.patch"
> Patch %{P}{%'}.patch is now on top
$ quilt add foo
> File foo added to patch %{P}{%'}.patch
$ echo baz > foo
"
$ quilt previous
> %{P}another:strange(name)
$ quilt series
> %{P}another:strange(name)
> %{P}{%'}.patch
$ quilt refresh -p0 "{%'}.patch"
> Refreshed patch %{P}{%'}.patch
$ cat "patches/{%'}.patch"
> Index: foo
> ===================================================================
> --- foo.orig
> +++ foo
> @@ -1 +1 @@
> -bar
> +baz
$ quilt pop "another:strange(name)"
> Removing patch %{P}{%'}.patch
> Restoring foo
>
> Now at patch %{P}another:strange(name)
$ quilt remove foo
> File foo removed from patch %{P}another:strange(name)

76
test/comments.test Normal file
View File

@ -0,0 +1,76 @@
Regresion test case: Empty lines in patch descriptions were
accidentally removed.
$ mkdir patches
$ echo one > f
$ cat > patches/test.diff
< C1
<
< C3
<
< Index: f
< ===================================================================
< --- f.orig foo
< +++ f bar
< @@ -1 +1 @@
< -one
< +two
$ cat > patches/series
< test.diff -p0 # What a wonderful patch
$ quilt push
> Applying patch %{P}test.diff
>~ patching file `?f'?
>
> Now at patch %{P}test.diff
$ quilt refresh
> Refreshed patch %{P}test.diff
$ cat patches/test.diff
> C1
>
> C3
>
> Index: f
> ===================================================================
> --- f.orig
> +++ f
> @@ -1 +1 @@
> -one
> +two
$ quilt refresh -c
> Refreshed patch %{P}test.diff
$ cat patches/test.diff
> C1
>
> C3
>
> Index: f
> ===================================================================
> *** f.orig
> --- f
> ***************
> *** 1 ****
> ! one
> --- 1 ----
> ! two
$ quilt refresh
> Refreshed patch %{P}test.diff
$ cat patches/test.diff
> C1
>
> C3
>
> Index: f
> ===================================================================
> --- f.orig
> +++ f
> @@ -1 +1 @@
> -one
> +two

163
test/conflicts.test Normal file
View File

@ -0,0 +1,163 @@
This test case creates a patch and then applies that patch to a modified
source file. The source file is modified until the patch doesn't apply
anymore, then the patch is fixed.
$ mkdir patches
$ cat > one.txt
< 1
< 2
< 3
< 4
< 5
< 6
< 7
< --
< a
< b
< c
< d
< e
< f
< g
$ quilt new a.diff
> Patch %{P}a.diff is now on top
$ echo %{?}
> 0
$ quilt add one.txt
> File one.txt added to patch %{P}a.diff
$ echo %{?}
> 0
$ mv one.txt one.orig
$ sed -e "s/4/4+/" -e 's/d/d+/' one.orig > one.txt
$ quilt refresh
> Refreshed patch %{P}a.diff
$ echo %{?}
> 0
$ quilt pop -q
> Removing patch %{P}a.diff
> No patches applied
$ echo %{?}
> 0
$ sed -e "s/^\\([17]\\)\$/\\1-/" one.orig > one.txt
$ quilt push -q
> Applying patch %{P}a.diff
> Now at patch %{P}a.diff
$ echo %{?}
> 0
$ quilt pop -q
> Removing patch %{P}a.diff
> No patches applied
$ echo %{?}
> 0
$ sed -e "s/^\\([1267]\\)\$/\\1-/" one.orig > one.txt
$ quilt push -q
> Applying patch %{P}a.diff
> Now at patch %{P}a.diff
$ echo %{?}
> 0
$ quilt pop -q
> Removing patch %{P}a.diff
> No patches applied
$ echo %{?}
> 0
$ sed -e "s/^\\([123567]\\)\$/\\1-/" one.orig > one.txt
$ quilt push -q
> Applying patch %{P}a.diff
> 1 out of 2 hunks FAILED
> Patch %{P}a.diff does not apply (enforce with -f)
$ echo %{?}
> 1
$ quilt push -qf
> Applying patch %{P}a.diff
>~ 1 out of 2 hunks FAILED -- saving rejects to (file )?`?one.txt.rej'?
> Applied patch %{P}a.diff (forced; needs refresh)
$ echo %{?}
> 1
$ mv one.txt one.x
$ sed -e "s/4/4+/" one.x > one.txt
$ rm -f one.x
$ quilt diff -z | grep -v "^\\(---\\|+++\\)"
>~ Index: [^/]+/one\.txt
> ===================================================================
> @@ -1,7 +1,7 @@
> 1-
> 2-
> 3-
> -4
> +4+
> 5-
> 6-
> 7-
$ echo %{?}
> 0
$ quilt diff | grep -v "^\\(---\\|+++\\)"
>~ Index: [^/]+/one\.txt
> ===================================================================
> @@ -1,7 +1,7 @@
> 1-
> 2-
> 3-
> -4
> +4+
> 5-
> 6-
> 7-
> @@ -9,7 +9,7 @@
> a
> b
> c
> -d
> +d+
> e
> f
> g
$ echo %{?}
> 0
$ quilt refresh
> Refreshed patch %{P}a.diff
$ echo %{?}
> 0
$ cat patches/a.diff | grep -v "^\\(---\\|+++\\)"
>~ Index: [^/]+/one\.txt
> ===================================================================
> @@ -1,7 +1,7 @@
> 1-
> 2-
> 3-
> -4
> +4+
> 5-
> 6-
> 7-
> @@ -9,7 +9,7 @@
> a
> b
> c
> -d
> +d+
> e
> f
> g
$ quilt pop -q
> Removing patch %{P}a.diff
> No patches applied
$ echo %{?}
> 0

58
test/create-delete.test Normal file
View File

@ -0,0 +1,58 @@
Check whether quilt generates patches properly so that GNU patch recognizes
file creates and deletions.
$ mkdir patches
$ echo delete > delete
$ quilt new test.diff
> Patch %{P}test.diff is now on top
$ quilt add create
> File create added to patch %{P}test.diff
$ echo create > create
$ quilt refresh
> Refreshed patch %{P}test.diff
$ quilt add delete
> File delete added to patch %{P}test.diff
$ rm -f delete
$ quilt refresh
> Refreshed patch %{P}test.diff
$ quilt header -r
< ---
< create | 1 +
< delete | 1 -
< 2 files changed, 1 insertion(+), 1 deletion(-)
<
> Replaced header of patch %{P}test.diff
$ quilt patches -v create
> = %{P}test.diff
$ quilt patches delete
> %{P}test.diff
$ quilt pop -q
> Removing patch %{P}test.diff
> No patches applied
$ quilt patches create
> %{P}test.diff
$ quilt patches -v delete
> %{P}test.diff
$ quilt patches -- /dev/null dev/null null ---
$ echo create > create
$ rm -f delete
$ patch -p1 --dry-run < patches/test.diff
>~ The next patch would create the file `?create'?,
> which already exists! Assume -R? [n]
> Apply anyway? [n]
> Skipping patch.
>~ 1 out of 1 hunk ignored( -- saving rejects to( file)? create.rej)?
>~ The next patch would delete the file `?delete'?,
> which does not exist! Assume -R? [n]
> Apply anyway? [n]
> Skipping patch.
> 1 out of 1 hunk ignored

101
test/delete.test Normal file
View File

@ -0,0 +1,101 @@
Test the delete command.
$ mkdir patches
$ quilt delete
> No series file found
$ cat > test.txt
< Calling pci_match_id() would be more feasible.
$ quilt new test1
> Patch %{P}test1 is now on top
$ quilt add test.txt
> File test.txt added to patch %{P}test1
$ cat > test.txt
< Try the following patch instead.
$ quilt refresh
> Refreshed patch %{P}test1
$ quilt new test2
> Patch %{P}test2 is now on top
$ quilt add test.txt
> File test.txt added to patch %{P}test2
$ cat > test.txt
< Ok, that's fine with me if you want to do that instead.
$ quilt refresh
> Refreshed patch %{P}test2
$ quilt delete test1
> Patch %{P}test1 is currently applied
$ quilt pop
> Removing patch %{P}test2
> Restoring test.txt
>
> Now at patch %{P}test1
$ quilt series
> %{P}test1
> %{P}test2
$ quilt delete -n
> Removed patch %{P}test2
$ quilt series
> %{P}test1
$ quilt pop
> Removing patch %{P}test1
> Restoring test.txt
>
> No patches applied
$ quilt delete test1
> Removed patch %{P}test1
$ quilt series
$ echo "test1" > patches/series
$ quilt delete -n
> Removed patch %{P}test1
$ quilt series
# Force the pop operaton to fail
$ echo "test3" > patches/series
$ echo "test3" > %{QUILT_PC}/applied-patches
$ mkdir -p %{QUILT_PC}/test3/dir
$ touch %{QUILT_PC}/test3/dir/file
$ chmod a-rx %{QUILT_PC}/test3/dir
# Note that this will succeed (instead of the expected failure) if
# running as root, but you shouldn't do that anyway.
$ quilt delete "test3"
> Removing patch %{P}test3
>~ .*find: [`']?\./dir'?: Permission denied
$ chmod a+rx %{QUILT_PC}/test3/dir
$ find %{QUILT_PC}/test3
> %{QUILT_PC}/test3
> %{QUILT_PC}/test3/dir
> %{QUILT_PC}/test3/dir/file
$ quilt applied
> No patches applied
$ quilt series
> %{P}test3
$ quilt delete
> No patches applied
$ quilt delete test3
> Removed patch %{P}test3

63
test/dir-a-b.test Normal file
View File

@ -0,0 +1,63 @@
$ mkdir patches
$ echo a > test.txt
$ echo d > test3.txt
$ cat > patches/ab.diff
< --- a/test.txt
< +++ b/test.txt
< @@ -1 +1 @@
< -a
< +b
< --- /dev/null
< +++ b/test2.txt
< @@ -0,0 +1 @@
< +c
< --- a/test3.txt
< +++ /dev/null
< @@ -1 +0,0 @@
< -d
$ echo "ab.diff" > patches/series
$ quilt push -q
> Applying patch %{P}ab.diff
> Now at patch %{P}ab.diff
$ quilt diff -p ab --no-index
> --- a/test.txt
> +++ b/test.txt
> @@ -1 +1 @@
> -a
> +b
> --- /dev/null
> +++ b/test2.txt
> @@ -0,0 +1 @@
> +c
> --- a/test3.txt
> +++ /dev/null
> @@ -1 +0,0 @@
> -d
$ rm -f patches/ab.diff
$ quilt refresh -p ab --no-index
> Refreshed patch %{P}ab.diff
$ cat patches/ab.diff
> --- a/test.txt
> +++ b/test.txt
> @@ -1 +1 @@
> -a
> +b
> --- /dev/null
> +++ b/test2.txt
> @@ -0,0 +1 @@
> +c
> --- a/test3.txt
> +++ /dev/null
> @@ -1 +0,0 @@
> -d
$ quilt pop -qR
> Removing patch %{P}ab.diff
> No patches applied

19
test/dotglob.test Normal file
View File

@ -0,0 +1,19 @@
$ mkdir patches
$ quilt new dotglob.diff
> Patch %{P}dotglob.diff is now on top
$ quilt add .foo
> File .foo added to patch %{P}dotglob.diff
$ echo dot-foo > .foo
$ quilt refresh
> Refreshed patch %{P}dotglob.diff
$ quilt pop -q
> Removing patch %{P}dotglob.diff
> No patches applied
$ quilt push -q
> Applying patch %{P}dotglob.diff
> Now at patch %{P}dotglob.diff

View File

@ -0,0 +1,37 @@
# Check that duplicate patches in generated series files won't cause havoc
# See bug #20628 at https://savannah.nongnu.org/bugs/?20628
$ mkdir patches
$ echo "old line" > file.txt
$ cat > patches/first.patch
< --- file.txt
< +++ file.txt
< @@ -1 +1 @@
< -old line
< +new line
$ cat > patches/series
< first.patch -p0
< first.patch -p0
$ quilt push
> Applying patch %{P}first.patch
> patching file file.txt
>
> Now at patch %{P}first.patch
$ quilt push
> Patch %{P}first.patch is already applied; check your series file
$ quilt pop
> Removing patch %{P}first.patch
> Restoring file.txt
>
> No patches applied
$ quilt push -qa
> Patch %{P}first.patch is already applied; check your series file
$ quilt pop -q
> No patch removed

97
test/edit.test Normal file
View File

@ -0,0 +1,97 @@
$ mkdir patches subdir
# Test the behavior if the editor modifies existing files
$ cat > editor
< #! /bin/sh
< echo Editing $1
< sed -e 's:foo:bar:' $1 > $1.new
< mv $1.new $1
$ chmod +x editor
$ export EDITOR=%{PWD}/editor
$ quilt new patch
> Patch %{P}patch is now on top
$ echo foobar > foobar
$ quilt edit foobar
> File foobar added to patch %{P}patch
> Editing foobar
$ cat foobar
> barbar
$ cd subdir
$ echo foo > foo
$ quilt edit foo
> File subdir/foo added to patch %{_P}patch
> Editing subdir/foo
$ cd ..
$ cat subdir/foo
> bar
$ quilt files
> foobar
> subdir/foo
$ quilt refresh
> Refreshed patch %{P}patch
# Test the behavior if the editor deletes a file completely
$ echo foobaz > foobaz
$ cat > editor
< #! /bin/sh
< echo Deleting $1
< rm -f $1
$ quilt edit foobaz
> File foobaz added to patch %{P}patch
> Deleting foobaz
$ [ ! -e foobaz ] || echo "File foobaz shouldn't exist"
# Test the behavior if the editor is called on a new file but
# does not actually create it
$ cat > editor
< #! /bin/sh
< echo Doing nothing to $1
$ quilt edit nofoo
> File nofoo added to patch %{P}patch
> Doing nothing to nofoo
> File nofoo removed from patch %{P}patch
# Test the behavior if the patch is deleting a file and the
# user calls "quilt edit" on that file but makes no change to it
$ rm -f foobar
$ quilt refresh
> Refreshed patch %{P}patch
$ quilt diff -p ab --no-index foobar
> --- a/foobar
> +++ /dev/null
> @@ -1 +0,0 @@
> -foobar
$ quilt edit foobar
> File foobar is already in patch %{P}patch
> Doing nothing to foobar
$ [ ! -e foobar ] || echo "File foobar shouldn't exist"
# Test the behavior if the editor creates a brand new file
$ cat > editor
< #! /bin/sh
< echo Creating $1
< echo "new line" > $1
$ quilt edit foo2
> File foo2 added to patch %{P}patch
> Creating foo2
$ cat foo2
> new line
$ quilt files -v
> + foo2
> - foobar
> - foobaz
> subdir/foo

131
test/empty-files.test Normal file
View File

@ -0,0 +1,131 @@
# Check that quilt properly deals with patches which delete vs. empty files
# Prepare the working tree
$ mkdir patches
$ echo "will be deleted" > deleted1
$ echo "will be emptied" > emptied1
$ echo "will be deleted" > deleted2
$ echo "will be emptied" > emptied2
# Prepate the patches and series
$ cat > patches/series
< using-filenames.patch
< using-timestamps.patch
$ cat > patches/using-filenames.patch
< diff -ruN a/deleted1 b/deleted1
< --- a/deleted1
< +++ /dev/null
< @@ -1 +0,0 @@
< -will be deleted
< diff -ruN a/emptied1 b/emptied1
< --- a/emptied1
< +++ b/emptied1
< @@ -1 +0,0 @@
< -will be emptied
$ cat > patches/using-timestamps.patch
< diff -ruN a/deleted2 b/deleted2
< --- a/deleted2 2014-01-15 11:19:43.000000000 +0100
< +++ b/deleted2 1970-01-01 01:00:00.000000000 +0100
< @@ -1 +0,0 @@
< -will be deleted
< diff -ruN a/emptied2 b/emptied2
< --- a/emptied2 2014-01-15 11:19:59.000000000 +0100
< +++ b/emptied2 2014-01-15 11:20:11.000000000 +0100
< @@ -1 +0,0 @@
< -will be emptied
# Test quilt push
$ quilt push
> Applying patch %{P}using-filenames.patch
> patching file deleted1
> patching file emptied1
>
> Now at patch %{P}using-filenames.patch
$ [ ! -e deleted1 ] && echo "File deleted1 does not exist"
> File deleted1 does not exist
$ [ -e deleted1 -a ! -s deleted1 ] && echo "File deleted1 is empty"
$ [ ! -e emptied1 ] && echo "File emptied1 does not exist"
$ [ -e emptied1 -a ! -s emptied1 ] && echo "File emptied1 is empty"
> File emptied1 is empty
$ quilt push
> Applying patch %{P}using-timestamps.patch
> patching file deleted2
> patching file emptied2
>
> Now at patch %{P}using-timestamps.patch
$ [ ! -e deleted2 ] && echo "File deleted2 does not exist"
> File deleted2 does not exist
$ [ -e deleted2 -a ! -s deleted2 ] && echo "File deleted2 is empty"
$ [ ! -e emptied2 ] && echo "File emptied2 does not exist"
$ [ -e emptied2 -a ! -s emptied2 ] && echo "File emptied2 is empty"
> File emptied2 is empty
# Test quilt fold
$ quilt pop -aq
> Removing patch %{P}using-timestamps.patch
> Removing patch %{P}using-filenames.patch
> No patches applied
$ quilt new fold.patch
> Patch %{P}fold.patch is now on top
$ quilt fold < patches/using-filenames.patch
> patching file deleted1
> patching file emptied1
$ [ ! -e deleted1 ] && echo "File deleted1 does not exist"
> File deleted1 does not exist
$ [ -e deleted1 -a ! -s deleted1 ] && echo "File deleted1 is empty"
$ [ ! -e emptied1 ] && echo "File emptied1 does not exist"
$ [ -e emptied1 -a ! -s emptied1 ] && echo "File emptied1 is empty"
> File emptied1 is empty
$ quilt fold < patches/using-timestamps.patch
> patching file deleted2
> patching file emptied2
$ [ ! -e deleted2 ] && echo "File deleted2 does not exist"
> File deleted2 does not exist
$ [ -e deleted2 -a ! -s deleted2 ] && echo "File deleted2 is empty"
$ [ ! -e emptied2 ] && echo "File emptied2 does not exist"
$ [ -e emptied2 -a ! -s emptied2 ] && echo "File emptied2 is empty"
> File emptied2 is empty
# Test quilt refresh
$ quilt delete
> Removing patch %{P}fold.patch
> No patches applied
> Removed patch %{P}fold.patch
$ quilt push -q
> Applying patch %{P}using-filenames.patch
> Now at patch %{P}using-filenames.patch
$ quilt refresh -pab --sort --no-index
> Refreshed patch %{P}using-filenames.patch
$ quilt pop -q
> Removing patch %{P}using-filenames.patch
> No patches applied
$ quilt push
> Applying patch %{P}using-filenames.patch
> patching file deleted1
> patching file emptied1
>
> Now at patch %{P}using-filenames.patch
$ [ ! -e deleted1 ] && echo "File deleted1 does not exist"
> File deleted1 does not exist
$ [ -e deleted1 -a ! -s deleted1 ] && echo "File deleted1 is empty"
$ [ ! -e emptied1 ] && echo "File emptied1 does not exist"
$ [ -e emptied1 -a ! -s emptied1 ] && echo "File emptied1 is empty"
> File emptied1 is empty
$ cat patches/using-filenames.patch
> --- a/deleted1
> +++ /dev/null
> @@ -1 +0,0 @@
> -will be deleted
> --- a/emptied1
> +++ b/emptied1
> @@ -1 +0,0 @@
> -will be emptied

34
test/empty.test Normal file
View File

@ -0,0 +1,34 @@
$ mkdir patches
$ cat > patches/series
< empty1.diff
< empty2.diff
$ touch patches/empty1.diff patches/empty2.diff
$ quilt push -qa
> Applying patch %{P}empty1.diff
> Patch %{P}empty1.diff appears to be empty; applied
> Applying patch %{P}empty2.diff
> Patch %{P}empty2.diff appears to be empty; applied
> Now at patch %{P}empty2.diff
$ quilt rename empty3.diff
> Patch %{P}empty2.diff renamed to %{P}empty3.diff
$ quilt pop -qa
> Patch %{P}empty3.diff appears to be empty, removing
> Patch %{P}empty1.diff appears to be empty, removing
> No patches applied
$ quilt new empty_new.diff
> Patch %{P}empty_new.diff is now on top
$ quilt pop -q
> Patch %{P}empty_new.diff appears to be empty, removing
> No patches applied
$ quilt delete empty_new.diff
> Removed patch %{P}empty_new.diff
$ quilt rename -P empty3.diff empty_new.diff
> Patch %{P}empty3.diff renamed to %{P}empty_new.diff

146
test/example1.test Normal file
View File

@ -0,0 +1,146 @@
The text used here was taken from:
http://the-tech.mit.edu/Shakespeare/midsummer/full.html
$ mkdir patches
$ cat > Oberon.txt
< Yet mark'd I where the bolt of Cupid fell:
< It fell upon a little western flower,
< Before milk-white, now purple with love's wound,
< And girls call it love-in-idleness.
$ quilt new flower.diff
> Patch %{P}flower.diff is now on top
$ quilt files
$ quilt add Oberon.txt
> File Oberon.txt added to patch %{P}flower.diff
$ cat >> Oberon.txt
< The juice of it on sleeping eye-lids laid
< Will make a man or woman madly dote
< Upon the next live creature that it sees.
Or ``quilt edit Oberon.txt''
$ quilt refresh -p ab
> Refreshed patch %{P}flower.diff
$ cat patches/flower.diff
> Index: b/Oberon.txt
> ===================================================================
> --- a/Oberon.txt
> +++ b/Oberon.txt
> @@ -2,3 +2,6 @@
> It fell upon a little western flower,
> Before milk-white, now purple with love's wound,
> And girls call it love-in-idleness.
> +The juice of it on sleeping eye-lids laid
> +Will make a man or woman madly dote
> +Upon the next live creature that it sees.
$ sed -ne '1,4p' Oberon.txt > Oberon.new
$ echo "Fetch me that flower; the herb I shew'd thee once:" >> Oberon.new
$ sed -e '1,4d' Oberon.txt >> Oberon.new
$ mv Oberon.new Oberon.txt
$ quilt diff -z -p ab
> Index: b/Oberon.txt
> ===================================================================
> --- a/Oberon.txt
> +++ b/Oberon.txt
> @@ -2,6 +2,7 @@
> It fell upon a little western flower,
> Before milk-white, now purple with love's wound,
> And girls call it love-in-idleness.
> +Fetch me that flower; the herb I shew'd thee once:
> The juice of it on sleeping eye-lids laid
> Will make a man or woman madly dote
> Upon the next live creature that it sees.
$ quilt diff -p ab
> Index: b/Oberon.txt
> ===================================================================
> --- a/Oberon.txt
> +++ b/Oberon.txt
> @@ -2,3 +2,7 @@
> It fell upon a little western flower,
> Before milk-white, now purple with love's wound,
> And girls call it love-in-idleness.
> +Fetch me that flower; the herb I shew'd thee once:
> +The juice of it on sleeping eye-lids laid
> +Will make a man or woman madly dote
> +Upon the next live creature that it sees.
$ quilt refresh
> Refreshed patch %{P}flower.diff
$ quilt top
> %{P}flower.diff
$ quilt files
> Oberon.txt
$ quilt patches Oberon.txt
> %{P}flower.diff
$ quilt pop -f
> Removing patch %{P}flower.diff
> Restoring Oberon.txt
>
> No patches applied
$ quilt files patches/flower.diff
> Oberon.txt
$ sed -e "s/girls/maidens/" Oberon.txt > Oberon.new
$ mv Oberon.new Oberon.txt
$ quilt push
> Applying patch %{P}flower.diff
>~ patching file `?Oberon.txt'?
> Hunk #1 FAILED at 2.
>~ 1 out of 1 hunk FAILED -- rejects in file `?Oberon.txt'?
> Patch %{P}flower.diff does not apply (enforce with -f)
$ quilt push -f
> Applying patch %{P}flower.diff
>~ patching file `?Oberon.txt'?
> Hunk #1 FAILED at 2.
>~ 1 out of 1 hunk FAILED -- saving rejects to (file )?`?Oberon.txt.rej'?
> Applied patch %{P}flower.diff (forced; needs refresh)
$ cat >> Oberon.txt
< Fetch me that flower; the herb I shew'd thee once:
< The juice of it on sleeping eye-lids laid
< Will make a man or woman madly dote
< Upon the next live creature that it sees.
$ quilt refresh -p ab
> Refreshed patch %{P}flower.diff
$ rm -f Oberon.txt.rej
$ cat Oberon.txt
> Yet mark'd I where the bolt of Cupid fell:
> It fell upon a little western flower,
> Before milk-white, now purple with love's wound,
> And maidens call it love-in-idleness.
> Fetch me that flower; the herb I shew'd thee once:
> The juice of it on sleeping eye-lids laid
> Will make a man or woman madly dote
> Upon the next live creature that it sees.
$ cat patches/flower.diff
> Index: b/Oberon.txt
> ===================================================================
> --- a/Oberon.txt
> +++ b/Oberon.txt
> @@ -2,3 +2,7 @@
> It fell upon a little western flower,
> Before milk-white, now purple with love's wound,
> And maidens call it love-in-idleness.
> +Fetch me that flower; the herb I shew'd thee once:
> +The juice of it on sleeping eye-lids laid
> +Will make a man or woman madly dote
> +Upon the next live creature that it sees.
$ quilt grep love
> Oberon.txt:Before milk-white, now purple with love's wound,
> Oberon.txt:And maidens call it love-in-idleness.

23
test/failbackup.test Normal file
View File

@ -0,0 +1,23 @@
$ mkdir patches
$ quilt new test.diff
> Patch %{P}test.diff is now on top
$ quilt add test.txt
> File test.txt added to patch %{P}test.diff
$ cat > test.txt
< This is test.txt.
$ quilt refresh
> Refreshed patch %{P}test.diff
What happens when refresh fails because of a permission error?
$ chmod -w patches
$ cat > test.txt
< This is updated test.txt.
$ quilt refresh --backup
>~ mv: cannot move [`']?patches/test.diff'? to [`']?patches/test.diff~'?: Permission denied
$ echo %{?}
> 1
$ chmod +w patches

39
test/faildiff.test Normal file
View File

@ -0,0 +1,39 @@
$ mkdir patches
$ quilt new test.diff
> Patch %{P}test.diff is now on top
$ cat > test.txt
< This is test.txt.
$ quilt add test.txt
> File test.txt added to patch %{P}test.diff
What happens when diff fails because of a permission error?
$ chmod -r test.txt
$ quilt refresh
>~ .*diff: test\.txt: Permission denied
> Diff failed on file 'test.txt', aborting
$ echo %{?}
> 1
$ chmod +r test.txt
What happens on binary files?
$ printf "\\002\\000\\001" > test.bin
$ quilt add test.bin
> File test.bin added to patch %{P}test.diff
$ printf "\\003\\000\\001" > test.bin
$ quilt diff -pab --no-index
>~ (Files|Binary files) a/test\.bin and b/test\.bin differ
> Diff failed on file 'test.bin', aborting
$ echo %{?}
> 1
$ quilt refresh
> Diff failed on file 'test.bin', aborting
$ echo %{?}
> 1

29
test/failpop.test Normal file
View File

@ -0,0 +1,29 @@
$ mkdir patches
$ cat > test.txt
< This is test.txt.
$ quilt new test.diff
> Patch %{P}test.diff is now on top
$ echo %{?}
> 0
$ quilt add test.txt
> File test.txt added to patch %{P}test.diff
$ echo %{?}
> 0
$ cat >> test.txt
< Line two.
$ quilt refresh
> Refreshed patch %{P}test.diff
$ echo %{?}
> 0
$ sed -e "s/ /_/g" patches/test.diff > patches/test.new
$ mv patches/test.new patches/test.diff
$ quilt pop
> Patch %{P}test.diff does not remove cleanly (refresh it or enforce with -f)
$ echo %{?}
> 1

69
test/fold.test Normal file
View File

@ -0,0 +1,69 @@
$ mkdir patches
$ cat > patches/series
< patch1.diff
$ cat > patches/patch1.diff
< --- q.orig/file1.txt
< +++ q/file1.txt
< @@ -0,0 +1 @@
< +This is file1.txt.
< --- q.orig/file2.txt
< +++ q/file2.txt
< @@ -0,0 +1 @@
< +This is file2.txt.
$ quilt push -q
> Applying patch %{P}patch1.diff
> Now at patch %{P}patch1.diff
$ quilt files
> file1.txt
> file2.txt
$ quilt fold -q
< --- q.orig/file2.txt
< +++ q/file2.txt
< @@ -1 +0,0 @@
< -This is file2.txt.
< --- q.orig/dir/file3.txt
< +++ q/dir/file3.txt
< @@ -0,0 +1 @@
< +This is file3.txt.
$ quilt diff -p ab
> Index: b/file1.txt
> ===================================================================
> --- /dev/null
> +++ b/file1.txt
> @@ -0,0 +1 @@
> +This is file1.txt.
> Index: b/dir/file3.txt
> ===================================================================
> --- /dev/null
> +++ b/dir/file3.txt
> @@ -0,0 +1 @@
> +This is file3.txt.
$ cd dir
$ quilt fold -q
< --- dir.orig/file3.txt
< +++ dir/file3.txt
< @@ -1 +1 @@
< -This is file3.txt.
< +This is file3.txt, now modified.
$ cd ..
$ quilt diff -p ab
> Index: b/file1.txt
> ===================================================================
> --- /dev/null
> +++ b/file1.txt
> @@ -0,0 +1 @@
> +This is file1.txt.
> Index: b/dir/file3.txt
> ===================================================================
> --- /dev/null
> +++ b/dir/file3.txt
> @@ -0,0 +1 @@
> +This is file3.txt, now modified.

120
test/formats.test Normal file
View File

@ -0,0 +1,120 @@
# We create our own working directory to be able to verify
# all patch formats, including the ones which mention the
# base directory.
$ mkdir -p d/patches
$ cd d
$ cat > test.txt
< 1
< 2
< old
< 4
< 5
$ quilt new test
> Patch %{P}test is now on top
$ quilt add test.txt
> File test.txt added to patch %{P}test
$ cat > test.txt
< 1
< 2
< new
< 4
< 5
$ quilt diff
> Index: d/test.txt
> ===================================================================
> --- d.orig/test.txt
> +++ d/test.txt
> @@ -1,5 +1,5 @@
> 1
> 2
> -old
> +new
> 4
> 5
$ quilt diff --no-index
> --- d.orig/test.txt
> +++ d/test.txt
> @@ -1,5 +1,5 @@
> 1
> 2
> -old
> +new
> 4
> 5
$ quilt diff -R
> Index: d/test.txt
> ===================================================================
> --- d.orig/test.txt
> +++ d/test.txt
> @@ -1,5 +1,5 @@
> 1
> 2
> -new
> +old
> 4
> 5
$ quilt diff -U1
> Index: d/test.txt
> ===================================================================
> --- d.orig/test.txt
> +++ d/test.txt
> @@ -2,3 +2,3 @@
> 2
> -old
> +new
> 4
$ quilt diff -c
> Index: d/test.txt
> ===================================================================
> *** d.orig/test.txt
> --- d/test.txt
> ***************
> *** 1,5 ****
> 1
> 2
> ! old
> 4
> 5
> --- 1,5 ----
> 1
> 2
> ! new
> 4
> 5
$ quilt diff -C1
> Index: d/test.txt
> ===================================================================
> *** d.orig/test.txt
> --- d/test.txt
> ***************
> *** 2,4 ****
> 2
> ! old
> 4
> --- 2,4 ----
> 2
> ! new
> 4
$ quilt diff -p ab
> Index: b/test.txt
> ===================================================================
> --- a/test.txt
> +++ b/test.txt
> @@ -1,5 +1,5 @@
> 1
> 2
> -old
> +new
> 4
> 5

48
test/half-applies.test Normal file
View File

@ -0,0 +1,48 @@
$ mkdir patches
$ echo foo > foo.orig
$ echo foo2 > foo
$ echo bar > bar.orig
$ echo bar2 > bar
$ diff -u foo.orig foo >> patches/foorab.diff
$ diff -u bar bar.orig >> patches/foorab.diff
$ mv foo.orig foo
$ mv bar.orig bar
$ echo foorab.diff -p0 > patches/series
$ quilt push
> Applying patch %{P}foorab.diff
>~ patching file `?foo'?
>~ patching file `?bar'?
> Hunk #1 FAILED at 1.
>~ 1 out of 1 hunk FAILED -- rejects in file `?bar'?
> Patch %{P}foorab.diff does not apply (enforce with -f)
$ echo %{?}
> 1
$ quilt push
> Applying patch %{P}foorab.diff
>~ patching file `?foo'?
>~ patching file `?bar'?
> Hunk #1 FAILED at 1.
>~ 1 out of 1 hunk FAILED -- rejects in file `?bar'?
> Patch %{P}foorab.diff does not apply (enforce with -f)
$ echo %{?}
> 1
$ quilt push -qf
> Applying patch %{P}foorab.diff
>~ 1 out of 1 hunk FAILED( -- saving rejects to( file)? bar.rej)?
> Applied patch %{P}foorab.diff (forced; needs refresh)
$ echo %{?}
> 1
$ quilt diff
> Index: foo
> ===================================================================
> --- foo.orig
> +++ foo
> @@ -1 +1 @@
> -foo
> +foo2
$ echo %{?}
> 0

View File

@ -0,0 +1,60 @@
If a patch file has hard links, refreshing it should break the links
so that the other copies are left unmodified.
$ mkdir patches
$ cat > patches/patch
< --- file.orig
< +++ file
< @@ -1 +1 @@
< -a
< +b
$ echo patch -p0 > patches/series
$ ln patches/patch hardlink
$ echo a > file
$ quilt push -q
> Applying patch %{P}patch
> Now at patch %{P}patch
$ echo c > file
$ quilt refresh --no-index
> Refreshed patch %{P}patch
$ cat patches/patch
> --- file.orig
> +++ file
> @@ -1 +1 @@
> -a
> +c
$ cat hardlink
> --- file.orig
> +++ file
> @@ -1 +1 @@
> -a
> +b
Same goes for a patch header update.
$ rm -f hardlink
$ ln patches/patch hardlink
$ quilt header -r
< c is so much better than a
> Replaced header of patch %{P}patch
$ cat patches/patch
> c is so much better than a
> --- file.orig
> +++ file
> @@ -1 +1 @@
> -a
> +c
$ cat hardlink
> --- file.orig
> +++ file
> @@ -1 +1 @@
> -a
> +c

57
test/header.test Normal file
View File

@ -0,0 +1,57 @@
$ mkdir patches
$ echo foo > foo
$ quilt new patch
> Patch %{P}patch is now on top
$ quilt add foo
> File foo added to patch %{P}patch
$ echo bar > foo
$ quilt refresh -p ab
> Refreshed patch %{P}patch
$ mv patches/patch patches/patch~
$ echo Header > patches/patch
$ cat patches/patch~ >> patches/patch
$ quilt header
> Header
$ quilt header -r
< Header2
> Replaced header of patch %{P}patch
$ quilt header
> Header2
$ quilt header -a
< Appended
> Appended text to header of patch %{P}patch
$ quilt header
> Header2
> Appended
$ cat patches/patch
> Header2
> Appended
> Index: b/foo
> ===================================================================
> --- a/foo
> +++ b/foo
> @@ -1 +1 @@
> -foo
> +bar
$ echo -n "No trailing newline" | quilt header -r
> Replaced header of patch patches/patch
$ cat patches/patch
> No trailing newline
> Index: b/foo
> ===================================================================
> --- a/foo
> +++ b/foo
> @@ -1 +1 @@
> -foo
> +bar

257
test/import.test Normal file
View File

@ -0,0 +1,257 @@
$ mkdir patches
$ quilt new patch1.diff
> Patch %{P}patch1.diff is now on top
$ quilt add f
> File f added to patch %{P}patch1.diff
$ echo f > f
$ quilt refresh
> Refreshed patch %{P}patch1.diff
$ quilt new patchR.diff
> Patch %{P}patchR.diff is now on top
$ quilt add f
> File f added to patch %{P}patchR.diff
$ rm -f f
$ quilt refresh
> Refreshed patch %{P}patchR.diff
$ quilt fork patchRp0.diff
> Fork of patch %{P}patchR.diff created as %{P}patchRp0.diff
$ quilt refresh -p0
> Refreshed patch %{P}patchRp0.diff
$ quilt pop -a
> Removing patch %{P}patchRp0.diff
> Restoring f
>
> Removing patch %{P}patch1.diff
> Removing f
>
> No patches applied
$ mkdir t
$ mv patches/patch1.diff t/patch1.diff
$ mv patches/patchR.diff t/patchR.diff
$ mv patches/patchRp0.diff t/patchRp0.diff
# test importing into an empty series
$ rm -rf patches/ %{QUILT_PC}/
$ mkdir patches
$ quilt import t/patch1.diff
> Importing patch t/patch1.diff (stored as %{P}patch1.diff)
$ quilt push
> Applying patch %{P}patch1.diff
>~ patching file `?f'?
>
> Now at patch %{P}patch1.diff
$ quilt new patch2.diff
> Patch %{P}patch2.diff is now on top
$ quilt add g
> File g added to patch %{P}patch2.diff
$ echo g > g
$ quilt refresh
> Refreshed patch %{P}patch2.diff
$ quilt pop
> Removing patch %{P}patch2.diff
> Removing g
>
> Now at patch %{P}patch1.diff
$ quilt header -a
< original description
> Appended text to header of patch %{P}patch1.diff
$ quilt pop
> Removing patch %{P}patch1.diff
> Removing f
>
> No patches applied
$ quilt delete patch1
> Removed patch %{P}patch1.diff
$ cat patches/series
> patch2.diff
# test a few error cases
$ quilt import missing.diff
> Patch missing.diff does not exist
$ quilt import patches/patch1.diff
> Importing patch %{P}patch1.diff
$ quilt import patches/patch2.diff
> Patch %{P}patch2.diff already exists in series.
# a simple use of import
$ quilt import t/patch1.diff
> Patch %{P}patch1.diff exists. Replace with -f.
$ quilt import -f t/patch1.diff
> Replacing patch %{P}patch1.diff with new version
# an import requiring a description merge
$ sed -e 's/original/new/' patches/patch1.diff > t/patch1.diff
$ quilt import t/patch1.diff
> Patch %{P}patch1.diff exists. Replace with -f.
$ quilt import -f t/patch1.diff
> Patch headers differ:
> @@ -1 +1 @@
> -original description
> +new description
> Please use -d {o|a|n} to specify which patch header(s) to keep.
$ quilt import -d a -f t/patch1.diff
> Replacing patch %{P}patch1.diff with new version
# quilt header does not work in this case because it stops at '---'
$ head -n 3 patches/patch1.diff
> original description
> ---
> new description
$ quilt import -d n -f t/patch1.diff
> Replacing patch %{P}patch1.diff with new version
$ quilt header patch1
> new description
$ quilt delete patch1
> Removed patch %{P}patch1.diff
# make sure it accepts non-conflicting names
# a small presentation problem here
$ cp patches/patch1.diff t/patch1.patch
$ quilt import t/patch1.patch
> Importing patch t/patch1.patch (stored as %{P}patch1.patch)
$ ls patches/
> patch1.diff
> patch1.patch
> patch2.diff
> series
$ cat patches/series
> patch1.patch
> patch2.diff
$ quilt delete patch1.diff
> Patch patch1.diff is not in series
# test importing a reverse patch
$ rm -rf patches/ %{QUILT_PC}/
$ mkdir patches
$ quilt import -R t/patchR.diff
> Importing patch t/patchR.diff (stored as %{P}patchR.diff)
$ quilt push
> Applying patch %{P}patchR.diff
>~ patching file `?f'?
>
> Now at patch %{P}patchR.diff
$ cat f
> f
$ cat patches/series
> patchR.diff -R
# test that comments are preserved
$ echo "# Test of -R import" > patches/series
$ echo "patchR.diff -R # This patch was originally -R -p1" >> patches/series
# refreshing a reverse patch un-reverses it
$ quilt refresh
> Refreshed patch %{P}patchR.diff
$ cat patches/series
> # Test of -R import
> patchR.diff # This patch was originally -R -p1
$ touch f
$ quilt pop
> Removing patch %{P}patchR.diff
> Removing f
>
> No patches applied
# test importing a reverse patch with strip level
$ rm -rf patches/ %{QUILT_PC}/
$ mkdir patches
$ quilt import -R -p0 t/patchRp0.diff
> Importing patch t/patchRp0.diff (stored as %{P}patchRp0.diff)
$ quilt push
> Applying patch %{P}patchRp0.diff
>~ patching file `?f'?
>
> Now at patch %{P}patchRp0.diff
$ cat f
> f
$ cat patches/series
> patchRp0.diff -p0 -R
# refreshing a reverse patch un-reverses it
$ quilt refresh
> Refreshed patch %{P}patchRp0.diff
$ cat patches/series
> patchRp0.diff -p0
$ touch f
$ quilt pop
> Removing patch %{P}patchRp0.diff
> Removing f
>
> No patches applied
# Test importing multiple patches at once
$ rm -rf patches/ %{QUILT_PC}/
$ mkdir patches
$ quilt import t/patch1.diff t/patchR.diff
> Importing patch t/patch1.diff (stored as %{P}patch1.diff)
> Importing patch t/patchR.diff (stored as %{P}patchR.diff)
$ cat patches/series
> patch1.diff
> patchR.diff
$ rm -rf patches/ %{QUILT_PC}/
$ mkdir patches
$ quilt import t/patchR.diff
> Importing patch t/patchR.diff (stored as %{P}patchR.diff)
$ quilt import t/patch1.diff
> Importing patch t/patch1.diff (stored as %{P}patch1.diff)
$ cat patches/series
> patch1.diff
> patchR.diff
# Also test importing when in a subdirectory
$ touch empty.patch
$ cd t
$ touch empty2.patch
$ quilt import ../empty.patch
> Importing patch ../empty.patch (stored as %{_P}empty.patch)
$ quilt import %{PWD}/empty2.patch
> Importing patch %{PWD}/empty2.patch (stored as %{_P}empty2.patch)

138
test/import2.test Normal file
View File

@ -0,0 +1,138 @@
# same as import.test, but with compressed patches
$ mkdir patches
$ quilt new patch1.diff
> Patch %{P}patch1.diff is now on top
$ quilt add f
> File f added to patch %{P}patch1.diff
$ echo f > f
$ quilt refresh
> Refreshed patch %{P}patch1.diff
$ quilt pop
> Removing patch %{P}patch1.diff
> Removing f
>
> No patches applied
$ mkdir t
$ gzip < patches/patch1.diff > t/patch1.diff.gz
$ rm -f patches/patch1.diff
# test importing into an empty series
$ rm -rf patches/ %{QUILT_PC}/
$ mkdir patches
$ quilt import t/patch1.diff.gz
> Importing patch t/patch1.diff.gz (stored as %{P}patch1.diff.gz)
$ quilt push
> Applying patch %{P}patch1.diff.gz
>~ patching file `?f'?
>
> Now at patch %{P}patch1.diff.gz
$ quilt new patch2.diff.gz
> Patch %{P}patch2.diff.gz is now on top
$ quilt add g
> File g added to patch %{P}patch2.diff.gz
$ echo g > g
$ quilt refresh
> Refreshed patch %{P}patch2.diff.gz
$ quilt pop
> Removing patch %{P}patch2.diff.gz
> Removing g
>
> Now at patch %{P}patch1.diff.gz
$ quilt header -a
< original description
> Appended text to header of patch %{P}patch1.diff.gz
$ quilt pop
> Removing patch %{P}patch1.diff.gz
> Removing f
>
> No patches applied
$ quilt delete patch1
> Removed patch %{P}patch1.diff.gz
$ cat patches/series
> patch2.diff.gz
# test a few error cases
$ quilt import missing.diff.gz
> Patch missing.diff.gz does not exist
$ quilt import patches/patch1.diff.gz
> Importing patch %{P}patch1.diff.gz
$ quilt import patches/patch2.diff.gz
> Patch %{P}patch2.diff.gz already exists in series.
# a simple use of import
$ quilt import t/patch1.diff.gz
> Patch %{P}patch1.diff.gz exists. Replace with -f.
$ quilt import -f t/patch1.diff.gz
> Replacing patch %{P}patch1.diff.gz with new version
# an import requiring a description merge
$ zcat patches/patch1.diff.gz | sed -e 's/original/new/' | gzip > t/patch1.diff.gz
$ quilt import t/patch1.diff.gz
> Patch %{P}patch1.diff.gz exists. Replace with -f.
$ quilt import -f t/patch1.diff.gz
> Patch headers differ:
> @@ -1 +1 @@
> -original description
> +new description
> Please use -d {o|a|n} to specify which patch header(s) to keep.
$ quilt import -d a -f t/patch1.diff.gz
> Replacing patch %{P}patch1.diff.gz with new version
# quilt header does not work in this case because it stops at '---'
$ zcat patches/patch1.diff.gz | head -n 3
> original description
> ---
> new description
$ quilt import -d n -f t/patch1.diff.gz
> Replacing patch %{P}patch1.diff.gz with new version
$ quilt header patch1
> new description
$ quilt delete patch1
> Removed patch %{P}patch1.diff.gz
# make sure it accepts non-conflicting names
# a small presentation problem here
$ cp patches/patch1.diff.gz t/patch1.patch.gz
$ quilt import t/patch1.patch.gz
> Importing patch t/patch1.patch.gz (stored as %{P}patch1.patch.gz)
$ ls patches/
> patch1.diff.gz
> patch1.patch.gz
> patch2.diff.gz
> series
$ cat patches/series
> patch1.patch.gz
> patch2.diff.gz
$ quilt delete patch1.diff.gz
> Patch patch1.diff.gz is not in series

Some files were not shown because too many files have changed in this diff Show More