diff --git a/vinca/naming.py b/vinca/naming.py index 39f6ea2..b3db5ae 100644 --- a/vinca/naming.py +++ b/vinca/naming.py @@ -2,6 +2,8 @@ from enum import Enum +from vinca.mutex import get_mutex_package_dependency + class PackageNameMode(str, Enum): """Supported ROS package naming transition modes.""" @@ -81,10 +83,17 @@ def generate_legacy_compatibility_output(output, pkg_shortname, distro, vinca_co legacy_name = get_legacy_package_name(pkg_shortname, distro) version = output["package"]["version"] + run = [f"{canonical_name} =={version}"] + # Several distributions can publish the same ros2- version to one channel; + # requiring this distribution's mutex (as the canonical packages do) keeps the + # alias from being satisfied by another distribution's build. + mutex_dependency = get_mutex_package_dependency(vinca_conf, distro) + if mutex_dependency: + run.append(mutex_dependency) return { "package": {"name": legacy_name, "version": version}, "build": {"script": ""}, - "requirements": {"run": [f"{canonical_name} =={version}"]}, + "requirements": {"run": run}, "about": {"summary": f"Compatibility package for {canonical_name}"}, } @@ -106,6 +115,6 @@ def is_legacy_compatibility_output(output, distro, vinca_conf): shortname = name[len(legacy_prefix) :] canonical_name = get_new_package_name(shortname, distro) version = output["package"]["version"] - return output.get("requirements", {}).get("run") == [ - f"{canonical_name} =={version}" - ] + # the canonical package comes first, optionally followed by the mutex + run = output.get("requirements", {}).get("run") or [] + return run[:1] == [f"{canonical_name} =={version}"] diff --git a/vinca/test_naming_scheme.py b/vinca/test_naming_scheme.py index 00d925b..32c939d 100644 --- a/vinca/test_naming_scheme.py +++ b/vinca/test_naming_scheme.py @@ -11,6 +11,7 @@ generate_legacy_compatibility_output, get_package_name, get_package_name_mode, + is_legacy_compatibility_output, ) from vinca.resolve import resolve_pkgname from vinca.utils import ( @@ -249,6 +250,40 @@ def test_both_mode_generates_legacy_compatibility_output(): } +@pytest.mark.parametrize( + "mutex_package,expected_mutex", + [ + ( + { + "name": "ros2-distro-mutex", + "version": "0.21.0", + "upper_bound": "x.x", + "run_constraints": [], + }, + "ros2-distro-mutex 0.21.* humble_*", + ), + # legacy string form: the spec is used verbatim, as for canonical packages + ("ros2-distro-mutex 0.5.* humble", "ros2-distro-mutex 0.5.* humble"), + ], +) +def test_compatibility_output_requires_the_distribution_mutex( + mutex_package, expected_mutex +): + distro = make_distro() + vinca_conf = {"package_name_mode": "both", "mutex_package": mutex_package} + output = {"package": {"name": "ros2-my-package", "version": "1.2.3"}} + + compatibility_output = generate_legacy_compatibility_output( + output, "my_package", distro, vinca_conf + ) + + assert compatibility_output["requirements"]["run"] == [ + "ros2-my-package ==1.2.3", + expected_mutex, + ] + assert is_legacy_compatibility_output(compatibility_output, distro, vinca_conf) + + @pytest.mark.parametrize("mode", ["legacy", "new"]) def test_single_name_modes_do_not_generate_compatibility_output(mode): distro = make_distro()