Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable building scala versions in the same bazel invocation #1

Merged
merged 21 commits into from
Jan 25, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 30 additions & 2 deletions WORKSPACE
Original file line number Diff line number Diff line change
@@ -1,6 +1,34 @@
workspace(name = "io_bazel_rules_scala")

load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")

#####
# bazel-skylib 0.8.0 released 2019.03.20 (https://github.com/bazelbuild/bazel-skylib/releases/tag/0.8.0)
skylib_version = "0.8.0"

http_archive(
name = "bazel_skylib",
sha256 = "2ef429f5d7ce7111263289644d233707dba35e39696377ebab8b0bc701f7818e",
type = "tar.gz",
url = "https://github.com/bazelbuild/bazel-skylib/releases/download/{}/bazel-skylib.{}.tar.gz".format(skylib_version, skylib_version),
)

load("@io_bazel_rules_scala//scala:rules_jvm_external.bzl", "rules_jvm_external")

rules_jvm_external()

load("@io_bazel_rules_scala//scala:scala_configuration.bzl", "scala_configuration")

scala_configuration()

load(
"@io_bazel_rules_scala//scala:scala_repositories.bzl",
"scala_repositories",
)

scala_repositories()
#####

load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository")
load("@bazel_tools//tools/build_defs/repo:jvm.bzl", "jvm_maven_import_external")

Expand Down Expand Up @@ -131,9 +159,9 @@ local_repository(
path = "third_party/test/strip_resource_external_workspace",
)

load("@io_bazel_rules_scala//scala:toolchains.bzl", "scala_register_unused_deps_toolchains")
# load("@io_bazel_rules_scala//scala:toolchains.bzl", "scala_register_unused_deps_toolchains")

scala_register_unused_deps_toolchains()
# scala_register_unused_deps_toolchains()

register_toolchains("@io_bazel_rules_scala//test/proto:scalapb_toolchain")

Expand Down
9 changes: 6 additions & 3 deletions docs/customizable_phase.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,14 +128,17 @@ Currently phase architecture is used by 7 rules:
- scala_junit_test
- scala_repl

In each of the rule implementation, it calls `run_phases` and returns the information from `phase_final`, which groups the final returns of the rule. To prevent consumers from accidently removing `phase_final` from the list, we make it a non-customizable phase.
If you need to expose providers to downstream targets you need to return a dict of providers (provider-name to provider instance) from your phase under the `external_providers` attribute.

If you need to override a provider returned by a previous phase you can adjust your phase to be after it and return the same key from your phase and it will override it.
Note you probably have a good reason to override since you're meddling with the public return value of a different phase.

In each of the rule implementations, it calls `run_phases` and returns the accumulated values of the `external_providers` dict declared by the phases.

To make a new phase, you have to define a new `phase_<PHASE_NAME>.bzl` in `scala/private/phases/`. Function definition should have 2 arguments, `ctx` and `p`. You may expose the information for later phases by returning a `struct`. In some phases, there are multiple phase functions since different rules may take slightly different input arguemnts. You may want to re-expose the phase definition in `scala/private/phases/phases.bzl`, so it's more convenient to access in rule files.

In the rule implementations, put your new phase in `builtin_customizable_phases` list. The phases are executed sequentially, the order matters if the new phase depends on previous phases.

If you are making new return fields of the rule, remember to modify `phase_final`.

### Phase naming convention
Files in `scala/private/phases/`
- `phase_<PHASE_NAME>.bzl`: phase definition file
Expand Down
61 changes: 18 additions & 43 deletions scala/BUILD
Original file line number Diff line number Diff line change
@@ -1,66 +1,41 @@
load(
"@io_bazel_rules_scala//scala:providers.bzl",
_declare_scalac_provider = "declare_scalac_provider",
)
load("//scala:scala_toolchain.bzl", "scala_toolchain")
load(":scala_toolchain.bzl", "scala_toolchain")
load(":toolchains.bzl", "scala_toolchains")
load(":scala_repositories.bzl", "pin_targets", "unpin_targets")

toolchain_type(
name = "toolchain_type",
name = "bootstrap_toolchain_type",
visibility = ["//visibility:public"],
)

scala_toolchain(
name = "default_toolchain_impl",
scalacopts = [],
toolchain_type(
name = "toolchain_type",
visibility = ["//visibility:public"],
)

toolchain(
name = "default_toolchain",
toolchain = ":default_toolchain_impl",
toolchain_type = "@io_bazel_rules_scala//scala:toolchain_type",
toolchain_type(
name = "scalatest_toolchain_type",
visibility = ["//visibility:public"],
)

scala_toolchain(
name = "unused_dependency_checker_error_toolchain_impl",
unused_dependency_checker_mode = "error",
visibility = ["//visibility:public"],
)

toolchain(
name = "unused_dependency_checker_error_toolchain",
toolchain = ":unused_dependency_checker_error_toolchain_impl",
toolchain_type = "@io_bazel_rules_scala//scala:toolchain_type",
visibility = ["//visibility:public"],
)
scala_toolchains()

java_import(
name = "bazel_test_runner_deploy",
jars = ["@bazel_tools//tools/jdk:TestRunner_deploy.jar"],
visibility = ["//visibility:public"],
)

_declare_scalac_provider(
name = "scalac_default",
default_classpath = [
"@io_bazel_rules_scala_scala_library",
"@io_bazel_rules_scala_scala_reflect",
],
default_macro_classpath = [
"@io_bazel_rules_scala_scala_library",
"@io_bazel_rules_scala_scala_reflect",
],
default_repl_classpath = [
"@io_bazel_rules_scala_scala_library",
"@io_bazel_rules_scala_scala_reflect",
"@io_bazel_rules_scala_scala_compiler",
],
visibility = ["//visibility:public"],
)

java_library(
name = "PlaceHolderClassToCreateEmptyJarForScalaImport",
srcs = ["PlaceHolderClassToCreateEmptyJarForScalaImport.java"],
visibility = ["//visibility:public"],
)

genrule(
name = "pin",
srcs = [], #
outs = ["pin.sh"],
cmd = "echo $(location tools)",
executable = True,
tools = pin_targets(),
)
4 changes: 2 additions & 2 deletions scala/plusone.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ PlusOneDeps = provider(
)

def _collect_plus_one_deps_aspect_impl(target, ctx):
if (ctx.toolchains["@io_bazel_rules_scala//scala:toolchain_type"].plus_one_deps_mode == "off"):
if (ctx.toolchains["@io_bazel_rules_scala//scala:bootstrap_toolchain_type"].plus_one_deps_mode == "off"):
return []
export_plus_one_deps = []
for exported_dep in getattr(ctx.rule.attr, "exports", []):
Expand All @@ -22,6 +22,6 @@ collect_plus_one_deps_aspect = aspect(
implementation = _collect_plus_one_deps_aspect_impl,
attr_aspects = ["deps", "exports"],
toolchains = [
"@io_bazel_rules_scala//scala:toolchain_type",
"@io_bazel_rules_scala//scala:bootstrap_toolchain_type",
],
)
50 changes: 23 additions & 27 deletions scala/private/common_attributes.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ load(
)

common_attrs_for_plugin_bootstrapping = {
# "scala_toolchain": attr.label(),
"srcs": attr.label_list(allow_files = [
".scala",
".srcjar",
Expand Down Expand Up @@ -50,13 +51,13 @@ common_attrs.update({
# using stricts scala deps is done by using command line flag called 'strict_java_deps'
# switching mode to "on" means that ANY API change in a target's transitive dependencies will trigger a recompilation of that target,
# on the other hand any internal change (i.e. on code that ijar omits) WON’T trigger recompilation by transitive dependencies
"_dependency_analyzer_plugin": attr.label(
default = Label(
"@io_bazel_rules_scala//third_party/dependency_analyzer/src/main:dependency_analyzer",
),
allow_files = [".jar"],
mandatory = False,
),
# "_dependency_analyzer_plugin": attr.label(
# default = Label(
# "@io_bazel_rules_scala//third_party/dependency_analyzer/src/main:dependency_analyzer",
# ),
# allow_files = [".jar"],
# mandatory = False,
# ),
"unused_dependency_checker_mode": attr.string(
values = [
"warn",
Expand All @@ -66,13 +67,13 @@ common_attrs.update({
],
mandatory = False,
),
"_unused_dependency_checker_plugin": attr.label(
default = Label(
"@io_bazel_rules_scala//third_party/unused_dependency_checker/src/main:unused_dependency_checker",
),
allow_files = [".jar"],
mandatory = False,
),
# "_unused_dependency_checker_plugin": attr.label(
# default = Label(
# "@io_bazel_rules_scala//third_party/unused_dependency_checker/src/main:unused_dependency_checker",
# ),
# allow_files = [".jar"],
# mandatory = False,
# ),
"unused_dependency_checker_ignored_targets": attr.label_list(default = []),
"_code_coverage_instrumentation_worker": attr.label(
default = "@io_bazel_rules_scala//src/java/io/bazel/rulesscala/coverage/instrumenter",
Expand Down Expand Up @@ -105,11 +106,6 @@ implicit_deps = {
"_java_runtime": attr.label(
default = Label("@bazel_tools//tools/jdk:current_java_runtime"),
),
"_scalac": attr.label(
default = Label(
"@io_bazel_rules_scala//src/java/io/bazel/rulesscala/scalac",
),
),
"_exe": attr.label(
executable = True,
cfg = "host",
Expand All @@ -125,12 +121,12 @@ launcher_template = {

# Single dep to allow IDEs to pickup all the implicit dependencies.
resolve_deps = {
"_scala_toolchain": attr.label_list(
default = [
Label(
"//external:io_bazel_rules_scala/dependency/scala/scala_library",
),
],
allow_files = False,
),
# "_scala_toolchain": attr.label_list(
# default = [
# Label(
# "//external:io_bazel_rules_scala/dependency/scala/scala_library",
# ),
# ],
# allow_files = False,
# ),
}
12 changes: 10 additions & 2 deletions scala/private/coverage_replacements_provider.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,14 @@ _dependency_attributes = [
"exports",
]

def get_provider(ctx):
return ctx.toolchains["@io_bazel_rules_scala//scala:bootstrap_toolchain_type"]
if ctx.attr.toolchain:
return ctx.attr.toolchain[platform_common.ToolchainInfo]
else:
# print("E using default for", ctx)
return ctx.toolchains["@io_bazel_rules_scala//scala:bootstrap_toolchain_type"]

def _combine(*entriess, base = {}):
return _CombinedCoverageReplacements(replacements = _dicts_add(base, *(
[
Expand Down Expand Up @@ -67,14 +75,14 @@ def _aspect_impl(target, ctx):
_aspect = aspect(
attr_aspects = _dependency_attributes,
implementation = _aspect_impl,
toolchains = ["@io_bazel_rules_scala//scala:toolchain_type"],
toolchains = ["@io_bazel_rules_scala//scala:bootstrap_toolchain_type"],
)

def _is_enabled(ctx):
if "@io_bazel_rules_scala//scala:toolchain_type" not in ctx.toolchains:
return False
else:
return ctx.toolchains["@io_bazel_rules_scala//scala:toolchain_type"].enable_code_coverage_aspect == "on"
return get_provider(ctx).enable_code_coverage_aspect == "on"

coverage_replacements_provider = struct(
aspect = _aspect,
Expand Down
14 changes: 9 additions & 5 deletions scala/private/phases/api.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ load(
"@io_bazel_rules_scala//scala:advanced_usage/providers.bzl",
_ScalaRulePhase = "ScalaRulePhase",
)
load("@bazel_skylib//lib:dicts.bzl", "dicts")

# A method to modify the built-in phase list
# - Insert new phases to the first/last position
Expand Down Expand Up @@ -41,7 +42,7 @@ def _adjust_phases(phases, adjustments):
return phases

# Execute phases
def run_phases(ctx, builtin_customizable_phases, fixed_phase):
def run_phases(ctx, builtin_customizable_phases):
# Loading custom phases
# Phases must be passed in by provider
phase_providers = [
Expand All @@ -63,21 +64,24 @@ def run_phases(ctx, builtin_customizable_phases, fixed_phase):
# A placeholder for data shared with later phases
global_provider = {}
current_provider = struct(**global_provider)
acculmulated_external_providers = []
for (name, function) in adjusted_phases + [fixed_phase]:
acculmulated_external_providers = {}
for (name, function) in adjusted_phases:
# Run a phase
new_provider = function(ctx, current_provider)

# If a phase returns data, append it to global_provider
# for later phases to access
if new_provider != None:
if (hasattr(new_provider, "external_providers")):
acculmulated_external_providers.extend(new_provider.external_providers)
acculmulated_external_providers = dicts.add(
acculmulated_external_providers,
new_provider.external_providers,
)
global_provider[name] = new_provider
current_provider = struct(**global_provider)

# The final return of rules implementation
return acculmulated_external_providers + current_provider.final
return acculmulated_external_providers.values()

# A method to pass in phase provider
def extras_phases(extras):
Expand Down
Loading