dnf4.mark: mark packages in DNF state database
This adjustment allows the definition of the mark with the RPMs and runs DNF after installing the RPMs to put the proper markings in the DNF state database. See #455. This ensures that packages don't get removed during `autoremove` leading to broken systems.
This commit is contained in:
parent
4ddfe5ed0f
commit
161fe789af
4 changed files with 1244 additions and 0 deletions
81
stages/org.osbuild.dnf4.mark
Executable file
81
stages/org.osbuild.dnf4.mark
Executable file
|
|
@ -0,0 +1,81 @@
|
|||
#!/usr/bin/python3
|
||||
"""
|
||||
Mark packages in the DNF state database.
|
||||
"""
|
||||
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
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": ["install", "group"],
|
||||
"description": "Package mark."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
def mark(tree, packages):
|
||||
dnf_bin = shutil.which("dnf-3")
|
||||
|
||||
if not dnf_bin:
|
||||
print("dnf not found")
|
||||
return 1
|
||||
|
||||
markings = {}
|
||||
|
||||
for package in packages:
|
||||
if package["mark"] not in markings:
|
||||
markings[package["mark"]] = []
|
||||
|
||||
markings[package["mark"]] += [package]
|
||||
|
||||
if "install" in markings:
|
||||
subprocess.run(
|
||||
[dnf_bin, "--installroot", tree, "mark", "-y", "install"]
|
||||
+ [package["name"] for package in markings["install"]],
|
||||
check=True,
|
||||
)
|
||||
|
||||
if "group" in markings:
|
||||
subprocess.run(
|
||||
[dnf_bin, "--installroot", tree, "mark", "-y", "group"]
|
||||
+ [package["name"] for package in markings["group"]],
|
||||
check=True,
|
||||
)
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
def main(tree, options):
|
||||
return mark(tree, options["packages"])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
args = api.arguments()
|
||||
r = main(args["tree"], args["options"])
|
||||
sys.exit(r)
|
||||
1100
test/data/stages/dnf4.mark/tree.json
Normal file
1100
test/data/stages/dnf4.mark/tree.json
Normal file
File diff suppressed because it is too large
Load diff
30
test/data/stages/dnf4.mark/tree.mpp.yaml
Normal file
30
test/data/stages/dnf4.mark/tree.mpp.yaml
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
version: '2'
|
||||
pipelines:
|
||||
- mpp-import-pipelines:
|
||||
path: ../manifests/fedora-vars.ipp.yaml
|
||||
- mpp-import-pipeline:
|
||||
path: ../manifests/fedora-build-v2.ipp.yaml
|
||||
id: build
|
||||
runner:
|
||||
mpp-format-string: org.osbuild.fedora{release}
|
||||
- name: tree
|
||||
build: name:build
|
||||
stages:
|
||||
- type: org.osbuild.rpm
|
||||
inputs:
|
||||
packages:
|
||||
type: org.osbuild.files
|
||||
origin: org.osbuild.source
|
||||
mpp-depsolve:
|
||||
architecture: $arch
|
||||
module-platform-id: $module_platform_id
|
||||
repos:
|
||||
mpp-eval: repos
|
||||
packages:
|
||||
- dnf
|
||||
- fedora-release
|
||||
- type: org.osbuild.dnf4.mark
|
||||
options:
|
||||
packages:
|
||||
- name: dnf
|
||||
mark: install
|
||||
|
|
@ -521,3 +521,36 @@ class TestStages(test.TestBase):
|
|||
assert capacity == str(json.loads(res.stdout)["virtual-size"])
|
||||
pop_size = ovf_tree_disk.attrib["{http://schemas.dmtf.org/ovf/envelope/1}populatedSize"]
|
||||
assert pop_size == str(os.stat(vmdk).st_size)
|
||||
|
||||
|
||||
def test_dnf4_mark(self):
|
||||
datadir = self.locate_test_data()
|
||||
testdir = os.path.join(datadir, "stages", "dnf4.mark")
|
||||
|
||||
with self.osbuild as osb, tempfile.TemporaryDirectory(dir="/var/tmp") as outdir:
|
||||
osb.compile_file(os.path.join(testdir, "tree.json"), exports=["tree"], output_dir=outdir)
|
||||
|
||||
tree = os.path.join(outdir, "tree")
|
||||
assert os.path.isdir(tree)
|
||||
|
||||
# we're going to verify that packages in the tree are marked according to
|
||||
r = subprocess.run(
|
||||
[
|
||||
"dnf",
|
||||
"--installroot", tree,
|
||||
"repoquery", "--installed",
|
||||
"--qf", "%{name},%{reason}"
|
||||
],
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
encoding="utf8",
|
||||
check=True
|
||||
)
|
||||
|
||||
for line in r.stdout.splitlines():
|
||||
package, mark = line.strip().split(",")
|
||||
|
||||
if package == "dnf":
|
||||
assert mark == "user"
|
||||
else:
|
||||
assert mark == "unknown"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue