コード例 #1
0
def create_environment_scripts_only(prefix_path,
                                    pkg,
                                    *,
                                    default_hooks=None,
                                    additional_hooks=None):
    """
    Create the environment scripts for a package.

    :param prefix_path: The prefix path
    :param pkg: The package descriptor
    :param list default_hooks: If none are parsed explicitly the hooks provided
      by :function:`create_environment_hooks` are used
    :param list additional_hooks: Any additional hooks which should be
      referenced by the generated scripts
    """
    logger.log(1, 'create_environment_scripts_only(%s)', pkg.name)

    hooks = []
    if default_hooks is None:
        default_hooks = create_environment_hooks(prefix_path, pkg.name)
    hooks += default_hooks
    if additional_hooks:
        hooks += additional_hooks
    hooks += pkg.hooks

    # ensure each hook is presented by a tuple
    # with the first element being a relative path
    # and the second element being a list of arguments
    hook_tuples = []
    for hook in hooks:
        hook_args = []
        if isinstance(hook, list) or isinstance(hook, tuple):
            hook_args = hook[1:]
            hook = hook[0]

        if os.path.isabs(str(hook)):
            hook = os.path.relpath(str(hook), start=str(prefix_path))

        hook_tuples.append((hook, hook_args))

    extensions = get_shell_extensions()
    for priority in extensions.keys():
        extensions_same_prio = extensions[priority]
        for extension in extensions_same_prio.values():
            try:
                retval = extension.create_package_script(
                    prefix_path, pkg.name, hook_tuples)
                assert retval is None, \
                    'create_package_script() should return None'
            except Exception as e:  # noqa: F841
                # catch exceptions raised in shell extension
                exc = traceback.format_exc()
                logger.error(
                    "Exception in shell extension '{extension.SHELL_NAME}': "
                    '{e}\n{exc}'.format_map(locals()))
コード例 #2
0
ファイル: build.py プロジェクト: seanyen/colcon-ros
    async def build(self):  # noqa: D102
        args = self.context.args
        logger.info("Building ROS package in '{args.path}' with build type "
                    "'ament_cmake'".format_map(locals()))

        # reuse CMake build task with additional logic
        extension = CmakeBuildTask()
        extension.set_context(context=self.context)

        # additional arguments
        if args.test_result_base:
            if args.cmake_args is None:
                args.cmake_args = []
            # ament_cmake appends the project name itself
            args.cmake_args.append('-DAMENT_TEST_RESULTS_DIR=' +
                                   os.path.dirname(args.test_result_base))
        if args.symlink_install:
            if args.cmake_args is None:
                args.cmake_args = []
            args.cmake_args.append('-DAMENT_CMAKE_SYMLINK_INSTALL=1')
        if args.ament_cmake_args:
            if args.cmake_args is None:
                args.cmake_args = []
            args.cmake_args += args.ament_cmake_args

        rc = await extension.build(skip_hook_creation=False,
                                   environment_callback=add_app_to_cpp)

        # if the build has failed getting targets might not be possible
        try:
            has_install_target = await has_target(args.build_base, 'install')
        except Exception:  # noqa: B902
            if not rc:
                raise
            has_install_target = False

        # add a hook for each available shell
        # only if the package has an install target
        additional_hooks = []
        if has_install_target:
            shell_extensions = get_shell_extensions()
            file_extensions = []
            for shell_extensions_same_prio in shell_extensions.values():
                for shell_extension in shell_extensions_same_prio.values():
                    file_extensions += shell_extension.get_file_extensions()
            for ext in sorted(file_extensions):
                additional_hooks.append(
                    'share/{self.context.pkg.name}/local_setup.{ext}'.
                    format_map(locals()))

        create_environment_scripts(self.context.pkg,
                                   args,
                                   additional_hooks=additional_hooks)

        return rc
コード例 #3
0
ファイル: test_shell.py プロジェクト: tobiasblass/colcon-core
def test_get_command_environment():
    with EntryPointContext(extension1=Extension1, extension2=Extension2):
        extensions = get_shell_extensions()

        # one not implemented, one skipped extension
        extensions[90]['extension1'].generate_command_environment = Mock(
            side_effect=SkipExtensionException())
        coroutine = get_command_environment(None, '/build/base', None)
        with patch('colcon_core.shell.logger.debug') as debug:
            with patch('colcon_core.shell.logger.info') as info:
                with pytest.raises(RuntimeError) as e:
                    run_until_complete(coroutine)
        assert 'Could not find a shell extension for the command environment' \
            in str(e.value)
        assert extensions[90]['extension1'].generate_command_environment \
            .call_count == 1
        # the raised exceptions are catched and result in a debug/info message
        assert debug.call_count == 1
        assert len(debug.call_args[0]) == 1
        assert debug.call_args[0][0] == \
            "Skip shell extension 'extension2' for command environment"
        assert info.call_count == 1
        assert len(info.call_args[0]) == 1
        assert info.call_args[0][0].startswith(
            "Skip shell extension 'extension1' for command environment: ")

        # raise runtime error
        extensions[100]['extension2'].generate_command_environment = Mock(
            side_effect=RuntimeError('custom exception'))
        extensions[90]['extension1'].generate_command_environment.reset_mock()
        coroutine = get_command_environment(None, '/build/base', None)
        with pytest.raises(RuntimeError) as e:
            run_until_complete(coroutine)
        assert str(e.value) == 'custom exception'
        assert extensions[90]['extension1'].generate_command_environment \
            .call_count == 0

        # one exception, one successful
        extensions[100]['extension2'].generate_command_environment = Mock(
            side_effect=Exception('custom exception'))
        extensions[90]['extension1'].generate_command_environment = Mock(
            side_effect=generate_command_environment)
        coroutine = get_command_environment(None, '/build/base', None)
        with patch('colcon_core.shell.logger.error') as error:
            env = run_until_complete(coroutine)
        assert env == {'key': 'value'}
        # the raised exception is catched and results in an error message
        assert error.call_count == 1
        assert len(error.call_args[0]) == 1
        assert error.call_args[0][0].startswith(
            "Exception in shell extension 'extension2': custom exception\n")
コード例 #4
0
 def _create_prefix_scripts(self, install_base, merge_install):
     extensions = get_shell_extensions()
     for priority in extensions.keys():
         extensions_same_prio = extensions[priority]
         for extension in extensions_same_prio.values():
             try:
                 retval = extension.create_prefix_script(
                     Path(install_base), merge_install)
                 assert retval is None, \
                     'create_prefix_script() should return None'
             except Exception as e:  # noqa: F841
                 # catch exceptions raised in shell extension
                 exc = traceback.format_exc()
                 logger.error(
                     'Exception in shell extension '
                     "'{extension.SHELL_NAME}': {e}\n{exc}".format_map(
                         locals()))
コード例 #5
0
def test_create_environment_scripts():
    with TemporaryDirectory(prefix='test_colcon_') as basepath:
        pkg = Mock()
        pkg.name = 'name'
        pkg.dependencies = {}
        pkg.hooks = []
        args = Mock()
        args.install_base = basepath

        # no hooks at all
        with patch(
            'colcon_core.environment.create_environment_hooks', return_value=[]
        ):
            with patch(
                'colcon_core.environment.get_shell_extensions', return_value={}
            ):
                create_environment_scripts(pkg, args)

        pkg.hooks = [os.path.join(basepath, 'subA')]
        with EntryPointContext(extension3=Extension3, extension4=Extension4):
            extensions = get_shell_extensions()
            # one invalid return value, one check correct hooks argument
            extensions[100]['extension3'].create_package_script = Mock()
            extensions[100]['extension4'].create_package_script = Mock(
                return_value=None)
            with patch('colcon_core.environment.logger.error') as error:
                create_environment_scripts(
                    pkg, args, default_hooks=[('subB', )],
                    additional_hooks=[['subC', 'arg1', 'arg2']])
            # the raised exception is catched and results in an error message
            assert error.call_count == 1
            assert len(error.call_args[0]) == 1
            assert error.call_args[0][0].startswith(
                "Exception in shell extension 'extension3': "
                'create_package_script() should return None\n')
            # check for correct hooks argument
            mock = extensions[100]['extension4'].create_package_script
            assert mock.call_count == 1
            assert len(mock.call_args[0]) == 3
            assert mock.call_args[0][0] == Path(args.install_base)
            assert mock.call_args[0][1] == pkg.name
            hook_tuples = mock.call_args[0][2]
            assert len(hook_tuples) == 3
            assert hook_tuples[0] == ('subB', ())
            assert hook_tuples[1] == ('subC', ['arg1', 'arg2'])
            assert hook_tuples[2] == ('subA', [])
コード例 #6
0
    async def build(self):  # noqa: D102
        args = self.context.args
        logger.info("Building ROS package in '{args.path}' with build type "
                    "'ament_cmake'".format_map(locals()))

        # reuse CMake build task with additional logic
        extension = CmakeBuildTask()
        extension.set_context(context=self.context)

        # add a hook for each available shell
        additional_hooks = create_environment_hook('ament_current_prefix',
                                                   Path(args.install_base),
                                                   self.context.pkg.name,
                                                   'AMENT_CURRENT_PREFIX',
                                                   '',
                                                   mode='prepend')
        shell_extensions = get_shell_extensions()
        file_extensions = []
        for shell_extensions_same_prio in shell_extensions.values():
            for shell_extension in shell_extensions_same_prio.values():
                file_extensions += shell_extension.get_file_extensions()
        for file_extension in sorted(file_extensions):
            additional_hooks.append(
                'share/{self.context.pkg.name}/local_setup.{file_extension}'.
                format_map(locals()))

        # additional arguments
        if args.test_result_base:
            if args.cmake_args is None:
                args.cmake_args = []
            # ament_cmake appends the project name itself
            args.cmake_args.append('-DAMENT_TEST_RESULTS_DIR=' +
                                   os.path.dirname(args.test_result_base))
        if args.symlink_install:
            if args.cmake_args is None:
                args.cmake_args = []
            args.cmake_args.append('-DAMENT_CMAKE_SYMLINK_INSTALL=1')
        if args.ament_cmake_args:
            if args.cmake_args is None:
                args.cmake_args = []
            args.cmake_args += args.ament_cmake_args

        return await extension.build(environment_callback=add_app_to_cpp,
                                     additional_hooks=additional_hooks)
コード例 #7
0
ファイル: test_shell.py プロジェクト: tobiasblass/colcon-core
def test_create_environment_hook():
    with EntryPointContext(extension1=Extension1, extension2=Extension2):
        # no primary shell extension
        with pytest.raises(RuntimeError) as e:
            create_environment_hook(None, None, None, None, None)
        assert str(e.value).endswith(
            'Could not find a primary shell extension for creating an '
            'environment hook')

    with EntryPointContext(extension3=Extension3,
                           extension4=Extension4,
                           extension5=Extension5):
        extensions = get_shell_extensions()

        # one invalid, two valid return values
        extensions[105]['extension3'].create_hook_prepend_value = Mock()
        extensions[101]['extension4'].create_hook_prepend_value = Mock(
            return_value=Path('/some/path/sub/hookA'))
        extensions[110]['extension5'].create_hook_prepend_value = Mock(
            return_value=Path('/some/path/sub/hookB'))
        with patch('colcon_core.shell.logger.error') as error:
            hooks = create_environment_hook(None, None, None, None, None)
        assert len(hooks) == 2
        assert str(hooks[0]) == '/some/path/sub/hookB'.replace('/', os.sep)
        assert str(hooks[1]) == '/some/path/sub/hookA'.replace('/', os.sep)
        # the raised exception is catched and results in an error message
        assert error.call_count == 1
        assert len(error.call_args[0]) == 1
        assert error.call_args[0][0].startswith(
            "Exception in shell extension 'extension3': "
            'create_hook_prepend_value() should return a Path object')

        # invalid mode
        with pytest.raises(NotImplementedError):
            create_environment_hook(None,
                                    None,
                                    None,
                                    None,
                                    None,
                                    mode='invalid')
コード例 #8
0
ファイル: test_shell.py プロジェクト: tobiasblass/colcon-core
def test_get_shell_extensions():
    with EntryPointContext(extension1=Extension1, extension2=Extension2):
        extensions = get_shell_extensions()
    assert list(extensions.keys()) == [100, 90]
    assert list(extensions[100].keys()) == ['extension2']
    assert list(extensions[90].keys()) == ['extension1']
コード例 #9
0
    async def build(self):  # noqa: D102
        args = self.context.args
        logger.info(
            "Building ROS package in '{args.path}' with build type 'catkin'".
            format_map(locals()))

        # reuse CMake build task with additional logic
        extension = CmakeBuildTask()
        extension.set_context(context=self.context)

        # additional arguments
        if args.cmake_args is None:
            args.cmake_args = []
        args.cmake_args += ['-DCATKIN_INSTALL_INTO_PREFIX_ROOT=0']
        if args.test_result_base:
            # catkin appends the project name itself
            args.cmake_args.append('-DCATKIN_TEST_RESULTS_DIR=' +
                                   os.path.dirname(args.test_result_base))
        if args.catkin_cmake_args:
            args.cmake_args += args.catkin_cmake_args

        # invoke the build
        additional_targets = []
        # if no specific target is specified consider building the 'tests'
        # target and continue if such a target doesn't exist
        if args.cmake_target is None:
            if not args.catkin_skip_building_tests:
                additional_targets.append('tests')
                args.cmake_target_skip_unavailable = True
        rc = await extension.build(skip_hook_creation=True,
                                   additional_targets=additional_targets)

        # for catkin packages add additional hooks after the package has
        # been built and installed depending on the installed files
        additional_hooks = create_environment_hook('ros_package_path',
                                                   Path(args.install_base),
                                                   self.context.pkg.name,
                                                   'ROS_PACKAGE_PATH',
                                                   'share',
                                                   mode='prepend')
        additional_hooks += create_pythonpath_environment_hook(
            Path(args.install_base), self.context.pkg.name)
        additional_hooks += create_pkg_config_path_environment_hooks(
            Path(args.install_base), self.context.pkg.name)

        # register hooks created via catkin_add_env_hooks
        shell_extensions = get_shell_extensions()
        file_extensions = OrderedDict()
        for shell_extensions_same_prio in shell_extensions.values():
            for shell_extension in shell_extensions_same_prio.values():
                for file_extension in shell_extension.get_file_extensions():
                    file_extensions[file_extension] = shell_extension
        custom_hooks_path = Path(args.install_base) / \
            'share' / self.context.pkg.name / 'catkin_env_hook'
        for file_extension, shell_extension in file_extensions.items():
            file_extension_hooks = sorted(
                custom_hooks_path.glob('*.{file_extension}'.format_map(
                    locals())))
            if file_extension_hooks:
                try:
                    # try to set CATKIN_ENV_HOOK_WORKSPACE explicitly before
                    # sourcing these hooks
                    additional_hooks.append(
                        shell_extension.create_hook_set_value(
                            'catkin_env_hook_workspace',
                            Path(args.install_base), self.context.pkg.name,
                            'CATKIN_ENV_HOOK_WORKSPACE',
                            '$COLCON_CURRENT_PREFIX'))
                except NotImplementedError:
                    # since not all shell extensions might implement this
                    pass
                additional_hooks += file_extension_hooks

        create_environment_scripts(self.context.pkg,
                                   args,
                                   additional_hooks=additional_hooks)

        # ensure that the install base has the marker file
        # identifying it as a catkin workspace
        marker = Path(args.install_base) / '.catkin'
        marker.touch(exist_ok=True)

        return rc
コード例 #10
0
ファイル: __init__.py プロジェクト: sniperkit/colcon-core
def create_environment_scripts(
    pkg, args, *, default_hooks=None, additional_hooks=None
):
    """
    Create the environment scripts for a package.

    Also create a file with the runtime dependencies of each packages which can
    be used by the prefix scripts to source all packages in topological order.

    :param pkg: The package descriptor
    :param args: The parsed command line arguments
    :param list default_hooks: If none are parsed explicitly the hooks provided
      by :function:`create_environment_hooks` are used
    :param list additional_hooks: Any additional hooks which should be
      referenced by the generated scripts
    :returns: iterable of the generated hook paths
    :rtype: Iterable
    """
    logger.log(1, 'create_environment_scripts()')
    prefix_path = Path(args.install_base)

    hooks = []
    if default_hooks is None:
        default_hooks = create_environment_hooks(prefix_path, pkg.name)
    hooks += default_hooks
    if additional_hooks:
        hooks += additional_hooks
    hooks += pkg.hooks

    # ensure each hook is presented by a tuple
    # with the first element being a relative path
    # and the second element being a list of arguments
    hook_tuples = []
    for hook in hooks:
        hook_args = []
        if isinstance(hook, list) or isinstance(hook, tuple):
            hook_args = hook[1:]
            hook = hook[0]

        if os.path.isabs(str(hook)):
            hook = os.path.relpath(str(hook), start=str(prefix_path))

        hook_tuples.append((hook, hook_args))

    extensions = get_shell_extensions()
    for priority in extensions.keys():
        extensions_same_prio = extensions[priority]
        for extension in extensions_same_prio.values():
            try:
                retval = extension.create_package_script(
                    prefix_path, pkg.name, hook_tuples)
                assert retval is None, \
                    'create_package_script() should return None'
            except Exception as e:
                # catch exceptions raised in shell extension
                exc = traceback.format_exc()
                logger.error(
                    "Exception in shell extension '{extension.SHELL_NAME}': "
                    '{e}\n{exc}'.format_map(locals()))
                # skip failing extension, continue with next one

    # create file containing the runtime dependencies
    path = prefix_path / get_relative_package_index_path() / pkg.name
    path.parent.mkdir(parents=True, exist_ok=True)
    path.write_text(
        os.pathsep.join(sorted(pkg.dependencies.get('run', set()))))