Better support for dnf5 in Fedora 41/42#67975
Conversation
|
Hi there! Welcome to the Salt Community! Thank you for making your first contribution. We have a lengthy process for issues and PRs. Someone from the Core Team will follow up as soon as possible. In the meantime, here’s some information that may help as you continue your Salt journey. There are lots of ways to get involved in our community. Every month, there are around a dozen opportunities to meet with other contributors and the Salt Core team and collaborate in real time. The best way to keep track is by subscribing to the Salt Community Events Calendar. |
twangboy
left a comment
There was a problem hiding this comment.
Please create a changelog and write a test for this.
|
Changelog entry added. I looked to add a test to test/pytest/unit/modules/test_yumpkg.py, but on running (without any changes):
I don't have a test environment setup for salt development, and don't intend to be doing further salt development, so my incentive to debug why this didn't Just Work is quite low :( Sorry. |
twangboy
left a comment
There was a problem hiding this comment.
Could you write a simple test here, or ensure that existing tests cover these changes
|
Please see my previous comment. I've tried to build a test, but I'm failing right now to even get a basic test environment setup. |
|
@gregoster Sorry, there are more conflicts that need to be addressed. |
'grouplist' and 'groupinfo' are each now two words. 'group' and 'group-id' have been replaced with 'name' and 'id', so check for those too.
The dnf5 'group info' output differs from the dnf 'groupinfo' output. In particular, a package name is now also listed on the first line of each section. Need to also strip leading spaces from lines.
dnf5 group_list-specific test was missing, but these tests should only be run against dnf5, as yum/dnf provide different output for 'grouplist' and 'groupinfo'.
dnf5 'group list' output needs to be handed differently than yum/dnf 'grouplist' output. Also condition on _yum() so we don't break 'grouplist' and 'groupinfo' on systems using yum/dnf.
the case of the package name when adding it to the list.
- test_67975_dnf5_group_info: add missing "type": "package group" key to
the expected dict (the new elif "name" in g_info branch populates it).
- yumpkg group_list/group_info: replace `_yum() in ("dnf5")`,
`pkg_id not in ("id")`, and `pkg_installed in ("yes")` with `==`/`!=`
comparisons. These were substring-in-string checks (no trailing comma
on a single-string tuple); they worked for exact equality but would
have accepted any single character in those strings as a match.
- yumpkg group_info: drop stray space inside `re.match( r"..." )` so
black is happy.
Co-authored-by: Greg Oster <oster@fween.ca>
|
Heads-up that this also affects the 3006 LTS line: dnf5 ships on Fedora 41+ and AlmaLinux/RHEL 10, and on 3006.26 Since 3006.x is supported into 2027 and the contributing guide has bug fixes start on the oldest supported branch and merge forward, would it make sense to target this at If it helps, I'm happy to put up a 3006.x backport that preserves your authorship and adds the changelog + tests -- just say the word, or feel free to retarget this one. Thanks for chasing this down. |
I'm happy to have you (or anyone else) take over the lead on this :) |
| line_lc = line.lower() | ||
| # split line into 3 parts: ID (no spaces), Name (contains spaces), and | ||
| # Installed (one of 'yes' or 'no') | ||
| match = re.match(r"^(\S+?)\s+(.+?)\s*(yes|no)$", line_lc) |
There was a problem hiding this comment.
The Problem
The current regex r"^(\S+?)\s+(.+?)\s*(yes|no)$" relies on a lazy match (.+?) for the group name. If a group name naturally contains the word "yes" or "no" (e.g., "Just (testing) yes"), the lazy match can cut off early or misalign the columns.
The Fix
Since terminal tables from tools like dnf5 use predictable, whitespace-aligned columns, it is safer to tokenize the line from the right side first to isolate the status, or use a regex that explicitly binds the trailing status to the end of the line while allowing spaces in the name.
# Instead of: match = re.match(r"^(\S+?)\s+(.+?)\s*(yes|no)$", line_lc)
# A more robust regex approach:
# This ensures the group ID is a single word, the status is strictly the last word,
# and everything in between is captured cleanly as the group name.
match = re.match(r"^(\S+)\s+(.+)\s+(yes|no)$", line_lc)Alternatively, you can split by whitespace and pop the trailing status directly, which completely avoids regex backtracking traps:
parts = line.strip().split()
if len(parts) >= 3:
pkg_installed = parts[-1].lower()
if pkg_installed in ("yes", "no"):
pkg_id = parts[0]
pkg_name = " ".join(parts[1:-1])
# Proceed with logic...| # The difference here from dnf (above) is that this line | ||
| # also contains the first package of this section. | ||
| # Have to pull out the package name, but not changing the case | ||
| rematch_dnf5 = re.match(r"^.*:\s*(.*?)$", line) |
There was a problem hiding this comment.
The Problem
Mutating the line variable mid-stream using a broad re.match(r"^.*:\s*(.*?)$", line) can result in an empty string if a header layout has trailing spaces or localized structural content. If line becomes empty, it can bypass downstream assertions or drop packages.
The Fix
Instead of overwriting the loop context variable line directly and executing an immediate continue, explicitly extract the package payload into a dedicated variable name and process it safely inside a structured block:
# Instead of mutating the loop variable:
# if rematch_dnf5:
# line = rematch_dnf5.group(1)
# Safer approach:
match_dnf5 = re.match(
pkgtypes_capturegroup + r" (?:groups|packages)\s*:\s*(.*?)$",
line.lower(),
)
if match_dnf5:
if target_found:
break
if match_dnf5.group(1) == pkgtype:
target_found = True
# Safely extract the inline package without losing the loop context
header_package_match = re.match(r"^[^:]+:\s*(.+)$", line)
if header_package_match:
inline_pkg = header_package_match.group(1).strip()
if inline_pkg and inline_pkg not in completed_groups:
# Append the inline package immediately here
if expand and ret["type"] == "environment group":
# handle environment group nesting...
pass
else:
ret[pkgtype].append(inline_pkg)
continue| target_found = False | ||
| for line in salt.utils.itertools.split(out, "\n"): | ||
| line = line.strip().lstrip(string.punctuation) | ||
| line = line.strip().lstrip(string.punctuation).lstrip() |
There was a problem hiding this comment.
While the second .lstrip() was likely added to catch any new leading spaces exposed after removing punctuation, this structure leaves a silent bug if a line contains trailing punctuation.
To guarantee that the string is completely tightened on both ends regardless of what characters or whitespace get shifted around by the punctuation drop, the final call should be a full .strip().
line = line.strip().lstrip(string.punctuation).strip()|
@gregoster thanks for the go-ahead. I've put the 3006.x backport up as #69813, with you as co-author. Since 3006.x's @twangboy I also folded in your three review points there:
Validated end to end against live dnf5 5.4.2.1 on Fedora 44: This master PR still stands on its own -- happy to help forward-port the same three fixes here if that's useful. |
|
Closing in favor of: #69813 |
'grouplist' and 'groupinfo' are each now two words. 'group' and 'group-id' have been replaced with 'name' and 'id', so check for those too.
What does this PR do?
Improve support for installing via groups with dnf5 on Fedora 41/42. Issue found when attempting to run salt 3007 on Fedora 42. Problem also exists in master/main, so starting there.
What issues does this PR fix or reference?
Fixes salt failing on a Fedora 41/42 install when (e.g.) installing KDE Fonts via a group:
The name of the group doesn't seem to matter -- all groups fail, as 'groupinfo' and 'grouplist' have been deprecated since dnf5 as shipped with Fedora 41.
Merge requirements satisfied?
[NOTICE] Bug fixes or features added to Salt require tests.
Commits signed with GPG?
No