]>
Commit | Line | Data |
---|---|---|
7eacbddd AM |
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 | # - argparse fro arguments | |
9 | # - cleanup | |
10 | ||
11 | import os | |
12 | import re | |
13 | import rpm | |
14 | import shutil | |
15 | import subprocess | |
16 | import sys | |
17 | import tempfile | |
18 | ||
19 | RPMBUILD_ISPATCH = (1<<1) | |
20 | ||
21 | def unpack(spec, builddir, until_patch=None): | |
2addb8ce | 22 | cmd = [ 'rpmbuild', '-bp', '--define', '_builddir %s' % builddir, '--define', '_default_patch_fuzz 2' ] |
7eacbddd AM |
23 | if until_patch is not None: |
24 | cmd += [ '--define', '%%patch%d exit; #' % until_patch ] | |
25 | cmd += [ spec ] | |
26 | subprocess.check_call(cmd, stdout=sys.stderr, stderr=sys.stderr, timeout=600) | |
27 | ||
28 | def diff(diffdir_org, diffdir, builddir, output): | |
29 | diffdir_org = os.path.basename(diffdir_org) | |
30 | diffdir = os.path.basename(diffdir) | |
31 | ||
32 | with open(output, 'wt') as f: | |
33 | cmd = [ 'diff', '-urNp', '-x', '*.orig', diffdir_org, diffdir ] | |
34 | try: | |
35 | subprocess.check_call(cmd, cwd=builddir, stdout=f, stderr=sys.stderr, timeout=600) | |
36 | except subprocess.CalledProcessError as err: | |
37 | if err.returncode != 1: | |
38 | raise | |
39 | ||
40 | specfile = sys.argv[1] | |
41 | ||
42 | tempdir = tempfile.TemporaryDirectory(dir="/dev/shm") | |
43 | topdir = tempdir.name | |
44 | builddir = os.path.join(topdir, 'BUILD') | |
45 | ||
46 | rpm.addMacro("_builddir", builddir) | |
47 | ||
48 | r = rpm.spec(specfile) | |
49 | ||
50 | patches = {} | |
51 | ||
52 | for (name, nr, flags) in r.sources: | |
53 | if flags & RPMBUILD_ISPATCH: | |
54 | patches[nr] = name | |
55 | ||
56 | applied_patches = {} | |
57 | re_patch = re.compile(r'^%patch(?P<patch_number>\d+)\w*(?P<patch_args>.*)') | |
58 | for line in r.parsed.split('\n'): | |
59 | m = re_patch.match(line) | |
60 | if not m: | |
61 | continue | |
62 | patch_nr = int(m.group('patch_number')) | |
63 | patch_args = m.group('patch_args') | |
64 | applied_patches[patch_nr] = patch_args | |
65 | ||
66 | appsourcedir = rpm.expandMacro("%{_sourcedir}") | |
67 | appbuilddir = rpm.expandMacro("%{_builddir}/%{?buildsubdir}") | |
68 | ||
69 | for (patch_nr, patch_name) in sorted(patches.items()): | |
70 | if patch_nr not in applied_patches: | |
71 | continue | |
72 | print("*** patch %d: %s" % (patch_nr, patch_name), file=sys.stderr) | |
73 | unpack(specfile, builddir, patch_nr) | |
74 | os.rename(appbuilddir, appbuilddir + ".org") | |
75 | unpack(specfile, builddir, patch_nr + 1) | |
76 | diff(appbuilddir + ".org", appbuilddir, builddir, os.path.join(topdir, os.path.join(appsourcedir, patch_name + ".rediff"))) | |
77 | shutil.rmtree(builddir) | |
78 | tempdir.cleanup() |