def test_sibling_references(self): with temporary_dir() as root_dir: buildfile = create_buildfile(root_dir, 'a', name='BUILD', content=dedent(""" dependencies(name='util', dependencies=[ jar(org='com.twitter', name='util', rev='0.0.1') ] ) """).strip() ) sibling = create_buildfile(root_dir, 'a', name='BUILD.sibling', content=dedent(""" dependencies(name='util-ex', dependencies=[ pants(':util'), jar(org='com.twitter', name='util-ex', rev='0.0.1') ] ) """).strip() ) ParseContext(buildfile).parse() utilex = Target.get(Address.parse(root_dir, 'a:util-ex', is_relative=False)) utilex_deps = set(utilex.resolve()) util = Target.get(Address.parse(root_dir, 'a:util', is_relative=False)) util_deps = set(util.resolve()) self.assertEquals(util_deps, util_deps.intersection(utilex_deps))
def make_target(self, spec="", target_type=Target, dependencies=None, derived_from=None, **kwargs): """Creates a target and injects it into the test's build graph. :param string spec: The target address spec that locates this target. :param type target_type: The concrete target subclass to create this new target from. :param list dependencies: A list of target instances this new target depends on. :param derived_from: The target this new target was derived from. :type derived_from: :class:`pants.base.target.Target` """ address = Address.parse(spec) target = target_type(name=address.target_name, address=address, build_graph=self.build_graph, **kwargs) dependencies = dependencies or [] self.build_graph.inject_target( target, dependencies=[dep.address for dep in dependencies], derived_from=derived_from ) # TODO(John Sirois): This re-creates a little bit too much work done by the BuildGraph. # Fixup the BuildGraph to deal with non BuildFileAddresses better and just leverage it. for traversable_dependency_spec in target.traversable_dependency_specs: traversable_dependency_address = Address.parse(traversable_dependency_spec, relative_to=address.spec_path) traversable_dependency_target = self.build_graph.get_target(traversable_dependency_address) if not traversable_dependency_target: raise ValueError( "Tests must make targets for traversable dependency specs ahead of them " "being traversed, {} tried to traverse {} which does not exist.".format( target, traversable_dependency_address ) ) if traversable_dependency_target not in target.dependencies: self.build_graph.inject_dependency(dependent=target.address, dependency=traversable_dependency_address) target.mark_transitive_invalidation_hash_dirty() return target
def test_invalidate_build_file_added(self): address_family = self.address_mapper.family('a/b') a_b_target = Target( name='b', dependencies=['//d:e'], configurations=['//a', Configuration(embedded='yes')]) self.assertEqual({Address.parse('a/b'): a_b_target}, address_family.addressables) with open(os.path.join(self.build_root, 'a/b/sibling.BUILD.json'), 'w') as fp: fp.write('{"typename": "configuration", "name": "c"}') still_valid = self.address_mapper.family('a/b') self.assertIs(address_family, still_valid) self.address_mapper.invalidate_build_file('a/b/sibling.BUILD.json') newly_formed = self.address_mapper.family('a/b') self.assertIsNot(address_family, newly_formed) self.assertEqual( { Address.parse('a/b'): a_b_target, Address.parse('a/b:c'): Configuration(name='c') }, newly_formed.addressables)
def parse_address(): if spec.startswith(':'): # the :[target] could be in a sibling BUILD - so parse using the canonical address pathish = "%s:%s" % (parse_context.buildfile.canonical_relpath, spec[1:]) return Address.parse(parse_context.buildfile.root_dir, pathish, False) else: return Address.parse(parse_context.buildfile.root_dir, spec, False)
def test_top_level(self): with self.workspace('BUILD') as root_dir: self.assertAddress(root_dir, 'BUILD', 'c', Address.parse(root_dir, ':c')) self.assertAddress(root_dir, 'BUILD', 'c', Address.parse(root_dir, '.:c')) self.assertAddress(root_dir, 'BUILD', 'c', Address.parse(root_dir, './:c')) self.assertAddress(root_dir, 'BUILD', 'c', Address.parse(root_dir, './BUILD:c')) self.assertAddress(root_dir, 'BUILD', 'c', Address.parse(root_dir, 'BUILD:c'))
def test_parse_from_sub_dir(self): with self.workspace('a/b/c/BUILD') as root_dir: with pushd(os.path.join(root_dir, 'a')): self.assertAddress(root_dir, 'a/b/c/BUILD', 'c', Address.parse(root_dir, 'b/c', is_relative=True)) with pytest.raises(IOError): Address.parse(root_dir, 'b/c', is_relative=False)
def test_target_invalid(self): self.add_to_build_file('a/BUILD', 'target(name="a")') with self.assertRaises(AddressLookupError): self.build_graph.inject_address_closure(Address.parse('a:nope')) self.add_to_build_file('b/BUILD', 'target(name="a")') with self.assertRaises(AddressLookupError): self.build_graph.inject_address_closure(Address.parse('b')) with self.assertRaises(AddressLookupError): self.build_graph.inject_address_closure(Address.parse('b:b'))
def test_target_invalid(self): self.add_to_build_file('a/BUILD', 'target(name="a")') with self.assertRaises(AddressLookupError): self.build_graph.inject_address_closure(Address.parse('a:nope')) self.add_to_build_file('b/BUILD', 'target(name="a")') with self.assertRaises(AddressLookupError): self.build_graph.inject_address_closure(Address.parse('b')) with self.assertRaises(AddressLookupError): self.build_graph.inject_address_closure(Address.parse('b:b'))
def test_create_single(self): address_family = AddressFamily.create('/dev/null', [AddressMap('/dev/null/0', { 'one': Thing(name='one', age=42), 'two': Thing(name='two', age=37) })]) self.assertEqual('', address_family.namespace) self.assertEqual({Address.parse('//:one'): Thing(name='one', age=42), Address.parse('//:two'): Thing(name='two', age=37)}, address_family.addressables)
def _synthesize_resources_target(self): # Create an address for the synthetic target. spec = self.address.spec + '_synthetic_resources' synthetic_address = Address.parse(spec=spec) # For safety, ensure an address that's not used already, even though that's highly unlikely. while self._build_graph.contains_address(synthetic_address): spec += '_' synthetic_address = Address.parse(spec=spec) self._build_graph.inject_synthetic_target(synthetic_address, Resources, sources=self.payload.resources.source_paths, derived_from=self) return self._build_graph.get_target(synthetic_address)
def test_create_single(self): address_family = AddressFamily.create('/dev/null', [ AddressMap('/dev/null/0', { 'one': Thing(name='one', age=42), 'two': Thing(name='two', age=37) }) ]) self.assertEqual('', address_family.namespace) self.assertEqual( { Address.parse('//:one'): Thing(name='one', age=42), Address.parse('//:two'): Thing(name='two', age=37) }, address_family.addressables)
def test_resolve_cache(self): graph = self.create_json_graph() nonstrict_address = Address.parse('examples/graph_test:nonstrict') nonstrict = graph.resolve(nonstrict_address) self.assertIs(nonstrict, graph.resolve(nonstrict_address)) # The already resolved `nonstrict` interior node should be re-used by `java1`. java1_address = Address.parse('examples/graph_test:java1') java1 = graph.resolve(java1_address) self.assertIs(nonstrict, java1.configurations[1]) self.assertIs(java1, graph.resolve(java1_address))
def test_invalidation_relative(self): resolved = self.address_mapper.resolve(Address.parse('a/b')) a_b_target = Target(name='b', dependencies=['//d:e'], configurations=['//a', Configuration(embedded='yes')]) self.assertEqual(a_b_target, resolved) build_file = os.path.join(self.build_root, 'a/b/b.BUILD.json') os.unlink(build_file) self.assertIs(resolved, self.address_mapper.resolve(Address.parse('a/b'))) self.address_mapper.invalidate_build_file('a/b/b.BUILD.json') with self.assertRaises(ResolveError): self.address_mapper.resolve(Address.parse('a/b'))
def _synthesize_resources_target(self): # Create an address for the synthetic target. spec = self.address.spec + '_synthetic_resources' synthetic_address = Address.parse(spec=spec) # For safety, ensure an address that's not used already, even though that's highly unlikely. while self._build_graph.contains_address(synthetic_address): spec += '_' synthetic_address = Address.parse(spec=spec) self._build_graph.inject_synthetic_target( synthetic_address, Resources, sources=self.payload.resources.source_paths, derived_from=self) return self._build_graph.get_target(synthetic_address)
def test_invalidation_relative(self): resolved = self.address_mapper.resolve(Address.parse('a/b')) a_b_target = Target( name='b', dependencies=['//d:e'], configurations=['//a', Configuration(embedded='yes')]) self.assertEqual(a_b_target, resolved) build_file = os.path.join(self.build_root, 'a/b/b.BUILD.json') os.unlink(build_file) self.assertIs(resolved, self.address_mapper.resolve(Address.parse('a/b'))) self.address_mapper.invalidate_build_file('a/b/b.BUILD.json') with self.assertRaises(ResolveError): self.address_mapper.resolve(Address.parse('a/b'))
def test_resolve(self): resolved = self.address_mapper.resolve(Address.parse('a/b')) self.assertEqual( Target(name='b', dependencies=['//d:e'], configurations=['//a', Configuration(embedded='yes')]), resolved)
def to_jar_dependencies(relative_to, jar_library_specs, build_graph): """Convenience method to resolve a list of specs to JarLibraries and return its jars attributes. Expects that the jar_libraries are declared relative to this target. :param Address relative_to: address target that references jar_library_specs, for error messages :param list jar_library_specs: string specs to JavaLibrary targets. Note, this list should be returned by the caller's traversable_specs() implementation to make sure that the jar_dependency jars have been added to the build graph. :param BuildGraph build_graph: build graph instance used to search for specs :return: list of JarDependency instances represented by the library_specs """ jar_deps = OrderedSet() for spec in jar_library_specs: if not isinstance(spec, six.string_types): raise JarLibrary.ExpectedAddressError( "{address}: expected imports to contain string addresses, got {found_class}." .format(address=relative_to.spec, found_class=type(spec).__name__)) lookup = Address.parse(spec, relative_to=relative_to.spec_path) target = build_graph.get_target(lookup) if not isinstance(target, JarLibrary): raise JarLibrary.WrongTargetTypeError( "{address}: expected {spec} to be jar_library target type, got {found_class}" .format(address=relative_to.spec, spec=spec, found_class=type(target).__name__)) jar_deps.update(target.jar_dependencies) return list(jar_deps)
def test_raises_address_not_in_build_file(self): self.add_to_build_file('BUILD', 'target(name="foo")') # Create an address that doesn't exist in an existing BUILD file address = Address.parse(':bar') with self.assertRaises(BuildFileAddressMapper.AddressNotInBuildFile): self.address_mapper.resolve(address)
def java_sources(self): for spec in self._java_sources_specs: address = Address.parse(spec, relative_to=self.address.spec_path) target = self._build_graph.get_target(address) if target is None: raise TargetDefinitionException(self, "No such java target: {}".format(spec)) yield target
def traversable_specs(self): for spec in super(PythonTarget, self).traversable_specs: yield spec if self._provides: for spec in self._provides._binaries.values(): address = Address.parse(spec, relative_to=self.address.spec_path) yield address.spec
def create_sources_field(self, sources, sources_rel_path, address=None, key_arg=None): """Factory method to create a SourcesField appropriate for the type of the sources object. Note that this method is called before the call to Target.__init__ so don't expect fields to be populated! :return: a payload field object representing the sources parameter :rtype: SourcesField """ if isinstance(sources, Addresses): # Currently, this is only created by the result of from_target() which takes a single argument if len(sources.addresses) != 1: raise self.WrongNumberOfAddresses( "Expected a single address to from_target() as argument to {spec}" .format(spec=address.spec)) referenced_address = Address.parse(sources.addresses[0], relative_to=sources.rel_path) return DeferredSourcesField(ref_address=referenced_address) elif isinstance(sources, FilesetWithSpec): filespec = sources.filespec else: sources = sources or [] assert_list(sources, key_arg=key_arg) filespec = {'globs': [os.path.join(sources_rel_path, src) for src in (sources or [])]} return SourcesField(sources=sources, sources_rel_path=sources_rel_path, filespec=filespec)
def test_validation(self): target = Target(name='mybird', address=Address.parse('//:mybird'), build_graph=self.build_graph) # jars attribute must contain only JarLibrary instances with self.assertRaises(TargetDefinitionException): JarLibrary(name="test", jars=[target])
def test_invalidation_un_normalized(self): resolved = self.address_mapper.resolve(Address.parse('a/b')) a_b_target = Target(name='b', dependencies=['//d:e'], configurations=['//a', Configuration(embedded='yes')]) self.assertEqual(a_b_target, resolved) os.unlink(os.path.join(self.build_root, 'a/b/b.BUILD.json')) self.assertIs(resolved, self.address_mapper.resolve(Address.parse('a/b'))) un_normalized_build_root = os.path.join(self.work_dir, 'build_root_linked') os.symlink(self.build_root, un_normalized_build_root) un_normalized_build_file = os.path.join(un_normalized_build_root, 'a/b/b.BUILD.json') self.address_mapper.invalidate_build_file(un_normalized_build_file) with self.assertRaises(ResolveError): self.address_mapper.resolve(Address.parse('a/b'))
def assert_parsed_list(self, cmdline_spec_list, expected): def sort(addresses): return sorted(addresses, key=lambda address: address.spec) self.assertEqual( sort(Address.parse(addr) for addr in expected), sort(self.spec_parser.parse_addresses(cmdline_spec_list)))
def test_excludes(self): # TODO(Eric Ayers) There doesn't seem to be any way to set this field at the moment. lib = JarLibrary(name='foo', address=Address.parse('//:foo'), build_graph=self.build_graph, jars=[jar1]) self.assertEquals([], lib.excludes)
def parse_jarcoordinate(coordinate): components = coordinate.split('#', 1) if len(components) == 2: org, name = components return org, name else: try: # TODO(Eric Ayers) This code is suspect. Target.get() is a very old method and almost certainly broken. # Refactor to use methods from BuildGraph or BuildFileAddressMapper address = Address.parse(get_buildroot(), coordinate) target = Target.get(address) if not target: siblings = Target.get_all_addresses(address.build_file) prompt = 'did you mean' if len( siblings) == 1 else 'maybe you meant one of these' raise TaskError('%s => %s?:\n %s' % (address, prompt, '\n '.join( str(a) for a in siblings))) if not target.is_exported: raise TaskError('%s is not an exported target' % coordinate) return target.provides.org, target.provides.name except (BuildFile.BuildFileError, BuildFileParser.BuildFileParserError, AddressLookupError) as e: raise TaskError( '{message}\n Problem with BUILD file at {coordinate}' .format(message=e, coordinate=coordinate))
def test_register_bad_target_alias(self): with self.assertRaises(TypeError): self.build_configuration._register_target_alias('fred', object()) target = Target('fred', Address.parse('a:b'), BuildGraph(address_mapper=None)) with self.assertRaises(TypeError): self.build_configuration._register_target_alias('fred', target)
def parse_jarcoordinate(coordinate): components = coordinate.split('#', 1) if len(components) == 2: org, name = components return org, name else: try: address = Address.parse(get_buildroot(), coordinate) try: target = Target.get(address) if not target: siblings = Target.get_all_addresses( address.buildfile) prompt = 'did you mean' if len( siblings ) == 1 else 'maybe you meant one of these' raise TaskError('%s => %s?:\n %s' % (address, prompt, '\n '.join( str(a) for a in siblings))) if not target.is_exported: raise TaskError('%s is not an exported target' % coordinate) return target.provides.org, target.provides.name except (ImportError, SyntaxError, TypeError): raise TaskError('Failed to parse %s' % address.buildfile.relpath) except IOError: raise TaskError('No BUILD file could be found at %s' % coordinate)
def __init__(self, name, build_file, build_file_source_lines, target_source_lines, target_interval, dependencies, dependencies_interval): """See BuildFileManipulator.load() for how to construct one as a user.""" self.name = name self.build_file = build_file self.target_address = BuildFileAddress(build_file, name) self._build_file_source_lines = build_file_source_lines self._target_source_lines = target_source_lines self._target_interval = target_interval self._dependencies_interval = dependencies_interval self._dependencies_by_address = {} for dep in dependencies: dep_address = Address.parse(dep.spec, relative_to=build_file.spec_path) if dep_address in self._dependencies_by_address: raise BuildTargetParseError('The address {dep_address} occurred multiple times in the ' 'dependency specs for target {name} in {build_file}. ' .format(dep_address=dep_address.spec, name=name, build_file=build_file)) self._dependencies_by_address[dep_address] = dep
def to_jar_dependencies(relative_to, jar_library_specs, build_graph): """Convenience method to resolve a list of specs to JarLibraries and return its jars attributes. Expects that the jar_libraries are declared relative to this target. :param Address relative_to: address target that references jar_library_specs, for error messages :param list jar_library_specs: string specs to JavaLibrary targets. Note, this list should be returned by the caller's traversable_specs() implementation to make sure that the jar_dependency jars have been added to the build graph. :param BuildGraph build_graph: build graph instance used to search for specs :return: list of JarDependency instances represented by the library_specs """ jar_deps = OrderedSet() for spec in jar_library_specs: if not isinstance(spec, six.string_types): raise JarLibrary.ExpectedAddressError( "{address}: expected imports to contain string addresses, got {found_class}.".format( address=relative_to.spec, found_class=type(spec).__name__ ) ) lookup = Address.parse(spec, relative_to=relative_to.spec_path) target = build_graph.get_target(lookup) if not isinstance(target, JarLibrary): raise JarLibrary.WrongTargetTypeError( "{address}: expected {spec} to be jar_library target type, got {found_class}".format( address=relative_to.spec, spec=spec, found_class=type(target).__name__ ) ) jar_deps.update(target.jar_dependencies) return list(jar_deps)
def test_target_insertion_middle(self): expected_build_string = dedent( """\ # This comment should stay target_type( name = 'target_top', dependencies = [ ':dep_a', ] ) target_type( name = 'target_middle', dependencies = [ ':dep_b', ':new_dep', ], ) # This comment should be okay target_type( name = 'target_bottom', ) # Also this one though it's weird""" ) build_file = self.add_to_build_file('BUILD', self.multi_target_build_string) multi_targ_bfm = BuildFileManipulator.load(build_file, 'target_middle', {'target_type'}) multi_targ_bfm.add_dependency(Address.parse(':new_dep')) build_file_str = '\n'.join(multi_targ_bfm.build_file_lines()) self.assertEqual(build_file_str, expected_build_string)
def test_raises_address_not_in_build_file(self): self.add_to_build_file('BUILD', 'target(name="foo")') # Create an address that doesn't exist in an existing BUILD file address = Address.parse(':bar') with self.assertRaises(BuildFileAddressMapper.AddressNotInBuildFile): self.address_mapper.resolve(address)
def parse_jarcoordinate(coordinate): components = coordinate.split('#', 1) if len(components) == 2: org, name = components return org, name else: spec = components[0] address = Address.parse(spec) try: self.context.build_graph.inject_address_closure(address) target = self.context.build_graph.get_target(address) if not target: siblings = self.context.address_mapper.addresses_in_spec_path( address.spec_path) prompt = 'did you mean' if len( siblings) == 1 else 'maybe you meant one of these' raise TaskError('{} => {}?:\n {}'.format( address, prompt, '\n '.join(str(a) for a in siblings))) if not target.is_exported: raise TaskError( '{} is not an exported target'.format(coordinate)) return target.provides.org, target.provides.name except (BuildFile.BuildFileError, BuildFileParser.BuildFileParserError, AddressLookupError) as e: raise TaskError( '{message}\n Problem identifying target at {spec}'. format(message=e, spec=spec))
def test_create_bad_targets(self): with self.assertRaises(TypeError): BuildFileAliases(targets={'fred': object()}) target = Target('fred', Address.parse('a:b'), BuildGraph(address_mapper=None)) with self.assertRaises(TypeError): BuildFileAliases(targets={'fred': target})
def test_cycle_self(self): graph = self.create_json_graph() with self.assertRaises(CycleError) as exc: graph.resolve(Address.parse('examples/graph_test:self_cycle')) self.assertEqual(['* examples/graph_test:self_cycle', '* examples/graph_test:self_cycle'], self.extract_path_tail(exc.exception, 2))
def test_simple_targets(self): simple_targets = dedent( """ target_type( name = 'no_deps', ) target_type( name = 'empty_deps', dependencies = [ ] ) target_type( name = 'empty_deps_inline', dependencies = [] ) """ ) build_file = self.add_to_build_file('BUILD', simple_targets) for no_deps_name in ['no_deps', 'empty_deps', 'empty_deps_inline']: no_deps = BuildFileManipulator.load(build_file, no_deps_name, {'target_type'}) self.assertEqual(tuple(no_deps.dependency_lines()), tuple()) no_deps.add_dependency(Address.parse(':fake_dep')) self.assertEqual(tuple(no_deps.dependency_lines()), tuple([' dependencies = [', " ':fake_dep',", ' ],'])) no_deps.add_dependency(Address.parse(':b_fake_dep')) no_deps.add_dependency(Address.parse(':a_fake_dep')) self.assertEqual(tuple(no_deps.dependency_lines()), tuple([' dependencies = [', " ':a_fake_dep',", " ':b_fake_dep',", " ':fake_dep',", ' ],'])) self.assertEqual(tuple(no_deps.target_lines()), tuple(['target_type(', " name = '{0}',".format(no_deps_name), ' dependencies = [', " ':a_fake_dep',", " ':b_fake_dep',", " ':fake_dep',", ' ],', ')']))
def test_parse(self): self.assert_address('a/b', 'target', Address.parse('a/b:target')) self.assert_address('a/b', 'target', Address.parse('//a/b:target')) self.assert_address('a/b', 'b', Address.parse('a/b')) self.assert_address('a/b', 'b', Address.parse('//a/b')) self.assert_address('a/b', 'target', Address.parse(':target', relative_to='a/b')) self.assert_address('', 'target', Address.parse('//:target', relative_to='a/b')) self.assert_address('', 'target', Address.parse(':target')) self.assert_address('a/b', 'target', Address.parse(':target', relative_to='a/b'))
def target(cls, address): """Resolves the given target address to a Target object. address: The BUILD target address to resolve. Returns the corresponding Target or else None if the address does not point to a defined Target. """ return Target.get(Address.parse(cls.build_root, address, is_relative=False))
def test_resolve(self): build_file = self.add_to_build_file('BUILD', 'target(name="foo")') address, addressable = self.address_mapper.resolve(Address.parse('//:foo')) self.assertIsInstance(address, BuildFileAddress) self.assertEqual(build_file, address.build_file) self.assertEqual('foo', address.target_name) self.assertEqual(address.target_name, addressable.addressed_name) self.assertEqual(addressable.addressed_type, Target)
def get_target(spec): address = Address.parse(spec, relative_to=self.address.spec_path) tgt = self._build_graph.get_target(address) if tgt is None: raise TargetDefinitionException( self, 'No such resource target: {}'.format(address)) return tgt
def test_targets_ignore_synthetics_with_no_derived_from_not_injected_into_graph(self): a = self.make_target('a') b = self.make_target('b') context = self.context(target_roots=[b]) self.assertEquals([b], context.targets()) context.add_new_target(Address.parse('syn_with_deps'), Target, dependencies=[a]) self.assertEquals([b], context.targets())
def test_targets_synthetic(self): a = self.make_target('a') b = self.make_target('b', dependencies=[a]) c = self.make_target('c', dependencies=[b]) d = self.make_target('d', dependencies=[c, a]) context = self.context(target_roots=[c]) self.assertEquals([c, b, a], context.targets()) syn_b = context.add_new_target(Address.parse('syn_b'), Target, derived_from=b) context.add_new_target(Address.parse('syn_d'), Target, derived_from=d) # We expect syn_b to be included now since it has been synthesized during this run from an # in-play target. self.assertEquals([c, b, a, syn_b], context.targets()) # And verify the predicate operates over both normal and synthetic targets. self.assertEquals([syn_b], context.targets(lambda t: t.derived_from != t)) self.assertEquals([c, b, a], context.targets(lambda t: t.derived_from == t))
def test_targets_ignore_synthetics_with_no_derived_from_not_injected_into_graph(self): a = self.make_target('a') b = self.make_target('b') context = self.context(target_roots=[b]) self.assertEquals([b], context.targets()) context.add_new_target(Address.parse('syn_with_deps'), Target, dependencies=[a]) self.assertEquals([b], context.targets())
def test_targets_synthetic(self): a = self.make_target('a') b = self.make_target('b', dependencies=[a]) c = self.make_target('c', dependencies=[b]) d = self.make_target('d', dependencies=[c, a]) context = self.context(target_roots=[c]) self.assertEquals([c, b, a], context.targets()) syn_b = context.add_new_target(Address.parse('syn_b'), Target, derived_from=b) context.add_new_target(Address.parse('syn_d'), Target, derived_from=d) # We expect syn_b to be included now since it has been synthesized during this run from an # in-play target. self.assertEquals([c, b, a, syn_b], context.targets()) # And verify the predicate operates over both normal and synthetic targets. self.assertEquals([syn_b], context.targets(lambda t: t.derived_from != t)) self.assertEquals([c, b, a], context.targets(lambda t: t.derived_from == t))
def test_contains_address(self): a = Address.parse('a') self.assertFalse(self.build_graph.contains_address(a)) target = Target(name='a', address=a, build_graph=self.build_graph) self.build_graph.inject_target(target) self.assertTrue(self.build_graph.contains_address(a))
def resolve_spec(self, spec): """Converts a spec to an address and maps it using `resolve`""" try: address = Address.parse(spec) except ValueError as e: raise self.InvalidAddressError(e) _, addressable = self.resolve(address) return addressable
def resolve_spec(self, spec): """Converts a spec to an address and maps it using `resolve`""" try: address = Address.parse(spec) except ValueError as e: raise self.InvalidAddressError(e) _, addressable = self.resolve(address) return addressable
def test_create_bad_targets(self): with self.assertRaises(TypeError): BuildFileAliases(targets={'fred': object()}) target = Target('fred', Address.parse('a:b'), BuildGraph(address_mapper=None)) with self.assertRaises(TypeError): BuildFileAliases(targets={'fred': target})
def traversable_specs(self): for spec in super(PythonTarget, self).traversable_specs: yield spec if self._provides: for spec in self._provides._binaries.values(): address = Address.parse(spec, relative_to=self.address.spec_path) yield address.spec
def java_sources(self): for spec in self._java_sources_specs: address = Address.parse(spec, relative_to=self.address.spec_path) target = self._build_graph.get_target(address) if target is None: raise TargetDefinitionException( self, 'No such java target: {}'.format(spec)) yield target
def test_contains_address(self): a = Address.parse('a') self.assertFalse(self.build_graph.contains_address(a)) target = Target(name='a', address=a, build_graph=self.build_graph) self.build_graph.inject_target(target) self.assertTrue(self.build_graph.contains_address(a))
def _synthesize_command(root_dir, args): register_commands() command = args[0] if command in Command.all_commands(): subcommand_args = args[1:] if len(args) > 1 else [] return command, _add_default_options(command, subcommand_args) if command.startswith('-'): _exit_and_fail('Invalid command: %s' % command) # assume 'build' if a command was omitted. try: Address.parse(root_dir, command) return _BUILD_COMMAND, _add_default_options(_BUILD_COMMAND, args) except: _exit_and_fail('Failed to execute pants build: %s' % traceback.format_exc())
def test_resolve(self): build_file = self.add_to_build_file('BUILD', 'target(name="foo")') address, addressable = self.address_mapper.resolve(Address.parse('//:foo')) self.assertIsInstance(address, BuildFileAddress) self.assertEqual(build_file, address.build_file) self.assertEqual('foo', address.target_name) self.assertEqual(address.target_name, addressable.addressable_name) self.assertEqual(addressable.target_type, Target)
def _alternate_target_roots(cls, options, address_mapper, build_graph): processed = set() for jvm_tool in JvmToolMixin.get_registered_tools(): dep_spec = jvm_tool.dep_spec(options) dep_address = Address.parse(dep_spec) # Some JVM tools are requested multiple times, we only need to handle them once. if dep_address not in processed: processed.add(dep_address) try: if build_graph.contains_address(dep_address) or address_mapper.resolve(dep_address): # The user has defined a tool classpath override - we let that stand. continue except AddressLookupError as e: if jvm_tool.classpath is None: raise cls._tool_resolve_error(e, dep_spec, jvm_tool) else: if not jvm_tool.is_default(options): # The user specified a target spec for this jvm tool that doesn't actually exist. # We want to error out here instead of just silently using the default option while # appearing to respect their config. raise cls.ToolResolveError(dedent(""" Failed to resolve target for tool: {tool}. This target was obtained from option {option} in scope {scope}. Make sure you didn't make a typo in the tool's address. You specified that the tool should use the target found at "{tool}". This target has a default classpath configured, so you can simply remove: [{scope}] {option}: {tool} from pants.ini (or any other config file) to use the default tool. The default classpath is: {default_classpath} Note that tool target addresses in pants.ini should be specified *without* quotes. """).strip().format(tool=dep_spec, option=jvm_tool.key, scope=jvm_tool.scope, default_classpath=':'.join(map(str, jvm_tool.classpath or ())))) if jvm_tool.classpath: tool_classpath_target = JarLibrary(name=dep_address.target_name, address=dep_address, build_graph=build_graph, jars=jvm_tool.classpath) else: # The tool classpath is empty by default, so we just inject a dummy target that # ivy resolves as the empty list classpath. JarLibrary won't do since it requires # one or more jars, so we just pick a target type ivy has no resolve work to do for. tool_classpath_target = Target(name=dep_address.target_name, address=dep_address, build_graph=build_graph) build_graph.inject_target(tool_classpath_target) # We use the trick of not returning alternate roots, but instead just filling the dep_spec # holes with a JarLibrary built from a tool's default classpath JarDependency list if there is # no over-riding targets present. This means we do modify the build_graph, but we at least do # it at a time in the engine lifecycle cut out for handling that. return None
def make_target(self, spec='', target_type=Target, dependencies=None, derived_from=None, **kwargs): """Creates a target and injects it into the test's build graph. :param string spec: The target address spec that locates this target. :param type target_type: The concrete target subclass to create this new target from. :param list dependencies: A list of target instances this new target depends on. :param derived_from: The target this new target was derived from. :type derived_from: :class:`pants.base.target.Target` """ address = Address.parse(spec) target = target_type(name=address.target_name, address=address, build_graph=self.build_graph, **kwargs) dependencies = dependencies or [] self.build_graph.inject_target( target, dependencies=[dep.address for dep in dependencies], derived_from=derived_from) # TODO(John Sirois): This re-creates a little bit too much work done by the BuildGraph. # Fixup the BuildGraph to deal with non BuildFileAddresses better and just leverage it. for traversable_dependency_spec in target.traversable_dependency_specs: traversable_dependency_address = Address.parse( traversable_dependency_spec, relative_to=address.spec_path) traversable_dependency_target = self.build_graph.get_target( traversable_dependency_address) if not traversable_dependency_target: raise ValueError( 'Tests must make targets for traversable dependency specs ahead of them ' 'being traversed, {} tried to traverse {} which does not exist.' .format(target, traversable_dependency_address)) if traversable_dependency_target not in target.dependencies: self.build_graph.inject_dependency( dependent=target.address, dependency=traversable_dependency_address) target.mark_transitive_invalidation_hash_dirty() return target