diff --git a/BUILD.bazel b/BUILD.bazel new file mode 100644 index 000000000..e69de29bb diff --git a/WORKSPACE b/WORKSPACE index 708662bce..054ed1478 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -15,6 +15,10 @@ load("@com_github_bazelbuild_buildtools//buildifier:deps.bzl", "buildifier_depen buildifier_dependencies() +load("//scala:toolchains.bzl", "scala_register_toolchains") + +scala_register_toolchains() + load("//scala:scala.bzl", "scala_repositories") scala_repositories() diff --git a/private/example/App.scala b/private/example/App.scala new file mode 100644 index 000000000..79148dace --- /dev/null +++ b/private/example/App.scala @@ -0,0 +1,5 @@ +object App extends scala.App { + def version = scala.util.Properties.versionString + + println(s"hello, world from $version!") +} diff --git a/private/example/AppTest.scala b/private/example/AppTest.scala new file mode 100644 index 000000000..a7f9bf841 --- /dev/null +++ b/private/example/AppTest.scala @@ -0,0 +1,9 @@ +import org.scalatest._ + +class AppTest extends FlatSpec with Matchers { + it should "have a successful test" in { + System.err.println(s"hello, world from ${scala.util.Properties.versionString}!") + + App.version should be (scala.util.Properties.versionString) + } +} diff --git a/private/example/BUILD.bazel b/private/example/BUILD.bazel new file mode 100644 index 000000000..4fd5480ca --- /dev/null +++ b/private/example/BUILD.bazel @@ -0,0 +1,26 @@ +load( + "@io_bazel_rules_scala//scala:scala.bzl", + "scala_binary", + "scala_library", + "scala_test", +) + +scala_library( + name = "library", + srcs = glob( + ["*.scala"], + exclude = ["*Test.scala"], + ), +) + +scala_binary( + name = "app", + main_class = "App", + runtime_deps = [":library"], +) + +scala_test( + name = "test", + srcs = ["AppTest.scala"], + deps = [":library"], +) diff --git a/private/example/WORKSPACE b/private/example/WORKSPACE new file mode 100644 index 000000000..96a04949f --- /dev/null +++ b/private/example/WORKSPACE @@ -0,0 +1,27 @@ +load("//repositories:bazel_skylib.bzl", "load_bazel_skylib") + +load_bazel_skylib() + +load("//repositories:rules_jvm_external.bzl", "load_rules_jvm_external") + +load_rules_jvm_external() + +load("//repositories:rules_scala.bzl", "load_rules_scala") + +load_rules_scala() + +load("//repositories:rules_proto.bzl", "load_rules_proto") + +load_rules_proto() + +load("//repositories:rules_python.bzl", "load_rules_python") + +load_rules_python() + +load("@io_bazel_rules_scala//scala:toolchains.bzl", "scala_register_toolchains") + +scala_register_toolchains() + +load("@io_bazel_rules_scala//scala:scala.bzl", "scala_repositories") + +scala_repositories() diff --git a/private/example/repositories/BUILD.bazel b/private/example/repositories/BUILD.bazel new file mode 100644 index 000000000..e69de29bb diff --git a/private/example/repositories/bazel_skylib.bzl b/private/example/repositories/bazel_skylib.bzl new file mode 100644 index 000000000..e6477bed7 --- /dev/null +++ b/private/example/repositories/bazel_skylib.bzl @@ -0,0 +1,11 @@ +"""load skylib""" + +load(":tools.bzl", _github_release = "github_release") + +def load_bazel_skylib(): + _github_release( + name = "bazel_skylib", + sha256 = "97e70364e9249702246c0e9444bccdc4b847bed1eb03c5a3ece4f83dfe6abc44", + repository = "bazelbuild/bazel-skylib", + release = "1.0.2", + ) diff --git a/private/example/repositories/rules_jvm_external.bzl b/private/example/repositories/rules_jvm_external.bzl new file mode 100644 index 000000000..d68a0e2c4 --- /dev/null +++ b/private/example/repositories/rules_jvm_external.bzl @@ -0,0 +1,11 @@ +"""load rules_jvm_external""" + +load(":tools.bzl", _github_archive = "github_archive") + +def load_rules_jvm_external(): + _github_archive( + name = "rules_jvm_external", + repository = "bazelbuild/rules_jvm_external", + sha256 = "62133c125bf4109dfd9d2af64830208356ce4ef8b165a6ef15bbff7460b35c3a", + tag = "3.0", + ) diff --git a/private/example/repositories/rules_proto.bzl b/private/example/repositories/rules_proto.bzl new file mode 100644 index 000000000..bddf5cc67 --- /dev/null +++ b/private/example/repositories/rules_proto.bzl @@ -0,0 +1,11 @@ +"""load rules_proto: needed by protobuf repo""" + +load(":tools.bzl", _github_archive = "github_archive") + +def load_rules_proto(): + _github_archive( + name = "rules_proto", + repository = "bazelbuild/rules_proto", + sha256 = "62847ac7740865d73a2c8199be292bba913d62e79084442f3e829c3058a25e64", + tag = "d7666ec475c1f8d4a6803cbc0a0b6b4374360868", + ) diff --git a/private/example/repositories/rules_python.bzl b/private/example/repositories/rules_python.bzl new file mode 100644 index 000000000..9ab16594c --- /dev/null +++ b/private/example/repositories/rules_python.bzl @@ -0,0 +1,11 @@ +"""load rules_python: needed by protobuf repo""" + +load(":tools.bzl", _github_archive = "github_archive") + +def load_rules_python(): + _github_archive( + name = "rules_python", + repository = "bazelbuild/rules_python", + sha256 = "7d64815f4b22400bed0f1b9da663037e1578573446b7bc78f20f24b2b5459bb9", + tag = "38f86fb55b698c51e8510c807489c9f4e047480e", + ) diff --git a/private/example/repositories/rules_scala.bzl b/private/example/repositories/rules_scala.bzl new file mode 100644 index 000000000..3eb26a745 --- /dev/null +++ b/private/example/repositories/rules_scala.bzl @@ -0,0 +1,7 @@ +"""link back to parent rules_scala repo""" + +def load_rules_scala(): + native.local_repository( + name = "io_bazel_rules_scala", + path = "../..", + ) diff --git a/private/example/repositories/tools.bzl b/private/example/repositories/tools.bzl new file mode 100644 index 000000000..88f628714 --- /dev/null +++ b/private/example/repositories/tools.bzl @@ -0,0 +1,28 @@ +"""helpers for to remove http_archive boilerplate + +N.B.: doesn't currently include the bazel mirros +""" + +load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") + +def github_release(name, repository, release, sha256): + (org, repo) = repository.split("/") + http_archive( + name = name, + sha256 = sha256, + urls = [ + "https://github.com/{repository}/releases/download/{release}/{repo}-{release}.tar.gz".format(repository = repository, repo = repo, release = release), + ], + ) + +def github_archive(name, repository, sha256, tag): + (org, repo) = repository.split("/") + without_v = tag[1:] if tag.startswith("v") else tag + http_archive( + name = name, + sha256 = sha256, + strip_prefix = "{repo}-{without_v}".format(repo = repo, without_v = without_v), + urls = [ + "https://github.com/{repository}/archive/{tag}.zip".format(repository = repository, tag = tag), + ], + ) diff --git a/scala/BUILD b/scala/BUILD index a5c8f2416..efae634cc 100644 --- a/scala/BUILD +++ b/scala/BUILD @@ -1,8 +1,42 @@ -load( - "@io_bazel_rules_scala//scala:providers.bzl", - _declare_scalac_provider = "declare_scalac_provider", -) +load("//scala:bootstrap_toolchain.bzl", "bootstrap_toolchain") load("//scala:scala_toolchain.bzl", "scala_toolchain") +load("//scala:scala_test_toolchain.bzl", "scala_test_toolchain") + +# default toolchains registered by `scala_register_toolchains` + +# bootstrap toolchain + +toolchain_type( + name = "bootstrap_toolchain_type", + visibility = ["//visibility:public"], +) + +bootstrap_toolchain( + name = "bootstrap_toolchain_impl", + classpath = [ + "@io_bazel_rules_scala_scala_library", + "@io_bazel_rules_scala_scala_reflect", + ], + macro_classpath = [ + "@io_bazel_rules_scala_scala_library", + "@io_bazel_rules_scala_scala_reflect", + ], + repl_classpath = [ + "@io_bazel_rules_scala_scala_library", + "@io_bazel_rules_scala_scala_reflect", + "@io_bazel_rules_scala_scala_compiler", + ], + visibility = ["//visibility:public"], +) + +toolchain( + name = "bootstrap_toolchain", + toolchain = ":bootstrap_toolchain_impl", + toolchain_type = "@io_bazel_rules_scala//scala:bootstrap_toolchain_type", + visibility = ["//visibility:public"], +) + +# standard toolchain toolchain_type( name = "toolchain_type", @@ -10,20 +44,48 @@ toolchain_type( ) scala_toolchain( - name = "default_toolchain_impl", + name = "toolchain_impl", + scalac = "//src/java/io/bazel/rulesscala/scalac", scalacopts = [], visibility = ["//visibility:public"], ) toolchain( - name = "default_toolchain", - toolchain = ":default_toolchain_impl", + name = "toolchain", + toolchain = ":toolchain_impl", toolchain_type = "@io_bazel_rules_scala//scala:toolchain_type", visibility = ["//visibility:public"], ) +# test toolchain + +toolchain_type( + name = "scala_test_toolchain_type", + visibility = ["//visibility:public"], +) + +scala_test_toolchain( + name = "scala_test_toolchain_impl", + reporter = "//scala/support:test_reporter", + runner = "//src/java/io/bazel/rulesscala/scala_test:runner", + visibility = ["//visibility:public"], + deps = [ + "//external:io_bazel_rules_scala/dependency/scalatest/scalatest", + ], +) + +toolchain( + name = "scala_test_toolchain", + toolchain = ":scala_test_toolchain_impl", + toolchain_type = "@io_bazel_rules_scala//scala:scala_test_toolchain_type", + visibility = ["//visibility:public"], +) + +# unused dependency checker toolchain + scala_toolchain( name = "unused_dependency_checker_error_toolchain_impl", + scalac = "//src/java/io/bazel/rulesscala/scalac", unused_dependency_checker_mode = "error", visibility = ["//visibility:public"], ) @@ -41,24 +103,6 @@ java_import( 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"], diff --git a/scala/bootstrap_toolchain.bzl b/scala/bootstrap_toolchain.bzl new file mode 100644 index 000000000..b1b2628f8 --- /dev/null +++ b/scala/bootstrap_toolchain.bzl @@ -0,0 +1,27 @@ +BootstrapInfo = provider( + doc = "BootstrapInfo", + fields = [ + "classpath", + "macro_classpath", + "repl_classpath", + ], +) + +def _impl(ctx): + toolchain = platform_common.ToolchainInfo( + bootstrapinfo = BootstrapInfo( + classpath = ctx.attr.classpath, + macro_classpath = ctx.attr.macro_classpath, + repl_classpath = ctx.attr.repl_classpath, + ), + ) + return [toolchain] + +bootstrap_toolchain = rule( + _impl, + attrs = { + "classpath": attr.label_list(mandatory = True, allow_files = True), + "repl_classpath": attr.label_list(mandatory = True, allow_files = True), + "macro_classpath": attr.label_list(mandatory = True, allow_files = True), + }, +) diff --git a/scala/plusone.bzl b/scala/plusone.bzl index 1efd17093..fc858c894 100644 --- a/scala/plusone.bzl +++ b/scala/plusone.bzl @@ -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:toolchain_type"].scalainfo.plus_one_deps_mode == "off"): return [] export_plus_one_deps = [] for exported_dep in getattr(ctx.rule.attr, "exports", []): diff --git a/scala/private/common_attributes.bzl b/scala/private/common_attributes.bzl index bd6c3fc3c..09c4c3464 100644 --- a/scala/private/common_attributes.bzl +++ b/scala/private/common_attributes.bzl @@ -98,11 +98,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", diff --git a/scala/private/coverage_replacements_provider.bzl b/scala/private/coverage_replacements_provider.bzl index 3d45bf64b..da9cc4a13 100644 --- a/scala/private/coverage_replacements_provider.bzl +++ b/scala/private/coverage_replacements_provider.bzl @@ -74,7 +74,7 @@ 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 ctx.toolchains["@io_bazel_rules_scala//scala:toolchain_type"].scalainfo.enable_code_coverage_aspect == "on" coverage_replacements_provider = struct( aspect = _aspect, diff --git a/scala/private/macros/scala_repositories.bzl b/scala/private/macros/scala_repositories.bzl index a822993a3..2cdbbee63 100644 --- a/scala/private/macros/scala_repositories.bzl +++ b/scala/private/macros/scala_repositories.bzl @@ -199,3 +199,18 @@ def scala_repositories( name = "io_bazel_rules_scala/dependency/scala/guava", actual = "@io_bazel_rules_scala_guava", ) + + native.bind( + name = "io_bazel_rules_scala/dependency/scalac_rules_commons_io", + actual = "@scalac_rules_commons_io", + ) + + native.bind( + name = "io_bazel_rules_scala/dependency/scala/scalatest/scalatest", + actual = "@io_bazel_rules_scala_scalatest", + ) + + native.bind( + name = "io_bazel_rules_scala/dependency/scala/scalactic/scalactic", + actual = "@io_bazel_rules_scala_scalactic", + ) diff --git a/scala/private/phases/phase_collect_jars.bzl b/scala/private/phases/phase_collect_jars.bzl index d3d4fce9b..02e1035ff 100644 --- a/scala/private/phases/phase_collect_jars.bzl +++ b/scala/private/phases/phase_collect_jars.bzl @@ -14,24 +14,26 @@ load( ) def phase_collect_jars_scalatest(ctx, p): + boostrap_classpath = ctx.toolchains["@io_bazel_rules_scala//scala:bootstrap_toolchain_type"].bootstrapinfo.classpath + test_classpath = ctx.toolchains["@io_bazel_rules_scala//scala:scala_test_toolchain_type"].scalatestinfo.deps args = struct( - base_classpath = p.scalac_provider.default_classpath + [ctx.attr._scalatest], + base_classpath = boostrap_classpath + test_classpath, extra_runtime_deps = [ - ctx.attr._scalatest_reporter, - ctx.attr._scalatest_runner, + ctx.toolchains["@io_bazel_rules_scala//scala:scala_test_toolchain_type"].scalatestinfo.reporter, + ctx.toolchains["@io_bazel_rules_scala//scala:scala_test_toolchain_type"].scalatestinfo.runner, ], ) return _phase_collect_jars_default(ctx, p, args) def phase_collect_jars_repl(ctx, p): args = struct( - base_classpath = p.scalac_provider.default_repl_classpath, + base_classpath = ctx.toolchains["@io_bazel_rules_scala//scala:bootstrap_toolchain_type"].bootstrapinfo.repl_classpath, ) return _phase_collect_jars_default(ctx, p, args) def phase_collect_jars_macro_library(ctx, p): args = struct( - base_classpath = p.scalac_provider.default_macro_classpath, + base_classpath = ctx.toolchains["@io_bazel_rules_scala//scala:bootstrap_toolchain_type"].bootstrapinfo.macro_classpath, ) return _phase_collect_jars_default(ctx, p, args) @@ -58,7 +60,7 @@ def phase_collect_jars_common(ctx, p): def _phase_collect_jars_default(ctx, p, _args = struct()): return _phase_collect_jars( ctx, - _args.base_classpath if hasattr(_args, "base_classpath") else p.scalac_provider.default_classpath, + _args.base_classpath if hasattr(_args, "base_classpath") else ctx.toolchains["@io_bazel_rules_scala//scala:bootstrap_toolchain_type"].bootstrapinfo.classpath, _args.extra_deps if hasattr(_args, "extra_deps") else [], _args.extra_runtime_deps if hasattr(_args, "extra_runtime_deps") else [], _args.unused_dependency_checker_mode if hasattr(_args, "unused_dependency_checker_mode") else p.unused_deps_checker, diff --git a/scala/private/phases/phase_compile.bzl b/scala/private/phases/phase_compile.bzl index 1e730a574..f8d8106d4 100644 --- a/scala/private/phases/phase_compile.bzl +++ b/scala/private/phases/phase_compile.bzl @@ -35,7 +35,7 @@ def phase_compile_binary(ctx, p): buildijar = False, unused_dependency_checker_ignored_targets = [ target.label - for target in p.scalac_provider.default_classpath + + for target in ctx.toolchains["@io_bazel_rules_scala//scala:bootstrap_toolchain_type"].bootstrapinfo.classpath + ctx.attr.unused_dependency_checker_ignored_targets ], ) @@ -46,7 +46,7 @@ def phase_compile_library(ctx, p): srcjars = p.collect_srcjars, unused_dependency_checker_ignored_targets = [ target.label - for target in p.scalac_provider.default_classpath + ctx.attr.exports + + for target in ctx.toolchains["@io_bazel_rules_scala//scala:bootstrap_toolchain_type"].bootstrapinfo.classpath + ctx.attr.exports + ctx.attr.unused_dependency_checker_ignored_targets ], ) @@ -56,7 +56,7 @@ def phase_compile_library_for_plugin_bootstrapping(ctx, p): args = struct( unused_dependency_checker_ignored_targets = [ target.label - for target in p.scalac_provider.default_classpath + ctx.attr.exports + for target in ctx.toolchains["@io_bazel_rules_scala//scala:bootstrap_toolchain_type"].bootstrapinfo.classpath + ctx.attr.exports ], unused_dependency_checker_mode = "off", ) @@ -67,7 +67,7 @@ def phase_compile_macro_library(ctx, p): buildijar = False, unused_dependency_checker_ignored_targets = [ target.label - for target in p.scalac_provider.default_macro_classpath + ctx.attr.exports + + for target in ctx.toolchains["@io_bazel_rules_scala//scala:bootstrap_toolchain_type"].bootstrapinfo.macro_classpath + ctx.attr.exports + ctx.attr.unused_dependency_checker_ignored_targets ], ) @@ -82,7 +82,7 @@ def phase_compile_junit_test(ctx, p): ], unused_dependency_checker_ignored_targets = [ target.label - for target in p.scalac_provider.default_classpath + + for target in ctx.toolchains["@io_bazel_rules_scala//scala:bootstrap_toolchain_type"].bootstrapinfo.classpath + ctx.attr.unused_dependency_checker_ignored_targets ] + [ ctx.attr._junit.label, @@ -98,7 +98,7 @@ def phase_compile_repl(ctx, p): buildijar = False, unused_dependency_checker_ignored_targets = [ target.label - for target in p.scalac_provider.default_repl_classpath + + for target in ctx.toolchains["@io_bazel_rules_scala//scala:bootstrap_toolchain_type"].bootstrapinfo.repl_classpath + ctx.attr.unused_dependency_checker_ignored_targets ], ) @@ -109,7 +109,7 @@ def phase_compile_scalatest(ctx, p): buildijar = False, unused_dependency_checker_ignored_targets = [ target.label - for target in p.scalac_provider.default_classpath + + for target in ctx.toolchains["@io_bazel_rules_scala//scala:bootstrap_toolchain_type"].bootstrapinfo.classpath + ctx.attr.unused_dependency_checker_ignored_targets ], ) @@ -144,7 +144,7 @@ def _phase_compile( transitive_compile_jars = p.collect_jars.transitive_compile_jars jars2labels = p.collect_jars.jars2labels.jars_to_labels deps_providers = p.collect_jars.deps_providers - default_classpath = p.scalac_provider.default_classpath + default_classpath = ctx.toolchains["@io_bazel_rules_scala//scala:bootstrap_toolchain_type"].bootstrapinfo.classpath out = _compile_or_empty( ctx, @@ -228,7 +228,6 @@ def _compile_or_empty( ctx.attr.print_compile_time, ctx.attr.expect_java_output, ctx.attr.scalac_jvm_flags, - ctx.attr._scalac, unused_dependency_checker_ignored_targets = unused_dependency_checker_ignored_targets, unused_dependency_checker_mode = unused_dependency_checker_mode, diff --git a/scala/private/phases/phase_scalac_provider.bzl b/scala/private/phases/phase_scalac_provider.bzl deleted file mode 100644 index aff54f32f..000000000 --- a/scala/private/phases/phase_scalac_provider.bzl +++ /dev/null @@ -1,12 +0,0 @@ -# -# PHASE: scalac provider -# -# DOCUMENT THIS -# -load( - "@io_bazel_rules_scala//scala:providers.bzl", - _ScalacProvider = "ScalacProvider", -) - -def phase_scalac_provider(ctx, p): - return ctx.toolchains["@io_bazel_rules_scala//scala:toolchain_type"].scalac_provider_attr[_ScalacProvider] diff --git a/scala/private/phases/phase_unused_deps_checker.bzl b/scala/private/phases/phase_unused_deps_checker.bzl index 21f0daebb..6529e7b35 100644 --- a/scala/private/phases/phase_unused_deps_checker.bzl +++ b/scala/private/phases/phase_unused_deps_checker.bzl @@ -8,4 +8,4 @@ def phase_unused_deps_checker(ctx, p): if ctx.attr.unused_dependency_checker_mode: return ctx.attr.unused_dependency_checker_mode else: - return ctx.toolchains["@io_bazel_rules_scala//scala:toolchain_type"].unused_dependency_checker_mode + return ctx.toolchains["@io_bazel_rules_scala//scala:toolchain_type"].scalainfo.unused_dependency_checker_mode diff --git a/scala/private/phases/phase_write_executable.bzl b/scala/private/phases/phase_write_executable.bzl index 3c8c11fbc..e92602243 100644 --- a/scala/private/phases/phase_write_executable.bzl +++ b/scala/private/phases/phase_write_executable.bzl @@ -21,7 +21,7 @@ def phase_write_executable_scalatest(ctx, p): # toolchain final_jvm_flags = first_non_empty( ctx.attr.jvm_flags, - ctx.toolchains["@io_bazel_rules_scala//scala:toolchain_type"].scala_test_jvm_flags, + ctx.toolchains["@io_bazel_rules_scala//scala:scala_test_toolchain_type"].scalatestinfo.scala_test_jvm_flags, ) args = struct( rjars = p.coverage_runfiles.rjars, diff --git a/scala/private/phases/phases.bzl b/scala/private/phases/phases.bzl index cc2396684..b18798da5 100644 --- a/scala/private/phases/phases.bzl +++ b/scala/private/phases/phases.bzl @@ -46,7 +46,6 @@ load( _phase_runfiles_scalatest = "phase_runfiles_scalatest", ) load("@io_bazel_rules_scala//scala/private:phases/phase_default_info.bzl", _phase_default_info = "phase_default_info") -load("@io_bazel_rules_scala//scala/private:phases/phase_scalac_provider.bzl", _phase_scalac_provider = "phase_scalac_provider") load("@io_bazel_rules_scala//scala/private:phases/phase_write_manifest.bzl", _phase_write_manifest = "phase_write_manifest") load("@io_bazel_rules_scala//scala/private:phases/phase_collect_srcjars.bzl", _phase_collect_srcjars = "phase_collect_srcjars") load("@io_bazel_rules_scala//scala/private:phases/phase_collect_exports_jars.bzl", _phase_collect_exports_jars = "phase_collect_exports_jars") @@ -61,9 +60,6 @@ load("@io_bazel_rules_scala//scala/private:phases/phase_scalafmt.bzl", _phase_sc run_phases = _run_phases extras_phases = _extras_phases -# scalac_provider -phase_scalac_provider = _phase_scalac_provider - # collect_srcjars phase_collect_srcjars = _phase_collect_srcjars diff --git a/scala/private/rule_impls.bzl b/scala/private/rule_impls.bzl index 68f16eeba..dd556b082 100644 --- a/scala/private/rule_impls.bzl +++ b/scala/private/rule_impls.bzl @@ -60,7 +60,6 @@ def compile_scala( print_compile_time, expect_java_output, scalac_jvm_flags, - scalac, unused_dependency_checker_mode = "off", unused_dependency_checker_ignored_targets = []): # look for any plugins: @@ -136,7 +135,7 @@ CurrentTarget: {current_target} compiler_classpath = _join_path(compiler_classpath_jars.to_list(), separator) toolchain = ctx.toolchains["@io_bazel_rules_scala//scala:toolchain_type"] - scalacopts = [ctx.expand_location(v, input_plugins) for v in toolchain.scalacopts + in_scalacopts] + scalacopts = [ctx.expand_location(v, input_plugins) for v in toolchain.scalainfo.scalacopts + in_scalacopts] resource_paths = _resource_paths(resources, resource_strip_prefix) scalac_args = """ @@ -187,7 +186,7 @@ StatsfileOutput: {statsfile_output} ) scalac_inputs, _, scalac_input_manifests = ctx.resolve_command( - tools = [scalac], + tools = [ctx.toolchains["@io_bazel_rules_scala//scala:toolchain_type"].scalainfo.scalac], ) outs = [output, statsfile] @@ -197,17 +196,19 @@ StatsfileOutput: {statsfile_output} resource_jars + [manifest, argfile] + scalac_inputs ) + scalainfo = ctx.toolchains["@io_bazel_rules_scala//scala:toolchain_type"].scalainfo + # scalac_jvm_flags passed in on the target override scalac_jvm_flags passed in on the # toolchain final_scalac_jvm_flags = first_non_empty( scalac_jvm_flags, - ctx.toolchains["@io_bazel_rules_scala//scala:toolchain_type"].scalac_jvm_flags, + scalainfo.scalac_jvm_flags, ) ctx.actions.run( inputs = ins, outputs = outs, - executable = scalac.files_to_run.executable, + executable = scalainfo.scalac.files_to_run.executable, input_manifests = scalac_input_manifests, mnemonic = "Scalac", progress_message = "scala %s" % target_label, @@ -250,7 +251,7 @@ def is_dependency_analyzer_off(ctx): return not is_dependency_analyzer_on(ctx) def is_plus_one_deps_off(ctx): - return ctx.toolchains["@io_bazel_rules_scala//scala:toolchain_type"].plus_one_deps_mode == "off" + return ctx.toolchains["@io_bazel_rules_scala//scala:toolchain_type"].scalainfo.plus_one_deps_mode == "off" def is_windows(ctx): return ctx.configuration.host_path_separator == ";" diff --git a/scala/private/rules/scala_binary.bzl b/scala/private/rules/scala_binary.bzl index 07afd2574..9b8d3261a 100644 --- a/scala/private/rules/scala_binary.bzl +++ b/scala/private/rules/scala_binary.bzl @@ -19,7 +19,6 @@ load( "phase_java_wrapper_common", "phase_merge_jars", "phase_runfiles_common", - "phase_scalac_provider", "phase_unused_deps_checker", "phase_write_executable_common", "phase_write_manifest", @@ -31,7 +30,6 @@ def _scala_binary_impl(ctx): ctx, # customizable phases [ - ("scalac_provider", phase_scalac_provider), ("write_manifest", phase_write_manifest), ("unused_deps_checker", phase_unused_deps_checker), ("collect_jars", phase_collect_jars_common), @@ -73,7 +71,10 @@ def make_scala_binary(*extras): common_outputs, *[extra["outputs"] for extra in extras if "outputs" in extra] ), - toolchains = ["@io_bazel_rules_scala//scala:toolchain_type"], + toolchains = [ + "@io_bazel_rules_scala//scala:bootstrap_toolchain_type", + "@io_bazel_rules_scala//scala:toolchain_type", + ], implementation = _scala_binary_impl, ) diff --git a/scala/private/rules/scala_junit_test.bzl b/scala/private/rules/scala_junit_test.bzl index 8b58180b7..c70fbc39b 100644 --- a/scala/private/rules/scala_junit_test.bzl +++ b/scala/private/rules/scala_junit_test.bzl @@ -19,7 +19,6 @@ load( "phase_jvm_flags", "phase_merge_jars", "phase_runfiles_common", - "phase_scalac_provider", "phase_unused_deps_checker", "phase_write_executable_junit_test", "phase_write_manifest", @@ -35,7 +34,6 @@ def _scala_junit_test_impl(ctx): ctx, # customizable phases [ - ("scalac_provider", phase_scalac_provider), ("write_manifest", phase_write_manifest), ("unused_deps_checker", phase_unused_deps_checker), ("collect_jars", phase_collect_jars_junit_test), @@ -125,7 +123,13 @@ def make_scala_junit_test(*extras): *[extra["outputs"] for extra in extras if "outputs" in extra] ), test = True, - toolchains = ["@io_bazel_rules_scala//scala:toolchain_type"], + toolchains = [ + "@io_bazel_rules_scala//scala:bootstrap_toolchain_type", + "@io_bazel_rules_scala//scala:toolchain_type", + # unclear on next and will consider in factoring, whether + # scalatest and junit tests should be different toolchain types + "@io_bazel_rules_scala//scala:scala_test_toolchain_type", + ], implementation = _scala_junit_test_impl, ) diff --git a/scala/private/rules/scala_library.bzl b/scala/private/rules/scala_library.bzl index 17356b843..0ffe81b46 100644 --- a/scala/private/rules/scala_library.bzl +++ b/scala/private/rules/scala_library.bzl @@ -29,7 +29,6 @@ load( "phase_default_info", "phase_merge_jars", "phase_runfiles_library", - "phase_scalac_provider", "phase_unused_deps_checker", "phase_write_manifest", "run_phases", @@ -57,7 +56,6 @@ def _scala_library_impl(ctx): ctx, # customizable phases [ - ("scalac_provider", phase_scalac_provider), ("collect_srcjars", phase_collect_srcjars), ("write_manifest", phase_write_manifest), ("unused_deps_checker", phase_unused_deps_checker), @@ -92,7 +90,10 @@ def make_scala_library(*extras): common_outputs, *[extra["outputs"] for extra in extras if "outputs" in extra] ), - toolchains = ["@io_bazel_rules_scala//scala:toolchain_type"], + toolchains = [ + "@io_bazel_rules_scala//scala:bootstrap_toolchain_type", + "@io_bazel_rules_scala//scala:toolchain_type", + ], implementation = _scala_library_impl, ) @@ -134,7 +135,6 @@ def _scala_library_for_plugin_bootstrapping_impl(ctx): ctx, # customizable phases [ - ("scalac_provider", phase_scalac_provider), ("collect_srcjars", phase_collect_srcjars), ("write_manifest", phase_write_manifest), ("collect_jars", phase_collect_jars_library_for_plugin_bootstrapping), @@ -173,7 +173,10 @@ def make_scala_library_for_plugin_bootstrapping(*extras): common_outputs, *[extra["outputs"] for extra in extras if "outputs" in extra] ), - toolchains = ["@io_bazel_rules_scala//scala:toolchain_type"], + toolchains = [ + "@io_bazel_rules_scala//scala:bootstrap_toolchain_type", + "@io_bazel_rules_scala//scala:toolchain_type", + ], implementation = _scala_library_for_plugin_bootstrapping_impl, ) @@ -188,7 +191,6 @@ def _scala_macro_library_impl(ctx): ctx, # customizable phases [ - ("scalac_provider", phase_scalac_provider), ("collect_srcjars", phase_collect_srcjars), ("write_manifest", phase_write_manifest), ("unused_deps_checker", phase_unused_deps_checker), @@ -238,7 +240,10 @@ def make_scala_macro_library(*extras): common_outputs, *[extra["outputs"] for extra in extras if "outputs" in extra] ), - toolchains = ["@io_bazel_rules_scala//scala:toolchain_type"], + toolchains = [ + "@io_bazel_rules_scala//scala:bootstrap_toolchain_type", + "@io_bazel_rules_scala//scala:toolchain_type", + ], implementation = _scala_macro_library_impl, ) diff --git a/scala/private/rules/scala_repl.bzl b/scala/private/rules/scala_repl.bzl index 3d508af45..3aa3bd770 100644 --- a/scala/private/rules/scala_repl.bzl +++ b/scala/private/rules/scala_repl.bzl @@ -19,7 +19,6 @@ load( "phase_java_wrapper_repl", "phase_merge_jars", "phase_runfiles_common", - "phase_scalac_provider", "phase_unused_deps_checker", "phase_write_executable_repl", "phase_write_manifest", @@ -31,7 +30,6 @@ def _scala_repl_impl(ctx): ctx, # customizable phases [ - ("scalac_provider", phase_scalac_provider), ("write_manifest", phase_write_manifest), ("unused_deps_checker", phase_unused_deps_checker), # need scala-compiler for MainGenericRunner below @@ -72,7 +70,10 @@ def make_scala_repl(*extras): common_outputs, *[extra["outputs"] for extra in extras if "outputs" in extra] ), - toolchains = ["@io_bazel_rules_scala//scala:toolchain_type"], + toolchains = [ + "@io_bazel_rules_scala//scala:bootstrap_toolchain_type", + "@io_bazel_rules_scala//scala:toolchain_type", + ], implementation = _scala_repl_impl, ) diff --git a/scala/private/rules/scala_test.bzl b/scala/private/rules/scala_test.bzl index 1a6bd3e7d..a67775704 100644 --- a/scala/private/rules/scala_test.bzl +++ b/scala/private/rules/scala_test.bzl @@ -20,7 +20,6 @@ load( "phase_java_wrapper_common", "phase_merge_jars", "phase_runfiles_scalatest", - "phase_scalac_provider", "phase_unused_deps_checker", "phase_write_executable_scalatest", "phase_write_manifest", @@ -32,7 +31,6 @@ def _scala_test_impl(ctx): ctx, # customizable phases [ - ("scalac_provider", phase_scalac_provider), ("write_manifest", phase_write_manifest), ("unused_deps_checker", phase_unused_deps_checker), ("collect_jars", phase_collect_jars_scalatest), @@ -55,18 +53,6 @@ _scala_test_attrs = { "colors": attr.bool(default = True), "full_stacktraces": attr.bool(default = True), "jvm_flags": attr.string_list(), - "_scalatest": attr.label( - default = Label( - "//external:io_bazel_rules_scala/dependency/scalatest/scalatest", - ), - ), - "_scalatest_runner": attr.label( - cfg = "host", - default = Label("//src/java/io/bazel/rulesscala/scala_test:runner"), - ), - "_scalatest_reporter": attr.label( - default = Label("//scala/support:test_reporter"), - ), "_jacocorunner": attr.label( default = Label("@bazel_tools//tools/jdk:JacocoCoverage"), ), @@ -111,7 +97,11 @@ def make_scala_test(*extras): *[extra["outputs"] for extra in extras if "outputs" in extra] ), test = True, - toolchains = ["@io_bazel_rules_scala//scala:toolchain_type"], + toolchains = [ + "@io_bazel_rules_scala//scala:bootstrap_toolchain_type", + "@io_bazel_rules_scala//scala:toolchain_type", + "@io_bazel_rules_scala//scala:scala_test_toolchain_type", + ], implementation = _scala_test_impl, ) diff --git a/scala/providers.bzl b/scala/providers.bzl deleted file mode 100644 index 66fc97f0b..000000000 --- a/scala/providers.bzl +++ /dev/null @@ -1,26 +0,0 @@ -ScalacProvider = provider( - doc = "ScalacProvider", - fields = [ - "default_classpath", - "default_macro_classpath", - "default_repl_classpath", - ], -) - -def _declare_scalac_provider(ctx): - return [ - ScalacProvider( - default_classpath = ctx.attr.default_classpath, - default_repl_classpath = ctx.attr.default_repl_classpath, - default_macro_classpath = ctx.attr.default_macro_classpath, - ), - ] - -declare_scalac_provider = rule( - implementation = _declare_scalac_provider, - attrs = { - "default_classpath": attr.label_list(allow_files = True), - "default_repl_classpath": attr.label_list(allow_files = True), - "default_macro_classpath": attr.label_list(allow_files = True), - }, -) diff --git a/scala/scala_test_toolchain.bzl b/scala/scala_test_toolchain.bzl new file mode 100644 index 000000000..767d88c60 --- /dev/null +++ b/scala/scala_test_toolchain.bzl @@ -0,0 +1,34 @@ +ScalaTestInfo = provider( + doc = "ScalaTestInfo", + fields = [ + "deps", + "reporter", + "runner", + "scala_test_jvm_flags", + ], +) + +def _scala_test_toolchain_impl(ctx): + scalatestinfo = ScalaTestInfo( + deps = ctx.attr.deps, + reporter = ctx.attr.reporter, + runner = ctx.attr.runner, + scala_test_jvm_flags = ctx.attr.scala_test_jvm_flags, + ) + toolchain = platform_common.ToolchainInfo( + scalatestinfo = scalatestinfo, + ) + return [toolchain] + +scala_test_toolchain = rule( + _scala_test_toolchain_impl, + attrs = { + "deps": attr.label_list( + providers = [JavaInfo], + mandatory = True, + ), + "reporter": attr.label(mandatory = True), + "runner": attr.label(mandatory = True), + "scala_test_jvm_flags": attr.string_list(), + }, +) diff --git a/scala/scala_toolchain.bzl b/scala/scala_toolchain.bzl index f57e23302..574582527 100644 --- a/scala/scala_toolchain.bzl +++ b/scala/scala_toolchain.bzl @@ -1,28 +1,33 @@ -load( - "@io_bazel_rules_scala//scala:providers.bzl", - _ScalacProvider = "ScalacProvider", +ScalaInfo = provider( + doc = "ScalaInfo", + fields = [ + "scalacopts", + "unused_dependency_checker_mode", + "plus_one_deps_mode", + "enable_code_coverage_aspect", + "scalac_jvm_flags", + "scalac", + ], ) def _scala_toolchain_impl(ctx): - toolchain = platform_common.ToolchainInfo( + scalainfo = ScalaInfo( scalacopts = ctx.attr.scalacopts, - scalac_provider_attr = ctx.attr.scalac_provider_attr, unused_dependency_checker_mode = ctx.attr.unused_dependency_checker_mode, plus_one_deps_mode = ctx.attr.plus_one_deps_mode, enable_code_coverage_aspect = ctx.attr.enable_code_coverage_aspect, scalac_jvm_flags = ctx.attr.scalac_jvm_flags, - scala_test_jvm_flags = ctx.attr.scala_test_jvm_flags, + scalac = ctx.attr.scalac, + ) + toolchain = platform_common.ToolchainInfo( + scalainfo = scalainfo, ) - return [toolchain] + return [toolchain, platform_common.TemplateVariableInfo({})] scala_toolchain = rule( _scala_toolchain_impl, attrs = { "scalacopts": attr.string_list(), - "scalac_provider_attr": attr.label( - default = "@io_bazel_rules_scala//scala:scalac_default", - providers = [_ScalacProvider], - ), "unused_dependency_checker_mode": attr.string( default = "off", values = ["off", "warn", "error"], @@ -36,6 +41,6 @@ scala_toolchain = rule( values = ["off", "on"], ), "scalac_jvm_flags": attr.string_list(), - "scala_test_jvm_flags": attr.string_list(), + "scalac": attr.label(mandatory = True, allow_files = True), }, ) diff --git a/scala/scalatest/BUILD b/scala/scalatest/BUILD index 2e4ad67bb..4e7439e96 100644 --- a/scala/scalatest/BUILD +++ b/scala/scalatest/BUILD @@ -6,7 +6,7 @@ scala_import( name = "scalatest", jars = [], exports = [ - "@io_bazel_rules_scala_scalactic", - "@io_bazel_rules_scala_scalatest", + "//external:io_bazel_rules_scala/dependency/scala/scalactic/scalactic", + "//external:io_bazel_rules_scala/dependency/scala/scalatest/scalatest", ], ) diff --git a/scala/toolchains.bzl b/scala/toolchains.bzl index 89a2bdc08..c4f438f50 100644 --- a/scala/toolchains.bzl +++ b/scala/toolchains.bzl @@ -1,5 +1,7 @@ def scala_register_toolchains(): - native.register_toolchains("@io_bazel_rules_scala//scala:default_toolchain") + native.register_toolchains("@io_bazel_rules_scala//scala:bootstrap_toolchain") + native.register_toolchains("@io_bazel_rules_scala//scala:toolchain") + native.register_toolchains("@io_bazel_rules_scala//scala:scala_test_toolchain") def scala_register_unused_deps_toolchains(): native.register_toolchains( diff --git a/scala_proto/default_dep_sets.bzl b/scala_proto/default_dep_sets.bzl index 345890cd8..6a5878727 100644 --- a/scala_proto/default_dep_sets.bzl +++ b/scala_proto/default_dep_sets.bzl @@ -11,7 +11,6 @@ DEFAULT_SCALAPB_COMPILE_DEPS = [ "//external:io_bazel_rules_scala/dependency/com_google_protobuf/protobuf_java", "//external:io_bazel_rules_scala/dependency/proto/scalapb_lenses", "//external:io_bazel_rules_scala/dependency/proto/scalapb_fastparse", - "//external:io_bazel_rules_scala/dependency/scala/scala_library", ] DEFAULT_SCALAPB_GRPC_DEPS = [ diff --git a/scala_proto/private/scalapb_aspect.bzl b/scala_proto/private/scalapb_aspect.bzl index 0d51cfb65..47c7605f2 100644 --- a/scala_proto/private/scalapb_aspect.bzl +++ b/scala_proto/private/scalapb_aspect.bzl @@ -46,7 +46,6 @@ def _compiled_jar_file(actions, scalapb_jar): def _compile_scala( ctx, - scalac, label, output, scalapb_jar, @@ -88,7 +87,6 @@ def _compile_scala( print_compile_time = False, expect_java_output = False, scalac_jvm_flags = [], - scalac = scalac, ) return JavaInfo( @@ -134,8 +132,9 @@ def _scalapb_aspect_impl(target, ctx): transitive_protos = sorted(target_ti.transitive_sources.to_list()) toolchain = ctx.toolchains["@io_bazel_rules_scala//scala_proto:toolchain_type"] + boostrap_toolchain = ctx.toolchains["@io_bazel_rules_scala//scala:bootstrap_toolchain_type"] flags = [] - imps = [j[JavaInfo] for j in ctx.attr._implicit_compile_deps] + imps = [j[JavaInfo] for j in ctx.attr._implicit_compile_deps + boostrap_toolchain.bootstrapinfo.classpath] if toolchain.with_grpc: flags.append("grpc") @@ -189,7 +188,6 @@ def _scalapb_aspect_impl(target, ctx): outs = depset([output]) java_info = _compile_scala( ctx, - toolchain.scalac, target.label, output, scalapb_file, @@ -236,6 +234,7 @@ scalapb_aspect = aspect( ]), }, toolchains = [ + "@io_bazel_rules_scala//scala:bootstrap_toolchain_type", "@io_bazel_rules_scala//scala:toolchain_type", "@io_bazel_rules_scala//scala_proto:toolchain_type", ], diff --git a/scala_proto/scala_proto_toolchain.bzl b/scala_proto/scala_proto_toolchain.bzl index a733a2fbf..1ef1ad98e 100644 --- a/scala_proto/scala_proto_toolchain.bzl +++ b/scala_proto/scala_proto_toolchain.bzl @@ -1,5 +1,3 @@ -load("//scala_proto:default_dep_sets.bzl", "DEFAULT_SCALAPB_COMPILE_DEPS", "DEFAULT_SCALAPB_GRPC_DEPS") - def _scala_proto_toolchain_impl(ctx): toolchain = platform_common.ToolchainInfo( with_grpc = ctx.attr.with_grpc, @@ -8,7 +6,6 @@ def _scala_proto_toolchain_impl(ctx): blacklisted_protos = ctx.attr.blacklisted_protos, code_generator = ctx.attr.code_generator, extra_generator_dependencies = ctx.attr.extra_generator_dependencies, - scalac = ctx.attr.scalac, named_generators = ctx.attr.named_generators, ) return [toolchain] @@ -36,10 +33,5 @@ scala_proto_toolchain = rule( "extra_generator_dependencies": attr.label_list( providers = [JavaInfo], ), - "scalac": attr.label( - default = Label( - "@io_bazel_rules_scala//src/java/io/bazel/rulesscala/scalac", - ), - ), }, ) diff --git a/src/java/io/bazel/rulesscala/scalac/BUILD b/src/java/io/bazel/rulesscala/scalac/BUILD index ec7f89795..272cf2995 100644 --- a/src/java/io/bazel/rulesscala/scalac/BUILD +++ b/src/java/io/bazel/rulesscala/scalac/BUILD @@ -1,9 +1,9 @@ load( ":jvm_export_toolchain.bzl", - _export_scalac_repositories_from_toolchain_to_jvm = "export_scalac_repositories_from_toolchain_to_jvm", + "export_scalac_repositories_from_toolchain_to_jvm", ) -_export_scalac_repositories_from_toolchain_to_jvm( +export_scalac_repositories_from_toolchain_to_jvm( name = "exported_scalac_repositories_from_toolchain_to_jvm", ) @@ -20,10 +20,10 @@ java_binary( visibility = ["//visibility:public"], deps = [ ":exported_scalac_repositories_from_toolchain_to_jvm", + "//external:io_bazel_rules_scala/dependency/scalac_rules_commons_io", "//third_party/bazel/src/main/protobuf:worker_protocol_java_proto", "@io_bazel_rules_scala//src/java/io/bazel/rulesscala/jar", "@io_bazel_rules_scala//src/java/io/bazel/rulesscala/worker", - "@scalac_rules_commons_io//jar", ], ) diff --git a/src/java/io/bazel/rulesscala/scalac/jvm_export_toolchain.bzl b/src/java/io/bazel/rulesscala/scalac/jvm_export_toolchain.bzl index 6636a3add..9075fcc7d 100644 --- a/src/java/io/bazel/rulesscala/scalac/jvm_export_toolchain.bzl +++ b/src/java/io/bazel/rulesscala/scalac/jvm_export_toolchain.bzl @@ -1,8 +1,3 @@ -load( - "@io_bazel_rules_scala//scala:providers.bzl", - _ScalacProvider = "ScalacProvider", -) - def _files_of(deps): files = [] for dep in deps: @@ -10,7 +5,7 @@ def _files_of(deps): return depset(transitive = files) def _export_scalac_repositories_from_toolchain_to_jvm_impl(ctx): - default_repl_classpath_deps = ctx.toolchains["@io_bazel_rules_scala//scala:toolchain_type"].scalac_provider_attr[_ScalacProvider].default_repl_classpath + default_repl_classpath_deps = ctx.toolchains["@io_bazel_rules_scala//scala:bootstrap_toolchain_type"].bootstrapinfo.repl_classpath default_repl_classpath_files = _files_of( default_repl_classpath_deps, ).to_list() @@ -19,5 +14,5 @@ def _export_scalac_repositories_from_toolchain_to_jvm_impl(ctx): export_scalac_repositories_from_toolchain_to_jvm = rule( _export_scalac_repositories_from_toolchain_to_jvm_impl, - toolchains = ["@io_bazel_rules_scala//scala:toolchain_type"], + toolchains = ["@io_bazel_rules_scala//scala:bootstrap_toolchain_type"], ) diff --git a/test/coverage/BUILD b/test/coverage/BUILD index 1d3cc583b..0adeeb6f6 100644 --- a/test/coverage/BUILD +++ b/test/coverage/BUILD @@ -4,6 +4,7 @@ load("//scala:scala_toolchain.bzl", "scala_toolchain") scala_toolchain( name = "enable_code_coverage_aspect_impl", enable_code_coverage_aspect = "on", + scalac = "//src/java/io/bazel/rulesscala/scalac", visibility = ["//visibility:public"], ) diff --git a/test/src/main/scala/scalarules/test/twitter_scrooge/twitter_scrooge_test.bzl b/test/src/main/scala/scalarules/test/twitter_scrooge/twitter_scrooge_test.bzl index 8432659fc..1805d642c 100644 --- a/test/src/main/scala/scalarules/test/twitter_scrooge/twitter_scrooge_test.bzl +++ b/test/src/main/scala/scalarules/test/twitter_scrooge/twitter_scrooge_test.bzl @@ -1,4 +1,4 @@ -load("@bazel_skylib//:lib.bzl", "asserts", "unittest") +load("@bazel_skylib//lib:unittest.bzl", "asserts", "unittest") load("//twitter_scrooge:twitter_scrooge.bzl", "scrooge_scala_library") load("//thrift:thrift.bzl", "thrift_library") diff --git a/third_party/dependency_analyzer/src/test/BUILD b/third_party/dependency_analyzer/src/test/BUILD index 659c7ed06..def70457f 100644 --- a/third_party/dependency_analyzer/src/test/BUILD +++ b/third_party/dependency_analyzer/src/test/BUILD @@ -37,9 +37,6 @@ scala_test( ], unused_dependency_checker_mode = "off", deps = [ - "//external:io_bazel_rules_scala/dependency/scala/scala_compiler", - "//external:io_bazel_rules_scala/dependency/scala/scala_library", - "//external:io_bazel_rules_scala/dependency/scala/scala_reflect", "//third_party/dependency_analyzer/src/main:dependency_analyzer", "//third_party/utils/src/test:test_util", "@com_google_guava_guava_21_0_with_file//jar", @@ -58,9 +55,6 @@ scala_test( ], unused_dependency_checker_mode = "off", deps = [ - "//external:io_bazel_rules_scala/dependency/scala/scala_compiler", - "//external:io_bazel_rules_scala/dependency/scala/scala_library", - "//external:io_bazel_rules_scala/dependency/scala/scala_reflect", "//third_party/dependency_analyzer/src/main:dependency_analyzer", "//third_party/utils/src/test:test_util", "@org_apache_commons_commons_lang_3_5_without_file//:linkable_org_apache_commons_commons_lang_3_5_without_file", diff --git a/twitter_scrooge/twitter_scrooge.bzl b/twitter_scrooge/twitter_scrooge.bzl index a0217d668..f3968a665 100644 --- a/twitter_scrooge/twitter_scrooge.bzl +++ b/twitter_scrooge/twitter_scrooge.bzl @@ -238,7 +238,6 @@ def _compile_scala( print_compile_time = False, expect_java_output = False, scalac_jvm_flags = [], - scalac = ctx.attr._scalac, ) return JavaInfo( diff --git a/unstable/multiscala/BUILD.bazel b/unstable/multiscala/BUILD.bazel new file mode 100644 index 000000000..0915b96c9 --- /dev/null +++ b/unstable/multiscala/BUILD.bazel @@ -0,0 +1,8 @@ +load(":toolchains.bzl", "create_toolchains") + +create_toolchains() + +toolchain_type( + name = "test_toolchain_type", + visibility = ["//visibility:public"], +) diff --git a/unstable/multiscala/ExternalRepositories.md b/unstable/multiscala/ExternalRepositories.md new file mode 100644 index 000000000..1d9c6a9d2 --- /dev/null +++ b/unstable/multiscala/ExternalRepositories.md @@ -0,0 +1,96 @@ +# External Repositories + +## Summary + +This is a WIP summary of approaches to external dependencies. The text isn't structured at this point. It's a raw capture of current understanding so we can collaborate on the issues and approaches. When we close on that, we can turn this into real user documentation. + +Every scala build is going to have external dependencies. There are toolchain dependencies like the scala compiler and runtime library. There are dependencies used by the `rules_scala` infrastructure like `commons-io` in the scalac driver. Users will have dependencies in their code represented in build files, things like like `com.fasterxml.jackson.core`. + +Some of these dependencies are java and so can be imported fairly straightforwardly. + +Scala dependencies are more complicated in a multiscala environment. Now each abstract dependency is potentially multiple concrete dependencies. For example, abstractly `scalatest` is a single dependency. In a multiscala environment, this can actually mean multiple jars, e.g., `org.scalatest:scalatest_2_11` and `org.scalatest:scalatest_2_12`. We do not want any manual per-version repetition exposed to the user in the common case. + +There are also multiple mechanisms for downloading external dependencies. All these mechanisms end up downloading the desired contents into one or more external bazel repositories. + +The mapping from dependency to label depends on the loader used: e.g., [`jvm.bzl`](https://github.com/bazelbuild/bazel/blob/master/tools/build_defs/repo/jvm.bzl)(and it's variants), [`rules_jvm_external`](https://github.com/bazelbuild/rules_jvm_external), etc. These mechanisms create labels in incompatible ways. Moreover, in many cases, the exact labels used depends on arguments provided by the user. + +Mandating a particular loading mechanism and with particular arguments would provide the ability to uniquely map scala version to label but this restriction is not acceptable. + +There appear to be two options: +1. use pairs of helper macros to produce and consume structured labels +2. use `bind` to create labels in a canonical pattern + +Both of these approaches would rely on a canonical representation of a dependency. Presumably this would be something like `{org}:{artifact}:{version}`. At target creation time, version would be dropped, e.g., `{org}:{artifact}`. The scala version _is not_ included in the canonical representation since it's assume to follow the common scala pattern. (This is actually a bit of a problem for the `org.scala-lang` artifacts that don't follow the common pattern.) + +## Using helper macros + +In essence, for each loader type (and with the user being able to extend), a pair of macros would be defined, each of which takes the canonical format. The loader macro would translate the canonical coordinate to an external repo request, e.g., +``` +"commons-io:commons-io:2.6" +``` +could translate to a macro the calls, approximately, +``` + _scala_maven_import_external( + name = "scalac_rules_commons_io", + artifact = "commons-io:commons-io:2.6", + artifact_sha256 = "f877d304660ac2a142f3865badfc971dec7ed73c747c7f8d5d2f5139ca736513", + licenses = ["notice"], + server_urls = ... + ) +``` +or one that calls +``` +maven_install( + artifacts = [ + "commons-io:commons-io:2.6", + ], + repositories = ... +) +``` +These aren't literal but accurate in direction. + +In the case of a scala dep, they must make loader calls for each coordinate for each version. (FWIW, bazel is smart enough to only download the versions you need for the targets you ask for.) + +The rule-time reference takes the coordinate and returns the label the loader produces. In the cases above, these would be `@scalac_rules_common_io//jar` and `@maven//:commons_io_commons_io`. + +In both cases, the macros needs to know whether the jar is scala-versioned and adjust accordingly. + +This all seems very doable and can, to some extent, be built into the library so it doesn't have to be reflected in every build file. + +Because loading and rule-time reference are so far apart in the structure of bazel, I think it might be necessary to parameterize this behavior per repo by injecting the user choice into the synthetically-created configuration repository. This is not particularly hard or objectionable. + +The bigger concern is if multiple loading techniques are used within the same workspace, e.g., some `jvm.bzl` and some `rules_jvm_external`. It relatively straightfoward to to do this but the simplest approach would require each build file to know which mechanism was used for each dependencies. It's possible to imagine keeping track of the per-coordinate choice in the configuration repo but that might be a bit scary ... + +## Using `bind` + +A potentially straightforward alternative is to simply require `bind`ing whatever label is created by the loader to a canonical label in the external namespace. This separates the loading mechanism from the rule-time consumption mechanism. This simplies consumtion at the expense of loading time work (`bind`ing labels) which, if you have to choose, is the right place to mange the complexity. Among other things, ad hoc corner-cases could be handled relatively easily, more easily than with the previous mechanism. It's also amenable to using multiple loading mechanisms without having to reflect the loader chose in build files. + +It's required that the `external` path is canonically paired with the maven coordinate, e.g., `commons-io:commons-io` would end up at `//external:maven/commons-io/commons-io` no matter how the jar was loaded. + +## Which to use? + +I'm not sure. I don't know if we need to support mixed loaders in a single workspace. If we did, I think I'd tend to lean towards `bind`. + +`bind` is considered bad in many cases and for good reason. Where patterns aren't strongly enforced and/or where it's not actually adding any value (you could easily depend on the loader label because it's well known), using `bind` is a significant increase in complexity. However, here we'd be using a very strict target pattern which, among other things, would make understanding the meaning of th label and searching for references to the label straightforward. + +The alternative, at this point, in the face of supporting multiple loading mechanisms by needing to reflect the mechanism for each dependency in every build file, I find a significant burden for build file writers. + +The alternative of keeping a map of the necessary information in the configuration workspace is potentially viable but I haven't really investigated it. + +## Open issues + +### Handling different versions across different targets + +Do we need this? I suspect we might, for instance if the version of `commons-io` we need for building the toolchain is different than the one a user wants for their own code. I think the answer to this is the idea of a scope. + +This is easy to handle at load time: `rules_jvm_external` has this natively and it can added systemtically as part of the name in `jvm.bzl` repos. + +We would have to figure out how to reflect scopes in rule dependencies since it's not reflected in the normal maven coordinate. + +### Handling different shas for tools that want to pass the shas inline + +`rules_jvm_external` doesn't use this (it puts the shas in a separate out-of-band file in a way that shouldn't affect this work). Other tools like `jvm.bzl` do. Maybe we factor our the shas into a dict and add them at repo call time. + +### Handling multiple references to the same object + +This is essentially the `if not native.existing_rule` issue and I still don't have a handle on what happens (or should happen) when you have reconvergence: where two paths want the same dependency and give it the same label but spec different versions, e.g., protobufs. IIUC, it's possible you could get non-deterministic builds because I think the results would depend on execution order of loads which I think can run concurrently and therefore non-deterministicly. diff --git a/unstable/multiscala/README.md b/unstable/multiscala/README.md new file mode 100644 index 000000000..594c8c4a6 --- /dev/null +++ b/unstable/multiscala/README.md @@ -0,0 +1,46 @@ +# This is a very early work-in-progress. + +It is not only not stable, it's not complete. All the documentation here is as much or more about collaborating on the design as it is on documenting the behavior. In other words, it's highly likely that the behavior does not yet match the documentation. + +## example + +In [`private/example`](private/example) + +## Configuration + +The configuration is currently via a dict of dicts, lists, strings and booleans. It's not yet documented but there is an example in the example [`WORKSPACE`]((private/example/WORKSPACE)). The feeling is that this is ripe for refactoring. There's been a request to support multiple minor versions for the same major version which wouldn't be very hard. Another thing to consider is do we use helper macros to construct this rather than core types. That would be less error prone. Also, it's possible structs might be preferable to dicts since it might make code more succinct and less error prone. + +## Creating targets + +I would like to make the use of multiscala easy ("make easy things simple and hard things possible") + +One goal would be that + +``` +scala_library( + name = "lib", + ... +) + +scala_binary( + name = "app", + deps = [ + ":lib", + ... + ] + ... +) +``` +would act with the current default single version configuration mostly exactly as it does today: it would create a single jar for each target, e.g., `lib.jar` and `app.jar` (but we would probably add some aliases, too, with version suffixes as commmonly seen in maven). + +A change of configuration to specify two scala versions would not require any changes from the user. In other words, the default behavior would be to build everything against all versions and use arguments to reduce targets, not require them to increase them. + +So in the example above, with two scala versions configured, a build would create, for example, `lib_2_11.jar`, `lib_2_12.jar`, `app_2_11.jar` and `app_2_12.jar`. The mutliscala code will create the versioned targets based on the version deps. (This is a simplified example. As mentioned, I think we'll end up creating one jar for every version and then a set of aliases to give people the names that they expect.) + +To do this, we'd need to change `scala_library` from a rule to a macro. The macro has access to the configuration (which is why it's an external repo) and can instantiate the necessary targets and aliases. + +I do wonder if folks will consider this _too magic_. I can say that the developers I work with would prefer this to manual copying or having to write a starlark loop themselves for every target. + +## External Repos + +See [External Repositories](ExternalReposistories.md) diff --git a/unstable/multiscala/configuration.bzl b/unstable/multiscala/configuration.bzl new file mode 100644 index 000000000..f56aef55e --- /dev/null +++ b/unstable/multiscala/configuration.bzl @@ -0,0 +1,151 @@ +"""Macros to configure scala versions and dependencies. + +Creates the configuration repo @io_bazel_rules_scala_configuration. +""" + +load("@bazel_skylib//lib:dicts.bzl", _dicts = "dicts") +load("@bazel_skylib//lib:sets.bzl", _sets = "sets") + +# default configuration: public for user examination (if desired?) +default_configuration = { + "compatability_labels": True, + "default": "2.11", + "repositories": [ + "https://jcenter.bintray.com/", + "https://maven.google.com", + "https://repo1.maven.org/maven2", + ], + "scala": { + "2.11": { + "minor": "12", + }, + }, + "scala-parser-combinators": "1.0.4", + "scala-xml": "1.0.5", + "scala_bootstrap_toolchain": { + "scala_test_jvm_flags": [], + "scalac_jvm_flags": [], + "scalacopts": [], + }, + "scala_toolchain": { + "enable_code_coverage_aspect": "off", + "plus_one_deps_mode": "off", + "unused_dependency_checker_mode": "off", + }, + "scalactic": "3.0.5", + "scalatest": "3.0.5", +} + +def _repo_impl(ctx): + ctx.file( + "BUILD.bazel", + content = 'exports_files(["configuration.bzl"])', + executable = False, + ) + ctx.template( + "configuration.bzl", + ctx.attr._template, + substitutions = {"%{STARLARK_STRING}": ctx.attr.starlark_string}, + executable = False, + ) + +_repo = repository_rule( + implementation = _repo_impl, + attrs = { + "starlark_string": attr.string(mandatory = True), + "_template": attr.label( + default = ":configuration.bzl.tpl", + ), + }, +) + +def _merge_dicts(*dicts, exclude = None): + """merge multiple dictionaries + + This is a lot like typical map merging but limited by the lack of + recursion in starlark. It will merge values to one level only. + + Args: + *dicts: the list of dicts to merge, sequentially + exclude: a key to exclude from merging (merging may not work) + + """ + + configuration = {} + + for input in dicts: + keys = _sets.make(configuration.keys() + input.keys()) + + if exclude and _sets.contains(keys, exclude): + _sets.remove(keys, exclude) + + keys = _sets.to_list(keys) + + for key in keys: + if key in input: + field_type = type(input[key]) + if field_type == "string" or field_type == "list" or field_type == "bool": + configuration[key] = input[key] + elif field_type == "dict": + configuration[key] = _dicts.add( + configuration.get(key, {}), + input[key], + ) + elif field_type == "NoneType": + configuration.pop(key) + else: + fail([key, field_type]) + + return configuration + +def multiscala_configuration(configuration = default_configuration): + """Primary entry point for configuration. + + Args: + configuration: the configuration the user desires. Defaults to the one distributed. + """ + + configuration = _merge_dicts(default_configuration, configuration) + + # include default (true or false) for each target scala version rather than the selected default + if not "default" in configuration and len(configuration["scala"].keys()) == 1: + configuration = _dicts.add( + configuration, + {"default": configuration["scala"][configuration["scala"].keys()[0]]}, + ) + + # since "scala" is a map key, we need to merge each item rather + # than having a user-specified scala key completely override the + # default. + + scala = {} + + for version in configuration["scala"].keys(): + scala[version] = _merge_dicts(configuration, configuration["scala"][version], exclude = "scala") + scala[version]["scala"] = version + scala[version]["mvn"] = version.replace(".", "_") + scala[version]["complete"] = version + "." + scala[version]["minor"] + scala[version]["default"] = True if scala[version].get("default") == version else False + + configuration["scala"] = scala + + starlark_string = struct(**configuration).to_json() # .replace(":null,", ":None,") + + _repo( + name = "io_bazel_rules_scala_configuration", + starlark_string = starlark_string, + ) + +def toolchain_label(toolchain, version, in_package = False): + return "{package}{toolchain}_{version}_toolchain".format( + package = "@io_bazel_rules_scala//unstable/multiscala:" if not in_package else "", + toolchain = toolchain, + version = version.replace(".", "_"), + ) + +def native_toolchain_label(toolchain, version, in_package = False): + return "{package}native_{toolchain}_{version}_toolchain".format( + package = "@io_bazel_rules_scala//unstable/multiscala:" if not in_package else "", + toolchain = toolchain, + version = version.replace(".", "_"), + ) diff --git a/unstable/multiscala/configuration.bzl.tpl b/unstable/multiscala/configuration.bzl.tpl new file mode 100644 index 000000000..375c08247 --- /dev/null +++ b/unstable/multiscala/configuration.bzl.tpl @@ -0,0 +1,18 @@ +# -*- mode: python -*- + +load("@io_bazel_rules_scala//unstable/multiscala:tools.bzl", _maven_install = "maven_install") +load("@rules_jvm_external//:defs.bzl", _artifact = "artifact") + +def _from_json(): + # starlark vs json ... + + true = True + false = False + null = None + + return %{STARLARK_STRING} + +configuration = _from_json() + +def versions(): + return configuration["scala"].values() diff --git a/unstable/multiscala/configure.bzl b/unstable/multiscala/configure.bzl new file mode 100644 index 000000000..3a3aa025c --- /dev/null +++ b/unstable/multiscala/configure.bzl @@ -0,0 +1,26 @@ +"""post-configuration generation, complete other actions based on the resulting configuration""" + +load( + "@io_bazel_rules_scala//unstable/multiscala:configuration.bzl", + _native_toolchain_label = "native_toolchain_label", +) +load( + "@io_bazel_rules_scala_configuration//:configuration.bzl", + _configuration = "configuration", +) + +def multiscala_configure(): + _maybe_register_default_toolchains() + +def _maybe_default(): + return _configuration["scala"][_configuration["default"]] if "default" in _configuration else None + +def _maybe_register_default_toolchains(): + version = _maybe_default() + if version: + for toolchain in [ + # "bootstrap", + "scala", + # "scalatest" + ]: + native.register_toolchains(_native_toolchain_label(toolchain, version["mvn"])) diff --git a/unstable/multiscala/multiscala.bzl b/unstable/multiscala/multiscala.bzl new file mode 100644 index 000000000..c701aa0a7 --- /dev/null +++ b/unstable/multiscala/multiscala.bzl @@ -0,0 +1,20 @@ +"""multiscala equivalents to scala/scala.bzl + +TBD +""" + +load( + "//scala:scala.bzl", + _scala_binary = "scala_binary", + _scala_library = "scala_library", + _scala_test = "scala_test", +) + +def scala_binary(**kwargs): + _scala_binary(**kwargs) + +def scala_library(**kwargs): + _scala_library(**kwargs) + +def scala_test(**kwargs): + _scala_test(**kwargs) diff --git a/unstable/multiscala/private/example/App.scala b/unstable/multiscala/private/example/App.scala new file mode 100644 index 000000000..c53463be0 --- /dev/null +++ b/unstable/multiscala/private/example/App.scala @@ -0,0 +1,3 @@ +object App extends scala.App { + println(s"hello, world from ${scala.util.Properties.versionString}!") +} diff --git a/unstable/multiscala/private/example/AppTest.scala b/unstable/multiscala/private/example/AppTest.scala new file mode 100644 index 000000000..27bb7c3ec --- /dev/null +++ b/unstable/multiscala/private/example/AppTest.scala @@ -0,0 +1,9 @@ +import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.matchers.should.Matchers + +class AppTest extends AnyFlatSpec with Matchers { + it should "have a successful test" in { + System.err.println(s"hello, world from ${scala.util.Properties.versionString}!") + true should be (true) + } +} diff --git a/unstable/multiscala/private/example/BUILD.bazel b/unstable/multiscala/private/example/BUILD.bazel new file mode 100644 index 000000000..d5ae84ca0 --- /dev/null +++ b/unstable/multiscala/private/example/BUILD.bazel @@ -0,0 +1,45 @@ +load( + "@io_bazel_rules_scala//unstable/multiscala:configuration.bzl", + "toolchain_label", +) +load( + "@io_bazel_rules_scala//unstable/multiscala:multiscala.bzl", + _scala_binary = "scala_binary", + _scala_library = "scala_library", + _scala_test = "scala_test", +) + +_scala_library( + name = "library", + srcs = ["App.scala"], +) + +_scala_binary( + name = "app", + main_class = "App", + runtime_deps = [":library"], +) + +_scala_test( + name = "test", + srcs = ["AppTest.scala"], +) + +_scala_library( + name = "library_with_explict_toolchain", + srcs = ["App.scala"], + toolchains = [toolchain_label("scala", "2.11")], +) + +_scala_binary( + name = "app_with_explict_toolchain", + main_class = "App", + toolchains = [toolchain_label("scala", "2.11")], + runtime_deps = [":library"], +) + +_scala_test( + name = "test_with_explict_toolchain", + srcs = ["AppTest.scala"], + toolchains = [toolchain_label("scala", "2.11")], +) diff --git a/unstable/multiscala/private/example/WORKSPACE b/unstable/multiscala/private/example/WORKSPACE new file mode 100644 index 000000000..a9f12068f --- /dev/null +++ b/unstable/multiscala/private/example/WORKSPACE @@ -0,0 +1,77 @@ +load("//repositories:bazel_skylib.bzl", "load_bazel_skylib") + +load_bazel_skylib() + +load("//repositories:rules_jvm_external.bzl", "load_rules_jvm_external") + +load_rules_jvm_external() + +load("//repositories:rules_scala.bzl", "load_rules_scala") + +load_rules_scala() + +load("//repositories:rules_proto.bzl", "load_rules_proto") + +load_rules_proto() + +load("//repositories:rules_python.bzl", "load_rules_python") + +load_rules_python() + +load( + "@io_bazel_rules_scala//unstable/multiscala:configuration.bzl", + "multiscala_configuration", +) + +multiscala_configuration(configuration = { + "default": "2.12", + "scala": { + "2.11": { + "minor": "12", + }, + "2.12": { + "minor": "10", + }, + "2.13": { + "minor": "1", + "scala_bootstrap_toolchain": { + "scalacopts": [ + "-deprecation:true", + "-encoding", + "UTF-8", + "-feature", + "-unchecked", + "-Xfatal-warnings", + "-Xsource:2.13", + ], + }, + }, + }, + "scala-parser-combinators": "1.1.2", + "scala-xml": "1.2.0", + "scala_bootstrap_toolchain": { + "scalacopts": [ + "-deprecation:true", + "-encoding", + "UTF-8", + "-feature", + "-unchecked", + "-Xfatal-warnings", + "-Xfuture", + "-Xsource:2.12", + "-Ypartial-unification", + ], + }, + "scala_toolchain": { + "unused_dependency_checker_mode": "error", + }, + "scalatest": "3.1.0", +}) + +load("@io_bazel_rules_scala//unstable/multiscala:repositories.bzl", "create_repositories") + +create_repositories() + +load("@io_bazel_rules_scala//unstable/multiscala:configure.bzl", "multiscala_configure") + +multiscala_configure() diff --git a/unstable/multiscala/private/example/repositories/BUILD.bazel b/unstable/multiscala/private/example/repositories/BUILD.bazel new file mode 100644 index 000000000..e69de29bb diff --git a/unstable/multiscala/private/example/repositories/bazel_skylib.bzl b/unstable/multiscala/private/example/repositories/bazel_skylib.bzl new file mode 100644 index 000000000..e6477bed7 --- /dev/null +++ b/unstable/multiscala/private/example/repositories/bazel_skylib.bzl @@ -0,0 +1,11 @@ +"""load skylib""" + +load(":tools.bzl", _github_release = "github_release") + +def load_bazel_skylib(): + _github_release( + name = "bazel_skylib", + sha256 = "97e70364e9249702246c0e9444bccdc4b847bed1eb03c5a3ece4f83dfe6abc44", + repository = "bazelbuild/bazel-skylib", + release = "1.0.2", + ) diff --git a/unstable/multiscala/private/example/repositories/rules_jvm_external.bzl b/unstable/multiscala/private/example/repositories/rules_jvm_external.bzl new file mode 100644 index 000000000..d68a0e2c4 --- /dev/null +++ b/unstable/multiscala/private/example/repositories/rules_jvm_external.bzl @@ -0,0 +1,11 @@ +"""load rules_jvm_external""" + +load(":tools.bzl", _github_archive = "github_archive") + +def load_rules_jvm_external(): + _github_archive( + name = "rules_jvm_external", + repository = "bazelbuild/rules_jvm_external", + sha256 = "62133c125bf4109dfd9d2af64830208356ce4ef8b165a6ef15bbff7460b35c3a", + tag = "3.0", + ) diff --git a/unstable/multiscala/private/example/repositories/rules_proto.bzl b/unstable/multiscala/private/example/repositories/rules_proto.bzl new file mode 100644 index 000000000..bddf5cc67 --- /dev/null +++ b/unstable/multiscala/private/example/repositories/rules_proto.bzl @@ -0,0 +1,11 @@ +"""load rules_proto: needed by protobuf repo""" + +load(":tools.bzl", _github_archive = "github_archive") + +def load_rules_proto(): + _github_archive( + name = "rules_proto", + repository = "bazelbuild/rules_proto", + sha256 = "62847ac7740865d73a2c8199be292bba913d62e79084442f3e829c3058a25e64", + tag = "d7666ec475c1f8d4a6803cbc0a0b6b4374360868", + ) diff --git a/unstable/multiscala/private/example/repositories/rules_python.bzl b/unstable/multiscala/private/example/repositories/rules_python.bzl new file mode 100644 index 000000000..9ab16594c --- /dev/null +++ b/unstable/multiscala/private/example/repositories/rules_python.bzl @@ -0,0 +1,11 @@ +"""load rules_python: needed by protobuf repo""" + +load(":tools.bzl", _github_archive = "github_archive") + +def load_rules_python(): + _github_archive( + name = "rules_python", + repository = "bazelbuild/rules_python", + sha256 = "7d64815f4b22400bed0f1b9da663037e1578573446b7bc78f20f24b2b5459bb9", + tag = "38f86fb55b698c51e8510c807489c9f4e047480e", + ) diff --git a/unstable/multiscala/private/example/repositories/rules_scala.bzl b/unstable/multiscala/private/example/repositories/rules_scala.bzl new file mode 100644 index 000000000..d02164e0c --- /dev/null +++ b/unstable/multiscala/private/example/repositories/rules_scala.bzl @@ -0,0 +1,7 @@ +"""link back to parent rules_scala repo""" + +def load_rules_scala(): + native.local_repository( + name = "io_bazel_rules_scala", + path = "../../../..", + ) diff --git a/unstable/multiscala/private/example/repositories/tools.bzl b/unstable/multiscala/private/example/repositories/tools.bzl new file mode 100644 index 000000000..88f628714 --- /dev/null +++ b/unstable/multiscala/private/example/repositories/tools.bzl @@ -0,0 +1,28 @@ +"""helpers for to remove http_archive boilerplate + +N.B.: doesn't currently include the bazel mirros +""" + +load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") + +def github_release(name, repository, release, sha256): + (org, repo) = repository.split("/") + http_archive( + name = name, + sha256 = sha256, + urls = [ + "https://github.com/{repository}/releases/download/{release}/{repo}-{release}.tar.gz".format(repository = repository, repo = repo, release = release), + ], + ) + +def github_archive(name, repository, sha256, tag): + (org, repo) = repository.split("/") + without_v = tag[1:] if tag.startswith("v") else tag + http_archive( + name = name, + sha256 = sha256, + strip_prefix = "{repo}-{without_v}".format(repo = repo, without_v = without_v), + urls = [ + "https://github.com/{repository}/archive/{tag}.zip".format(repository = repository, tag = tag), + ], + ) diff --git a/unstable/multiscala/repositories.bzl b/unstable/multiscala/repositories.bzl new file mode 100644 index 000000000..432afa73d --- /dev/null +++ b/unstable/multiscala/repositories.bzl @@ -0,0 +1,119 @@ +"""macros to load all necessary repos + +Only public function is `create_repositories` + +Determines all necessary dependences from configuration and loads them. + +All loading via rules_jvm_external. + +If configuration asks for compatiblity labels, `bind`s aliases. + +Includes helpers to reduce boilerplate for github archives and artifact naming. +""" + +load("@bazel_tools//tools/build_defs/repo:http.bzl", _http_archive = "http_archive") +load("@io_bazel_rules_scala_configuration//:configuration.bzl", _configuration = "configuration", _versions = "versions") +load("@rules_jvm_external//:defs.bzl", _artifact = "artifact") +load(":tools.bzl", _maven_install = "maven_install") + +def _github_archive(name, repository, sha256, tag): + (org, repo) = repository.split("/") + without_v = tag[1:] if tag.startswith("v") else tag + _http_archive( + name = name, + sha256 = sha256, + strip_prefix = "{repo}-{without_v}".format(repo = repo, without_v = without_v), + urls = [ + "https://github.com/{repository}/archive/{tag}.zip".format(repository = repository, tag = tag), + ], + ) + +def _maven_install_artifacts(artifacts): + return artifacts.keys() + +def _bind_default_labels(repository_name, artifacts): + for artifact in artifacts.items(): + (mvn, label) = artifact + without_version = ":".join(mvn.split(":")[0:2]) + native.bind( + name = label, + actual = _artifact(without_version, repository_name = repository_name), + ) + +def create_repositories(): + """create all necessary repos""" + _create_protobuf() + _create_maven_installed_repos() + +def _create_protobuf(): + _github_archive( + name = "com_google_protobuf", + sha256 = "e4f8bedb19a93d0dccc359a126f51158282e0b24d92e0cad9c76a9699698268d", + repository = "protocolbuffers/protobuf", + tag = "v3.11.2", + ) + + # N.B.: could use protobuf/protobuf_deps.bzl + + _http_archive( + name = "zlib", + build_file = "@com_google_protobuf//:third_party/zlib.BUILD", + sha256 = "629380c90a77b964d896ed37163f5c3a34f6e6d897311f1df2a7016355c45eff", + strip_prefix = "zlib-1.2.11", + urls = ["https://github.com/madler/zlib/archive/v1.2.11.tar.gz"], + ) + + if _configuration["compatability_labels"]: + native.bind( + name = "io_bazel_rules_scala/dependency/com_google_protobuf/protobuf_java", + actual = "@com_google_protobuf//:protobuf_java", + ) + +def _scala_artifact(version, scala_coordinate): + components = scala_coordinate.split(":") + if len(components) == 2: + components.append("{" + components[1] + "}") + (org, artifact, artifact_version) = components + java_coordinate = ":".join([org, artifact + "_" + version["scala"], artifact_version]) + return java_coordinate.format(**version) + +def _create_maven_installed_repos(): + for version in _versions(): + repository_name = "io_bazel_rules_scala_" + version["mvn"] + + artifacts = { + "org.scala-lang:scala-compiler:" + version["complete"]: "io_bazel_rules_scala/dependency/scala/scala_compiler", + "org.scala-lang:scala-library:" + version["complete"]: "io_bazel_rules_scala/dependency/scala/scala_library", + "org.scala-lang:scala-reflect:" + version["complete"]: "io_bazel_rules_scala/dependency/scala/scala_reflect", + _scala_artifact(version, "org.scala-lang.modules:scala-xml"): "io_bazel_rules_scala/dependency/scala/scala_xml", + _scala_artifact(version, "org.scalatest:scalatest"): "io_bazel_rules_scala/dependency/scala/scalatest/scalatest", + _scala_artifact(version, "org.scalactic:scalactic"): "io_bazel_rules_scala/dependency/scala/scalactic/scalactic", + } + + _maven_install( + name = repository_name, + artifacts = _maven_install_artifacts(artifacts), + repositories = version["repositories"], + ) + + if version["default"] and version["compatability_labels"]: + _bind_default_labels(repository_name, artifacts) + + if version["default"] and version["compatability_labels"]: + native.bind( + name = "io_bazel_rules_scala/dependency/scalatest/scalatest", + actual = "@io_bazel_rules_scala//scala/scalatest:scalatest", + ) + + java_artifacts = { + "com.google.guava:guava:21.0": "io_bazel_rules_scala/dependency/scala/guava", + "commons-io:commons-io:2.6": "io_bazel_rules_scala/dependency/scalac_rules_commons_io", + } + + _maven_install( + name = "io_bazel_rules_scala_scalac", + artifacts = _maven_install_artifacts(java_artifacts), + repositories = _configuration["repositories"], + ) + if _configuration["compatability_labels"]: + _bind_default_labels("io_bazel_rules_scala_scalac", java_artifacts) diff --git a/unstable/multiscala/toolchains.bzl b/unstable/multiscala/toolchains.bzl new file mode 100644 index 000000000..91440ad5e --- /dev/null +++ b/unstable/multiscala/toolchains.bzl @@ -0,0 +1,64 @@ +"""create toolchains required by configuration""" + +load( + "@io_bazel_rules_scala//scala:scala_toolchain.bzl", + _scala_toolchain_rule = "scala_toolchain", +) +load( + "@io_bazel_rules_scala_configuration//:configuration.bzl", + _versions = "versions", +) +load( + ":configuration.bzl", + _native_toolchain_label = "native_toolchain_label", + _toolchain_label = "toolchain_label", +) + +def create_toolchains(): + _create_all_toolchains() + +def _create_all_toolchains(): + for version in _versions(): + _create_version_toolchains(version) + +def _create_version_toolchains(version): + _create_bootstrap_toolchain(version) + _create_scala_toolchain(version) + _create_scalatest_toolchain(version) + +def _create_bootstrap_toolchain(version): + pass + +_scala_toolchain_attrs = [ + "scalacopts", + "scalac_provider_attr", + "unused_dependency_checker_mode", + "plus_one_deps_mode", + "enable_code_coverage_aspect", + "scalac_jvm_flags", + "scala_test_jvm_flags", +] + +def _create_scala_toolchain(version): + name = _toolchain_label("scala", version["mvn"], in_package = True) + + attrs = {} + + for attr in _scala_toolchain_attrs: + if attr in version["scala_toolchain"]: + attrs[attr] = version["scala_toolchain"][attr] + + attrs["name"] = name + attrs["visibility"] = ["//visibility:public"] + + _scala_toolchain_rule(**attrs) + + native.toolchain( + name = _native_toolchain_label("scala", version["mvn"], in_package = True), + toolchain = name, + toolchain_type = "@io_bazel_rules_scala//scala:toolchain_type", + visibility = ["//visibility:public"], + ) + +def _create_scalatest_toolchain(version): + pass diff --git a/unstable/multiscala/tools.bzl b/unstable/multiscala/tools.bzl new file mode 100644 index 000000000..551c0f042 --- /dev/null +++ b/unstable/multiscala/tools.bzl @@ -0,0 +1,12 @@ +"""helpers for loading externa repos + +TBD: maybe delete +""" + +load("@rules_jvm_external//:defs.bzl", _maven_install = "maven_install") + +def maven_install(**kwargs): + _maven_install(**kwargs) + +def scala_maven_install(): + fail()