async def determine_go_mod_info(request: GoModInfoRequest, ) -> GoModInfo: if isinstance(request.source, Address): wrapped_target = await Get( WrappedTarget, WrappedTargetRequest(request.source, description_of_origin="<go mod info rule>"), ) sources_field = wrapped_target.target[GoModSourcesField] else: sources_field = request.source go_mod_path = sources_field.go_mod_path go_mod_dir = os.path.dirname(go_mod_path) # Get the `go.mod` (and `go.sum`) and strip so the file has no directory prefix. hydrated_sources = await Get(HydratedSources, HydrateSourcesRequest(sources_field)) sources_digest = hydrated_sources.snapshot.digest mod_json = await Get( ProcessResult, GoSdkProcess( command=("mod", "edit", "-json"), input_digest=sources_digest, working_dir=go_mod_dir, description=f"Parse {go_mod_path}", ), ) module_metadata = json.loads(mod_json.stdout) return GoModInfo( import_path=module_metadata["Module"]["Path"], digest=sources_digest, mod_path=go_mod_path, minimum_go_version=module_metadata.get("Go"), )
async def find_apache_thrift_python_requirement( request: InjectApacheThriftPythonDependencies, thrift_python: ThriftPythonSubsystem, python_setup: PythonSetup, # TODO(#12946): Make this a lazy Get once possible. module_mapping: ThirdPartyPythonModuleMapping, ) -> InjectedDependencies: if not thrift_python.infer_runtime_dependency: return InjectedDependencies() wrapped_tgt = await Get( WrappedTarget, WrappedTargetRequest( request.dependencies_field.address, description_of_origin="<infallible>" ), ) resolve = wrapped_tgt.target.get(PythonResolveField).normalized_value(python_setup) addr = find_python_runtime_library_or_raise_error( module_mapping, request.dependencies_field.address, "thrift", resolve=resolve, resolves_enabled=python_setup.enable_resolves, recommended_requirement_name="thrift", recommended_requirement_url="https://pypi.org/project/thrift/", disable_inference_option=f"[{thrift_python.options_scope}].infer_runtime_dependency", ) return InjectedDependencies([addr])
async def run( run_subsystem: RunSubsystem, global_options: GlobalOptions, workspace: Workspace, build_root: BuildRoot, complete_env: CompleteEnvironment, ) -> Run: targets_to_valid_field_sets = await Get( TargetRootsToFieldSets, TargetRootsToFieldSetsRequest( RunFieldSet, goal_description="the `run` goal", no_applicable_targets_behavior=NoApplicableTargetsBehavior.error, expect_single_field_set=True, ), ) field_set = targets_to_valid_field_sets.field_sets[0] request = await Get(RunRequest, RunFieldSet, field_set) wrapped_target = await Get( WrappedTarget, WrappedTargetRequest(field_set.address, description_of_origin="<infallible>")) restartable = wrapped_target.target.get(RestartableField).value # Cleanup is the default, so we want to preserve the chroot if either option is off. cleanup = run_subsystem.cleanup and global_options.process_cleanup with temporary_dir(root_dir=global_options.pants_workdir, cleanup=cleanup) as tmpdir: if not cleanup: logger.info(f"Preserving running binary chroot {tmpdir}") workspace.write_digest( request.digest, path_prefix=PurePath(tmpdir).relative_to( build_root.path).as_posix(), # We don't want to influence whether the InteractiveProcess is able to restart. Because # we're writing into a temp directory, we can safely mark this side_effecting=False. side_effecting=False, ) args = (arg.format(chroot=tmpdir) for arg in request.args) env = { **complete_env, **{ k: v.format(chroot=tmpdir) for k, v in request.extra_env.items() } } result = await Effect( InteractiveProcessResult, InteractiveProcess( argv=(*args, *run_subsystem.args), env=env, run_in_workspace=True, restartable=restartable, ), ) exit_code = result.exit_code return Run(exit_code)
async def resolve_unexpanded_targets( addresses: Addresses) -> UnexpandedTargets: wrapped_targets = await MultiGet( Get(WrappedTarget, WrappedTargetRequest(a, description_of_origin="TODO(#14468)")) for a in addresses) return UnexpandedTargets(wrapped_target.target for wrapped_target in wrapped_targets)
async def parse_dockerfile(request: DockerfileInfoRequest) -> DockerfileInfo: wrapped_target = await Get( WrappedTarget, WrappedTargetRequest(request.address, description_of_origin="<infallible>")) target = wrapped_target.target sources = await Get( HydratedSources, HydrateSourcesRequest( target.get(SourcesField), for_sources_types=(DockerImageSourceField, ), enable_codegen=True, ), ) dockerfiles = sources.snapshot.files assert len(dockerfiles) == 1, ( f"Internal error: Expected a single source file to Dockerfile parse request {request}, " f"got: {dockerfiles}.") result = await Get( ProcessResult, DockerfileParseRequest( sources.snapshot.digest, dockerfiles, ), ) try: raw_output = result.stdout.decode("utf-8") outputs = json.loads(raw_output) assert len(outputs) == len(dockerfiles) except Exception as e: raise DockerfileInfoError( f"Unexpected failure to parse Dockerfiles: {', '.join(dockerfiles)}, " f"for the {request.address} target: {e}") from e info = outputs[0] try: return DockerfileInfo( address=request.address, digest=sources.snapshot.digest, source=info["source"], build_args=DockerBuildArgs.from_strings( *info["build_args"], duplicates_must_match=True), copy_source_paths=tuple(info["copy_source_paths"]), from_image_build_args=DockerBuildArgs.from_strings( *info["from_image_build_args"], duplicates_must_match=True), version_tags=tuple(info["version_tags"]), ) except ValueError as e: raise DockerfileInfoError( f"Error while parsing {info['source']} for the {request.address} target: {e}" ) from e
async def inject_pex_binary_entry_point_dependency( request: InjectPexBinaryEntryPointDependency, python_infer_subsystem: PythonInferSubsystem, python_setup: PythonSetup, ) -> InjectedDependencies: if not python_infer_subsystem.entry_points: return InjectedDependencies() original_tgt = await Get( WrappedTarget, WrappedTargetRequest( request.dependencies_field.address, description_of_origin="<infallible>" ), ) entry_point_field = original_tgt.target.get(PexEntryPointField) if entry_point_field.value is None: return InjectedDependencies() explicitly_provided_deps, entry_point = await MultiGet( Get(ExplicitlyProvidedDependencies, DependenciesRequest(original_tgt.target[Dependencies])), Get(ResolvedPexEntryPoint, ResolvePexEntryPointRequest(entry_point_field)), ) if entry_point.val is None: return InjectedDependencies() owners = await Get( PythonModuleOwners, PythonModuleOwnersRequest( entry_point.val.module, resolve=original_tgt.target[PythonResolveField].normalized_value(python_setup), ), ) address = original_tgt.target.address explicitly_provided_deps.maybe_warn_of_ambiguous_dependency_inference( owners.ambiguous, address, # If the entry point was specified as a file, like `app.py`, we know the module must # live in the pex_binary's directory or subdirectory, so the owners must be ancestors. owners_must_be_ancestors=entry_point.file_name_used, import_reference="module", context=softwrap( f""" The pex_binary target {address} has the field `entry_point={repr(entry_point_field.value.spec)}`, which maps to the Python module `{entry_point.val.module}` """ ), ) maybe_disambiguated = explicitly_provided_deps.disambiguated( owners.ambiguous, owners_must_be_ancestors=entry_point.file_name_used ) unambiguous_owners = owners.unambiguous or ( (maybe_disambiguated,) if maybe_disambiguated else () ) return InjectedDependencies(unambiguous_owners)
async def isolate_local_dist_wheels( dist_field_set: PythonDistributionFieldSet, bash: BashBinary, unzip_binary: UnzipBinary, ) -> LocalDistWheels: dist = await Get(BuiltPackage, PackageFieldSet, dist_field_set) wheels_snapshot = await Get(Snapshot, DigestSubset(dist.digest, PathGlobs(["**/*.whl"]))) # A given local dist might build a wheel and an sdist (and maybe other artifacts - # we don't know what setup command was run...) # As long as there is a wheel, we can ignore the other artifacts. artifacts = {(a.relpath or "") for a in dist.artifacts} wheels = [wheel for wheel in wheels_snapshot.files if wheel in artifacts] if not wheels: tgt = await Get( WrappedTarget, WrappedTargetRequest(dist_field_set.address, description_of_origin="<infallible>"), ) logger.warning( softwrap( f""" Encountered a dependency on the {tgt.target.alias} target at {dist_field_set.address}, but this target does not produce a Python wheel artifact. Therefore this target's code will be used directly from sources, without a distribution being built, and any native extensions in it will not be built. See {doc_url('python-distributions')} for details on how to set up a {tgt.target.alias} target to produce a wheel. """ ) ) wheels_listing_result = await Get( ProcessResult, Process( argv=[ bash.path, "-c", f""" set -ex for f in {' '.join(shlex.quote(f) for f in wheels)}; do {unzip_binary.path} -Z1 "$f" done """, ], input_digest=wheels_snapshot.digest, description=f"List contents of artifacts produced by {dist_field_set.address}", ), ) provided_files = set(wheels_listing_result.stdout.decode().splitlines()) return LocalDistWheels(tuple(wheels), wheels_snapshot.digest, frozenset(provided_files))
async def inject_lambda_handler_dependency( request: InjectPythonLambdaHandlerDependency, python_infer_subsystem: PythonInferSubsystem, python_setup: PythonSetup, ) -> InjectedDependencies: if not python_infer_subsystem.entry_points: return InjectedDependencies() original_tgt = await Get( WrappedTarget, WrappedTargetRequest( request.dependencies_field.address, description_of_origin="<infallible>" ), ) explicitly_provided_deps, handler = await MultiGet( Get(ExplicitlyProvidedDependencies, DependenciesRequest(original_tgt.target[Dependencies])), Get( ResolvedPythonAwsHandler, ResolvePythonAwsHandlerRequest(original_tgt.target[PythonAwsLambdaHandlerField]), ), ) module, _, _func = handler.val.partition(":") owners = await Get( PythonModuleOwners, PythonModuleOwnersRequest( module, resolve=original_tgt.target[PythonResolveField].normalized_value(python_setup) ), ) address = original_tgt.target.address explicitly_provided_deps.maybe_warn_of_ambiguous_dependency_inference( owners.ambiguous, address, # If the handler was specified as a file, like `app.py`, we know the module must # live in the python_awslambda's directory or subdirectory, so the owners must be ancestors. owners_must_be_ancestors=handler.file_name_used, import_reference="module", context=softwrap( f""" The python_awslambda target {address} has the field `handler={repr(original_tgt.target[PythonAwsLambdaHandlerField].value)}`, which maps to the Python module `{module}`" """ ), ) maybe_disambiguated = explicitly_provided_deps.disambiguated( owners.ambiguous, owners_must_be_ancestors=handler.file_name_used ) unambiguous_owners = owners.unambiguous or ( (maybe_disambiguated,) if maybe_disambiguated else () ) return InjectedDependencies(unambiguous_owners)
def get_target(self, address: Address) -> Target: """Find the target for a given address. This requires that the target actually exists, i.e. that you set up its BUILD file. :API: public """ return self.request( WrappedTarget, [ WrappedTargetRequest( address, description_of_origin="RuleRunner.get_target()") ], ).target
async def inject_go_binary_main_dependency( request: InjectGoBinaryMainDependencyRequest, ) -> InjectedDependencies: wrapped_tgt = await Get( WrappedTarget, WrappedTargetRequest( request.dependencies_field.address, description_of_origin="<infallible>" ), ) main_pkg = await Get( GoBinaryMainPackage, GoBinaryMainPackageRequest(wrapped_tgt.target[GoBinaryMainPackageField]), ) return InjectedDependencies([main_pkg.address])
async def run_shell_command_request( shell_command: RunShellCommand) -> RunRequest: wrapped_tgt = await Get( WrappedTarget, WrappedTargetRequest(shell_command.address, description_of_origin="<infallible>"), ) process = await Get(Process, ShellCommandProcessRequest(wrapped_tgt.target)) return RunRequest( digest=process.input_digest, args=process.argv, extra_env=process.env, )
async def run_all_setup_plugins( request: AllPytestPluginSetupsRequest, union_membership: UnionMembership) -> AllPytestPluginSetups: wrapped_tgt = await Get( WrappedTarget, WrappedTargetRequest(request.address, description_of_origin="<infallible>")) applicable_setup_request_types = tuple( request for request in union_membership.get(PytestPluginSetupRequest) if request.is_applicable(wrapped_tgt.target)) setups = await MultiGet( Get(PytestPluginSetup, PytestPluginSetupRequest, request(wrapped_tgt.target)) # type: ignore[misc, abstract] for request in applicable_setup_request_types) return AllPytestPluginSetups(setups)
async def inject_dependencies( request: InjectPythonProtobufDependencies, python_protobuf: PythonProtobufSubsystem, python_setup: PythonSetup, # TODO(#12946): Make this a lazy Get once possible. module_mapping: ThirdPartyPythonModuleMapping, ) -> InjectedDependencies: if not python_protobuf.infer_runtime_dependency: return InjectedDependencies() wrapped_tgt = await Get( WrappedTarget, WrappedTargetRequest(request.dependencies_field.address, description_of_origin="<infallible>"), ) tgt = wrapped_tgt.target resolve = tgt.get(PythonResolveField).normalized_value(python_setup) result = [ find_python_runtime_library_or_raise_error( module_mapping, request.dependencies_field.address, "google.protobuf", resolve=resolve, resolves_enabled=python_setup.enable_resolves, recommended_requirement_name="protobuf", recommended_requirement_url="https://pypi.org/project/protobuf/", disable_inference_option= f"[{python_protobuf.options_scope}].infer_runtime_dependency", ) ] if tgt.get(ProtobufGrpcToggleField).value: result.append( find_python_runtime_library_or_raise_error( module_mapping, request.dependencies_field.address, # Note that the library is called `grpcio`, but the module is `grpc`. "grpc", resolve=resolve, resolves_enabled=python_setup.enable_resolves, recommended_requirement_name="grpcio", recommended_requirement_url="https://pypi.org/project/grpcio/", disable_inference_option= f"[{python_protobuf.options_scope}].infer_runtime_dependency", )) return InjectedDependencies(result)
async def infer_scala_dependencies_via_source_analysis( request: InferScalaSourceDependencies, scala_infer_subsystem: ScalaInferSubsystem, jvm: JvmSubsystem, symbol_mapping: SymbolMapping, ) -> InferredDependencies: if not scala_infer_subsystem.imports: return InferredDependencies([]) address = request.sources_field.address wrapped_tgt = await Get( WrappedTarget, WrappedTargetRequest(address, description_of_origin="<infallible>")) tgt = wrapped_tgt.target explicitly_provided_deps, analysis = await MultiGet( Get(ExplicitlyProvidedDependencies, DependenciesRequest(tgt[Dependencies])), Get(ScalaSourceDependencyAnalysis, SourceFilesRequest([request.sources_field])), ) symbols: OrderedSet[str] = OrderedSet() if scala_infer_subsystem.imports: symbols.update(analysis.all_imports()) if scala_infer_subsystem.consumed_types: symbols.update(analysis.fully_qualified_consumed_symbols()) resolve = tgt[JvmResolveField].normalized_value(jvm) dependencies: OrderedSet[Address] = OrderedSet() for symbol in symbols: for matches in symbol_mapping.addresses_for_symbol(symbol, resolve).values(): explicitly_provided_deps.maybe_warn_of_ambiguous_dependency_inference( matches, address, import_reference="type", context=f"The target {address} imports `{symbol}`", ) maybe_disambiguated = explicitly_provided_deps.disambiguated( matches) if maybe_disambiguated: dependencies.add(maybe_disambiguated) return InferredDependencies(dependencies)
async def infer_python_init_dependencies( request: InferInitDependencies, python_infer_subsystem: PythonInferSubsystem, python_setup: PythonSetup, ) -> InferredDependencies: if ( not python_infer_subsystem.options.is_default("inits") and not python_infer_subsystem.inits ) or python_infer_subsystem.init_files is InitFilesInference.never: return InferredDependencies([]) ignore_empty_files = ( python_infer_subsystem.options.is_default("inits") and python_infer_subsystem.init_files is InitFilesInference.content_only ) fp = request.sources_field.file_path assert fp is not None init_files = await Get( AncestorFiles, AncestorFilesRequest( input_files=(fp,), requested=("__init__.py", "__init__.pyi"), ignore_empty_files=ignore_empty_files, ), ) owners = await MultiGet(Get(Owners, OwnersRequest((f,))) for f in init_files.snapshot.files) original_tgt, owner_tgts = await MultiGet( Get( WrappedTarget, WrappedTargetRequest( request.sources_field.address, description_of_origin="<infallible>" ), ), Get(Targets, Addresses(itertools.chain.from_iterable(owners))), ) resolve = original_tgt.target[PythonResolveField].normalized_value(python_setup) python_owners = [ tgt.address for tgt in owner_tgts if ( tgt.has_field(PythonSourceField) and tgt[PythonResolveField].normalized_value(python_setup) == resolve ) ] return InferredDependencies(python_owners)
async def inject_apache_thrift_java_dependencies( request: InjectApacheThriftJavaDependencies, jvm: JvmSubsystem) -> InjectedDependencies: wrapped_target = await Get( WrappedTarget, WrappedTargetRequest(request.dependencies_field.address, description_of_origin="<infallible>"), ) target = wrapped_target.target if not target.has_field(JvmResolveField): return InjectedDependencies() resolve = target[JvmResolveField].normalized_value(jvm) dependencies_info = await Get( ApacheThriftJavaRuntimeForResolve, ApacheThriftJavaRuntimeForResolveRequest(resolve)) return InjectedDependencies(dependencies_info.addresses)
async def inject_scala_library_dependency( request: InjectScalaLibraryDependencyRequest, jvm: JvmSubsystem, ) -> InjectedDependencies: wrapped_target = await Get( WrappedTarget, WrappedTargetRequest(request.dependencies_field.address, description_of_origin="<infallible>"), ) target = wrapped_target.target if not target.has_field(JvmResolveField): return InjectedDependencies() resolve = target[JvmResolveField].normalized_value(jvm) scala_library_target_info = await Get( ScalaRuntimeForResolve, ScalaRuntimeForResolveRequest(resolve)) return InjectedDependencies(scala_library_target_info.addresses)
async def _determine_literal_addresses_from_raw_specs( literal_specs: tuple[AddressLiteralSpec, ...], *, description_of_origin: str) -> tuple[WrappedTarget, ...]: literal_addresses = await MultiGet( Get( Address, AddressInput( spec.path_component, spec.target_component, generated_component=spec.generated_component, parameters=spec.parameters, description_of_origin=description_of_origin, ), ) for spec in literal_specs) # We replace references to parametrized target templates with all their created targets. For # example: # - dir:tgt -> (dir:tgt@k=v1, dir:tgt@k=v2) # - dir:tgt@k=v -> (dir:tgt@k=v,another=a, dir:tgt@k=v,another=b), but not anything # where @k=v is not true. literal_parametrizations = await MultiGet( Get( _TargetParametrizations, _TargetParametrizationsRequest( address.maybe_convert_to_target_generator(), description_of_origin=description_of_origin, ), ) for address in literal_addresses) # Note that if the address is not in the _TargetParametrizations, we must fall back to that # address's value. This will allow us to error that the address is invalid. all_candidate_addresses = itertools.chain.from_iterable( list(params.get_all_superset_targets(address)) or [address] for address, params in zip(literal_addresses, literal_parametrizations)) # We eagerly call the `WrappedTarget` rule because it will validate that every final address # actually exists, such as with generated target addresses. return await MultiGet( Get( WrappedTarget, WrappedTargetRequest(addr, description_of_origin=description_of_origin)) for addr in all_candidate_addresses)
async def inject_kotlin_junit_dependency( request: InjectKotlinJunitTestDependencyRequest, jvm: JvmSubsystem, ) -> InjectedDependencies: wrapped_target = await Get( WrappedTarget, WrappedTargetRequest(request.dependencies_field.address, description_of_origin="<infallible>"), ) target = wrapped_target.target if not target.has_field(JvmResolveField): return InjectedDependencies() resolve = target[JvmResolveField].normalized_value(jvm) kotlin_junit_libraries = await Get( KotlinJunitLibrariesForResolve, KotlinJunitLibrariesForResolveRequest(resolve)) return InjectedDependencies(kotlin_junit_libraries.addresses)
async def validate_python_dependencies( request: PythonValidateDependenciesRequest, python_setup: PythonSetup, ) -> ValidatedDependencies: dependencies = await MultiGet( Get( WrappedTarget, WrappedTargetRequest( d, description_of_origin=f"the dependencies of {request.field_set.address}" ), ) for d in request.dependencies ) # Validate that the ICs for dependencies are all compatible with our own. target_ics = request.field_set.interpreter_constraints.value_or_global_default(python_setup) non_subset_items = [] for dep in dependencies: if not dep.target.has_field(InterpreterConstraintsField): continue dep_ics = dep.target[InterpreterConstraintsField].value_or_global_default(python_setup) if not interpreter_constraints_contains( dep_ics, target_ics, python_setup.interpreter_universe ): non_subset_items.append(f"{dep_ics}: {dep.target.address}") if non_subset_items: raise InvalidFieldException( softwrap( f""" The target {request.field_set.address} has the `interpreter_constraints` {target_ics}, which are not a subset of the `interpreter_constraints` of some of its dependencies: {bullet_list(sorted(non_subset_items))} To fix this, you should likely adjust {request.field_set.address}'s `interpreter_constraints` to match the narrowest range in the above list. """ ) ) return ValidatedDependencies()
async def inject_protobuf_java_runtime_dependency( request: InjectProtobufJavaRuntimeDependencyRequest, jvm: JvmSubsystem, ) -> InjectedDependencies: wrapped_target = await Get( WrappedTarget, WrappedTargetRequest(request.dependencies_field.address, description_of_origin="<infallible>"), ) target = wrapped_target.target if not target.has_field(JvmResolveField): return InjectedDependencies() resolve = target[JvmResolveField].normalized_value(jvm) protobuf_java_runtime_target_info = await Get( ProtobufJavaRuntimeForResolve, ProtobufJavaRuntimeForResolveRequest(resolve)) return InjectedDependencies(protobuf_java_runtime_target_info.addresses)
async def infer_shell_dependencies( request: InferShellDependencies, shell_mapping: ShellMapping, shell_setup: ShellSetup) -> InferredDependencies: if not shell_setup.dependency_inference: return InferredDependencies([]) address = request.sources_field.address wrapped_tgt = await Get( WrappedTarget, WrappedTargetRequest(address, description_of_origin="<infallible>")) explicitly_provided_deps, hydrated_sources = await MultiGet( Get(ExplicitlyProvidedDependencies, DependenciesRequest(wrapped_tgt.target[Dependencies])), Get(HydratedSources, HydrateSourcesRequest(request.sources_field)), ) assert len(hydrated_sources.snapshot.files) == 1 detected_imports = await Get( ParsedShellImports, ParseShellImportsRequest(hydrated_sources.snapshot.digest, hydrated_sources.snapshot.files[0]), ) result: OrderedSet[Address] = OrderedSet() for import_path in detected_imports: unambiguous = shell_mapping.mapping.get(import_path) ambiguous = shell_mapping.ambiguous_modules.get(import_path) if unambiguous: result.add(unambiguous) elif ambiguous: explicitly_provided_deps.maybe_warn_of_ambiguous_dependency_inference( ambiguous, address, import_reference="file", context=f"The target {address} sources `{import_path}`", ) maybe_disambiguated = explicitly_provided_deps.disambiguated( ambiguous) if maybe_disambiguated: result.add(maybe_disambiguated) return InferredDependencies(sorted(result))
async def infer_protobuf_dependencies( request: InferProtobufDependencies, protobuf_mapping: ProtobufMapping, protoc: Protoc ) -> InferredDependencies: if not protoc.dependency_inference: return InferredDependencies([]) address = request.sources_field.address wrapped_tgt = await Get( WrappedTarget, WrappedTargetRequest(address, description_of_origin="<infallible>") ) explicitly_provided_deps, hydrated_sources = await MultiGet( Get(ExplicitlyProvidedDependencies, DependenciesRequest(wrapped_tgt.target[Dependencies])), Get(HydratedSources, HydrateSourcesRequest(request.sources_field)), ) digest_contents = await Get(DigestContents, Digest, hydrated_sources.snapshot.digest) assert len(digest_contents) == 1 file_content = digest_contents[0] result: OrderedSet[Address] = OrderedSet() for import_path in parse_proto_imports(file_content.content.decode()): unambiguous = protobuf_mapping.mapping.get(import_path) ambiguous = protobuf_mapping.ambiguous_modules.get(import_path) if unambiguous: result.add(unambiguous) elif ambiguous: explicitly_provided_deps.maybe_warn_of_ambiguous_dependency_inference( ambiguous, address, import_reference="file", context=softwrap( f""" The target {address} imports `{import_path}` in the file {file_content.path} """ ), ) maybe_disambiguated = explicitly_provided_deps.disambiguated(ambiguous) if maybe_disambiguated: result.add(maybe_disambiguated) return InferredDependencies(sorted(result))
async def infer_python_conftest_dependencies( request: InferConftestDependencies, python_infer_subsystem: PythonInferSubsystem, python_setup: PythonSetup, ) -> InferredDependencies: if not python_infer_subsystem.conftests: return InferredDependencies([]) fp = request.sources_field.file_path assert fp is not None conftest_files = await Get( AncestorFiles, AncestorFilesRequest(input_files=(fp,), requested=("conftest.py",)), ) owners = await MultiGet( # NB: Because conftest.py files effectively always have content, we require an # owning target. Get(Owners, OwnersRequest((f,), OwnersNotFoundBehavior.error)) for f in conftest_files.snapshot.files ) original_tgt, owner_tgts = await MultiGet( Get( WrappedTarget, WrappedTargetRequest( request.sources_field.address, description_of_origin="<infallible>" ), ), Get(Targets, Addresses(itertools.chain.from_iterable(owners))), ) resolve = original_tgt.target[PythonResolveField].normalized_value(python_setup) python_owners = [ tgt.address for tgt in owner_tgts if ( tgt.has_field(PythonSourceField) and tgt[PythonResolveField].normalized_value(python_setup) == resolve ) ] return InferredDependencies(python_owners)
async def analyze_first_party_package( request: FirstPartyPkgAnalysisRequest, analyzer: PackageAnalyzerSetup) -> FallibleFirstPartyPkgAnalysis: wrapped_target, import_path_info, owning_go_mod = await MultiGet( Get( WrappedTarget, WrappedTargetRequest( request.address, description_of_origin="<first party pkg analysis>"), ), Get(FirstPartyPkgImportPath, FirstPartyPkgImportPathRequest(request.address)), Get(OwningGoMod, OwningGoModRequest(request.address)), ) go_mod_info = await Get(GoModInfo, GoModInfoRequest(owning_go_mod.address)) pkg_sources = await Get( HydratedSources, HydrateSourcesRequest(wrapped_target.target[GoPackageSourcesField]), ) input_digest = await Get( Digest, MergeDigests([pkg_sources.snapshot.digest, analyzer.digest])) result = await Get( FallibleProcessResult, Process( (analyzer.path, request.address.spec_path or "."), input_digest=input_digest, description=f"Determine metadata for {request.address}", level=LogLevel.DEBUG, env={"CGO_ENABLED": "0"}, ), ) return FallibleFirstPartyPkgAnalysis.from_process_result( result, dir_path=request.address.spec_path, import_path=import_path_info.import_path, minimum_go_version=go_mod_info.minimum_go_version or "", description_of_source=f"first-party Go package `{request.address}`", )
async def inject_go_third_party_package_dependencies( request: InjectGoThirdPartyPackageDependenciesRequest, std_lib_imports: GoStdLibImports, package_mapping: ImportPathToPackages, ) -> InjectedDependencies: addr = request.dependencies_field.address go_mod_address = addr.maybe_convert_to_target_generator() wrapped_target, go_mod_info = await MultiGet( Get(WrappedTarget, WrappedTargetRequest(addr, description_of_origin="<infallible>")), Get(GoModInfo, GoModInfoRequest(go_mod_address)), ) tgt = wrapped_target.target pkg_info = await Get( ThirdPartyPkgAnalysis, ThirdPartyPkgAnalysisRequest( tgt[GoImportPathField].value, go_mod_info.digest, go_mod_info.mod_path ), ) inferred_dependencies = [] for import_path in pkg_info.imports: if import_path in std_lib_imports: continue candidate_packages = package_mapping.mapping.get(import_path, ()) if len(candidate_packages) > 1: # TODO(#12761): Use ExplicitlyProvidedDependencies for disambiguation. logger.warning( f"Ambiguous mapping for import path {import_path} on packages at addresses: {candidate_packages}" ) elif len(candidate_packages) == 1: inferred_dependencies.append(candidate_packages[0]) else: logger.debug( f"Unable to infer dependency for import path '{import_path}' " f"in go_third_party_package at address '{addr}'." ) return InjectedDependencies(inferred_dependencies)
async def create_analyze_scala_source_request( scala_subsystem: ScalaSubsystem, jvm: JvmSubsystem, scalac: Scalac, request: SourceFilesRequest) -> AnalyzeScalaSourceRequest: address = request.sources_fields[0].address wrapped_tgt, source_files = await MultiGet( Get( WrappedTarget, WrappedTargetRequest( address, description_of_origin="<the Scala analyze request setup rule>" ), ), Get(SourceFiles, SourceFilesRequest, request), ) tgt = wrapped_tgt.target resolve = tgt[JvmResolveField].normalized_value(jvm) scala_version = scala_subsystem.version_for_resolve(resolve) source3 = "-Xsource:3" in scalac.args return AnalyzeScalaSourceRequest(source_files, scala_version, source3)
async def inject_scala_plugin_dependencies( request: InjectScalaPluginDependenciesRequest, ) -> InjectedDependencies: """Adds dependencies on plugins for scala source files, so that they get included in the target's resolve.""" wrapped_target = await Get( WrappedTarget, WrappedTargetRequest(request.dependencies_field.address, description_of_origin="<infallible>"), ) target = wrapped_target.target if not target.has_field(JvmResolveField): return InjectedDependencies() scala_plugins = await Get( ScalaPluginTargetsForTarget, ScalaPluginsForTargetWithoutResolveRequest(target)) plugin_addresses = [target.address for target in scala_plugins.artifacts] return InjectedDependencies(plugin_addresses)
async def infer_thrift_dependencies( request: InferThriftDependencies, thrift_mapping: ThriftMapping, thrift: ThriftSubsystem) -> InferredDependencies: if not thrift.dependency_inference: return InferredDependencies([]) address = request.sources_field.address wrapped_tgt = await Get( WrappedTarget, WrappedTargetRequest(address, description_of_origin="<infallible>")) explicitly_provided_deps, parsed_thrift = await MultiGet( Get(ExplicitlyProvidedDependencies, DependenciesRequest(wrapped_tgt.target[Dependencies])), Get(ParsedThrift, ParsedThriftRequest(request.sources_field)), ) result: OrderedSet[Address] = OrderedSet() for import_path in parsed_thrift.imports: unambiguous = thrift_mapping.mapping.get(import_path) ambiguous = thrift_mapping.ambiguous_modules.get(import_path) if unambiguous: result.add(unambiguous) elif ambiguous: explicitly_provided_deps.maybe_warn_of_ambiguous_dependency_inference( ambiguous, address, import_reference="file", context=softwrap(f""" The target {address} imports `{import_path}` in the file {wrapped_tgt.target[ThriftSourceField].file_path} """), ) maybe_disambiguated = explicitly_provided_deps.disambiguated( ambiguous) if maybe_disambiguated: result.add(maybe_disambiguated) return InferredDependencies(sorted(result))
async def infer_python_dependencies_via_source( request: InferPythonImportDependencies, python_infer_subsystem: PythonInferSubsystem, python_setup: PythonSetup, ) -> InferredDependencies: if not python_infer_subsystem.imports and not python_infer_subsystem.assets: return InferredDependencies([]) _wrapped_tgt = await Get( WrappedTarget, WrappedTargetRequest(request.sources_field.address, description_of_origin="<infallible>"), ) tgt = _wrapped_tgt.target interpreter_constraints = InterpreterConstraints.create_from_targets([tgt], python_setup) if interpreter_constraints is None: # TODO: This would represent a target with a PythonSource field, but no # InterpreterConstraints field. #15400 would allow inference to require both # fields. return InferredDependencies([]) parsed_dependencies = await Get( ParsedPythonDependencies, ParsePythonDependenciesRequest( cast(PythonSourceField, request.sources_field), interpreter_constraints, string_imports=python_infer_subsystem.string_imports, string_imports_min_dots=python_infer_subsystem.string_imports_min_dots, assets=python_infer_subsystem.assets, assets_min_slashes=python_infer_subsystem.assets_min_slashes, ), ) inferred_deps: set[Address] = set() unowned_imports: set[str] = set() parsed_imports = parsed_dependencies.imports parsed_assets = parsed_dependencies.assets if not python_infer_subsystem.imports: parsed_imports = ParsedPythonImports([]) explicitly_provided_deps = await Get( ExplicitlyProvidedDependencies, DependenciesRequest(tgt[Dependencies]) ) resolve = tgt[PythonResolveField].normalized_value(python_setup) if parsed_imports: import_deps, unowned_imports = _get_imports_info( address=tgt.address, owners_per_import=await MultiGet( Get(PythonModuleOwners, PythonModuleOwnersRequest(imported_module, resolve=resolve)) for imported_module in parsed_imports ), parsed_imports=parsed_imports, explicitly_provided_deps=explicitly_provided_deps, ) inferred_deps.update(import_deps) if parsed_assets: all_asset_targets = await Get(AllAssetTargets, AllAssetTargetsRequest()) assets_by_path = await Get(AllAssetTargetsByPath, AllAssetTargets, all_asset_targets) inferred_deps.update( _get_inferred_asset_deps( tgt.address, request.sources_field.file_path, assets_by_path, parsed_assets, explicitly_provided_deps, ) ) _ = await _handle_unowned_imports( tgt.address, python_infer_subsystem.unowned_dependency_behavior, python_setup, unowned_imports, parsed_imports, resolve=resolve, ) return InferredDependencies(sorted(inferred_deps))