diff --git a/plugin/builder/image_builder.py b/plugin/builder/image_builder.py index 116b4dc..e0591d4 100644 --- a/plugin/builder/image_builder.py +++ b/plugin/builder/image_builder.py @@ -109,6 +109,28 @@ def target_repo(topdir, target_info, repo_info): return f"{repo}/$arch" +def load_rpmlist_from_output(output_dir): + """Load *.rpmlist.json files written by image-builder-cli --with-rpmlist. + """ + + rpmlist = [] + if not os.path.isdir(output_dir): + return rpmlist + + for root, _, files in os.walk(output_dir): + for file in files: + if not file.endswith(".rpmlist.json"): + continue + path = os.path.join(root, file) + try: + with open(path, "r", encoding="utf-8") as f: + rpmlist.extend(json.load(f)) + except (OSError, UnicodeError, json.JSONDecodeError) as e: + logger.warning("skipped rpmlist %s: %s", path, e) + + return rpmlist + + class ImageBuilderBuildTask(BuildImageTask): """Spawns imageBuilderBuildArch tasks.""" @@ -421,6 +443,7 @@ def handler( [ "--with-sbom", "--with-manifest", + "--with-rpmlist", ] ) @@ -504,6 +527,12 @@ def handler( self.uploadFile(os.path.join(root, file), remoteName=file) data["files"].append(file) + # Only do the hdrlist when this is a non-scratch build + if not self.opts.get("scratch"): + rpmlist = load_rpmlist_from_output(output) + broot.markExternalRPMs(rpmlist) + data["rpmlist"] = rpmlist + broot.expire() return data diff --git a/test/conftest.py b/test/conftest.py index 3fd4c0c..0266052 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -32,6 +32,9 @@ def mock(self, args): return 0 + def markExternalRPMs(self, args, **kwargs): + pass + @pytest.fixture def koji_mock_kojid(mocker, tmpdir): diff --git a/test/unit/test_builder.py b/test/unit/test_builder.py index 6c4ae3e..9496ad3 100644 --- a/test/unit/test_builder.py +++ b/test/unit/test_builder.py @@ -53,6 +53,7 @@ def test_build_arch_task(koji_mock_kojid): "//repos/f42-build/1/$arch", "--with-sbom", "--with-manifest", + "--with-rpmlist", "--output-dir", "/builddir/output", "--output-name", @@ -101,6 +102,7 @@ def test_build_arch_task_with_repos(koji_mock_kojid): "c/x86_64/d", "--with-sbom", "--with-manifest", + "--with-rpmlist", "--output-dir", "/builddir/output", "--output-name", @@ -147,6 +149,7 @@ def test_build_arch_task_multiple_types(koji_mock_kojid): "//repos/f42-build/1/$arch", "--with-sbom", "--with-manifest", + "--with-rpmlist", "--output-dir", "/builddir/output", "--output-name", @@ -168,6 +171,7 @@ def test_build_arch_task_multiple_types(koji_mock_kojid): "//repos/f42-build/1/$arch", "--with-sbom", "--with-manifest", + "--with-rpmlist", "--output-dir", "/builddir/output", "--output-name", @@ -220,6 +224,7 @@ def test_build_arch_task_ostree(koji_mock_kojid): "//repos/f42-build/1/$arch", "--with-sbom", "--with-manifest", + "--with-rpmlist", "--ostree-url", "https://kojipkgs.fedoraproject.org/compose/iot/repo/", "--ostree-ref", @@ -297,6 +302,7 @@ def test_build_arch_task_seed(koji_mock_kojid): "//repos/f42-build/1/$arch", "--with-sbom", "--with-manifest", + "--with-rpmlist", "--seed", "1234", "--output-dir", "/builddir/output", @@ -347,6 +353,7 @@ def test_build_arch_task_preview(koji_mock_kojid): "//repos/f42-build/1/$arch", "--with-sbom", "--with-manifest", + "--with-rpmlist", "--preview", "false", "--output-dir", "/builddir/output", @@ -357,3 +364,22 @@ def test_build_arch_task_preview(koji_mock_kojid): ] +def test_load_rpmlist_from_output_missing(koji_mock_kojid, tmp_path): + import plugin.builder.image_builder as builder + + missing = tmp_path / "not-a-dir" + assert builder.load_rpmlist_from_output(str(missing)) == [] + + +def test_load_rpmlist_from_output(koji_mock_kojid, tmp_path): + import plugin.builder.image_builder as builder + + out = tmp_path / "output" + out.mkdir() + (out / "img.rpmlist.json").write_text( + '[{"name":"mpfr","version":"4.1.0","release":"10.el9","epoch":0,"arch":"x86_64","buildtime":1770637270,"size":331788,"payloadhash":"11c1d6b33b7e64ddc40faf45b949618c829bd2e3d3661132417e4c8aee6ab0fd"}]', + encoding="utf-8", + ) + assert builder.load_rpmlist_from_output(str(out)) == [ + {"name":"mpfr","version":"4.1.0","release":"10.el9","epoch":0,"arch":"x86_64","buildtime":1770637270,"size":331788,"payloadhash":"11c1d6b33b7e64ddc40faf45b949618c829bd2e3d3661132417e4c8aee6ab0fd"}, + ]