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
|
#!/usr/bin/python3
import codecs
import io
import os
import os.path
import re
import shutil
import subprocess
import sys
import tempfile
def main(source, version=None):
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'
# 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)]
format_proc = subprocess.Popen(args,
cwd=patch_dir,
env=env, stdout=subprocess.PIPE)
with io.open(format_proc.stdout.fileno(), encoding='utf-8') \
as pipe:
for line in pipe:
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)
# 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)
if unxz_proc.wait() or \
not re.search(r'^\[GNUPG:\]\s+VALIDSIG\s',
codecs.decode(verify_output),
re.MULTILINE):
os.write(2, verify_output) # bytes not str!
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__':
if not (1 <= len(sys.argv) <= 3):
print('Usage: %s {TAR [RT-VERSION] | REPO RT-VERSION}' % sys.argv[0],
file=sys.stderr)
print('TAR is a tarball of patches.', file=sys.stderr)
print('REPO is a git repo containing the given RT-VERSION.',
file=sys.stderr)
sys.exit(2)
main(*sys.argv[1:])
|