#!/usr/bin/env python import os, re, sys class entry(dict): __slots__ = ('_list') def __init__(self): super(entry, self).__init__() self._list = [] def __delitem__(self, key): super(entry, self).__delitem__(key) if key in self._list: raise NotImplemented def __setitem__(self, key, value): super(entry, self).__setitem__(key, value) if key.startswith('_'): return if key not in self._list: self._list.append(key) def iterkeys(self): for i in self._list: yield i def iteritems(self): for i in self._list: yield (i, self[i]) def read(f): entries = [] while True: e = entry() while True: line = f.readline() if not line: break line = line.strip('\n') if not line: break if line[0] in ' \t': if not last: raise ValueError('Continuation line seen before first header') e[last] += '\n' + line continue i = line.find(':') if i < 0: raise ValueError("Not a header, not a continuation: ``%s''" % line) last = line[:i] e[last] = line[i+1:].lstrip() if not e: break entries.append(e) return entries def read_changelog(): import os f = os.popen("dpkg-parsechangelog") entries = read(f) return entries[0] def read_control_in(): f = file("debian/control.in") entries = read(f) return entries[0], entries[1:] def process_binaries(in_binaries, changelog): binaries = [] patches = {} for in_binary in in_binaries: package = in_binary['Package'] binary = entry() patch = {} for i in in_binary.iterkeys(): if i.startswith('X-'): if i.startswith('X-Depends-'): process_depends(i, binary, in_binary, changelog) if i.startswith('X-Patch-'): patch[i[8:]] = in_binary[i] else: binary[i] = in_binary[i] binaries.append(binary) if patch: patches[package] = patch return binaries, patches def process_depends(in_key, e, in_e, changelog): key = in_key[len('X-Depends-'):] in_dep = in_e[in_key].split(',') dep = [] for d in in_dep: package, command = d.strip().split(':') if command == 'match': v = changelog['Version'] import re m = re.match("^(.*?)(\d+)(-[^-]+|)$", v) if not m.group(3): raise RuntimeError("The match command makes no sense with nativ versions") v1 = m.group(1) + m.group(2) v2 = m.group(1) + str(int(m.group(2)) + 1) dep.extend(('%s (>> %s)' % (package, v1), '%s (<< %s)' % (package, v2))) elif command == 'expand': if package == 'libc': dep.extend(('libc6-dev-s390x [s390]', 'libc6-dev-sparc64 [sparc]')) else: raise NotImplementedError else: raise NotImplementedError if dep: t = in_e.get(key, None) if t is not None: t += ', ' + ', '.join(dep) else: t = ', '.join(dep) e[key] = t def process_patches(in_patches, source): patches = [] kpatches = {} kernel_versions = [] for package, in_patch in in_patches.iteritems(): id = in_patch['Id'] p = [] patch = entry() for i in ('Id', 'Name'): patch['Patch-' + i] = in_patch[i] p.append(patch) for v in in_patch['Kernel-Versions'].split(): i = v.rfind('-') if i == -1: version = v revision = None else: version = v[:i] revision = v[i+1:] kernel_versions.append((version, revision)) e = entry() e['Kernel-Version'] = version e['Patch-File'] = in_patch['File'] % {'id': id, 'version': version} try: e['Depends'] = in_patch['Depends'] except KeyError: pass p.append(e) if revision: debian_version = "%s-%s" % (version, revision) else: debian_version = '' patches.append({'id': id, 'version': version, 'debian_version': debian_version, 'patch_version': version}) kpatches[package] = p build_deps = [] for version, revision in kernel_versions: if revision: build_deps.append("kernel-tree-%s-%s" % (version, revision)) else: build_deps.append("kernel-tree-%s" % version) if build_deps: t = source.get("Build-Depends-Indep", None) if t is not None: t += ', ' + ', '.join(build_deps) else: t = ', '.join(build_deps) source["Build-Depends-Indep"] = t return patches, kpatches, source def process_source(in_source, changelog): source = entry() for i in in_source.iterkeys(): if i.startswith('X-'): if i.startswith('X-Depends-'): process_depends(i, source, in_source, changelog) else: source[i] = in_source[i] return source def write(f, list): for i in list: for j in i.iteritems(): f.write("%s: %s\n" % j) f.write('\n') def write_control(list): f = file("debian/control", 'w') write(f, list) def write_kpatches(kpatches): for package, entry in kpatches.iteritems(): f = file("debian/%s.kpatches" % package, 'w') write(f, entry) def write_patches(patches): if len(patches) == 0: return f = file("debian/build-patch", 'w') f.write("set -e\n") for e in patches: f.write('debian/rules build-patch ID="%(id)s" VERSION="%(version)s" DEBIAN_VERSION="%(debian_version)s" PATCH_VERSION="%(patch_version)s"\n' % e) if __name__ == '__main__': changelog = read_changelog() source, binaries = read_control_in() source = process_source(source, changelog) binaries, patches = process_binaries(binaries, changelog) patches, kpatches, source = process_patches(patches, source) write_control([source] + binaries) write_kpatches(kpatches) write_patches(patches)