def complete_scopes( cls, scope_infos: Iterable[ScopeInfo]) -> FrozenOrderedSet[ScopeInfo]: """Expand a set of scopes to include all enclosing scopes. E.g., if the set contains `foo.bar.baz`, ensure that it also contains `foo.bar` and `foo`. Also adds any deprecated scopes. """ ret: OrderedSet[ScopeInfo] = OrderedSet() original_scopes: Dict[str, ScopeInfo] = {} for si in sorted(scope_infos, key=lambda si: si.scope): ret.add(si) if si.scope in original_scopes: raise cls.DuplicateScopeError( "Scope `{}` claimed by {}, was also claimed by {}.".format( si.scope, si, original_scopes[si.scope])) original_scopes[si.scope] = si if si.deprecated_scope: ret.add( ScopeInfo(si.deprecated_scope, si.category, si.optionable_cls)) original_scopes[si.deprecated_scope] = si # TODO: Once scope name validation is enforced (so there can be no dots in scope name # components) we can replace this line with `for si in scope_infos:`, because it will # not be possible for a deprecated_scope to introduce any new intermediate scopes. for si in copy.copy(ret): for scope in all_enclosing_scopes(si.scope, allow_global=False): if scope not in original_scopes: ret.add(ScopeInfo(scope, ScopeInfo.INTERMEDIATE)) return FrozenOrderedSet(ret)
def known_scope_infos() -> list[ScopeInfo]: return [ ScopeInfo("check", is_goal=True), ScopeInfo("test", is_goal=True), ScopeInfo("jvm", is_goal=False), ScopeInfo("reporting", is_goal=False), ]
def known_scope_infos(cls): """Yields ScopeInfo for all known scopes for this task, in no particular order.""" # The task's own scope. yield ScopeInfo(cls.options_scope, ScopeInfo.TASK) # The scopes of any task-specific subsystems it uses. for subsystem in cls.task_subsystems(): yield ScopeInfo(subsystem.subscope(cls.options_scope), ScopeInfo.TASK_SUBSYSTEM)
def test_options_pantsrc_files(self) -> None: def create_options_bootstrapper(*config_paths: str) -> OptionsBootstrapper: return OptionsBootstrapper.create( env={}, args=[f"--pantsrc-files={cp}" for cp in config_paths], allow_pantsrc=True, ) with temporary_file(binary_mode=False) as fp: fp.write( dedent( """ [resolver] resolver = "coursier" """ ) ) fp.close() bootstrapped_options = create_options_bootstrapper(fp.name) opts_single_config = bootstrapped_options.full_options_for_scopes( known_scope_infos=[ ScopeInfo(""), ScopeInfo("resolver"), ] ) opts_single_config.register("", "--pantsrc-files", type=list) opts_single_config.register("resolver", "--resolver") self.assertEqual("coursier", opts_single_config.for_scope("resolver").resolver)
def complete_scopes(cls, scope_infos): """Expand a set of scopes to include all enclosing scopes. E.g., if the set contains `foo.bar.baz`, ensure that it also contains `foo.bar` and `foo`. Also adds any deprecated scopes. """ ret = {GlobalOptionsRegistrar.get_scope_info()} original_scopes = set() for si in scope_infos: ret.add(si) original_scopes.add(si.scope) if si.deprecated_scope: ret.add( ScopeInfo(si.deprecated_scope, si.category, si.optionable_cls)) original_scopes.add(si.deprecated_scope) # TODO: Once scope name validation is enforced (so there can be no dots in scope name # components) we can replace this line with `for si in scope_infos:`, because it will # not be possible for a deprecated_scope to introduce any new intermediate scopes. for si in copy.copy(ret): scope = si.scope while scope != '': if scope not in original_scopes: ret.add(ScopeInfo(scope, ScopeInfo.INTERMEDIATE)) scope = enclosing_scope(scope) return ret
def test_create_bootstrapped_options(self): # Check that we can set a bootstrap option from a cmd-line flag and have that interpolate # correctly into regular config. with temporary_file() as fp: fp.write( dedent(""" [foo] bar: %(pants_workdir)s/baz [fruit] apple: %(pants_supportdir)s/banana """)) fp.close() bootstrapper = OptionsBootstrapper( env={'PANTS_SUPPORTDIR': '/pear'}, configpath=fp.name, args=['--pants-workdir=/qux']) opts = bootstrapper.get_full_options(known_scope_infos=[ ScopeInfo('', ScopeInfo.GLOBAL), ScopeInfo('foo', ScopeInfo.TASK), ScopeInfo('fruit', ScopeInfo.TASK) ]) opts.register( '', '--pants-workdir') # So we don't choke on it on the cmd line. opts.register('foo', '--bar') opts.register('fruit', '--apple') self.assertEquals('/qux/baz', opts.for_scope('foo').bar) self.assertEquals('/pear/banana', opts.for_scope('fruit').apple)
def complete_scopes(cls, scope_infos): """Expand a set of scopes to include all enclosing scopes. E.g., if the set contains `foo.bar.baz`, ensure that it also contains `foo.bar` and `foo`. Also adds any deprecated scopes. """ ret = {GlobalOptionsRegistrar.get_scope_info()} original_scopes = dict() for si in scope_infos: ret.add(si) if si.scope in original_scopes: raise cls.DuplicateScopeError('Scope `{}` claimed by {}, was also claimed by {}.'.format( si.scope, si, original_scopes[si.scope] )) original_scopes[si.scope] = si if si.deprecated_scope: ret.add(ScopeInfo(si.deprecated_scope, si.category, si.optionable_cls)) original_scopes[si.deprecated_scope] = si # TODO: Once scope name validation is enforced (so there can be no dots in scope name # components) we can replace this line with `for si in scope_infos:`, because it will # not be possible for a deprecated_scope to introduce any new intermediate scopes. for si in copy.copy(ret): for scope in all_enclosing_scopes(si.scope, allow_global=False): if scope not in original_scopes: ret.add(ScopeInfo(scope, ScopeInfo.INTERMEDIATE)) return ret
def test_create_bootstrapped_options(self) -> None: # Check that we can set a bootstrap option from a cmd-line flag and have that interpolate # correctly into regular config. with temporary_file(binary_mode=False) as fp: fp.write( dedent(""" [foo] bar: %(pants_workdir)s/baz [fruit] apple: %(pants_supportdir)s/banana """)) fp.close() args = ["--pants-workdir=/qux"] + self._config_path(fp.name) bootstrapper = OptionsBootstrapper.create( env={"PANTS_SUPPORTDIR": "/pear"}, args=args) opts = bootstrapper.get_full_options(known_scope_infos=[ ScopeInfo("", ScopeInfo.GLOBAL), ScopeInfo("foo", ScopeInfo.TASK), ScopeInfo("fruit", ScopeInfo.TASK), ]) # So we don't choke on these on the cmd line. opts.register("", "--pants-workdir") opts.register("", "--pants-config-files") opts.register("foo", "--bar") opts.register("fruit", "--apple") self.assertEqual("/qux/baz", opts.for_scope("foo").bar) self.assertEqual("/pear/banana", opts.for_scope("fruit").apple)
def known_scope_infos() -> list[ScopeInfo]: return [ ScopeInfo("check", is_goal=True), ScopeInfo("test", is_goal=True), ScopeInfo("jvm", is_goal=False), ScopeInfo("reporting", is_goal=False), # TODO: move help related tests closer to `pants.goal.help` to avoid this cludge. *(goal.get_scope_info() for goal in builtin_goals()), ]
def test_full_options_caching(self) -> None: with temporary_file_path() as config: args = self._config_path(config) bootstrapper = OptionsBootstrapper.create(env={}, args=args, allow_pantsrc=False) opts1 = bootstrapper.full_options_for_scopes( known_scope_infos=[ ScopeInfo(""), ScopeInfo("foo"), ] ) opts2 = bootstrapper.full_options_for_scopes( known_scope_infos=[ ScopeInfo("foo"), ScopeInfo(""), ] ) assert opts1 is opts2 opts3 = bootstrapper.full_options_for_scopes( known_scope_infos=[ ScopeInfo(""), ScopeInfo("foo"), ScopeInfo(""), ] ) assert opts1 is opts3 opts4 = bootstrapper.full_options_for_scopes(known_scope_infos=[ScopeInfo("")]) assert opts1 is not opts4 opts5 = bootstrapper.full_options_for_scopes(known_scope_infos=[ScopeInfo("")]) assert opts4 is opts5 assert opts1 is not opts5
def test_full_options_caching(self) -> None: with temporary_file_path() as config: args = self._config_path(config) bootstrapper = OptionsBootstrapper.create(env={}, args=args) opts1 = bootstrapper.get_full_options(known_scope_infos=[ ScopeInfo("", ScopeInfo.GLOBAL), ScopeInfo("foo", ScopeInfo.TASK), ]) opts2 = bootstrapper.get_full_options(known_scope_infos=[ ScopeInfo("foo", ScopeInfo.TASK), ScopeInfo("", ScopeInfo.GLOBAL), ]) assert opts1 is opts2 opts3 = bootstrapper.get_full_options(known_scope_infos=[ ScopeInfo("", ScopeInfo.GLOBAL), ScopeInfo("foo", ScopeInfo.TASK), ScopeInfo("", ScopeInfo.GLOBAL), ]) assert opts1 is opts3 opts4 = bootstrapper.get_full_options( known_scope_infos=[ScopeInfo("", ScopeInfo.GLOBAL)]) assert opts1 is not opts4 opts5 = bootstrapper.get_full_options( known_scope_infos=[ScopeInfo("", ScopeInfo.GLOBAL)]) assert opts4 is opts5 assert opts1 is not opts5
def test_full_options_caching(self): with temporary_file_path() as config: bootstrapper = OptionsBootstrapper(env={}, configpath=config, args=[]) opts1 = bootstrapper.get_full_options(known_scope_infos=[ ScopeInfo('', ScopeInfo.GLOBAL), ScopeInfo('foo', ScopeInfo.TASK) ]) opts2 = bootstrapper.get_full_options(known_scope_infos=[ ScopeInfo('foo', ScopeInfo.TASK), ScopeInfo('', ScopeInfo.GLOBAL) ]) self.assertIs(opts1, opts2) opts3 = bootstrapper.get_full_options(known_scope_infos=[ ScopeInfo('', ScopeInfo.GLOBAL), ScopeInfo('foo', ScopeInfo.TASK), ScopeInfo('', ScopeInfo.GLOBAL) ]) self.assertIs(opts1, opts3) opts4 = bootstrapper.get_full_options( known_scope_infos=[ScopeInfo('', ScopeInfo.GLOBAL)]) self.assertIsNot(opts1, opts4) opts5 = bootstrapper.get_full_options( known_scope_infos=[ScopeInfo('', ScopeInfo.GLOBAL)]) self.assertIs(opts4, opts5) self.assertIsNot(opts1, opts5)
def test_complete_scopes(self): _global = ScopeInfo.for_global_scope() self.assertEquals({_global, intermediate('foo'), intermediate('foo.bar'), task('foo.bar.baz')}, Options.complete_scopes({task('foo.bar.baz')})) self.assertEquals({_global, intermediate('foo'), intermediate('foo.bar'), task('foo.bar.baz')}, Options.complete_scopes({ScopeInfo.for_global_scope(), task('foo.bar.baz')})) self.assertEquals({_global, goal('foo'), intermediate('foo.bar'), task('foo.bar.baz')}, Options.complete_scopes({goal('foo'), task('foo.bar.baz')})) self.assertEquals({_global, intermediate('foo'), intermediate('foo.bar'), task('foo.bar.baz'), intermediate('qux'), task('qux.quux')}, Options.complete_scopes({task('foo.bar.baz'), task('qux.quux')}))
def known_scope_infos(cls): """Yields ScopeInfos for all known scopes for this task, in no particular order.""" # We need this because task.py initializes a cache factory for every task type, # even if it's never used. This is slightly icky, but is better than forcing tasks # to explicitly call a cache setup method. And we want to kill GroupTask anyway. yield ScopeInfo(cls.options_scope, ScopeInfo.TASK) for subsystem in cls.task_subsystems(): yield ScopeInfo(subsystem.subscope(cls.options_scope), ScopeInfo.TASK_SUBSYSTEM) for member_type in cls._member_types(): for scope in member_type.known_scope_infos(): yield scope
def get_scope_info(cls): """Returns a ScopeInfo instance representing this Optionable's options scope.""" if cls.options_scope is None or cls.options_scope_category is None: raise OptionsError( '{} must set options_scope and options_scope_category.'.format( cls.__name__)) return ScopeInfo(cls.options_scope, cls.options_scope_category, cls)
def collect_scope_infos(optionable_cls, scoped_to, removal_version=None, removal_hint=None): if optionable_cls in optionables_path: raise cls.CycleException(list(optionables_path) + [optionable_cls]) optionables_path.add(optionable_cls) scope = (optionable_cls.options_scope if scoped_to == GLOBAL_SCOPE else optionable_cls.subscope(scoped_to)) scope_info = ScopeInfo( scope, optionable_cls.options_scope_category, optionable_cls, removal_version=removal_version, removal_hint=removal_hint ) if scope_info not in known_scope_infos: known_scope_infos.add(scope_info) for dep in scope_info.optionable_cls.subsystem_dependencies_iter(): # A subsystem always exists at its global scope (for the purpose of options # registration and specification), even if in practice we only use it scoped to # some other scope. # # NB: We do not apply deprecations to this implicit global copy of the scope, because if # the intention was to deprecate the entire scope, that could be accomplished by # deprecating all options in the scope. collect_scope_infos(dep.subsystem_cls, GLOBAL_SCOPE) if not dep.is_global(): collect_scope_infos(dep.subsystem_cls, scope, removal_version=dep.removal_version, removal_hint=dep.removal_hint) optionables_path.remove(scope_info.optionable_cls)
def complete_scopes(cls, scope_infos): """Expand a set of scopes to include all enclosing scopes. E.g., if the set contains `foo.bar.baz`, ensure that it also contains `foo.bar` and `foo`. """ ret = {ScopeInfo.for_global_scope()} for scope_info in scope_infos: ret.add(scope_info) original_scopes = {si.scope for si in scope_infos} for scope_info in scope_infos: scope = scope_info.scope while scope != '': if scope not in original_scopes: ret.add(ScopeInfo(scope, ScopeInfo.INTERMEDIATE)) scope = scope.rpartition('.')[0] return ret
def test_goal_scope_flag() -> None: class DummyGoal(GoalSubsystem): name = "dummy" dummy = create_goal_subsystem(DummyGoal) assert dummy.get_scope_info() == ScopeInfo(scope="dummy", subsystem_cls=DummyGoal, is_goal=True)
def test_options_pantsrc_files(self) -> None: def create_options_bootstrapper(*config_paths: str) -> OptionsBootstrapper: return OptionsBootstrapper.create(args=[f'--pantsrc-files={cp}' for cp in config_paths]) with temporary_file(binary_mode=False) as fp: fp.write(dedent(""" [resolver] resolver: coursier """)) fp.close() bootstrapped_options = create_options_bootstrapper(fp.name) opts_single_config = bootstrapped_options.get_full_options(known_scope_infos=[ ScopeInfo('', ScopeInfo.GLOBAL), ScopeInfo('resolver', ScopeInfo.TASK), ]) opts_single_config.register('', '--pantsrc-files', type=list) opts_single_config.register('resolver', '--resolver') self.assertEqual('coursier', opts_single_config.for_scope('resolver').resolver)
def assert_config_read_correctly( options_bootstrapper: OptionsBootstrapper, *, expected_worker_count: int, ) -> None: options = options_bootstrapper.get_full_options( known_scope_infos=[ ScopeInfo('', ScopeInfo.GLOBAL), ScopeInfo('compile.apt', ScopeInfo.TASK), ScopeInfo('fruit', ScopeInfo.TASK), ], ) # So we don't choke on these on the cmd line. options.register('', '--pants-config-files', type=list) options.register('', '--config-override', type=list) options.register('compile.apt', '--worker-count') options.register('fruit', '--apple') self.assertEqual(str(expected_worker_count), options.for_scope('compile.apt').worker_count) self.assertEqual('red', options.for_scope('fruit').apple)
def test_banned_alias_names() -> None: cli_alias = CliAlias.from_dict({"fmt": "--cleverness format"}) with pytest.raises( CliAliasInvalidError, match= (r"Invalid alias in `\[cli\]\.alias` option: 'fmt'\. This is already a registered goal\." ), ): cli_alias.check_name_conflicts({"fmt": ScopeInfo("fmt", is_goal=True)})
def assert_config_read_correctly( options_bootstrapper: OptionsBootstrapper, *, expected_worker_count: int, ) -> None: options = options_bootstrapper.get_full_options(known_scope_infos=[ ScopeInfo(""), ScopeInfo("compile.apt"), ScopeInfo("fruit"), ], ) # So we don't choke on these on the cmd line. options.register("", "--pants-config-files", type=list) options.register("", "--config-override", type=list) options.register("compile.apt", "--worker-count") options.register("fruit", "--apple") self.assertEqual(str(expected_worker_count), options.for_scope("compile.apt").worker_count) self.assertEqual("red", options.for_scope("fruit").apple)
def _print_options_help(self): """Print a help screen. Assumes that self._help_request is an instance of OptionsHelp. Note: Ony useful if called after options have been registered. """ show_all_help = self._help_request.all_scopes if show_all_help: help_scopes = list(self._options.known_scope_to_info.keys()) else: # The scopes explicitly mentioned by the user on the cmd line. help_scopes = set( self._options.scope_to_flags.keys()) - {GLOBAL_SCOPE} scope_infos = list( ScopeInfoIterator( self._options.known_scope_to_info).iterate(help_scopes)) if scope_infos: for scope_info in scope_infos: help_str = self._format_help(scope_info) if help_str: print(help_str) return else: print(pants_release()) print('\nUsage:') print( f' {self.bin_name} [option ...] [goal ...] [target...] Attempt the specified goals.' ) print( f' {self.bin_name} help Get help.' ) print( f' {self.bin_name} help [goal] Get help for a goal.' ) print( f' {self.bin_name} help-advanced [goal] Get help for a goal\'s advanced options.' ) print( f' {self.bin_name} help-all Get help for all goals.' ) print( f' {self.bin_name} goals List all installed goals.' ) print('') print(' [target] accepts two special forms:') print( ' dir: to include all targets in the specified directory.') print( ' dir:: to include all targets found recursively under the directory.' ) print('\nFriendly docs:\n http://pantsbuild.org/') print(self._format_help(ScopeInfo(GLOBAL_SCOPE, ScopeInfo.GLOBAL)))
def bootstrap_options_from_config(config): bootstrap_options = Options( env=self._env, config=config, known_scope_infos=[ScopeInfo.for_global_scope()], args=bargs) def register_global(*args, **kwargs): bootstrap_options.register(GLOBAL_SCOPE, *args, **kwargs) GlobalOptionsRegistrar.register_bootstrap_options( register_global) return bootstrap_options
def test_complete_scopes(self): _global = ScopeInfo.for_global_scope() self.assertEquals( { _global, intermediate('foo'), intermediate('foo.bar'), task('foo.bar.baz') }, Options.complete_scopes({task('foo.bar.baz')})) self.assertEquals( { _global, intermediate('foo'), intermediate('foo.bar'), task('foo.bar.baz') }, Options.complete_scopes( {ScopeInfo.for_global_scope(), task('foo.bar.baz')})) self.assertEquals( { _global, intermediate('foo'), intermediate('foo.bar'), task('foo.bar.baz') }, Options.complete_scopes({intermediate('foo'), task('foo.bar.baz')})) self.assertEquals( { _global, intermediate('foo'), intermediate('foo.bar'), task('foo.bar.baz'), intermediate('qux'), task('qux.quux') }, Options.complete_scopes({task('foo.bar.baz'), task('qux.quux')}))
def do_test_create_bootstrapped_multiple_config(self, create_options_bootstrapper): # check with multiple config files, the latest values always get taken # in this case worker_count will be overwritten, while fruit stays the same with temporary_file() as fp: fp.write(dedent(""" [compile.apt] worker_count: 1 [fruit] apple: red """)) fp.close() bootstrapper_single_config = create_options_bootstrapper(fp.name) opts_single_config = bootstrapper_single_config.get_full_options(known_scope_infos=[ ScopeInfo('', ScopeInfo.GLOBAL), ScopeInfo('compile.apt', ScopeInfo.TASK), ScopeInfo('fruit', ScopeInfo.TASK), ]) # So we don't choke on these on the cmd line. opts_single_config.register('', '--pants-config-files', type=list) opts_single_config.register('', '--config-override', type=list) opts_single_config.register('compile.apt', '--worker-count') opts_single_config.register('fruit', '--apple') self.assertEquals('1', opts_single_config.for_scope('compile.apt').worker_count) self.assertEquals('red', opts_single_config.for_scope('fruit').apple) with temporary_file() as fp2: fp2.write(dedent(""" [compile.apt] worker_count: 2 """)) fp2.close() bootstrapper_double_config = create_options_bootstrapper(fp.name, fp2.name) opts_double_config = bootstrapper_double_config.get_full_options(known_scope_infos=[ ScopeInfo('', ScopeInfo.GLOBAL), ScopeInfo('compile.apt', ScopeInfo.TASK), ScopeInfo('fruit', ScopeInfo.TASK), ]) # So we don't choke on these on the cmd line. opts_double_config.register('', '--pants-config-files', type=list) opts_double_config.register('', '--config-override', type=list) opts_double_config.register('compile.apt', '--worker-count') opts_double_config.register('fruit', '--apple') self.assertEquals('2', opts_double_config.for_scope('compile.apt').worker_count) self.assertEquals('red', opts_double_config.for_scope('fruit').apple)
def collect_scope_infos(optionable_cls, scoped_to): if optionable_cls in optionables_path: raise cls.CycleException(list(optionables_path) + [optionable_cls]) optionables_path.add(optionable_cls) scope = (optionable_cls.options_scope if scoped_to == GLOBAL_SCOPE else optionable_cls.subscope(scoped_to)) scope_info = ScopeInfo(scope, optionable_cls.options_scope_category, optionable_cls) if scope_info not in known_scope_infos: known_scope_infos.add(scope_info) for dep in scope_info.optionable_cls.subsystem_dependencies_iter(): # A subsystem always exists at its global scope (for the purpose of options # registration and specification), even if in practice we only use it scoped to # some other scope. collect_scope_infos(dep.subsystem_cls, GLOBAL_SCOPE) if not dep.is_global(): collect_scope_infos(dep.subsystem_cls, scope) optionables_path.remove(scope_info.optionable_cls)
def subsystem(scope): return ScopeInfo(scope, ScopeInfo.SUBSYSTEM)
def intermediate(scope): return ScopeInfo(scope, ScopeInfo.INTERMEDIATE)
def task(scope): return ScopeInfo(scope, ScopeInfo.TASK)
def get_scope_info(cls): """Returns a ScopeInfo instance representing this Optionable's options scope.""" if cls.options_scope is None: raise OptionsError(f"{cls.__name__} must set options_scope.") return ScopeInfo(cls.options_scope, cls)
def setup(self): options_bootstrapper = OptionsBootstrapper() bootstrap_options = options_bootstrapper.get_bootstrap_options() # Get logging setup prior to loading backends so that they can log as needed. self._setup_logging(bootstrap_options.for_global_scope()) # Add any extra paths to python path (eg for loading extra source backends) for path in bootstrap_options.for_global_scope().pythonpath: sys.path.append(path) pkg_resources.fixup_namespace_packages(path) # Load plugins and backends. plugins = bootstrap_options.for_global_scope().plugins backend_packages = bootstrap_options.for_global_scope().backend_packages build_configuration = load_plugins_and_backends(plugins, backend_packages) # Now that plugins and backends are loaded, we can gather the known scopes. self.targets = [] known_scope_infos = [ScopeInfo.for_global_scope()] # Add scopes for all needed subsystems. subsystems = (set(self.subsystems) | Goal.subsystems() | build_configuration.subsystems()) for subsystem in subsystems: known_scope_infos.append(ScopeInfo(subsystem.options_scope, ScopeInfo.GLOBAL_SUBSYSTEM)) # Add scopes for all tasks in all goals. for goal in Goal.all(): known_scope_infos.extend(filter(None, goal.known_scope_infos())) # Now that we have the known scopes we can get the full options. self.options = options_bootstrapper.get_full_options(known_scope_infos) self.register_options(subsystems) # Make the options values available to all subsystems. Subsystem._options = self.options # Now that we have options we can instantiate subsystems. self.run_tracker = RunTracker.global_instance() self.reporting = Reporting.global_instance() report = self.reporting.initial_reporting(self.run_tracker) self.run_tracker.start(report) url = self.run_tracker.run_info.get_info('report_url') if url: self.run_tracker.log(Report.INFO, 'See a report at: {}'.format(url)) else: self.run_tracker.log(Report.INFO, '(To run a reporting server: ./pants server)') self.build_file_parser = BuildFileParser(build_configuration=build_configuration, root_dir=self.root_dir, run_tracker=self.run_tracker) rev = self.options.for_global_scope().build_file_rev if rev: ScmBuildFile.set_rev(rev) ScmBuildFile.set_scm(get_scm()) build_file_type = ScmBuildFile else: build_file_type = FilesystemBuildFile self.address_mapper = BuildFileAddressMapper(self.build_file_parser, build_file_type) self.build_graph = BuildGraph(run_tracker=self.run_tracker, address_mapper=self.address_mapper) # TODO(John Sirois): Kill when source root registration is lifted out of BUILD files. with self.run_tracker.new_workunit(name='bootstrap', labels=[WorkUnit.SETUP]): source_root_bootstrapper = SourceRootBootstrapper.global_instance() source_root_bootstrapper.bootstrap(self.address_mapper, self.build_file_parser) self._expand_goals_and_specs() # Now that we've parsed the bootstrap BUILD files, and know about the SCM system. self.run_tracker.run_info.add_scm_info()