2015-02-10 13:19:34 +00:00
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
|
|
|
|
|
|
|
# This program is free software; you can redistribute it and/or modify
|
|
|
|
# it under the terms of the GNU General Public License as published by
|
|
|
|
# the Free Software Foundation; version 2 of the License.
|
|
|
|
#
|
|
|
|
# This program is distributed in the hope that it will be useful,
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
# GNU Library General Public License for more details.
|
|
|
|
#
|
|
|
|
# You should have received a copy of the GNU General Public License
|
2016-09-21 12:49:13 +00:00
|
|
|
# along with this program; if not, see <https://gnu.org/licenses/>.
|
2015-02-10 13:19:34 +00:00
|
|
|
|
|
|
|
|
|
|
|
import os
|
|
|
|
|
|
|
|
from kobo.shortcuts import run
|
2017-06-13 12:39:33 +00:00
|
|
|
from kobo.pkgset import SimpleRpmWrapper, RpmWrapper
|
2018-02-12 07:02:45 +00:00
|
|
|
from kobo.rpmlib import parse_nvra
|
2015-02-10 13:19:34 +00:00
|
|
|
|
2018-04-06 13:28:33 +00:00
|
|
|
from pungi.util import get_arch_variant_data, temp_dir
|
2015-03-12 21:12:38 +00:00
|
|
|
from pungi.wrappers.pungi import PungiWrapper
|
2015-02-10 13:19:34 +00:00
|
|
|
|
2018-03-09 12:45:03 +00:00
|
|
|
from pungi.arch import tree_arch_to_yum_arch, get_valid_arches
|
2015-03-12 21:12:38 +00:00
|
|
|
import pungi.phases.gather
|
2015-02-10 13:19:34 +00:00
|
|
|
|
2015-03-12 21:12:38 +00:00
|
|
|
import pungi.phases.gather.method
|
2015-02-10 13:19:34 +00:00
|
|
|
|
|
|
|
|
2015-03-12 21:12:38 +00:00
|
|
|
class GatherMethodDeps(pungi.phases.gather.method.GatherMethodBase):
|
2015-02-10 13:19:34 +00:00
|
|
|
enabled = True
|
|
|
|
|
|
|
|
def __call__(self, arch, variant, packages, groups, filter_packages, multilib_whitelist, multilib_blacklist, package_sets, path_prefix=None, fulltree_excludes=None, prepopulate=None):
|
|
|
|
# result = {
|
|
|
|
# "rpm": [],
|
|
|
|
# "srpm": [],
|
|
|
|
# "debuginfo": [],
|
|
|
|
# }
|
|
|
|
|
2017-03-31 06:57:28 +00:00
|
|
|
write_pungi_config(self.compose, arch, variant, packages, groups, filter_packages,
|
2017-03-31 08:12:11 +00:00
|
|
|
multilib_whitelist, multilib_blacklist,
|
2017-11-07 13:16:37 +00:00
|
|
|
fulltree_excludes=fulltree_excludes, prepopulate=prepopulate,
|
2018-04-09 07:43:31 +00:00
|
|
|
source_name=self.source_name, package_sets=package_sets)
|
2017-11-07 13:16:37 +00:00
|
|
|
result, missing_deps = resolve_deps(self.compose, arch, variant, source_name=self.source_name)
|
2018-02-12 07:02:45 +00:00
|
|
|
raise_on_invalid_sigkeys(arch, variant, package_sets, result)
|
2017-08-03 11:42:04 +00:00
|
|
|
check_deps(self.compose, arch, variant, missing_deps)
|
2015-02-10 13:19:34 +00:00
|
|
|
return result
|
|
|
|
|
|
|
|
|
2018-02-12 07:02:45 +00:00
|
|
|
def raise_on_invalid_sigkeys(arch, variant, package_sets, result):
|
|
|
|
"""
|
|
|
|
Raises RuntimeError if some package in compose is signed with an invalid
|
|
|
|
sigkey.
|
|
|
|
"""
|
2018-02-12 12:21:07 +00:00
|
|
|
invalid_sigkey_rpms = []
|
2018-02-12 07:02:45 +00:00
|
|
|
for package in result["rpm"]:
|
|
|
|
name = parse_nvra(package["path"])["name"]
|
2018-02-12 12:21:07 +00:00
|
|
|
for forbidden_package in package_sets["global"].invalid_sigkey_rpms:
|
2018-02-12 07:02:45 +00:00
|
|
|
if name == forbidden_package["name"]:
|
2018-02-12 12:21:07 +00:00
|
|
|
invalid_sigkey_rpms.append(forbidden_package)
|
2018-02-12 07:02:45 +00:00
|
|
|
|
2018-02-12 12:21:07 +00:00
|
|
|
if invalid_sigkey_rpms:
|
2018-02-12 07:02:45 +00:00
|
|
|
package_sets["global"].raise_invalid_sigkeys_exception(
|
2018-02-12 12:21:07 +00:00
|
|
|
invalid_sigkey_rpms)
|
2018-02-12 07:02:45 +00:00
|
|
|
|
|
|
|
|
2017-03-31 08:12:11 +00:00
|
|
|
def _format_packages(pkgs):
|
|
|
|
"""Sort packages and merge name with arch."""
|
2019-07-02 08:09:20 +00:00
|
|
|
result = set()
|
|
|
|
for pkg, pkg_arch in pkgs:
|
2017-06-13 12:39:33 +00:00
|
|
|
if type(pkg) in [SimpleRpmWrapper, RpmWrapper]:
|
|
|
|
pkg_name = pkg.name
|
|
|
|
else:
|
|
|
|
pkg_name = pkg
|
2017-03-31 08:12:11 +00:00
|
|
|
if pkg_arch:
|
2019-07-02 08:09:20 +00:00
|
|
|
result.add("%s.%s" % (pkg_name, pkg_arch))
|
2017-03-31 08:12:11 +00:00
|
|
|
else:
|
2019-07-02 08:09:20 +00:00
|
|
|
result.add(pkg_name)
|
|
|
|
return sorted(result)
|
2017-03-31 08:12:11 +00:00
|
|
|
|
|
|
|
|
2017-03-31 06:57:28 +00:00
|
|
|
def write_pungi_config(compose, arch, variant, packages, groups, filter_packages,
|
2017-03-31 08:12:11 +00:00
|
|
|
multilib_whitelist, multilib_blacklist, fulltree_excludes=None,
|
2018-04-09 07:43:31 +00:00
|
|
|
prepopulate=None, source_name=None, package_sets=None):
|
2015-02-10 13:19:34 +00:00
|
|
|
"""write pungi config (kickstart) for arch/variant"""
|
2015-06-05 20:34:24 +00:00
|
|
|
pungi_wrapper = PungiWrapper()
|
2017-11-07 13:16:37 +00:00
|
|
|
pungi_cfg = compose.paths.work.pungi_conf(variant=variant, arch=arch, source_name=source_name)
|
2015-02-10 13:19:34 +00:00
|
|
|
|
2019-07-24 11:45:00 +00:00
|
|
|
compose.log_info(
|
|
|
|
"Writing pungi config (arch: %s, variant: %s): %s", arch, variant, pungi_cfg
|
|
|
|
)
|
2015-02-10 13:19:34 +00:00
|
|
|
|
2018-04-09 13:32:33 +00:00
|
|
|
repos = {
|
|
|
|
"pungi-repo": compose.paths.work.arch_repo(arch=arch),
|
|
|
|
}
|
2018-04-17 12:49:46 +00:00
|
|
|
if compose.has_comps:
|
|
|
|
repos["comps-repo"] = compose.paths.work.comps_repo(arch=arch, variant=variant)
|
2018-04-09 13:32:33 +00:00
|
|
|
if variant.type == "optional":
|
|
|
|
for var in variant.parent.get_variants(
|
|
|
|
arch=arch, types=["self", "variant", "addon", "layered-product"]):
|
|
|
|
repos['%s-comps' % var.uid] = compose.paths.work.comps_repo(arch=arch, variant=var)
|
|
|
|
if variant.type in ["addon", "layered-product"]:
|
|
|
|
repos['parent-comps'] = compose.paths.work.comps_repo(arch=arch, variant=variant.parent)
|
2015-02-10 13:19:34 +00:00
|
|
|
|
|
|
|
lookaside_repos = {}
|
2015-03-12 21:12:38 +00:00
|
|
|
for i, repo_url in enumerate(pungi.phases.gather.get_lookaside_repos(compose, arch, variant)):
|
2015-02-10 13:19:34 +00:00
|
|
|
lookaside_repos["lookaside-repo-%s" % i] = repo_url
|
|
|
|
|
2017-03-31 08:12:11 +00:00
|
|
|
packages_str = list(_format_packages(packages))
|
|
|
|
filter_packages_str = list(_format_packages(filter_packages))
|
2015-02-10 13:19:34 +00:00
|
|
|
|
2017-03-31 06:57:28 +00:00
|
|
|
if not groups and not packages_str and not prepopulate:
|
|
|
|
raise RuntimeError(
|
|
|
|
'No packages included in %s.%s (no comps groups, no input packages, no prepopulate)'
|
|
|
|
% (variant.uid, arch))
|
|
|
|
|
2018-03-07 11:35:33 +00:00
|
|
|
package_whitelist = set()
|
|
|
|
if variant.pkgset:
|
2018-03-09 12:45:03 +00:00
|
|
|
multilib = get_arch_variant_data(compose.conf, 'multilib', arch, variant)
|
|
|
|
for i in get_valid_arches(arch, multilib=multilib, add_noarch=True, add_src=True):
|
|
|
|
for rpm_obj in variant.pkgset.rpms_by_arch.get(i, []):
|
|
|
|
package_whitelist.add(
|
|
|
|
'{0.name}-{1}:{0.version}-{0.release}'.format(rpm_obj, rpm_obj.epoch or 0))
|
2018-03-07 11:35:33 +00:00
|
|
|
|
2018-04-09 07:43:31 +00:00
|
|
|
# If the variant contains just modules or just comps groups, the pkgset
|
|
|
|
# is sufficient and contains all necessary packages.
|
|
|
|
|
2018-07-26 13:12:10 +00:00
|
|
|
has_additional_pkgs = get_arch_variant_data(
|
|
|
|
compose.conf, "additional_packages", arch, variant
|
|
|
|
)
|
|
|
|
has_traditional_content = variant.groups or has_additional_pkgs
|
|
|
|
if has_traditional_content and variant.modules is not None and package_sets:
|
2018-04-09 07:43:31 +00:00
|
|
|
# The variant is hybrid. The modular builds are already available.
|
|
|
|
# We need to add packages from base tag, but only if they are not
|
|
|
|
# already on the whitelist.
|
|
|
|
package_names = set(p.rsplit('-', 2)[0] for p in package_whitelist)
|
|
|
|
for i in get_valid_arches(arch, multilib=multilib, add_noarch=True, add_src=True):
|
|
|
|
for rpm_obj in package_sets[arch].rpms_by_arch.get(i, []):
|
|
|
|
if rpm_obj.name in package_names:
|
|
|
|
# We already have a package with this name in the whitelist, skip it.
|
|
|
|
continue
|
|
|
|
package_whitelist.add(
|
|
|
|
'{0.name}-{1}:{0.version}-{0.release}'.format(rpm_obj, rpm_obj.epoch or 0))
|
|
|
|
|
2017-03-31 06:57:28 +00:00
|
|
|
pungi_wrapper.write_kickstart(
|
|
|
|
ks_path=pungi_cfg, repos=repos, groups=groups, packages=packages_str,
|
2017-03-31 08:12:11 +00:00
|
|
|
exclude_packages=filter_packages_str,
|
2017-03-31 06:57:28 +00:00
|
|
|
lookaside_repos=lookaside_repos, fulltree_excludes=fulltree_excludes,
|
|
|
|
multilib_whitelist=multilib_whitelist, multilib_blacklist=multilib_blacklist,
|
2018-03-07 11:35:33 +00:00
|
|
|
prepopulate=prepopulate, package_whitelist=package_whitelist)
|
2015-02-10 13:19:34 +00:00
|
|
|
|
|
|
|
|
2017-11-07 13:16:37 +00:00
|
|
|
def resolve_deps(compose, arch, variant, source_name=None):
|
2015-06-05 20:34:24 +00:00
|
|
|
pungi_wrapper = PungiWrapper()
|
2017-11-07 13:16:37 +00:00
|
|
|
pungi_log = compose.paths.work.pungi_log(arch, variant, source_name=source_name)
|
2015-02-10 13:19:34 +00:00
|
|
|
|
|
|
|
msg = "Running pungi (arch: %s, variant: %s)" % (arch, variant)
|
|
|
|
|
|
|
|
compose.log_info("[BEGIN] %s" % msg)
|
2017-11-07 13:16:37 +00:00
|
|
|
pungi_conf = compose.paths.work.pungi_conf(arch, variant, source_name=source_name)
|
2015-02-10 13:19:34 +00:00
|
|
|
|
2016-01-20 11:53:08 +00:00
|
|
|
multilib_methods = get_arch_variant_data(compose.conf, 'multilib', arch, variant)
|
2015-02-10 13:19:34 +00:00
|
|
|
|
2016-08-22 14:08:25 +00:00
|
|
|
greedy_method = compose.conf["greedy_method"]
|
2015-02-10 13:19:34 +00:00
|
|
|
|
|
|
|
# variant
|
2016-08-22 14:08:25 +00:00
|
|
|
fulltree = compose.conf["gather_fulltree"]
|
|
|
|
selfhosting = compose.conf["gather_selfhosting"]
|
2015-02-10 13:19:34 +00:00
|
|
|
|
2017-09-02 00:04:02 +00:00
|
|
|
# profiling
|
|
|
|
profiler = compose.conf["gather_profiler"]
|
|
|
|
|
2015-02-10 13:19:34 +00:00
|
|
|
# optional
|
|
|
|
if variant.type == "optional":
|
|
|
|
fulltree = True
|
|
|
|
selfhosting = True
|
|
|
|
|
|
|
|
# addon
|
|
|
|
if variant.type in ["addon", "layered-product"]:
|
|
|
|
# packages having SRPM in parent variant are excluded from fulltree (via %fulltree-excludes)
|
|
|
|
fulltree = True
|
|
|
|
selfhosting = False
|
|
|
|
|
|
|
|
lookaside_repos = {}
|
2015-03-12 21:12:38 +00:00
|
|
|
for i, repo_url in enumerate(pungi.phases.gather.get_lookaside_repos(compose, arch, variant)):
|
2015-02-10 13:19:34 +00:00
|
|
|
lookaside_repos["lookaside-repo-%s" % i] = repo_url
|
|
|
|
|
|
|
|
yum_arch = tree_arch_to_yum_arch(arch)
|
|
|
|
tmp_dir = compose.paths.work.tmp_dir(arch, variant)
|
|
|
|
cache_dir = compose.paths.work.pungi_cache_dir(arch, variant)
|
2015-07-10 10:43:06 +00:00
|
|
|
# TODO: remove YUM code, fully migrate to DNF
|
2017-03-06 14:25:55 +00:00
|
|
|
backends = {
|
|
|
|
'yum': pungi_wrapper.get_pungi_cmd,
|
|
|
|
'dnf': pungi_wrapper.get_pungi_cmd_dnf,
|
|
|
|
}
|
|
|
|
get_cmd = backends[compose.conf['gather_backend']]
|
2017-01-18 08:30:46 +00:00
|
|
|
cmd = get_cmd(pungi_conf, destdir=tmp_dir, name=variant.uid,
|
|
|
|
selfhosting=selfhosting, fulltree=fulltree, arch=yum_arch,
|
|
|
|
full_archlist=True, greedy=greedy_method, cache_dir=cache_dir,
|
2017-09-02 00:04:02 +00:00
|
|
|
lookaside_repos=lookaside_repos, multilib_methods=multilib_methods,
|
|
|
|
profiler=profiler)
|
2015-02-10 13:19:34 +00:00
|
|
|
# Use temp working directory directory as workaround for
|
|
|
|
# https://bugzilla.redhat.com/show_bug.cgi?id=795137
|
2018-04-05 13:21:39 +00:00
|
|
|
with temp_dir(prefix='pungi_') as tmp_dir:
|
2015-07-08 12:27:00 +00:00
|
|
|
run(cmd, logfile=pungi_log, show_cmd=True, workdir=tmp_dir, env=os.environ)
|
2017-06-14 13:20:20 +00:00
|
|
|
|
|
|
|
with open(pungi_log, "r") as f:
|
2017-08-03 11:42:04 +00:00
|
|
|
packages, broken_deps, missing_comps_pkgs = pungi_wrapper.parse_log(f)
|
2017-08-03 11:28:34 +00:00
|
|
|
|
|
|
|
if missing_comps_pkgs:
|
2017-08-16 11:12:58 +00:00
|
|
|
log_msg = ("Packages mentioned in comps do not exist for %s.%s: %s"
|
|
|
|
% (variant.uid, arch, ", ".join(sorted(missing_comps_pkgs))))
|
|
|
|
compose.log_warning(log_msg)
|
2017-08-03 11:28:34 +00:00
|
|
|
if compose.conf['require_all_comps_packages']:
|
2017-08-16 11:12:58 +00:00
|
|
|
raise RuntimeError(log_msg)
|
2015-02-10 13:19:34 +00:00
|
|
|
|
|
|
|
compose.log_info("[DONE ] %s" % msg)
|
2017-08-03 11:42:04 +00:00
|
|
|
return packages, broken_deps
|
2015-02-10 13:19:34 +00:00
|
|
|
|
|
|
|
|
2017-08-03 11:42:04 +00:00
|
|
|
def check_deps(compose, arch, variant, missing_deps):
|
2016-08-22 14:08:25 +00:00
|
|
|
if not compose.conf["check_deps"]:
|
2015-02-10 13:19:34 +00:00
|
|
|
return
|
|
|
|
|
|
|
|
if missing_deps:
|
|
|
|
for pkg in sorted(missing_deps):
|
|
|
|
compose.log_error("Unresolved dependencies in package %s: %s" % (pkg, sorted(missing_deps[pkg])))
|
|
|
|
raise RuntimeError("Unresolved dependencies detected")
|