1
0
mirror of https://github.com/coreos/fedora-coreos-config.git synced 2026-02-05 09:45:30 +01:00

build-rootfs: add overrides/rpm API

Allow a yum repo at `overrides/rpm` to exist in the context dir, in
which case we automatically create a lockfile and repo file that we
inject out of that.

This matches the `overrides/rpm` functionality in cosa, but the
API lives here. cosa can then just use that API to retain its
`overrides/rpm` behaviour.

A lot of the code is lifted from cosa's `cmdlib.sh`, which conveniently
had it in Python already among its many liberal uses of inline Python
scripts.
This commit is contained in:
Jonathan Lebon
2025-08-12 22:45:22 -04:00
parent 85c36c9137
commit 4310c8ee72
2 changed files with 52 additions and 2 deletions

View File

@@ -5,6 +5,11 @@
#
# Note: we should be able to drop the `-v $PWD:/run/src` once
# https://github.com/containers/buildah/issues/5952 is fixed.
#
# For development convenience, an `overrides/` directory in the context dir, or
# mounted at `/run/src/overrides` is supported:
# - The `overrides/rpm` directory can be a yum repo. Its packages take
# precedence over those from remote repos.
# Overridden by build-args.conf. The value here is invalid on purpose.
ARG BUILDER_IMG=overridden

View File

@@ -35,7 +35,11 @@ def main():
if repos:
inject_yumrepos()
locked_nevras = get_locked_nevras()
local_overrides = prepare_local_rpm_overrides(target_rootfs)
if local_overrides:
repos += ['overrides']
locked_nevras = get_locked_nevras(local_overrides)
if locked_nevras:
modify_pool_repo(locked_nevras)
@@ -179,6 +183,38 @@ def run_postprocess_scripts(rootfs, manifest):
os.unlink(os.path.join(rootfs, name))
def prepare_local_rpm_overrides(rootfs):
overrides_repo = os.path.join(CONTEXTDIR, 'overrides/rpm')
if not os.path.isdir(f'{overrides_repo}/repodata'):
return None
pkglist = subprocess.check_output(['dnf', 'repoquery', f'--repofrompath=overrides,file://{overrides_repo}',
'--repo=overrides', '--latest-limit=1', f'--arch={ARCH},noarch',
'--qf', 'pkg: %{name} %{evr} %{arch}\n'], encoding='utf-8')
lockfile = {"packages": {}}
for line in pkglist.splitlines():
if not line.startswith("pkg: "):
continue
_, name, evr, arch = line.strip().split()
lockfile["packages"][name] = {"evra": f"{evr}.{arch}"}
if len(lockfile['packages']) == 0:
return None
with open('/etc/yum.repos.d/overrides.repo', 'w') as f:
f.write(f'''
[overrides]
name=overrides
baseurl=file://{overrides_repo}
gpgcheck=0
cost=500
priority=1
''')
print("Injected", len(lockfile['packages']), 'package overrides')
return lockfile
# Could upstream this as e.g. `bootc-base-imagectl runroot /rootfs <cmd>` maybe?
# But we'd need to carry it anyway at least for RHCOS 9.6.
def bwrap(rootfs, args):
@@ -189,7 +225,7 @@ def bwrap(rootfs, args):
'--'] + args)
def get_locked_nevras():
def get_locked_nevras(local_overrides):
lockfile_path = os.path.join(CONTEXTDIR, f"manifest-lock.{ARCH}.json")
overrides_path = os.path.join(CONTEXTDIR, "manifest-lock.overrides.yaml")
overrides_arch_path = os.path.join(CONTEXTDIR, f"manifest-lock.overrides.{ARCH}.yaml")
@@ -205,6 +241,15 @@ def get_locked_nevras():
# this essentially re-implements the merge semantics of rpm-ostree
locks.update({pkgname: v['evra'] if 'evra' in v else v['evr']
for (pkgname, v) in data['packages'].items()})
if local_overrides:
# Note here we only add the minimal number of overrides needed to
# nullify the base locks rather than take all of them wholesale. We
# don't want to force-install everything in `overrides/rpm` -- e.g. we
# want to support dumb `koji download-build` flows. For everything else
# that's unlocked, we rely on the overrides repo having priority=1.
locks.update({pkgname: v['evra'] if 'evra' in v else v['evr']
for (pkgname, v) in local_overrides['packages'].items()
if pkgname in locks})
return [f'{k}-{v}' for (k, v) in locks.items()]