Beispiel #1
0
class Gencontrol(Base):
    config_schema = {
        'abi': {
            'ignore-changes': config.SchemaItemList(),
        },
        'build': {
            'debug-info': config.SchemaItemBoolean(),
        },
        'description': {
            'parts': config.SchemaItemList(),
        },
        'image': {
            'bootloaders': config.SchemaItemList(),
            'configs': config.SchemaItemList(),
            'initramfs-generators': config.SchemaItemList(),
            'check-size': config.SchemaItemInteger(),
            'check-size-with-dtb': config.SchemaItemBoolean(),
        },
        'relations': {},
    }

    def __init__(self,
                 config_dirs=["debian/config"],
                 template_dirs=["debian/templates"]):
        super(Gencontrol, self).__init__(
            config.ConfigCoreHierarchy(self.config_schema, config_dirs),
            Templates(template_dirs), VersionLinux)
        self.process_changelog()
        self.config_dirs = config_dirs

    def _setup_makeflags(self, names, makeflags, data):
        for src, dst, optional in names:
            if src in data or not optional:
                makeflags[dst] = data[src]

    def _substitute_file(self, template, vars, target, append=False):
        with codecs.open(target, 'a' if append else 'w', 'utf-8') as f:
            f.write(self.substitute(self.templates[template], vars))

    def do_main_setup(self, vars, makeflags, extra):
        super(Gencontrol, self).do_main_setup(vars, makeflags, extra)
        makeflags.update({
            'VERSION': self.version.linux_version,
            'UPSTREAMVERSION': self.version.linux_upstream,
            'ABINAME': self.abiname_version + self.abiname_part,
            'SOURCEVERSION': self.version.complete,
        })
        """
        # Prepare to generate debian/tests/control
        self.tests_control = None
        """

    def do_main_makefile(self, makefile, makeflags, extra):
        fs_enabled = [
            featureset for featureset in self.config['base', ]['featuresets']
            if self.config.merge('base', None, featureset).get(
                'enabled', True)
        ]
        for featureset in fs_enabled:
            makeflags_featureset = makeflags.copy()
            makeflags_featureset['FEATURESET'] = featureset
            cmds_source = [
                "$(MAKE) -f debian/rules.real source-featureset %s" %
                makeflags_featureset
            ]
            makefile.add('source_%s_real' % featureset, cmds=cmds_source)
            makefile.add('source_%s' % featureset,
                         ['source_%s_real' % featureset])
            makefile.add('source', ['source_%s' % featureset])

        triplet_enabled = []
        for arch in iter(self.config['base', ]['arches']):
            for featureset in self.config['base', arch].get('featuresets', ()):
                if self.config.merge('base', None,
                                     featureset).get('enabled', True):
                    for flavour in self.config['base', arch,
                                               featureset]['flavours']:
                        triplet_enabled.append('%s_%s_%s' %
                                               (arch, featureset, flavour))

        makeflags = makeflags.copy()
        makeflags['ALL_FEATURESETS'] = ' '.join(fs_enabled)
        makeflags['ALL_TRIPLETS'] = ' '.join(triplet_enabled)
        super(Gencontrol, self).do_main_makefile(makefile, makeflags, extra)

        # linux-source-$UPSTREAMVERSION will contain all kconfig files
        makefile.add('binary-indep', deps=['setup'])

    def do_main_packages(self, packages, vars, makeflags, extra):
        packages.extend(
            self.process_packages(self.templates["control.main"], self.vars))

    arch_makeflags = (('kernel-arch', 'KERNEL_ARCH', False), )

    def do_arch_setup(self, vars, makeflags, arch, extra):
        config_base = self.config.merge('base', arch)

        self._setup_makeflags(self.arch_makeflags, makeflags, config_base)

    def do_arch_packages(self, packages, makefile, arch, vars, makeflags,
                         extra):
        # Some userland architectures require kernels from another
        # (Debian) architecture, e.g. x32/amd64.
        foreign_kernel = not self.config['base', arch].get('featuresets')

        if self.version.linux_modifier is None:
            try:
                abiname_part = '-%s' % self.config['abi', arch]['abiname']
            except KeyError:
                abiname_part = self.abiname_part
            makeflags['ABINAME'] = vars['abiname'] = \
                self.abiname_version + abiname_part
        """
        if foreign_kernel:
            packages_headers_arch = []
            makeflags['FOREIGN_KERNEL'] = True
        else:
            headers_arch = self.templates["control.headers.arch"]
            packages_headers_arch = self.process_packages(headers_arch, vars)

        libc_dev = self.templates["control.libc-dev"]
        packages_headers_arch[0:0] = self.process_packages(libc_dev, {})

        packages_headers_arch[-1]['Depends'].extend(PackageRelation())
        extra['headers_arch_depends'] = packages_headers_arch[-1]['Depends']

        merge_packages(packages, packages_headers_arch, arch)

        cmds_binary_arch = ["$(MAKE) -f debian/rules.real binary-arch-arch %s" % makeflags]
        makefile.add('binary-arch_%s_real' % arch, cmds=cmds_binary_arch)

        # Shortcut to aid architecture bootstrapping
        makefile.add('binary-libc-dev_%s' % arch,
                     ['source_none_real'],
                     ["$(MAKE) -f debian/rules.real install-libc-dev_%s %s" %
                      (arch, makeflags)])

        if os.getenv('DEBIAN_KERNEL_DISABLE_INSTALLER'):
            if self.changelog[0].distribution == 'UNRELEASED':
                import warnings
                warnings.warn('Disable installer modules on request (DEBIAN_KERNEL_DISABLE_INSTALLER set)')
            else:
                raise RuntimeError('Unable to disable installer modules in release build (DEBIAN_KERNEL_DISABLE_INSTALLER set)')
        else:
            # Add udebs using kernel-wedge
            installer_def_dir = 'debian/installer'
            installer_arch_dir = os.path.join(installer_def_dir, arch)
            if os.path.isdir(installer_arch_dir):
                kw_env = os.environ.copy()
                kw_env['KW_DEFCONFIG_DIR'] = installer_def_dir
                kw_env['KW_CONFIG_DIR'] = installer_arch_dir
                kw_proc = subprocess.Popen(
                    ['kernel-wedge', 'gen-control', vars['abiname']],
                    stdout=subprocess.PIPE,
                    env=kw_env)
                if not isinstance(kw_proc.stdout, io.IOBase):
                    udeb_packages = read_control(io.open(kw_proc.stdout.fileno(), encoding='utf-8', closefd=False))
                else:
                    udeb_packages = read_control(io.TextIOWrapper(kw_proc.stdout, 'utf-8'))
                kw_proc.wait()
                if kw_proc.returncode != 0:
                    raise RuntimeError('kernel-wedge exited with code %d' %
                                       kw_proc.returncode)

                merge_packages(packages, udeb_packages, arch)

                # These packages must be built after the per-flavour/
                # per-featureset packages.  Also, this won't work
                # correctly with an empty package list.
                if udeb_packages:
                    makefile.add(
                        'binary-arch_%s' % arch,
                        cmds=["$(MAKE) -f debian/rules.real install-udeb_%s %s "
                              "PACKAGE_NAMES='%s'" %
                              (arch, makeflags,
                               ' '.join(p['Package'] for p in udeb_packages))])
        """

    def do_featureset_setup(self, vars, makeflags, arch, featureset, extra):
        config_base = self.config.merge('base', arch, featureset)
        makeflags['LOCALVERSION_HEADERS'] = vars[
            'localversion_headers'] = vars['localversion']

    def do_featureset_packages(self, packages, makefile, arch, featureset,
                               vars, makeflags, extra):
        """
        headers_featureset = self.templates["control.headers.featureset"]
        package_headers = self.process_package(headers_featureset[0], vars)

        merge_packages(packages, (package_headers,), arch)

        cmds_binary_arch = ["$(MAKE) -f debian/rules.real binary-arch-featureset %s" % makeflags]
        makefile.add('binary-arch_%s_%s_real' % (arch, featureset), cmds=cmds_binary_arch)
        """

    flavour_makeflags_base = (
        ('compiler', 'COMPILER', False),
        ('kernel-arch', 'KERNEL_ARCH', False),
        ('cflags', 'CFLAGS_KERNEL', True),
        ('override-host-type', 'OVERRIDE_HOST_TYPE', True),
    )

    flavour_makeflags_build = (('image-file', 'IMAGE_FILE', True), )

    flavour_makeflags_image = (('install-stem', 'IMAGE_INSTALL_STEM', True), )

    flavour_makeflags_other = (
        ('localversion', 'LOCALVERSION', False),
        ('localversion-image', 'LOCALVERSION_IMAGE', True),
    )

    def do_flavour_setup(self, vars, makeflags, arch, featureset, flavour,
                         extra):
        config_base = self.config.merge('base', arch, featureset, flavour)
        config_build = self.config.merge('build', arch, featureset, flavour)
        config_description = self.config.merge('description', arch, featureset,
                                               flavour)
        config_image = self.config.merge('image', arch, featureset, flavour)

        vars['class'] = config_description['hardware']
        vars['longclass'] = config_description.get(
            'hardware-long') or vars['class']

        vars['localversion-image'] = vars['localversion']
        override_localversion = config_image.get('override-localversion', None)
        if override_localversion is not None:
            vars['localversion-image'] = vars[
                'localversion_headers'] + '-' + override_localversion
        vars['image-stem'] = config_image.get('install-stem')

        self._setup_makeflags(self.flavour_makeflags_base, makeflags,
                              config_base)
        self._setup_makeflags(self.flavour_makeflags_build, makeflags,
                              config_build)
        self._setup_makeflags(self.flavour_makeflags_image, makeflags,
                              config_image)
        self._setup_makeflags(self.flavour_makeflags_other, makeflags, vars)

    def do_flavour_packages(self, packages, makefile, arch, featureset,
                            flavour, vars, makeflags, extra):
        headers = self.templates["control.headers"]

        config_entry_base = self.config.merge('base', arch, featureset,
                                              flavour)
        config_entry_build = self.config.merge('build', arch, featureset,
                                               flavour)
        config_entry_description = self.config.merge('description', arch,
                                                     featureset, flavour)
        config_entry_image = self.config.merge('image', arch, featureset,
                                               flavour)
        config_entry_relations = self.config.merge('relations', arch,
                                                   featureset, flavour)

        compiler = config_entry_base.get('compiler', 'gcc')

        relations_compiler_headers = PackageRelation(
            config_entry_relations.get('headers%' + compiler)
            or config_entry_relations.get(compiler))

        relations_compiler_build_dep = PackageRelation(
            config_entry_relations[compiler])
        for group in relations_compiler_build_dep:
            for item in group:
                item.arches = [arch]
        packages['source']['Build-Depends'].extend(
            relations_compiler_build_dep)

        image_fields = {'Description': PackageDescription()}
        for field in 'Depends', 'Provides', 'Suggests', 'Recommends', 'Conflicts', 'Breaks':
            image_fields[field] = PackageRelation(config_entry_image.get(
                field.lower(), None),
                                                  override_arches=(arch, ))

        generators = config_entry_image['initramfs-generators']
        l = PackageRelationGroup()
        for i in generators:
            i = config_entry_relations.get(i, i)
            l.append(i)
            a = PackageRelationEntry(i)
            if a.operator is not None:
                a.operator = -a.operator
                image_fields['Breaks'].append(PackageRelationGroup([a]))
        for item in l:
            item.arches = [arch]
        image_fields['Depends'].append(l)

        bootloaders = config_entry_image.get('bootloaders')
        if bootloaders:
            l = PackageRelationGroup()
            for i in bootloaders:
                i = config_entry_relations.get(i, i)
                l.append(i)
                a = PackageRelationEntry(i)
                if a.operator is not None:
                    a.operator = -a.operator
                    image_fields['Breaks'].append(PackageRelationGroup([a]))
            for item in l:
                item.arches = [arch]
            image_fields['Suggests'].append(l)

        desc_parts = self.config.get_merge('description', arch, featureset,
                                           flavour, 'parts')
        if desc_parts:
            # XXX: Workaround, we need to support multiple entries of the same name
            parts = list(set(desc_parts))
            parts.sort()
            desc = image_fields['Description']
            for part in parts:
                desc.append(config_entry_description['part-long-' + part])
                desc.append_short(
                    config_entry_description.get('part-short-' + part, ''))

        packages_dummy = []
        packages_own = []

        image = self.templates["control.image"]

        vars.setdefault('desc', None)

        image_main = self.process_real_image(image[0], image_fields, vars)
        packages_own.append(image_main)
        packages_own.extend(self.process_packages(image[1:], vars))

        package_headers = self.process_package(headers[0], vars)
        package_headers['Depends'].extend(relations_compiler_headers)
        packages_own.append(package_headers)
        """
        extra['headers_arch_depends'].append('%s (= ${binary:Version})' % packages_own[-1]['Package'])
        """

        build_debug = config_entry_build.get('debug-info')

        if os.getenv('DEBIAN_KERNEL_DISABLE_DEBUG'):
            if self.changelog[0].distribution == 'UNRELEASED':
                import warnings
                warnings.warn(
                    'Disable debug infos on request (DEBIAN_KERNEL_DISABLE_DEBUG set)'
                )
                build_debug = False
            else:
                raise RuntimeError(
                    'Unable to disable debug infos in release build (DEBIAN_KERNEL_DISABLE_DEBUG set)'
                )

        if build_debug:
            makeflags['DEBUG'] = True
            packages_own.extend(
                self.process_packages(self.templates['control.image-dbg'],
                                      vars))

        merge_packages(packages, packages_own + packages_dummy, arch)
        """
        tests_control = self.process_package(
            self.templates['tests-control.main'][0], vars)
        tests_control['Depends'].append(
            PackageRelationGroup(image_main['Package'],
                                 override_arches=(arch,)))
        if self.tests_control:
            self.tests_control['Depends'].extend(tests_control['Depends'])
        else:
            self.tests_control = tests_control
        """
        def get_config(*entry_name):
            entry_real = ('image', ) + entry_name
            entry = self.config.get(entry_real, None)
            if entry is None:
                return None
            return entry.get('configs', None)

        def check_config_default(fail, f):
            for d in self.config_dirs[::-1]:
                f1 = d + '/' + f
                if os.path.exists(f1):
                    return [f1]
            if fail:
                raise RuntimeError("%s unavailable" % f)
            return []

        def check_config_files(files):
            ret = []
            for f in files:
                for d in self.config_dirs[::-1]:
                    f1 = d + '/' + f
                    if os.path.exists(f1):
                        ret.append(f1)
                        break
                else:
                    raise RuntimeError("%s unavailable" % f)
            return ret

        def check_config(default, fail, *entry_name):
            configs = get_config(*entry_name)
            if configs is None:
                return check_config_default(fail, default)
            return check_config_files(configs)

        kconfig = check_config('config', True)
        kconfig.extend(
            check_config(
                "kernelarch-%s/config" % config_entry_base['kernel-arch'],
                False))
        kconfig.extend(check_config("%s/config" % arch, True, arch))
        kconfig.extend(
            check_config("%s/config.%s" % (arch, flavour), False, arch, None,
                         flavour))
        kconfig.extend(
            check_config("featureset-%s/config" % featureset, False, None,
                         featureset))
        kconfig.extend(
            check_config("%s/%s/config" % (arch, featureset), False, arch,
                         featureset))
        kconfig.extend(
            check_config("%s/%s/config.%s" % (arch, featureset, flavour),
                         False, arch, featureset, flavour))
        makeflags['KCONFIG'] = ' '.join(kconfig)
        if build_debug:
            makeflags['KCONFIG_OPTIONS'] = '-o DEBUG_INFO=y'

        cmds_binary_arch = [
            "$(MAKE) -f debian/rules.real binary-arch-flavour %s" % makeflags
        ]
        if packages_dummy:
            cmds_binary_arch.append(
                "$(MAKE) -f debian/rules.real install-dummy DH_OPTIONS='%s' %s"
                % (' '.join("-p%s" % i['Package']
                            for i in packages_dummy), makeflags))
        cmds_build = [
            "$(MAKE) -f debian/rules.real build-arch-flavour %s" % makeflags
        ]
        cmds_setup = [
            "$(MAKE) -f debian/rules.real setup-arch-flavour %s" % makeflags
        ]
        makefile.add('binary-arch_%s_%s_%s_real' % (arch, featureset, flavour),
                     cmds=cmds_binary_arch)
        makefile.add('build-arch_%s_%s_%s_real' % (arch, featureset, flavour),
                     cmds=cmds_build)
        makefile.add('setup_%s_%s_%s_real' % (arch, featureset, flavour),
                     cmds=cmds_setup)

        # Substitute kernel version etc. into maintainer scripts,
        # translations and lintian overrides
        self._substitute_file(
            'headers.postinst', vars, 'debian/linux-headers-%s%s.postinst' %
            (vars['abiname'], vars['localversion']))
        for name in ['postinst', 'postrm', 'preinst', 'prerm']:
            self._substitute_file(
                'image.%s' % name, vars, 'debian/linux-image-%s%s.%s' %
                (vars['abiname'], vars['localversion'], name))
        if build_debug:
            self._substitute_file(
                'image-dbg.lintian-override', vars,
                'debian/linux-image-%s%s-dbgsym.lintian-overrides' %
                (vars['abiname'], vars['localversion']))

    def process_changelog(self):
        act_upstream = self.changelog[0].version.upstream
        versions = []
        for i in self.changelog:
            if i.version.upstream != act_upstream:
                break
            versions.append(i.version)
        self.versions = versions
        version = self.version = self.changelog[0].version
        if self.version.linux_modifier is not None:
            self.abiname_part = ''
        else:
            self.abiname_part = '-%s' % self.config['abi', ]['abiname']
        # We need to keep at least three version components to avoid
        # userland breakage (e.g. #742226, #745984).
        self.abiname_version = re.sub('^(\d+\.\d+)(?=-|$)', r'\1.0',
                                      self.version.linux_upstream)
        self.vars = {
            'upstreamversion': self.version.linux_upstream,
            'version': self.version.linux_version,
            'source_upstream': self.version.upstream,
            'source_package': self.changelog[0].source,
            'abiname': self.abiname_version + self.abiname_part,
        }
        self.config['version', ] = {
            'source': self.version.complete,
            'upstream': self.version.linux_upstream,
            'abiname_base': self.abiname_version,
            'abiname': (self.abiname_version + self.abiname_part)
        }

        distribution = self.changelog[0].distribution
        if distribution in ('unstable', ):
            if (version.linux_revision_experimental
                    or version.linux_revision_backports
                    or version.linux_revision_other):
                raise RuntimeError("Can't upload to %s with a version of %s" %
                                   (distribution, version))
        if distribution in ('experimental', ):
            if not version.linux_revision_experimental:
                raise RuntimeError("Can't upload to %s with a version of %s" %
                                   (distribution, version))
        if distribution.endswith('-security') or distribution.endswith('-lts'):
            if (not version.linux_revision_security
                    or version.linux_revision_backports):
                raise RuntimeError("Can't upload to %s with a version of %s" %
                                   (distribution, version))
        if distribution.endswith('-backports'):
            if not version.linux_revision_backports:
                raise RuntimeError("Can't upload to %s with a version of %s" %
                                   (distribution, version))

    def process_real_image(self, entry, fields, vars):
        entry = self.process_package(entry, vars)
        for key, value in fields.items():
            if key in entry:
                real = entry[key]
                real.extend(value)
            elif value:
                entry[key] = value
        return entry

    def write(self, packages, makefile):
        self.write_config()
        super(Gencontrol, self).write(packages, makefile)
        """
        self.write_tests_control()
        """

    def write_config(self):
        f = open("debian/config.defines.dump", 'wb')
        self.config.dump(f)
        f.close()

    def write_tests_control(self):
        self.write_rfc822(codecs.open("debian/tests/control", 'w', 'utf-8'),
                          [self.tests_control])
Beispiel #2
0
class Gencontrol(Base):
    config_schema = {
        'abi': {
            'ignore-changes': config.SchemaItemList(),
        },
        'build': {
            'debug-info': config.SchemaItemBoolean(),
            'modules': config.SchemaItemBoolean(),
        },
        'description': {
            'parts': config.SchemaItemList(),
        },
        'image': {
            'bootloaders': config.SchemaItemList(),
            'configs': config.SchemaItemList(),
            'initramfs': config.SchemaItemBoolean(),
            'initramfs-generators': config.SchemaItemList(),
        },
        'relations': {
        },
        'xen': {
            'flavours': config.SchemaItemList(),
            'versions': config.SchemaItemList(),
        }
    }

    def __init__(self, config_dirs=["debian/config"], template_dirs=["debian/templates"]):
        super(Gencontrol, self).__init__(config.ConfigCoreHierarchy(self.config_schema, config_dirs), Templates(template_dirs), VersionLinux)
        self.process_changelog()
        self.config_dirs = config_dirs

    def _setup_makeflags(self, names, makeflags, data):
        for src, dst, optional in names:
            if src in data or not optional:
                makeflags[dst] = data[src]

    def do_main_setup(self, vars, makeflags, extra):
        super(Gencontrol, self).do_main_setup(vars, makeflags, extra)
        makeflags.update({
            'VERSION': self.version.linux_version,
            'UPSTREAMVERSION': self.version.linux_upstream,
            'ABINAME': self.abiname,
            'ABINAME_PART': self.abiname_part,
            'SOURCEVERSION': self.version.complete,
        })

    def do_main_makefile(self, makefile, makeflags, extra):
        fs_enabled = [featureset
                      for featureset in self.config['base', ]['featuresets']
                      if self.config.merge('base', None, featureset).get('enabled', True)]
        for featureset in fs_enabled:
            makeflags_featureset = makeflags.copy()
            makeflags_featureset['FEATURESET'] = featureset
            cmds_source = ["$(MAKE) -f debian/rules.real source-featureset %s"
                           % makeflags_featureset]
            makefile.add('source_%s_real' % featureset, cmds=cmds_source)
            makefile.add('source_%s' % featureset,
                         ['source_%s_real' % featureset])
            makefile.add('source', ['source_%s' % featureset])

        makeflags = makeflags.copy()
        makeflags['ALL_FEATURESETS'] = ' '.join(fs_enabled)
        super(Gencontrol, self).do_main_makefile(makefile, makeflags, extra)

    def do_main_packages(self, packages, vars, makeflags, extra):
        packages.extend(self.process_packages(self.templates["control.main"], self.vars))

    arch_makeflags = (
        ('kernel-arch', 'KERNEL_ARCH', False),
    )

    def do_arch_setup(self, vars, makeflags, arch, extra):
        config_base = self.config.merge('base', arch)
        self._setup_makeflags(self.arch_makeflags, makeflags, config_base)

    def do_arch_packages(self, packages, makefile, arch, vars, makeflags, extra):
        # Some userland architectures require kernels from another
        # (Debian) architecture, e.g. x32/amd64.
        foreign_kernel = not self.config['base', arch].get('featuresets')

        if self.version.linux_modifier is None:
            try:
                vars['abiname'] = '-%s' % self.config['abi', arch]['abiname']
            except KeyError:
                vars['abiname'] = self.abiname
            makeflags['ABINAME'] = vars['abiname']

        if foreign_kernel:
            packages_headers_arch = []
            makeflags['FOREIGN_KERNEL'] = True
        else:
            headers_arch = self.templates["control.headers.arch"]
            packages_headers_arch = self.process_packages(headers_arch, vars)

        libc_dev = self.templates["control.libc-dev"]
        packages_headers_arch[0:0] = self.process_packages(libc_dev, {})

        packages_headers_arch[-1]['Depends'].extend(PackageRelation())
        extra['headers_arch_depends'] = packages_headers_arch[-1]['Depends']

        self.merge_packages(packages, packages_headers_arch, arch)

        cmds_binary_arch = ["$(MAKE) -f debian/rules.real binary-arch-arch %s" % makeflags]
        makefile.add('binary-arch_%s_real' % arch, cmds=cmds_binary_arch)

        # Shortcut to aid architecture bootstrapping
        makefile.add('binary-libc-dev_%s' % arch,
                     ['source_none_real'],
                     ["$(MAKE) -f debian/rules.real install-libc-dev_%s %s" %
                      (arch, makeflags)])

        if os.getenv('DEBIAN_KERNEL_DISABLE_INSTALLER'):
            if self.changelog[0].distribution == 'UNRELEASED':
                import warnings
                warnings.warn(u'Disable installer modules on request (DEBIAN_KERNEL_DISABLE_INSTALLER set)')
            else:
                raise RuntimeError(u'Unable to disable installer modules in release build (DEBIAN_KERNEL_DISABLE_INSTALLER set)')
        else:
            # Add udebs using kernel-wedge
            installer_def_dir = 'debian/installer'
            installer_arch_dir = os.path.join(installer_def_dir, arch)
            if os.path.isdir(installer_arch_dir):
                kw_env = os.environ.copy()
                kw_env['KW_DEFCONFIG_DIR'] = installer_def_dir
                kw_env['KW_CONFIG_DIR'] = installer_arch_dir
                kw_proc = subprocess.Popen(
                    ['kernel-wedge', 'gen-control',
                     self.abiname],
                    stdout=subprocess.PIPE,
                    env=kw_env)
                udeb_packages = read_control(kw_proc.stdout)
                kw_proc.wait()
                if kw_proc.returncode != 0:
                    raise RuntimeError('kernel-wedge exited with code %d' %
                                       kw_proc.returncode)

                self.merge_packages(packages, udeb_packages, arch)

                # These packages must be built after the per-flavour/
                # per-featureset packages.
                makefile.add(
                    'binary-arch_%s' % arch,
                    cmds=["$(MAKE) -f debian/rules.real install-udeb_%s %s "
                            "PACKAGE_NAMES='%s'" %
                            (arch, makeflags,
                             ' '.join(p['Package'] for p in udeb_packages))])

    def do_featureset_setup(self, vars, makeflags, arch, featureset, extra):
        config_base = self.config.merge('base', arch, featureset)
        makeflags['LOCALVERSION_HEADERS'] = vars['localversion_headers'] = vars['localversion']

    def do_featureset_packages(self, packages, makefile, arch, featureset, vars, makeflags, extra):
        headers_featureset = self.templates["control.headers.featureset"]
        package_headers = self.process_package(headers_featureset[0], vars)

        self.merge_packages(packages, (package_headers,), arch)

        cmds_binary_arch = ["$(MAKE) -f debian/rules.real binary-arch-featureset %s" % makeflags]
        makefile.add('binary-arch_%s_%s_real' % (arch, featureset), cmds=cmds_binary_arch)

    flavour_makeflags_base = (
        ('compiler', 'COMPILER', False),
        ('kernel-arch', 'KERNEL_ARCH', False),
        ('cflags', 'CFLAGS_KERNEL', True),
        ('override-host-type', 'OVERRIDE_HOST_TYPE', True),
    )

    flavour_makeflags_image = (
        ('type', 'TYPE', False),
        ('initramfs', 'INITRAMFS', True),
    )

    flavour_makeflags_other = (
        ('localversion', 'LOCALVERSION', False),
        ('localversion-image', 'LOCALVERSION_IMAGE', True),
    )

    def do_flavour_setup(self, vars, makeflags, arch, featureset, flavour, extra):
        config_base = self.config.merge('base', arch, featureset, flavour)
        config_description = self.config.merge('description', arch, featureset, flavour)
        config_image = self.config.merge('image', arch, featureset, flavour)

        vars['class'] = config_description['hardware']
        vars['longclass'] = config_description.get('hardware-long') or vars['class']

        vars['localversion-image'] = vars['localversion']
        #override_localversion = config_image.get('override-localversion', None)
        #if override_localversion is not None:
        #    vars['localversion-image'] = vars['localversion_headers'] + '-' + override_localversion

        self._setup_makeflags(self.flavour_makeflags_base, makeflags, config_base)
        self._setup_makeflags(self.flavour_makeflags_image, makeflags, config_image)
        self._setup_makeflags(self.flavour_makeflags_other, makeflags, vars)

    def do_flavour_packages(self, packages, makefile, arch, featureset, flavour, vars, makeflags, extra):
        headers = self.templates["control.headers"]

        config_entry_base = self.config.merge('base', arch, featureset, flavour)
        config_entry_build = self.config.merge('build', arch, featureset, flavour)
        config_entry_description = self.config.merge('description', arch, featureset, flavour)
        config_entry_image = self.config.merge('image', arch, featureset, flavour)
        config_entry_relations = self.config.merge('relations', arch, featureset, flavour)

        compiler = config_entry_base.get('compiler', 'gcc')
        relations_compiler = PackageRelation(config_entry_relations[compiler])
        relations_compiler_build_dep = PackageRelation(config_entry_relations[compiler])
        for group in relations_compiler_build_dep:
            for item in group:
                item.arches = [arch]
        packages['source']['Build-Depends'].extend(relations_compiler_build_dep)

        image_fields = {'Description': PackageDescription()}
        for field in 'Depends', 'Provides', 'Suggests', 'Recommends', 'Conflicts', 'Breaks':
            image_fields[field] = PackageRelation(config_entry_image.get(field.lower(), None), override_arches=(arch,))

        if config_entry_image.get('initramfs', True):
            generators = config_entry_image['initramfs-generators']
            l = PackageRelationGroup()
            for i in generators:
                i = config_entry_relations.get(i, i)
                l.append(i)
                a = PackageRelationEntry(i)
                if a.operator is not None:
                    a.operator = -a.operator
                    image_fields['Breaks'].append(PackageRelationGroup([a]))
            for item in l:
                item.arches = [arch]
            image_fields['Depends'].append(l)

        bootloaders = config_entry_image.get('bootloaders')
        if bootloaders:
            l = PackageRelationGroup()
            for i in bootloaders:
                i = config_entry_relations.get(i, i)
                l.append(i)
                a = PackageRelationEntry(i)
                if a.operator is not None:
                    a.operator = -a.operator
                    image_fields['Breaks'].append(PackageRelationGroup([a]))
            for item in l:
                item.arches = [arch]
            image_fields['Suggests'].append(l)

        desc_parts = self.config.get_merge('description', arch, featureset, flavour, 'parts')
        if desc_parts:
            # XXX: Workaround, we need to support multiple entries of the same name
            parts = list(set(desc_parts))
            parts.sort()
            desc = image_fields['Description']
            for part in parts:
                desc.append(config_entry_description['part-long-' + part])
                desc.append_short(config_entry_description.get('part-short-' + part, ''))

        packages_dummy = []
        packages_own = []

        image = self.templates["control.image.type-%s" % config_entry_image['type']]

        config_entry_xen = self.config.merge('xen', arch, featureset, flavour)
        if config_entry_xen:
            p = self.process_packages(self.templates['control.xen-linux-system'], vars)
            l = PackageRelationGroup()
            for xen_flavour in config_entry_xen['flavours']:
                l.append("xen-system-%s" % xen_flavour)
            p[0]['Depends'].append(l)
            packages_dummy.extend(p)

        vars.setdefault('desc', None)

        packages_own.append(self.process_real_image(image[0], image_fields, vars))
        packages_own.extend(self.process_packages(image[1:], vars))

        if config_entry_build.get('modules', True):
            makeflags['MODULES'] = True
            package_headers = self.process_package(headers[0], vars)
            package_headers['Depends'].extend(relations_compiler)
            packages_own.append(package_headers)
            extra['headers_arch_depends'].append('%s (= ${binary:Version})' % packages_own[-1]['Package'])

        build_debug = config_entry_build.get('debug-info')

        if os.getenv('DEBIAN_KERNEL_DISABLE_DEBUG'):
            if self.changelog[0].distribution == 'UNRELEASED':
                import warnings
                warnings.warn(u'Disable debug infos on request (DEBIAN_KERNEL_DISABLE_DEBUG set)')
                build_debug = False
            else:
                raise RuntimeError(u'Unable to disable debug infos in release build (DEBIAN_KERNEL_DISABLE_DEBUG set)')

        if build_debug:
            makeflags['DEBUG'] = True
            packages_own.extend(self.process_packages(self.templates['control.image-dbg'], vars))

        self.merge_packages(packages, packages_own + packages_dummy, arch)

        def get_config(*entry_name):
            entry_real = ('image',) + entry_name
            entry = self.config.get(entry_real, None)
            if entry is None:
                return None
            return entry.get('configs', None)

        def check_config_default(fail, f):
            for d in self.config_dirs[::-1]:
                f1 = d + '/' + f
                if os.path.exists(f1):
                    return [f1]
            if fail:
                raise RuntimeError("%s unavailable" % f)
            return []

        def check_config_files(files):
            ret = []
            for f in files:
                for d in self.config_dirs[::-1]:
                    f1 = d + '/' + f
                    if os.path.exists(f1):
                        ret.append(f1)
                        break
                else:
                    raise RuntimeError("%s unavailable" % f)
            return ret

        def check_config(default, fail, *entry_name):
            configs = get_config(*entry_name)
            if configs is None:
                return check_config_default(fail, default)
            return check_config_files(configs)

        kconfig = check_config('config', True)
        kconfig.extend(check_config("kernelarch-%s/config" % config_entry_base['kernel-arch'], False))
        kconfig.extend(check_config("%s/config" % arch, True, arch))
        kconfig.extend(check_config("%s/config.%s" % (arch, flavour), False, arch, None, flavour))
        kconfig.extend(check_config("featureset-%s/config" % featureset, False, None, featureset))
        kconfig.extend(check_config("%s/%s/config" % (arch, featureset), False, arch, featureset))
        kconfig.extend(check_config("%s/%s/config.%s" % (arch, featureset, flavour), False, arch, featureset, flavour))
        makeflags['KCONFIG'] = ' '.join(kconfig)
        if build_debug:
            makeflags['KCONFIG_OPTIONS'] = '-o DEBUG_INFO=y'

        cmds_binary_arch = ["$(MAKE) -f debian/rules.real binary-arch-flavour %s" % makeflags]
        if packages_dummy:
            cmds_binary_arch.append("$(MAKE) -f debian/rules.real install-dummy DH_OPTIONS='%s' %s" % (' '.join(["-p%s" % i['Package'] for i in packages_dummy]), makeflags))
        cmds_build = ["$(MAKE) -f debian/rules.real build-arch %s" % makeflags]
        cmds_setup = ["$(MAKE) -f debian/rules.real setup-flavour %s" % makeflags]
        makefile.add('binary-arch_%s_%s_%s_real' % (arch, featureset, flavour), cmds=cmds_binary_arch)
        makefile.add('build-arch_%s_%s_%s_real' % (arch, featureset, flavour), cmds=cmds_build)
        makefile.add('setup_%s_%s_%s_real' % (arch, featureset, flavour), cmds=cmds_setup)

    def merge_packages(self, 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)

    def process_changelog(self):
        act_upstream = self.changelog[0].version.upstream
        versions = []
        for i in self.changelog:
            if i.version.upstream != act_upstream:
                break
            versions.append(i.version)
        self.versions = versions
        version = self.version = self.changelog[0].version
        if self.version.linux_modifier is not None:
            self.abiname_part = ''
        else:
            self.abiname_part = '-%s' % self.config['abi', ]['abiname']
        self.abiname = self.version.linux_upstream + self.abiname_part
        self.vars = {
            'upstreamversion': self.version.linux_upstream,
            'version': self.version.linux_version,
            'source_upstream': self.version.upstream,
            'source_package': self.changelog[0].source,
            'abiname': self.abiname,
        }
        self.config['version', ] = {'source': self.version.complete, 'abiname': self.abiname}

        distribution = self.changelog[0].distribution
        if distribution in ('unstable', ):
            if (version.linux_revision_experimental or
                    version.linux_revision_other):
                raise RuntimeError("Can't upload to %s with a version of %s" %
                        (distribution, version))
        if distribution in ('experimental', ):
            if not version.linux_revision_experimental:
                raise RuntimeError("Can't upload to %s with a version of %s" %
                        (distribution, version))

    def process_real_image(self, entry, fields, vars):
        entry = self.process_package(entry, vars)
        for key, value in fields.iteritems():
            if key in entry:
                real = entry[key]
                real.extend(value)
            elif value:
                entry[key] = value
        return entry

    def write(self, packages, makefile):
        self.write_config()
        super(Gencontrol, self).write(packages, makefile)

    def write_config(self):
        f = file("debian/config.defines.dump", 'w')
        self.config.dump(f)
        f.close()
class Gencontrol(Base):
    config_schema = {
        'abi': {
            'ignore-changes': config.SchemaItemList(),
        },
        'build': {
            'debug-info': config.SchemaItemBoolean(),
            'signed-code': config.SchemaItemBoolean(),
            'vdso': config.SchemaItemBoolean(),
        },
        'description': {
            'parts': config.SchemaItemList(),
        },
        'image': {
            'bootloaders': config.SchemaItemList(),
            'configs': config.SchemaItemList(),
            'initramfs-generators': config.SchemaItemList(),
            'check-size': config.SchemaItemInteger(),
            'check-size-with-dtb': config.SchemaItemBoolean(),
            'check-uncompressed-size': config.SchemaItemInteger(),
        },
        'relations': {
        },
        'packages': {
            'docs': config.SchemaItemBoolean(),
            'headers-all': config.SchemaItemBoolean(),
            'installer': config.SchemaItemBoolean(),
            'libc-dev': config.SchemaItemBoolean(),
            'tools': config.SchemaItemBoolean(),
        }
    }

    def __init__(self, config_dirs=["debian/config"], template_dirs=["debian/templates"]):
        super(Gencontrol, self).__init__(
            config.ConfigCoreHierarchy(self.config_schema, config_dirs),
            Templates(template_dirs),
            VersionLinux)
        self.process_changelog()
        self.config_dirs = config_dirs

    def _setup_makeflags(self, names, makeflags, data):
        for src, dst, optional in names:
            if src in data or not optional:
                makeflags[dst] = data[src]

    def _substitute_file(self, template, vars, target, append=False):
        with open(target, 'a' if append else 'w') as f:
            f.write(self.substitute(self.templates[template], vars))

    def do_main_setup(self, vars, makeflags, extra):
        super(Gencontrol, self).do_main_setup(vars, makeflags, extra)
        makeflags.update({
            'VERSION': self.version.linux_version,
            'UPSTREAMVERSION': self.version.linux_upstream,
            'ABINAME': self.abiname_version + self.abiname_part,
            'SOURCEVERSION': self.version.complete,
        })

        # Prepare to generate debian/tests/control
        self.tests_control = None

    def do_main_makefile(self, makefile, makeflags, extra):
        fs_enabled = [featureset
                      for featureset in self.config['base', ]['featuresets']
                      if self.config.merge('base', None, featureset).get('enabled', True)]
        for featureset in fs_enabled:
            makeflags_featureset = makeflags.copy()
            makeflags_featureset['FEATURESET'] = featureset
            cmds_source = ["$(MAKE) -f debian/rules.real source-featureset %s"
                           % makeflags_featureset]
            makefile.add('source_%s_real' % featureset, cmds=cmds_source)
            makefile.add('source_%s' % featureset,
                         ['source_%s_real' % featureset])
            makefile.add('source', ['source_%s' % featureset])

        triplet_enabled = []
        for arch in iter(self.config['base', ]['arches']):
            for featureset in self.config['base', arch].get('featuresets', ()):
                if self.config.merge('base', None, featureset).get('enabled', True):
                    for flavour in self.config['base', arch, featureset]['flavours']:
                        triplet_enabled.append('%s_%s_%s' %
                                               (arch, featureset, flavour))

        makeflags = makeflags.copy()
        makeflags['ALL_FEATURESETS'] = ' '.join(fs_enabled)
        makeflags['ALL_TRIPLETS'] = ' '.join(triplet_enabled)
        if not self.config.merge('packages').get('docs', True):
            makeflags['DO_DOCS'] = False
        if not self.config.merge('packages').get('tools', True):
            makeflags['DO_TOOLS'] = False
        super(Gencontrol, self).do_main_makefile(makefile, makeflags, extra)

        # linux-source-$UPSTREAMVERSION will contain all kconfig files
        makefile.add('binary-indep', deps=['setup'])

    def do_main_packages(self, packages, vars, makeflags, extra):
        packages.extend(self.process_packages(self.templates["control.main"], self.vars))
        if self.config.merge('packages').get('docs', True):
            packages.extend(self.process_packages(self.templates["control.docs"], self.vars))
        if self.config.merge('packages').get('tools', True):
            packages.extend(self.process_packages(self.templates["control.tools"], self.vars))

        self._substitute_file('perf.lintian-overrides', self.vars,
                              'debian/linux-perf-%s.lintian-overrides' %
                              self.vars['version'])

    def do_indep_featureset_setup(self, vars, makeflags, featureset, extra):
        makeflags['LOCALVERSION'] = vars['localversion']
        kernel_arches = set()
        for arch in iter(self.config['base', ]['arches']):
            if self.config.get_merge('base', arch, featureset, None, 'flavours'):
                kernel_arches.add(self.config['base', arch]['kernel-arch'])
        makeflags['ALL_KERNEL_ARCHES'] = ' '.join(sorted(list(kernel_arches)))

        vars['featureset_desc'] = ''
        if featureset != 'none':
            desc = self.config[('description', None, featureset)]
            desc_parts = desc['parts']
            vars['featureset_desc'] = (' with the %s featureset' %
                                       desc['part-short-%s' % desc_parts[0]])

    def do_indep_featureset_packages(self, packages, makefile, featureset,
                                     vars, makeflags, extra):
        headers_featureset = self.templates["control.headers.featureset"]
        packages.extend(self.process_packages(headers_featureset, vars))

        cmds_binary_arch = ["$(MAKE) -f debian/rules.real binary-indep-featureset %s" %
                            makeflags]
        makefile.add('binary-indep_%s_real' % featureset, cmds=cmds_binary_arch)

    arch_makeflags = (
        ('kernel-arch', 'KERNEL_ARCH', False),
    )

    def do_arch_setup(self, vars, makeflags, arch, extra):
        config_base = self.config.merge('base', arch)

        self._setup_makeflags(self.arch_makeflags, makeflags, config_base)

        try:
            gnu_type_bytes = subprocess.check_output(['dpkg-architecture', '-f',
                                                      '-a', arch,
                                                      '-q', 'DEB_HOST_GNU_TYPE'],
                                                     stderr=subprocess.DEVNULL)
        except subprocess.CalledProcessError:
            # This sometimes happens for the newest ports :-/
            print('W: Unable to get GNU type for %s' % arch, file=sys.stderr)
        else:
            vars['gnu-type-package'] = gnu_type_bytes.decode('utf-8').strip().replace('_', '-')

    def do_arch_packages(self, packages, makefile, arch, vars, makeflags, extra):
        if self.version.linux_modifier is None:
            try:
                abiname_part = '-%s' % self.config['abi', arch]['abiname']
            except KeyError:
                abiname_part = self.abiname_part
            makeflags['ABINAME'] = vars['abiname'] = \
                self.abiname_version + abiname_part

        build_signed = self.config.merge('build', arch).get('signed-code', False)

        # Some userland architectures require kernels from another
        # (Debian) architecture, e.g. x32/amd64.
        # And some derivatives don't need the headers-all packages
        # for other reasons.
        if (self.config['base', arch].get('featuresets') and
            self.config.merge('packages').get('headers-all', True)):
            headers_arch = self.templates["control.headers.arch"]
            packages_headers_arch = self.process_packages(headers_arch, vars)
            packages_headers_arch[-1]['Depends'].extend(PackageRelation())
            extra['headers_arch_depends'] = packages_headers_arch[-1]['Depends']
        else:
            packages_headers_arch = []
            makeflags['DO_HEADERS_ALL'] = False

        if self.config.merge('packages').get('libc-dev', True):
            libc_dev = self.templates["control.libc-dev"]
            packages_headers_arch[0:0] = self.process_packages(libc_dev, {})
        else:
            makeflags['DO_LIBC'] = False

        if not self.config.merge('packages').get('tools', True):
            makeflags['DO_TOOLS'] = False


        merge_packages(packages, packages_headers_arch, arch)

        cmds_build_arch = ["$(MAKE) -f debian/rules.real build-arch-arch %s" % makeflags]
        makefile.add('build-arch_%s_real' % arch, cmds=cmds_build_arch)

        cmds_binary_arch = ["$(MAKE) -f debian/rules.real binary-arch-arch %s" % makeflags]
        makefile.add('binary-arch_%s_real' % arch, cmds=cmds_binary_arch)

        # For stage1 build profile
        makefile.add('binary-libc-dev_%s' % arch,
                     ['source_none_real'],
                     ["$(MAKE) -f debian/rules.real install-libc-dev_%s %s" %
                      (arch, makeflags)])

        if os.getenv('DEBIAN_KERNEL_DISABLE_INSTALLER'):
            if self.changelog[0].distribution == 'UNRELEASED':
                import warnings
                warnings.warn('Disable installer modules on request (DEBIAN_KERNEL_DISABLE_INSTALLER set)')
            else:
                raise RuntimeError('Unable to disable installer modules in release build (DEBIAN_KERNEL_DISABLE_INSTALLER set)')
        elif self.config.merge('packages').get('installer', True):
            # Add udebs using kernel-wedge
            installer_def_dir = 'debian/installer'
            installer_arch_dir = os.path.join(installer_def_dir, arch)
            if os.path.isdir(installer_arch_dir):
                kw_env = os.environ.copy()
                kw_env['KW_DEFCONFIG_DIR'] = installer_def_dir
                kw_env['KW_CONFIG_DIR'] = installer_arch_dir
                kw_proc = subprocess.Popen(
                    ['kernel-wedge', 'gen-control', vars['abiname']],
                    stdout=subprocess.PIPE,
                    env=kw_env)
                if not isinstance(kw_proc.stdout, io.IOBase):
                    udeb_packages = read_control(io.open(kw_proc.stdout.fileno(), closefd=False))
                else:
                    udeb_packages = read_control(io.TextIOWrapper(kw_proc.stdout))
                kw_proc.wait()
                if kw_proc.returncode != 0:
                    raise RuntimeError('kernel-wedge exited with code %d' %
                                       kw_proc.returncode)

                # If we're going to build signed udebs later, don't actually
                # generate udebs.  Just test that we *can* build, so we find
                # configuration errors before building linux-signed.

                # kernel-wedge currently chokes on Build-Profiles so add it now
                for package in udeb_packages:
                    if build_signed:
                        # XXX This is a hack to exclude the udebs from
                        # the package list while still being able to
                        # convince debhelper and kernel-wedge to go
                        # part way to building them.
                        package['Build-Profiles'] = '<pkg.linux.udeb-unsigned-test-build>'
                    else:
                        package['Build-Profiles'] = '<!stage1>'

                merge_packages(packages, udeb_packages, arch)

                # These packages must be built after the per-flavour/
                # per-featureset packages.  Also, this won't work
                # correctly with an empty package list.
                if udeb_packages:
                    makefile.add(
                        'binary-arch_%s' % arch,
                        cmds=["$(MAKE) -f debian/rules.real install-udeb_%s %s "
                              "PACKAGE_NAMES='%s' UDEB_UNSIGNED_TEST_BUILD=%s" %
                              (arch, makeflags,
                               ' '.join(p['Package'] for p in udeb_packages),
                               build_signed)])

        # This also needs to be built after the per-flavour/per-featureset
        # packages.
        if build_signed:
            merge_packages(packages,
                           self.process_packages(
                               self.templates['control.signed-template'], vars),
                           arch)
            makefile.add(
                'binary-arch_%s' % arch,
                cmds=["$(MAKE) -f debian/rules.real install-signed-template_%s %s" %
                      (arch, makeflags)])

    def do_featureset_setup(self, vars, makeflags, arch, featureset, extra):
        config_base = self.config.merge('base', arch, featureset)
        makeflags['LOCALVERSION_HEADERS'] = vars['localversion_headers'] = vars['localversion']

    flavour_makeflags_base = (
        ('compiler', 'COMPILER', False),
        ('compiler-filename', 'COMPILER', True),
        ('kernel-arch', 'KERNEL_ARCH', False),
        ('cflags', 'CFLAGS_KERNEL', True),
        ('override-host-type', 'OVERRIDE_HOST_TYPE', True),
    )

    flavour_makeflags_build = (
        ('image-file', 'IMAGE_FILE', True),
    )

    flavour_makeflags_image = (
        ('install-stem', 'IMAGE_INSTALL_STEM', True),
    )

    flavour_makeflags_other = (
        ('localversion', 'LOCALVERSION', False),
        ('localversion-image', 'LOCALVERSION_IMAGE', True),
    )

    def do_flavour_setup(self, vars, makeflags, arch, featureset, flavour, extra):
        config_base = self.config.merge('base', arch, featureset, flavour)
        config_build = self.config.merge('build', arch, featureset, flavour)
        config_description = self.config.merge('description', arch, featureset, flavour)
        config_image = self.config.merge('image', arch, featureset, flavour)

        vars['class'] = config_description['hardware']
        vars['longclass'] = config_description.get('hardware-long') or vars['class']

        vars['localversion-image'] = vars['localversion']
        override_localversion = config_image.get('override-localversion', None)
        if override_localversion is not None:
            vars['localversion-image'] = vars['localversion_headers'] + '-' + override_localversion
        vars['image-stem'] = config_image.get('install-stem')

        self._setup_makeflags(self.flavour_makeflags_base, makeflags, config_base)
        self._setup_makeflags(self.flavour_makeflags_build, makeflags, config_build)
        self._setup_makeflags(self.flavour_makeflags_image, makeflags, config_image)
        self._setup_makeflags(self.flavour_makeflags_other, makeflags, vars)

    def do_flavour_packages(self, packages, makefile, arch, featureset, flavour, vars, makeflags, extra):
        headers = self.templates["control.headers"]

        config_entry_base = self.config.merge('base', arch, featureset, flavour)
        config_entry_build = self.config.merge('build', arch, featureset, flavour)
        config_entry_description = self.config.merge('description', arch, featureset, flavour)
        config_entry_image = self.config.merge('image', arch, featureset, flavour)
        config_entry_relations = self.config.merge('relations', arch, featureset, flavour)

        compiler = config_entry_base.get('compiler', 'gcc')

        # Work out dependency from linux-headers to compiler.  Drop
        # dependencies for cross-builds.  Strip any remaining
        # restrictions, as they don't apply to binary Depends.
        relations_compiler_headers = PackageRelation(
            self.substitute(config_entry_relations.get('headers%' + compiler) or
                            config_entry_relations.get(compiler), vars))
        relations_compiler_headers = PackageRelation(
            PackageRelationGroup(entry for entry in group
                                 if 'cross' not in entry.restrictions)
            for group in relations_compiler_headers)
        for group in relations_compiler_headers:
            for entry in group:
                entry.restrictions = []

        relations_compiler_build_dep = PackageRelation(
            self.substitute(config_entry_relations[compiler], vars))
        for group in relations_compiler_build_dep:
            for item in group:
                item.arches = [arch]
        packages['source']['Build-Depends-Arch'].extend(relations_compiler_build_dep)

        image_fields = {'Description': PackageDescription()}
        for field in 'Depends', 'Provides', 'Suggests', 'Recommends', 'Conflicts', 'Breaks':
            image_fields[field] = PackageRelation(config_entry_image.get(field.lower(), None), override_arches=(arch,))

        generators = config_entry_image['initramfs-generators']
        l = PackageRelationGroup()
        for i in generators:
            i = config_entry_relations.get(i, i)
            l.append(i)
            a = PackageRelationEntry(i)
            if a.operator is not None:
                a.operator = -a.operator
                image_fields['Breaks'].append(PackageRelationGroup([a]))
        for item in l:
            item.arches = [arch]
        image_fields['Depends'].append(l)

        bootloaders = config_entry_image.get('bootloaders')
        if bootloaders:
            l = PackageRelationGroup()
            for i in bootloaders:
                i = config_entry_relations.get(i, i)
                l.append(i)
                a = PackageRelationEntry(i)
                if a.operator is not None:
                    a.operator = -a.operator
                    image_fields['Breaks'].append(PackageRelationGroup([a]))
            for item in l:
                item.arches = [arch]
            image_fields['Suggests'].append(l)

        desc_parts = self.config.get_merge('description', arch, featureset, flavour, 'parts')
        if desc_parts:
            # XXX: Workaround, we need to support multiple entries of the same name
            parts = list(set(desc_parts))
            parts.sort()
            desc = image_fields['Description']
            for part in parts:
                desc.append(config_entry_description['part-long-' + part])
                desc.append_short(config_entry_description.get('part-short-' + part, ''))

        packages_dummy = []
        packages_own = []

        build_signed = config_entry_build.get('signed-code')

        image = self.templates[build_signed and "control.image-unsigned"
                               or "control.image"]

        vars.setdefault('desc', None)

        image_main = self.process_real_image(image[0], image_fields, vars)
        packages_own.append(image_main)
        makeflags['IMAGE_PACKAGE_NAME'] = image_main['Package']
        packages_own.extend(self.process_packages(image[1:], vars))

        package_headers = self.process_package(headers[0], vars)
        package_headers['Depends'].extend(relations_compiler_headers)
        packages_own.append(package_headers)
        if extra.get('headers_arch_depends'):
            extra['headers_arch_depends'].append('%s (= ${binary:Version})' % packages_own[-1]['Package'])

        if config_entry_build.get('vdso', False):
            makeflags['VDSO'] = True

        build_debug = config_entry_build.get('debug-info')

        if os.getenv('DEBIAN_KERNEL_DISABLE_DEBUG'):
            if self.changelog[0].distribution == 'UNRELEASED':
                import warnings
                warnings.warn('Disable debug infos on request (DEBIAN_KERNEL_DISABLE_DEBUG set)')
                build_debug = False
            else:
                raise RuntimeError('Unable to disable debug infos in release build (DEBIAN_KERNEL_DISABLE_DEBUG set)')

        if build_debug:
            makeflags['DEBUG'] = True
            packages_own.extend(self.process_packages(self.templates['control.image-dbg'], vars))

        merge_packages(packages, packages_own + packages_dummy, arch)

        tests_control = self.process_package(
            self.templates['tests-control.main'][0], vars)
        tests_control['Depends'].append(
            PackageRelationGroup(image_main['Package'],
                                 override_arches=(arch,)))
        if self.tests_control:
            self.tests_control['Depends'].extend(tests_control['Depends'])
        else:
            self.tests_control = tests_control

        def get_config(*entry_name):
            entry_real = ('image',) + entry_name
            entry = self.config.get(entry_real, None)
            if entry is None:
                return None
            return entry.get('configs', None)

        def check_config_default(fail, f):
            for d in self.config_dirs[::-1]:
                f1 = d + '/' + f
                if os.path.exists(f1):
                    return [f1]
            if fail:
                raise RuntimeError("%s unavailable" % f)
            return []

        def check_config_files(files):
            ret = []
            for f in files:
                for d in self.config_dirs[::-1]:
                    f1 = d + '/' + f
                    if os.path.exists(f1):
                        ret.append(f1)
                        break
                else:
                    raise RuntimeError("%s unavailable" % f)
            return ret

        def check_config(default, fail, *entry_name):
            configs = get_config(*entry_name)
            if configs is None:
                return check_config_default(fail, default)
            return check_config_files(configs)

        kconfig = check_config('config', True)
        kconfig.extend(check_config("kernelarch-%s/config" % config_entry_base['kernel-arch'], False))
        kconfig.extend(check_config("%s/config" % arch, True, arch))
        kconfig.extend(check_config("%s/config.%s" % (arch, flavour), False, arch, None, flavour))
        kconfig.extend(check_config("featureset-%s/config" % featureset, False, None, featureset))
        kconfig.extend(check_config("%s/%s/config" % (arch, featureset), False, arch, featureset))
        kconfig.extend(check_config("%s/%s/config.%s" % (arch, featureset, flavour), False, arch, featureset, flavour))
        makeflags['KCONFIG'] = ' '.join(kconfig)
        makeflags['KCONFIG_OPTIONS'] = ''
        if build_debug:
            makeflags['KCONFIG_OPTIONS'] += ' -o DEBUG_INFO=y'
        if build_signed:
            makeflags['KCONFIG_OPTIONS'] += ' -o MODULE_SIG=y'

        cmds_binary_arch = ["$(MAKE) -f debian/rules.real binary-arch-flavour %s" % makeflags]
        if packages_dummy:
            cmds_binary_arch.append(
                "$(MAKE) -f debian/rules.real install-dummy DH_OPTIONS='%s' %s"
                % (' '.join("-p%s" % i['Package'] for i in packages_dummy), makeflags))
        cmds_build = ["$(MAKE) -f debian/rules.real build-arch-flavour %s" % makeflags]
        cmds_setup = ["$(MAKE) -f debian/rules.real setup-arch-flavour %s" % makeflags]
        makefile.add('binary-arch_%s_%s_%s_real' % (arch, featureset, flavour), cmds=cmds_binary_arch)
        makefile.add('build-arch_%s_%s_%s_real' % (arch, featureset, flavour), cmds=cmds_build)
        makefile.add('setup_%s_%s_%s_real' % (arch, featureset, flavour), cmds=cmds_setup)

        # Substitute kernel version etc. into maintainer scripts,
        # translations and lintian overrides
        self._substitute_file('headers.postinst', vars,
                              'debian/linux-headers-%s%s.postinst' %
                              (vars['abiname'], vars['localversion']))
        for name in ['postinst', 'postrm', 'preinst', 'prerm']:
            self._substitute_file('image.%s' % name, vars,
                                  'debian/%s.%s' % (image_main['Package'], name))
        if build_debug:
            debug_lintian_over = ('debian/linux-image-%s%s-dbg.lintian-overrides' %
                                  (vars['abiname'], vars['localversion']))
            self._substitute_file('image-dbg.lintian-overrides', vars,
                                  debug_lintian_over)
            os.chmod(debug_lintian_over, 0o755)

    def process_changelog(self):
        act_upstream = self.changelog[0].version.upstream
        versions = []
        for i in self.changelog:
            if i.version.upstream != act_upstream:
                break
            versions.append(i.version)
        self.versions = versions
        version = self.version = self.changelog[0].version
        if self.version.linux_modifier is not None:
            self.abiname_part = ''
        else:
            self.abiname_part = '-%s' % self.config['abi', ]['abiname']
        # We need to keep at least three version components to avoid
        # userland breakage (e.g. #742226, #745984).
        self.abiname_version = re.sub('^(\d+\.\d+)(?=-|$)', r'\1.0',
                                      self.version.linux_upstream)
        self.vars = {
            'upstreamversion': self.version.linux_upstream,
            'version': self.version.linux_version,
            'source_upstream': self.version.upstream,
            'source_package': self.changelog[0].source,
            'abiname': self.abiname_version + self.abiname_part,
        }
        self.config['version', ] = {'source': self.version.complete,
                                    'upstream': self.version.linux_upstream,
                                    'abiname_base': self.abiname_version,
                                    'abiname': (self.abiname_version +
                                                self.abiname_part)}

        distribution = self.changelog[0].distribution
        if distribution in ('unstable', ):
            if (version.linux_revision_experimental or
                version.linux_revision_backports or
                version.linux_revision_other):
                raise RuntimeError("Can't upload to %s with a version of %s" % (distribution, version))
        if distribution in ('experimental', ):
            if not version.linux_revision_experimental:
                raise RuntimeError("Can't upload to %s with a version of %s" % (distribution, version))
        if distribution.endswith('-security') or distribution.endswith('-lts'):
            if version.linux_revision_backports or version.linux_revision_other:
                raise RuntimeError("Can't upload to %s with a version of %s" % (distribution, version))
        if distribution.endswith('-backports'):
            if not version.linux_revision_backports:
                raise RuntimeError("Can't upload to %s with a version of %s" % (distribution, version))

    def process_real_image(self, entry, fields, vars):
        entry = self.process_package(entry, vars)
        for key, value in fields.items():
            if key in entry:
                real = entry[key]
                real.extend(value)
            elif value:
                entry[key] = value
        return entry

    def write(self, packages, makefile):
        self.write_config()
        super(Gencontrol, self).write(packages, makefile)
        self.write_tests_control()

    def write_config(self):
        f = open("debian/config.defines.dump", 'wb')
        self.config.dump(f)
        f.close()

    def write_tests_control(self):
        self.write_rfc822(open("debian/tests/control", 'w'),
                          [self.tests_control])
Beispiel #4
0
class Gencontrol(Base):
    config_schema = {
        'abi': {
            'ignore-changes': config.SchemaItemList(),
        },
        'build': {
            'debug-info': config.SchemaItemBoolean(),
            'signed-code': config.SchemaItemBoolean(),
            'vdso': config.SchemaItemBoolean(),
        },
        'description': {
            'parts': config.SchemaItemList(),
        },
        'image': {
            'bootloaders': config.SchemaItemList(),
            'configs': config.SchemaItemList(),
            'initramfs-generators': config.SchemaItemList(),
            'check-size': config.SchemaItemInteger(),
            'check-size-with-dtb': config.SchemaItemBoolean(),
            'check-uncompressed-size': config.SchemaItemInteger(),
            'depends': config.SchemaItemList(','),
            'provides': config.SchemaItemList(','),
            'suggests': config.SchemaItemList(','),
            'recommends': config.SchemaItemList(','),
            'conflicts': config.SchemaItemList(','),
            'breaks': config.SchemaItemList(','),
        },
        'relations': {},
        'packages': {
            'docs': config.SchemaItemBoolean(),
            'installer': config.SchemaItemBoolean(),
            'libc-dev': config.SchemaItemBoolean(),
            'meta': config.SchemaItemBoolean(),
            'tools-unversioned': config.SchemaItemBoolean(),
            'tools-versioned': config.SchemaItemBoolean(),
            'source': config.SchemaItemBoolean(),
        }
    }

    def __init__(self,
                 config_dirs=["debian/config"],
                 template_dirs=["debian/templates"]):
        super(Gencontrol, self).__init__(
            config.ConfigCoreHierarchy(self.config_schema, config_dirs),
            Templates(template_dirs), VersionLinux)
        self.process_changelog()
        self.config_dirs = config_dirs

    def _setup_makeflags(self, names, makeflags, data):
        for src, dst, optional in names:
            if src in data or not optional:
                makeflags[dst] = data[src]

    def do_main_setup(self, vars, makeflags, extra):
        super(Gencontrol, self).do_main_setup(vars, makeflags, extra)
        makeflags.update({
            'VERSION': self.version.linux_version,
            'UPSTREAMVERSION': self.version.linux_upstream,
            'ABINAME': self.abiname_version + self.abiname_part,
            'SOURCEVERSION': self.version.complete,
        })
        makeflags['SOURCE_BASENAME'] = vars['source_basename']
        makeflags['SOURCE_SUFFIX'] = vars['source_suffix']

        # Prepare to generate debian/tests/control
        self.tests_control = self.process_packages(
            self.templates['tests-control.main'], vars)
        self.tests_control_image = None

        self.installer_packages = {}

        if os.getenv('DEBIAN_KERNEL_DISABLE_INSTALLER'):
            if self.changelog[0].distribution == 'UNRELEASED':
                import warnings
                warnings.warn('Disable installer modules on request '
                              '(DEBIAN_KERNEL_DISABLE_INSTALLER set)')
            else:
                raise RuntimeError(
                    'Unable to disable installer modules in release build '
                    '(DEBIAN_KERNEL_DISABLE_INSTALLER set)')
        elif self.config.merge('packages').get('installer', True):
            # Add udebs using kernel-wedge
            kw_env = os.environ.copy()
            kw_env['KW_DEFCONFIG_DIR'] = 'debian/installer'
            kw_env['KW_CONFIG_DIR'] = 'debian/installer'
            kw_proc = subprocess.Popen(
                ['kernel-wedge', 'gen-control', vars['abiname']],
                stdout=subprocess.PIPE,
                env=kw_env)
            if not isinstance(kw_proc.stdout, io.IOBase):
                udeb_packages = read_control(
                    io.open(kw_proc.stdout.fileno(), closefd=False))
            else:
                udeb_packages = read_control(io.TextIOWrapper(kw_proc.stdout))
            kw_proc.wait()
            if kw_proc.returncode != 0:
                raise RuntimeError('kernel-wedge exited with code %d' %
                                   kw_proc.returncode)

            # All architectures that have some installer udebs
            arches = set()
            for package in udeb_packages:
                arches.update(package['Architecture'])

            # Code-signing status for those architectures
            # If we're going to build signed udebs later, don't actually
            # generate udebs.  Just test that we *can* build, so we find
            # configuration errors before building linux-signed.
            build_signed = {}
            for arch in arches:
                build_signed[arch] = self.config.merge('build', arch) \
                                                .get('signed-code', False)

            for package in udeb_packages:
                # kernel-wedge currently chokes on Build-Profiles so add it now
                if any(build_signed[arch] for arch in package['Architecture']):
                    assert all(build_signed[arch]
                               for arch in package['Architecture'])
                    # XXX This is a hack to exclude the udebs from
                    # the package list while still being able to
                    # convince debhelper and kernel-wedge to go
                    # part way to building them.
                    package['Build-Profiles'] = (
                        '<pkg.linux.udeb-unsigned-test-build>')
                else:
                    package['Build-Profiles'] = '<!stage1 !pkg.linux.nokernel>'

                for arch in package['Architecture']:
                    self.installer_packages.setdefault(arch, []) \
                                           .append(package)

    def do_main_makefile(self, makefile, makeflags, extra):
        for featureset in iter_featuresets(self.config):
            makeflags_featureset = makeflags.copy()
            makeflags_featureset['FEATURESET'] = featureset
            cmds_source = [
                "$(MAKE) -f debian/rules.real source-featureset %s" %
                makeflags_featureset
            ]
            makefile.add('source_%s_real' % featureset, cmds=cmds_source)
            makefile.add('source_%s' % featureset,
                         ['source_%s_real' % featureset])
            makefile.add('source', ['source_%s' % featureset])

        makeflags = makeflags.copy()
        makeflags['ALL_FEATURESETS'] = ' '.join(iter_featuresets(self.config))
        super(Gencontrol, self).do_main_makefile(makefile, makeflags, extra)

    def do_main_packages(self, packages, vars, makeflags, extra):
        packages.extend(
            self.process_packages(self.templates["control.main"], vars))

        # Only build the metapackages if their names won't exactly match
        # the packages they depend on
        do_meta = self.config.merge('packages').get('meta', True) \
            and vars['source_suffix'] != '-' + vars['version']

        if self.config.merge('packages').get('docs', True):
            packages.extend(
                self.process_packages(self.templates["control.docs"], vars))
            if do_meta:
                packages.extend(
                    self.process_packages(self.templates["control.docs.meta"],
                                          vars))
                self.substitute_debhelper_config(
                    'docs.meta', vars,
                    '%(source_basename)s-doc%(source_suffix)s' % vars)
        if self.config.merge('packages').get('tools-unversioned', True):
            packages.extend(
                self.process_packages(
                    self.templates["control.tools-unversioned"], vars))
        if self.config.merge('packages').get('tools-versioned', True):
            packages.extend(
                self.process_packages(
                    self.templates["control.tools-versioned"], vars))
            self.substitute_debhelper_config('perf', vars,
                                             'linux-perf-%(version)s' % vars)
            if do_meta:
                packages.extend(
                    self.process_packages(
                        self.templates["control.tools-versioned.meta"], vars))
                self.substitute_debhelper_config('perf.meta', vars,
                                                 'linux-perf')
        if self.config.merge('packages').get('source', True):
            packages.extend(
                self.process_packages(self.templates["control.sourcebin"],
                                      vars))
            if do_meta:
                packages.extend(
                    self.process_packages(
                        self.templates["control.sourcebin.meta"], vars))
                self.substitute_debhelper_config(
                    'sourcebin.meta', vars,
                    '%(source_basename)s-source%(source_suffix)s' % vars)

    def do_indep_featureset_setup(self, vars, makeflags, featureset, extra):
        makeflags['LOCALVERSION'] = vars['localversion']
        kernel_arches = set()
        for arch in iter(self.config['base', ]['arches']):
            if self.config.get_merge('base', arch, featureset, None,
                                     'flavours'):
                kernel_arches.add(self.config['base', arch]['kernel-arch'])
        makeflags['ALL_KERNEL_ARCHES'] = ' '.join(sorted(list(kernel_arches)))

        vars['featureset_desc'] = ''
        if featureset != 'none':
            desc = self.config[('description', None, featureset)]
            desc_parts = desc['parts']
            vars['featureset_desc'] = (' with the %s featureset' %
                                       desc['part-short-%s' % desc_parts[0]])

    def do_indep_featureset_packages(self, packages, makefile, featureset,
                                     vars, makeflags, extra):
        headers_featureset = self.templates["control.headers.featureset"]
        packages.extend(self.process_packages(headers_featureset, vars))

        cmds_binary_arch = [
            "$(MAKE) -f debian/rules.real "
            "binary-indep-featureset %s" % makeflags
        ]
        makefile.add('binary-indep_%s_real' % featureset,
                     cmds=cmds_binary_arch)

    arch_makeflags = (('kernel-arch', 'KERNEL_ARCH', False), )

    def do_arch_setup(self, vars, makeflags, arch, extra):
        config_base = self.config.merge('base', arch)

        self._setup_makeflags(self.arch_makeflags, makeflags, config_base)

        try:
            gnu_type_bytes = subprocess.check_output([
                'dpkg-architecture', '-f', '-a', arch, '-q',
                'DEB_HOST_GNU_TYPE'
            ],
                                                     stderr=subprocess.DEVNULL)
        except subprocess.CalledProcessError:
            # This sometimes happens for the newest ports :-/
            print('W: Unable to get GNU type for %s' % arch, file=sys.stderr)
        else:
            vars['gnu-type-package'] = (
                gnu_type_bytes.decode('utf-8').strip().replace('_', '-'))

    def do_arch_packages(self, packages, makefile, arch, vars, makeflags,
                         extra):
        if self.version.linux_modifier is None:
            try:
                abiname_part = '-%s' % self.config['abi', arch]['abiname']
            except KeyError:
                abiname_part = self.abiname_part
            makeflags['ABINAME'] = vars['abiname'] = \
                self.abiname_version + abiname_part

        build_signed = self.config.merge('build', arch) \
                                  .get('signed-code', False)

        if self.config.merge('packages').get('libc-dev', True):
            libc_dev = self.templates["control.libc-dev"]
            merge_packages(packages, self.process_packages(libc_dev, {}), arch)

        if self.config['base', arch].get('featuresets') and \
           self.config.merge('packages').get('source', True):
            merge_packages(
                packages,
                self.process_packages(self.templates["control.config"], vars),
                arch)

        cmds_build_arch = [
            "$(MAKE) -f debian/rules.real build-arch-arch %s" % makeflags
        ]
        makefile.add('build-arch_%s_real' % arch, cmds=cmds_build_arch)

        cmds_binary_arch = [
            "$(MAKE) -f debian/rules.real binary-arch-arch %s" % makeflags
        ]
        makefile.add('binary-arch_%s_real' % arch,
                     cmds=cmds_binary_arch,
                     deps=['setup_%s' % arch])

        udeb_packages = self.installer_packages.get(arch, [])
        if udeb_packages:
            merge_packages(packages, udeb_packages, arch)

            # These packages must be built after the per-flavour/
            # per-featureset packages.  Also, this won't work
            # correctly with an empty package list.
            makefile.add('binary-arch_%s' % arch,
                         cmds=[
                             "$(MAKE) -f debian/rules.real install-udeb_%s %s "
                             "PACKAGE_NAMES='%s' UDEB_UNSIGNED_TEST_BUILD=%s" %
                             (arch, makeflags, ' '.join(
                                 p['Package']
                                 for p in udeb_packages), build_signed)
                         ])

        # This also needs to be built after the per-flavour/per-featureset
        # packages.
        if build_signed:
            merge_packages(
                packages,
                self.process_packages(
                    self.templates['control.signed-template'], vars), arch)
            makefile.add('binary-arch_%s' % arch,
                         cmds=[
                             "$(MAKE) -f debian/rules.real "
                             "install-signed-template_%s %s" %
                             (arch, makeflags)
                         ])

    def do_featureset_setup(self, vars, makeflags, arch, featureset, extra):
        vars['localversion_headers'] = vars['localversion']
        makeflags['LOCALVERSION_HEADERS'] = vars['localversion_headers']

    flavour_makeflags_base = (
        ('compiler', 'COMPILER', False),
        ('compiler-filename', 'COMPILER', True),
        ('kernel-arch', 'KERNEL_ARCH', False),
        ('cflags', 'KCFLAGS', True),
        ('override-host-type', 'OVERRIDE_HOST_TYPE', True),
        ('cross-compile-compat', 'CROSS_COMPILE_COMPAT', True),
    )

    flavour_makeflags_build = (('image-file', 'IMAGE_FILE', True), )

    flavour_makeflags_image = (('install-stem', 'IMAGE_INSTALL_STEM', True), )

    flavour_makeflags_other = (
        ('localversion', 'LOCALVERSION', False),
        ('localversion-image', 'LOCALVERSION_IMAGE', True),
    )

    def do_flavour_setup(self, vars, makeflags, arch, featureset, flavour,
                         extra):
        config_base = self.config.merge('base', arch, featureset, flavour)
        config_build = self.config.merge('build', arch, featureset, flavour)
        config_description = self.config.merge('description', arch, featureset,
                                               flavour)
        config_image = self.config.merge('image', arch, featureset, flavour)

        vars['flavour'] = vars['localversion'][1:]
        vars['class'] = config_description['hardware']
        vars['longclass'] = (config_description.get('hardware-long')
                             or vars['class'])

        vars['localversion-image'] = vars['localversion']
        override_localversion = config_image.get('override-localversion', None)
        if override_localversion is not None:
            vars['localversion-image'] = (vars['localversion_headers'] + '-' +
                                          override_localversion)
        vars['image-stem'] = config_image.get('install-stem')

        self._setup_makeflags(self.flavour_makeflags_base, makeflags,
                              config_base)
        self._setup_makeflags(self.flavour_makeflags_build, makeflags,
                              config_build)
        self._setup_makeflags(self.flavour_makeflags_image, makeflags,
                              config_image)
        self._setup_makeflags(self.flavour_makeflags_other, makeflags, vars)

    def do_flavour_packages(self, packages, makefile, arch, featureset,
                            flavour, vars, makeflags, extra):
        headers = self.templates["control.headers"]
        assert len(headers) == 1

        do_meta = self.config.merge('packages').get('meta', True)
        config_entry_base = self.config.merge('base', arch, featureset,
                                              flavour)
        config_entry_build = self.config.merge('build', arch, featureset,
                                               flavour)
        config_entry_description = self.config.merge('description', arch,
                                                     featureset, flavour)
        config_entry_relations = self.config.merge('relations', arch,
                                                   featureset, flavour)

        def config_entry_image(key, *args, **kwargs):
            return self.config.get_merge('image', arch, featureset, flavour,
                                         key, *args, **kwargs)

        compiler = config_entry_base.get('compiler', 'gcc')

        # Work out dependency from linux-headers to compiler.  Drop
        # dependencies for cross-builds.  Strip any remaining
        # restrictions, as they don't apply to binary Depends.
        relations_compiler_headers = PackageRelation(
            self.substitute(
                config_entry_relations.get('headers%' + compiler)
                or config_entry_relations.get(compiler), vars))
        relations_compiler_headers = PackageRelation(
            PackageRelationGroup(entry for entry in group
                                 if 'cross' not in entry.restrictions)
            for group in relations_compiler_headers)
        for group in relations_compiler_headers:
            for entry in group:
                entry.restrictions = []

        relations_compiler_build_dep = PackageRelation(
            self.substitute(config_entry_relations[compiler], vars))
        for group in relations_compiler_build_dep:
            for item in group:
                item.arches = [arch]
        packages['source']['Build-Depends-Arch'].extend(
            relations_compiler_build_dep)

        image_fields = {'Description': PackageDescription()}
        for field in ('Depends', 'Provides', 'Suggests', 'Recommends',
                      'Conflicts', 'Breaks'):
            image_fields[field] = PackageRelation(config_entry_image(
                field.lower(), None),
                                                  override_arches=(arch, ))

        generators = config_entry_image('initramfs-generators')
        group = PackageRelationGroup()
        for i in generators:
            i = config_entry_relations.get(i, i)
            group.append(i)
            a = PackageRelationEntry(i)
            if a.operator is not None:
                a.operator = -a.operator
                image_fields['Breaks'].append(PackageRelationGroup([a]))
        for item in group:
            item.arches = [arch]
        image_fields['Depends'].append(group)

        bootloaders = config_entry_image('bootloaders', None)
        if bootloaders:
            group = PackageRelationGroup()
            for i in bootloaders:
                i = config_entry_relations.get(i, i)
                group.append(i)
                a = PackageRelationEntry(i)
                if a.operator is not None:
                    a.operator = -a.operator
                    image_fields['Breaks'].append(PackageRelationGroup([a]))
            for item in group:
                item.arches = [arch]
            image_fields['Suggests'].append(group)

        desc_parts = self.config.get_merge('description', arch, featureset,
                                           flavour, 'parts')
        if desc_parts:
            # XXX: Workaround, we need to support multiple entries of the same
            # name
            parts = list(set(desc_parts))
            parts.sort()
            desc = image_fields['Description']
            for part in parts:
                desc.append(config_entry_description['part-long-' + part])
                desc.append_short(
                    config_entry_description.get('part-short-' + part, ''))

        packages_own = []

        build_signed = config_entry_build.get('signed-code')

        image = self.templates[build_signed and "control.image-unsigned"
                               or "control.image"]
        assert len(image) == 1

        vars.setdefault('desc', None)

        image_main = self.process_real_image(image[0], image_fields, vars)
        packages_own.append(image_main)
        makeflags['IMAGE_PACKAGE_NAME'] = image_main['Package']

        # The image meta-packages will depend on signed linux-image
        # packages where applicable, so should be built from the
        # signed source packages
        if do_meta and not build_signed:
            packages_own.extend(
                self.process_packages(self.templates["control.image.meta"],
                                      vars))
            self.substitute_debhelper_config(
                "image.meta", vars, "linux-image%(localversion)s" % vars)

        package_headers = self.process_package(headers[0], vars)
        package_headers['Depends'].extend(relations_compiler_headers)
        packages_own.append(package_headers)
        if extra.get('headers_arch_depends'):
            extra['headers_arch_depends'].append('%s (= ${binary:Version})' %
                                                 packages_own[-1]['Package'])

        # The header meta-packages will be built along with the signed
        # packages, to create a dependency relationship that ensures
        # src:linux and src:linux-signed-* transition to testing together.
        if do_meta and not build_signed:
            packages_own.extend(
                self.process_packages(self.templates["control.headers.meta"],
                                      vars))
            self.substitute_debhelper_config(
                'headers.meta', vars, 'linux-headers%(localversion)s' % vars)

        if config_entry_build.get('vdso', False):
            makeflags['VDSO'] = True

        build_debug = config_entry_build.get('debug-info')

        if os.getenv('DEBIAN_KERNEL_DISABLE_DEBUG'):
            if self.changelog[0].distribution == 'UNRELEASED':
                import warnings
                warnings.warn('Disable debug infos on request '
                              '(DEBIAN_KERNEL_DISABLE_DEBUG set)')
                build_debug = False
            else:
                raise RuntimeError(
                    'Unable to disable debug infos in release build '
                    '(DEBIAN_KERNEL_DISABLE_DEBUG set)')

        if build_debug:
            makeflags['DEBUG'] = True
            packages_own.extend(
                self.process_packages(self.templates['control.image-dbg'],
                                      vars))
            if do_meta:
                packages_own.extend(
                    self.process_packages(
                        self.templates["control.image-dbg.meta"], vars))
                self.substitute_debhelper_config(
                    'image-dbg.meta', vars,
                    'linux-image%(localversion)s-dbg' % vars)

        merge_packages(packages, packages_own, arch)

        tests_control = self.process_package(
            self.templates['tests-control.image'][0], vars)
        tests_control['Depends'].append(
            PackageRelationGroup(image_main['Package'],
                                 override_arches=(arch, )))
        if self.tests_control_image:
            self.tests_control_image['Depends'].extend(
                tests_control['Depends'])
        else:
            self.tests_control_image = tests_control
            self.tests_control.append(tests_control)

        def get_config(*entry_name):
            entry_real = ('image', ) + entry_name
            entry = self.config.get(entry_real, None)
            if entry is None:
                return None
            return entry.get('configs', None)

        def check_config_default(fail, f):
            for d in self.config_dirs[::-1]:
                f1 = d + '/' + f
                if os.path.exists(f1):
                    return [f1]
            if fail:
                raise RuntimeError("%s unavailable" % f)
            return []

        def check_config_files(files):
            ret = []
            for f in files:
                for d in self.config_dirs[::-1]:
                    f1 = d + '/' + f
                    if os.path.exists(f1):
                        ret.append(f1)
                        break
                else:
                    raise RuntimeError("%s unavailable" % f)
            return ret

        def check_config(default, fail, *entry_name):
            configs = get_config(*entry_name)
            if configs is None:
                return check_config_default(fail, default)
            return check_config_files(configs)

        kconfig = check_config('config', True)
        kconfig.extend(
            check_config(
                "kernelarch-%s/config" % config_entry_base['kernel-arch'],
                False))
        kconfig.extend(check_config("%s/config" % arch, True, arch))
        kconfig.extend(
            check_config("%s/config.%s" % (arch, flavour), False, arch, None,
                         flavour))
        kconfig.extend(
            check_config("featureset-%s/config" % featureset, False, None,
                         featureset))
        kconfig.extend(
            check_config("%s/%s/config" % (arch, featureset), False, arch,
                         featureset))
        kconfig.extend(
            check_config("%s/%s/config.%s" % (arch, featureset, flavour),
                         False, arch, featureset, flavour))
        makeflags['KCONFIG'] = ' '.join(kconfig)
        makeflags['KCONFIG_OPTIONS'] = ''
        if build_debug:
            makeflags['KCONFIG_OPTIONS'] += ' -o DEBUG_INFO=y'
        if build_signed:
            makeflags['KCONFIG_OPTIONS'] += ' -o MODULE_SIG=y'
        # Add "salt" to fix #872263
        makeflags['KCONFIG_OPTIONS'] += \
            ' -o "BUILD_SALT=\\"%(abiname)s%(localversion)s\\""' % vars

        cmds_binary_arch = [
            "$(MAKE) -f debian/rules.real binary-arch-flavour "
            "%s" % makeflags
        ]
        cmds_build = [
            "$(MAKE) -f debian/rules.real build-arch-flavour %s" % makeflags
        ]
        cmds_setup = [
            "$(MAKE) -f debian/rules.real setup-arch-flavour %s" % makeflags
        ]
        makefile.add('binary-arch_%s_%s_%s_real' % (arch, featureset, flavour),
                     cmds=cmds_binary_arch)
        makefile.add('build-arch_%s_%s_%s_real' % (arch, featureset, flavour),
                     cmds=cmds_build)
        makefile.add('setup_%s_%s_%s_real' % (arch, featureset, flavour),
                     cmds=cmds_setup)

        merged_config = ('debian/build/config.%s_%s_%s' %
                         (arch, featureset, flavour))
        makefile.add(merged_config,
                     cmds=[
                         "$(MAKE) -f debian/rules.real %s %s" %
                         (merged_config, makeflags)
                     ])

        self.substitute_debhelper_config(
            'headers', vars,
            'linux-headers-%(abiname)s%(localversion)s' % vars)
        self.substitute_debhelper_config('image', vars, image_main['Package'])
        if build_debug:
            self.substitute_debhelper_config(
                'image-dbg', vars,
                'linux-image-%(abiname)s%(localversion)s-dbg' % vars)

    def process_changelog(self):
        version = self.version = self.changelog[0].version
        if self.version.linux_modifier is not None:
            self.abiname_part = ''
        else:
            self.abiname_part = '-%s' % self.config['abi', ]['abiname']
        # We need to keep at least three version components to avoid
        # userland breakage (e.g. #742226, #745984).
        self.abiname_version = re.sub(r'^(\d+\.\d+)(?=-|$)', r'\1.0',
                                      self.version.linux_upstream)
        self.vars = {
            'upstreamversion': self.version.linux_upstream,
            'version': self.version.linux_version,
            'source_basename': re.sub(r'-[\d.]+$', '',
                                      self.changelog[0].source),
            'source_upstream': self.version.upstream,
            'source_package': self.changelog[0].source,
            'abiname': self.abiname_version + self.abiname_part,
        }
        self.vars['source_suffix'] = \
            self.changelog[0].source[len(self.vars['source_basename']):]
        self.config['version', ] = {
            'source': self.version.complete,
            'upstream': self.version.linux_upstream,
            'abiname_base': self.abiname_version,
            'abiname': (self.abiname_version + self.abiname_part)
        }

        distribution = self.changelog[0].distribution
        if distribution in ('unstable', ):
            if version.linux_revision_experimental or \
               version.linux_revision_backports or \
               version.linux_revision_other:
                raise RuntimeError("Can't upload to %s with a version of %s" %
                                   (distribution, version))
        if distribution in ('experimental', ):
            if not version.linux_revision_experimental:
                raise RuntimeError("Can't upload to %s with a version of %s" %
                                   (distribution, version))
        if distribution.endswith('-security') or distribution.endswith('-lts'):
            if version.linux_revision_backports or \
               version.linux_revision_other:
                raise RuntimeError("Can't upload to %s with a version of %s" %
                                   (distribution, version))
        if distribution.endswith('-backports'):
            if not version.linux_revision_backports:
                raise RuntimeError("Can't upload to %s with a version of %s" %
                                   (distribution, version))

    def process_real_image(self, entry, fields, vars):
        entry = self.process_package(entry, vars)
        for key, value in fields.items():
            if key in entry:
                real = entry[key]
                real.extend(value)
            elif value:
                entry[key] = value
        return entry

    def write(self, packages, makefile):
        self.write_config()
        super(Gencontrol, self).write(packages, makefile)
        self.write_tests_control()

    def write_config(self):
        f = open("debian/config.defines.dump", 'wb')
        self.config.dump(f)
        f.close()

    def write_tests_control(self):
        self.write_rfc822(open("debian/tests/control", 'w'),
                          self.tests_control)