Skip to content

Commit

Permalink
Override releasever_{major,minor} with provides
Browse files Browse the repository at this point in the history
The releasever_major and releasever_minor substitution variables are
usually derived by splitting releasever on the first `.`. However, to
support EPEL 10 [1], we would like a way for distributions to override these
values. Specifically, we would like RHEL 10 to have a releasever of `10`
with a releasever_major of `10` and a releasever_minor of `0` (later
incrementing to `1`, `2`, to correspond with the RHEL minor version).

This commit adds a new API function, `detect_releasevers`, which derives
releasever, releasever_major, and releasever_minor from virtual provides
on the system-release package (any of `DISTROVERPKG`). The detection of
releasever is unchanged. releasever_major and releasever_minor are
specified by the versions of the `system-release-major` and
`system-release-minor` provides, respectively.

If the user specifies a `--releasever=X.Y` on the command line, the
distribution settings for releasever, releasever_major, and releasever_minor
will all be overridden: releasever will be set to X.Y, releasever_major will be
set to X, and releasever_minor will be set to Y, same as before.  If a user
wants to specify a custom releasever_major and releasever_minor, they have to
set all three with `--setopt=releasever=X --setopt=releasever_major=Y
--setopt=releasever_minor=z`, taking care to put `releasever_major` and
`releasever_minor` after `releasever` so they are not overridden.

[1] https://issues.redhat.com/browse/RHEL-68034
  • Loading branch information
evan-goode committed Jan 22, 2025
1 parent 6b8e120 commit 4872d0a
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 7 deletions.
10 changes: 8 additions & 2 deletions dnf/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,8 +157,14 @@ def _setup_default_conf():
conf = dnf.conf.Conf()
subst = conf.substitutions
if 'releasever' not in subst:
subst['releasever'] = \
dnf.rpm.detect_releasever(conf.installroot)
releasever, major, minor = \
dnf.rpm.detect_releasevers(conf.installroot)
subst['releasever'] = releasever
if major is not None:
subst['releasever_major'] = major
if minor is not None:
subst['releasever_minor'] = minor

return conf

def _setup_modular_excludes(self):
Expand Down
11 changes: 9 additions & 2 deletions dnf/cli/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -951,13 +951,20 @@ def _read_conf_file(self, releasever=None):
from_root = "/"
subst = conf.substitutions
subst.update_from_etc(from_root, varsdir=conf._get_value('varsdir'))

# cachedir, logs, releasever, and gpgkey are taken from or stored in installroot
major = None
minor = None
if releasever is None and conf.releasever is None:
releasever = dnf.rpm.detect_releasever(conf.installroot)
releasever, major, minor = dnf.rpm.detect_releasevers(conf.installroot)
elif releasever == '/':
releasever = dnf.rpm.detect_releasever(releasever)
releasever, major, minor = dnf.rpm.detect_releasevers(releasever)
if releasever is not None:
conf.releasever = releasever
if major is not None:
conf.releasever_major = major
if minor is not None:
conf.releasever_minor = minor
if conf.releasever is None:
logger.warning(_("Unable to detect release version (use '--releasever' to specify "
"release version)"))
Expand Down
2 changes: 2 additions & 0 deletions dnf/const.py.in
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ CONF_AUTOMATIC_FILENAME='/etc/dnf/automatic.conf'
DISTROVERPKG=('system-release(releasever)', 'system-release',
'distribution-release(releasever)', 'distribution-release',
'redhat-release', 'suse-release')
DISTROVER_MAJOR_PKG='system-release(releasever_major)'
DISTROVER_MINOR_PKG='system-release(releasever_minor)'
GROUP_PACKAGE_TYPES = ('mandatory', 'default', 'conditional') # :api
INSTALLONLYPKGS=['kernel', 'kernel-PAE',
'installonlypkg(kernel)',
Expand Down
41 changes: 38 additions & 3 deletions dnf/rpm/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,21 @@
import rpm # used by ansible (dnf.rpm.rpm.labelCompare in lib/ansible/modules/packaging/os/dnf.py)


def detect_releasever(installroot):
def detect_releasevers(installroot):
# :api
"""Calculate the release version for the system."""
"""Calculate the release version for the system, including releasever_major
and releasever_minor if they are overriden by the system-release-major or
system-release-minor provides."""

ts = transaction.initReadOnlyTransaction(root=installroot)
ts.pushVSFlags(~(rpm._RPMVSF_NOSIGNATURES | rpm._RPMVSF_NODIGESTS))

distrover_major_pkg = dnf.const.DISTROVER_MAJOR_PKG
distrover_minor_pkg = dnf.const.DISTROVER_MINOR_PKG
if dnf.pycomp.PY3:
distrover_major_pkg = bytes(distrover_major_pkg, 'utf-8')
distrover_minor_pkg = bytes(distrover_minor_pkg, 'utf-8')

for distroverpkg in dnf.const.DISTROVERPKG:
if dnf.pycomp.PY3:
distroverpkg = bytes(distroverpkg, 'utf-8')
Expand All @@ -47,6 +56,8 @@ def detect_releasever(installroot):
msg = 'Error: rpmdb failed to list provides. Try: rpm --rebuilddb'
raise dnf.exceptions.Error(msg)
releasever = hdr['version']
releasever_major = None
releasever_minor = None
try:
try:
# header returns bytes -> look for bytes
Expand All @@ -61,15 +72,39 @@ def detect_releasever(installroot):
if hdr['name'] not in (distroverpkg, distroverpkg.decode("utf8")):
# override the package version
releasever = ver

for provide, flag, ver in zip(
hdr[rpm.RPMTAG_PROVIDENAME],
hdr[rpm.RPMTAG_PROVIDEFLAGS],
hdr[rpm.RPMTAG_PROVIDEVERSION]):
if isinstance(provide, str):
provide = bytes(provide, "utf-8")
if provide == distrover_major_pkg and flag == rpm.RPMSENSE_EQUAL and ver:
releasever_major = ver
if provide == distrover_minor_pkg and flag == rpm.RPMSENSE_EQUAL and ver:
releasever_minor = ver

except (ValueError, KeyError, IndexError):
pass

if is_py3bytes(releasever):
releasever = str(releasever, "utf-8")
return releasever
if is_py3bytes(releasever_major):
releasever_major = str(releasever_major, "utf-8")
if is_py3bytes(releasever_minor):
releasever_minor = str(releasever_minor, "utf-8")
return releasever, releasever_major, releasever_minor
return None


def detect_releasever(installroot):
# :api
"""Calculate the release version for the system."""

releasever, _, _ = detect_releasevers(installroot)
return releasever


def _header(path):
"""Return RPM header of the file."""
ts = transaction.initReadOnlyTransaction()
Expand Down

0 comments on commit 4872d0a

Please sign in to comment.