1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
|
#!/usr/bin/python3
import argparse
import os
import os.path
import re
import shutil
import subprocess
import sys
import tempfile
def main(source, version, verify_signature):
patch_dir = 'debian/patches-rt'
series_name = 'series'
old_series = set()
new_series = set()
try:
with open(os.path.join(patch_dir, series_name), 'r') as series_fh:
for line in series_fh:
name = line.strip()
if name != '' and name[0] != '#':
old_series.add(name)
except FileNotFoundError:
pass
with open(os.path.join(patch_dir, series_name), 'w') as series_fh:
# Add Origin to all patch headers.
def add_patch(name, source_patch, origin):
path = os.path.join(patch_dir, name)
try:
os.unlink(path)
except FileNotFoundError:
pass
with open(path, 'w') as patch:
in_header = True
for line in source_patch:
if in_header and re.match(r'^(\n|[^\w\s]|Index:)', line):
patch.write('Origin: %s\n' % origin)
if line != '\n':
patch.write('\n')
in_header = False
patch.write(line)
new_series.add(name)
if os.path.isdir(os.path.join(source, '.git')):
# Export rebased branch from stable-rt git as patch series
up_ver = re.sub(r'-rt\d+$', '', version)
env = os.environ.copy()
env['GIT_DIR'] = os.path.join(source, '.git')
env['DEBIAN_KERNEL_KEYRING'] = 'rt-signing-key.pgp'
if verify_signature:
# Validate tag signature
gpg_wrapper = os.path.join(os.getcwd(),
"debian/bin/git-tag-gpg-wrapper")
verify_proc = subprocess.Popen(
['git', '-c', 'gpg.program=%s' % gpg_wrapper,
'tag', '-v', 'v%s-rebase' % version],
env=env)
if verify_proc.wait():
raise RuntimeError("GPG tag verification failed")
args = ['git', 'format-patch',
'v%s..v%s-rebase' % (up_ver, version)]
with subprocess.Popen(args,
cwd=patch_dir,
env=env, stdout=subprocess.PIPE,
text=True) \
as format_proc:
for line in format_proc.stdout:
name = line.strip('\n')
with open(os.path.join(patch_dir, name)) as source_patch:
patch_from = source_patch.readline()
match = re.match(r'From ([0-9a-f]{40}) ', patch_from)
assert match
origin = ('https://git.kernel.org/cgit/linux/kernel/'
'git/rt/linux-stable-rt.git/commit?id=%s' %
match.group(1))
add_patch(name, source_patch, origin)
series_fh.write(line)
else:
# Get version and upstream version
if version is None:
match = re.search(r'(?:^|/)patches-(.+)\.tar\.[gx]z$', source)
assert match, 'no version specified or found in filename'
version = match.group(1)
match = re.match(r'^(\d+\.\d+)(?:\.\d+|-rc\d+)?-rt\d+$', version)
assert match, 'could not parse version string'
up_ver = match.group(1)
if verify_signature:
# Expect an accompanying signature, and validate it
source_sig = re.sub(r'.[gx]z$', '.sign', source)
unxz_proc = subprocess.Popen(['xzcat', source],
stdout=subprocess.PIPE)
verify_output = subprocess.check_output(
['gpgv', '--status-fd', '1',
'--keyring', 'debian/upstream/rt-signing-key.pgp',
'--ignore-time-conflict', source_sig, '-'],
stdin=unxz_proc.stdout,
text=True)
if unxz_proc.wait() or \
not re.search(r'^\[GNUPG:\]\s+VALIDSIG\s',
verify_output, re.MULTILINE):
sys.stderr.write(verify_output)
raise RuntimeError("GPG signature verification failed")
temp_dir = tempfile.mkdtemp(prefix='rt-genpatch', dir='debian')
try:
# Unpack tarball
subprocess.check_call(['tar', '-C', temp_dir, '-xaf', source])
source_dir = os.path.join(temp_dir, 'patches')
assert os.path.isdir(source_dir), \
'tarball does not contain patches directory'
# Copy patch series
origin = ('https://www.kernel.org/pub/linux/kernel/projects/'
'rt/%s/older/patches-%s.tar.xz' %
(up_ver, version))
with open(os.path.join(source_dir, 'series'), 'r') \
as source_series_fh:
for line in source_series_fh:
name = line.strip()
if name != '' and name[0] != '#':
with open(os.path.join(source_dir, name)) \
as source_patch:
add_patch(name, source_patch, origin)
series_fh.write(line)
finally:
shutil.rmtree(temp_dir)
for name in new_series:
if name in old_series:
old_series.remove(name)
else:
print('Added patch', os.path.join(patch_dir, name))
for name in old_series:
print('Obsoleted patch', os.path.join(patch_dir, name))
if __name__ == '__main__':
parser = argparse.ArgumentParser(
description='Generate or update the rt featureset patch series')
parser.add_argument(
'source', metavar='SOURCE', type=str,
help='tarball of patches or git repo containing the given RT-VERSION')
parser.add_argument(
'version', metavar='RT-VERSION', type=str, nargs='?',
help='rt kernel version (optional for tarballs)')
parser.add_argument(
'--verify-signature', action=argparse.BooleanOptionalAction,
default=True,
help='verify signature on tarball (detached in .sign file) or git tag')
args = parser.parse_args()
main(args.source, args.version, args.verify_signature)
|