Skip to content

Commit

Permalink
Add support for architectures in deb source file
Browse files Browse the repository at this point in the history
When apt resolves packages on a multiarch repo it can happen
that dependencies for packages from other architectures are
pulled into the solver process but are not provided by any
repository. To overcome this behavior the repository can
be setup to serve packages only for a specified architecture
or list of architectures. This is related to
OSInside/kiwi-descriptions#102
  • Loading branch information
schaefi committed Sep 9, 2024
1 parent 322eb33 commit 3e5023e
Show file tree
Hide file tree
Showing 18 changed files with 79 additions and 20 deletions.
2 changes: 1 addition & 1 deletion build-tests/arm/ubuntu/test-image-rpi/appliance.kiwi
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
<user password="$1$wYJUgpM5$RXMMeASDc035eX.NbYWFl0" home="/home/ubuntu" name="ubuntu" groups="users,kvm" shell="/bin/bash"/>
</users>

<repository type="apt-deb" alias="kiwi-next-generation" priority="1" repository_gpgcheck="false">
<repository type="apt-deb" alias="kiwi-next-generation" priority="1" repository_gpgcheck="false" architectures="arm64">
<source path="obs://Virtualization:Appliances:Staging/xUbuntu_23.04"/>
</repository>
<repository type="apt-deb" alias="Ubuntu-Lunar-Universe" distribution="lunar" components="main multiverse restricted universe" repository_gpgcheck="false">
Expand Down
2 changes: 1 addition & 1 deletion build-tests/x86/debian/test-image-live-disk/appliance.kiwi
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
<users>
<user password="$1$wYJUgpM5$RXMMeASDc035eX.NbYWFl0" home="/root" name="root" groups="root"/>
</users>
<repository type="apt-deb" repository_gpgcheck="false">
<repository type="apt-deb" repository_gpgcheck="false" architectures="amd64">
<source path="obs://Virtualization:Appliances:Staging/Debian_12"/>
</repository>
<repository type="apt-deb" distribution="bookworm" components="main contrib non-free" repository_gpgcheck="false">
Expand Down
2 changes: 1 addition & 1 deletion build-tests/x86/ubuntu/test-image-docker/appliance.kiwi
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
<users>
<user name="vagrant" password="vh4vw1N4alxKQ" home="/home/vagrant" groups="vagrant"/>
</users>
<repository type="apt-deb" alias="kiwi-next-generation" priority="1" repository_gpgcheck="false">
<repository type="apt-deb" alias="kiwi-next-generation" priority="1" repository_gpgcheck="false" architectures="amd64">
<source path="obs://Virtualization:Appliances:Staging/xUbuntu_23.04"/>
</repository>
<repository type="apt-deb" alias="Ubuntu-Lunar-Universe" distribution="lunar" components="main multiverse restricted universe" repository_gpgcheck="false">
Expand Down
2 changes: 1 addition & 1 deletion build-tests/x86/ubuntu/test-image-live-disk/appliance.kiwi
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
<users>
<user password="$1$wYJUgpM5$RXMMeASDc035eX.NbYWFl0" home="/root" name="root" groups="root"/>
</users>
<repository type="apt-deb" alias="kiwi-next-generation" priority="1" repository_gpgcheck="false">
<repository type="apt-deb" alias="kiwi-next-generation" priority="1" repository_gpgcheck="false" architectures="amd64">
<source path="obs://Virtualization:Appliances:Staging/xUbuntu_23.04"/>
</repository>
<repository type="apt-deb" alias="Ubuntu-Lunar-Universe" distribution="lunar" components="main multiverse restricted universe" repository_gpgcheck="false">
Expand Down
9 changes: 8 additions & 1 deletion kiwi/repository/apt.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,8 @@ def add_repo(
prio: int = None, dist: str = None, components: str = None,
user: str = None, secret: str = None, credentials_file: str = None,
repo_gpgcheck: bool = None, pkg_gpgcheck: bool = None,
sourcetype: str = None, customization_script: str = None
sourcetype: str = None, customization_script: str = None,
architectures: str = None
) -> None:
"""
Add apt_get repository
Expand All @@ -157,6 +158,8 @@ def add_repo(
:param str sourcetype: unused
:param str customization_script:
custom script called after the repo file was created
:param str architectures:
identifies which architectures are supported by this repository
"""
sources_file = '/'.join(
[self.shared_apt_get_dir['sources-dir'], name + '.sources']
Expand All @@ -175,6 +178,10 @@ def add_repo(
with open(sources_file, 'w') as repo:
repo_details = 'Types: deb' + os.linesep
repo_details += 'URIs: ' + uri + os.linesep
if architectures:
repo_details += 'Architectures: {}{}'.format(
architectures.replace(',', ' '), os.linesep
)
if not dist:
# create a debian flat repository setup. We consider the
# repository metadata to exist on the toplevel of the
Expand Down
3 changes: 2 additions & 1 deletion kiwi/repository/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ def add_repo(
self, name: str, uri: str, repo_type: str, prio: int, dist: str,
components: str, user: str, secret: str, credentials_file: str,
repo_gpgcheck: bool, pkg_gpgcheck: bool, sourcetype: str,
customization_script: str = None
customization_script: str = None, architectures: str = None
) -> None:
"""
Add repository
Expand All @@ -97,6 +97,7 @@ def add_repo(
:param bool pkg_gpgcheck: unused
:param str sourcetype: unused
:param str customization_script: unused
:param str architectures: unused
"""
raise NotImplementedError

Expand Down
4 changes: 3 additions & 1 deletion kiwi/repository/dnf4.py
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,8 @@ def add_repo(
prio: int = None, dist: str = None, components: str = None,
user: str = None, secret: str = None, credentials_file: str = None,
repo_gpgcheck: bool = False, pkg_gpgcheck: bool = False,
sourcetype: str = None, customization_script: str = None
sourcetype: str = None, customization_script: str = None,
architectures: str = None
) -> None:
"""
Add dnf repository
Expand All @@ -212,6 +213,7 @@ def add_repo(
source type, one of 'baseurl', 'metalink' or 'mirrorlist'
:param str customization_script:
custom script called after the repo file was created
:param str architectures: unused
"""
repo_file = self.shared_dnf_dir['reposd-dir'] + '/' + name + '.repo'
self.repo_names.append(name + '.repo')
Expand Down
4 changes: 3 additions & 1 deletion kiwi/repository/dnf5.py
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,8 @@ def add_repo(
prio: int = None, dist: str = None, components: str = None,
user: str = None, secret: str = None, credentials_file: str = None,
repo_gpgcheck: bool = False, pkg_gpgcheck: bool = False,
sourcetype: str = None, customization_script: str = None
sourcetype: str = None, customization_script: str = None,
architectures: str = None
) -> None:
"""
Add dnf repository
Expand All @@ -212,6 +213,7 @@ def add_repo(
source type, one of 'baseurl', 'metalink' or 'mirrorlist'
:param str customization_script:
custom script called after the repo file was created
:param str architectures: unused
"""
repo_file = self.shared_dnf_dir['reposd-dir'] + '/' + name + '.repo'
self.repo_names.append(name + '.repo')
Expand Down
4 changes: 3 additions & 1 deletion kiwi/repository/pacman.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,8 @@ def add_repo(
prio: int = None, dist: str = None, components: str = None,
user: str = None, secret: str = None, credentials_file: str = None,
repo_gpgcheck: bool = False, pkg_gpgcheck: bool = False,
sourcetype: str = None, customization_script: str = None
sourcetype: str = None, customization_script: str = None,
architectures: str = None
) -> None:
"""
Add pacman repository
Expand All @@ -134,6 +135,7 @@ def add_repo(
:param str sourcetype: unused
:param str customization_script:
custom script called after the repo file was created
:param str architectures: unused
"""
repo_file = '{0}/{1}.repo'.format(
self.shared_pacman_dir['repos-dir'], name
Expand Down
4 changes: 3 additions & 1 deletion kiwi/repository/zypper.py
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,8 @@ def add_repo(
prio: int = None, dist: str = None, components: str = None,
user: str = None, secret: str = None, credentials_file: str = None,
repo_gpgcheck: bool = False, pkg_gpgcheck: bool = False,
sourcetype: str = None, customization_script: str = None
sourcetype: str = None, customization_script: str = None,
architectures: str = None
) -> None:
"""
Add zypper repository
Expand All @@ -271,6 +272,7 @@ def add_repo(
:param str sourcetype: unused
:param str customization_script:
custom script called after the repo file was created
:param str architectures: unused
"""
if credentials_file:
repo_secret = os.sep.join(
Expand Down
14 changes: 12 additions & 2 deletions kiwi/schema/kiwi.rnc
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ volume-size-type = xsd:token {pattern = "(\d+|\d+M|\d+G|all)"}
partition-size-type = xsd:token {pattern = "(\d+|\d+M|\d+G)"}
vhd-tag-type = xsd:token {pattern = "[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}"}
groups-list = xsd:token {pattern = "[a-zA-Z0-9_\-\.:]+(,[a-zA-Z0-9_\-\.:]+)*"}
arch-name = xsd:token {pattern = "(x86_64|i586|i686|ix86|aarch64|arm64|armv5el|armv5tel|armv6hl|armv6l|armv7hl|armv7l|ppc|ppc64|ppc64le|s390|s390x|riscv64)(,(x86_64|i586|i686|ix86|aarch64|arm64|armv5el|armv5tel|armv6hl|armv6l|armv7hl|armv7l|ppc|ppc64|ppc64le|s390|s390x|riscv64))*"}
arch-name = xsd:token {pattern = "(x86_64|i586|i686|ix86|aarch64|arm64|amd64|armv5el|armv5tel|armv6hl|armv6l|armv7hl|armv7l|ppc|ppc64|ppc64le|s390|s390x|riscv64)(,(x86_64|i586|i686|ix86|aarch64|arm64|amd64|armv5el|armv5tel|armv6hl|armv6l|armv7hl|armv7l|ppc|ppc64|ppc64le|s390|s390x|riscv64))*"}
portnum-type = xsd:token {pattern = "(\d+|\d+/(udp|tcp))"}
grub_console = xsd:token {pattern = "(none|console|gfxterm|serial|vga_text|mda_text|morse|spkmodem)( (none|console|serial|at_keyboard|usb_keyboard))*"}
fs_attributes = xsd:token {pattern = "(no-copy-on-write|synchronous-updates)(,(no-copy-on-write|synchronous-updates))*"}
Expand Down Expand Up @@ -1135,6 +1135,15 @@ div {
attribute sourcetype {
"baseurl" | "metalink" | "mirrorlist"
}
k.repository.architectures.attribute =
## Specifies for which architecture(s) this repository is
## supposed to provide packages. Multiple architecture names
## needs to be separated by a comma
attribute architectures { arch-name }
>> sch:pattern [ id = "architectures" is-a = "repo_type"
sch:param [ name = "attr" value = "architectures" ]
sch:param [ name = "types" value = "apt-deb" ]
]
k.repository.attlist =
k.repository.type.attribute? &
k.repository.profiles.attribute? &
Expand All @@ -1152,7 +1161,8 @@ div {
k.repository.package_gpgcheck.attribute? &
k.repository.priority.attribute? &
k.repository.password.attribute? &
k.repository.username.attribute?
k.repository.username.attribute? &
k.repository.architectures.attribute?
k.repository =
## The Name of the Repository
element repository {
Expand Down
17 changes: 16 additions & 1 deletion kiwi/schema/kiwi.rng
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@
</define>
<define name="arch-name">
<data type="token">
<param name="pattern">(x86_64|i586|i686|ix86|aarch64|arm64|armv5el|armv5tel|armv6hl|armv6l|armv7hl|armv7l|ppc|ppc64|ppc64le|s390|s390x|riscv64)(,(x86_64|i586|i686|ix86|aarch64|arm64|armv5el|armv5tel|armv6hl|armv6l|armv7hl|armv7l|ppc|ppc64|ppc64le|s390|s390x|riscv64))*</param>
<param name="pattern">(x86_64|i586|i686|ix86|aarch64|arm64|amd64|armv5el|armv5tel|armv6hl|armv6l|armv7hl|armv7l|ppc|ppc64|ppc64le|s390|s390x|riscv64)(,(x86_64|i586|i686|ix86|aarch64|arm64|amd64|armv5el|armv5tel|armv6hl|armv6l|armv7hl|armv7l|ppc|ppc64|ppc64le|s390|s390x|riscv64))*</param>
</data>
</define>
<define name="portnum-type">
Expand Down Expand Up @@ -1728,6 +1728,18 @@ be a simple repository url</a:documentation>
</choice>
</attribute>
</define>
<define name="k.repository.architectures.attribute">
<attribute name="architectures">
<a:documentation>Specifies for which architecture(s) this repository is
supposed to provide packages. Multiple architecture names
needs to be separated by a comma</a:documentation>
<ref name="arch-name"/>
</attribute>
<sch:pattern id="architectures" is-a="repo_type">
<sch:param name="attr" value="architectures"/>
<sch:param name="types" value="apt-deb"/>
</sch:pattern>
</define>
<define name="k.repository.attlist">
<interleave>
<optional>
Expand Down Expand Up @@ -1775,6 +1787,9 @@ be a simple repository url</a:documentation>
<optional>
<ref name="k.repository.username.attribute"/>
</optional>
<optional>
<ref name="k.repository.architectures.attribute"/>
</optional>
</interleave>
</define>
<define name="k.repository">
Expand Down
4 changes: 3 additions & 1 deletion kiwi/system/prepare.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ def setup_repositories(
for xml_repo in repository_sections:
repo_type = xml_repo.get_type()
repo_source = xml_repo.get_source().get_path()
repo_architectures = xml_repo.get_architectures()
repo_user = xml_repo.get_username()
repo_secret = xml_repo.get_password()
repo_alias = xml_repo.get_alias()
Expand Down Expand Up @@ -209,7 +210,8 @@ def setup_repositories(
repo_type, repo_priority, repo_dist, repo_components,
repo_user, repo_secret, uri.credentials_file_name(),
repo_repository_gpgcheck, repo_package_gpgcheck,
repo_sourcetype, repo_customization_script
repo_sourcetype, repo_customization_script,
repo_architectures
)
if clear_cache:
repo.delete_repo_cache(repo_alias)
Expand Down
4 changes: 3 additions & 1 deletion kiwi/system/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ def import_repositories_marked_as_imageinclude(self) -> None:
for xml_repo in repository_sections:
repo_type = xml_repo.get_type()
repo_source = xml_repo.get_source().get_path()
repo_architectures = xml_repo.get_architectures()
repo_user = xml_repo.get_username()
repo_secret = xml_repo.get_password()
repo_alias = xml_repo.get_alias()
Expand Down Expand Up @@ -184,7 +185,8 @@ def import_repositories_marked_as_imageinclude(self) -> None:
repo_type, repo_priority, repo_dist, repo_components,
repo_user, repo_secret, uri.credentials_file_name(),
repo_repository_gpgcheck, repo_package_gpgcheck,
repo_sourcetype, repo_customization_script
repo_sourcetype, repo_customization_script,
repo_architectures
)

def import_cdroot_files(self, target_dir: str) -> None:
Expand Down
14 changes: 13 additions & 1 deletion kiwi/xml_parse.py
Original file line number Diff line number Diff line change
Expand Up @@ -2442,7 +2442,7 @@ class repository(k_source):
"""The Name of the Repository"""
subclass = None
superclass = k_source
def __init__(self, source=None, type_=None, profiles=None, arch=None, alias=None, sourcetype=None, components=None, distribution=None, imageinclude=None, imageonly=None, repository_gpgcheck=None, customize=None, package_gpgcheck=None, priority=None, password=None, username=None):
def __init__(self, source=None, type_=None, profiles=None, arch=None, alias=None, sourcetype=None, components=None, distribution=None, imageinclude=None, imageonly=None, repository_gpgcheck=None, customize=None, package_gpgcheck=None, priority=None, password=None, username=None, architectures=None):
self.original_tagname_ = None
super(repository, self).__init__(source, )
self.type_ = _cast(None, type_)
Expand All @@ -2460,6 +2460,7 @@ def __init__(self, source=None, type_=None, profiles=None, arch=None, alias=None
self.priority = _cast(int, priority)
self.password = _cast(None, password)
self.username = _cast(None, username)
self.architectures = _cast(None, architectures)
def factory(*args_, **kwargs_):
if CurrentSubclassModule_ is not None:
subclass = getSubclassFromModule_(
Expand Down Expand Up @@ -2501,6 +2502,8 @@ def get_password(self): return self.password
def set_password(self, password): self.password = password
def get_username(self): return self.username
def set_username(self, username): self.username = username
def get_architectures(self): return self.architectures
def set_architectures(self, architectures): self.architectures = architectures
def validate_arch_name(self, value):
# Validate type arch-name, a restriction on xs:token.
if value is not None and Validate_simpletypes_:
Expand Down Expand Up @@ -2590,6 +2593,9 @@ def exportAttributes(self, outfile, level, already_processed, namespaceprefix_='
if self.username is not None and 'username' not in already_processed:
already_processed.add('username')
outfile.write(' username=%s' % (self.gds_encode(self.gds_format_string(quote_attrib(self.username), input_name='username')), ))
if self.architectures is not None and 'architectures' not in already_processed:
already_processed.add('architectures')
outfile.write(' architectures=%s' % (quote_attrib(self.architectures), ))
def exportChildren(self, outfile, level, namespaceprefix_='', name_='repository', fromsubclass_=False, pretty_print=True):
super(repository, self).exportChildren(outfile, level, namespaceprefix_, name_, True, pretty_print=pretty_print)
def build(self, node):
Expand Down Expand Up @@ -2689,6 +2695,12 @@ def buildAttributes(self, node, attrs, already_processed):
if value is not None and 'username' not in already_processed:
already_processed.add('username')
self.username = value
value = find_attr_value_('architectures', node)
if value is not None and 'architectures' not in already_processed:
already_processed.add('architectures')
self.architectures = value
self.architectures = ' '.join(self.architectures.split())
self.validate_arch_name(self.architectures) # validate type arch-name
super(repository, self).buildAttributes(node, attrs, already_processed)
def buildChildren(self, child_, node, nodeName_, fromsubclass_=False):
super(repository, self).buildChildren(child_, node, nodeName_, True)
Expand Down
4 changes: 3 additions & 1 deletion test/unit/repository/apt_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,11 +151,13 @@ def test_add_repo_distribution(self, mock_exists):
mock_open.return_value = MagicMock(spec=io.IOBase)
file_handle = mock_open.return_value.__enter__.return_value
self.repo.add_repo(
'foo', 'kiwi_iso_mount/uri', 'deb', None, 'xenial', 'a b'
'foo', 'kiwi_iso_mount/uri', 'deb', None, 'xenial', 'a b',
architectures='amd64,arm64'
)
file_handle.write.assert_called_once_with(
'Types: deb\n'
'URIs: file:/kiwi_iso_mount/uri\n'
'Architectures: amd64 arm64\n'
'Suites: xenial\n'
'Components: a b\n'
)
Expand Down
4 changes: 2 additions & 2 deletions test/unit/system/prepare_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -287,12 +287,12 @@ def test_setup_repositories(
call(
'uri-alias', 'uri', None, 42,
None, None, None, None, 'credentials-file', None, None,
'baseurl', None
'baseurl', None, None
),
call(
'uri-alias', 'uri', 'rpm-md', None,
None, None, None, None, 'credentials-file', None, None,
None, '../data/script'
None, '../data/script', None
)
]
assert repo.delete_repo_cache.call_args_list == [
Expand Down
2 changes: 1 addition & 1 deletion test/unit/system/setup_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -1678,7 +1678,7 @@ def test_import_repositories_marked_as_imageinclude(
self.setup_with_real_xml.import_repositories_marked_as_imageinclude()
assert repo.add_repo.call_args_list[0] == call(
'uri-alias', 'uri', 'rpm-md', None, None, None, None, None,
'kiwiRepoCredentials', None, None, None, '../data/script'
'kiwiRepoCredentials', None, None, None, '../data/script', None
)

@patch('os.path.exists')
Expand Down

0 comments on commit 3e5023e

Please sign in to comment.