PageRenderTime 25ms CodeModel.GetById 0ms RepoModel.GetById 0ms app.codeStats 0ms

/src/python/pants/bin/engine_initializer.py

https://gitlab.com/Ivy001/pants
Python | 136 lines | 112 code | 13 blank | 11 comment | 3 complexity | 35eccba353a559203c7342d88b1a9d67 MD5 | raw file
  1. # coding=utf-8
  2. # Copyright 2016 Pants project contributors (see CONTRIBUTORS.md).
  3. # Licensed under the Apache License, Version 2.0 (see LICENSE).
  4. from __future__ import (absolute_import, division, generators, nested_scopes, print_function,
  5. unicode_literals, with_statement)
  6. import logging
  7. from collections import namedtuple
  8. from pants.base.build_environment import get_buildroot
  9. from pants.base.cmd_line_spec_parser import CmdLineSpecParser
  10. from pants.base.file_system_project_tree import FileSystemProjectTree
  11. from pants.bin.options_initializer import OptionsInitializer
  12. from pants.engine.engine import LocalSerialEngine
  13. from pants.engine.fs import create_fs_tasks
  14. from pants.engine.graph import create_graph_tasks
  15. from pants.engine.legacy.address_mapper import LegacyAddressMapper
  16. from pants.engine.legacy.graph import LegacyBuildGraph, LegacyTarget, create_legacy_graph_tasks
  17. from pants.engine.legacy.parser import LegacyPythonCallbacksParser
  18. from pants.engine.legacy.structs import (JvmAppAdaptor, PythonTargetAdaptor, RemoteSourcesAdaptor,
  19. TargetAdaptor)
  20. from pants.engine.mapper import AddressMapper
  21. from pants.engine.parser import SymbolTable
  22. from pants.engine.scheduler import LocalScheduler
  23. from pants.engine.storage import Storage
  24. from pants.option.options_bootstrapper import OptionsBootstrapper
  25. from pants.util.memo import memoized_method
  26. logger = logging.getLogger(__name__)
  27. # N.B. This should be top-level in the module for pickleability - don't nest it.
  28. class LegacySymbolTable(SymbolTable):
  29. """A v1 SymbolTable facade for use with the v2 engine."""
  30. @classmethod
  31. @memoized_method
  32. def aliases(cls):
  33. """TODO: This is a nasty escape hatch to pass aliases to LegacyPythonCallbacksParser."""
  34. _, build_config = OptionsInitializer(OptionsBootstrapper()).setup(init_logging=False)
  35. return build_config.registered_aliases()
  36. @classmethod
  37. @memoized_method
  38. def table(cls):
  39. aliases = {alias: TargetAdaptor for alias in cls.aliases().target_types}
  40. # TODO: The alias replacement here is to avoid elevating "TargetAdaptors" into the public
  41. # API until after https://github.com/pantsbuild/pants/issues/3560 has been completed.
  42. # These should likely move onto Target subclasses as the engine gets deeper into beta
  43. # territory.
  44. aliases['jvm_app'] = JvmAppAdaptor
  45. aliases['remote_sources'] = RemoteSourcesAdaptor
  46. for alias in ('python_library', 'python_tests', 'python_binary'):
  47. aliases[alias] = PythonTargetAdaptor
  48. return aliases
  49. class LegacyGraphHelper(namedtuple('LegacyGraphHelper', ['scheduler', 'engine', 'symbol_table_cls'])):
  50. """A container for the components necessary to construct a legacy BuildGraph facade."""
  51. def warm_product_graph(self, spec_roots):
  52. """Warm the scheduler's `ProductGraph` with `LegacyTarget` products."""
  53. request = self.scheduler.execution_request([LegacyTarget], spec_roots)
  54. result = self.engine.execute(request)
  55. if result.error:
  56. raise result.error
  57. def create_build_graph(self, spec_roots, build_root=None):
  58. """Construct and return a `BuildGraph` given a set of input specs."""
  59. graph = LegacyBuildGraph(self.scheduler, self.engine, self.symbol_table_cls)
  60. with self.scheduler.locked():
  61. # Ensure the entire generator is unrolled.
  62. for _ in graph.inject_specs_closure(spec_roots):
  63. pass
  64. logger.debug('engine cache stats: %s', self.engine.cache_stats())
  65. address_mapper = LegacyAddressMapper(graph, build_root or get_buildroot())
  66. logger.debug('build_graph is: %s', graph)
  67. logger.debug('address_mapper is: %s', address_mapper)
  68. return graph, address_mapper
  69. class EngineInitializer(object):
  70. """Constructs the components necessary to run the v2 engine with v1 BuildGraph compatibility."""
  71. @staticmethod
  72. def parse_commandline_to_spec_roots(options=None, args=None, build_root=None):
  73. if not options:
  74. options, _ = OptionsInitializer(OptionsBootstrapper(args=args)).setup(init_logging=False)
  75. cmd_line_spec_parser = CmdLineSpecParser(build_root or get_buildroot())
  76. spec_roots = [cmd_line_spec_parser.parse_spec(spec) for spec in options.target_specs]
  77. return spec_roots
  78. @staticmethod
  79. def setup_legacy_graph(pants_ignore_patterns,
  80. symbol_table_cls=None,
  81. build_ignore_patterns=None,
  82. exclude_target_regexps=None):
  83. """Construct and return the components necessary for LegacyBuildGraph construction.
  84. :param list pants_ignore_patterns: A list of path ignore patterns for FileSystemProjectTree,
  85. usually taken from the '--pants-ignore' global option.
  86. :param SymbolTable symbol_table_cls: A SymbolTable class to use for build file parsing, or
  87. None to use the default.
  88. :param list build_ignore_patterns: A list of paths ignore patterns used when searching for BUILD
  89. files, usually taken from the '--build-ignore' global option.
  90. :param list exclude_target_regexps: A list of regular expressions for excluding targets.
  91. :returns: A tuple of (scheduler, engine, symbol_table_cls, build_graph_cls).
  92. """
  93. build_root = get_buildroot()
  94. project_tree = FileSystemProjectTree(build_root, pants_ignore_patterns)
  95. symbol_table_cls = symbol_table_cls or LegacySymbolTable
  96. # Register "literal" subjects required for these tasks.
  97. # TODO: Replace with `Subsystems`.
  98. address_mapper = AddressMapper(symbol_table_cls=symbol_table_cls,
  99. parser_cls=LegacyPythonCallbacksParser,
  100. build_ignore_patterns=build_ignore_patterns,
  101. exclude_target_regexps=exclude_target_regexps)
  102. # Create a Scheduler containing graph and filesystem tasks, with no installed goals. The
  103. # LegacyBuildGraph will explicitly request the products it needs.
  104. tasks = (
  105. create_legacy_graph_tasks() +
  106. create_fs_tasks() +
  107. create_graph_tasks(address_mapper, symbol_table_cls)
  108. )
  109. scheduler = LocalScheduler(dict(), tasks, project_tree)
  110. # TODO: Do not use the cache yet, as it incurs a high overhead.
  111. engine = LocalSerialEngine(scheduler, Storage.create(), use_cache=False)
  112. return LegacyGraphHelper(scheduler, engine, symbol_table_cls)