From 2026deec087f80c96e50e7ddb6a342400f6bc948 Mon Sep 17 00:00:00 2001 From: Scott K Logan Date: Tue, 1 Sep 2026 22:12:50 -0500 Subject: [PATCH] Fix dynrpm handling of '' The 'Obsoletes:' tag in RPM spec files cannot carry virtual package names like the others. Unfortunately, this is the only tag where we'll have to reference an actual package name in `bloom-deps.py`. --- etc/rpm/bloom-deps.py | 55 +++++++++++++------ test/unit_tests/test_bloom_deps.py | 15 +++++ .../test_replaces/package.xml | 14 +++++ 3 files changed, 67 insertions(+), 17 deletions(-) create mode 100644 test/unit_tests/test_bloom_deps_data/test_replaces/package.xml diff --git a/etc/rpm/bloom-deps.py b/etc/rpm/bloom-deps.py index 24f99072..55d86c73 100755 --- a/etc/rpm/bloom-deps.py +++ b/etc/rpm/bloom-deps.py @@ -192,14 +192,12 @@ def enumerate_msg_pkg_workaround_deps(pkg): @classmethod def enumerate_rosdeps( - cls, pkg, *, conflicts=False, obsoletes=False, requires=False, + cls, pkg, *, conflicts=False, requires=False, requires_check=False, requires_doc=False, requires_build=False, requires_devel=False, resolve_groups=False, ): if conflicts: yield from pkg.conflicts - if obsoletes: - yield from pkg.replaces if requires: yield from pkg.exec_depends if pkg.name not in _BOOTSTRAP_PKGS: @@ -269,18 +267,7 @@ def _parse_args(argv): return args -def main(argv=sys.argv[1:]): - args = _parse_args(argv) - skip_keys = set(args.skip_keys or ()) - - if os.environ.get('ROS_DISTRO') not in (None, '', args.ros_distro): - print( - "Environment variable 'ROS_DISTRO' does not match package name", - file=sys.stderr) - return 1 - - os.environ['ROS_DISTRO'] = args.ros_distro - +def get_dependencies(args, skip_keys): resolver = DependencyResolver() pkg = parse_package(args.manifest_path) @@ -292,7 +279,7 @@ def main(argv=sys.argv[1:]): # Runtime deps if not args.is_devel: for dep in resolver.enumerate_rosdeps( - pkg, conflicts=args.conflicts, obsoletes=args.obsoletes, + pkg, conflicts=args.conflicts, requires=args.requires, resolve_groups=args.resolve_groups, ): if str(dep) in skip_keys: @@ -307,7 +294,7 @@ def main(argv=sys.argv[1:]): # Devel deps if not args.is_runtime: for dep in resolver.enumerate_rosdeps( - pkg, conflicts=args.conflicts, obsoletes=args.obsoletes, + pkg, conflicts=args.conflicts, requires_devel=args.requires_devel, resolve_groups=args.resolve_groups, ): @@ -337,6 +324,23 @@ def main(argv=sys.argv[1:]): ): sysdeps[sysdep].update(constraints) + if args.obsoletes: + for dep in pkg.replaces: + if dep.evaluated_condition is not True: + continue + if str(dep.name) in skip_keys: + print(f'Skipping dependency: {dep.name}', file=sys.stderr) + continue + + dep_name_sanitized = dep.name.replace('_', '-') + constraints = set(resolver.enumerate_constraints(dep)) + if args.is_runtime: + sysdep = f"ros-{args.ros_distro}-{dep_name_sanitized}-runtime" + sysdeps[sysdep].update(constraints) + else: + sysdep = f"ros-{args.ros_distro}-{dep_name_sanitized}-devel" + sysdeps[sysdep].update(constraints) + if args.provides: if not args.is_devel: pkgprov = f'ros-{args.ros_distro}({pkg.name})' @@ -373,6 +377,23 @@ def main(argv=sys.argv[1:]): groupprov = f'ros-{args.ros_distro}({group})(devel)(all)' sysdeps.setdefault(groupprov, set()) + return dict(sysdeps) + + +def main(argv=sys.argv[1:]): + args = _parse_args(argv) + skip_keys = set(args.skip_keys or ()) + + if os.environ.get('ROS_DISTRO') not in (None, '', args.ros_distro): + print( + "Environment variable 'ROS_DISTRO' does not match package name", + file=sys.stderr) + return 1 + + os.environ['ROS_DISTRO'] = args.ros_distro + + sysdeps = get_dependencies(args, skip_keys) + for sysdep, constraints in sorted(sysdeps.items()): if not constraints: print(sysdep) diff --git a/test/unit_tests/test_bloom_deps.py b/test/unit_tests/test_bloom_deps.py index 39a62fdc..5daf54c3 100644 --- a/test/unit_tests/test_bloom_deps.py +++ b/test/unit_tests/test_bloom_deps.py @@ -183,3 +183,18 @@ def test_enumerate_msg_pkg_workaround_deps(self): resolver.evaluate_conditions(pkg, 'rolling') deps = bloom_deps.DependencyResolver.enumerate_msg_pkg_workaround_deps(pkg) self.assertCountEqual(deps, ('rosidl_default_generators',)) + + def test_replaces(self): + # 1. Runtime subpackage with --obsoletes + argv = [self.package_xml_path, 'ros-rolling-my-pkg-runtime', '--obsoletes'] + args = bloom_deps._parse_args(argv) + sysdeps = bloom_deps.get_dependencies(args, set()) + self.assertEqual(sysdeps['ros-rolling-foobar-runtime'], set()) + self.assertEqual(sysdeps['ros-rolling-foo-bar-runtime'], {'< 2.0'}) + + # 2. Devel/non-runtime subpackage with --obsoletes + argv = [self.package_xml_path, 'ros-rolling-my-pkg-devel', '--obsoletes'] + args = bloom_deps._parse_args(argv) + sysdeps = bloom_deps.get_dependencies(args, set()) + self.assertEqual(sysdeps['ros-rolling-foobar-devel'], set()) + self.assertEqual(sysdeps['ros-rolling-foo-bar-devel'], {'< 2.0'}) diff --git a/test/unit_tests/test_bloom_deps_data/test_replaces/package.xml b/test/unit_tests/test_bloom_deps_data/test_replaces/package.xml new file mode 100644 index 00000000..bdca7be1 --- /dev/null +++ b/test/unit_tests/test_bloom_deps_data/test_replaces/package.xml @@ -0,0 +1,14 @@ + + + + my_pkg + 1.2.3 + Test package for replaces + Tester + Apache-2.0 + + ament_cmake + + foobar + foo_bar +