Esempio n. 1
0
async def test_bundle():
    descriptor = PackageDescriptor('some/path')
    descriptor.name = 'python_package'
    deps = [DependencyDescriptor('pkg1', metadata={'version_eq': '1.3.2'}),
            DependencyDescriptor('pkg_in_workspace'),
            DependencyDescriptor('pkg2', metadata={'version_lt': '1.2'}),
            'ignored_pkg']
    descriptor.dependencies['run'] = deps

    workspace = {'pkg_in_workspace': 'path/to/pkg'}
    task_args = MagicMock(build_base='build/base',
                          install_base='install/base',
                          bundle_base='bundle/base')
    pip_installer = MagicMock()
    apt_installer = MagicMock()
    args = BundlePackageArguments(
        descriptor, {'pip3': pip_installer, 'apt': apt_installer}, task_args)
    context = TaskContext(pkg=descriptor, args=args, dependencies=workspace)
    task = PythonBundleTask()
    task.set_context(context=context)

    await task.bundle()

    pip_installer.add_to_install_list.assert_called_once_with('pkg1==1.3.2')

    apt_calls = apt_installer.add_to_install_list.call_args_list
    assert len(apt_calls) == 2
    assert apt_calls[0][0][0] == 'libpython3-dev'
    assert apt_calls[1][0][0] == 'python3-pip'
Esempio n. 2
0
def test_constructor():
    d = DependencyDescriptor('foo')
    assert d == 'foo'
    assert str(d) == 'foo'
    assert d.name == 'foo'
    assert len(d.metadata) == 0

    d = DependencyDescriptor('foo', metadata={'bar': 'baz'})
    assert d == 'foo'
    assert str(d) == 'foo'
    assert d.name == 'foo'
    assert len(d.metadata) == 1
    assert 'bar' in d.metadata
    assert d.metadata['bar'] == 'baz'
Esempio n. 3
0
    def identify(self, desc):  # noqa: D102
        # ignore packages which have been identified with a different type
        if desc.type is not None and desc.type != 'ros':
            return

        # skip paths with an ignore marker file
        if (desc.path / 'CATKIN_IGNORE').exists():
            raise IgnoreLocationException()
        if (desc.path / 'AMENT_IGNORE').exists():
            raise IgnoreLocationException()

        # parse package manifest and get build type
        pkg, build_type = get_package_with_build_type(str(desc.path))
        if not pkg or not build_type:
            # if it is not a wet ROS package check for a dry ROS package
            if (desc.path / 'manifest.xml').exists():
                # ignore location to avoid being identified as a CMake package
                raise IgnoreLocationException()
            return

        desc.type = 'ros.{build_type}'.format_map(locals())

        # use package name from manifest if not already set
        # e.g. from external configuration
        if desc.name is None:
            desc.name = pkg.name

        desc.metadata['version'] = pkg.version

        # get dependencies
        for d in pkg.build_depends + pkg.buildtool_depends:
            assert d.evaluated_condition is not None
            if d.evaluated_condition:
                desc.dependencies['build'].add(
                    DependencyDescriptor(d.name, metadata=_create_metadata(d)))

        for d in (pkg.build_export_depends + pkg.buildtool_export_depends +
                  pkg.exec_depends):
            assert d.evaluated_condition is not None
            if d.evaluated_condition:
                desc.dependencies['run'].add(
                    DependencyDescriptor(d.name, metadata=_create_metadata(d)))

        for d in pkg.test_depends:
            assert d.evaluated_condition is not None
            if d.evaluated_condition:
                desc.dependencies['test'].add(
                    DependencyDescriptor(d.name, metadata=_create_metadata(d)))
Esempio n. 4
0
def create_dependency_descriptor(requirement_string):
    """
    Create a DependencyDescriptor from a PEP440 compliant string.

    See https://www.python.org/dev/peps/pep-0440/#version-specifiers

    :param str requirement_string: a PEP440 compliant requirement string
    :return: A descriptor with version constraints from the requirement string
    :rtype: DependencyDescriptor
    """
    symbol_mapping = {
        '==': 'version_eq',
        '!=': 'version_neq',
        '<=': 'version_lte',
        '>=': 'version_gte',
        '>': 'version_gt',
        '<': 'version_lt',
    }

    requirement = parse_requirement(requirement_string)
    metadata = {}
    for symbol, version in (requirement.constraints or []):
        if symbol in symbol_mapping:
            metadata[symbol_mapping[symbol]] = version
        elif symbol == '~=':
            metadata['version_gte'] = version
            metadata['version_lt'] = _next_incompatible_version(version)
        else:
            logger.warn(
                "Ignoring unknown symbol '{symbol}' in '{requirement}'".format(
                    locals()))
    return DependencyDescriptor(requirement.name, metadata=metadata)
 def test_dependencies_changed(self):
     package_1_desc = PackageDescriptor('fake/path')
     package_1_desc.name = 'package1'
     package_1_desc.dependencies['run'] = [DependencyDescriptor('foo')]
     package_1 = PackageDecorator(package_1_desc)
     decorators = [package_1]
     self.assertTrue(
         package_dependencies_changed(self.path_context, decorators))
     update_dependencies_cache(self.path_context)
     package_1_desc.dependencies['run'] = [
         DependencyDescriptor('foo'), 'baz'
     ]
     package_1 = PackageDecorator(package_1_desc)
     decorators = [package_1]
     self.assertTrue(
         package_dependencies_changed(self.path_context, decorators))
Esempio n. 6
0
def test_constructor():
    d = DependencyDescriptor('foo')
    assert d == 'foo'
    assert str(d) == 'foo'
    assert d.name == 'foo'
    assert len(d.metadata) == 0

    d = DependencyDescriptor('foo', metadata={'bar': 'baz'})
    assert d == 'foo'
    assert str(d) == 'foo'
    assert d.name == 'foo'
    assert len(d.metadata) == 1
    assert 'bar' in d.metadata
    assert d.metadata['bar'] == 'baz'

    d2 = copy.deepcopy(d)
    assert d.name == d2.name
    assert d.metadata == d2.metadata
    d.metadata['bar'] = 'baz baz'
    assert d.metadata != d2.metadata
Esempio n. 7
0
async def test_bundle():
    pkg = PackageDescriptor('package/path')
    pkg.name = 'MyPackageName'
    pkg.dependencies['run'] = {
        DependencyDescriptor('source_pkg'),
        DependencyDescriptor('other_pkg'),
        DependencyDescriptor('system_pkg')
    }
    installers = {
        'rdmanifest': MagicMock(),
        'system': MagicMock(),
        'other': MagicMock()
    }
    top_level_args = MagicMock(build_base='build/base',
                               install_base='install/base',
                               bundle_base='bundle/base')
    args = BundlePackageArguments(pkg, installers, top_level_args)
    args.ros_distribution = 'kinetic'
    args.exclude_ros_base = True

    context = TaskContext(pkg=pkg, args=args, dependencies={})
    task = RosBundle()
    task.set_context(context=context)

    # Concise read on why it's patched this way.
    # http://www.voidspace.org.uk/python/mock/patch.html#where-to-patch
    with patch('colcon_ros_bundle.task.ros_bundle.RosdepWrapper'
               ) as wrapper:  # noqa: E501
        wrapper().get_rule.side_effect = _get_rule_side_effect
        wrapper().resolve.side_effect = _resolve_side_effect
        await task.bundle()

    installers['rdmanifest'].add_to_install_list.assert_called_with(
        'source_pkg', {
            's': 'ource',
            'uri': 'rdmanifest'
        })
    installers['other'].add_to_install_list.assert_called_with(
        'other_pkg_name')
    installers['system'].add_to_install_list.assert_called_with(
        'system_pkg_name')
Esempio n. 8
0
    def augment_packages(  # noqa: D102
            self, descs, *, additional_argument_names=None):
        # get all parsed ROS package manifests
        global _cached_packages
        pkgs = {}
        for desc in descs:
            if str(desc.path) not in _cached_packages:
                continue
            pkg = _cached_packages[str(desc.path)][0]
            if pkg:
                pkgs[pkg] = desc

        # resolve group members and add them to the descriptor dependencies
        for pkg, desc in pkgs.items():
            for group_depend in pkg.group_depends:
                assert group_depend.evaluated_condition is not None
                if not group_depend.evaluated_condition:
                    continue
                group_depend.extract_group_members(pkgs)
                for name in group_depend.members:
                    desc.dependencies['build'].add(DependencyDescriptor(name))
                    desc.dependencies['run'].add(DependencyDescriptor(name))
    def get_dependencies(self, *, categories=None):
        """
        Get the dependencies for specific categories or for all categories.

        :param Iterable[str] categories: The names of the specific categories
        :returns: The dependencies
        :rtype: set[DependencyDescriptor]
        :raises AssertionError: if the package name is listed as a dependency
        """
        dependencies = set()
        if categories is None:
            categories = self.dependencies.keys()
        for category in sorted(categories):
            dependencies |= self.dependencies[category]
        assert self.name not in dependencies, \
            "The package '{self.name}' has a dependency with the same name" \
            .format_map(locals())
        return {(DependencyDescriptor(d) if d is str else d)
                for d in dependencies}
Esempio n. 10
0
    def identify(self, desc):  # noqa: D102
        # ignore packages which have been identified with a different type
        if desc.type is not None and desc.type != 'ros':
            return

        # skip paths with an ignore marker file
        if (desc.path / 'CATKIN_IGNORE').exists():
            raise IgnoreLocationException()
        if (desc.path / 'AMENT_IGNORE').exists():
            raise IgnoreLocationException()

        # parse package manifest and get build type
        pkg, build_type = get_package_with_build_type(str(desc.path))
        if not pkg or not build_type:
            # if it is not a wet ROS package check for a dry ROS package
            if (desc.path / 'manifest.xml').exists():
                # ignore location to avoid being identified as a CMake package
                raise IgnoreLocationException()
            return

        # for Python build types ensure that a setup.py file exists
        if build_type == 'ament_python':
            setup_py = desc.path / 'setup.py'
            if not setup_py.is_file():
                logger.error(
                    "ROS package '{desc.path}' with build type '{build_type}' "
                    "has no 'setup.py' file".format_map(locals()))
                raise IgnoreLocationException()

        desc.type = 'ros.{build_type}'.format_map(locals())

        # use package name from manifest if not already set
        # e.g. from external configuration
        if desc.name is None:
            desc.name = pkg.name

        desc.metadata['version'] = pkg.version

        # get dependencies
        for d in pkg.build_depends + pkg.buildtool_depends:
            assert d.evaluated_condition is not None
            if d.evaluated_condition:
                desc.dependencies['build'].add(
                    DependencyDescriptor(d.name, metadata=_create_metadata(d)))

        for d in (pkg.build_export_depends + pkg.buildtool_export_depends +
                  pkg.exec_depends):
            assert d.evaluated_condition is not None
            if d.evaluated_condition:
                desc.dependencies['run'].add(
                    DependencyDescriptor(d.name, metadata=_create_metadata(d)))

        for d in pkg.test_depends:
            assert d.evaluated_condition is not None
            if d.evaluated_condition:
                desc.dependencies['test'].add(
                    DependencyDescriptor(d.name, metadata=_create_metadata(d)))

        # for Python build types ensure that a setup.py file exists
        if build_type == 'ament_python':
            setup_cfg = desc.path / 'setup.cfg'
            for _ in (1, ):
                # try to get information from setup.cfg file
                if setup_cfg.is_file():
                    if is_reading_cfg_sufficient(setup_py):
                        config = get_configuration(setup_cfg)
                        name = config.get('metadata', {}).get('name')
                        if name:
                            options = config.get('options', {})

                            def getter(env):
                                nonlocal options
                                return options

                            break
            else:
                # use information from setup.py file

                def getter(env):  # noqa: F811
                    nonlocal desc
                    return get_setup_information(desc.path / 'setup.py',
                                                 env=env)

            desc.metadata['get_python_setup_options'] = getter