Ejemplo n.º 1
0
def create_pkg_config_path_environment_hooks(basepath, pkg_name):
    """
    Create hook scripts to prepend to the PKG_CONFIG_PATH.

    :param Path basepath: The path of the prefix
    :param str pkg_name: The package name
    :returns: The relative paths to the created hook scripts
    :rtype: list
    """
    hooks = create_environment_hook('pkg_config_path',
                                    basepath,
                                    pkg_name,
                                    'PKG_CONFIG_PATH',
                                    os.path.join('lib', 'pkgconfig'),
                                    mode='prepend')
    if platform.system() == 'Linux':
        multiarch = get_multiarch()
        if multiarch:
            hooks += create_environment_hook('pkg_config_path_multiarch',
                                             basepath,
                                             pkg_name,
                                             'PKG_CONFIG_PATH',
                                             os.path.join(
                                                 'lib', multiarch,
                                                 'pkgconfig'),
                                             mode='prepend')
    return hooks
Ejemplo n.º 2
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

        # additional hooks
        additional_hooks = create_environment_hook('ros_package_path',
                                                   Path(args.install_base),
                                                   self.context.pkg.name,
                                                   'ROS_PACKAGE_PATH',
                                                   'share',
                                                   mode='prepend')

        # for catkin packages add additional hooks after the package has
        # been built and installed depending on the installed files
        rc = await extension.build(skip_hook_creation=True)

        # add Python 2 specific path to PYTHONPATH if it exists
        if os.environ.get('ROS_PYTHON_VERSION', '2') == '2':
            for subdirectory in ('dist-packages', 'site-packages'):
                python_path = Path(args.install_base) / \
                    'lib' / 'python2.7' / subdirectory
                logger.log(1, "checking '%s'" % python_path)
                if python_path.exists():
                    rel_python_path = python_path.relative_to(
                        args.install_base)
                    additional_hooks += create_environment_hook(
                        'python2path',
                        Path(args.install_base),
                        self.context.pkg.name,
                        'PYTHONPATH',
                        str(rel_python_path),
                        mode='prepend')
        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
Ejemplo n.º 3
0
    async def build(self,
                    *,
                    additional_hooks=[],
                    skip_hook_creation=False):  # noqa: D102
        pkg = self.context.pkg
        args = self.context.args

        logger.info("Building Cargo package in '{args.path}'".format_map(
            locals()))

        try:
            env = await get_command_environment('build', args.build_base,
                                                self.context.dependencies)
        except RuntimeError as e:
            logger.error(str(e))
            return 1

        rc = await self._build(args, env)
        if rc and rc.returncode:
            return rc.returncode

        additional_hooks += create_environment_hook(
            'cargo_{}_path'.format(pkg.name),
            Path(args.install_base),
            pkg.name,
            'PATH',
            os.path.join('lib', self.context.pkg.name, 'bin'),
            mode='prepend')

        if not skip_hook_creation:
            create_environment_scripts(pkg,
                                       args,
                                       additional_hooks=additional_hooks)
Ejemplo n.º 4
0
    def create_environment_hooks(self, prefix_path, pkg_name):  # noqa: D102
        hooks = OrderedDict()

        logger.log(1, "checking '%s' for CMake module files" % prefix_path)
        for path in self._get_potential_cmake_module_paths(
                prefix_path, pkg_name):
            if not path.is_dir():
                continue
            # skip paths which are the same but only differ in case
            if any(path.samefile(p) for p in hooks.keys()):
                continue

            for filename in path.iterdir():
                if not filename.is_file():
                    continue
                if (filename.name.startswith('Find')
                        and filename.name.endswith('.cmake')):
                    hooks[path] = create_environment_hook(
                        'cmake_module_path' +
                        (str(len(hooks)) if hooks else ''),
                        prefix_path,
                        pkg_name,
                        'CMAKE_MODULE_PATH',
                        str(path.relative_to(prefix_path)),
                        mode='prepend')

        return hooks.values()
Ejemplo n.º 5
0
    async def test(self):  # noqa: D102
        args = self.context.args
        logger.info(
            "Testing ROS package in '{args.path}' with build type 'catkin'".
            format_map(locals()))

        # for catkin packages it is expected that the devel space
        # and not the install space is in the environment for testing
        self.context.dependencies[self.context.pkg.name] = \
            os.path.join(self.context.args.build_base, 'devel')

        # additional hooks
        additional_hooks = create_environment_hook('ros_package_path',
                                                   Path(args.build_base) /
                                                   'devel',
                                                   self.context.pkg.name,
                                                   'ROS_PACKAGE_PATH',
                                                   args.path,
                                                   mode='prepend')
        additional_hooks += create_pythonpath_environment_hook(
            Path(args.build_base) / 'devel', self.context.pkg.name)

        # generate the necessary setup files for the devel space
        create_environment_scripts_only(Path(args.build_base) / 'devel',
                                        self.context.pkg,
                                        additional_hooks=additional_hooks)

        # reuse CMake test task
        extension = CmakeTestTask()
        extension.set_context(context=self.context)
        return await extension.test()
Ejemplo n.º 6
0
    def create_environment_hooks(self, prefix_path, pkg_name):  # noqa: D102
        LibraryDescriptor = namedtuple(
            'LibraryDescriptor',
            ['hook_name', 'subdirectory', 'extension', 'environment_variable'])

        if sys.platform == 'win32':
            library_descriptors = [
                LibraryDescriptor('path_dll', 'bin', 'dll', 'PATH')
            ]
        elif platform.system() == 'Darwin':
            library_descriptors = [
                LibraryDescriptor(
                    'dyld_library_path', 'lib', 'dylib', 'DYLD_LIBRARY_PATH')]
        else:
            library_descriptors = [
                LibraryDescriptor(
                    'ld_library_path_{directory.name}'.format_map(locals()),
                    directory.name, 'so', 'LD_LIBRARY_PATH')
                for directory in prefix_path.glob('lib*')]

        environment_hooks = []
        for library_descriptor in library_descriptors:
            library_path = prefix_path / library_descriptor.subdirectory
            logger.log(1, "checking '%s'" % library_path)

            if any(library_path.glob('*.' + library_descriptor.extension)):
                environment_hooks += create_environment_hook(
                    library_descriptor.hook_name,
                    prefix_path, pkg_name,
                    library_descriptor.environment_variable,
                    library_descriptor.subdirectory, mode='prepend')

        return environment_hooks
Ejemplo n.º 7
0
    async def build(self):  # noqa: D102
        args = self.context.args
        logger.info("Building ROS package in '{args.path}' with build type "
                    "'ament_python'".format_map(locals()))

        # reuse Python build task with additional logic
        extension = PythonBuildTask()
        extension.set_context(context=self.context)

        # additional hooks
        additional_hooks = create_environment_hook('ament_prefix_path',
                                                   Path(args.install_base),
                                                   self.context.pkg.name,
                                                   'AMENT_PREFIX_PATH',
                                                   '',
                                                   mode='prepend')
        # create package marker in ament resource index
        create_file(
            args,
            'share/ament_index/resource_index/packages/{self.context.pkg.name}'
            .format_map(locals()))
        # copy / symlink package manifest
        install(
            args, 'package.xml',
            'share/{self.context.pkg.name}/package.xml'.format_map(locals()))

        return await extension.build(additional_hooks=additional_hooks)
Ejemplo n.º 8
0
def create_pythonpath_environment_hook(build_base, install_base, pkg_name):
    """
    Create a hook script for each primary shell to prepend to the PYTHONPATH.

    :param str build_base: The path of the build directory
    :param Path install_base: The path of the install prefix
    :param str pkg_name: The package name
    :returns: The relative paths to the created hook scripts
    :rtype: list
    """
    hooks = []
    # catkin packages might use `--install-layout deb`
    # therefore getting the used install directory from the CMake cache
    # since it might not match distutils.sysconfig.get_python_lib()
    rel_python_path = get_variable_from_cmake_cache(build_base,
                                                    'PYTHON_INSTALL_DIR')
    # prepend Python specific path to PYTHONPATH if it exists
    if rel_python_path:
        abs_python_path = install_base / rel_python_path
        logger.log(1, "checking '%s'" % abs_python_path)
        if abs_python_path.exists():
            hooks += create_environment_hook('catkin_pythonpath',
                                             install_base,
                                             pkg_name,
                                             'PYTHONPATH',
                                             rel_python_path,
                                             mode='prepend')
    return hooks
Ejemplo n.º 9
0
 def create_environment_hooks(self, prefix_path, pkg_name):  # noqa: D102
     subdirectory = Path('lib') / 'pkgconfig'
     pkg_config_file = prefix_path / subdirectory / (pkg_name + '.pc')
     logger.log(1, "checking '%s'" % pkg_config_file)
     if not pkg_config_file.is_file():
         return []
     return create_environment_hook('pkg_config',
                                    prefix_path,
                                    pkg_name,
                                    'PKG_CONFIG_PATH',
                                    str(subdirectory),
                                    mode='prepend')
Ejemplo n.º 10
0
    def create_environment_hooks(self, prefix_path, pkg_name):  # noqa: D102
        hooks = []

        python_path = Path(get_python_lib(prefix=str(prefix_path)))
        logger.log(1, "checking '%s'" % python_path)
        if python_path.exists():
            rel_python_path = python_path.relative_to(prefix_path)
            hooks += shell.create_environment_hook(
                'pythonpath', prefix_path, pkg_name,
                'PYTHONPATH', str(rel_python_path), mode='prepend')

        return hooks
Ejemplo n.º 11
0
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')
Ejemplo n.º 12
0
    def create_environment_hooks(self, prefix_path: Path,
                                 pkg_name: str):  # noqa D102
        hooks = []
        dub_path = prefix_path / 'lib' / 'dub' / pkg_name
        dub_package = DubPackage.load(dub_path)
        logger.log(1, "checking '%s'" % dub_path)

        if dub_package:
            hooks += shell.create_environment_hook('dub_package_path',
                                                   prefix_path,
                                                   pkg_name,
                                                   DUB_PACKAGE_PATH_ENV,
                                                   str(dub_package.path),
                                                   mode='prepend')

        return hooks
Ejemplo n.º 13
0
    def create_environment_hooks(self, prefix_path, pkg_name):  # noqa: D102
        hooks = []

        logger.log(1, "checking '%s' for CMake config files" % prefix_path)
        for _, _, filenames in os.walk(str(prefix_path)):
            for filename in filenames:
                if filename.endswith('-config.cmake') or \
                        filename.endswith('Config.cmake'):
                    hooks += create_environment_hook(
                        'cmake_prefix_path', prefix_path, pkg_name,
                        'CMAKE_PREFIX_PATH', '', mode='prepend')
                    break
            else:
                continue
            break

        return hooks
Ejemplo n.º 14
0
    async def build(self,
                    *,
                    additional_hooks=[],
                    skip_hook_creation=False):  # noqa: D102
        pkg = self.context.pkg
        args = self.context.args

        # TODO(jacobperron): This would be better handled by a more generic ament_java library
        additional_hooks += create_environment_hook('ament_prefix_path',
                                                    Path(args.install_base),
                                                    pkg.name,
                                                    'AMENT_PREFIX_PATH',
                                                    args.install_base,
                                                    mode='prepend')

        return await super(AmentGradleBuildTask,
                           self).build(additional_hooks=additional_hooks,
                                       skip_hook_creation=skip_hook_creation)
Ejemplo n.º 15
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)
Ejemplo n.º 16
0
    def _create_environment_hooks(
        self, prefix_path, pkg_name, subdirectory, suffix=''
    ):
        hooks = []
        bin_path = prefix_path / subdirectory
        logger.log(1, "checking '%s'" % bin_path)
        try:
            names = os.listdir(str(bin_path))
        except FileNotFoundError:
            pass
        else:
            for name in names:
                if not (bin_path / name).is_file():
                    continue
                hooks += shell.create_environment_hook(
                    'path' + suffix, prefix_path, pkg_name, 'PATH',
                    subdirectory, mode='prepend')
                break

        return hooks
Ejemplo n.º 17
0
    async def build(self,
                    *,
                    additional_hooks=None,
                    skip_hook_creation=False):  # noqa D102
        args = self.context.args  # BuildPackageArguments
        logger.info("Building ROS package in '{args.path}'"
                    "with build type 'ros.ament_dub'".format_map(locals()))

        extension = DubBuildTask()
        extension.set_context(context=self.context)

        additional_hooks = create_environment_hook('ament_prefix_path',
                                                   Path(args.install_base),
                                                   self.context.pkg.name,
                                                   'AMENT_PREFIX_PATH',
                                                   '',
                                                   mode='prepend')

        rc = await extension.build(additional_hooks=additional_hooks,
                                   skip_hook_creation=skip_hook_creation)
        if rc:
            return rc
Ejemplo n.º 18
0
def create_pythonpath_environment_hook(basepath, pkg_name):
    """
    Create a hook script for each primary shell to prepend to the PYTHONPATH.

    :param Path basepath: The path of the prefix
    :param str pkg_name: The package name
    :returns: The relative paths to the created hook scripts
    :rtype: list
    """
    hooks = []
    # prepend Python 2 specific path to PYTHONPATH if it exists
    if os.environ.get('ROS_PYTHON_VERSION', '2') == '2':
        for subdirectory in ('dist-packages', 'site-packages'):
            python_path = basepath / 'lib' / 'python2.7' / subdirectory
            logger.log(1, "checking '%s'" % python_path)
            if python_path.exists():
                rel_python_path = python_path.relative_to(basepath)
                hooks += create_environment_hook('python2path',
                                                 basepath,
                                                 pkg_name,
                                                 'PYTHONPATH',
                                                 str(rel_python_path),
                                                 mode='prepend')
    return hooks
Ejemplo n.º 19
0
    async def build(self):  # noqa: D102
        args = self.context.args
        logger.info(
            "Building ROS package in '{args.path}' with build type "
            "'ament_python'".format_map(locals()))

        # reuse Python build task with additional logic
        extension = PythonBuildTask()
        extension.set_context(context=self.context)

        # additional hooks
        additional_hooks = create_environment_hook(
            'ament_prefix_path', Path(args.install_base),
            self.context.pkg.name, 'AMENT_PREFIX_PATH', '', mode='prepend')

        # get options from the Python manifest
        try:
            env = await get_command_environment(
                'setup_py', args.build_base, self.context.dependencies)
        except RuntimeError as e:
            logger.error(str(e))
            return 1
        setup_py_data = get_setup_data(self.context.pkg, env)

        # check if the package index and manifest are being installed
        data_files = get_data_files_mapping(
            setup_py_data.get('data_files', []))
        installs_package_index = False
        installs_package_manifest = False

        # check if package index and manifest are being installed
        for source, destination in data_files.items():
            if sys.platform == 'win32':
                destination = Path(destination).as_posix()
            # work around data files incorrectly defined as not relative
            if os.path.isabs(source):
                source = os.path.relpath(source, args.path)
            if (
                destination == 'share/ament_index/resource_index/packages/' +
                self.context.pkg.name
            ):
                installs_package_index = True
            elif (
                source == 'package.xml' and
                destination == 'share/{self.context.pkg.name}/package.xml'
                .format_map(locals())
            ):
                installs_package_manifest = True

        # warn about missing explicit installation
        # for now implicitly install the marker and the manifest
        if not installs_package_index:
            # TODO remove magic helper in the future
            logger.warn(
                "Package '{self.context.pkg.name}' doesn't explicitly install "
                'a marker in the package index (colcon-ros currently does it '
                'implicitly but that fallback will be removed in the future)'
                .format_map(locals()))
            # create package marker in ament resource index
            create_file(
                args,
                'share/ament_index/resource_index/packages/'
                '{self.context.pkg.name}'.format_map(locals()))
        if not installs_package_manifest:
            # TODO remove magic helper in the future
            logger.warn(
                "Package '{self.context.pkg.name}' doesn't explicitly install "
                "the 'package.xml' file (colcon-ros currently does it "
                'implicitly but that fallback will be removed in the future)'
                .format_map(locals()))
            # copy / symlink package manifest
            install(
                args, 'package.xml',
                'share/{self.context.pkg.name}/package.xml'
                .format_map(locals()))

        return await extension.build(additional_hooks=additional_hooks)
Ejemplo n.º 20
0
    async def build(self, *, additional_hooks=None):  # noqa: D102
        pkg = self.context.pkg
        args = self.context.args

        logger.info(
            "Building Python package in '{args.path}'".format_map(locals()))

        try:
            env = await get_command_environment(
                'setup_py', args.build_base, self.context.dependencies)
        except RuntimeError as e:
            logger.error(str(e))
            return 1
        setup_py_data = get_setup_data(self.context.pkg, env)

        # `setup.py egg_info` requires the --egg-base to exist
        os.makedirs(args.build_base, exist_ok=True)
        # `setup.py develop|install` requires the python lib path to exist
        python_lib = os.path.join(
            args.install_base, self._get_python_lib(args))
        os.makedirs(python_lib, exist_ok=True)
        # and being in the PYTHONPATH
        env = dict(env)
        env['PYTHONPATH'] = python_lib + os.pathsep + \
            env.get('PYTHONPATH', '')

        if not args.symlink_install:
            rc = await self._undo_develop(pkg, args, env)
            if rc and rc.returncode:
                return rc.returncode

            # invoke `setup.py install` step with lots of arguments
            # to avoid placing any files in the source space
            cmd = [
                executable, 'setup.py',
                'egg_info', '--egg-base', args.build_base,
                'build', '--build-base', os.path.join(
                    args.build_base, 'build'),
                'install', '--prefix', args.install_base,
                '--record', os.path.join(args.build_base, 'install.log'),
                # prevent installation of dependencies specified in setup.py
                '--single-version-externally-managed',
            ]
            self._append_install_layout(args, cmd)
            rc = await check_call(self.context, cmd, cwd=args.path, env=env)
            if rc and rc.returncode:
                return rc.returncode

        else:
            self._undo_install(pkg, args, setup_py_data, python_lib)
            self._symlinks_in_build(args, setup_py_data)

            # invoke `setup.py develop` step in build space
            # to avoid placing any files in the source space

            # --editable causes this to skip creating/editing the
            # easy-install.pth file
            cmd = [
                executable, 'setup.py',
                'develop', '--prefix', args.install_base,
                '--editable',
                '--build-directory', os.path.join(args.build_base, 'build'),
                '--no-deps',
            ]
            if setup_py_data.get('data_files'):
                cmd += ['install_data', '--install-dir', args.install_base]
            self._append_install_layout(args, cmd)
            rc = await check_call(
                self.context, cmd, cwd=args.build_base, env=env)
            if rc and rc.returncode:
                return rc.returncode

            # explicitly add the build directory to the PYTHONPATH
            # to maintain the desired order
            if additional_hooks is None:
                additional_hooks = []
            base_path = args.build_base
            # if the Python packages are in a subdirectory
            # that needs to be appended to the build directory
            package_dir = setup_py_data.get('package_dir') or {}
            if '' in package_dir:
                base_path = os.path.join(base_path, package_dir[''])
            additional_hooks += create_environment_hook(
                'pythonpath_develop', Path(base_path), pkg.name, 'PYTHONPATH',
                base_path, mode='prepend')

        hooks = create_environment_hooks(args.install_base, pkg.name)
        create_environment_scripts(
            pkg, args, default_hooks=hooks, additional_hooks=additional_hooks)
Ejemplo n.º 21
0
    async def build(self):  # noqa: D102
        args = self.context.args

        # get build type of package from manifest
        pkg, build_type = get_package_with_build_type(args.path)
        logger.info("Building ROS package in '{args.path}' with build type "
                    "'{build_type}'".format_map(locals()))

        # choose the task extension and additional hooks and arguments
        additional_hooks = []
        if build_type == 'ament_cmake':
            extension = CmakeBuildTask()
            additional_hooks += [
                'share/{pkg.name}/local_setup.bash'.format_map(locals()),
                'share/{pkg.name}/local_setup.bat'.format_map(locals()),
                'share/{pkg.name}/local_setup.ps1'.format_map(locals()),
                'share/{pkg.name}/local_setup.sh'.format_map(locals()),
            ]
            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
            # extend CMAKE_PREFIX_PATH with AMENT_PREFIX_PATH
            ament_prefix_path = os.environ.get('AMENT_PREFIX_PATH')
            if ament_prefix_path:
                ament_prefix_path = ament_prefix_path.replace(os.pathsep, ';')
                if args.cmake_args is None:
                    args.cmake_args = []
                # check if the CMAKE_PREFIX_PATH is explicitly set
                prefix = '-DCMAKE_PREFIX_PATH='
                for i, value in reversed(list(enumerate(args.cmake_args))):
                    if not value.startswith(prefix):
                        continue
                    # extend the last existing entry
                    existing = value[len(prefix):]
                    if existing:
                        existing = ';' + existing
                    args.cmake_args[i] = \
                        '-DCMAKE_PREFIX_PATH={ament_prefix_path}{existing}' \
                        .format_map(locals())
                    break
                else:
                    # otherwise extend the environment variable
                    existing = os.environ.get('CMAKE_PREFIX_PATH', '')
                    if existing:
                        existing = ';' + existing.replace(os.pathsep, ';')
                    args.cmake_args.append(
                        '-DCMAKE_PREFIX_PATH={ament_prefix_path}{existing}'.
                        format_map(locals()))

        elif build_type == 'ament_python':
            extension = PythonBuildTask()
            additional_hooks += create_environment_hook('ament_prefix_path',
                                                        Path(
                                                            args.install_base),
                                                        pkg.name,
                                                        'AMENT_PREFIX_PATH',
                                                        '',
                                                        mode='prepend')
            # create package marker in ament resource index
            create_file(
                args, 'share/ament_index/resource_index/packages/{pkg.name}'.
                format_map(locals()))
            # copy / symlink package manifest
            install(args, 'package.xml',
                    'share/{pkg.name}/package.xml'.format_map(locals()))

        elif build_type == 'catkin':
            extension = CmakeBuildTask()
            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
            additional_hooks += create_environment_hook('ros_package_path',
                                                        Path(
                                                            args.install_base),
                                                        pkg.name,
                                                        'ROS_PACKAGE_PATH',
                                                        'share',
                                                        mode='prepend')

        elif build_type == 'cmake':
            extension = CmakeBuildTask()

        elif build_type == 'cargo':
            extension = CargoBuildTask()
            additional_hooks += create_environment_hook('ament_prefix_path',
                                                        Path(
                                                            args.install_base),
                                                        pkg.name,
                                                        'AMENT_PREFIX_PATH',
                                                        '',
                                                        mode='prepend')
            # create package marker in ament resource index
            create_file(
                args, 'share/ament_index/resource_index/packages/{pkg.name}'.
                format_map(locals()))
            # copy / symlink package manifest
            install(args, 'package.xml',
                    'share/{pkg.name}/package.xml'.format_map(locals()))

        else:
            assert False, 'Unknown build type: ' + build_type

        extension.set_context(context=self.context)
        if build_type != 'catkin':
            return await extension.build(additional_hooks=additional_hooks)
        else:
            # for catkin packages add additional hooks after the package has
            # been built and installed depending on the installed files
            rc = await extension.build(skip_hook_creation=True)

            # add Python 2 specific path to PYTHONPATH if it exists
            if os.environ.get('ROS_PYTHON_VERSION', '2') == '2':
                for subdirectory in ('dist-packages', 'site-packages'):
                    python_path = Path(args.install_base) / \
                        'lib' / 'python2.7' / subdirectory
                    logger.log(1, "checking '%s'" % python_path)
                    if python_path.exists():
                        rel_python_path = python_path.relative_to(
                            args.install_base)
                        additional_hooks += create_environment_hook(
                            'python2path',
                            Path(args.install_base),
                            pkg.name,
                            'PYTHONPATH',
                            str(rel_python_path),
                            mode='prepend')
            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
Ejemplo n.º 22
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