def _run_and_check(self, address_specs, incremental_import=None): """ Invoke idea-plugin goal and check for target specs and project in the generated project and workspace file. :param address_specs: list of address specs :return: n/a """ self.assertTrue(address_specs, "targets are empty") spec_parser = CmdLineSpecParser(get_buildroot()) # project_path is always the directory of the first target, # which is where intellij is going to zoom in under project view. project_path = spec_parser.parse_address_spec( address_specs[0]).directory with self.temporary_workdir() as workdir: with temporary_file(root_dir=workdir, cleanup=True) as output_file: args = [ 'idea-plugin', f'--output-file={output_file.name}', '--no-open', ] if incremental_import is not None: args.append(f'--incremental-import={incremental_import}') pants_run = self.run_pants_with_workdir( args + address_specs, workdir) self.assert_success(pants_run) project_dir = self._get_project_dir(output_file.name) self.assertTrue(os.path.exists(project_dir), f"{project_dir} does not exist") self._do_check(project_dir, project_path, address_specs, incremental_import=incremental_import)
def _get_targets(spec_str): spec_parser = CmdLineSpecParser(get_buildroot()) try: address_spec = spec_parser.parse_address_spec(spec_str) addresses = self.context.address_mapper.scan_address_specs([address_spec]) except AddressLookupError as e: raise TaskError('Failed to parse address selector: {spec_str}\n {message}'.format(spec_str=spec_str, message=e)) # filter specs may not have been parsed as part of the context: force parsing matches = set() for address in addresses: self.context.build_graph.inject_address_closure(address) matches.add(self.context.build_graph.get_target(address)) if not matches: raise TaskError('No matches for address selector: {spec_str}'.format(spec_str=spec_str)) return matches
def parse_address_specs( cls, target_specs: Iterable[str], build_root: Optional[str] = None, exclude_patterns: Optional[Iterable[str]] = None, tags: Optional[Iterable[str]] = None, ) -> AddressSpecs: """Parse string specs into unique `AddressSpec` objects.""" build_root = build_root or get_buildroot() spec_parser = CmdLineSpecParser(build_root) dependencies = tuple( OrderedSet( spec_parser.parse_address_spec(spec_str) for spec_str in target_specs)) return AddressSpecs( dependencies=dependencies, exclude_patterns=exclude_patterns if exclude_patterns else tuple(), tags=tags)
def set_start_time(self, start_time): # Launch RunTracker as early as possible (before .run() is called). self._run_tracker = RunTracker.global_instance() # Propagates parent_build_id to pants runs that may be called from this pants run. os.environ['PANTS_PARENT_BUILD_ID'] = self._run_tracker.run_id self._reporting = Reporting.global_instance() self._run_start_time = start_time self._reporting.initialize(self._run_tracker, self._options, start_time=self._run_start_time) spec_parser = CmdLineSpecParser(get_buildroot()) address_specs = [ spec_parser.parse_address_spec(spec).to_spec_string() for spec in self._options.specs ] # Note: This will not include values from `--owner-of` or `--changed-*` flags. self._run_tracker.run_info.add_info("specs_from_command_line", address_specs, stringify=False) # Capture a repro of the 'before' state for this build, if needed. self._repro = Reproducer.global_instance().create_repro() if self._repro: self._repro.capture(self._run_tracker.run_info.get_as_dict())
class CmdLineSpecParserTest(TestBase): def setUp(self): super().setUp() self._spec_parser = CmdLineSpecParser(self.build_root) def test_normal(self): self.assert_parsed(':root', single('', 'root')) self.assert_parsed('//:root', single('', 'root')) self.assert_parsed('a', single('a')) self.assert_parsed('a:a', single('a', 'a')) self.assert_parsed('a/b', single('a/b')) self.assert_parsed('a/b:b', single('a/b', 'b')) self.assert_parsed('a/b:c', single('a/b', 'c')) def test_sibling(self): self.assert_parsed(':', sib('')) self.assert_parsed('//:', sib('')) self.assert_parsed('a:', sib('a')) self.assert_parsed('//a:', sib('a')) self.assert_parsed('a/b:', sib('a/b')) self.assert_parsed('//a/b:', sib('a/b')) def test_sibling_or_descendents(self): self.assert_parsed('::', desc('')) self.assert_parsed('//::', desc('')) self.assert_parsed('a::', desc('a')) self.assert_parsed('//a::', desc('a')) self.assert_parsed('a/b::', desc('a/b')) self.assert_parsed('//a/b::', desc('a/b')) def test_absolute(self): self.assert_parsed(os.path.join(self.build_root, 'a'), single('a')) self.assert_parsed(os.path.join(self.build_root, 'a:a'), single('a', 'a')) self.assert_parsed(os.path.join(self.build_root, 'a:'), sib('a')) self.assert_parsed(os.path.join(self.build_root, 'a::'), desc('a')) with self.assertRaises(CmdLineSpecParser.BadSpecError): self.assert_parsed('/not/the/buildroot/a', sib('a')) def test_absolute_double_slashed(self): # By adding a double slash, we are insisting that this absolute path is actually # relative to the buildroot. Thus, it should parse correctly. double_absolute = '/' + os.path.join(self.build_root, 'a') self.assertEqual('//', double_absolute[:2], 'A sanity check we have a leading-// absolute spec') self.assert_parsed(double_absolute, single(double_absolute[2:])) def test_cmd_line_affordances(self): self.assert_parsed('./:root', single('', 'root')) self.assert_parsed('//./:root', single('', 'root')) self.assert_parsed('//./a/../:root', single('', 'root')) self.assert_parsed(os.path.join(self.build_root, './a/../:root'), single('', 'root')) self.assert_parsed('a/', single('a')) self.assert_parsed('./a/', single('a')) self.assert_parsed(os.path.join(self.build_root, './a/'), single('a')) self.assert_parsed('a/b/:b', single('a/b', 'b')) self.assert_parsed('./a/b/:b', single('a/b', 'b')) self.assert_parsed(os.path.join(self.build_root, './a/b/:b'), single('a/b', 'b')) def assert_parsed(self, spec_str: str, expected_address_spec: AddressSpec) -> None: self.assertEqual(self._spec_parser.parse_address_spec(spec_str), expected_address_spec)