Example #1
0
    def _register(cls, source_root_dir, mutable, *allowed_target_types):
        """Registers a source root.

    :param string source_root_dir: The source root directory against which we resolve source paths,
                     relative to the build root.
    :param list allowed_target_types: Optional list of target types. If specified, we enforce that
                          only targets of those types appear under this source root.
    """
        # Temporary delegation to the new implementation, until this entire file goes away.
        SourceRootConfig.global_instance().get_source_roots().add_source_root(
            source_root_dir)

        source_root_dir = SourceRoot._relative_to_buildroot(source_root_dir)

        types = cls._TYPES_BY_ROOT.get(source_root_dir)
        if types is None:
            types = OrderedSet()
            cls._TYPES_BY_ROOT[source_root_dir] = types

        for allowed_target_type in allowed_target_types:
            types.add(allowed_target_type)
            roots = cls._ROOTS_BY_TYPE.get(allowed_target_type)
            if roots is None:
                roots = OrderedSet()
                cls._ROOTS_BY_TYPE[allowed_target_type] = roots
            roots.add(source_root_dir)

        cls._SOURCE_ROOT_TREE.add_root(source_root_dir, allowed_target_types,
                                       mutable)
Example #2
0
  def _register(cls, source_root_dir, mutable, *allowed_target_types):
    """Registers a source root.

    :param string source_root_dir: The source root directory against which we resolve source paths,
                     relative to the build root.
    :param list allowed_target_types: Optional list of target types. If specified, we enforce that
                          only targets of those types appear under this source root.
    """
    # Temporary delegation to the new implementation, until this entire file goes away.
    SourceRootConfig.global_instance().get_source_roots().add_source_root(source_root_dir)

    source_root_dir = SourceRoot._relative_to_buildroot(source_root_dir)

    types = cls._TYPES_BY_ROOT.get(source_root_dir)
    if types is None:
      types = OrderedSet()
      cls._TYPES_BY_ROOT[source_root_dir] = types

    for allowed_target_type in allowed_target_types:
      types.add(allowed_target_type)
      roots = cls._ROOTS_BY_TYPE.get(allowed_target_type)
      if roots is None:
        roots = OrderedSet()
        cls._ROOTS_BY_TYPE[allowed_target_type] = roots
      roots.add(source_root_dir)

    cls._SOURCE_ROOT_TREE.add_root(source_root_dir, allowed_target_types, mutable)
Example #3
0
    def assert_sources(
        self,
        expected_files,
        expected_packages,
        expected_namespace_packages,
        expected_package_data,
        addrs,
    ):
        srcs = self.request_single_product(
            SetupPySources,
            Params(
                SetupPySourcesRequest(Targets(
                    [self.tgt(addr) for addr in addrs]),
                                      py2=False),
                SourceRootConfig.global_instance(),
            ),
        )
        chroot_snapshot = self.request_single_product(Snapshot,
                                                      Params(srcs.digest))

        assert sorted(expected_files) == sorted(chroot_snapshot.files)
        assert sorted(expected_packages) == sorted(srcs.packages)
        assert sorted(expected_namespace_packages) == sorted(
            srcs.namespace_packages)
        assert expected_package_data == dict(srcs.package_data)
Example #4
0
async def strip_source_root(
        hydrated_target: HydratedTarget,
        source_root_config: SourceRootConfig) -> SourceRootStrippedSources:
    """Relativize targets to their source root, e.g.
  `src/python/pants/util/strutil.py` -> `pants/util/strutil.py ."""

    target_adaptor = hydrated_target.adaptor
    source_roots = source_root_config.get_source_roots()

    # TODO: make TargetAdaptor return a 'sources' field with an empty snapshot instead of raising to
    # simplify the hasattr() checks here!
    if not hasattr(target_adaptor, 'sources'):
        return SourceRootStrippedSources(snapshot=EMPTY_SNAPSHOT)

    digest = target_adaptor.sources.snapshot.directory_digest
    source_root = source_roots.find_by_path(target_adaptor.address.spec_path)
    if source_root is None:
        # If we found no source root, use the target's dir.
        # Note that when --source-unmatched is 'create' (the default) we'll never return None,
        # but will return the target's dir. This check allows this code to work even if
        # --source-unmatched is 'fail'.
        source_root_path = target_adaptor.address.spec_path
    else:
        source_root_path = source_root.path

    # Loose `Files`, as opposed to `Resources` or `Target`s, have no (implied) package
    # structure and so we do not remove their source root like we normally do, so that filesystem
    # APIs may still access the files. See pex_build_util.py's `_create_source_dumper`.
    if target_adaptor.type_alias == Files.alias():
        source_root_path = ''

    resulting_digest = await Get[Digest](DirectoryWithPrefixToStrip(
        directory_digest=digest, prefix=source_root_path))
    resulting_snapshot = await Get[Snapshot](Digest, resulting_digest)
    return SourceRootStrippedSources(snapshot=resulting_snapshot)
Example #5
0
async def strip_source_root(
        hydrated_target: HydratedTarget,
        source_root_config: SourceRootConfig) -> SourceRootStrippedSources:
    """Relativize targets to their source root, e.g.
  `src/python/pants/util/strutil.py` -> `pants/util/strutil.py ."""

    target_adaptor = hydrated_target.adaptor
    source_roots = source_root_config.get_source_roots()

    # TODO: make TargetAdaptor return a 'sources' field with an empty snapshot instead of raising to
    # simplify the hasattr() checks here!
    if not hasattr(target_adaptor, 'sources'):
        return SourceRootStrippedSources(snapshot=EMPTY_SNAPSHOT)

    digest = target_adaptor.sources.snapshot.directory_digest
    source_root = source_roots.find_by_path(target_adaptor.address.spec_path)

    # Loose `Files`, as opposed to `Resources` or `Target`s, have no (implied) package
    # structure and so we do not remove their source root like we normally do, so that filesystem
    # APIs may still access the files. See pex_build_util.py's `_create_source_dumper`.
    if target_adaptor.type_alias == Files.alias():
        source_root = None

    resulting_digest = await Get(
        Digest,
        DirectoryWithPrefixToStrip(
            directory_digest=digest,
            prefix=source_root.path if source_root else ""))
    resulting_snapshot = await Get(Snapshot, Digest, resulting_digest)
    return SourceRootStrippedSources(snapshot=resulting_snapshot)
Example #6
0
 def __init__(self,
              options,
              run_tracker,
              target_roots,
              requested_goals=None,
              target_base=None,
              build_graph=None,
              build_file_parser=None,
              address_mapper=None,
              console_outstream=None,
              scm=None,
              workspace=None,
              invalidation_report=None):
     self._options = options
     self.build_graph = build_graph
     self.build_file_parser = build_file_parser
     self.address_mapper = address_mapper
     self.run_tracker = run_tracker
     self._log = self.Log(run_tracker)
     self._target_base = target_base or Target
     self._products = Products()
     self._buildroot = get_buildroot()
     self._source_roots = SourceRootConfig.global_instance(
     ).get_source_roots()
     self._lock = OwnerPrintingInterProcessFileLock(
         os.path.join(self._buildroot, '.pants.workdir.file_lock'))
     self._java_sysprops = None  # Computed lazily.
     self.requested_goals = requested_goals or []
     self._console_outstream = console_outstream or sys.stdout
     self._scm = scm or get_scm()
     self._workspace = workspace or (ScmWorkspace(self._scm)
                                     if self._scm else None)
     self._replace_targets(target_roots)
     self._invalidation_report = invalidation_report
Example #7
0
def all_roots(source_root_config: SourceRootConfig) -> AllSourceRoots:

    source_roots = source_root_config.get_source_roots()

    all_paths: Set[str] = set()
    for path in source_roots.traverse():
        if path.startswith("^/"):
            all_paths.add(f"{path[2:]}/")
        else:
            all_paths.add(f"**/{path}/")

    snapshot = yield Get(Snapshot, PathGlobs(include=tuple(all_paths)))

    all_source_roots: Set[SourceRoot] = set()

    # The globs above can match on subdirectories of the source roots.
    # For instance, `src/*/` might match 'src/rust/' as well as
    # 'src/rust/engine/process_execution/bazel_protos/src/gen'.
    # So we use find_by_path to verify every candidate source root.
    for directory in snapshot.dirs:
        match: SourceRoot = source_roots.find_by_path(directory)
        if match:
            all_source_roots.add(match)

    yield AllSourceRoots(all_source_roots)
Example #8
0
  def __init__(self, options, run_tracker, target_roots,
               requested_goals=None, target_base=None, build_graph=None,
               build_file_parser=None, build_configuration=None,
               address_mapper=None, console_outstream=None, scm=None,
               workspace=None, invalidation_report=None, scheduler=None):
    self._options = options

    # We register a callback that will cause build graph edits to invalidate our caches, and we hold
    # a handle directly to the callback function to ensure that it is not GC'd until the context is.
    self.build_graph = build_graph
    self._clear_target_cache_handle = self._clear_target_cache
    self._targets_cache = dict()
    self.build_graph.add_invalidation_callback(self._clear_target_cache_handle)

    self._build_file_parser = build_file_parser
    self.build_configuration = build_configuration
    self.address_mapper = address_mapper
    self.run_tracker = run_tracker
    self._log = run_tracker.logger
    self._target_base = target_base or Target
    self._products = Products()
    self._buildroot = get_buildroot()
    self._source_roots = SourceRootConfig.global_instance().get_source_roots()
    self._lock = OwnerPrintingInterProcessFileLock(os.path.join(self._buildroot, '.pants.workdir.file_lock'))
    self._java_sysprops = None  # Computed lazily.
    self.requested_goals = requested_goals or []
    self._console_outstream = console_outstream or sys.stdout.buffer
    self._scm = scm or get_scm()
    self._workspace = workspace or (ScmWorkspace(self._scm) if self._scm else None)
    self._replace_targets(target_roots)
    self._invalidation_report = invalidation_report
    self._scheduler = scheduler
Example #9
0
  def __init__(self, options, run_tracker, target_roots,
               requested_goals=None, target_base=None, build_graph=None,
               build_file_parser=None, address_mapper=None, console_outstream=None, scm=None,
               workspace=None, spec_excludes=None, invalidation_report=None):
    """
    :API: public
    """
    deprecated_conditional(lambda: spec_excludes is not None,
                           '0.0.75',
                           'Use address_mapper#build_ignore_patterns instead.')

    self._options = options
    self.build_graph = build_graph
    self.build_file_parser = build_file_parser
    self.address_mapper = address_mapper
    self.run_tracker = run_tracker
    self._log = self.Log(run_tracker)
    self._target_base = target_base or Target
    self._products = Products()
    self._buildroot = get_buildroot()
    self._source_roots = SourceRootConfig.global_instance().get_source_roots()
    self._lock = OwnerPrintingPIDLockFile(os.path.join(self._buildroot, '.pants.run'))
    self._java_sysprops = None  # Computed lazily.
    self.requested_goals = requested_goals or []
    self._console_outstream = console_outstream or sys.stdout
    self._scm = scm or get_scm()
    self._workspace = workspace or (ScmWorkspace(self._scm) if self._scm else None)
    self._spec_excludes = spec_excludes
    self._replace_targets(target_roots)
    self._invalidation_report = invalidation_report
 def create_python_awslambda(self, addr: str) -> Tuple[str, bytes]:
     lambdex_setup = self.request_single_product(
         LambdexSetup,
         Params(
             PythonSetup.global_instance(),
             PythonNativeCode.global_instance(),
             SubprocessEnvironment.global_instance(),
             Lambdex.global_instance(),
         ))
     target = self.request_single_product(HydratedTarget,
                                          Address.parse(addr))
     created_awslambda = self.request_single_product(
         CreatedAWSLambda,
         Params(
             target.adaptor,
             lambdex_setup,
             SourceRootConfig.global_instance(),
             PythonSetup.global_instance(),
             PythonNativeCode.global_instance(),
             SubprocessEnvironment.global_instance(),
         ))
     files_content = list(
         self.request_single_product(FilesContent,
                                     Params(created_awslambda.digest)))
     assert len(files_content) == 1
     return created_awslambda.name, files_content[0].content
Example #11
0
 def __init__(
     self,
     options,
     run_tracker,
     target_roots,
     requested_goals=None,
     target_base=None,
     build_graph=None,
     build_file_parser=None,
     address_mapper=None,
     console_outstream=None,
     scm=None,
     workspace=None,
     invalidation_report=None,
 ):
     self._options = options
     self.build_graph = build_graph
     self.build_file_parser = build_file_parser
     self.address_mapper = address_mapper
     self.run_tracker = run_tracker
     self._log = self.Log(run_tracker)
     self._target_base = target_base or Target
     self._products = Products()
     self._buildroot = get_buildroot()
     self._source_roots = SourceRootConfig.global_instance().get_source_roots()
     self._lock = OwnerPrintingInterProcessFileLock(os.path.join(self._buildroot, ".pants.workdir.file_lock"))
     self._java_sysprops = None  # Computed lazily.
     self.requested_goals = requested_goals or []
     self._console_outstream = console_outstream or sys.stdout
     self._scm = scm or get_scm()
     self._workspace = workspace or (ScmWorkspace(self._scm) if self._scm else None)
     self._replace_targets(target_roots)
     self._invalidation_report = invalidation_report
Example #12
0
 def source_root(self):
     """:returns: the source root for these sources, or None if they're not under a source root."""
     # TODO: It's a shame that we have to access the singleton directly here, instead of getting
     # the SourceRoots instance from context, as tasks do.  In the new engine we could inject
     # this into the target, rather than have it reach out for global singletons.
     return SourceRootConfig.global_instance().get_source_roots(
     ).find_by_path(self.rel_path)
Example #13
0
    def test_all_roots_with_root_at_buildroot(self):
        options = {
            "pants_ignore": [],
            "root_patterns": ["/"],
        }
        options.update(self.options[""])  # We need inherited values for pants_workdir etc.

        self.context(
            for_subsystems=[SourceRootConfig], options={SourceRootConfig.options_scope: options}
        )

        source_root_config = SourceRootConfig.global_instance()

        # This function mocks out reading real directories off the file system
        def provider_rule(path_globs: PathGlobs) -> Snapshot:
            dirs = ("foo",)  # A python package at the buildroot.
            return Snapshot(Digest("abcdef", 10), (), dirs)

        output = run_rule(
            list_roots.all_roots,
            rule_args=[source_root_config],
            mock_gets=[
                MockGet(product_type=Snapshot, subject_type=PathGlobs, mock=provider_rule),
                MockGet(
                    product_type=OptionalSourceRoot,
                    subject_type=SourceRootRequest,
                    mock=lambda req: OptionalSourceRoot(SourceRoot(".")),
                ),
            ],
        )

        self.assertEqual({SourceRoot(".")}, set(output))
Example #14
0
async def get_sources(request: SetupPySourcesRequest,
                      source_root_config: SourceRootConfig) -> SetupPySources:
    targets = request.hydrated_targets
    stripped_srcs_list = await MultiGet(
        Get[SourceRootStrippedSources](HydratedTarget, target)
        for target in targets)

    # Create a chroot with all the sources, and any ancestor __init__.py files that might be needed
    # for imports to work.  Note that if a repo has multiple exported targets under a single ancestor
    # package, then that package must be a namespace package, which in Python 3 means it must not
    # have an __init__.py. We don't validate this here, because it would require inspecting *all*
    # targets, whether or not they are in the target set for this run - basically the entire repo.
    # So it's the repo owners' responsibility to ensure __init__.py hygiene.
    stripped_srcs_digests = [
        stripped_sources.snapshot.directory_digest
        for stripped_sources in stripped_srcs_list
    ]
    ancestor_init_pys = await Get[AncestorInitPyFiles](HydratedTargets,
                                                       targets)
    sources_digest = await Get[Digest](DirectoriesToMerge(directories=tuple(
        [*stripped_srcs_digests, *ancestor_init_pys.digests])))
    init_pys_snapshot = await Get[Snapshot](SnapshotSubset(
        sources_digest, PathGlobs(['**/__init__.py'])))
    init_py_contents = await Get[FilesContent](
        Digest, init_pys_snapshot.directory_digest)

    packages, namespace_packages, package_data = find_packages(
        source_roots=source_root_config.get_source_roots(),
        tgts_and_stripped_srcs=list(zip(targets, stripped_srcs_list)),
        init_py_contents=init_py_contents,
        py2=request.py2)
    return SetupPySources(digest=sources_digest,
                          packages=packages,
                          namespace_packages=namespace_packages,
                          package_data=package_data)
Example #15
0
 def source_root(self):
     """:returns: the source root for these sources, or None if they're not under a source root."""
     # TODO: It's a shame that we have to access the singleton directly here, instead of getting
     # the SourceRoots instance from context, as tasks do.  In the new engine we could inject
     # this into the target, rather than have it reach out for global singletons.
     return SourceRootConfig.global_instance().get_source_roots(
     ).find_by_path(self.rel_path)
Example #16
0
  def test_collapse_source_root(self):
    self.context(for_subsystems=[SourceRootConfig], options={
      SourceRootConfig.options_scope: {
        'source_roots': {
          '/src/java': [],
          '/tests/java': [],
          '/some/other': []
        },
        'unmatched': 'fail'
      }
    })
    source_roots = SourceRootConfig.global_instance().get_source_roots()
    source_set_list = []
    self.assertEquals([], Project._collapse_by_source_root(source_roots, source_set_list))

    source_sets = [
      SourceSet('/repo-root', 'src/java', 'org/pantsbuild/app', False),
      SourceSet('/repo-root', 'tests/java', 'org/pantsbuild/app', True),
      SourceSet('/repo-root', 'some/other', 'path', False),
    ]

    results = Project._collapse_by_source_root(source_roots, source_sets)

    self.assertEquals(SourceSet('/repo-root', 'src/java', '', False), results[0])
    self.assertFalse(results[0].is_test)
    self.assertEquals(SourceSet('/repo-root', 'tests/java', '', True), results[1])
    self.assertTrue(results[1].is_test)
    # If there is no registered source root, the SourceSet should be returned unmodified
    self.assertEquals(source_sets[2], results[2])
    self.assertFalse(results[2].is_test)
Example #17
0
 def assert_chroot(self, expected_files, expected_setup_kwargs, addr):
     chroot = self.request_single_product(
         SetupPyChroot,
         Params(SetupPyChrootRequest(ExportedTarget(self.tgt(addr))),
                SourceRootConfig.global_instance()))
     snapshot = self.request_single_product(Snapshot, Params(chroot.digest))
     assert sorted(expected_files) == sorted(snapshot.files)
     kwargs = json.loads(chroot.setup_keywords_json)
     assert expected_setup_kwargs == kwargs
Example #18
0
 def assert_error(self, addr: str, exc_cls: Type[Exception]):
     with pytest.raises(ExecutionError) as excinfo:
         self.request_single_product(
             SetupPyChroot,
             Params(SetupPyChrootRequest(ExportedTarget(self.tgt(addr))),
                    SourceRootConfig.global_instance()))
     ex = excinfo.value
     assert len(ex.wrapped_exceptions) == 1
     assert type(ex.wrapped_exceptions[0]) == exc_cls
Example #19
0
 def target_base(self):
   """:returns: the source root path for this target."""
   # TODO: It's a shame that we have to access the singleton directly here, instead of getting
   # the SourceRoots instance from context, as tasks do.  In the new engine we could inject
   # this into the target, rather than have it reach out for global singletons.
   source_root = SourceRootConfig.global_instance().get_source_roots().find(self)
   if not source_root:
     raise TargetDefinitionException(self, 'Not under any configured source root.')
   return source_root.path
Example #20
0
async def create_coverage_config(
    coverage_config_request: CoverageConfigRequest, source_root_config: SourceRootConfig
) -> CoverageConfig:
    sources = await Get[SourceFiles](
        AllSourceFilesRequest(
            (tgt.get(Sources) for tgt in coverage_config_request.targets), strip_source_roots=False,
        )
    )
    init_injected = await Get[InitInjectedSnapshot](InjectInitRequest(sources.snapshot))
    source_roots = source_root_config.get_source_roots()

    # Generate a map from source root stripped source to its source root. eg:
    #  {'pants/testutil/subsystem/util.py': 'src/python'}. This is so that coverage reports
    #  referencing /chroot/path/pants/testutil/subsystem/util.py can be mapped back to the actual
    #  sources they reference when generating coverage reports.
    def stripped_file_with_source_root(file_name: str) -> Tuple[str, str]:
        source_root_object = source_roots.find_by_path(file_name)
        source_root = source_root_object.path if source_root_object is not None else ""
        stripped_path = file_name[len(source_root) + 1 :]
        return stripped_path, source_root

    stripped_files_to_source_roots = dict(
        stripped_file_with_source_root(filename)
        for filename in sorted(init_injected.snapshot.files)
    )

    default_config = dedent(
        """
        [run]
        branch = True
        timid = False
        relative_files = True
        """
    )

    config_parser = configparser.ConfigParser()
    config_parser.read_file(StringIO(default_config))
    config_parser.set("run", "plugins", COVERAGE_PLUGIN_MODULE_NAME)
    config_parser.add_section(COVERAGE_PLUGIN_MODULE_NAME)
    config_parser.set(
        COVERAGE_PLUGIN_MODULE_NAME,
        "source_to_target_base",
        json.dumps(stripped_files_to_source_roots),
    )
    config_parser.set(
        COVERAGE_PLUGIN_MODULE_NAME, "test_time", json.dumps(coverage_config_request.is_test_time)
    )

    config_io_stream = StringIO()
    config_parser.write(config_io_stream)
    digest = await Get[Digest](
        InputFilesContent(
            [FileContent(".coveragerc", content=config_io_stream.getvalue().encode())]
        )
    )
    return CoverageConfig(digest)
Example #21
0
 def target_base(self):
     """:returns: the source root path for this target."""
     # TODO: It's a shame that we have to access the singleton directly here, instead of getting
     # the SourceRoots instance from context, as tasks do.  In the new engine we could inject
     # this into the target, rather than have it reach out for global singletons.
     source_root = SourceRootConfig.global_instance().get_source_roots(
     ).find(self)
     if not source_root:
         raise TargetDefinitionException(
             self, 'Not under any configured source root.')
     return source_root.path
Example #22
0
 def assert_ancestor_init_py(self, expected_init_pys: Iterable[str],
                             addrs: Iterable[str]) -> None:
     ancestor_init_py_files = self.request_single_product(
         AncestorInitPyFiles,
         Params(HydratedTargets([self.tgt(addr) for addr in addrs]),
                SourceRootConfig.global_instance()))
     snapshots = [
         self.request_single_product(Snapshot, Params(digest))
         for digest in ancestor_init_py_files.digests
     ]
     init_py_files_found = set(
         [file for snapshot in snapshots for file in snapshot.files])
     # NB: Doesn't include the root __init__.py or the missing src/python/foo/bar/__init__.py.
     assert sorted(expected_init_pys) == sorted(init_py_files_found)
Example #23
0
    def test_all_roots(self):
        self.create_dir("contrib/go/examples/3rdparty/go")
        self.create_dir("contrib/go/examples/src/go/src")
        self.create_dir("src/java")
        self.create_dir("src/python")
        self.create_dir("src/kotlin")
        self.create_dir("src/example/java")
        self.create_dir("src/example/python")
        self.create_dir("my/project/src/java")
        self.create_dir("fixed/root/jvm")
        self.create_dir("not/a/srcroot/java")

        options = {
            "pants_ignore": [],
            "source_root_patterns": ["src/*", "src/example/*"],
            "source_roots": {
                # Fixed roots should trump patterns which would detect contrib/go/examples/src/go here.
                "contrib/go/examples/src/go/src": ["go"],
                # Dir does not exist, should not be listed as a root.
                "java": ["java"],
            },
        }
        options.update(self.options[""]
                       )  # We need inherited values for pants_workdir etc.

        self.context(for_subsystems=[SourceRootConfig],
                     options={SourceRootConfig.options_scope: options})
        source_roots = SourceRootConfig.global_instance().get_source_roots()
        # Ensure that we see any manually added roots.
        source_roots.add_source_root("fixed/root/jvm", ("java", "scala"), TEST)
        source_roots.all_roots()

        self.assertEqual(
            {
                SourceRoot("contrib/go/examples/3rdparty/go",
                           ("go", ), THIRDPARTY),
                SourceRoot("contrib/go/examples/src/go/src", ("go", ), SOURCE),
                SourceRoot("src/java", ("java", ), SOURCE),
                SourceRoot("src/python", ("python", ), SOURCE),
                SourceRoot("src/kotlin", ("kotlin", ), SOURCE),
                SourceRoot("src/example/java", ("java", ), SOURCE),
                SourceRoot("src/example/python", ("python", ), SOURCE),
                SourceRoot("my/project/src/java", ("java", ), SOURCE),
                SourceRoot("fixed/root/jvm", ("java", "scala"), TEST),
            },
            set(source_roots.all_roots()),
        )
Example #24
0
async def strip_source_roots_from_snapshot(
    request: StripSnapshotRequest,
    source_root_config: SourceRootConfig,
) -> SourceRootStrippedSources:
    """Removes source roots from a snapshot, e.g. `src/python/pants/util/strutil.py` ->
    `pants/util/strutil.py`."""
    if not request.snapshot.files:
        return SourceRootStrippedSources(request.snapshot)

    source_roots_object = source_root_config.get_source_roots()

    def determine_source_root(path: str) -> str:
        return cast(str, source_roots_object.strict_find_by_path(path).path)

    if request.representative_path is not None:
        source_root = determine_source_root(request.representative_path)
        if source_root == ".":
            return SourceRootStrippedSources(request.snapshot)
        resulting_snapshot = await Get[Snapshot](RemovePrefix(
            request.snapshot.digest, source_root))
        return SourceRootStrippedSources(resulting_snapshot)

    files_grouped_by_source_root = {
        source_root: tuple(files)
        for source_root, files in itertools.groupby(request.snapshot.files,
                                                    key=determine_source_root)
    }

    if len(files_grouped_by_source_root) == 1:
        source_root = next(iter(files_grouped_by_source_root.keys()))
        if source_root == ".":
            return SourceRootStrippedSources(request.snapshot)
        resulting_snapshot = await Get[Snapshot](RemovePrefix(
            request.snapshot.digest, source_root))
        return SourceRootStrippedSources(resulting_snapshot)

    snapshot_subsets = await MultiGet(
        Get[Snapshot](SnapshotSubset(request.snapshot.digest, PathGlobs(
            files))) for files in files_grouped_by_source_root.values())
    resulting_digests = await MultiGet(
        Get[Digest](RemovePrefix(snapshot.digest, source_root))
        for snapshot, source_root in zip(snapshot_subsets,
                                         files_grouped_by_source_root.keys()))

    resulting_snapshot = await Get[Snapshot](MergeDigests(resulting_digests))
    return SourceRootStrippedSources(resulting_snapshot)
Example #25
0
    def test_all_roots(self):
        self.create_dir('contrib/go/examples/3rdparty/go')
        self.create_dir('contrib/go/examples/src/go/src')
        self.create_dir('src/java')
        self.create_dir('src/python')
        self.create_dir('src/kotlin')
        self.create_dir('src/example/java')
        self.create_dir('src/example/python')
        self.create_dir('my/project/src/java')
        self.create_dir('fixed/root/jvm')
        self.create_dir('not/a/srcroot/java')

        options = {
            'pants_ignore': [],
            'source_root_patterns': ['src/*', 'src/example/*'],
            'source_roots': {
                # Fixed roots should trump patterns which would detect contrib/go/examples/src/go here.
                'contrib/go/examples/src/go/src': ['go'],

                # Dir does not exist, should not be listed as a root.
                'java': ['java']
            }
        }
        options.update(self.options['']
                       )  # We need inherited values for pants_workdir etc.

        self.context(for_subsystems=[SourceRootConfig],
                     options={SourceRootConfig.options_scope: options})
        source_roots = SourceRootConfig.global_instance().get_source_roots()
        # Ensure that we see any manually added roots.
        source_roots.add_source_root('fixed/root/jvm', ('java', 'scala'), TEST)
        source_roots.all_roots()

        self.assertEqual(
            {
                SourceRoot('contrib/go/examples/3rdparty/go',
                           ('go', ), THIRDPARTY),
                SourceRoot('contrib/go/examples/src/go/src', ('go', ), SOURCE),
                SourceRoot('src/java', ('java', ), SOURCE),
                SourceRoot('src/python', ('python', ), SOURCE),
                SourceRoot('src/kotlin', ('kotlin', ), SOURCE),
                SourceRoot('src/example/java', ('java', ), SOURCE),
                SourceRoot('src/example/python', ('python', ), SOURCE),
                SourceRoot('my/project/src/java', ('java', ), SOURCE),
                SourceRoot('fixed/root/jvm', ('java', 'scala'), TEST)
            }, set(source_roots.all_roots()))
Example #26
0
async def strip_source_roots_from_snapshot(
    request: StripSnapshotRequest,
    source_root_config: SourceRootConfig,
) -> SourceRootStrippedSources:
    """Removes source roots from a snapshot, e.g. `src/python/pants/util/strutil.py` ->
    `pants/util/strutil.py`."""
    source_roots_object = source_root_config.get_source_roots()

    def determine_source_root(path: str) -> str:
        source_root = source_roots_object.safe_find_by_path(path)
        if source_root is not None:
            return cast(str, source_root.path)
        if source_root_config.options.unmatched == "fail":
            raise NoSourceRootError(
                f"Could not find a source root for `{path}`.")
        # Otherwise, create a source root by using the parent directory.
        return PurePath(path).parent.as_posix()

    if request.representative_path is not None:
        resulting_digest = await Get[Digest](DirectoryWithPrefixToStrip(
            directory_digest=request.snapshot.directory_digest,
            prefix=determine_source_root(request.representative_path),
        ))
        resulting_snapshot = await Get[Snapshot](Digest, resulting_digest)
        return SourceRootStrippedSources(snapshot=resulting_snapshot)

    files_grouped_by_source_root = {
        source_root: tuple(files)
        for source_root, files in itertools.groupby(request.snapshot.files,
                                                    key=determine_source_root)
    }
    snapshot_subsets = await MultiGet(Get[Snapshot](SnapshotSubset(
        directory_digest=request.snapshot.directory_digest,
        globs=PathGlobs(files),
    )) for files in files_grouped_by_source_root.values())
    resulting_digests = await MultiGet(
        Get[Digest](DirectoryWithPrefixToStrip(
            directory_digest=snapshot.directory_digest, prefix=source_root))
        for snapshot, source_root in zip(snapshot_subsets,
                                         files_grouped_by_source_root.keys()))

    merged_result = await Get[Digest](DirectoriesToMerge(resulting_digests))
    resulting_snapshot = await Get[Snapshot](Digest, merged_result)
    return SourceRootStrippedSources(resulting_snapshot)
 def assert_stripped_source_file(self,
                                 *,
                                 original_path: str,
                                 expected_path: str,
                                 target_type_alias=None):
     init_subsystem(SourceRootConfig)
     adaptor = Mock()
     adaptor.sources = Mock()
     source_files = {original_path: "print('random python')"}
     adaptor.sources.snapshot = self.make_snapshot(source_files)
     adaptor.address = Mock()
     adaptor.address.spec_path = original_path
     if target_type_alias:
         adaptor.type_alias = target_type_alias
     target = HydratedTarget('some/target/address', adaptor, tuple())
     stripped_sources = self.request_single_product(
         SourceRootStrippedSources,
         Params(target, SourceRootConfig.global_instance()))
     self.assertEqual(stripped_sources.snapshot.files, (expected_path, ))
Example #28
0
    def __init__(self,
                 options,
                 run_tracker,
                 target_roots,
                 requested_goals=None,
                 target_base=None,
                 build_graph=None,
                 build_file_parser=None,
                 address_mapper=None,
                 console_outstream=None,
                 scm=None,
                 workspace=None,
                 spec_excludes=None,
                 invalidation_report=None):
        """
    :API: public
    """
        deprecated_conditional(
            lambda: spec_excludes is not None, '0.0.75',
            'Use address_mapper#build_ignore_patterns instead.')

        self._options = options
        self.build_graph = build_graph
        self.build_file_parser = build_file_parser
        self.address_mapper = address_mapper
        self.run_tracker = run_tracker
        self._log = self.Log(run_tracker)
        self._target_base = target_base or Target
        self._products = Products()
        self._buildroot = get_buildroot()
        self._source_roots = SourceRootConfig.global_instance(
        ).get_source_roots()
        self._lock = OwnerPrintingPIDLockFile(
            os.path.join(self._buildroot, '.pants.run'))
        self._java_sysprops = None  # Computed lazily.
        self.requested_goals = requested_goals or []
        self._console_outstream = console_outstream or sys.stdout
        self._scm = scm or get_scm()
        self._workspace = workspace or (ScmWorkspace(self._scm)
                                        if self._scm else None)
        self._spec_excludes = spec_excludes
        self._replace_targets(target_roots)
        self._invalidation_report = invalidation_report
Example #29
0
async def get_ancestor_init_py(
    targets: Targets, source_root_config: SourceRootConfig
) -> AncestorInitPyFiles:
    """Find any ancestor __init__.py files for the given targets.

    Includes sibling __init__.py files. Returns the files stripped of their source roots.
    """
    source_roots = source_root_config.get_source_roots()
    sources = await Get[SourceFiles](
        AllSourceFilesRequest(tgt[PythonSources] for tgt in targets if tgt.has_field(PythonSources))
    )
    # Find the ancestors of all dirs containing .py files, including those dirs themselves.
    source_dir_ancestors: Set[Tuple[str, str]] = set()  # Items are (src_root, path incl. src_root).
    for fp in sources.snapshot.files:
        source_dir_ancestor = os.path.dirname(fp)
        source_root = source_root_or_raise(source_roots, fp)
        # Do not allow the repository root to leak (i.e., '.' should not be a package in setup.py).
        while source_dir_ancestor != source_root:
            source_dir_ancestors.add((source_root, source_dir_ancestor))
            source_dir_ancestor = os.path.dirname(source_dir_ancestor)

    source_dir_ancestors_list = list(source_dir_ancestors)  # To force a consistent order.

    # Note that we must MultiGet single globs instead of a a single Get for all the globs, because
    # we match each result to its originating glob (see use of zip below).
    ancestor_init_py_snapshots = await MultiGet[Snapshot](
        Get[Snapshot](PathGlobs, PathGlobs([os.path.join(source_dir_ancestor[1], "__init__.py")]))
        for source_dir_ancestor in source_dir_ancestors_list
    )

    source_root_stripped_ancestor_init_pys = await MultiGet[Digest](
        Get[Digest](
            DirectoryWithPrefixToStrip(
                directory_digest=snapshot.directory_digest, prefix=source_dir_ancestor[0]
            )
        )
        for snapshot, source_dir_ancestor in zip(
            ancestor_init_py_snapshots, source_dir_ancestors_list
        )
    )

    return AncestorInitPyFiles(source_root_stripped_ancestor_init_pys)
Example #30
0
  def test_all_roots(self):
    self.create_dir('contrib/go/examples/3rdparty/go')
    self.create_dir('contrib/go/examples/src/go/src')
    self.create_dir('src/java')
    self.create_dir('src/python')
    self.create_dir('src/example/java')
    self.create_dir('src/example/python')
    self.create_dir('my/project/src/java')
    self.create_dir('fixed/root/jvm')
    self.create_dir('not/a/srcroot/java')

    options = {
      'build_file_rev': None,
      'pants_ignore': [],

      'source_root_patterns': ['src/*', 'src/example/*'],
      'source_roots': {
        # Fixed roots should trump patterns which would detect contrib/go/examples/src/go here.
        'contrib/go/examples/src/go/src': ['go'],

        # Dir does not exist, should not be listed as a root.
        'java': ['java']}
    }
    options.update(self.options[''])  # We need inherited values for pants_workdir etc.

    self.context(for_subsystems=[SourceRootConfig], options={
      SourceRootConfig.options_scope: options
    })
    source_roots = SourceRootConfig.global_instance().get_source_roots()
    # Ensure that we see any manually added roots.
    source_roots.add_source_root('fixed/root/jvm', ('java', 'scala'), TEST)
    source_roots.all_roots()

    self.assertEquals({SourceRoot('contrib/go/examples/3rdparty/go', ('go',), THIRDPARTY),
                       SourceRoot('contrib/go/examples/src/go/src', ('go',), SOURCE),
                       SourceRoot('src/java', ('java',), SOURCE),
                       SourceRoot('src/python', ('python',), SOURCE),
                       SourceRoot('src/example/java', ('java',), SOURCE),
                       SourceRoot('src/example/python', ('python',), SOURCE),
                       SourceRoot('my/project/src/java', ('java',), SOURCE),
                       SourceRoot('fixed/root/jvm', ('java','scala'), TEST)},
                      set(source_roots.all_roots()))
Example #31
0
async def construct_coverage_config(
        source_root_config: SourceRootConfig,
        coverage_config_request: CoveragercRequest) -> Coveragerc:
    sources = await Get[SourceFiles](AllSourceFilesRequest(
        (ht.adaptor for ht in coverage_config_request.hydrated_targets),
        strip_source_roots=False,
    ))
    init_injected = await Get[InitInjectedSnapshot](InjectInitRequest(
        sources.snapshot))
    source_roots = source_root_config.get_source_roots()

    # Generate a map from source root stripped source to its source root. eg:
    #  {'pants/testutil/subsystem/util.py': 'src/python'}
    # This is so coverage reports referencing /chroot/path/pants/testutil/subsystem/util.py can be mapped
    # back to the actual sources they reference when generating coverage reports.
    def source_root_stripped_source_and_source_root(
            file_name: str) -> Tuple[str, str]:
        source_root = source_roots.find_by_path(file_name)
        source_root_path = source_root.path if source_root is not None else ""
        source_root_stripped_path = file_name[len(source_root_path) + 1:]
        return (source_root_stripped_path, source_root_path)

    source_to_target_base = dict(
        source_root_stripped_source_and_source_root(filename)
        for filename in sorted(init_injected.snapshot.files))
    config_parser = configparser.ConfigParser()
    config_parser.read_file(StringIO(DEFAULT_COVERAGE_CONFIG))
    ensure_section(config_parser, "run")
    config_parser.set("run", "plugins", COVERAGE_PLUGIN_MODULE_NAME)
    config_parser.add_section(COVERAGE_PLUGIN_MODULE_NAME)
    config_parser.set(COVERAGE_PLUGIN_MODULE_NAME, "source_to_target_base",
                      json.dumps(source_to_target_base))
    config_parser.set(COVERAGE_PLUGIN_MODULE_NAME, "test_time",
                      json.dumps(coverage_config_request.test_time))
    config = StringIO()
    config_parser.write(config)
    coveragerc_digest = await Get[Digest](InputFilesContent,
                                          get_coveragerc_input(
                                              config.getvalue()))
    return Coveragerc(coveragerc_digest)
Example #32
0
async def all_roots(source_root_config: SourceRootConfig) -> AllSourceRoots:
    source_root_pattern_matcher = source_root_config.get_pattern_matcher()

    # Create globs corresponding to all source root patterns.
    all_paths: Set[str] = set()
    for path in source_root_pattern_matcher.get_patterns():
        if path == "/":
            all_paths.add("**")
        elif path.startswith("/"):
            all_paths.add(f"{path[1:]}/")
        else:
            all_paths.add(f"**/{path}/")

    # Match the patterns against actual files, to find the roots that actually exist.
    snapshot = await Get[Snapshot](PathGlobs(globs=sorted(all_paths)))
    responses = await MultiGet(
        Get[OptionalSourceRoot](SourceRootRequest(PurePath(d))) for d in snapshot.dirs
    )
    all_source_roots = {
        response.source_root for response in responses if response.source_root is not None
    }
    return AllSourceRoots(all_source_roots)
Example #33
0
async def list_backends(
    backend_options: BackendsOptions,
    source_roots_config: SourceRootConfig,
    global_options: GlobalOptions,
    console: Console,
) -> Backends:
    source_roots = source_roots_config.get_source_roots()
    discovered_register_pys = await Get[Snapshot](PathGlobs(
        ["**/*/register.py"]))
    register_pys_content = await Get[FilesContent](
        Digest, discovered_register_pys.digest)

    backend_infos = tuple(
        BackendInfo.create(fc, source_roots, global_options)
        for fc in register_pys_content)
    v1_backends = []
    v2_backends = []
    for backend in backend_infos:
        if backend.is_v1:
            v1_backends.append(backend)
        if backend.is_v2:
            v2_backends.append(backend)

    with backend_options.line_oriented(console) as print_stdout:
        if global_options.options.v1:
            print_stdout(
                format_section(v1_backends,
                               console,
                               version_number=1,
                               option_name="backend_packages"))
        if global_options.options.v2:
            print_stdout(
                format_section(v2_backends,
                               console,
                               version_number=2,
                               option_name="backend_packages2"))
    return Backends(exit_code=0)
Example #34
0
    def test_all_roots(self):

        dirs = (
            "contrib/go/examples/src/go/src",
            "src/java",
            "src/python",
            "src/python/subdir/src/python",  # We allow source roots under source roots.
            "src/kotlin",
            "my/project/src/java",
            "src/example/java",
            "src/example/python",
            "fixed/root/jvm",
        )

        options = {
            "pants_ignore": [],
            "root_patterns": [
                "src/*",
                "src/example/*",
                "contrib/go/examples/src/go/src",
                # Dir does not exist, should not be listed as a root.
                "java",
                "fixed/root/jvm",
            ],
        }
        options.update(self.options[""])  # We need inherited values for pants_workdir etc.

        self.context(
            for_subsystems=[SourceRootConfig], options={SourceRootConfig.options_scope: options}
        )

        source_root_config = SourceRootConfig.global_instance()

        # This function mocks out reading real directories off the file system.
        def provider_rule(path_globs: PathGlobs) -> Snapshot:
            return Snapshot(Digest("abcdef", 10), (), dirs)

        def source_root_mock_rule(req: SourceRootRequest) -> OptionalSourceRoot:
            for d in dirs:
                if str(req.path).startswith(d):
                    return OptionalSourceRoot(SourceRoot(str(req.path)))
            return OptionalSourceRoot(None)

        output = run_rule(
            list_roots.all_roots,
            rule_args=[source_root_config],
            mock_gets=[
                MockGet(product_type=Snapshot, subject_type=PathGlobs, mock=provider_rule),
                MockGet(
                    product_type=OptionalSourceRoot,
                    subject_type=SourceRootRequest,
                    mock=source_root_mock_rule,
                ),
            ],
        )

        self.assertEqual(
            {
                SourceRoot("contrib/go/examples/src/go/src"),
                SourceRoot("src/java"),
                SourceRoot("src/python"),
                SourceRoot("src/python/subdir/src/python"),
                SourceRoot("src/kotlin"),
                SourceRoot("src/example/java"),
                SourceRoot("src/example/python"),
                SourceRoot("my/project/src/java"),
                SourceRoot("fixed/root/jvm"),
            },
            set(output),
        )
Example #35
0
    def test_all_roots(self):
        SOURCE = SourceRootCategories.SOURCE
        TEST = SourceRootCategories.TEST
        THIRDPARTY = SourceRootCategories.THIRDPARTY

        options = {
            'pants_ignore': [],
            'source_root_patterns': ['src/*', 'src/example/*'],
            'source_roots': {
                # Fixed roots should trump patterns which would detect contrib/go/examples/src/go here.
                'contrib/go/examples/src/go/src': ['go'],

                # Dir does not exist, should not be listed as a root.
                'java': ['java']
            }
        }
        options.update(self.options['']
                       )  # We need inherited values for pants_workdir etc.

        self.context(for_subsystems=[SourceRootConfig],
                     options={SourceRootConfig.options_scope: options})

        source_root_config = SourceRootConfig.global_instance()
        source_roots = source_root_config.get_source_roots()

        # Ensure that we see any manually added roots.
        source_roots.add_source_root('fixed/root/jvm', ('java', 'scala'), TEST)

        # This function mocks out reading real directories off the file system
        def provider_rule(path_globs: PathGlobs) -> Snapshot:
            dirs = (
                'contrib/go/examples/3rdparty/go',
                'contrib/go/examples/src/go/src',
                'src/java',
                'src/python',
                'src/kotlin',
                'my/project/src/java',
                'src/example/java',
                'src/example/python',
                'fixed/root/jvm',
                # subdirectories of source roots should not show up in final output
                'src/kotlin/additional/directories/that/might/get/matched/src/foo',
            )
            return Snapshot(Digest('abcdef', 10), (), dirs)

        output = run_rule(list_roots.all_roots, source_root_config,
                          {(Snapshot, PathGlobs): provider_rule})

        self.assertEqual(
            {
                SourceRoot('contrib/go/examples/3rdparty/go',
                           ('go', ), THIRDPARTY),
                SourceRoot('contrib/go/examples/src/go/src', ('go', ), SOURCE),
                SourceRoot('src/java', ('java', ), SOURCE),
                SourceRoot('src/python', ('python', ), SOURCE),
                SourceRoot('src/kotlin', ('kotlin', ), SOURCE),
                SourceRoot('src/example/java', ('java', ), SOURCE),
                SourceRoot('src/example/python', ('python', ), SOURCE),
                SourceRoot('my/project/src/java', ('java', ), SOURCE),
                SourceRoot('fixed/root/jvm', ('java', 'scala'), TEST)
            }, set(output))
Example #36
0
    def test_all_roots(self):
        SOURCE = SourceRootCategories.SOURCE
        TEST = SourceRootCategories.TEST
        THIRDPARTY = SourceRootCategories.THIRDPARTY

        options = {
            "pants_ignore": [],
            "source_root_patterns": ["src/*", "src/example/*"],
            "source_roots": {
                # Fixed roots should trump patterns which would detect contrib/go/examples/src/go here.
                "contrib/go/examples/src/go/src": ["go"],
                # Dir does not exist, should not be listed as a root.
                "java": ["java"],
            },
        }
        options.update(self.options[""]
                       )  # We need inherited values for pants_workdir etc.

        self.context(for_subsystems=[SourceRootConfig],
                     options={SourceRootConfig.options_scope: options})

        source_root_config = SourceRootConfig.global_instance()
        source_roots = source_root_config.get_source_roots()

        # Ensure that we see any manually added roots.
        source_roots.add_source_root("fixed/root/jvm", ("java", "scala"), TEST)

        # This function mocks out reading real directories off the file system
        def provider_rule(path_globs: PathGlobs) -> Snapshot:
            dirs = (
                "contrib/go/examples/3rdparty/go",
                "contrib/go/examples/src/go/src",
                "src/java",
                "src/python",
                "src/kotlin",
                "my/project/src/java",
                "src/example/java",
                "src/example/python",
                "fixed/root/jvm",
                # subdirectories of source roots should not show up in final output
                "src/kotlin/additional/directories/that/might/get/matched/src/foo",
            )
            return Snapshot(Digest("abcdef", 10), (), dirs)

        output = run_rule(
            list_roots.all_roots,
            rule_args=[source_root_config],
            mock_gets=[
                MockGet(product_type=Snapshot,
                        subject_type=PathGlobs,
                        mock=provider_rule)
            ],
        )

        self.assertEqual(
            {
                SourceRoot("contrib/go/examples/3rdparty/go",
                           ("go", ), THIRDPARTY),
                SourceRoot("contrib/go/examples/src/go/src", ("go", ), SOURCE),
                SourceRoot("src/java", ("java", ), SOURCE),
                SourceRoot("src/python", ("python", ), SOURCE),
                SourceRoot("src/kotlin", ("kotlin", ), SOURCE),
                SourceRoot("src/example/java", ("java", ), SOURCE),
                SourceRoot("src/example/python", ("python", ), SOURCE),
                SourceRoot("my/project/src/java", ("java", ), SOURCE),
                SourceRoot("fixed/root/jvm", ("java", "scala"), TEST),
            },
            set(output),
        )