async def build(self, *, additional_hooks=None, skip_hook_creation=False): # noqa: D102 pkg = self.context.pkg args = self.context.args logger.info("Building Gradle 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 rc = await self._install(args, env) if rc and rc.returncode: return rc.returncode if not skip_hook_creation: create_environment_scripts(pkg, args, additional_hooks=additional_hooks)
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)
async def build(self): # noqa: D102 args = self.context.args logger.info( "Building ROS package in '{args.path}' with build type 'cmake'". format_map(locals())) # reuse CMake build task with additional logic extension = CmakeBuildTask_() extension.set_context(context=self.context) rc = await extension.build(skip_hook_creation=True, 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: if not rc: raise has_install_target = False additional_hooks = [] if has_install_target: additional_hooks += create_pkg_config_path_environment_hooks( Path(args.install_base), self.context.pkg.name) create_environment_scripts(self.context.pkg, args, additional_hooks=additional_hooks) return rc
async def build( # noqa: D102 self, *, additional_hooks=None, skip_hook_creation=False, environment_callback=None, additional_targets=None): pkg = self.context.pkg args = self.context.args logger.info("Building CMake 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 if environment_callback is not None: environment_callback(env) rc = await self._reconfigure(args, env) if rc: return rc # ensure that CMake cache contains the project name project_name = get_variable_from_cmake_cache(args.build_base, 'CMAKE_PROJECT_NAME') if project_name is None: # if not the CMake code hasn't called project() and can't be built logger.warning( "Could not build CMake package '{pkg.name}' because the " "CMake cache has no 'CMAKE_PROJECT_NAME' variable".format_map( locals())) return rc = await self._build(args, env, additional_targets=additional_targets) if rc: return rc # skip install step if a specific target was requested if not args.cmake_target: if await has_target(args.build_base, 'install'): completed = await self._install(args, env) if completed.returncode: return completed.returncode else: logger.warning( "Could not run installation step for package '{pkg.name}' " "because it has no 'install' target".format_map(locals())) if not skip_hook_creation: create_environment_scripts(pkg, args, additional_hooks=additional_hooks)
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
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
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', [])
async def build(self): # noqa: D102 args = self.context.args logger.info( "Building ROS package in '{args.path}' with build type 'cmake'". format_map(locals())) # reuse CMake build task with additional logic extension = CmakeBuildTask_() extension.set_context(context=self.context) rc = await extension.build(environment_callback=add_app_to_cpp) additional_hooks = create_pkg_config_path_environment_hooks( Path(args.install_base), self.context.pkg.name) create_environment_scripts(self.context.pkg, args, additional_hooks=additional_hooks) return rc
async def build( self, additional_hooks=None, skip_hook_creation=False ) -> Optional[int]: # noqa: D102 pkg = self.context.pkg args = self.context.args # BuildPackageArguments logger.info( "Building DUB 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 dub_package = DubPackage(Path(args.path)) rc = await self._configure(dub_package, env) if rc: return rc rc = await self._build(dub_package, env) if rc: return rc rc = await self._install(dub_package) if rc: return rc if not skip_hook_creation: create_environment_scripts( pkg, args, additional_hooks=additional_hooks)
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)
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
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
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) cmd += [ 'bdist_egg', '--dist-dir', os.path.join( args.build_base, 'dist'), ] 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 cmd = [ executable, 'setup.py', 'develop', '--prefix', args.install_base, '--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 hooks = create_environment_hooks(args.install_base, pkg.name) create_environment_scripts( pkg, args, default_hooks=hooks, additional_hooks=additional_hooks)