Example #1
0
async def render_classpath(classpath: Classpath) -> RenderedClasspath:
    rendered_classpaths = await MultiGet(
        Get(RenderedClasspath, ClasspathEntry, cpe)
        for cpe in ClasspathEntry.closure(classpath.entries))
    return RenderedClasspath(
        {k: v
         for rc in rendered_classpaths for k, v in rc.content.items()})
Example #2
0
 def immutable_inputs(self,
                      *,
                      prefix: str = "") -> Iterator[tuple[str, Digest]]:
     """Returns (relpath, Digest) tuples for use with `Process.immutable_input_digests`."""
     return ClasspathEntry.immutable_inputs(ClasspathEntry.closure(
         self.entries),
                                            prefix=prefix)
Example #3
0
async def fetch_kotlinc_plugins(
        request: KotlincPluginsRequest) -> KotlincPlugins:
    # Fetch all the artifacts
    coarsened_targets = await Get(
        CoarsenedTargets,
        Addresses(target.address for target in request.artifacts))
    fallible_artifacts = await MultiGet(
        Get(
            FallibleClasspathEntry,
            CoursierFetchRequest(ct, resolve=request.resolve),
        ) for ct in coarsened_targets)

    artifacts = FallibleClasspathEntry.if_all_succeeded(fallible_artifacts)
    if artifacts is None:
        failed = [i for i in fallible_artifacts if i.exit_code != 0]
        raise Exception(f"Fetching local kotlinc plugins failed: {failed}")

    entries = list(ClasspathEntry.closure(artifacts))
    merged_classpath_digest = await Get(
        Digest, MergeDigests(entry.digest for entry in entries))
    merged = ClasspathEntry.merge(merged_classpath_digest, entries)

    ids = tuple(_plugin_id(target) for target in request.plugins)

    plugin_args = FrozenDict({
        _plugin_id(plugin): tuple(plugin[KotlincPluginArgsField].value or [])
        for plugin in request.plugins
    })

    return KotlincPlugins(ids=ids, classpath=merged, plugin_args=plugin_args)
Example #4
0
 def immutable_inputs_args(self, *, prefix: str = "") -> Iterator[str]:
     """Returns relative filenames for the given entries to be used as immutable_inputs."""
     return ClasspathEntry.immutable_inputs_args(ClasspathEntry.closure(
         self.entries),
                                                 prefix=prefix)
Example #5
0
 def digests(self) -> Iterator[Digest]:
     """All transitive Digests for this Classpath."""
     return (entry.digest for entry in ClasspathEntry.closure(self.entries))
Example #6
0
 def args(self, *, prefix: str = "") -> Iterator[str]:
     """All transitive filenames for this Classpath."""
     return ClasspathEntry.args(ClasspathEntry.closure(self.entries),
                                prefix=prefix)
Example #7
0
def test_compile_with_multiple_scala_versions(rule_runner: RuleRunner) -> None:
    scala_library_coord_2_12 = Coordinate(group="org.scala-lang",
                                          artifact="scala-library",
                                          version="2.12.15")
    scala_library_coord_2_13 = Coordinate(group="org.scala-lang",
                                          artifact="scala-library",
                                          version="2.13.8")
    rule_runner.write_files({
        "BUILD":
        dedent("""\
                scala_sources(
                    name = 'main_2.12',
                    resolve = "scala2.12",
                )
                scala_sources(
                    name = 'main_2.13',
                    resolve = "scala2.13",
                )
                jvm_artifact(
                  name="org.scala-lang_scala-library_2.12.15",
                  group="org.scala-lang",
                  artifact="scala-library",
                  version="2.12.15",
                  resolve="scala2.12",
                )
                jvm_artifact(
                  name="org.scala-lang_scala-library_2.13.8",
                  group="org.scala-lang",
                  artifact="scala-library",
                  version="2.13.8",
                  resolve="scala2.13",
                )
                """),
        "Example.scala":
        SCALA_LIB_SOURCE,
        "3rdparty/jvm/scala2.12.lock":
        TestCoursierWrapper.new(entries=(CoursierLockfileEntry(
            coord=scala_library_coord_2_12,
            file_name="org.scala-lang_scala-library_2.12.15.jar",
            direct_dependencies=Coordinates([]),
            dependencies=Coordinates([]),
            file_digest=FileDigest(
                "e518bb640e2175de5cb1f8e326679b8d975376221f1b547757de429bbf4563f0",
                5443542,
            ),
        ), ), ).serialize([ArtifactRequirement(scala_library_coord_2_12)]),
        "3rdparty/jvm/scala2.13.lock":
        TestCoursierWrapper.new(entries=(CoursierLockfileEntry(
            coord=scala_library_coord_2_13,
            file_name="org.scala-lang_scala-library_2.13.8.jar",
            direct_dependencies=Coordinates([]),
            dependencies=Coordinates([]),
            file_digest=FileDigest(
                "a0882b82514190c2bac7d1a459872a75f005fc0f3e88b2bc0390367146e35db7",
                6003601,
            ),
        ), ), ).serialize([ArtifactRequirement(scala_library_coord_2_13)]),
    })
    rule_runner.set_options(
        [
            '--scala-version-for-resolve={"scala2.12":"2.12.15","scala2.13":"2.13.8"}',
            '--jvm-resolves={"scala2.12":"3rdparty/jvm/scala2.12.lock","scala2.13":"3rdparty/jvm/scala2.13.lock"}',
        ],
        env_inherit=PYTHON_BOOTSTRAP_ENV,
    )
    classpath_2_12 = rule_runner.request(
        ClasspathEntry,
        [
            CompileScalaSourceRequest(
                component=expect_single_expanded_coarsened_target(
                    rule_runner, Address(spec_path="",
                                         target_name="main_2.12")),
                resolve=make_resolve(rule_runner, "scala2.12",
                                     "3rdparty/jvm/scala2.12.lock"),
            )
        ],
    )
    entries_2_12 = list(ClasspathEntry.closure([classpath_2_12]))
    filenames_2_12 = sorted(
        itertools.chain.from_iterable(entry.filenames
                                      for entry in entries_2_12))
    assert filenames_2_12 == [
        ".Example.scala.main_2.12.scalac.jar",
        "org.scala-lang_scala-library_2.12.15.jar",
    ]

    classpath_2_13 = rule_runner.request(
        ClasspathEntry,
        [
            CompileScalaSourceRequest(
                component=expect_single_expanded_coarsened_target(
                    rule_runner, Address(spec_path="",
                                         target_name="main_2.13")),
                resolve=make_resolve(rule_runner, "scala2.13",
                                     "3rdparty/jvm/scala2.13.lock"),
            )
        ],
    )
    entries_2_13 = list(ClasspathEntry.closure([classpath_2_13]))
    filenames_2_13 = sorted(
        itertools.chain.from_iterable(entry.filenames
                                      for entry in entries_2_13))
    assert filenames_2_13 == [
        ".Example.scala.main_2.13.scalac.jar",
        "org.scala-lang_scala-library_2.13.8.jar",
    ]
Example #8
0
async def compile_scala_source(
    bash: BashBinary,
    coursier: Coursier,
    jdk_setup: JdkSetup,
    scala: ScalaSubsystem,
    union_membership: UnionMembership,
    request: CompileScalaSourceRequest,
) -> FallibleClasspathEntry:
    # Request classpath entries for our direct dependencies.
    direct_dependency_classpath_entries = FallibleClasspathEntry.if_all_succeeded(
        await MultiGet(
            Get(
                FallibleClasspathEntry,
                ClasspathEntryRequest,
                ClasspathEntryRequest.for_targets(union_membership,
                                                  component=coarsened_dep,
                                                  resolve=request.resolve),
            ) for coarsened_dep in request.component.dependencies))
    if direct_dependency_classpath_entries is None:
        return FallibleClasspathEntry(
            description=str(request.component),
            result=CompileResult.DEPENDENCY_FAILED,
            output=None,
            exit_code=1,
        )

    component_members_with_sources = tuple(t for t in request.component.members
                                           if t.has_field(SourcesField))
    component_members_and_source_files = zip(
        component_members_with_sources,
        await MultiGet(
            Get(
                SourceFiles,
                SourceFilesRequest(
                    (t.get(SourcesField), ),
                    for_sources_types=(ScalaSourceField, ),
                    enable_codegen=True,
                ),
            ) for t in component_members_with_sources),
    )

    component_members_and_scala_source_files = [
        (target, sources)
        for target, sources in component_members_and_source_files
        if sources.snapshot.digest != EMPTY_DIGEST
    ]

    if not component_members_and_scala_source_files:
        # Is a generator, and so exports all of its direct deps.
        exported_digest = await Get(
            Digest,
            MergeDigests(cpe.digest
                         for cpe in direct_dependency_classpath_entries))
        classpath_entry = ClasspathEntry.merge(
            exported_digest, direct_dependency_classpath_entries)
        return FallibleClasspathEntry(
            description=str(request.component),
            result=CompileResult.SUCCEEDED,
            output=classpath_entry,
            exit_code=0,
        )

    (
        tool_classpath,
        merged_transitive_dependency_classpath_entries_digest,
    ) = await MultiGet(
        Get(
            MaterializedClasspath,
            MaterializedClasspathRequest(
                prefix="__toolcp",
                artifact_requirements=(ArtifactRequirements([
                    Coordinate(
                        group="org.scala-lang",
                        artifact="scala-compiler",
                        version=scala.version,
                    ),
                    Coordinate(
                        group="org.scala-lang",
                        artifact="scala-library",
                        version=scala.version,
                    ),
                ]), ),
            ),
        ),
        Get(
            Digest,
            # Flatten the entire transitive classpath.
            MergeDigests(classfiles.digest
                         for classfiles in ClasspathEntry.closure(
                             direct_dependency_classpath_entries)),
        ),
    )

    usercp = "__cp"
    prefixed_transitive_dependency_classpath_digest = await Get(
        Digest,
        AddPrefix(merged_transitive_dependency_classpath_entries_digest,
                  usercp))

    merged_digest = await Get(
        Digest,
        MergeDigests((
            prefixed_transitive_dependency_classpath_digest,
            tool_classpath.digest,
            jdk_setup.digest,
            *(sources.snapshot.digest
              for _, sources in component_members_and_scala_source_files),
        )),
    )

    classpath_arg = ClasspathEntry.arg(
        ClasspathEntry.closure(direct_dependency_classpath_entries),
        prefix=usercp)

    output_file = f"{request.component.representative.address.path_safe_spec}.jar"
    process_result = await Get(
        FallibleProcessResult,
        Process(
            argv=[
                *jdk_setup.args(bash, tool_classpath.classpath_entries()),
                "scala.tools.nsc.Main",
                "-bootclasspath",
                ":".join(tool_classpath.classpath_entries()),
                *(("-classpath", classpath_arg) if classpath_arg else ()),
                "-d",
                output_file,
                *sorted(
                    chain.from_iterable(
                        sources.snapshot.files for _, sources in
                        component_members_and_scala_source_files)),
            ],
            input_digest=merged_digest,
            use_nailgun=jdk_setup.digest,
            output_files=(output_file, ),
            description=f"Compile {request.component} with scalac",
            level=LogLevel.DEBUG,
            append_only_caches=jdk_setup.append_only_caches,
            env=jdk_setup.env,
        ),
    )
    output: ClasspathEntry | None = None
    if process_result.exit_code == 0:
        output = ClasspathEntry(process_result.output_digest, (output_file, ),
                                direct_dependency_classpath_entries)

    return FallibleClasspathEntry.from_fallible_process_result(
        str(request.component),
        process_result,
        output,
    )