]> git.pld-linux.org Git - packages/rpm-build-tools.git/blame - rediff-patches.py
Generate diffstat for each patch, so it's easier to compare if rediff is not broken.
[packages/rpm-build-tools.git] / rediff-patches.py
CommitLineData
7eacbddd
AM
1#!/usr/bin/python3
2
3# rediff-patches.py name.spec
4
1e57e977
AM
5import argparse
6import collections
7import logging
7eacbddd
AM
8import os
9import re
10import rpm
11import shutil
12import subprocess
13import sys
14import tempfile
15
16RPMBUILD_ISPATCH = (1<<1)
17
ce75a2bd
AM
18def prepare_spec(r, patch_nr, before=False):
19 tempspec = tempfile.NamedTemporaryFile()
20 re_patch = re.compile(r'^%patch(?P<patch_number>\d+)\w*')
21 for line in r.parsed.split('\n'):
22 m = re_patch.match(line)
23 if m:
24 patch_number = int(m.group('patch_number'))
25 if patch_nr == patch_number:
26 if before:
27 tempspec.write(b"exit 0\n# here was patch%d\n" % patch_nr)
28 else:
29 line = re.sub(r'#.*', "", line)
30 tempspec.write(b"%s\nexit 0\n" % line.encode('utf-8'))
31 continue
32 tempspec.write(b"%s\n" % line.encode('utf-8'))
33 tempspec.flush()
34 return tempspec
35
36def unpack(spec, builddir):
37 cmd = [ 'rpmbuild', '-bp',
38 '--define', '_builddir %s' % builddir,
39 '--define', '_enable_debug_packages 0',
40 '--define', '_default_patch_fuzz 2',
41 spec ]
1e57e977
AM
42 logging.debug("running %s" % repr(cmd))
43 subprocess.check_call(cmd, stdout=sys.stderr, stderr=sys.stderr,
44 env={'LC_ALL': 'C.UTF-8'}, timeout=600)
7eacbddd
AM
45
46def diff(diffdir_org, diffdir, builddir, output):
47 diffdir_org = os.path.basename(diffdir_org)
48 diffdir = os.path.basename(diffdir)
49
50 with open(output, 'wt') as f:
51 cmd = [ 'diff', '-urNp', '-x', '*.orig', diffdir_org, diffdir ]
1e57e977 52 logging.debug("running %s" % repr(cmd))
7eacbddd 53 try:
1e57e977
AM
54 subprocess.check_call(cmd, cwd=builddir, stdout=f, stderr=sys.stderr,
55 env={'LC_ALL': 'C.UTF-8'}, timeout=600)
7eacbddd
AM
56 except subprocess.CalledProcessError as err:
57 if err.returncode != 1:
58 raise
1e57e977
AM
59 logging.info("rediff generated as %s" % output)
60
0f726ca6
AM
61def diffstat(patch):
62 cmd = [ 'diffstat', patch ]
63 logging.info("running diffstat for: %s" % patch)
64 try:
65 subprocess.check_call(cmd, stdout=sys.stdout, stderr=sys.stderr,
66 env={'LC_ALL': 'C.UTF-8'}, timeout=60)
67 except subprocess.CalledProcessError as err:
68 logging.error("running diffstat failed: %s" % err)
69 except FileNotFoundError as err:
70 logging.error("running diffstat failed: %s, install diffstat package?" % err)
71
c65b587f 72def main():
1e57e977
AM
73 parser = parser = argparse.ArgumentParser(description='rediff patches to avoid fuzzy hunks')
74 parser.add_argument('spec', type=str, help='spec file name')
75 parser.add_argument('-p', '--patches', type=str, help='comma separated list of patch numbers to rediff')
76 parser.add_argument('-v', '--verbose', help='increase output verbosity', action='store_true')
77 args = parser.parse_args()
78
79 logging.basicConfig(level=logging.INFO)
80 rpm.setVerbosity(rpm.RPMLOG_ERR)
81
82 if args.verbose:
83 logging.basicConfig(level=logging.DEBUG)
84 rpm.setVerbosity(rpm.RPMLOG_DEBUG)
85
86 if args.patches:
87 args.patches = [int(x) for x in args.patches.split(',')]
88
89 specfile = args.spec
c65b587f
AM
90
91 tempdir = tempfile.TemporaryDirectory(dir="/dev/shm")
92 topdir = tempdir.name
93 builddir = os.path.join(topdir, 'BUILD')
94
95 rpm.addMacro("_builddir", builddir)
96
97 r = rpm.spec(specfile)
98
99 patches = {}
100
101 for (name, nr, flags) in r.sources:
102 if flags & RPMBUILD_ISPATCH:
103 patches[nr] = name
104
1e57e977 105 applied_patches = collections.OrderedDict()
c65b587f
AM
106 re_patch = re.compile(r'^%patch(?P<patch_number>\d+)\w*(?P<patch_args>.*)')
107 for line in r.parsed.split('\n'):
108 m = re_patch.match(line)
109 if not m:
110 continue
111 patch_nr = int(m.group('patch_number'))
112 patch_args = m.group('patch_args')
113 applied_patches[patch_nr] = patch_args
114
115 appsourcedir = rpm.expandMacro("%{_sourcedir}")
116 appbuilddir = rpm.expandMacro("%{_builddir}/%{?buildsubdir}")
117
ce75a2bd 118 for patch_nr in applied_patches.keys():
1e57e977 119 if args.patches and patch_nr not in args.patches:
c65b587f 120 continue
1e57e977
AM
121 patch_name = patches[patch_nr]
122 logging.info("*** patch %d: %s" % (patch_nr, patch_name))
ce75a2bd
AM
123
124 tempspec = prepare_spec(r, patch_nr, before=True)
125 unpack(tempspec.name, builddir)
126 tempspec.close()
c65b587f 127 os.rename(appbuilddir, appbuilddir + ".org")
ce75a2bd
AM
128
129 tempspec = prepare_spec(r, patch_nr, before=False)
130 unpack(tempspec.name, builddir)
131 tempspec.close()
132
c65b587f 133 diff(appbuilddir + ".org", appbuilddir, builddir, os.path.join(topdir, os.path.join(appsourcedir, patch_name + ".rediff")))
ce75a2bd 134
0f726ca6
AM
135 diffstat(os.path.join(topdir, os.path.join(appsourcedir, patch_name)))
136 diffstat(os.path.join(topdir, os.path.join(appsourcedir, patch_name + ".rediff")))
137
c65b587f
AM
138 shutil.rmtree(builddir)
139 tempdir.cleanup()
140
141if __name__ == '__main__':
142 main()
This page took 0.05639 seconds and 4 git commands to generate.