[Rpm-maint] [PATCH] Read uncompressed patches from stdin

Jean Delvare jdelvare at suse.de
Mon Jan 19 16:21:26 UTC 2015


Since commit 15e9e1ff64aaf986ab0dd97b9b12c3d4fb22a484 ("Simplify
doPatch()" in May 2008), uncompressed patches are read with "cat" then
piped to "patch". The idea was to simplify the code, however this
change had consequences which I suspect were not considered.

The first consequence is a performance regression. Forking and passing
the data through a pipe is much more expensive than reading from
stdin. For packages with a lot of patches, this makes a significant
difference.

A second issue is the integration with other tools. I am working on
quilt. Quilt has a "setup" command which reads a rpm spec file and
produces a compliant working tree with all patches ready to be
applied. This is implemented with rpmbuild as the backend. We
intercept the calls to patch to record the name and sequencing of the
patch files. If the file is read from stdin, we can obtain its name
directly. But if it comes through a pipe, we have to compare the
md5sum of the contents with the md5sum of all candidates in
$RPM_SOURCE_DIR. Again this is much more expensive.

For these reasons I would like to ask that commit
15e9e1ff64aaf986ab0dd97b9b12c3d4fb22a484 is partly reverted. In my
experience, uncompressed patches account for 99% of patches in rpm
packages so I believe it makes sense to optimize for this case.

Signed-off-by: Jean Delvare <jdelvare at suse.de>
---
 build/parsePrep.c |   10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

--- rpm.orig/build/parsePrep.c	2015-01-19 08:14:53.673496847 +0100
+++ rpm/build/parsePrep.c	2015-01-19 08:51:45.197107629 +0100
@@ -62,6 +62,7 @@ static char *doPatch(rpmSpec spec, uint3
     char *arg_patch_flags = rpmExpand("%{?_default_patch_flags}", NULL);
     struct Source *sp;
     char *patchcmd;
+    rpmCompressedMagic compressed = COMPRESSED_NOT;
 
     for (sp = spec->sources; sp != NULL; sp = sp->next) {
 	if ((sp->flags & RPMBUILD_ISPATCH) && (sp->num == c)) {
@@ -80,7 +81,7 @@ static char *doPatch(rpmSpec spec, uint3
     fn = rpmGetPath("%{_sourcedir}/", sp->source, NULL);
 
     /* On non-build parse's, file cannot be stat'd or read. */
-    if ((spec->flags & RPMSPEC_FORCE) || checkOwners(fn)) goto exit;
+    if ((spec->flags & RPMSPEC_FORCE) || rpmFileIsCompressed(fn, &compressed) || checkOwners(fn)) goto exit;
 
     if (db) {
 	rasprintf(&arg_backup,
@@ -102,7 +103,12 @@ static char *doPatch(rpmSpec spec, uint3
 		reverse ? " -R" : "", 
 		removeEmpties ? " -E" : "");
 
-    patchcmd = rpmExpand("%{uncompress: ", fn, "} | %{__patch} ", args, NULL);
+    /* Avoid the extra cost of fork and pipe for uncompressed patches */
+    if (compressed != COMPRESSED_NOT) {
+	patchcmd = rpmExpand("%{uncompress: ", fn, "} | %{__patch} ", args, NULL);
+    } else {
+	patchcmd = rpmExpand("%{__patch} ", args, " < ", fn, NULL);
+    }
 
     free(arg_fuzz);
     free(arg_dir);


-- 
Jean Delvare
SUSE L3 Support


More information about the Rpm-maint mailing list