Repository URL to install this package:
|
Version:
1.26.0.dev0+gite506aa5f ▾
|
# Copyright 2015 Pants project contributors (see CONTRIBUTORS.md).
# Licensed under the Apache License, Version 2.0 (see LICENSE).
from collections import namedtuple
from pants.backend.jvm.subsystems.jvm_tool_mixin import JvmToolMixin
from pants.backend.jvm.subsystems.zinc_language_mixin import ZincLanguageMixin
from pants.backend.jvm.targets.jar_library import JarLibrary
from pants.build_graph.address import Address
from pants.build_graph.injectables_mixin import InjectablesMixin
from pants.java.jar.jar_dependency import JarDependency
from pants.subsystem.subsystem import Subsystem
# full_version - the full scala version to use.
major_version_info = namedtuple("major_version_info", ["full_version"])
# Note that the compiler has two roles here: as a tool (invoked by the compile task), and as a
# runtime library (when compiling plugins, which require the compiler library as a dependency).
scala_build_info = {
"2.10": major_version_info(full_version="2.10.6"),
"2.11": major_version_info(full_version="2.11.12"),
"2.12": major_version_info(full_version="2.12.8"),
}
# Because scalastyle inspects only the sources, it needn't match the platform version.
scala_style_jar = JarDependency("org.scalastyle", "scalastyle_2.11", "0.8.0")
# TODO: Sort out JVM compile config model: https://github.com/pantsbuild/pants/issues/4483.
class ScalaPlatform(JvmToolMixin, ZincLanguageMixin, InjectablesMixin, Subsystem):
"""A scala platform.
:API: public
"""
options_scope = "scala"
@classmethod
def create_jardep(cls, name, version):
return JarDependency(
org="org.scala-lang", name=name, rev=scala_build_info[version].full_version
)
@classmethod
def _create_runtime_jardep(cls, version):
return cls.create_jardep("scala-library", version)
@classmethod
def _create_compiler_jardep(cls, version):
return cls.create_jardep("scala-compiler", version)
@classmethod
def versioned_tool_name(cls, tool, version):
if version == "custom":
return tool
else:
return f"{tool}_{version.replace('.', '_')}"
@classmethod
def register_options(cls, register):
def register_scala_compiler_tool(version):
cls.register_jvm_tool(
register,
cls.versioned_tool_name("scalac", version),
classpath=[cls._create_compiler_jardep(version)],
)
def register_scala_repl_tool(version, with_jline=False):
classpath = [
cls._create_compiler_jardep(version)
] # Note: the REPL is in the compiler jar.
if with_jline:
jline_dep = JarDependency(
org="org.scala-lang", name="jline", rev=scala_build_info[version].full_version
)
classpath.append(jline_dep)
cls.register_jvm_tool(
register, cls.versioned_tool_name("scala-repl", version), classpath=classpath
)
def register_style_tool(version):
cls.register_jvm_tool(
register,
cls.versioned_tool_name("scalastyle", version),
classpath=[scala_style_jar],
)
super().register_options(register)
register(
"--scalac-plugins",
advanced=True,
type=list,
fingerprint=True,
help="Use these scalac plugins.",
)
register(
"--scalac-plugin-args",
advanced=True,
type=dict,
default={},
fingerprint=True,
help="Map from scalac plugin name to list of arguments for that plugin.",
)
cls.register_jvm_tool(
register,
"scalac-plugin-dep",
classpath=[],
help="Search for scalac plugins here, as well as in any " "explicit dependencies.",
)
register(
"--version",
advanced=True,
default="2.12",
choices=["2.10", "2.11", "2.12", "custom"],
fingerprint=True,
help="The scala platform version. If --version=custom, the targets "
"//:scala-library, //:scalac, //:scala-repl and //:scalastyle will be used, "
"and must exist. Otherwise, defaults for the specified version will be used.",
)
register(
"--suffix-version",
advanced=True,
default=None,
help="Scala suffix to be used in `scala_jar` definitions. For example, specifying "
"`2.11` or `2.12.0-RC1` would cause `scala_jar` lookups for artifacts with "
"those suffixes.",
)
# Register the fixed version tools.
register_scala_compiler_tool("2.10")
register_scala_repl_tool("2.10", with_jline=True) # 2.10 repl requires jline.
register_style_tool("2.10")
register_scala_compiler_tool("2.11")
register_scala_repl_tool("2.11")
register_style_tool("2.11")
register_scala_compiler_tool("2.12")
register_scala_repl_tool("2.12")
register_style_tool("2.12")
# Register the custom tools. We provide a dummy classpath, so that register_jvm_tool won't
# require that a target with the given spec actually exist (not everyone will define custom
# scala platforms). However if the custom tool is actually resolved, we want that to
# fail with a useful error, hence the dummy jardep with rev=None.
def register_custom_tool(key):
dummy_jardep = JarDependency("missing spec", f" //:{key}")
cls.register_jvm_tool(
register, cls.versioned_tool_name(key, "custom"), classpath=[dummy_jardep]
)
register_custom_tool("scalac")
register_custom_tool("scala-repl")
register_custom_tool("scalastyle")
def _tool_classpath(self, tool, products):
"""Return the proper classpath based on products and scala version."""
return self.tool_classpath_entries_from_products(
products, self.versioned_tool_name(tool, self.version), scope=self.options_scope,
)
def compiler_classpath_entries(self, products):
"""Returns classpath entries for the scalac tool."""
return self._tool_classpath("scalac", products)
def style_classpath(self, products):
"""Returns classpath as paths for scalastyle."""
classpath_entries = self._tool_classpath("scalastyle", products)
return [classpath_entry.path for classpath_entry in classpath_entries]
@property
def version(self):
return self.get_options().version
def suffix_version(self, name):
"""Appends the platform version to the given artifact name.
Also validates that the name doesn't already end with the version.
"""
if self.version == "custom":
suffix = self.get_options().suffix_version
if suffix:
return f"{name}_{suffix}"
else:
raise RuntimeError(
"Suffix version must be specified if using a custom scala version. "
"Suffix version is used for bootstrapping jars. If a custom "
"scala version is not specified, then the version specified in "
"--scala-suffix-version is used. For example for Scala "
'2.10.7 you would use the suffix version "2.10".'
)
elif name.endswith(self.version):
raise ValueError(
'The name "{0}" should not be suffixed with the scala platform version '
"({1}): it will be added automatically.".format(name, self.version)
)
return f"{name}_{self.version}"
@property
def repl(self):
"""Return the repl tool key."""
return self.versioned_tool_name("scala-repl", self.version)
def injectables(self, build_graph):
if self.version == "custom":
return
specs_to_create = [
("scalac", self._create_compiler_jardep),
("scala-library", self._create_runtime_jardep),
]
for spec_key, create_jardep_func in specs_to_create:
address_spec = self.injectables_address_spec_for_key(spec_key)
target_address = Address.parse(address_spec)
if not build_graph.contains_address(target_address):
jars = [create_jardep_func(self.version)]
build_graph.inject_synthetic_target(
target_address, JarLibrary, jars=jars, scope="forced"
)
elif not build_graph.get_target(target_address).is_synthetic:
raise build_graph.ManualSyntheticTargetError(target_address)
@property
def injectables_address_spec_mapping(self):
maybe_suffix = "" if self.version == "custom" else "-synthetic"
return {
# Target spec for the scala compiler library.
"scalac": [f"//:scalac{maybe_suffix}"],
# Target spec for the scala runtime library.
"scala-library": [f"//:scala-library{maybe_suffix}"],
}