linux/debian/bin/gencontrol.py
2024-02-26 13:55:15 +04:00

719 lines
31 KiB
Python
Executable file

#!/usr/bin/python3
import sys
import json
import locale
import os
import os.path
import pathlib
import subprocess
import re
import tempfile
from typing import Any
from debian_linux import config
from debian_linux.debian import \
PackageRelationEntry, PackageRelationGroup, \
VersionLinux, BinaryPackage, TestsControl
from debian_linux.gencontrol import Gencontrol as Base, PackagesBundle, \
iter_featuresets, iter_flavours
from debian_linux.utils import Templates
locale.setlocale(locale.LC_CTYPE, "C.UTF-8")
class Gencontrol(Base):
disable_installer: bool
disable_signed: bool
tests_control_headers: TestsControl | None
config_schema = {
'build': {
'signed-code': config.SchemaItemBoolean(),
'vdso': config.SchemaItemBoolean(),
},
'description': {
'parts': config.SchemaItemList(),
},
'image': {
'configs': 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(','),
},
'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(),
}
}
env_flags = [
('DEBIAN_KERNEL_DISABLE_INSTALLER', 'disable_installer', 'installer modules'),
('DEBIAN_KERNEL_DISABLE_SIGNED', 'disable_signed', 'signed code'),
]
def __init__(self, config_dirs=["debian/config", "debian/config.local"],
template_dirs=["debian/templates"]) -> None:
super(Gencontrol, self).__init__(
config.ConfigCoreHierarchy(self.config_schema, config_dirs),
Templates(template_dirs),
VersionLinux)
self.process_changelog()
self.config_dirs = config_dirs
for env, attr, desc in self.env_flags:
setattr(self, attr, False)
if os.getenv(env):
if self.changelog[0].distribution == 'UNRELEASED':
import warnings
warnings.warn(f'Disable {desc} on request ({env} set)')
setattr(self, attr, True)
else:
raise RuntimeError(
f'Unable to disable {desc} in release build ({env} set)')
def _setup_makeflags(self, names, makeflags, data) -> None:
for src, dst, optional in names:
if src in data or not optional:
makeflags[dst] = data[src]
def do_main_setup(self, vars, makeflags) -> None:
super(Gencontrol, self).do_main_setup(vars, makeflags)
makeflags.update({
'VERSION': self.version.linux_version,
'UPSTREAMVERSION': self.version.linux_upstream,
'ABINAME': self.abiname,
'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.templates.get_tests_control('main.tests-control', vars)
self.tests_control_image = None
self.tests_control_headers = None
def do_main_makefile(self, makeflags) -> None:
for featureset in iter_featuresets(self.config):
makeflags_featureset = makeflags.copy()
makeflags_featureset['FEATURESET'] = featureset
self.bundle.makefile.add_rules(f'source_{featureset}',
'source', makeflags_featureset)
self.bundle.makefile.add_deps('source', [f'source_{featureset}'])
makeflags = makeflags.copy()
makeflags['ALL_FEATURESETS'] = ' '.join(iter_featuresets(self.config))
super().do_main_makefile(makeflags)
def do_main_packages(self, vars, makeflags) -> None:
self.bundle.add('main', (), makeflags, 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):
self.bundle.add('docs', (), makeflags, vars)
if do_meta:
self.bundle.add('docs.meta', (), makeflags, vars)
if self.config.merge('packages').get('source', True):
self.bundle.add('sourcebin', (), makeflags, vars)
if do_meta:
self.bundle.add('sourcebin.meta', (), makeflags, vars)
if self.config.merge('packages').get('libc-dev', True):
libcdev_kernelarches = set()
libcdev_multiarches = set()
for arch in iter(self.config['base', ]['arches']):
libcdev_kernelarch = self.config['base', arch]['kernel-arch']
libcdev_multiarch = subprocess.check_output(
['dpkg-architecture', '-f', '-a', arch,
'-q', 'DEB_HOST_MULTIARCH'],
stderr=subprocess.DEVNULL,
encoding='utf-8').strip()
libcdev_kernelarches.add(libcdev_kernelarch)
libcdev_multiarches.add(f'{libcdev_multiarch}:{libcdev_kernelarch}')
libcdev_makeflags = makeflags.copy()
libcdev_makeflags['ALL_LIBCDEV_KERNELARCHES'] = ' '.join(sorted(libcdev_kernelarches))
libcdev_makeflags['ALL_LIBCDEV_MULTIARCHES'] = ' '.join(sorted(libcdev_multiarches))
self.bundle.add('libc-dev', (), libcdev_makeflags, vars)
def do_indep_featureset_setup(self, vars, makeflags, featureset) -> None:
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, featureset, vars, makeflags) -> None:
self.bundle.add('headers.featureset', (featureset, ), makeflags, vars)
arch_makeflags = (
('kernel-arch', 'KERNEL_ARCH', False),
)
def do_arch_setup(self, vars, makeflags, arch) -> None:
config_base = self.config.merge('base', arch)
self._setup_makeflags(self.arch_makeflags, makeflags, config_base)
try:
gnu_type = subprocess.check_output(
['dpkg-architecture', '-f', '-a', arch,
'-q', 'DEB_HOST_GNU_TYPE'],
stderr=subprocess.DEVNULL,
encoding='utf-8')
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.strip().replace('_', '-')
def do_arch_packages(self, arch, vars, makeflags) -> None:
if not self.disable_signed:
build_signed = self.config.merge('build', arch) \
.get('signed-code', False)
else:
build_signed = False
if build_signed:
# Make sure variables remain
vars['signedtemplate_binaryversion'] = '@signedtemplate_binaryversion@'
vars['signedtemplate_sourceversion'] = '@signedtemplate_sourceversion@'
self.bundle.add('signed-template', (arch,), makeflags, vars, arch=arch)
bundle_signed = self.bundles[f'signed-{arch}'] = \
PackagesBundle(f'signed-{arch}', self.templates)
bundle_signed.packages['source'] = \
self.templates.get_source_control('signed.source.control', vars)[0]
with bundle_signed.open('source/lintian-overrides', 'w') as f:
f.write(self.substitute(
self.templates.get('signed.source.lintian-overrides'), vars))
with bundle_signed.open('changelog.head', 'w') as f:
dist = self.changelog[0].distribution
urgency = self.changelog[0].urgency
f.write(f'''\
linux-signed-{vars['arch']} (@signedtemplate_sourceversion@) {dist}; urgency={urgency}
* Sign kernel from {self.changelog[0].source} @signedtemplate_binaryversion@
''')
if self.config['base', arch].get('featuresets') and \
self.config.merge('packages').get('source', True):
self.bundle.add('config', (arch, ), makeflags, vars)
if self.config.merge('packages').get('tools-unversioned', True):
self.bundle.add('tools-unversioned', (arch, ), makeflags, vars)
if self.config.merge('packages').get('tools-versioned', True):
self.bundle.add('tools-versioned', (arch, ), makeflags, vars)
def do_featureset_setup(self, vars, makeflags, arch, featureset) -> None:
vars['localversion_headers'] = vars['localversion']
makeflags['LOCALVERSION_HEADERS'] = vars['localversion_headers']
self.default_flavour = self.config.merge('base', arch, featureset) \
.get('default-flavour')
if self.default_flavour is not None:
if featureset != 'none':
raise RuntimeError("default-flavour set for %s %s,"
" but must only be set for featureset none"
% (arch, featureset))
if self.default_flavour \
not in iter_flavours(self.config, arch, featureset):
raise RuntimeError("default-flavour %s for %s %s does not exist"
% (self.default_flavour, arch, featureset))
self.quick_flavour = self.config.merge('base', arch, featureset) \
.get('quick-flavour')
flavour_makeflags_base = (
('compiler', 'COMPILER', False),
('compiler-filename', 'COMPILER', True),
('kernel-arch', 'KERNEL_ARCH', False),
('cflags', 'KCFLAGS', True),
('kernel-deb-arch', 'KERNEL_DEB_ARCH', True),
('kernel-gnu-type', 'KERNEL_GNU_TYPE', True),
('compat-deb-arch', 'COMPAT_DEB_ARCH', True),
('compat-gnu-type', 'COMPAT_GNU_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) -> None:
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, arch, featureset,
flavour, vars, makeflags) -> None:
ruleid = (arch, featureset, flavour)
packages_headers = (
self.bundle.add('headers', ruleid, makeflags, vars, arch=arch)
)
assert len(packages_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_packages = self.config.merge('packages', arch, featureset,
flavour)
def config_entry_image(key, *args, **kwargs) -> Any:
return self.config.get_merge(
'image', arch, featureset, flavour, key, *args, **kwargs)
compiler = config_entry_base.get('compiler', 'gcc')
relation_compiler = PackageRelationEntry(compiler)
relation_compiler_header = PackageRelationGroup([relation_compiler])
# Generate compiler build-depends for native:
# gcc-13 [arm64] <!cross !pkg.linux.nokernel>
self.bundle.packages['source']['Build-Depends-Arch'].merge([
PackageRelationEntry(
relation_compiler,
arches={arch},
restrictions='<!cross !pkg.linux.nokernel>',
)
])
# Generate compiler build-depends for cross:
# gcc-13-aarch64-linux-gnu [arm64] <cross !pkg.linux.nokernel>
self.bundle.packages['source']['Build-Depends-Arch'].merge([
PackageRelationEntry(
relation_compiler,
name=f'{relation_compiler.name}-{vars["gnu-type-package"]}',
arches={arch},
restrictions='<cross !pkg.linux.nokernel>',
)
])
# Generate compiler build-depends for kernel:
# gcc-13-hppa64-linux-gnu [hppa] <!pkg.linux.nokernel>
if gnutype := config_entry_base.get('kernel-gnu-type'):
self.bundle.packages['source']['Build-Depends-Arch'].merge([
PackageRelationEntry(
relation_compiler,
name=f'{relation_compiler.name}-{gnutype}',
arches={arch},
restrictions='<!pkg.linux.nokernel>',
)
])
# Generate compiler build-depends for compat:
# gcc-arm-linux-gnueabihf [arm64] <!pkg.linux.nokernel>
# XXX: Linux uses various definitions for this, all ending with "gcc", not $CC
if gnutype := config_entry_base.get('compat-gnu-type'):
self.bundle.packages['source']['Build-Depends-Arch'].merge([
PackageRelationEntry(
f'gcc-{gnutype}',
arches={arch},
restrictions='<!pkg.linux.nokernel>',
)
])
packages_own = []
if not self.disable_signed:
build_signed = config_entry_build.get('signed-code')
else:
build_signed = False
if build_signed:
bundle_signed = self.bundles[f'signed-{arch}']
else:
bundle_signed = self.bundle
vars.setdefault('desc', None)
packages_image = []
if build_signed:
packages_image.extend(
bundle_signed.add('signed.image', ruleid, makeflags, vars, arch=arch))
packages_image.extend(
self.bundle.add('image-unsigned', ruleid, makeflags, vars, arch=arch))
else:
packages_image.extend(bundle_signed.add('image', ruleid, makeflags, vars, arch=arch))
for field in ('Depends', 'Provides', 'Suggests', 'Recommends',
'Conflicts', 'Breaks'):
for i in config_entry_image(field.lower(), ()):
for package_image in packages_image:
package_image.setdefault(field).merge(
PackageRelationGroup(i, arches={arch})
)
for field in ('Depends', 'Suggests', 'Recommends'):
for i in config_entry_image(field.lower(), ()):
group = PackageRelationGroup(i, arches={arch})
for entry in group:
if entry.operator is not None:
entry.operator = -entry.operator
for package_image in packages_image:
package_image.setdefault('Breaks').append(PackageRelationGroup([entry]))
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()
for package_image in packages_image:
desc = package_image['Description']
for part in parts:
desc.append(config_entry_description['part-long-' + part])
desc.append_short(config_entry_description
.get('part-short-' + part, ''))
packages_headers[0]['Depends'].merge(relation_compiler_header)
packages_own.extend(packages_image)
packages_own.extend(packages_headers)
# The image meta-packages will depend on signed linux-image
# packages where applicable, so should be built from the
# signed source packages The header meta-packages will also 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:
packages_meta = (
self.bundle.add('image.meta', ruleid, makeflags, vars, arch=arch)
)
assert len(packages_meta) == 1
packages_meta += (
self.bundle.add('headers.meta',
ruleid, makeflags, vars, arch=arch)
)
assert len(packages_meta) == 2
if flavour == self.default_flavour \
and not self.vars['source_suffix']:
packages_meta[0].setdefault('Provides') \
.append('linux-image-generic')
packages_meta[1].setdefault('Provides') \
.append('linux-headers-generic')
packages_own.extend(packages_meta)
if config_entry_build.get('vdso', False):
makeflags['VDSO'] = True
packages_own.extend(
self.bundle.add('image-dbg', ruleid, makeflags, vars, arch=arch)
)
if do_meta:
packages_own.extend(
self.bundle.add('image-dbg.meta', ruleid, makeflags, vars, arch=arch)
)
# In a quick build, only build the quick flavour (if any).
if flavour != self.quick_flavour:
for package in packages_own:
package['Build-Profiles'][0].neg.add('pkg.linux.quick')
tests_control = self.templates.get_tests_control('image.tests-control', vars)[0]
tests_control['Depends'].merge(
PackageRelationGroup(package_image['Package'],
arches={arch}))
if self.tests_control_image:
for i in tests_control['Depends']:
self.tests_control_image['Depends'].merge(i)
else:
self.tests_control_image = tests_control
self.tests_control.append(tests_control)
if flavour == (self.quick_flavour or self.default_flavour):
if not self.tests_control_headers:
self.tests_control_headers = \
self.templates.get_tests_control('headers.tests-control', vars)[0]
self.tests_control.append(self.tests_control_headers)
assert self.tests_control_headers is not None
self.tests_control_headers['Architecture'].add(arch)
self.tests_control_headers['Depends'].merge(
PackageRelationGroup(packages_headers[0]['Package'],
arches={arch}))
def get_config(*entry_name) -> Any:
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) -> list[str]:
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) -> list[str]:
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) -> list[str]:
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)
# XXX: We have no way to override kernelarch-X configs
kconfig.extend(check_config_default(False,
"kernelarch-%s/config" % config_entry_base['kernel-arch']))
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'] = ''
# Add "salt" to fix #872263
makeflags['KCONFIG_OPTIONS'] += \
' -o "BUILD_SALT=\\"%(abiname)s%(localversion)s\\""' % vars
merged_config = ('debian/build/config.%s_%s_%s' %
(arch, featureset, flavour))
self.bundle.makefile.add_cmds(merged_config,
["$(MAKE) -f debian/rules.real %s %s" %
(merged_config, makeflags)])
if not self.disable_installer and config_entry_packages.get('installer'):
with tempfile.TemporaryDirectory(prefix='linux-gencontrol') as config_dir:
base_path = pathlib.Path('debian/installer').absolute()
config_path = pathlib.Path(config_dir)
(config_path / 'modules').symlink_to(base_path / 'modules')
(config_path / 'package-list').symlink_to(base_path / 'package-list')
with (config_path / 'kernel-versions').open('w') as versions:
versions.write(f'{arch} - {vars["flavour"]} - - -\n')
# Add udebs using kernel-wedge
kw_env = os.environ.copy()
kw_env['KW_DEFCONFIG_DIR'] = config_dir
kw_env['KW_CONFIG_DIR'] = config_dir
kw_proc = subprocess.Popen(
['kernel-wedge', 'gen-control', vars['abiname']],
stdout=subprocess.PIPE,
text=True,
env=kw_env)
udeb_packages_base = BinaryPackage.read_rfc822(kw_proc.stdout)
kw_proc.wait()
if kw_proc.returncode != 0:
raise RuntimeError('kernel-wedge exited with code %d' %
kw_proc.returncode)
udeb_packages = []
for package_base in udeb_packages_base:
package = package_base.copy()
# kernel-wedge currently chokes on Build-Profiles so add it now
package['Build-Profiles'] = (
'<!noudeb !pkg.linux.nokernel !pkg.linux.quick>')
package.meta['rules-target'] = 'installer'
udeb_packages.append(package)
makeflags_local = makeflags.copy()
makeflags_local['IMAGE_PACKAGE_NAME'] = udeb_packages[0]['Package']
bundle_signed.add_packages(
udeb_packages,
(arch, featureset, flavour),
makeflags_local, arch=arch,
)
if build_signed:
udeb_packages = []
# 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.
for package_base in udeb_packages_base:
package = package_base.copy()
# kernel-wedge currently chokes on Build-Profiles so add it now
package['Build-Profiles'] = (
'<pkg.linux.udeb-unsigned-test-build !noudeb'
' !pkg.linux.nokernel !pkg.linux.quick>')
package.meta['rules-target'] = 'installer-test'
udeb_packages.append(package)
self.bundle.add_packages(
udeb_packages,
(arch, featureset, flavour),
makeflags, arch=arch, check_packages=False,
)
def process_changelog(self) -> None:
version = self.version = self.changelog[0].version
if self.changelog[0].distribution == 'UNRELEASED':
self.abiname = f'{version.linux_upstream}+unreleased'
elif self.changelog[0].distribution == 'experimental':
self.abiname = f'{version.linux_upstream}'
elif version.linux_revision_backports:
self.abiname = f'{version.linux_upstream_full}+bpo'
else:
self.abiname = f'{version.linux_upstream_full}'
self.vars = {
'upstreamversion': self.version.linux_upstream,
'version': self.version.linux_version,
'version_complete': self.version.complete,
'source_basename': re.sub(r'-[\d.]+$', '',
self.changelog[0].source),
'source_upstream': self.version.upstream,
'source_package': self.changelog[0].source,
'abiname': self.abiname,
}
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,
'abiname': self.abiname}
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 write(self) -> None:
self.write_config()
super().write()
self.write_tests_control()
self.write_signed()
def write_config(self) -> None:
f = open("debian/config.defines.dump", 'wb')
self.config.dump(f)
f.close()
def write_signed(self) -> None:
for bundle in self.bundles.values():
pkg_sign_entries = {}
for p in bundle.packages.values():
if pkg_sign_pkg := p.meta.get('sign-package'):
pkg_sign_entries[pkg_sign_pkg] = {
'trusted_certs': [],
'files': [
{
'sig_type': e.split(':', 1)[-1],
'file': e.split(':', 1)[0],
}
for e in p.meta['sign-files'].split()
],
}
if pkg_sign_entries:
with bundle.path('files.json').open('w') as f:
json.dump({'packages': pkg_sign_entries}, f, indent=2)
def write_tests_control(self) -> None:
self.bundle.write_rfc822(open("debian/tests/control", 'w'),
self.tests_control)
if __name__ == '__main__':
Gencontrol()()