mirror of
https://pagure.io/fm-orchestrator.git
synced 2026-04-14 12:59:49 +08:00
Support Virtual Streams in MMDResolver.
Modularity team needs to be able to define multiple streams for single "platform"
module. They need it to express that "platform:el8.1.0" also provides "platform:el8".
This needs changes in a way how MMDResolver resolves dependencies between modules.
For example, if we are building module against platform:el8.1.0, the MMDResolver must
not return buildrequired module built against platform > el8.1.0, but it can for example
return (cherry-pick) buildrequired module from platform:el8.0.0 if there is no such
module built for platform:el8.1.0.
The way how it is implemented is following:
- MMDResolver reads list of virtual streams from xmd["mbs"]["virtual_streams"] when
creating Solvable from MMD and adds additional Provides for these virtual streams.
We expect these to be set mainly on base modules. The versions of such provides
are based on "stream version" number, so we can compare them.
- The base module ("platform") buildrequires of MMDs added to MMDResolver are overriden
to mark particular platform "stream version". For example, if module "foo" buildrequires
"platform:el8" in MMD file, but was in fact built against platform:el8.1.0, it will
be treated as if it would really buildrequire "platform:el8.1.0". This is needed
to not include buildrequired modules built against newer platform than what we want.
- MMDResolver resolves all the valid combinations of buildrequires, but we are only
interested in the one with latest versions of buildrequired module. Therefore the
solve() method is changed to find out combinations which have the latest versions
for each alternative name:stream buildrequires.
This commit is contained in:
@@ -28,6 +28,7 @@ import pytest
|
||||
|
||||
from module_build_service.mmd_resolver import MMDResolver
|
||||
from module_build_service import Modulemd
|
||||
from module_build_service import glib
|
||||
|
||||
|
||||
class TestMMDResolver:
|
||||
@@ -39,7 +40,7 @@ class TestMMDResolver:
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
def _make_mmd(nsvc, requires):
|
||||
def _make_mmd(nsvc, requires, xmd_buildrequires=None, virtual_streams=None):
|
||||
name, stream, version = nsvc.split(":", 2)
|
||||
mmd = Modulemd.Module()
|
||||
mmd.set_mdversion(2)
|
||||
@@ -51,6 +52,17 @@ class TestMMDResolver:
|
||||
licenses.add("GPL")
|
||||
mmd.set_module_licenses(licenses)
|
||||
|
||||
xmd = glib.from_variant_dict(mmd.get_xmd())
|
||||
xmd["mbs"] = {}
|
||||
xmd["mbs"]["buildrequires"] = {}
|
||||
if xmd_buildrequires:
|
||||
for ns in xmd_buildrequires:
|
||||
n, s = ns.split(":")
|
||||
xmd["mbs"]["buildrequires"][n] = {"stream": s}
|
||||
if virtual_streams:
|
||||
xmd["mbs"]["virtual_streams"] = virtual_streams
|
||||
mmd.set_xmd(glib.dict_values(xmd))
|
||||
|
||||
if ":" in version:
|
||||
version, context = version.split(":")
|
||||
mmd.set_context(context)
|
||||
@@ -162,3 +174,89 @@ class TestMMDResolver:
|
||||
for e in exp)
|
||||
|
||||
assert expanded == expected
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"buildrequires, xmd_buildrequires, expected", (
|
||||
# BR all platform streams -> build for all platform streams.
|
||||
({"platform": []}, {}, [
|
||||
[["platform:el8.2.0:0:c0:x86_64"],
|
||||
["platform:el8.1.0:0:c0:x86_64"],
|
||||
["platform:el8.0.0:0:c0:x86_64"],
|
||||
["platform:el7.6.0:0:c0:x86_64"]],
|
||||
]),
|
||||
# BR "el8" platform stream -> build for all el8 platform streams.
|
||||
({"platform": ["el8"]}, {}, [
|
||||
[["platform:el8.2.0:0:c0:x86_64"],
|
||||
["platform:el8.1.0:0:c0:x86_64"],
|
||||
["platform:el8.0.0:0:c0:x86_64"]],
|
||||
]),
|
||||
# BR "el8.1.0" platfrom stream -> build just for el8.1.0.
|
||||
({"platform": ["el8"]}, ["platform:el8.1.0"], [
|
||||
[["platform:el8.1.0:0:c0:x86_64"]],
|
||||
]),
|
||||
# BR platform:el8.1.0 and gtk:3, which is not built against el8.1.0,
|
||||
# but it is built only against el8.0.0 -> cherry-pick gtk:3 from el8.0.0
|
||||
# and build once against platform:el8.1.0.
|
||||
({"platform": ["el8"], "gtk": ["3"]}, ["platform:el8.1.0"], [
|
||||
[["platform:el8.1.0:0:c0:x86_64", "gtk:3:0:c8:x86_64", ]],
|
||||
]),
|
||||
# BR platform:el8.2.0 and gtk:3, this time gtk:3 build against el8.2.0 exists
|
||||
# -> use both platform and gtk from el8.2.0 and build once.
|
||||
({"platform": ["el8"], "gtk": ["3"]}, ["platform:el8.2.0"], [
|
||||
[["platform:el8.2.0:0:c0:x86_64", "gtk:3:1:c8:x86_64", ]],
|
||||
]),
|
||||
# BR platform:el8.2.0 and mess:1 which is built against platform:el8.1.0 and
|
||||
# requires gtk:3 which is built against platform:el8.2.0 and platform:el8.0.0
|
||||
# -> Use platform:el8.2.0 and
|
||||
# -> cherry-pick mess:1 from el8.1.0 and
|
||||
# -> use gtk:3:1 from el8.2.0.
|
||||
({"platform": ["el8"], "mess": ["1"]}, ["platform:el8.2.0"], [
|
||||
[["platform:el8.2.0:0:c0:x86_64", "mess:1:0:c0:x86_64", "gtk:3:1:c8:x86_64", ]],
|
||||
]),
|
||||
# BR platform:el8.1.0 and mess:1 which is built against platform:el8.1.0 and
|
||||
# requires gtk:3 which is built against platform:el8.2.0 and platform:el8.0.0
|
||||
# -> Use platform:el8.1.0 and
|
||||
# -> Used mess:1 from el8.1.0 and
|
||||
# -> cherry-pick gtk:3:0 from el8.0.0.
|
||||
({"platform": ["el8"], "mess": ["1"]}, ["platform:el8.1.0"], [
|
||||
[["platform:el8.1.0:0:c0:x86_64", "mess:1:0:c0:x86_64", "gtk:3:0:c8:x86_64", ]],
|
||||
]),
|
||||
# BR platform:el8.0.0 and mess:1 which is built against platform:el8.1.0 and
|
||||
# requires gtk:3 which is built against platform:el8.2.0 and platform:el8.0.0
|
||||
# -> No valid combination, because mess:1 is only available in el8.1.0 and later.
|
||||
({"platform": ["el8"], "mess": ["1"]}, ["platform:el8.0.0"], []),
|
||||
# This is undefined... it might build just once against latest platform or
|
||||
# against all the platforms... we don't know
|
||||
# ({"platform": ["el8"], "gtk": ["3"]}, {}, [
|
||||
# [["platform:el8.2.0:0:c0:x86_64", "gtk:3:1:c8:x86_64"]],
|
||||
# ]),
|
||||
)
|
||||
)
|
||||
def test_solve_virtual_streams(self, buildrequires, xmd_buildrequires, expected):
|
||||
modules = (
|
||||
# (nsvc, buildrequires, expanded_buildrequires, virtual_streams)
|
||||
("platform:el8.0.0:0:c0", {}, {}, ["el8"]),
|
||||
("platform:el8.1.0:0:c0", {}, {}, ["el8"]),
|
||||
("platform:el8.2.0:0:c0", {}, {}, ["el8"]),
|
||||
("platform:el7.6.0:0:c0", {}, {}, ["el7"]),
|
||||
("gtk:3:0:c8", {"platform": ["el8"]}, {"platform:el8.0.0"}, None),
|
||||
("gtk:3:1:c8", {"platform": ["el8"]}, {"platform:el8.2.0"}, None),
|
||||
("mess:1:0:c0", [{"gtk": ["3"], "platform": ["el8"]}], {"platform:el8.1.0"}, None),
|
||||
)
|
||||
for n, req, xmd_br, virtual_streams in modules:
|
||||
self.mmd_resolver.add_modules(self._make_mmd(
|
||||
n, req, xmd_br, virtual_streams))
|
||||
|
||||
app = self._make_mmd("app:1:0", buildrequires, xmd_buildrequires)
|
||||
if not expected:
|
||||
with pytest.raises(RuntimeError):
|
||||
self.mmd_resolver.solve(app)
|
||||
return
|
||||
else:
|
||||
expanded = self.mmd_resolver.solve(app)
|
||||
|
||||
expected = set(frozenset(["app:1:0:%d:src" % c] + e)
|
||||
for c, exp in enumerate(expected)
|
||||
for e in exp)
|
||||
|
||||
assert expanded == expected
|
||||
|
||||
@@ -70,8 +70,8 @@ class TestUtilsModuleStreamExpansion:
|
||||
|
||||
xmd = {
|
||||
"mbs": {
|
||||
"buildrequires": [],
|
||||
"requires": [],
|
||||
"buildrequires": {},
|
||||
"requires": {},
|
||||
"commit": "ref_%s" % context,
|
||||
"mse": "true",
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user