Skip to content
Permalink
Browse files

Leverage fromfile option to simplify providing tag / targets mappings

The keys / values for this option should parse correctly to a python dict from json (no booleans or nulls), so adding this allows for either a source file as before, or a dict added to the pants.ini
  • Loading branch information...
codealchemy committed Mar 6, 2019
1 parent 4471768 commit d4e53c745bf42c66172d2d847f57bba7ba06f94e
Showing with 27 additions and 45 deletions.
  1. +6 −22 src/python/pants/build_graph/target.py
  2. +21 −23 tests/python/pants_test/build_graph/test_target.py
@@ -29,7 +29,6 @@
from pants.source.payload_fields import SourcesField
from pants.source.wrapped_globs import EagerFilesetWithSpec, FilesetWithSpec
from pants.subsystem.subsystem import Subsystem
from pants.util.dirutil import maybe_read_file
from pants.util.memo import memoized_method, memoized_property


@@ -142,38 +141,23 @@ def check_unknown(self, target, kwargs, payload):
))

class TagAssignments(Subsystem):
"""Tags to be applied to targets defined in a single source file."""
"""Tags to add to targets in addition to any defined in their BUILD files."""

options_scope = 'target-tag-assignments'

@classmethod
def register_options(cls, register):
register('--tag-targets-file', type=str, default=None, fingerprint=True,
help='Source JSON file with tag assignments for targets. Ex: \
{ "tag_targets_mappings": { "tag1": ["path/to/target:foo"] } }')
register('--tag-targets-mappings', type=dict, default=None, fromfile=True, fingerprint=True,
help='Dict with tag assignments for targets. Ex: { "tag1": ["path/to/target:foo"] }')

@classmethod
def tags_for(cls, target_address):
tag_assignments = cls.global_instance()
if tag_assignments.get_options().tag_targets_file:
return tag_assignments._parsed_tag_mappings().get(target_address, [])
else:
return []
return cls.global_instance()._invert_tag_targets_mappings().get(target_address, [])

@memoized_method
def _parsed_tag_mappings(self):
tag_targets_file = maybe_read_file(self.get_options().tag_targets_file, binary_mode=False)

if tag_targets_file:
parsed_json = json.loads(tag_targets_file)
mappings = parsed_json.get("tag_targets_mappings", {})
return self._invert_tag_targets_mappings(mappings)
else:
return {}

def _invert_tag_targets_mappings(self, parsed_json):
def _invert_tag_targets_mappings(self):
result = {}
for tag, targets in parsed_json.items():
for tag, targets in (self.get_options().tag_targets_mappings or {}).items():
for target in targets:
target_tags = result.setdefault(Address.parse(target).spec, [])
target_tags.append(tag)
@@ -112,29 +112,27 @@ def test_unknown_kwargs(self):
target = self.make_target('foo:bar', Target, foobar='barfoo')
self.assertFalse(hasattr(target, 'foobar'))

def test_tags_applied_from_configured_json(self):
with temporary_file(binary_mode=False) as fp:
json.dump({
'tag_targets_mappings': {
'special_tag': ['foo:bar', 'path/to/target:foo', 'path/to/target'],
'special_tag2': ['path/to/target:target', '//base:foo']
}
}, fp)
fp.flush()

options = {Target.TagAssignments.options_scope: {'tag_targets_file': fp.name}}
init_subsystem(Target.TagAssignments, options)
target1 = self.make_target('foo:bar', Target, tags=['tag1', 'tag2'])
target2 = self.make_target('path/to/target:foo', Target, tags=['tag1'])
target3 = self.make_target('path/to/target', Target, tags=['tag2'])
target4 = self.make_target('//base:foo', Target, tags=['tag3'])
target5 = self.make_target('baz:qux', Target, tags=['tag3'])

self.assertEqual({'tag1', 'tag2', 'special_tag'}, target1.tags)
self.assertEqual({'tag1', 'special_tag'}, target2.tags)
self.assertEqual({'tag2', 'special_tag', 'special_tag2'}, target3.tags)
self.assertEqual({'tag3', 'special_tag2'}, target4.tags)
self.assertEqual({'tag3'}, target5.tags)
def test_tags_applied_from_configured_dict(self):
options = {Target.TagAssignments.options_scope: {
'tag_targets_mappings': {
'special_tag': ['foo:bar', 'path/to/target:foo', 'path/to/target'],
'special_tag2': ['path/to/target:target', '//base:foo'],
'nonextant_target_tag': ['i/dont/exist'],
}
}}

init_subsystem(Target.TagAssignments, options)
target1 = self.make_target('foo:bar', Target, tags=['tag1', 'tag2'])
target2 = self.make_target('path/to/target:foo', Target, tags=['tag1'])
target3 = self.make_target('path/to/target', Target, tags=['tag2'])
target4 = self.make_target('//base:foo', Target, tags=['tag3'])
target5 = self.make_target('baz:qux', Target, tags=['tag3'])

self.assertEqual({'tag1', 'tag2', 'special_tag'}, target1.tags)
self.assertEqual({'tag1', 'special_tag'}, target2.tags)
self.assertEqual({'tag2', 'special_tag', 'special_tag2'}, target3.tags)
self.assertEqual({'tag3', 'special_tag2'}, target4.tags)
self.assertEqual({'tag3'}, target5.tags)

def test_target_id_long(self):
long_path = 'dummy'

0 comments on commit d4e53c7

Please sign in to comment.
You can’t perform that action at this time.