Skip to content

Commit 1bf3ed0

Browse files
committed
When the reject file is simple, replace it by rpmdev-bumpspec
1 parent 0a7a564 commit 1bf3ed0

7 files changed

Lines changed: 3607 additions & 9 deletions

File tree

.github/workflows/main.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ jobs:
1414
uses: fedora-python/tox-github-action@master
1515
with:
1616
tox_env: ${{ matrix.tox_env }}
17+
dnf_install: /usr/bin/rpmdev-bumpspec
1718
strategy:
1819
matrix:
1920
tox_env: [py38, py39]

README.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,17 @@ ferrypick
33

44
Apply patches from Fedora dist git to different components.
55

6-
This simple tool does 3 steps:
6+
This simple tool does these steps:
77

88
1. download patch file from src.fedoraproject.org
99
2. replaces package name with current dist-git work dir package name
1010
3. runs `git am --reject` on the product
11+
4. if the rejected hunks only touch `Release` and add `%changelog` in spec
12+
files, ignore the rejects and run rpmdev-bumpspec instead
13+
14+
Requires the `rpmdev-bumpspec` tool from [rpmdevtools].
15+
16+
[rpmdevtools]: https://pagure.io/rpmdevtools
1117

1218
Usage:
1319

ferrypick.py

Lines changed: 82 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
import subprocess
66
import sys
77
import urllib.request
8+
import shlex
9+
from pathlib import Path
810

911
COMMIT_RE = re.compile(r"^https://src\.fedoraproject\.org/\S+/([^/\s]+)/c/([0-9a-f]+)")
1012
PR_RE = re.compile(r"^https://src\.fedoraproject\.org/\S+/([^/\s]+)/pull-request/\d+")
@@ -64,9 +66,9 @@ def stdout(cmd):
6466
return subprocess.check_output(cmd, shell=True, text=True).rstrip()
6567

6668

67-
def execute(cmd):
68-
proc = subprocess.run(cmd, shell=True, text=True)
69-
return proc.returncode
69+
def execute(*cmd, **kwargs):
70+
print(f"$ {' '.join(shlex.quote(str(c)) for c in cmd)}")
71+
return subprocess.run(cmd, text=True, **kwargs)
7072

7173

7274
def parse_args():
@@ -97,15 +99,87 @@ def get_patch_content(link):
9799
return (content, original_name)
98100

99101

102+
def handle_reject(filename):
103+
"""If the .rej file given in `filename` is "simple", run rmpdev-bumpspec
104+
105+
Simple means roughly that only Release lines are touched and
106+
%changelog lines are added.
107+
108+
Removes the reject file if successful.
109+
"""
110+
changelog = None
111+
path = Path(filename)
112+
author = None
113+
with path.open() as f:
114+
for line in f:
115+
# Find first hunk header
116+
if line.startswith('@'):
117+
break
118+
for line in f:
119+
marker = line[:1]
120+
print(line.rstrip())
121+
if marker == '@':
122+
# Hunk header
123+
continue
124+
elif marker == ' ':
125+
# Context
126+
if line.strip() == '%changelog':
127+
changelog = []
128+
continue
129+
elif marker in ('+', '-'):
130+
if changelog is not None:
131+
if marker == '-':
132+
# Removing existing changelog - bad
133+
return
134+
if match := re.match(
135+
r'\*\s+(\S+\s+){4}(?P<author>[^>]+>)',
136+
line[1:]
137+
):
138+
author = match['author']
139+
else:
140+
changelog.append(line[1:])
141+
elif line[1:].startswith('Release:'):
142+
continue
143+
else:
144+
# Adding/removing something else - bad
145+
return
146+
else:
147+
# Unknown line - bad
148+
return
149+
if author is None:
150+
print('No author found in reject')
151+
return
152+
print(f'Rejects in {filename} look harmless')
153+
execute(
154+
'rpmdev-bumpspec',
155+
'-u', author,
156+
'-c', ''.join(changelog).strip(),
157+
path.with_suffix(''),
158+
check=True,
159+
)
160+
path.unlink()
161+
162+
100163
def apply_patch(filename):
101-
cmd = f"git am --committer-date-is-author-date --reject {filename}"
102-
print(f"$ {cmd}")
103-
exitcode = execute(cmd)
164+
args = [
165+
"git", "am", "--committer-date-is-author-date ", "--reject", filename,
166+
]
167+
exitcode = execute(*args).returncode
104168
if exitcode:
105169
print(file=sys.stderr)
106-
print(f"{cmd} failed with exit code {exitcode}", file=sys.stderr)
170+
print(f"git am failed with exit code {exitcode}", file=sys.stderr)
107171
print(f"Patch stored as: {filename}", file=sys.stderr)
108-
sys.exit(exitcode)
172+
173+
for spec_rej in Path().glob(f'**/*.spec.rej'):
174+
print(f'Processing rejects in {spec_rej}')
175+
handle_reject(spec_rej)
176+
if not any(Path().glob(f'**/*.rej')):
177+
for spec in Path().glob(f'**/*.spec'):
178+
execute("git", "add", spec.relative_to(Path()), check=True)
179+
exitcode = execute("git", "am", "--continue").returncode
180+
181+
if exitcode:
182+
sys.exit(exitcode)
109183

110184

111185
def main():

0 commit comments

Comments
 (0)