diff --git a/stages/org.osbuild.dnf.mark b/stages/org.osbuild.dnf.mark new file mode 100755 index 0000000000..6072f1d43f --- /dev/null +++ b/stages/org.osbuild.dnf.mark @@ -0,0 +1,105 @@ +#!/usr/bin/python3 +""" +Mark packages in the DNF state database. +""" + +import shutil +import sys +import subprocess + +from osbuild import api + +SCHEMA_2 = """ +"options": { + "additionalProperties": false, + "properties": { + "packages": { + "type": "array", + "minItems": 1, + "description": "Packages and their marks.", + "items": { + "type": "object", + "additionalProperties": false, + "required": ["name", "mark"], + "properties": { + "name": { + "type": "string", + "description": "Package name." + }, + "mark": { + "type": "string", + "enum": ["user", "dependency", "weak", "group"], + "description": "Package mark." + }, + "group": { + "type": "string", + "description": "Group to mark package for when `mark` is `group`." + } + } + } + } + } +} +""" + + +def mark(packages): + dnf_bin = shutil.which("dnf5") + + # let's start by finding out which version of dnf we have + version = subprocess.run( + [dnf_bin, "--version"], capture_output=True, encoding="utf8", check=True + ).stdout + + # now it's important to note that dnf and dnf5 have different version outputs, + # dnf outputs it's version directly and dnf5 has a prefix. we can strip that + # prefix and it'll be a no-op if it isn't there, both have this on the first + # line + version = version.splitlines()[0] + version = version.removeprefix("dnf5 version ") + version, _ = version.split(".", 1) + + # if that's a 5, then we have dnf5 + is_dnf5 = version == "5" + + # now there is an alternative and that is dnf5 installed separately, in which + # case we adjust our path and turn on dnf5 + dnf5_bin = shutil.which("dnf5") + + if dnf5_bin: + dnf_bin = dnf5_bin + is_dnf5 = True + + markings = {} + + for package in packages: + if package["mark"] not in markings: + markings[package["mark"]] = [] + markings[package["mark"]].append(package) + + # we can mark more things with dnf5 + if is_dnf5: + for mark_as in ["user", "dependency", "weak"]: + subprocess.run( + [dnf_bin, "mark", mark_as] + + [package["name"] for package in markings[mark]], + check=True, + ) + else: + for mark_as in ["user"]: + subprocess.run( + [dnf_bin, "mark", mark_as] + + [package["name"] for package in markings[mark]], + check=True, + ) + + +def main(_, options): + mark(options["packages"]) + return 0 + + +if __name__ == "__main__": + args = api.arguments() + r = main(args["tree"], args["options"]) + sys.exit(r)