]> git.pld-linux.org Git - packages/rpm-build-tools.git/blame - rediff-patches.py
Keep comments at beginning of the patch.
[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
98607168 36def unpack(spec, appsourcedir, builddir):
ce75a2bd
AM
37 cmd = [ 'rpmbuild', '-bp',
38 '--define', '_builddir %s' % builddir,
98607168
AM
39 '--define', '_specdir %s' % appsourcedir,
40 '--define', '_sourcedir %s' % appsourcedir,
ce75a2bd
AM
41 '--define', '_enable_debug_packages 0',
42 '--define', '_default_patch_fuzz 2',
43 spec ]
1e57e977 44 logging.debug("running %s" % repr(cmd))
98607168
AM
45 try:
46 res = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, check=True,
47 env={'LC_ALL': 'C.UTF-8'}, timeout=600)
48 except subprocess.CalledProcessError as err:
49 logging.error("unpacking exited with status code %d." % err.returncode)
50 logging.error("STDOUT:")
51 if err.stdout:
52 for line in err.stdout.decode('utf-8').split("\n"):
53 logging.error(line)
54 logging.error("STDERR:")
55 if err.stderr:
56 for line in err.stderr.decode('utf-8').split("\n"):
57 logging.error(line)
58 raise
59 else:
60 logging.debug("unpacking exited with status code %d." % res.returncode)
61 logging.debug("STDOUT/STDERR:")
62 if res.stdout:
63 for line in res.stdout.decode('utf-8').split("\n"):
64 logging.debug(line)
65
7eacbddd 66
3cc64e89
AM
67def patch_comment_get(patch):
68 patch_comment = ""
69 with open(patch, 'rt') as f:
70 for line in f:
71 if line.startswith('diff ') or line.startswith('--- '):
72 break
73 patch_comment += line
74 return patch_comment
75
76def diff(diffdir_org, diffdir, builddir, patch_comment, output):
7eacbddd
AM
77 diffdir_org = os.path.basename(diffdir_org)
78 diffdir = os.path.basename(diffdir)
79
80 with open(output, 'wt') as f:
3cc64e89
AM
81 if patch_comment:
82 f.write(patch_comment)
83 f.flush()
7eacbddd 84 cmd = [ 'diff', '-urNp', '-x', '*.orig', diffdir_org, diffdir ]
1e57e977 85 logging.debug("running %s" % repr(cmd))
7eacbddd 86 try:
1e57e977
AM
87 subprocess.check_call(cmd, cwd=builddir, stdout=f, stderr=sys.stderr,
88 env={'LC_ALL': 'C.UTF-8'}, timeout=600)
7eacbddd
AM
89 except subprocess.CalledProcessError as err:
90 if err.returncode != 1:
91 raise
1e57e977
AM
92 logging.info("rediff generated as %s" % output)
93
0f726ca6
AM
94def diffstat(patch):
95 cmd = [ 'diffstat', patch ]
96 logging.info("running diffstat for: %s" % patch)
97 try:
98 subprocess.check_call(cmd, stdout=sys.stdout, stderr=sys.stderr,
99 env={'LC_ALL': 'C.UTF-8'}, timeout=60)
100 except subprocess.CalledProcessError as err:
101 logging.error("running diffstat failed: %s" % err)
102 except FileNotFoundError as err:
103 logging.error("running diffstat failed: %s, install diffstat package?" % err)
104
c65b587f 105def main():
1e57e977
AM
106 parser = parser = argparse.ArgumentParser(description='rediff patches to avoid fuzzy hunks')
107 parser.add_argument('spec', type=str, help='spec file name')
108 parser.add_argument('-p', '--patches', type=str, help='comma separated list of patch numbers to rediff')
1cae170b 109 parser.add_argument('-s', '--skip-patches', type=str, help='comma separated list of patch numbers to skip rediff')
1e57e977
AM
110 parser.add_argument('-v', '--verbose', help='increase output verbosity', action='store_true')
111 args = parser.parse_args()
112
113 logging.basicConfig(level=logging.INFO)
114 rpm.setVerbosity(rpm.RPMLOG_ERR)
115
116 if args.verbose:
117 logging.basicConfig(level=logging.DEBUG)
118 rpm.setVerbosity(rpm.RPMLOG_DEBUG)
119
120 if args.patches:
121 args.patches = [int(x) for x in args.patches.split(',')]
122
1cae170b
AM
123 if args.skip_patches:
124 args.skip_patches = [int(x) for x in args.skip_patches.split(',')]
125
1e57e977 126 specfile = args.spec
98607168 127 appsourcedir = os.path.dirname(os.path.abspath(specfile))
c65b587f
AM
128
129 tempdir = tempfile.TemporaryDirectory(dir="/dev/shm")
130 topdir = tempdir.name
131 builddir = os.path.join(topdir, 'BUILD')
132
133 rpm.addMacro("_builddir", builddir)
134
135 r = rpm.spec(specfile)
136
137 patches = {}
138
139 for (name, nr, flags) in r.sources:
140 if flags & RPMBUILD_ISPATCH:
141 patches[nr] = name
142
1e57e977 143 applied_patches = collections.OrderedDict()
c65b587f
AM
144 re_patch = re.compile(r'^%patch(?P<patch_number>\d+)\w*(?P<patch_args>.*)')
145 for line in r.parsed.split('\n'):
146 m = re_patch.match(line)
147 if not m:
148 continue
149 patch_nr = int(m.group('patch_number'))
150 patch_args = m.group('patch_args')
151 applied_patches[patch_nr] = patch_args
152
c65b587f
AM
153 appbuilddir = rpm.expandMacro("%{_builddir}/%{?buildsubdir}")
154
ce75a2bd 155 for patch_nr in applied_patches.keys():
1e57e977 156 if args.patches and patch_nr not in args.patches:
c65b587f 157 continue
1cae170b
AM
158 if args.skip_patches and patch_nr in args.skip_patches:
159 continue
1e57e977
AM
160 patch_name = patches[patch_nr]
161 logging.info("*** patch %d: %s" % (patch_nr, patch_name))
ce75a2bd
AM
162
163 tempspec = prepare_spec(r, patch_nr, before=True)
98607168 164 unpack(tempspec.name, appsourcedir, builddir)
ce75a2bd 165 tempspec.close()
c65b587f 166 os.rename(appbuilddir, appbuilddir + ".org")
ce75a2bd
AM
167
168 tempspec = prepare_spec(r, patch_nr, before=False)
98607168 169 unpack(tempspec.name, appsourcedir, builddir)
ce75a2bd
AM
170 tempspec.close()
171
3cc64e89
AM
172 patch_comment = patch_comment_get(patch_name)
173 diff(appbuilddir + ".org",
174 appbuilddir,
175 builddir,
176 patch_comment,
177 os.path.join(topdir, os.path.join(appsourcedir, patch_name + ".rediff")))
ce75a2bd 178
0f726ca6
AM
179 diffstat(os.path.join(topdir, os.path.join(appsourcedir, patch_name)))
180 diffstat(os.path.join(topdir, os.path.join(appsourcedir, patch_name + ".rediff")))
181
c65b587f
AM
182 shutil.rmtree(builddir)
183 tempdir.cleanup()
184
185if __name__ == '__main__':
186 main()
This page took 0.053689 seconds and 4 git commands to generate.