def test_parse_local_spec(self): spec_path, target_name = parse_spec(':c') self.assertEqual(spec_path, '') self.assertEqual(target_name, 'c') spec_path, target_name = parse_spec(':c', relative_to='here') self.assertEqual(spec_path, 'here') self.assertEqual(target_name, 'c')
def test_parse_absolute_spec(self): spec_path, target_name = parse_spec('//a/b/c') self.assertEqual(spec_path, 'a/b/c') self.assertEqual(target_name, 'c') spec_path, target_name = parse_spec('//a/b/c:c') self.assertEqual(spec_path, 'a/b/c') self.assertEqual(target_name, 'c') spec_path, target_name = parse_spec('//:c') self.assertEqual(spec_path, '') self.assertEqual(target_name, 'c')
def test_parse_spec(self): spec_path, target_name = parse_spec('a/b/c') self.assertEqual(spec_path, 'a/b/c') self.assertEqual(target_name, 'c') spec_path, target_name = parse_spec('a/b/c:c') self.assertEqual(spec_path, 'a/b/c') self.assertEqual(target_name, 'c') spec_path, target_name = parse_spec('a/b/c', relative_to='here') # no effect - we have a path self.assertEqual(spec_path, 'a/b/c') self.assertEqual(target_name, 'c')
def parse(spec, relative_to): return parse_spec(spec, relative_to=relative_to, subproject_roots=[ 'subprojectA', 'path/to/subprojectB', ])[0]
def iter_resolve_and_parse_specs(rel_path, specs): """Given a relative path and set of input specs, produce a list of proper `Spec` objects. :param string rel_path: The relative path to the input specs from the build root. :param iterable specs: An iterable of specs. """ for spec in specs: spec_path, target_name = parse_spec(spec, rel_path) yield SingleAddress(spec_path, target_name)
def spec_to_address(self, spec, relative_to=''): """A helper method for mapping a spec to the correct address. :param string spec: A spec to lookup in the map. :param string relative_to: Path the spec might be relative to :raises :class:`pants.build_graph.address_lookup_error.AddressLookupError` If the BUILD file cannot be found in the path specified by the spec. :returns: A new Address instance. :rtype: :class:`pants.build_graph.address.Address` """ spec_path, name = parse_spec(spec, relative_to=relative_to) try: self.get_build_file(spec_path) except BuildFile.BuildFileError as e: raise self.InvalidBuildFileReference('{message}\n when translating spec {spec}' .format(message=e, spec=spec)) return Address(spec_path, name)
def spec_to_address(self, spec, relative_to=''): """A helper method for mapping a spec to the correct build file address. :param string spec: A spec to lookup in the map. :param string relative_to: Path the spec might be relative to :raises :class:`pants.build_graph.address_lookup_error.AddressLookupError` If the BUILD file cannot be found in the path specified by the spec. :returns: A new Address instance. :rtype: :class:`pants.build_graph.address.BuildFileAddress` """ try: spec = self.determine_subproject_spec(spec, relative_to) spec_path, name = parse_spec(spec, relative_to=relative_to) address = Address(spec_path, name) build_file_address, _ = self.resolve(address) return build_file_address except (ValueError, AddressLookupError) as e: raise self.InvalidBuildFileReference('{message}\n when translating spec {spec}' .format(message=e, spec=spec))
def inject_graph(self, root_spec, graph_dict): """Given a root spec, injects relevant targets from the graph represented by graph_dict. graph_dict should contain address specs, keyed by sources with lists of value destinations. Each created target will be a simple `target` alias. Returns the parsed Address for the root_spec. """ for src, targets in graph_dict.items(): src_path, src_name = parse_spec(src) if not src_path: # The target is located in the root. src_path = '.' self.add_to_build_file( '{}/BUILD'.format(src_path), '''target(name='{}', dependencies=[{}])\n'''.format( src_name, "'{}'".format("','".join(targets)) if targets else '' ) ) root_address = Address.parse(root_spec) self.build_graph.inject_address_closure(root_address) return root_address
def __init__(self, spec): spec_path, target_name = parse_spec(spec) super(AnotherTarget, self).__init__(target_name, Address.parse(spec), None)
def do_test_bad_target_name(self, spec: str) -> None: with self.assertRaises(InvalidTargetName): Address(*parse_spec(spec))
def test_banned_chars_in_target_name(self) -> None: with self.assertRaises(InvalidTargetName): Address(*parse_spec('a/b:c@d'))
def do_test_bad_target_name(self, spec): with self.assertRaises(InvalidTargetName): Address(*parse_spec(spec))
def test_banned_chars_in_target_name(self): # move to do_test_bad_spec_path after deprecation self.assertEquals('c@d', Address(*parse_spec('a/b:c@d')).target_name)
def do_test_bad_spec_path(self, spec): with self.assertRaises(InvalidSpecPath): Address(*parse_spec(spec))
def do_test_bad_spec(self, spec): with self.assertRaises(ValueError): parse_spec(spec)
def test_banned_chars_in_target_name(self): with self.assertRaises(InvalidTargetName): Address(*parse_spec('a/b:c@d'))
def _parse_spec(self, spec, fail_fast=False): def normalize_spec_path(path): is_abs = not path.startswith('//') and os.path.isabs(path) if is_abs: path = os.path.realpath(path) if os.path.commonprefix([self._root_dir, path]) != self._root_dir: raise self.BadSpecError('Absolute address path {0} does not share build root {1}' .format(path, self._root_dir)) else: if path.startswith('//'): path = path[2:] path = os.path.join(self._root_dir, path) normalized = os.path.relpath(path, self._root_dir) if normalized == '.': normalized = '' return normalized errored_out = [] if spec.endswith('::'): addresses = set() spec_path = spec[:-len('::')] spec_dir = normalize_spec_path(spec_path) try: build_files = self._address_mapper.scan_project_tree_build_files(base_path=spec_dir, spec_excludes=self._spec_excludes) except (BuildFile.BuildFileError, AddressLookupError) as e: raise self.BadSpecError(e) for build_file in build_files: try: # This attempts to filter out broken BUILD files before we parse them. if self._not_excluded_spec(build_file.spec_path): addresses.update(self._address_mapper.addresses_in_spec_path(build_file.spec_path)) except (BuildFile.BuildFileError, AddressLookupError) as e: if fail_fast: raise self.BadSpecError(e) errored_out.append('--------------------') errored_out.append(traceback.format_exc()) errored_out.append('Exception message: {0}'.format(e)) if errored_out: error_msg = '\n'.join(errored_out + ["Invalid BUILD files for [{0}]".format(spec)]) raise self.BadSpecError(error_msg) return addresses elif spec.endswith(':'): spec_path = spec[:-len(':')] spec_dir = normalize_spec_path(spec_path) try: return set(self._address_mapper.addresses_in_spec_path(spec_dir)) except AddressLookupError as e: raise self.BadSpecError(e) else: spec_parts = spec.rsplit(':', 1) spec_parts[0] = normalize_spec_path(spec_parts[0]) spec_path, target_name = parse_spec(':'.join(spec_parts)) try: self._address_mapper.get_build_file(spec_path) except BuildFile.BuildFileError as e: raise self.BadSpecError(e) return {Address(spec_path, target_name)}
def parse(spec, relative_to): return parse_spec( spec, relative_to=relative_to, subproject_roots=["subprojectA", "path/to/subprojectB"], )