]> git.pld-linux.org Git - packages/rpm-build-tools.git/blob - rediff-patches.py
Args parsing and few fixes.
[packages/rpm-build-tools.git] / rediff-patches.py
1 #!/usr/bin/python3
2
3 # rediff-patches.py name.spec
4
5 # TODO:
6 # - handle rediff of last patch (need some way to terminate build just after that patch is applied)
7 # - or maybe apply patches on our own instead of using rpmbuild for that
8 # - cleanup
9
10 import argparse
11 import collections
12 import logging
13 import os
14 import re
15 import rpm
16 import shutil
17 import subprocess
18 import sys
19 import tempfile
20
21 RPMBUILD_ISPATCH = (1<<1)
22
23 def unpack(spec, builddir, until_patch=None):
24     cmd = [ 'rpmbuild', '-bp', '--define',  '_builddir %s' % builddir, '--define', '_default_patch_fuzz 2' ]
25     if until_patch is not None:
26         cmd += [ '--define', '%%patch%d exit; #' % until_patch ]
27     cmd += [ spec ]
28     logging.debug("running %s" % repr(cmd))
29     subprocess.check_call(cmd, stdout=sys.stderr, stderr=sys.stderr,
30                           env={'LC_ALL': 'C.UTF-8'}, timeout=600)
31
32 def diff(diffdir_org, diffdir, builddir, output):
33     diffdir_org = os.path.basename(diffdir_org)
34     diffdir = os.path.basename(diffdir)
35
36     with open(output, 'wt') as f:
37         cmd = [ 'diff', '-urNp', '-x', '*.orig', diffdir_org, diffdir ]
38         logging.debug("running %s" % repr(cmd))
39         try:
40             subprocess.check_call(cmd, cwd=builddir, stdout=f, stderr=sys.stderr,
41                                   env={'LC_ALL': 'C.UTF-8'}, timeout=600)
42         except subprocess.CalledProcessError as err:
43             if err.returncode != 1:
44                 raise
45     logging.info("rediff generated as %s" % output)
46
47
48 def main():
49     parser = parser = argparse.ArgumentParser(description='rediff patches to avoid fuzzy hunks')
50     parser.add_argument('spec', type=str, help='spec file name')
51     parser.add_argument('-p', '--patches', type=str, help='comma separated list of patch numbers to rediff')
52     parser.add_argument('-v', '--verbose', help='increase output verbosity', action='store_true')
53     args = parser.parse_args()
54
55     logging.basicConfig(level=logging.INFO)
56     rpm.setVerbosity(rpm.RPMLOG_ERR)
57
58     if args.verbose:
59             logging.basicConfig(level=logging.DEBUG)
60             rpm.setVerbosity(rpm.RPMLOG_DEBUG)
61
62     if args.patches:
63         args.patches = [int(x) for x in args.patches.split(',')]
64
65     specfile = args.spec
66
67     tempdir = tempfile.TemporaryDirectory(dir="/dev/shm")
68     topdir = tempdir.name
69     builddir = os.path.join(topdir, 'BUILD')
70
71     rpm.addMacro("_builddir", builddir)
72
73     r = rpm.spec(specfile)
74
75     patches = {}
76
77     for (name, nr, flags) in r.sources:
78         if flags & RPMBUILD_ISPATCH:
79             patches[nr] = name
80
81     applied_patches = collections.OrderedDict()
82     re_patch = re.compile(r'^%patch(?P<patch_number>\d+)\w*(?P<patch_args>.*)')
83     for line in r.parsed.split('\n'):
84         m = re_patch.match(line)
85         if not m:
86             continue
87         patch_nr = int(m.group('patch_number'))
88         patch_args = m.group('patch_args')
89         applied_patches[patch_nr] = patch_args
90
91     appsourcedir = rpm.expandMacro("%{_sourcedir}")
92     appbuilddir = rpm.expandMacro("%{_builddir}/%{?buildsubdir}")
93
94     for patch_nr, patch_nr_next in zip(applied_patches.keys(), list(applied_patches.keys())[1:] + [None]):
95         if args.patches and patch_nr not in args.patches:
96             continue
97         if patch_nr_next is None:
98             logging.warning("can't rediff last patch, see TODO")
99             break
100         patch_name = patches[patch_nr]
101         logging.info("*** patch %d: %s" % (patch_nr, patch_name))
102         unpack(specfile, builddir, patch_nr)
103         os.rename(appbuilddir, appbuilddir + ".org")
104         unpack(specfile, builddir, patch_nr_next)
105         diff(appbuilddir + ".org", appbuilddir, builddir, os.path.join(topdir, os.path.join(appsourcedir, patch_name + ".rediff")))
106         shutil.rmtree(builddir)
107     tempdir.cleanup()
108
109 if __name__ == '__main__':
110     main()
This page took 0.043443 seconds and 4 git commands to generate.