summaryrefslogtreecommitdiffstats
path: root/debian/lib/python/debian_linux/gencontrol.py
diff options
context:
space:
mode:
Diffstat (limited to 'debian/lib/python/debian_linux/gencontrol.py')
-rw-r--r--debian/lib/python/debian_linux/gencontrol.py437
1 files changed, 437 insertions, 0 deletions
diff --git a/debian/lib/python/debian_linux/gencontrol.py b/debian/lib/python/debian_linux/gencontrol.py
new file mode 100644
index 000000000..388fc33f6
--- /dev/null
+++ b/debian/lib/python/debian_linux/gencontrol.py
@@ -0,0 +1,437 @@
+import codecs
+import os
+import re
+from collections import OrderedDict
+
+from .debian import Changelog, PackageArchitecture, PackageDescription, \
+ PackageRelation, Version
+
+
+class PackagesList(OrderedDict):
+ 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)
+ if deps is not None:
+ for i in deps:
+ if i not in self.rules:
+ self.rules[i] = self.Rule(i)
+
+ def write(self, out):
+ for i in sorted(self.rules.keys()):
+ 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 __str__(self):
+ return ' '.join("%s='%s'" % i for i in sorted(self.items()))
+
+ def copy(self):
+ return self.__class__(super(MakeFlags, self).copy())
+
+
+def iter_featuresets(config):
+ for featureset in config['base', ]['featuresets']:
+ if config.merge('base', None, featureset).get('enabled', True):
+ yield featureset
+
+
+def iter_arches(config):
+ return iter(config['base', ]['arches'])
+
+
+def iter_arch_featuresets(config, arch):
+ for featureset in config['base', arch].get('featuresets', []):
+ if config.merge('base', arch, featureset).get('enabled', True):
+ yield featureset
+
+
+def iter_flavours(config, arch, featureset):
+ return iter(config['base', arch, featureset]['flavours'])
+
+
+class Gencontrol(object):
+ makefile_targets = ('binary-arch', 'build-arch', 'setup')
+ makefile_targets_indep = ('binary-indep', 'build-indep', 'setup')
+
+ def __init__(self, config, templates, version=Version):
+ self.config, self.templates = config, templates
+ self.changelog = Changelog(version=version)
+ self.vars = {}
+
+ def __call__(self):
+ packages = PackagesList()
+ makefile = Makefile()
+
+ self.do_source(packages)
+ self.do_main(packages, makefile)
+ self.do_extra(packages, makefile)
+
+ self.merge_build_depends(packages)
+ self.write(packages, makefile)
+
+ def do_source(self, packages):
+ source = self.templates["control.source"][0]
+ if not source.get('Source'):
+ source['Source'] = self.changelog[0].source
+ packages['source'] = self.process_package(source, self.vars)
+
+ def do_main(self, packages, makefile):
+ vars = self.vars.copy()
+
+ makeflags = MakeFlags()
+ extra = {}
+
+ self.do_main_setup(vars, makeflags, extra)
+ self.do_main_makefile(makefile, makeflags, extra)
+ self.do_main_packages(packages, vars, makeflags, extra)
+ self.do_main_recurse(packages, makefile, vars, makeflags, extra)
+
+ def do_main_setup(self, vars, makeflags, extra):
+ pass
+
+ def do_main_makefile(self, makefile, makeflags, extra):
+ makefile.add('build-indep',
+ cmds=["$(MAKE) -f debian/rules.real build-indep %s" %
+ makeflags])
+ makefile.add('binary-indep',
+ cmds=["$(MAKE) -f debian/rules.real binary-indep %s" %
+ makeflags])
+
+ def do_main_packages(self, packages, vars, makeflags, extra):
+ pass
+
+ def do_main_recurse(self, packages, makefile, vars, makeflags, extra):
+ for featureset in iter_featuresets(self.config):
+ self.do_indep_featureset(packages, makefile, featureset,
+ vars.copy(), makeflags.copy(), extra)
+ for arch in iter_arches(self.config):
+ self.do_arch(packages, makefile, arch, vars.copy(),
+ makeflags.copy(), extra)
+
+ def do_extra(self, packages, makefile):
+ templates_extra = self.templates.get("control.extra", None)
+ if templates_extra is None:
+ return
+
+ packages_extra = self.process_packages(templates_extra, self.vars)
+ packages.extend(packages_extra)
+ extra_arches = {}
+ for package in packages_extra:
+ arches = package['Architecture']
+ for arch in arches:
+ i = extra_arches.get(arch, [])
+ i.append(package)
+ extra_arches[arch] = i
+ for arch in sorted(extra_arches.keys()):
+ cmds = []
+ for i in extra_arches[arch]:
+ cmds.append("$(MAKE) -f debian/rules.real install-dummy "
+ "ARCH='%s' DH_OPTIONS='-p%s'" %
+ (arch, i['Package']))
+ makefile.add('binary-arch_%s' % arch,
+ ['binary-arch_%s_extra' % arch])
+ makefile.add("binary-arch_%s_extra" % arch, cmds=cmds)
+
+ def do_indep_featureset(self, packages, makefile, featureset, vars,
+ makeflags, extra):
+ vars['localversion'] = ''
+ if featureset != 'none':
+ vars['localversion'] = '-' + featureset
+
+ self.do_indep_featureset_setup(vars, makeflags, featureset, extra)
+ self.do_indep_featureset_makefile(makefile, featureset, makeflags,
+ extra)
+ self.do_indep_featureset_packages(packages, makefile, featureset,
+ vars, makeflags, extra)
+
+ def do_indep_featureset_setup(self, vars, makeflags, featureset, extra):
+ pass
+
+ def do_indep_featureset_makefile(self, makefile, featureset, makeflags,
+ extra):
+ makeflags['FEATURESET'] = featureset
+
+ for i in self.makefile_targets_indep:
+ target1 = i
+ target2 = '_'.join((target1, featureset))
+ target3 = '_'.join((target2, 'real'))
+ makefile.add(target1, [target2])
+ makefile.add(target2, [target3])
+
+ def do_indep_featureset_packages(self, packages, makefile, featureset,
+ vars, makeflags, extra):
+ pass
+
+ def do_arch(self, packages, makefile, arch, vars, makeflags, extra):
+ vars['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):
+ makeflags['ARCH'] = arch
+
+ for i in self.makefile_targets:
+ target1 = i
+ target2 = '_'.join((target1, arch))
+ target3 = '_'.join((target2, 'real'))
+ makefile.add(target1, [target2])
+ makefile.add(target2, [target3])
+
+ 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 iter_arch_featuresets(self.config, arch):
+ self.do_featureset(packages, makefile, arch, featureset,
+ vars.copy(), makeflags.copy(), extra)
+
+ def do_featureset(self, packages, makefile, arch, featureset, vars,
+ makeflags, extra):
+ 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):
+ makeflags['FEATURESET'] = featureset
+
+ for i in self.makefile_targets:
+ target1 = '_'.join((i, arch))
+ target2 = '_'.join((target1, featureset))
+ target3 = '_'.join((target2, 'real'))
+ makefile.add(target1, [target2])
+ makefile.add(target2, [target3])
+
+ 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 iter_flavours(self.config, arch, featureset):
+ 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):
+ 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 i[0] in vars:
+ makeflags[i[1]] = vars[i[0]]
+
+ def do_flavour_makefile(self, makefile, arch, featureset, flavour,
+ makeflags, extra):
+ makeflags['FLAVOUR'] = flavour
+
+ for i in self.makefile_targets:
+ target1 = '_'.join((i, arch, featureset))
+ target2 = '_'.join((target1, flavour))
+ target3 = '_'.join((target2, 'real'))
+ makefile.add(target1, [target2])
+ makefile.add(target2, [target3])
+
+ def do_flavour_packages(self, packages, makefile, arch, featureset,
+ flavour, vars, makeflags, extra):
+ pass
+
+ def process_relation(self, dep, vars):
+ import copy
+ dep = copy.deepcopy(dep)
+ for groups in dep:
+ for item in groups:
+ item.name = self.substitute(item.name, vars)
+ if item.version:
+ item.version = self.substitute(item.version, vars)
+ return dep
+
+ def process_description(self, in_desc, vars):
+ desc = in_desc.__class__()
+ desc.short = self.substitute(in_desc.short, vars)
+ for i in in_desc.long:
+ desc.append(self.substitute(i, vars))
+ return desc
+
+ def process_package(self, in_entry, vars={}):
+ entry = in_entry.__class__()
+ for key, value in in_entry.items():
+ if isinstance(value, PackageRelation):
+ value = self.process_relation(value, vars)
+ elif isinstance(value, PackageDescription):
+ value = self.process_description(value, vars)
+ else:
+ value = self.substitute(value, vars)
+ entry[key] = value
+ return entry
+
+ def process_packages(self, entries, vars):
+ return [self.process_package(i, vars) for i in entries]
+
+ def substitute(self, s, vars):
+ if isinstance(s, (list, tuple)):
+ return [self.substitute(i, vars) for i in s]
+
+ def subst(match):
+ return vars[match.group(1)]
+
+ return re.sub(r'@([-_a-z0-9]+)@', subst, str(s))
+
+ # Substitute kernel version etc. into maintainer scripts,
+ # bug presubj message and lintian overrides
+ def substitute_debhelper_config(self, prefix, vars, package_name,
+ output_dir='debian'):
+ for id in ['bug-presubj', 'lintian-overrides', 'maintscript',
+ 'postinst', 'postrm', 'preinst', 'prerm']:
+ name = '%s.%s' % (prefix, id)
+ try:
+ template = self.templates[name]
+ except KeyError:
+ continue
+ else:
+ target = '%s/%s.%s' % (output_dir, package_name, id)
+ with open(target, 'w') as f:
+ f.write(self.substitute(template, vars))
+ os.chmod(f.fileno(),
+ self.templates.get_mode(name) & 0o777)
+
+ def merge_build_depends(self, packages):
+ # Merge Build-Depends pseudo-fields from binary packages into the
+ # source package
+ source = packages["source"]
+ arch_all = PackageArchitecture("all")
+ for name, package in packages.items():
+ if name == "source":
+ continue
+ dep = package.get("Build-Depends")
+ if not dep:
+ continue
+ del package["Build-Depends"]
+ for group in dep:
+ for item in group:
+ if package["Architecture"] != arch_all and not item.arches:
+ item.arches = sorted(package["Architecture"])
+ if package.get("Build-Profiles") and not item.restrictions:
+ profiles = package["Build-Profiles"]
+ assert profiles[0] == "<" and profiles[-1] == ">"
+ item.restrictions = re.split(r"\s+", profiles[1:-1])
+ if package["Architecture"] == arch_all:
+ dep_type = "Build-Depends-Indep"
+ else:
+ dep_type = "Build-Depends-Arch"
+ if dep_type not in source:
+ source[dep_type] = PackageRelation()
+ source[dep_type].extend(dep)
+
+ def write(self, packages, makefile):
+ self.write_control(packages.values())
+ self.write_makefile(makefile)
+
+ def write_control(self, list, name='debian/control'):
+ self.write_rfc822(codecs.open(name, 'w', 'utf-8'), list)
+
+ def write_makefile(self, makefile, name='debian/rules.gen'):
+ f = open(name, 'w')
+ makefile.write(f)
+ f.close()
+
+ def write_rfc822(self, f, list):
+ for entry in list:
+ for key, value in entry.items():
+ f.write(u"%s: %s\n" % (key, value))
+ f.write('\n')
+
+
+def merge_packages(packages, new, arch):
+ for new_package in new:
+ name = new_package['Package']
+ if name in packages:
+ package = packages.get(name)
+ package['Architecture'].add(arch)
+
+ for field in ('Depends', 'Provides', 'Suggests', 'Recommends',
+ 'Conflicts'):
+ if field in new_package:
+ if field in package:
+ v = package[field]
+ v.extend(new_package[field])
+ else:
+ package[field] = new_package[field]
+
+ else:
+ new_package['Architecture'] = arch
+ packages.append(new_package)