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 # 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(d.name) 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(d.name) for d in pkg.test_depends: assert d.evaluated_condition is not None if d.evaluated_condition: desc.dependencies['test'].add(d.name) def getter(env): nonlocal desc return get_setup_arguments_with_context( str(desc.path / 'setup.py'), env) desc.metadata['get_python_setup_options'] = getter
def identify(self, desc): # noqa: D102 filenames = ( '_order_isolated_packages.py', # ament_tools '_setup_util.py', # catkin ) for filename in filenames: ignore = desc.path / filename if ignore.exists(): raise IgnoreLocationException()
def test_identify(): path = '/some/path' context = EntryPointContext(extension1=Extension1, extension2=Extension2, extension3=Extension3, extension4=Extension4) with context: # no identification desc = identify({}, path) assert desc is None # no complete identification extensions = get_package_identification_extensions() extensions[80]['extension1'].identify = Mock(side_effect=identify_name) desc = identify(extensions, path) assert desc is None # valid result combined across priority groups extensions = get_package_identification_extensions() extensions[100]['extension4'].identify = Mock( side_effect=identify_type) desc = identify(extensions, path) assert isinstance(desc, PackageDescriptor) assert str(desc.path) == '/some/path'.replace('/', os.sep) assert desc.name == 'name' assert desc.type == 'type' # skip location extensions = get_package_identification_extensions() extensions[90]['extension3'].identify = Mock( side_effect=IgnoreLocationException()) with pytest.raises(IgnoreLocationException): identify(extensions, path) # valid result from first priority group # lower priority groups are not even invoked extensions = get_package_identification_extensions() extensions[100]['extension4'].identify.side_effect = \ identify_name_and_type desc = identify(extensions, path) assert isinstance(desc, PackageDescriptor) assert str(desc.path) == '/some/path'.replace('/', os.sep) assert desc.name == 'name' assert desc.type == 'type' with context: # multiple different results result in skipping the location extensions = get_package_identification_extensions() extensions[100]['extension2'].identify = Mock( side_effect=identify_name) extensions[100]['extension4'].identify = Mock( side_effect=identify_type) with pytest.raises(IgnoreLocationException): identify(extensions, path)
def test__identify(): desc_path_only = PackageDescriptor('/some/path') with EntryPointContext( extension1=Extension1, extension2=Extension2, extension3=Extension3, extension4=Extension4, ): # valid result extensions = get_package_identification_extensions()[100] extensions['extension2'].identify = Mock() extensions['extension4'].identify = identify_name_and_type desc = _identify(extensions, desc_path_only) assert isinstance(desc, PackageDescriptor) assert str(desc.path) == '/some/path'.replace('/', os.sep) assert desc.name == 'name' assert desc.type == 'type' # no results extensions = get_package_identification_extensions()[100] extensions['extension2'].identify = Mock() extensions['extension4'].identify = Mock() desc = _identify(extensions, desc_path_only) assert desc is None # multiple different results extensions = get_package_identification_extensions()[100] extensions['extension2'].identify = identify_name extensions['extension4'].identify = identify_type with patch( 'colcon_core.package_identification.logger.warning') as warn: desc = _identify(extensions, desc_path_only) assert desc is False # the raised exception is catched and results in a warn message assert warn.call_count == 1 assert len(warn.call_args[0]) == 1 assert 'multiple matches' in warn.call_args[0][0] # invalid return value extensions = get_package_identification_extensions()[90] extensions['extension3'].identify = Mock(return_value=True) with patch('colcon_core.package_identification.logger.error') as error: desc = _identify(extensions, desc_path_only) assert desc is None # 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 package identification extension 'extension3' " "in '/some/path': identify() should return None\n".replace( '/', os.sep)) # skip location extensions = get_package_identification_extensions()[90] extensions['extension3'].identify = Mock( side_effect=IgnoreLocationException()) with pytest.raises(IgnoreLocationException): _identify(extensions, desc_path_only) # raise exception extensions = get_package_identification_extensions()[90] extensions['extension3'].identify = Mock( side_effect=RuntimeError('custom exception')) with patch('colcon_core.package_identification.logger.error') as error: desc = _identify(extensions, desc_path_only) assert desc is None # 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 package identification extension 'extension3' " "in '/some/path': custom exception\n".replace('/', os.sep))
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
def identify(_, path): if path == os.path.realpath('/empty/path'): return None if path == os.path.realpath('/skip/path'): raise IgnoreLocationException() return PackageDescriptor(path)
def identify(self, desc): # noqa: D102 colcon_ignore = desc.path / IGNORE_MARKER if colcon_ignore.exists(): raise IgnoreLocationException()