diff --git a/debian/bin/gencontrol.py b/debian/bin/gencontrol.py index ecd28b2bd..2fdcdfd93 100755 --- a/debian/bin/gencontrol.py +++ b/debian/bin/gencontrol.py @@ -1,29 +1,22 @@ #!/usr/bin/env python2.4 + import sys sys.path.append("debian/lib/python") -import warnings + from debian_linux.debian import * +from debian_linux.gencontrol import PackagesList, Makefile, MakeFlags from debian_linux.utils import * -class packages_list(sorted_dict): - def append(self, package): - self[package['Package']] = package - - def extend(self, packages): - for package in packages: - self[package['Package']] = package - class gencontrol(object): makefile_targets = ('binary-arch', 'build') def __init__(self, underlay = None): - self.changelog = read_changelog() - self.templates = templates() - self.version, self.changelog_vars = self.process_changelog({}) + self.templates = Templates(['debian/templates']) + self.process_changelog() def __call__(self): - packages = packages_list() - makefile = [] + packages = PackagesList() + makefile = Makefile() self.do_source(packages) self.do_main(packages, makefile) @@ -33,61 +26,47 @@ class gencontrol(object): def do_source(self, packages): source = self.templates["control.source"] - packages['source'] = self.process_package(source[0], self.changelog_vars) + packages['source'] = self.process_package(source[0], self.vars) def do_main(self, packages, makefile): - makeflags = { - 'VERSION': self.version['linux']['version'], - 'SOURCE_UPSTREAM': self.version['upstream'], - 'SOURCEVERSION': self.version['linux']['source'], - 'UPSTREAMVERSION': self.version['linux']['upstream'], - } - - vars = self.changelog_vars.copy() + vars = self.vars.copy() + makeflags = MakeFlags() self.do_main_setup(vars, makeflags) self.do_main_packages(packages) self.do_main_makefile(makefile, makeflags) def do_main_setup(self, vars, makeflags): - pass + makeflags.update({ + 'MAJOR': self.version.linux_major, + 'VERSION': self.version.linux_version, + 'UPSTREAMVERSION': self.version.linux_upstream, + }) def do_main_makefile(self, makefile, makeflags): - makeflags_string = ' '.join(["%s='%s'" % i for i in makeflags.iteritems()]) - for i in self.makefile_targets: - makefile.append(("%s:" % i, ("$(MAKE) -f debian/rules.real %s %s" % (i, makeflags_string)))) + makefile.add(i, cmds = ["$(MAKE) -f debian/rules.real %s %s" % (i, makeflags)]) def do_main_packages(self, packages): - vars = self.changelog_vars - main = self.templates["control.main"] - packages.extend(self.process_packages(main, vars)) + packages.extend(self.process_packages(main, self.vars)) - def process_changelog(self, in_vars): - ret = [None, None] - ret[0] = version = self.changelog[0]['Version'] - vars = in_vars.copy() - vars['upstreamversion'] = version['linux']['upstream'] - vars['version'] = version['linux']['version'] - vars['source_upstream'] = version['upstream'] - vars['major'] = version['linux']['major'] - ret[1] = vars - return ret + def process_changelog(self): + changelog = Changelog(version = VersionLinux) + self.version = version = changelog[0].version + self.vars = { + 'upstreamversion': version.linux_upstream, + 'version': version.linux_version, + 'source_upstream': version.upstream, + 'major': version.linux_major, + } def process_relation(self, key, e, in_e, vars): - in_dep = in_e[key] - dep = package_relation_list() - for in_groups in in_dep: - groups = package_relation_group() - for in_item in in_groups: - item = package_relation() - item.name = self.substitute(in_item.name, vars) - if in_item.version is not None: - item.version = self.substitute(in_item.version, vars) - item.arches = in_item.arches - groups.append(item) - dep.append(groups) + import copy + dep = copy.deepcopy(in_e[key]) + for groups in dep: + for item in groups: + item.name = self.substitute(item.name, vars) e[key] = dep def process_description(self, e, in_e, vars): @@ -95,13 +74,13 @@ class gencontrol(object): desc = in_desc.__class__() desc.short = self.substitute(in_desc.short, vars) for i in in_desc.long: - desc.long.append(self.substitute(i, vars)) + desc.append(self.substitute(i, vars)) e['Description'] = desc def process_package(self, in_entry, vars): - e = package() + e = Package() for key, value in in_entry.iteritems(): - if isinstance(value, package_relation_list): + if isinstance(value, PackageRelation): self.process_relation(key, e, in_entry, vars) elif key == 'Description': self.process_description(e, in_entry, vars) @@ -129,18 +108,10 @@ class gencontrol(object): def write_control(self, list): self.write_rfc822(file("debian/control", 'w'), list) - def write_makefile(self, out_list): - out = file("debian/rules.gen", 'w') - for item in out_list: - if isinstance(item, (list, tuple)): - out.write("%s\n" % item[0]) - cmd_list = item[1] - if isinstance(cmd_list, basestring): - cmd_list = cmd_list.split('\n') - for j in cmd_list: - out.write("\t%s\n" % j) - else: - out.write("%s\n" % item) + def write_makefile(self, makefile): + f = file("debian/rules.gen", 'w') + makefile.write(f) + f.close() def write_rfc822(self, f, list): for entry in list: @@ -148,6 +119,5 @@ class gencontrol(object): f.write("%s: %s\n" % (key, value)) f.write('\n') - if __name__ == '__main__': gencontrol()() diff --git a/debian/bin/genorig.py b/debian/bin/genorig.py index 6a24304c5..637ecaff1 100755 --- a/debian/bin/genorig.py +++ b/debian/bin/genorig.py @@ -4,34 +4,39 @@ import sys sys.path.append("debian/lib/python") import os, os.path, re, shutil -from debian_linux.debian import read_changelog +from debian_linux.debian import Changelog, VersionLinux -class main(object): - def __init__(self, input_tar, input_patch = None): +class Main(object): + def __init__(self, input_tar, input_patch, override_version): self.log = sys.stdout.write self.input_tar = input_tar self.input_patch = input_patch - changelog = read_changelog()[0] - source = changelog['Source'] - version = changelog['Version']['linux']['source_upstream'] - self.orig = '%s-%s' % (source, version) - self.orig_tar = '%s_%s.orig.tar.gz' % (source, version) + changelog = Changelog(version = VersionLinux)[0] + source = changelog.source + version = changelog.version + + if override_version: + version = VersionLinux('%s-undef' % override_version) + + self.log('Using source name %s, version %s\n' % (source, version.upstream)) + + self.orig = '%s-%s' % (source, version.upstream) + self.orig_tar = '%s_%s.orig.tar.gz' % (source, version.upstream) def __call__(self): import tempfile self.dir = tempfile.mkdtemp(prefix = 'genorig', dir = 'debian') try: - self.extract() - self.patch() + self.upstream_extract() + self.upstream_patch() self.generate() self.tar() finally: - pass shutil.rmtree(self.dir) - def extract(self): + def upstream_extract(self): self.log("Extracting tarball %s\n" % self.input_tar) match = re.match(r'(^|.*/)(?Plinux-\d+\.\d+\.\d+(-\S+)?)\.tar(\.(?P(bz2|gz)))?$', self.input_tar) if not match: @@ -45,11 +50,11 @@ class main(object): raise RuntimeError("Can't extract tarball") os.rename(os.path.join(self.dir, match.group('dir')), os.path.join(self.dir, 'temp')) - def patch(self): + def upstream_patch(self): if self.input_patch is None: return self.log("Patching source with %s\n" % self.input_patch) - match = re.match(r'(^|.*/)(patch-\d+\.\d+\.\d+(-\S+)?(\.(?P(bz2|gz))))?$', self.input_patch) + match = re.match(r'(^|.*/)patch-\d+\.\d+\.\d+(-\S+?)?(\.(?P(bz2|gz)))?$', self.input_patch) if not match: raise RuntimeError("Can't identify name of patch") cmdline = [] @@ -68,9 +73,7 @@ class main(object): self.log("Generate orig\n") orig = os.path.join(self.dir, self.orig) temp = os.path.join(self.dir, 'temp') - os.mkdir(orig) - os.mkdir(os.path.join(orig, 'include')) - os.mkdir(os.path.join(orig, 'include', 'linux')) + os.makedirs(os.path.join(orig, 'include', 'linux')) shutil.copyfile(os.path.join(temp, 'COPYING'), os.path.join(orig, 'COPYING')) for i in ('input.h', 'license.h', 'mod_devicetable.h'): shutil.copyfile(os.path.join(temp, 'include', 'linux', i), os.path.join(orig, 'include', 'linux', i)) @@ -78,10 +81,35 @@ class main(object): def tar(self): out = os.path.join("../orig", self.orig_tar) + try: + os.mkdir("../orig") + except OSError: pass + try: + os.stat(out) + raise RuntimeError("Destination already exists") + except OSError: pass self.log("Generate tarball %s\n" % out) cmdline = ['tar -czf', out, '-C', self.dir, self.orig] - if os.spawnv(os.P_WAIT, '/bin/sh', ['sh', '-c', ' '.join(cmdline)]): - raise RuntimeError("Can't patch source") + try: + if os.spawnv(os.P_WAIT, '/bin/sh', ['sh', '-c', ' '.join(cmdline)]): + raise RuntimeError("Can't patch source") + os.chmod(out, 0644) + except: + try: + os.unlink(out) + except OSError: + pass + raise if __name__ == '__main__': - main(*sys.argv[1:])() + from optparse import OptionParser + parser = OptionParser(usage = "%prog [OPTION]... TAR [PATCH]") + parser.add_option("-V", "--override-version", dest = "override_version", help = "Override version", metavar = "VERSION") + options, args = parser.parse_args() + + input_tar = args[0] + input_patch = None + if len(args) > 1: + input_patch = args[1] + + Main(input_tar, input_patch, options.override_version)() diff --git a/debian/changelog b/debian/changelog index 8d4970214..ca5a48096 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,8 +1,8 @@ -linux-kbuild-2.6 (2.6.23~rc4-1) UNRELEASED; urgency=low +linux-kbuild-2.6 (2.6.23-1) UNRELEASED; urgency=low * New upstream version. - -- Bastian Blank Thu, 30 Aug 2007 21:15:03 +0200 + -- Bastian Blank Sun, 14 Oct 2007 11:28:39 +0200 linux-kbuild-2.6 (2.6.22-1) unstable; urgency=low diff --git a/debian/lib/python/debian_linux/__init__.py b/debian/lib/python/debian_linux/__init__.py index b989d7d15..e69de29bb 100644 --- a/debian/lib/python/debian_linux/__init__.py +++ b/debian/lib/python/debian_linux/__init__.py @@ -1,3 +0,0 @@ -from debian import * -from utils import * - diff --git a/debian/lib/python/debian_linux/config.py b/debian/lib/python/debian_linux/config.py new file mode 100644 index 000000000..7e3e12ae8 --- /dev/null +++ b/debian/lib/python/debian_linux/config.py @@ -0,0 +1,209 @@ +import os, os.path, re, sys, textwrap + +__all__ = [ + 'ConfigParser', + 'ConfigReaderCore', +] + +class SchemaItemBoolean(object): + def __call__(self, i): + i = i.strip().lower() + if i in ("true", "1"): + return True + if i in ("false", "0"): + return False + raise Error + +class SchemaItemList(object): + def __init__(self, type = "\s+"): + self.type = type + + def __call__(self, i): + i = i.strip() + if not i: + return [] + return [j.strip() for j in re.split(self.type, i)] + +class ConfigReaderCore(dict): + config_name = "defines" + + schemas = { + 'base': { + 'arches': SchemaItemList(), + 'enabled': SchemaItemBoolean(), + 'featuresets': SchemaItemList(), + 'flavours': SchemaItemList(), + 'modules': SchemaItemBoolean(), + }, + 'image': { + 'configs': SchemaItemList(), + 'initramfs': SchemaItemBoolean(), + 'initramfs-generators': SchemaItemList(), + }, + 'relations': { + }, + 'xen': { + 'dom0-support': SchemaItemBoolean(), + 'versions': SchemaItemList(), + } + } + + def __init__(self, dirs = []): + self._dirs = dirs + self._read_base() + + def _read_arch(self, arch): + config = ConfigParser(self.schemas) + config.read(self.get_files("%s/%s" % (arch, self.config_name))) + + featuresets = config['base',].get('featuresets', []) + flavours = config['base',].get('flavours', []) + + for section in iter(config): + if section[0] in featuresets: + real = (section[-1], arch, section[0]) + elif len(section) > 1: + real = (section[-1], arch, None) + section[:-1] + else: + real = (section[-1], arch) + section[:-1] + s = self.get(real, {}) + s.update(config[section]) + self[tuple(real)] = s + + for featureset in featuresets: + self._read_arch_featureset(arch, featureset) + + if flavours: + base = self['base', arch] + featuresets.insert(0, 'none') + base['featuresets'] = featuresets + del base['flavours'] + self['base', arch] = base + self['base', arch, 'none'] = {'flavours': flavours, 'implicit-flavour': True} + + def _read_arch_featureset(self, arch, featureset): + config = ConfigParser(self.schemas) + config.read(self.get_files("%s/%s/%s" % (arch, featureset, self.config_name))) + + flavours = config['base',].get('flavours', []) + + for section in iter(config): + real = (section[-1], arch, featureset) + section[:-1] + s = self.get(real, {}) + s.update(config[section]) + self[tuple(real)] = s + + def _read_base(self): + config = ConfigParser(self.schemas) + config.read(self.get_files(self.config_name)) + + arches = config['base',]['arches'] + featuresets = config['base',]['featuresets'] + + for section in iter(config): + if section[0].startswith('featureset-'): + real = (section[-1], None, section[0].lstrip('featureset-')) + else: + real = (section[-1],) + section[1:] + self[real] = config[section] + + for arch in arches: + self._read_arch(arch) + for featureset in featuresets: + self._read_featureset(featureset) + + def _read_featureset(self, featureset): + config = ConfigParser(self.schemas) + config.read(self.get_files("featureset-%s/%s" % (featureset, self.config_name))) + + for section in iter(config): + real = (section[-1], None, featureset) + s = self.get(real, {}) + s.update(config[section]) + self[real] = s + + def get_files(self, name): + return [os.path.join(i, name) for i in self._dirs if i] + + def merge(self, section, arch = None, featureset = None, flavour = None): + ret = {} + ret.update(self.get((section,), {})) + if featureset: + ret.update(self.get((section, None, featureset), {})) + if arch: + ret.update(self.get((section, arch), {})) + if arch and featureset: + ret.update(self.get((section, arch, featureset), {})) + if arch and featureset and flavour: + ret.update(self.get((section, arch, None, flavour), {})) + ret.update(self.get((section, arch, featureset, flavour), {})) + return ret + +class ConfigParser(object): + __slots__ = '_config', 'schemas' + + def __init__(self, schemas): + self.schemas = schemas + + from ConfigParser import RawConfigParser + self._config = config = RawConfigParser() + + def __getitem__(self, key): + return self._convert()[key] + + def __iter__(self): + return iter(self._convert()) + + def __str__(self): + return '<%s(%s)>' % (self.__class__.__name__, self._convert()) + + def _convert(self): + ret = {} + for section in self._config.sections(): + data = {} + for key, value in self._config.items(section): + data[key] = value + s1 = section.split('_') + if s1[-1] in self.schemas: + ret[tuple(s1)] = self.SectionSchema(data, self.schemas[s1[-1]]) + else: + ret[(section,)] = self.Section(data) + return ret + + def keys(self): + return self._convert().keys() + + def read(self, data): + return self._config.read(data) + + class Section(dict): + def __init__(self, data): + super(ConfigParser.Section, self).__init__(data) + + def __str__(self): + return '<%s(%s)>' % (self.__class__.__name__, self._data) + + class SectionSchema(Section): + __slots__ = () + + def __init__(self, data, schema): + for key in data.keys(): + try: + data[key] = schema[key](data[key]) + except KeyError: pass + super(ConfigParser.SectionSchema, self).__init__(data) + +if __name__ == '__main__': + import sys + config = ConfigReaderCore(['debian/config']) + sections = config.keys() + sections.sort() + for section in sections: + print "[%s]" % (section,) + items = config[section] + items_keys = items.keys() + items_keys.sort() + for item in items: + print "%s: %s" % (item, items[item]) + print + diff --git a/debian/lib/python/debian_linux/debian.py b/debian/lib/python/debian_linux/debian.py index 7b6e9ba10..977a0bd57 100644 --- a/debian/lib/python/debian_linux/debian.py +++ b/debian/lib/python/debian_linux/debian.py @@ -1,103 +1,154 @@ import itertools, os.path, re, utils -def read_changelog(dir = ''): - r = re.compile(r""" -^ -( -(?P
- (?P - \w[-+0-9a-z.]+ - ) - \ - \( - (?P - [^\(\)\ \t]+ - ) - \) - \s+ - (?P - [-0-9a-zA-Z]+ - ) - \; -) -) -""", re.VERBOSE) - f = file(os.path.join(dir, "debian/changelog")) - entries = [] - act_upstream = None - while True: - line = f.readline() - if not line: - break - line = line.strip('\n') - match = r.match(line) - if not match: - continue - if match.group('header'): - e = {} - e['Distribution'] = match.group('header_distribution') - e['Source'] = match.group('header_source') - version = parse_version(match.group('header_version')) - e['Version'] = version - if act_upstream is None: - act_upstream = version['upstream'] - elif version['upstream'] != act_upstream: - break - entries.append(e) - return entries - -def parse_version(version): - ret = { - 'complete': version, - 'upstream': version, - 'debian': None, - 'linux': None, - } - try: - i = len(version) - version[::-1].index('-') - except ValueError: - return ret - ret['upstream'] = version[:i-1] - ret['debian'] = version[i:] - try: - ret['linux'] = parse_version_linux(version) - except ValueError: - pass - return ret - -def parse_version_linux(version): - version_re = ur""" +class Changelog(list): + _rules = r""" ^ (?P - (?P - (?P\d+\.\d+) - \. + \w[-+0-9a-z.]+ +) +\ +\( +(?P + [^\(\)\ \t]+ +) +\) +\s+ +(?P + [-+0-9a-zA-Z.]+ +) +\; +""" + _re = re.compile(_rules, re.X) + + class Entry(object): + __slot__ = 'distribution', 'source', 'version' + + def __init__(self, distribution, source, version): + self.distribution, self.source, self.version = distribution, source, version + + def __init__(self, dir = '', version = None): + if version is None: + version = Version + f = file(os.path.join(dir, "debian/changelog")) + while True: + line = f.readline() + if not line: + break + match = self._re.match(line) + if not match: + continue + try: + v = version(match.group('version')) + except Exception: + if not len(self): + raise + v = Version(match.group('version')) + self.append(self.Entry(match.group('distribution'), match.group('source'), v)) + +class Version(object): + _version_rules = ur""" +^ +(?: + (?P \d+ ) - (?: - ~ - (?P - .+? - ) - )? + : +)? +(?P + .+? +) +(?: - (?P[^-]+) -) +)? $ """ - match = re.match(version_re, version, re.X) - if match is None: - raise ValueError - ret = match.groupdict() - if ret['modifier'] is not None: - ret['upstream'] = '%s-%s' % (ret['version'], ret['modifier']) - ret['source_upstream'] = '%s~%s' % (ret['version'], ret['modifier']) - else: - ret['upstream'] = ret['version'] - ret['source_upstream'] = ret['version'] - return ret + _version_re = re.compile(_version_rules, re.X) -class package_description(object): + def __init__(self, version): + match = self._version_re.match(version) + if match is None: + raise RuntimeError, "Invalid debian version" + self.epoch = None + if match.group("epoch") is not None: + self.epoch = int(match.group("epoch")) + self.upstream = match.group("upstream") + self.debian = match.group("debian") + + def __str__(self): + return self.complete + + @property + def complete(self): + if self.epoch is not None: + return "%d:%s" % (self.epoch, self.complete_noepoch) + return self.complete_noepoch + + @property + def complete_noepoch(self): + if self.debian is not None: + return "%s-%s" % (self.upstream, self.debian) + return self.upstream + +class VersionLinux(Version): + _version_linux_rules = ur""" +^ +(?P + (?P\d+\.\d+) + \. + \d+ +) +(?: + ~ + (?P + .+? + ) +)? +(?: + \.dfsg\. + (?P + \d+ + ) +)? +- +(?:[^-]+) +$ +""" + _version_linux_re = re.compile(_version_linux_rules, re.X) + + def __init__(self, version): + super(VersionLinux, self).__init__(version) + match = self._version_linux_re.match(version) + if match is None: + raise RuntimeError, "Invalid debian linux version" + d = match.groupdict() + self.linux_major = d['major'] + self.linux_modifier = d['modifier'] + self.linux_version = d['version'] + if d['modifier'] is not None: + self.linux_upstream = '-'.join((d['version'], d['modifier'])) + else: + self.linux_upstream = d['version'] + self.linux_dfsg = d['dfsg'] + +class PackageFieldList(list): + def __init__(self, value = None): + self.extend(value) + + def __str__(self): + return ' '.join(self) + + def _extend(self, value): + if value is not None: + self.extend([j.strip() for j in re.split('\s', value.strip())]) + + def extend(self, value): + if isinstance(value, str): + self._extend(value) + else: + super(PackageFieldList, self).extend(value) + +class PackageDescription(object): __slots__ = "short", "long" def __init__(self, value = None): @@ -110,7 +161,7 @@ class package_description(object): def __str__(self): ret = self.short + '\n' - w = utils.wrap(width = 74, fix_sentence_endings = True) + w = utils.TextWrapper(width = 74, fix_sentence_endings = True) pars = [] for i in self.long: pars.append('\n '.join(w.wrap(i))) @@ -121,48 +172,7 @@ class package_description(object): if str: self.long.extend(str.split("\n.\n")) -class package_relation(object): - __slots__ = "name", "version", "arches" - - _re = re.compile(r'^(\S+)(?: \(([^)]+)\))?(?: \[([^]]+)\])?$') - - def __init__(self, value = None): - if value is not None: - self.parse(value) - else: - self.name = None - self.version = None - self.arches = [] - - def __str__(self): - ret = [self.name] - if self.version is not None: - ret.extend([' (', self.version, ')']) - if self.arches: - ret.extend([' [', ' '.join(self.arches), ']']) - return ''.join(ret) - - def config(self, entry): - if self.version is not None or self.arches: - return - value = entry.get(self.name, None) - if value is None: - return - self.parse(value) - - def parse(self, value): - match = self._re.match(value) - if match is None: - raise RuntimeError, "Can't parse dependency %s" % value - match = match.groups() - self.name = match[0] - self.version = match[1] - if match[2] is not None: - self.arches = re.split('\s+', match[2]) - else: - self.arches = [] - -class package_relation_list(list): +class PackageRelation(list): def __init__(self, value = None): if value is not None: self.extend(value) @@ -178,18 +188,14 @@ class package_relation_list(list): def append(self, value): if isinstance(value, basestring): - value = package_relation_group(value) - elif not isinstance(value, package_relation_group): + value = PackageRelationGroup(value) + elif not isinstance(value, PackageRelationGroup): raise ValueError, "got %s" % type(value) j = self._match(value) if j: - j._update_arches(value) + j._updateArches(value) else: - super(package_relation_list, self).append(value) - - def config(self, entry): - for i in self: - i.config(entry) + super(PackageRelation, self).append(value) def extend(self, value): if isinstance(value, basestring): @@ -199,7 +205,7 @@ class package_relation_list(list): for i in value: self.append(i) -class package_relation_group(list): +class PackageRelationGroup(list): def __init__(self, value = None): if value is not None: self.extend(value) @@ -213,7 +219,7 @@ class package_relation_group(list): return None return self - def _update_arches(self, value): + def _updateArches(self, value): for i, j in itertools.izip(self, value): if i.arches: for arch in j.arches: @@ -222,14 +228,10 @@ class package_relation_group(list): def append(self, value): if isinstance(value, basestring): - value = package_relation(value) - elif not isinstance(value, package_relation): + value = PackageRelationEntry(value) + elif not isinstance(value, PackageRelationEntry): raise ValueError - super(package_relation_group, self).append(value) - - def config(self, entry): - for i in self: - i.config(entry) + super(PackageRelationGroup, self).append(value) def extend(self, value): if isinstance(value, basestring): @@ -239,25 +241,78 @@ class package_relation_group(list): for i in value: self.append(i) -class package(dict): - _fields = utils.sorted_dict(( +class PackageRelationEntry(object): + __slots__ = "name", "operator", "version", "arches" + + _re = re.compile(r'^(\S+)(?: \((<<|<=|=|!=|>=|>>)\s*([^)]+)\))?(?: \[([^]]+)\])?$') + + class _operator(object): + OP_LT = 1; OP_LE = 2; OP_EQ = 3; OP_NE = 4; OP_GE = 5; OP_GT = 6 + operators = { '<<': OP_LT, '<=': OP_LE, '=': OP_EQ, '!=': OP_NE, '>=': OP_GE, '>>': OP_GT } + operators_neg = { OP_LT: OP_GE, OP_LE: OP_GT, OP_EQ: OP_NE, OP_NE: OP_EQ, OP_GE: OP_LT, OP_GT: OP_LE } + operators_text = dict([(b, a) for a, b in operators.iteritems()]) + + __slots__ = '_op', + + def __init__(self, value): + self._op = self.operators[value] + + def __neg__(self): + return self.__class__(self.operators_text[self.operators_neg[self._op]]) + + def __str__(self): + return self.operators_text[self._op] + + def __init__(self, value = None): + if isinstance(value, basestring): + self.parse(value) + else: + raise ValueError + + def __str__(self): + ret = [self.name] + if self.operator is not None and self.version is not None: + ret.extend([' (', str(self.operator), ' ', self.version, ')']) + if self.arches: + ret.extend([' [', ' '.join(self.arches), ']']) + return ''.join(ret) + + def parse(self, value): + match = self._re.match(value) + if match is None: + raise RuntimeError, "Can't parse dependency %s" % value + match = match.groups() + self.name = match[0] + if match[1] is not None: + self.operator = self._operator(match[1]) + else: + self.operator = None + self.version = match[2] + if match[3] is not None: + self.arches = re.split('\s+', match[3]) + else: + self.arches = [] + +class Package(dict): + _fields = utils.SortedDict(( ('Package', str), ('Source', str), - ('Architecture', utils.field_list), + ('Architecture', PackageFieldList), ('Section', str), ('Priority', str), ('Maintainer', str), ('Uploaders', str), ('Standards-Version', str), - ('Build-Depends', package_relation_list), - ('Build-Depends-Indep', package_relation_list), - ('Provides', package_relation_list), - ('Depends', package_relation_list), - ('Recommends', package_relation_list), - ('Suggests', package_relation_list), - ('Replaces', package_relation_list), - ('Conflicts', package_relation_list), - ('Description', package_description), + ('Build-Depends', PackageRelation), + ('Build-Depends-Indep', PackageRelation), + ('Provides', PackageRelation), + ('Pre-Depends', PackageRelation), + ('Depends', PackageRelation), + ('Recommends', PackageRelation), + ('Suggests', PackageRelation), + ('Replaces', PackageRelation), + ('Conflicts', PackageRelation), + ('Description', PackageDescription), )) def __setitem__(self, key, value): @@ -266,7 +321,7 @@ class package(dict): if not isinstance(value, cls): value = cls(value) except KeyError: pass - super(package, self).__setitem__(key, value) + super(Package, self).__setitem__(key, value) def iterkeys(self): keys = set(self.keys()) @@ -278,20 +333,10 @@ class package(dict): yield i def iteritems(self): - keys = set(self.keys()) - for i in self._fields.iterkeys(): - if self.has_key(i): - keys.remove(i) - yield (i, self[i]) - for i in keys: + for i in self.iterkeys(): yield (i, self[i]) def itervalues(self): - keys = set(self.keys()) - for i in self._fields.iterkeys(): - if self.has_key(i): - keys.remove(i) - yield self[i] - for i in keys: + for i in self.iterkeys(): yield self[i] diff --git a/debian/lib/python/debian_linux/gencontrol.py b/debian/lib/python/debian_linux/gencontrol.py new file mode 100644 index 000000000..90b009f83 --- /dev/null +++ b/debian/lib/python/debian_linux/gencontrol.py @@ -0,0 +1,312 @@ +from config import * +from debian import * +from utils import * + +class PackagesList(SortedDict): + def append(self, package): + self[package['Package']] = package + + def extend(self, packages): + for package in packages: + self[package['Package']] = package + +class Makefile(object): + def __init__(self): + self.rules = {} + self.add('.NOTPARALLEL') + + def add(self, name, deps = None, cmds = None): + if name in self.rules: + self.rules[name].add(deps, cmds) + else: + self.rules[name] = self.Rule(name, deps, cmds) + + def write(self, out): + r = self.rules.keys() + r.sort() + for i in r: + self.rules[i].write(out) + + class Rule(object): + def __init__(self, name, deps = None, cmds = None): + self.name = name + self.deps, self.cmds = set(), [] + self.add(deps, cmds) + + def add(self, deps = None, cmds = None): + if deps is not None: + self.deps.update(deps) + if cmds is not None: + self.cmds.append(cmds) + + def write(self, out): + deps_string = '' + if self.deps: + deps = list(self.deps) + deps.sort() + deps_string = ' ' + ' '.join(deps) + + if self.cmds: + if deps_string: + out.write('%s::%s\n' % (self.name, deps_string)) + for c in self.cmds: + out.write('%s::\n' % self.name) + for i in c: + out.write('\t%s\n' % i) + else: + out.write('%s:%s\n' % (self.name, deps_string)) + +class MakeFlags(dict): + def __repr__(self): + repr = super(flags, self).__repr__() + return "%s(%s)" % (self.__class__.__name__, repr) + + def __str__(self): + return ' '.join(["%s='%s'" % i for i in self.iteritems()]) + + def copy(self): + return self.__class__(super(MakeFlags, self).copy()) + +class Gencontrol(object): + makefile_targets = ('binary-arch', 'build', 'setup', 'source') + + def __init__(self, config, templates): + self.config, self.templates = config, templates + + def __call__(self): + packages = PackagesList() + makefile = Makefile() + + self.do_source(packages) + self.do_main(packages, makefile) + self.do_extra(packages, makefile) + + self.write_control(packages.itervalues()) + self.write_makefile(makefile) + + def do_source(self, packages): + source = self.templates["control.source"] + packages['source'] = self.process_package(source[0], self.vars) + + def do_main(self, packages, makefile): + config_entry = self.config['base',] + vars = self.vars.copy() + vars.update(config_entry) + + makeflags = MakeFlags() + extra = {} + + self.do_main_setup(vars, makeflags, extra) + self.do_main_packages(packages, extra) + self.do_main_makefile(makefile, makeflags, extra) + + for arch in iter(self.config['base',]['arches']): + self.do_arch(packages, makefile, arch, vars.copy(), makeflags.copy(), extra) + + def do_main_setup(self, vars, makeflags, extra): + makeflags.update({ + 'MAJOR': self.version.linux_major, + 'VERSION': self.version.linux_version, + 'UPSTREAMVERSION': self.version.linux_upstream, + 'ABINAME': self.abiname, + }) + + def do_main_makefile(self, makefile, makeflags, extra): + makefile.add('binary-indep', cmds = ["$(MAKE) -f debian/rules.real binary-indep %s" % makeflags]) + + def do_main_packages(self, packages, extra): + pass + + def do_extra(self, packages, makefile): + try: + templates_extra = self.templates["control.extra"] + except IOError: + return + + packages.extend(self.process_packages(templates_extra, {})) + extra_arches = {} + for package in templates_extra: + arches = package['Architecture'] + for arch in arches: + i = extra_arches.get(arch, []) + i.append(package) + extra_arches[arch] = i + archs = extra_arches.keys() + archs.sort() + for arch in archs: + cmds = [] + for i in extra_arches[arch]: + tmp = [] + if i.has_key('X-Version-Overwrite-Epoch'): + tmp.append("-v1:%s" % self.version['source']) + cmds.append("$(MAKE) -f debian/rules.real install-dummy DH_OPTIONS='-p%s' GENCONTROL_ARGS='%s'" % (i['Package'], ' '.join(tmp))) + makefile.add('binary-arch_%s' % arch ['binary-arch_%s_extra' % arch]) + makefile.add("binary-arch_%s_extra" % arch, cmds = cmds) + + def do_arch(self, packages, makefile, arch, vars, makeflags, extra): + config_base = self.config['base', arch] + vars.update(config_base) + vars['arch'] = arch + + makeflags['ARCH'] = arch + + self.do_arch_setup(vars, makeflags, arch, extra) + self.do_arch_makefile(makefile, arch, makeflags, extra) + self.do_arch_packages(packages, makefile, arch, vars, makeflags, extra) + self.do_arch_recurse(packages, makefile, arch, vars, makeflags, extra) + + def do_arch_setup(self, vars, makeflags, arch, extra): + pass + + def do_arch_makefile(self, makefile, arch, makeflags, extra): + for i in self.makefile_targets: + target1 = i + target2 = "%s_%s" % (i, arch) + makefile.add(target1, [target2]) + makefile.add(target2, ['%s_real' % target2]) + makefile.add('%s_real' % target2) + + def do_arch_packages(self, packages, makefile, arch, vars, makeflags, extra): + pass + + def do_arch_recurse(self, packages, makefile, arch, vars, makeflags, extra): + for featureset in self.config['base', arch]['featuresets']: + self.do_featureset(packages, makefile, arch, featureset, vars.copy(), makeflags.copy(), extra) + + def do_featureset(self, packages, makefile, arch, featureset, vars, makeflags, extra): + config_base = self.config.merge('base', arch, featureset) + vars.update(config_base) + + if not config_base.get('enabled', True): + return + + makeflags['FEATURESET'] = featureset + + vars['localversion'] = '' + if featureset != 'none': + vars['localversion'] = '-' + featureset + + self.do_featureset_setup(vars, makeflags, arch, featureset, extra) + self.do_featureset_makefile(makefile, arch, featureset, makeflags, extra) + self.do_featureset_packages(packages, makefile, arch, featureset, vars, makeflags, extra) + self.do_featureset_recurse(packages, makefile, arch, featureset, vars, makeflags, extra) + + def do_featureset_setup(self, vars, makeflags, arch, featureset, extra): + pass + + def do_featureset_makefile(self, makefile, arch, featureset, makeflags, extra): + for i in self.makefile_targets: + target1 = "%s_%s" % (i, arch) + target2 = "%s_%s_%s" % (i, arch, featureset) + makefile.add(target1, [target2]) + makefile.add(target2, ['%s_real' % target2]) + makefile.add('%s_real' % target2) + + def do_featureset_packages(self, packages, makefile, arch, featureset, vars, makeflags, extra): + pass + + def do_featureset_recurse(self, packages, makefile, arch, featureset, vars, makeflags, extra): + for flavour in self.config['base', arch, featureset]['flavours']: + self.do_flavour(packages, makefile, arch, featureset, flavour, vars.copy(), makeflags.copy(), extra) + + def do_flavour(self, packages, makefile, arch, featureset, flavour, vars, makeflags, extra): + config_base = self.config.merge('base', arch, featureset, flavour) + vars.update(config_base) + + if not vars.has_key('longclass'): + vars['longclass'] = vars['class'] + + makeflags['FLAVOUR'] = flavour + vars['localversion'] += '-' + flavour + + self.do_flavour_setup(vars, makeflags, arch, featureset, flavour, extra) + self.do_flavour_makefile(makefile, arch, featureset, flavour, makeflags, extra) + self.do_flavour_packages(packages, makefile, arch, featureset, flavour, vars, makeflags, extra) + + def do_flavour_setup(self, vars, makeflags, arch, featureset, flavour, extra): + for i in ( + ('kernel-arch', 'KERNEL_ARCH'), + ('localversion', 'LOCALVERSION'), + ): + if vars.has_key(i[0]): + makeflags[i[1]] = vars[i[0]] + + def do_flavour_makefile(self, makefile, arch, featureset, flavour, makeflags, extra): + for i in self.makefile_targets: + target1 = "%s_%s_%s" % (i, arch, featureset) + target2 = "%s_%s_%s_%s" % (i, arch, featureset, flavour) + makefile.add(target1, [target2]) + makefile.add(target2, ['%s_real' % target2]) + makefile.add('%s_real' % target2) + + def do_flavour_packages(self, packages, makefile, arch, featureset, flavour, vars, makeflags, extra): + pass + + def process_relation(self, key, e, in_e, vars): + import copy + dep = copy.deepcopy(in_e[key]) + for groups in dep: + for item in groups: + item.name = self.substitute(item.name, vars) + e[key] = dep + + def process_description(self, e, in_e, vars): + in_desc = in_e['Description'] + desc = in_desc.__class__() + desc.short = self.substitute(in_desc.short, vars) + for i in in_desc.long: + desc.append(self.substitute(i, vars)) + e['Description'] = desc + + def process_package(self, in_entry, vars): + e = Package() + for key, value in in_entry.iteritems(): + if isinstance(value, PackageRelation): + self.process_relation(key, e, in_entry, vars) + elif key == 'Description': + self.process_description(e, in_entry, vars) + elif key[:2] == 'X-': + pass + else: + e[key] = self.substitute(value, vars) + return e + + def process_packages(self, in_entries, vars): + entries = [] + for i in in_entries: + entries.append(self.process_package(i, vars)) + return entries + + def process_version_linux(self, version, abiname): + return { + 'upstreamversion': version.linux_upstream, + 'version': version.linux_version, + 'source_upstream': version.upstream, + 'major': version.linux_major, + 'abiname': abiname, + } + + def substitute(self, s, vars): + if isinstance(s, (list, tuple)): + for i in xrange(len(s)): + s[i] = self.substitute(s[i], vars) + return s + def subst(match): + return vars[match.group(1)] + return re.sub(r'@([-_a-z]+)@', subst, s) + + def write_control(self, list): + self.write_rfc822(file("debian/control", 'w'), list) + + def write_makefile(self, makefile): + f = file("debian/rules.gen", 'w') + makefile.write(f) + f.close() + + def write_rfc822(self, f, list): + for entry in list: + for key, value in entry.iteritems(): + f.write("%s: %s\n" % (key, value)) + f.write('\n') + + diff --git a/debian/lib/python/debian_linux/utils.py b/debian/lib/python/debian_linux/utils.py index 1519e4ebb..abe46b7b3 100644 --- a/debian/lib/python/debian_linux/utils.py +++ b/debian/lib/python/debian_linux/utils.py @@ -1,21 +1,21 @@ -import debian, re, textwrap +import debian, re, os, textwrap -class sorted_dict(dict): +class SortedDict(dict): __slots__ = '_list', def __init__(self, entries = None): - super(sorted_dict, self).__init__() + super(SortedDict, self).__init__() self._list = [] if entries is not None: for key, value in entries: self[key] = value def __delitem__(self, key): - super(sorted_dict, self).__delitem__(key) + super(SortedDict, self).__delitem__(key) self._list.remove(key) def __setitem__(self, key, value): - super(sorted_dict, self).__setitem__(key, value) + super(SortedDict, self).__setitem__(key, value) if key not in self._list: self._list.append(key) @@ -31,74 +31,38 @@ class sorted_dict(dict): for i in iter(self._list): yield self[i] -class field_list(list): - TYPE_WHITESPACE = object() - TYPE_COMMATA = object() - - def __init__(self, value = None, type = TYPE_WHITESPACE): - self.type = type - if isinstance(value, field_list): - self.type = value.type - self.extend(value) - elif isinstance(value, (list, tuple)): - self.extend(value) - else: - self._extend(value) - - def __str__(self): - if self.type is self.TYPE_WHITESPACE: - type = ' ' - elif self.type is self.TYPE_COMMATA: - type = ', ' - return type.join(self) - - def _extend(self, value): - if self.type is self.TYPE_WHITESPACE: - type = '\s' - elif self.type is self.TYPE_COMMATA: - type = ',' - if value is not None: - self.extend([j.strip() for j in re.split(type, value.strip())]) - - def extend(self, value): - if isinstance(value, str): - self._extend(value) - else: - super(field_list, self).extend(value) - -class field_list_commata(field_list): - def __init__(self, value = None): - super(field_list_commata, self).__init__(value, field_list.TYPE_COMMATA) - -class field_string(str): - def __str__(self): - return '\n '.join(self.split('\n')) - -class templates(dict): - def __init__(self, dir = None): - if dir is None: - self.dir = "debian/templates" - else: - self.dir = dir +class Templates(dict): + def __init__(self, dirs = ["debian/templates"]): + self.dirs = dirs def __getitem__(self, key): try: - return dict.__getitem__(self, key) + return super(Templates, self).__getitem__(key) except KeyError: pass - ret = self._read(key) - dict.__setitem__(self, key, ret) - return ret + value = self._read(key) + super(Templates, self).__setitem__(key, value) + return value def __setitem__(self, key, value): raise NotImplemented() - def _read(self, filename): + def _read(self, name): + prefix, id = name.split('.', 1) + + for dir in self.dirs: + filename = "%s/%s.in" % (dir, name) + if os.path.exists(filename): + f = file(filename) + if prefix == 'control': + return self._read_control(f) + return f.read() + raise KeyError(name) + + def _read_control(self, f): entries = [] - f = file("%s/%s.in" % (self.dir, filename)) - while True: - e = debian.package() + e = debian.Package() last = None lines = [] while True: @@ -129,7 +93,7 @@ class templates(dict): return entries -class wrap(textwrap.TextWrapper): +class TextWrapper(textwrap.TextWrapper): wordsep_re = re.compile( r'(\s+|' # any whitespace r'(?<=[\w\!\"\'\&\.\,\?])-{2,}(?=\w))') # em-dash diff --git a/debian/rules b/debian/rules index d3d868cda..d0282eb68 100755 --- a/debian/rules +++ b/debian/rules @@ -1,10 +1,12 @@ #!/usr/bin/make -f + SHELL := sh -e DEB_HOST_ARCH := $(shell dpkg-architecture -qDEB_HOST_ARCH) DEB_BUILD_ARCH := $(shell dpkg-architecture -qDEB_BUILD_ARCH) -srcver := $(shell dpkg-parsechangelog | awk '/^Version:/ {print $$2}') -VERSION := $(shell echo $(srcver) | sed -e 's,-[^-]*$$,,') -MAJOR := $(word 1,$(subst ., ,$(VERSION))).$(word 2,$(subst ., ,$(VERSION))) +SOURCE := $(shell dpkg-parsechangelog | sed -ne 's,^Source: *\(.*\)$$,\1,p') +VERSION_DEBIAN := $(shell dpkg-parsechangelog | sed -ne 's,^Version: *\(.*\)$$,\1,p') +VERSION := $(shell echo "$(VERSION_DEBIAN)" | sed -e 's,-[^-]*$$,,') +VERSION_DEBIAN_BINNMU := $(shell echo "$(VERSION_DEBIAN)" | sed -ne 's,.*\+b\(.*\)$$,\1,p') include debian/rules.defs @@ -17,21 +19,24 @@ $(STAMPS_DIR)/build-base: $(BUILD_DIR) $(STAMPS_DIR) $(BUILD_DIR) $(STAMPS_DIR): @[ -d $@ ] || mkdir $@ -orig: ../orig/linux-kbuild-$(MAJOR)-$(VERSION) - rsync --delete --exclude debian --exclude src --exclude .svn --link-dest=$^/ -av $^/ . +DIR_ORIG = ../orig/$(SOURCE)-$(VERSION) +TAR_ORIG_NAME = $(SOURCE)_$(VERSION).orig.tar.gz +TAR_ORIG = $(firstword $(wildcard ../$(TAR_ORIG_NAME)) $(wildcard ../orig/$(TAR_ORIG_NAME))) -../orig/linux-kbuild-$(MAJOR)-$(VERSION): - if [ -f "../linux-kbuild-$(MAJOR)_$(VERSION).orig.tar.gz" ]; then \ - mkdir -p ../orig; \ - tar -C ../orig -xzf ../linux-kbuild-$(MAJOR)_$(VERSION).orig.tar.gz; \ - else \ - echo "Can't find orig tarball." >&2; \ - exit 1; \ - fi +orig: $(DIR_ORIG) + rsync --delete --exclude debian --exclude .svk --exclude .svn --link-dest=$(DIR_ORIG)/ -a $(DIR_ORIG)/ . + +$(DIR_ORIG): +ifeq ($(TAR_ORIG),) + $(error Cannot find orig tarball $(TAR_ORIG_NAME)) +else + mkdir -p ../orig + tar -C ../orig -xzf $(TAR_ORIG) +endif maintainerclean: -rm debian/control debian/control.md5sum debian/rules.gen - -rm -rf COPYING scripts + -rm -rf COPYING include scripts clean: debian/control dh_testdir @@ -47,7 +52,7 @@ binary-arch: binary: binary-indep binary-arch -CONTROL_FILES = debian/changelog $(wildcard debian/templates/control.*) +CONTROL_FILES = debian/changelog $(wildcard debian/templates/control.*) debian/control debian/rules.gen: debian/bin/gencontrol.py $(CONTROL_FILES) if [ -f debian/control.md5sum ]; then \ if md5sum $^ | diff - debian/control.md5sum > /dev/null; then true; else \