Exemple #1
0
async def resolve_scala_library_for_resolve(
    request: ScalaRuntimeForResolveRequest,
    jvm_artifact_targets: AllJvmArtifactTargets,
    jvm: JvmSubsystem,
    scala_subsystem: ScalaSubsystem,
) -> ScalaRuntimeForResolve:

    scala_version = scala_subsystem.version_for_resolve(request.resolve_name)

    for tgt in jvm_artifact_targets:
        if tgt[JvmResolveField].normalized_value(jvm) != request.resolve_name:
            continue

        artifact = ArtifactRequirement.from_jvm_artifact_target(tgt)
        if (
            artifact.coordinate.group != SCALA_LIBRARY_GROUP
            or artifact.coordinate.artifact != SCALA_LIBRARY_ARTIFACT
        ):
            continue

        if artifact.coordinate.version != scala_version:
            raise ConflictingScalaLibraryVersionInResolveError(
                request.resolve_name, scala_version, artifact.coordinate
            )

        return ScalaRuntimeForResolve(tgt.address)

    raise MissingScalaLibraryInResolveError(request.resolve_name, scala_version)
Exemple #2
0
async def setup_user_lockfile_requests(
    requested: RequestedJVMUserResolveNames,
    all_targets: AllTargets,
    jvm_subsystem: JvmSubsystem,
) -> UserGenerateLockfiles:
    resolve_to_artifacts: Mapping[
        str, OrderedSet[ArtifactRequirement]] = defaultdict(OrderedSet)
    for tgt in sorted(all_targets, key=lambda t: t.address):
        if not tgt.has_field(JvmArtifactResolveField):
            continue
        artifact = ArtifactRequirement.from_jvm_artifact_target(tgt)
        resolve = tgt[JvmResolveField].normalized_value(jvm_subsystem)
        resolve_to_artifacts[resolve].add(artifact)

    # Generate a JVM lockfile request for each requested resolve. This step also allows other backends to
    # validate the proposed set of artifact requirements for each resolve.
    jvm_lockfile_requests = await MultiGet(
        Get(
            GenerateJvmLockfile,
            _ValidateJvmArtifactsRequest(
                artifacts=ArtifactRequirements(
                    resolve_to_artifacts.get(resolve, ())),
                resolve_name=resolve,
            ),
        ) for resolve in requested)

    return UserGenerateLockfiles(jvm_lockfile_requests)
Exemple #3
0
async def gather_coordinates_for_jvm_lockfile(
    request: GatherJvmCoordinatesRequest, ) -> ArtifactRequirements:
    # Separate `artifact_inputs` by whether the strings parse as an `Address` or not.
    requirements: set[ArtifactRequirement] = set()
    candidate_address_inputs: set[AddressInput] = set()
    bad_artifact_inputs = []
    for artifact_input in request.artifact_inputs:
        # Try parsing as a `Coordinate` first since otherwise `AddressInput.parse` will try to see if the
        # group name is a file on disk.
        if 2 <= artifact_input.count(":") <= 3:
            try:
                maybe_coord = Coordinate.from_coord_str(
                    artifact_input).as_requirement()
                requirements.add(maybe_coord)
                continue
            except Exception:
                pass

        try:
            address_input = AddressInput.parse(
                artifact_input,
                description_of_origin=f"the option `{request.option_name}`")
            candidate_address_inputs.add(address_input)
        except Exception:
            bad_artifact_inputs.append(artifact_input)

    if bad_artifact_inputs:
        raise ValueError(
            "The following values could not be parsed as an address nor as a JVM coordinate string. "
            f"The problematic inputs supplied to the `{request.option_name}` option were: "
            f"{', '.join(bad_artifact_inputs)}.")

    # Gather coordinates from the provided addresses.
    addresses = await MultiGet(
        Get(Address, AddressInput, ai) for ai in candidate_address_inputs)
    all_supplied_targets = await Get(Targets, Addresses(addresses))
    other_targets = []
    for tgt in all_supplied_targets:
        if JvmArtifactFieldSet.is_applicable(tgt):
            requirements.add(ArtifactRequirement.from_jvm_artifact_target(tgt))
        else:
            other_targets.append(tgt)

    if other_targets:
        raise ValueError(
            softwrap(f"""
                The following addresses reference targets that are not `jvm_artifact` targets.
                Please only supply the addresses of `jvm_artifact` for the `{request.option_name}`
                option. The problematic addresses are: {', '.join(str(tgt.address) for tgt in other_targets)}.
                """))

    return ArtifactRequirements(requirements)
Exemple #4
0
async def collect_thirdparty_modules(
    request: ThirdpartyModulesRequest,
    classpath_entry_request: ClasspathEntryRequestFactory,
) -> ThirdpartyModules:
    coarsened_targets = await Get(CoarsenedTargets, Addresses,
                                  request.addresses)
    resolve = await Get(CoursierResolveKey, CoarsenedTargets,
                        coarsened_targets)
    lockfile = await Get(CoursierResolvedLockfile, CoursierResolveKey, resolve)

    applicable_lockfile_entries: dict[CoursierLockfileEntry,
                                      CoarsenedTarget] = {}
    for ct in coarsened_targets.coarsened_closure():
        for tgt in ct.members:
            if not JvmArtifactFieldSet.is_applicable(tgt):
                continue

            artifact_requirement = ArtifactRequirement.from_jvm_artifact_target(
                tgt)
            entry = get_entry_for_coord(lockfile,
                                        artifact_requirement.coordinate)
            if not entry:
                _logger.warning(
                    f"No lockfile entry for {artifact_requirement.coordinate} in resolve {resolve.name}."
                )
                continue
            applicable_lockfile_entries[entry] = ct

    classpath_entries = await MultiGet(
        Get(
            ClasspathEntry,
            ClasspathEntryRequest,
            classpath_entry_request.for_targets(component=target,
                                                resolve=resolve),
        ) for target in applicable_lockfile_entries.values())

    resolve_digest = await Get(
        Digest, MergeDigests(cpe.digest for cpe in classpath_entries))

    return ThirdpartyModules(
        resolve,
        dict(zip(applicable_lockfile_entries, classpath_entries)),
        resolve_digest,
    )
Exemple #5
0
def find_jvm_artifacts_or_raise(
    required_coordinates: Iterable[Coordinate | UnversionedCoordinate],
    resolve: str,
    jvm_artifact_targets: AllJvmArtifactTargets,
    jvm: JvmSubsystem,
) -> frozenset[Address]:
    remaining_coordinates: set[Coordinate | UnversionedCoordinate] = set(
        required_coordinates)

    addresses: set[Address] = set()
    for tgt in jvm_artifact_targets:
        if tgt[JvmResolveField].normalized_value(jvm) != resolve:
            continue

        artifact = ArtifactRequirement.from_jvm_artifact_target(tgt)
        found_coordinates: set[Coordinate | UnversionedCoordinate] = set()
        for coordinate in remaining_coordinates:
            if isinstance(coordinate, Coordinate):
                if (artifact.coordinate.group != coordinate.group or
                        artifact.coordinate.artifact != coordinate.artifact):
                    continue
                if artifact.coordinate.version != coordinate.version:
                    raise ConflictingJvmArtifactVersion(
                        group=coordinate.group,
                        artifact=coordinate.artifact,
                        required_version=coordinate.version,
                        found_coordinate=artifact.coordinate,
                    )
            elif isinstance(coordinate, UnversionedCoordinate):
                if (artifact.coordinate.group != coordinate.group or
                        artifact.coordinate.artifact != coordinate.artifact):
                    continue

            found_coordinates.add(coordinate)

        if found_coordinates:
            remaining_coordinates.difference_update(found_coordinates)
            addresses.add(tgt.address)

    if remaining_coordinates:
        raise MissingJvmArtifacts(remaining_coordinates)

    return frozenset(addresses)
Exemple #6
0
async def fetch_with_coursier(
        request: CoursierFetchRequest) -> FallibleClasspathEntry:
    # TODO: Loading this per JvmArtifact.
    lockfile = await Get(CoursierResolvedLockfile, CoursierResolveKey,
                         request.resolve)

    requirement = ArtifactRequirement.from_jvm_artifact_target(
        request.component.representative)

    if lockfile.metadata and not lockfile.metadata.is_valid_for(
        [requirement], LockfileContext.USER):
        raise ValueError(
            f"Requirement `{requirement.to_coord_arg_str()}` has changed since the lockfile "
            f"for {request.resolve.path} was generated. Run `{bin_name()} generate-lockfiles` to update your "
            "lockfile based on the new requirements.")

    # All of the transitive dependencies are exported.
    # TODO: Expose an option to control whether this exports only the root, direct dependencies,
    # transitive dependencies, etc.
    assert len(request.component.members
               ) == 1, "JvmArtifact does not have dependencies."
    root_entry, transitive_entries = lockfile.dependencies(
        request.resolve,
        requirement.coordinate,
    )

    classpath_entries = await MultiGet(
        Get(ClasspathEntry, CoursierLockfileEntry, entry)
        for entry in (root_entry, *transitive_entries))
    exported_digest = await Get(
        Digest, MergeDigests(cpe.digest for cpe in classpath_entries))

    return FallibleClasspathEntry(
        description=str(request.component),
        result=CompileResult.SUCCEEDED,
        output=ClasspathEntry.merge(exported_digest, classpath_entries),
        exit_code=0,
    )
Exemple #7
0
async def scala_bsp_dependency_modules(
    request: ScalaBSPDependencyModulesRequest,
    build_root: BuildRoot,
) -> BSPDependencyModulesResult:
    coarsened_targets = await Get(
        CoarsenedTargets, Addresses([fs.address for fs in request.field_sets]))
    resolve = await Get(CoursierResolveKey, CoarsenedTargets,
                        coarsened_targets)
    lockfile = await Get(CoursierResolvedLockfile, CoursierResolveKey, resolve)

    # TODO: Can this use ClasspathEntryRequest?
    transitive_targets = await Get(
        TransitiveTargets,
        TransitiveTargetsRequest(roots=[
            tgt.address for coarsened_target in coarsened_targets
            for tgt in coarsened_target.members
        ]),
    )

    artifact_requirements = [
        ArtifactRequirement.from_jvm_artifact_target(tgt)
        for tgt in transitive_targets.closure
        if JvmArtifactFieldSet.is_applicable(tgt)
    ]

    applicable_lockfile_entries: set[CoursierLockfileEntry] = set()
    for artifact_requirement in artifact_requirements:
        entry = get_entry_for_coord(lockfile, artifact_requirement.coordinate)
        if not entry:
            _logger.warning(
                f"No lockfile entry for {artifact_requirement.coordinate} in resolve {resolve.name}."
            )
            continue
        applicable_lockfile_entries.add(entry)

    resolve_digest = await Get(
        Digest,
        CreateDigest([
            FileEntry(entry.file_name, entry.file_digest)
            for entry in applicable_lockfile_entries
        ]),
    )

    resolve_digest = await Get(
        Digest, AddPrefix(resolve_digest, f"jvm/resolves/{resolve.name}/lib"))

    modules = [
        DependencyModule(
            name=f"{entry.coord.group}:{entry.coord.artifact}",
            version=entry.coord.version,
            data=MavenDependencyModule(
                organization=entry.coord.group,
                name=entry.coord.artifact,
                version=entry.coord.version,
                scope=None,
                artifacts=(MavenDependencyModuleArtifact(
                    uri=build_root.pathlib_path.joinpath(
                        f".pants.d/bsp/jvm/resolves/{resolve.name}/lib/{entry.file_name}"
                    ).as_uri()), ),
            ),
        ) for entry in applicable_lockfile_entries
    ]

    return BSPDependencyModulesResult(
        modules=tuple(modules),
        digest=resolve_digest,
    )