diff --git a/README.aptly.md b/README.aptly.md index 1c96e8f651e406971d7e6e537cb8e32f76139efe..7ee4fd6b5c018c96255b51afb210597a71dfc144 100644 --- a/README.aptly.md +++ b/README.aptly.md @@ -22,89 +22,139 @@ configurations defined in order to use the aptly backend. ### aptly repositories hash -The OBS configuration files must provide a hash named `aptly_config` with the +The OBS configuration files must provide a hash named `aptly_projects` with the following structure: ``` -our $aptly_config = { - "prefix_path" => { - "distribution_name" => { - "gpg-key" => "optional_gpg_hash", - "components" => { - "component_name" => { - "project" => "obs_project_id", - "repository" => "obs_repository_id", - }, - [...] - }, +our $aptly_projects = { + "obs_project_id" => { + "obs_repository_id" => { + "target" => "repository_name", + "distribution" => "distribution_name", + "component" => "component_name", + "gpg-key" => "optional_gpg_hash", }, [...] }, + [...] }; ``` -NOTE: a pair `(obs_project_id, obs_repository_id)` can only be appear once in -the hash, i.e. it can't be a component of more than one distribution. +For each `repository_name`, there must be an entry in a hash `aptly_targets`: + +``` +our $aptly_targets = { + "repository_name" => { + "server" => { + "url" => "https://...", + "token" => "...", + }, + "gpg-key" => "gpg_hash", + "prefix" => "prefix_path", + } +}; +``` -For example, for an Apertis v2022 release: +Instead of specifying `target` and a corresponding entry in `aptly_targets`, +it’s also possible to configure the aptly endpoint directly using +`aptly-server` hash (see example below). + +For example, for an Apertis v2025 release: * publish prefix path set to: `shared/apertis/public`. -* 3 distributions defined: `v2022`, `v2022-security`, `v2022-updates`. +* 3 distributions defined: `v2025`, `v2025-security`, `v2025-updates`. * each distribution has 3 components: `target`, `development`, `sdk`. * for each component, the OBS project and repository is defined. -* as an example, `v2022` will be published using the `gpg-key` defined for this +* `rebuild` repository for `sdk` is published at a separate aptly instance which + is specified inline using `aptly-server` setting. +* as an example, `v2025` will be published using the `gpg-key` defined for this distribution. Otherwise, the default `gpg-key` is used. ``` -our $aptly_config = { - "shared/apertis/public" => { - "v2022" => { - "gpg-key" => "8E62938108AE643A217D0511027B2E6C53229B30", - "components" => { - "target" => { - "project" => "apertis:v2022:target", - "repository" => "default", - }, - "development" => { - "project" => "apertis:v2022:development", - "repository" => "default", - }, - "sdk" => { - "project" => "apertis:v2022:sdk", - "repository" => "default", - }, - }, +my $apertis_aptly_server = { + "url" => "https://...", + "token" => "...", +}; + +our $aptly_repos = { + "apertis" => { + "server" => $apertis_aptly_server + "gpg-key" => $aptly_gpgkey, + "prefix" => "shared/apertis/public", + } +}; + +our $aptly_projects = { + "apertis:v2025:target" => { + "default" => { + "target" => "apertis", + "distribution" => "v2025", + "component" => "target", + } + }, + "apertis:v2025:development" => { + "default" => { + "target" => "apertis", + "distribution" => "v2025", + "component" => "development", + } + }, + "apertis:v2025:sdk" => { + "default" => { + "target" => "apertis", + "distribution" => "v2025", + "component" => "sdk", }, - "v2022-security" => { - "components" => { - "target" => { - "project" => "apertis:v2022:security:target", - "repository" => "default", - }, - "development" => { - "project" => "apertis:v2022:security:development", - "repository" => "default", - }, - "sdk" => { - "project" => "apertis:v2022:security:sdk", - "repository" => "default", - }, + "rebuild" => { + "distribution" => "v2025", + "component" => "sdk", + "gpg-key" => "...", + "prefix" => "apertis", + "aptly-server" => { + "url" => "https://rebuilds.apertis.org", + "token" => "tokentoken", }, }, - "v2022-updates" => { - "components" => { - "target" => { - "project" => "apertis:v2022:updates:target", - "repository" => "default", - }, - "development" => { - "project" => "apertis:v2022:updates:development", - "repository" => "default", - }, - "sdk" => { - "project" => "apertis:v2022:updates:sdk", - "repository" => "default", - }, - }, + }, + "apertis:v2025:updates:target" => { + "default" => { + "target" => "apertis", + "distribution" => "v2025-updates", + "component" => "target", + } + }, + "apertis:v2025:updates:development" => { + "default" => { + "target" => "apertis", + "distribution" => "v2025-updates", + "component" => "development", + } + }, + "apertis:v2025:updates:sdk" => { + "default" => { + "target" => "apertis", + "distribution" => "v2025-updates", + "component" => "sdk", + }, + }, + "apertis:v2025:security:target" => { + "default" => { + "target" => "apertis", + "distribution" => "v2025-security", + "component" => "target", + } + }, + "apertis:v2025:security:development" => { + "default" => { + "target" => "apertis", + "distribution" => "v2025-security", + "component" => "development", + } + }, + "apertis:v2025:security:sdk" => { + "default" => { + "target" => "apertis", + "distribution" => "v2025-security", + "component" => "sdk", }, }, }; diff --git a/src/backend/BSAptly.pm b/src/backend/BSAptly.pm old mode 100755 new mode 100644 index d7d2e91084af6a5c25c7a6064b4ff89a57f3a4ad..78751e80d0c42c9fc7d3d104939f31af0b248cf9 --- a/src/backend/BSAptly.pm +++ b/src/backend/BSAptly.pm @@ -1,4 +1,3 @@ -#!/usr/bin/perl -w # # SPDX-License-Identifier: GPL-2.0+ # @@ -14,12 +13,19 @@ use Build::Deb; use POSIX qw(strftime); use strict; +# TODO: drop "no warnings" when upgraded to Perl 5.36 +no warnings 'experimental::signatures'; +use feature 'signatures'; +use feature 'say'; our %aptly_config_projects; BEGIN { - # From the aptly configuration, generate hash mapping project and repositories + # From the obsolete aptly configuration, generate hash mapping project and repositories # to the distribution where they live. + say STDERR 'WARNING: Deprecated configuration option \$aptly_config used, please use $aptly_projects instead!' + if defined $BSConfig::aptly_config; + foreach my $prefix (keys %{ $BSConfig::aptly_config }) { my $distros = $BSConfig::aptly_config->{$prefix}; foreach my $distro (keys %{ $distros }) { @@ -36,6 +42,43 @@ BEGIN { } } } + + my $repo_components = {}; + + foreach my $projid (keys %{$BSConfig::aptly_projects}) { + my $repos = $BSConfig::aptly_projects->{$projid}; + foreach my $repoid (keys %{$repos}) { + my $repo_config = $repos->{$repoid}; + if (defined $repo_config->{'target'}) { + my $target_config = $BSConfig::aptly_targets->{$repo_config->{'target'}}; + die "$projid/$repoid refers to an undefined target repository $repo_config->{'target'}" if !defined $target_config; + + $repo_config->{'aptly-server'} ||= $target_config->{'server'}; + $repo_config->{'gpg-key'} ||= $target_config->{'gpg-key'}; + $repo_config->{'prefix'} ||= $target_config->{'prefix'}; + } + + die "$projid/$repoid does not have either aptly-server or target defined" if !defined $repo_config->{'aptly-server'}; + die "$projid/$repoid does not have prefix defined" if !defined $repo_config->{'prefix'}; + die "$projid/$repoid does not have distribution defined" if !defined $repo_config->{'distribution'}; + + # OBS gives us a single OBS project/repoid, but we need to publish all projects in the same prefix at once + # For this reason, we need to share the components set, which means that we (confusingly) have aptly + # repo-specific configs that contain information about their sibling repos. + my $all_components_in_prefix = ($repo_components + ->{$repo_config->{'aptly-server'}} + ->{$repo_config->{'prefix'}} + ->{$repo_config->{'distribution'}} + ->{'components'} ||= {}); + $all_components_in_prefix->{$repo_config->{'component'}} = { + 'project' => $projid, + 'repository' => $repoid, + 'component' => $repo_config->{'component'}, + }; + $repo_config->{'components'} = $all_components_in_prefix; + $aptly_config_projects{$projid}{$repoid} = $repo_config; + } + } } sub api_tool_exec { @@ -70,23 +113,15 @@ sub obs2aptly_exec { # Aptly configuration helpers -sub aptly_distro_get_config { - my ($prefix, $distro) = @_; - return $BSConfig::aptly_config->{$prefix}{$distro}; -} - -sub aptly_project_get_config { - my ($projid) = @_; +sub aptly_project_get_config($projid) { return $aptly_config_projects{$projid}; } -sub aptly_repo_get_config { - my ($projid, $repoid) = @_; +sub aptly_repo_get_config($projid, $repoid) { return $aptly_config_projects{$projid}{$repoid}; } -sub aptly_repo_get_component { - my ($projid, $repoid) = @_; +sub aptly_repo_get_component($projid, $repoid) { my $repo_config = aptly_repo_get_config($projid, $repoid); my $distro_components = $repo_config->{'components'}; foreach my $component (keys %$distro_components) { @@ -100,13 +135,11 @@ sub aptly_repo_get_component { # OBS objects helpers -sub obs_get_project { - my ($projid) = @_; +sub obs_get_project($projid) { return BSRevision::readproj_local($projid, 1); } -sub obs_get_repo { - my ($projid, $repoid) = @_; +sub obs_get_repo($projid, $repoid) { my $obs_proj = obs_get_project($projid); if (!$obs_proj || !$obs_proj->{'repository'}) { return undef; @@ -119,10 +152,9 @@ sub obs_get_repo { return undef; } -sub obs_project_repos { +sub obs_project_repos($proj) { # From an OBS project, get all its repositories names in a hash. Only those # repositories configured in aptly are included. - my ($proj) = @_; my %ret; if ($proj && $proj->{'repository'}) { foreach my $repo (@{ $proj->{'repository'} }) { @@ -134,23 +166,24 @@ sub obs_project_repos { return \%ret; } -sub aptly_publish_repo { +sub aptly_publish_repo($projid, $repoid) { # Given a prefix and distribution, publish a set of multi-component # repositories. A repository is included only if: - # * it's defined in the aptly config for this prefix/distribution. + # * it's defined in the aptly config. # * the publish flag is enabled on OBS for the related project/repository. - # Note that, as this included multiple OBS repositories, the archs defined - # for each one might differ. So the union of all the enabled archs is used + # Note that, as this included multiple OBS repositories, the arches defined + # for each one might differ. So the union of all the enabled arches is used # when publishing. - my ($prefix, $distribution) = @_; - my %archs; + my %arches; my @to_publish; - my $distro_config = aptly_distro_get_config($prefix, $distribution); - my $distro_components = $distro_config->{'components'}; + my $repo_config = aptly_repo_get_config($projid, $repoid); + my $repo_components = $repo_config->{'components'}; + my $prefix = $repo_config->{'prefix'}; + my $distribution = $repo_config->{'distribution'}; - foreach my $component (keys %$distro_components) { - my $component_config = $distro_components->{$component}; + foreach my $component (keys %$repo_components) { + my $component_config = $repo_components->{$component}; my $projid = $component_config->{'project'}; my $repoid = $component_config->{'repository'}; my $obs_proj = obs_get_project($projid); @@ -161,53 +194,55 @@ sub aptly_publish_repo { push @to_publish, "$projid/$repoid//$component"; foreach my $arch (@{ $obs_repo->{'arch'} }) { if (BSUtil::enabled($repoid, $obs_proj->{'publish'}, 1, $arch)) { - $archs{$arch} = 1; + $arches{$arch} = 1; } } } - if (!%archs) { + if (!%arches) { return 0; } - my $gpgkey = $distro_config->{'gpg-key'} || $BSConfig::aptly_defconfig->{'gpg-key'}; + my $gpgkey = $repo_config->{'gpg-key'} || $BSConfig::aptly_defconfig->{'gpg-key'}; my @args = ('publish', 'create', 'repo', - (map { "--architecture=".Build::Deb::basearch($_) } (('source'), keys %archs)), + (map { + "--architecture=".Build::Deb::basearch($_) + } (('source'), keys %arches)), "--distribution=$distribution", '--skip-contents', '--skip-bz2', $prefix, @to_publish); push @args, "--gpg-key=$gpgkey" if $gpgkey; - return aptlyctl_exec($distro_config->{'aptly-server'}, @args); + return aptlyctl_exec($repo_config->{'aptly-server'}, @args); } # Aptly publish command wrappers -sub aptly_publish_drop_check { - my ($prefix, $distribution) = @_; - my $distro_config = aptly_distro_get_config($prefix, $distribution); - my @args = ('publish', 'drop', '--ignore-if-missing', $prefix, $distribution); - return aptlyctl_exec($distro_config->{'aptly-server'}, @args); +sub aptly_publish_drop_check($projid, $repoid) { + my $repo_config = aptly_repo_get_config($projid, $repoid); + my @args = ('publish', 'drop', '--ignore-if-missing', + $repo_config->{'prefix'}, + $repo_config->{'distribution'}); + return aptlyctl_exec($repo_config->{'aptly-server'}, @args); } -sub aptly_publish_update { - my ($prefix, $distribution) = @_; +sub aptly_publish_update($projid, $repoid) { # Update an already published repository distribution - my $distro_config = aptly_distro_get_config($prefix, $distribution); - my $gpgkey = $distro_config->{'gpg-key'} || $BSConfig::aptly_defconfig->{'gpg-key'}; + my $repo_config = aptly_repo_get_config($projid, $repoid); + my $gpgkey = $repo_config->{'gpg-key'} || $BSConfig::aptly_defconfig->{'gpg-key'}; my @args = ('publish', 'update', '--skip-contents', '--skip-bz2', - $prefix, $distribution); + $repo_config->{'prefix'}, + $repo_config->{'distribution'}); push @args, "--gpg-key=$gpgkey" if $gpgkey; - return aptlyctl_exec($distro_config->{'aptly-server'}, @args); + return aptlyctl_exec($repo_config->{'aptly-server'}, @args); } # Aptly snapshot command wrappers -sub aptly_snapshot_create { - my ($projid, $repoid, $timestamp) = @_; +sub aptly_snapshot_create($projid, $repoid, $timestamp) { my $repo_config = aptly_repo_get_config($projid, $repoid); my @args = ('repo', 'snapshot', "$projid/$repoid", @@ -215,22 +250,23 @@ sub aptly_snapshot_create { return aptlyctl_exec($repo_config->{'aptly-server'}, @args); } -sub aptly_snapshot_exists { +sub aptly_snapshot_exists($projid, $repoid, $timestamp) { # Check if aptly snapshot exists - my ($projid, $repoid, $timestamp) = @_; my $repo_config = aptly_repo_get_config($projid, $repoid); my @args = ('snapshot', 'test-exists', "$projid/$repoid/$timestamp"); return aptlyctl_exec($repo_config->{'aptly-server'}, @args) == 0; } -sub aptly_distro_snapshot { - # Create snapshots for all the repositories in an aptly prefix/distribution. - my ($prefix, $distribution, $timestamp) = @_; - my $distro_config = aptly_distro_get_config($prefix, $distribution); - my $distro_components = $distro_config->{'components'}; +sub aptly_distro_snapshot($projid, $repoid, $timestamp) { + # Create snapshots for all the repositories for the project/repository. - foreach my $component (keys %$distro_components) { - my $component_config = $distro_components->{$component}; + my $repo_config = aptly_repo_get_config($projid, $repoid); + my $repo_components = $repo_config->{'components'}; + my $prefix = $repo_config->{'prefix'}; + my $distribution = $repo_config->{'distribution'}; + + foreach my $component (keys %$repo_components) { + my $component_config = $repo_components->{$component}; my $projid = $component_config->{'project'}; my $repoid = $component_config->{'repository'}; my $obs_proj = obs_get_project($projid); @@ -242,17 +278,18 @@ sub aptly_distro_snapshot { } } -sub aptly_publish_snapshot { - # Publish snapshots for the repositories in an aptly prefix/distribution. - my ($prefix, $distribution, $timestamp) = @_; - my %archs; +sub aptly_publish_snapshot($projid, $repoid, $timestamp) { + # Publish snapshots for the repositories in a corresponding aptly prefix/distribution. + my %arches; my @to_publish; - my $distro_config = aptly_distro_get_config($prefix, $distribution); - my $distro_components = $distro_config->{'components'}; + my $repo_config = aptly_repo_get_config($projid, $repoid); + my $repo_components = $repo_config->{'components'}; + my $prefix = $repo_config->{'prefix'}; + my $distribution = $repo_config->{'distribution'}; - foreach my $component (keys %$distro_components) { - my $component_config = $distro_components->{$component}; + foreach my $component (keys %$repo_components) { + my $component_config = $repo_components->{$component}; my $projid = $component_config->{'project'}; my $repoid = $component_config->{'repository'}; my $obs_proj = obs_get_project($projid); @@ -264,31 +301,32 @@ sub aptly_publish_snapshot { push @to_publish, "$projid/$repoid/$timestamp//$component"; foreach my $arch (@{ $obs_repo->{'arch'} }) { if (BSUtil::enabled($repoid, $obs_proj->{'publish'}, 1, $arch)) { - $archs{$arch} = 1; + $arches{$arch} = 1; } } } - if (!%archs) { + if (!%arches) { return 0; } - my $gpgkey = $distro_config->{'gpg-key'} || $BSConfig::aptly_defconfig->{'gpg-key'}; + my $gpgkey = $repo_config->{'gpg-key'} || $BSConfig::aptly_defconfig->{'gpg-key'}; my @args = ('publish', 'create', 'snapshot', - (map { "--architecture=".Build::Deb::basearch($_) } (('source'), keys %archs)), + (map { + "--architecture=".Build::Deb::basearch($_) + } (('source'), keys %arches)), "--distribution=$distribution/snapshots/$timestamp", '--skip-contents', '--skip-bz2', $prefix, @to_publish); push @args, "--gpg-key=$gpgkey" if $gpgkey; - return aptlyctl_exec($distro_config->{'aptly-server'}, @args); + return aptlyctl_exec($repo_config->{'aptly-server'}, @args); } # Aptly repo command wrappers -sub aptly_repo_create { - my ($projid, $repoid, $distribution, $component) = @_; +sub aptly_repo_create($projid, $repoid, $distribution, $component) { my $repo_config = aptly_repo_get_config($projid, $repoid); my @args = ('repo', 'create', "--distribution=$distribution", @@ -297,10 +335,9 @@ sub aptly_repo_create { return aptlyctl_exec($repo_config->{'aptly-server'}, @args); } -sub aptly_repo_drop { - # Remove aptly repository. Use -force flag to remove even if there's +sub aptly_repo_drop($projid, $repoid) { + # Remove aptly repository. Use --force flag to remove even if there's # a related snapshot based on this repo. - my ($projid, $repoid) = @_; my $repo_config = aptly_repo_get_config($projid, $repoid); my @args = ('repo', 'drop', '--force', "$projid/$repoid"); @@ -309,8 +346,7 @@ sub aptly_repo_drop { # Hook functions for OBS -sub aptly_putproject { - my ($proj, $oldproj, $proj_config) = @_; +sub aptly_putproject($proj, $oldproj, $proj_config) { my $oldrepos = obs_project_repos($oldproj); my $newrepos = obs_project_repos($proj); @@ -318,41 +354,38 @@ sub aptly_putproject { foreach my $repoid (keys %{ $oldrepos }) { my $repo_config = $proj_config->{$repoid}; if (!$newrepos->{$repoid}) { - #aptly_publish_drop_check($repo_config->{'prefix'}, $repo_config->{'distribution'}); + #aptly_publish_drop_check($proj->{'name'}, $repoid); aptly_repo_drop($proj->{'name'}, $repoid); - aptly_publish_repo($repo_config->{'prefix'}, $repo_config->{'distribution'}); + aptly_publish_repo($proj->{'name'}, $repoid); } } foreach my $repoid (keys %{ $newrepos }) { my $repo_config = $proj_config->{$repoid}; - #aptly_publish_drop_check($repo_config->{'prefix'}, $repo_config->{'distribution'}); + #aptly_publish_drop_check($proj->{'name'}, $repoid); if (!$oldrepos->{$repoid}) { my $component = aptly_repo_get_component($proj->{'name'}, $repoid); aptly_repo_create($proj->{'name'}, $repoid, $repo_config->{'distribution'}, $component); } - aptly_publish_repo($repo_config->{'prefix'}, $repo_config->{'distribution'}); + aptly_publish_repo($proj->{'name'}, $repoid); } } -sub aptly_delproject { - my ($proj, $proj_config) = @_; - +sub aptly_delproject($proj, $proj_config) { my $repos = obs_project_repos($proj); foreach my $repoid (keys %{ $repos }) { my $repo_config = $proj_config->{$repoid}; - aptly_publish_drop_check($repo_config->{'prefix'}, $repo_config->{'distribution'}); + aptly_publish_drop_check($proj->{'name'}, $repoid); aptly_repo_drop($proj->{'name'}, $repoid); - aptly_publish_repo($repo_config->{'prefix'}, $repo_config->{'distribution'}); + aptly_publish_repo($proj->{'name'}, $repoid); } } -sub aptly_update_repo { - my ($projid, $repoid, $config, $extrep) = @_; +sub aptly_update_repo($projid, $repoid, $config, $extrep) { my $repo_config = aptly_repo_get_config($projid, $repoid); return obs2aptly_exec($repo_config->{'aptly-server'}, "$projid/$repoid", $extrep) - || aptly_publish_update($config->{'prefix'}, $config->{'distribution'}); + || aptly_publish_update($projid, $repoid); } 1; diff --git a/src/backend/bs_published_hook_aptly_snapshot b/src/backend/bs_published_hook_aptly_snapshot index 047b87908078db934ffcb51ab475f415b72672a1..77b23deb3dbb7e8f30162464f92a0d191361e30d 100755 --- a/src/backend/bs_published_hook_aptly_snapshot +++ b/src/backend/bs_published_hook_aptly_snapshot @@ -28,26 +28,21 @@ sub distribution_basename { } sub do_distro_snapshot { - my ($prefix, $distribution, $timestamp) = @_; - my $distro_config = BSAptly::aptly_distro_get_config($prefix, $distribution); - die("can't find aptly configuration for distribution $prefix/$distribution\n") if !$distro_config; - BSAptly::aptly_distro_snapshot($prefix, $distribution, $timestamp); - BSAptly::aptly_publish_snapshot($prefix, $distribution, $timestamp); + my ($projid, $repoid, $timestamp) = @_; + my $repo_config = BSAptly::aptly_repo_get_config($projid, $repoid); + die("can't find aptly configuration for distribution $projid/$repoid\n") if !$repo_config; + BSAptly::aptly_distro_snapshot($projid, $repoid, $timestamp); + BSAptly::aptly_publish_snapshot($projid, $repoid, $timestamp); } getopts('t:'); my ($projid, $repoid) = $ARGV[0] =~ /(.*)\/(.*)/; -my @suffixes = ('', '-security', '-updates'); my $timestamp = $opt_t || strftime "%Y%m%dT%H%M%SZ", gmtime; die("bad project/repo parameter: $projid, $repoid\n") if !$projid || !$repoid; -my $distro_config = BSAptly::aptly_repo_get_config($projid, $repoid); -die("can't find related aptly distribution for $projid/$repoid\n") if !$distro_config; -my $prefix = $distro_config->{'prefix'}; -my $distribution = distribution_basename($distro_config->{'distribution'}); +my $repo_config = BSAptly::aptly_repo_get_config($projid, $repoid); +die("can't find related aptly distribution for $projid/$repoid\n") if !$repo_config; -foreach my $suffix (@suffixes) { - do_distro_snapshot($prefix, $distribution.$suffix, $timestamp); -} +do_distro_snapshot($projid, $repoid, $timestamp); diff --git a/tests/aptly/BSConfig.local.pm b/tests/aptly/BSConfig.local.pm index 6e3b44a4fe10c7dafae91015cfb67a35d0b510a0..baa3fe27b3ecc9526156727eee5ff2ff2e7f80a7 100644 --- a/tests/aptly/BSConfig.local.pm +++ b/tests/aptly/BSConfig.local.pm @@ -39,26 +39,28 @@ foreach $release (@reprepro_releases) { }; }; -our $aptly_config = {}; +our $aptly_targets = { + 'apertis' => { + 'server' => { + 'url' => 'http://aptly:8080', + }, + 'prefix' => $apertis_prefix, + }, +}; + +our $aptly_projects = {}; foreach $release (@aptly_releases) { foreach $component (@apertis_components) { - $aptly_config->{$apertis_prefix}{$release}{"aptly-server"} = $aptly_server; - $aptly_config->{$apertis_prefix}{$release."-updates"}{"aptly-server"} = $aptly_server; - $aptly_config->{$apertis_prefix}{$release."-security"}{"aptly-server"} = $aptly_server; - - $aptly_config->{$apertis_prefix}{$release}{"components"}{$component} = { - "project" => "apertis:".$release.":".$component, - "repository" => "default", - }; - $aptly_config->{$apertis_prefix}{$release."-updates"}{"components"}{$component} = { - "project" => "apertis:".$release.":updates:".$component, - "repository" => "default", - }; - $aptly_config->{$apertis_prefix}{$release."-security"}{"components"}{$component} = { - "project" => "apertis:".$release.":security:".$component, - "repository" => "default", - }; + foreach my $suffix ('', '-updates', '-security') { + $aptly_projects->{"apertis:$release$suffix:$component"} = { + 'default' => { + 'target' => 'apertis', + 'distribution' => $release . $suffix, + 'component' => $component, + }, + }; + } }; };