From 07968d0d034cdd34b7b29dad0b5877b6297cf217 Mon Sep 17 00:00:00 2001 From: Bor Kae Hwang Date: Fri, 25 Oct 2019 16:04:16 -0600 Subject: [PATCH 1/8] Add configurable phases --- scala/private/phases/api.bzl | 10 ++ scala/private/phases/phase_collect_jars.bzl | 71 +++++++++ scala/private/phases/phase_compile.bzl | 144 ++++++++++++++++++ .../phases/phase_coverage_runfiles.bzl | 28 ++++ .../phases/phase_declare_executable.bzl | 12 ++ scala/private/phases/phase_final.bzl | 38 +++++ scala/private/phases/phase_init.bzl | 39 +++++ scala/private/phases/phase_java_wrapper.bzl | 46 ++++++ scala/private/phases/phase_jvm_flags.bzl | 52 +++++++ scala/private/phases/phase_merge_jars.bzl | 19 +++ scala/private/phases/phase_runfiles.bzl | 65 ++++++++ scala/private/phases/phase_scala_provider.bzl | 45 ++++++ .../phases/phase_unused_deps_checker.bzl | 12 ++ .../private/phases/phase_write_executable.bzl | 72 +++++++++ scala/private/phases/phases.bzl | 127 +++++++++++++++ 15 files changed, 780 insertions(+) create mode 100644 scala/private/phases/api.bzl create mode 100644 scala/private/phases/phase_collect_jars.bzl create mode 100644 scala/private/phases/phase_compile.bzl create mode 100644 scala/private/phases/phase_coverage_runfiles.bzl create mode 100644 scala/private/phases/phase_declare_executable.bzl create mode 100644 scala/private/phases/phase_final.bzl create mode 100644 scala/private/phases/phase_init.bzl create mode 100644 scala/private/phases/phase_java_wrapper.bzl create mode 100644 scala/private/phases/phase_jvm_flags.bzl create mode 100644 scala/private/phases/phase_merge_jars.bzl create mode 100644 scala/private/phases/phase_runfiles.bzl create mode 100644 scala/private/phases/phase_scala_provider.bzl create mode 100644 scala/private/phases/phase_unused_deps_checker.bzl create mode 100644 scala/private/phases/phase_write_executable.bzl create mode 100644 scala/private/phases/phases.bzl diff --git a/scala/private/phases/api.bzl b/scala/private/phases/api.bzl new file mode 100644 index 000000000..afbcee020 --- /dev/null +++ b/scala/private/phases/api.bzl @@ -0,0 +1,10 @@ +def run_phases(ctx, phases): + global_provider = {} + current_provider = struct(**global_provider) + for (name, function) in phases: + new_provider = function(ctx, current_provider) + if new_provider != None: + global_provider[name] = new_provider + current_provider = struct(**global_provider) + + return current_provider diff --git a/scala/private/phases/phase_collect_jars.bzl b/scala/private/phases/phase_collect_jars.bzl new file mode 100644 index 000000000..6eac37475 --- /dev/null +++ b/scala/private/phases/phase_collect_jars.bzl @@ -0,0 +1,71 @@ +# +# PHASE: collect jars +# +# DOCUMENT THIS +# +load( + "@io_bazel_rules_scala//scala/private:rule_impls.bzl", + "collect_jars_from_common_ctx", +) + +def phase_test_collect_jars(ctx, p): + args = struct( + base_classpath = p.init.scalac_provider.default_classpath + [ctx.attr._scalatest], + extra_runtime_deps = [ + ctx.attr._scalatest_reporter, + ctx.attr._scalatest_runner, + ], + ) + return phase_common_collect_jars(ctx, p, args) + +def phase_repl_collect_jars(ctx, p): + args = struct( + base_classpath = p.init.scalac_provider.default_repl_classpath, + ) + return phase_common_collect_jars(ctx, p, args) + +def phase_macro_library_collect_jars(ctx, p): + args = struct( + base_classpath = p.init.scalac_provider.default_macro_classpath, + ) + return phase_common_collect_jars(ctx, p, args) + +def phase_junit_test_collect_jars(ctx, p): + args = struct( + extra_deps = [ + ctx.attr._junit, + ctx.attr._hamcrest, + ctx.attr.suite_label, + ctx.attr._bazel_test_runner, + ], + ) + return phase_common_collect_jars(ctx, p, args) + +def phase_library_for_plugin_bootstrapping_collect_jars(ctx, p): + args = struct( + unused_dependency_checker_mode = "off", + ) + return phase_common_collect_jars(ctx, p, args) + +def phase_common_collect_jars(ctx, p, _args = struct()): + return _phase_collect_jars( + ctx, + _args.base_classpath if hasattr(_args, "base_classpath") else p.init.scalac_provider.default_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, + ) + +def _phase_collect_jars( + ctx, + base_classpath, + extra_deps, + extra_runtime_deps, + unused_dependency_checker_mode): + return collect_jars_from_common_ctx( + ctx, + base_classpath, + extra_deps, + extra_runtime_deps, + unused_dependency_checker_mode == "off", + ) diff --git a/scala/private/phases/phase_compile.bzl b/scala/private/phases/phase_compile.bzl new file mode 100644 index 000000000..9027c67f4 --- /dev/null +++ b/scala/private/phases/phase_compile.bzl @@ -0,0 +1,144 @@ +# +# PHASE: compile +# +# DOCUMENT THIS +# +load( + "@io_bazel_rules_scala//scala/private:rule_impls.bzl", + "compile_or_empty", + "pack_source_jars", +) + +def phase_binary_compile(ctx, p): + args = struct( + unused_dependency_checker_ignored_targets = [ + target.label + for target in p.init.scalac_provider.default_classpath + + ctx.attr.unused_dependency_checker_ignored_targets + ], + ) + return phase_common_compile(ctx, p, args) + +def phase_library_compile(ctx, p): + args = struct( + srcjars = p.init.srcjars, + buildijar = True, + unused_dependency_checker_ignored_targets = [ + target.label + for target in p.init.scalac_provider.default_classpath + ctx.attr.exports + + ctx.attr.unused_dependency_checker_ignored_targets + ], + ) + return phase_common_compile(ctx, p, args) + +def phase_library_for_plugin_bootstrapping_compile(ctx, p): + args = struct( + buildijar = True, + unused_dependency_checker_ignored_targets = [ + target.label + for target in p.init.scalac_provider.default_classpath + ctx.attr.exports + ], + unused_dependency_checker_mode = "off", + ) + return phase_common_compile(ctx, p, args) + +def phase_macro_library_compile(ctx, p): + args = struct( + unused_dependency_checker_ignored_targets = [ + target.label + for target in p.init.scalac_provider.default_macro_classpath + ctx.attr.exports + + ctx.attr.unused_dependency_checker_ignored_targets + ], + ) + return phase_common_compile(ctx, p, args) + +def phase_junit_test_compile(ctx, p): + args = struct( + implicit_junit_deps_needed_for_java_compilation = [ + ctx.attr._junit, + ctx.attr._hamcrest, + ], + unused_dependency_checker_ignored_targets = [ + target.label + for target in p.init.scalac_provider.default_classpath + + ctx.attr.unused_dependency_checker_ignored_targets + ] + [ + ctx.attr._junit.label, + ctx.attr._hamcrest.label, + ctx.attr.suite_label.label, + ctx.attr._bazel_test_runner.label, + ], + ) + return phase_common_compile(ctx, p, args) + +def phase_repl_compile(ctx, p): + args = struct( + unused_dependency_checker_ignored_targets = [ + target.label + for target in p.init.scalac_provider.default_repl_classpath + + ctx.attr.unused_dependency_checker_ignored_targets + ], + ) + return phase_common_compile(ctx, p, args) + +def phase_test_compile(ctx, p): + args = struct( + unused_dependency_checker_ignored_targets = [ + target.label + for target in p.init.scalac_provider.default_classpath + + ctx.attr.unused_dependency_checker_ignored_targets + ], + ) + return phase_common_compile(ctx, p, args) + +def phase_common_compile(ctx, p, _args = struct()): + return _phase_compile( + ctx, + p, + _args.srcjars if hasattr(_args, "srcjars") else depset(), + _args.buildijar if hasattr(_args, "buildijar") else False, + _args.implicit_junit_deps_needed_for_java_compilation if hasattr(_args, "implicit_junit_deps_needed_for_java_compilation") else [], + _args.unused_dependency_checker_ignored_targets if hasattr(_args, "unused_dependency_checker_ignored_targets") else [], + _args.unused_dependency_checker_mode if hasattr(_args, "unused_dependency_checker_mode") else p.unused_deps_checker, + ) + +def _phase_compile( + ctx, + p, + srcjars, + buildijar, + implicit_junit_deps_needed_for_java_compilation, + unused_dependency_checker_ignored_targets, + unused_dependency_checker_mode): + manifest = ctx.outputs.manifest + jars = p.collect_jars.compile_jars + rjars = p.collect_jars.transitive_runtime_jars + transitive_compile_jars = p.collect_jars.transitive_compile_jars + jars2labels = p.collect_jars.jars2labels.jars_to_labels + deps_providers = p.collect_jars.deps_providers + + out = compile_or_empty( + ctx, + manifest, + jars, + srcjars, + buildijar, + transitive_compile_jars, + jars2labels, + implicit_junit_deps_needed_for_java_compilation, + unused_dependency_checker_mode, + unused_dependency_checker_ignored_targets, + deps_providers, + ) + + return struct( + class_jar = out.class_jar, + coverage = out.coverage, + full_jars = out.full_jars, + ijar = out.ijar, + ijars = out.ijars, + rjars = depset(out.full_jars, transitive = [rjars]), + java_jar = out.java_jar, + source_jars = pack_source_jars(ctx) + out.source_jars, + merged_provider = out.merged_provider, + ) diff --git a/scala/private/phases/phase_coverage_runfiles.bzl b/scala/private/phases/phase_coverage_runfiles.bzl new file mode 100644 index 000000000..00e50cf44 --- /dev/null +++ b/scala/private/phases/phase_coverage_runfiles.bzl @@ -0,0 +1,28 @@ +# +# PHASE: coverage runfiles +# +# DOCUMENT THIS +# +load( + "@io_bazel_rules_scala//scala/private:coverage_replacements_provider.bzl", + _coverage_replacements_provider = "coverage_replacements_provider", +) + +def phase_coverage_runfiles(ctx, p): + coverage_runfiles = [] + rjars = p.compile.rjars + if ctx.configuration.coverage_enabled and _coverage_replacements_provider.is_enabled(ctx): + coverage_replacements = _coverage_replacements_provider.from_ctx( + ctx, + base = p.compile.coverage.replacements, + ).replacements + + rjars = depset([ + coverage_replacements[jar] if jar in coverage_replacements else jar + for jar in rjars.to_list() + ]) + coverage_runfiles = ctx.files._jacocorunner + ctx.files._lcov_merger + coverage_replacements.values() + return struct( + coverage_runfiles = coverage_runfiles, + rjars = rjars, + ) diff --git a/scala/private/phases/phase_declare_executable.bzl b/scala/private/phases/phase_declare_executable.bzl new file mode 100644 index 000000000..53d0cdd50 --- /dev/null +++ b/scala/private/phases/phase_declare_executable.bzl @@ -0,0 +1,12 @@ +# +# PHASE: declare executable +# +# DOCUMENT THIS +# +load( + "@io_bazel_rules_scala//scala/private:rule_impls.bzl", + "declare_executable", +) + +def phase_declare_executable(ctx, p): + return declare_executable(ctx) diff --git a/scala/private/phases/phase_final.bzl b/scala/private/phases/phase_final.bzl new file mode 100644 index 000000000..771002dcb --- /dev/null +++ b/scala/private/phases/phase_final.bzl @@ -0,0 +1,38 @@ +# +# PHASE: final +# +# DOCUMENT THIS +# +def phase_binary_final(ctx, p): + return struct( + executable = p.declare_executable, + coverage = p.compile.coverage, + files = depset([p.declare_executable, ctx.outputs.jar]), + instrumented_files = p.compile.coverage.instrumented_files, + providers = [p.compile.merged_provider, p.collect_jars.jars2labels] + p.compile.coverage.providers, + runfiles = p.runfiles.runfiles, + scala = p.scala_provider, + transitive_rjars = p.compile.rjars, #calling rules need this for the classpath in the launcher + ) + +def phase_library_final(ctx, p): + return struct( + files = depset([ctx.outputs.jar] + p.compile.full_jars), # Here is the default output + instrumented_files = p.compile.coverage.instrumented_files, + jars_to_labels = p.collect_jars.jars2labels, + providers = [p.compile.merged_provider, p.collect_jars.jars2labels] + p.compile.coverage.providers, + runfiles = p.runfiles.runfiles, + scala = p.scala_provider, + ) + +def phase_test_final(ctx, p): + coverage_runfiles = p.coverage_runfiles.coverage_runfiles + coverage_runfiles.extend(p.write_executable) + return struct( + executable = p.declare_executable, + files = depset([p.declare_executable, ctx.outputs.jar]), + instrumented_files = p.compile.coverage.instrumented_files, + providers = [p.compile.merged_provider, p.collect_jars.jars2labels] + p.compile.coverage.providers, + runfiles = ctx.runfiles(coverage_runfiles, transitive_files = p.runfiles.runfiles.files), + scala = p.scala_provider, + ) diff --git a/scala/private/phases/phase_init.bzl b/scala/private/phases/phase_init.bzl new file mode 100644 index 000000000..f80494bef --- /dev/null +++ b/scala/private/phases/phase_init.bzl @@ -0,0 +1,39 @@ +# +# PHASE: init +# +# DOCUMENT THIS +# +load( + "@io_bazel_rules_scala//scala/private:rule_impls.bzl", + "get_scalac_provider", +) +load( + "@io_bazel_rules_scala//scala/private:common.bzl", + "collect_jars", + "collect_srcjars", + "write_manifest", +) + +def phase_library_init(ctx, p): + # This will be used to pick up srcjars from non-scala library + # targets (like thrift code generation) + srcjars = collect_srcjars(ctx.attr.deps) + + # Add information from exports (is key that AFTER all build actions/runfiles analysis) + # Since after, will not show up in deploy_jar or old jars runfiles + # Notice that compile_jars is intentionally transitive for exports + exports_jars = collect_jars(ctx.attr.exports) + + args = phase_common_init(ctx, p) + + return struct( + srcjars = srcjars, + exports_jars = exports_jars, + scalac_provider = args.scalac_provider, + ) + +def phase_common_init(ctx, p): + write_manifest(ctx) + return struct( + scalac_provider = get_scalac_provider(ctx), + ) diff --git a/scala/private/phases/phase_java_wrapper.bzl b/scala/private/phases/phase_java_wrapper.bzl new file mode 100644 index 000000000..64c7334cc --- /dev/null +++ b/scala/private/phases/phase_java_wrapper.bzl @@ -0,0 +1,46 @@ +# +# PHASE: java wrapper +# +# DOCUMENT THIS +# +load( + "@io_bazel_rules_scala//scala/private:rule_impls.bzl", + "write_java_wrapper", +) + +def phase_repl_java_wrapper(ctx, p): + args = struct( + args = " ".join(ctx.attr.scalacopts), + wrapper_preamble = """ +# save stty like in bin/scala +saved_stty=$(stty -g 2>/dev/null) +if [[ ! $? ]]; then + saved_stty="" +fi +function finish() { + if [[ "$saved_stty" != "" ]]; then + stty $saved_stty + saved_stty="" + fi +} +trap finish EXIT +""", + ) + return phase_common_java_wrapper(ctx, p, args) + +def phase_common_java_wrapper(ctx, p, _args = struct()): + return _phase_java_wrapper( + ctx, + _args.args if hasattr(_args, "args") else "", + _args.wrapper_preamble if hasattr(_args, "wrapper_preamble") else "", + ) + +def _phase_java_wrapper( + ctx, + args, + wrapper_preamble): + return write_java_wrapper( + ctx, + args, + wrapper_preamble, + ) diff --git a/scala/private/phases/phase_jvm_flags.bzl b/scala/private/phases/phase_jvm_flags.bzl new file mode 100644 index 000000000..9f17a95dd --- /dev/null +++ b/scala/private/phases/phase_jvm_flags.bzl @@ -0,0 +1,52 @@ +# +# PHASE: jvm flags +# +# DOCUMENT THIS +# +def phase_jvm_flags(ctx, p): + if ctx.attr.tests_from: + archives = _get_test_archive_jars(ctx, ctx.attr.tests_from) + else: + archives = [archive.class_jar for archive in p.scala_provider.outputs.jars] + + serialized_archives = _serialize_archives_short_path(archives) + test_suite = _gen_test_suite_flags_based_on_prefixes_and_suffixes( + ctx, + serialized_archives, + ) + return [ + "-ea", + test_suite.archiveFlag, + test_suite.prefixesFlag, + test_suite.suffixesFlag, + test_suite.printFlag, + test_suite.testSuiteFlag, + ] + +def _gen_test_suite_flags_based_on_prefixes_and_suffixes(ctx, archives): + return struct( + archiveFlag = "-Dbazel.discover.classes.archives.file.paths=%s" % + archives, + prefixesFlag = "-Dbazel.discover.classes.prefixes=%s" % ",".join( + ctx.attr.prefixes, + ), + printFlag = "-Dbazel.discover.classes.print.discovered=%s" % + ctx.attr.print_discovered_classes, + suffixesFlag = "-Dbazel.discover.classes.suffixes=%s" % ",".join( + ctx.attr.suffixes, + ), + testSuiteFlag = "-Dbazel.test_suite=%s" % ctx.attr.suite_class, + ) + +def _serialize_archives_short_path(archives): + archives_short_path = "" + for archive in archives: + archives_short_path += archive.short_path + "," + return archives_short_path[:-1] #remove redundant comma + +def _get_test_archive_jars(ctx, test_archives): + flattened_list = [] + for archive in test_archives: + class_jars = [java_output.class_jar for java_output in archive[JavaInfo].outputs.jars] + flattened_list.extend(class_jars) + return flattened_list diff --git a/scala/private/phases/phase_merge_jars.bzl b/scala/private/phases/phase_merge_jars.bzl new file mode 100644 index 000000000..bec2194f5 --- /dev/null +++ b/scala/private/phases/phase_merge_jars.bzl @@ -0,0 +1,19 @@ +# +# PHASE: merge jars +# +# DOCUMENT THIS +# +load( + "@io_bazel_rules_scala//scala/private:rule_impls.bzl", + "merge_jars", +) + +def phase_merge_jars(ctx, p): + merge_jars( + actions = ctx.actions, + deploy_jar = ctx.outputs.deploy_jar, + singlejar_executable = ctx.executable._singlejar, + jars_list = p.compile.rjars.to_list(), + main_class = getattr(ctx.attr, "main_class", ""), + progress_message = "Merging Scala jar: %s" % ctx.label, + ) diff --git a/scala/private/phases/phase_runfiles.bzl b/scala/private/phases/phase_runfiles.bzl new file mode 100644 index 000000000..bdc602524 --- /dev/null +++ b/scala/private/phases/phase_runfiles.bzl @@ -0,0 +1,65 @@ +# +# PHASE: runfiles +# +# DOCUMENT THIS +# +def phase_library_runfiles(ctx, p): + args = struct( + # Using transitive_files since transitive_rjars a depset and avoiding linearization + transitive_files = p.compile.rjars, + ) + return phase_common_runfiles(ctx, p, args) + +def phase_test_runfiles(ctx, p): + args = "\n".join([ + "-R", + ctx.outputs.jar.short_path, + _scala_test_flags(ctx), + "-C", + "io.bazel.rules.scala.JUnitXmlReporter", + ]) + args_file = ctx.actions.declare_file("%s.args" % ctx.label.name) + ctx.actions.write(args_file, args) + runfiles_ext = [args_file] + + args = struct( + transitive_files = depset( + [p.declare_executable, p.java_wrapper] + ctx.files._java_runtime + runfiles_ext, + transitive = [p.compile.rjars], + ), + args_file = args_file, + ) + return phase_common_runfiles(ctx, p, args) + +def phase_common_runfiles(ctx, p, _args = struct()): + return _phase_runfiles( + ctx, + _args.transitive_files if hasattr(_args, "transitive_files") else depset( + [p.declare_executable, p.java_wrapper] + ctx.files._java_runtime, + transitive = [p.compile.rjars], + ), + _args.args_file if hasattr(_args, "args_file") else None, + ) + +def _phase_runfiles( + ctx, + transitive_files, + args_file): + return struct( + runfiles = ctx.runfiles( + transitive_files = transitive_files, + collect_data = True, + ), + args_file = args_file, + ) + +def _scala_test_flags(ctx): + # output report test duration + flags = "-oD" + if ctx.attr.full_stacktraces: + flags += "F" + else: + flags += "S" + if not ctx.attr.colors: + flags += "W" + return flags diff --git a/scala/private/phases/phase_scala_provider.bzl b/scala/private/phases/phase_scala_provider.bzl new file mode 100644 index 000000000..3a4f821f6 --- /dev/null +++ b/scala/private/phases/phase_scala_provider.bzl @@ -0,0 +1,45 @@ +# +# PHASE: scala provider +# +# DOCUMENT THIS +# +load( + "@io_bazel_rules_scala//scala:providers.bzl", + "create_scala_provider", +) + +def phase_library_scala_provider(ctx, p): + args = struct( + rjars = depset( + transitive = [p.compile.rjars, p.init.exports_jars.transitive_runtime_jars], + ), + compile_jars = depset( + p.compile.ijars, + transitive = [p.init.exports_jars.compile_jars], + ), + ) + return phase_common_scala_provider(ctx, p, args) + +def phase_common_scala_provider(ctx, p, _args = struct()): + return _phase_scala_provider( + ctx, + p, + _args.rjars if hasattr(_args, "rjars") else p.compile.rjars, + _args.compile_jars if hasattr(_args, "compile_jars") else depset(p.compile.ijars), + ) + +def _phase_scala_provider( + ctx, + p, + rjars, + compile_jars): + return create_scala_provider( + class_jar = p.compile.class_jar, + compile_jars = compile_jars, + deploy_jar = ctx.outputs.deploy_jar, + full_jars = p.compile.full_jars, + ijar = p.compile.class_jar, # we aren't using ijar here + source_jars = p.compile.source_jars, + statsfile = ctx.outputs.statsfile, + transitive_runtime_jars = rjars, + ) diff --git a/scala/private/phases/phase_unused_deps_checker.bzl b/scala/private/phases/phase_unused_deps_checker.bzl new file mode 100644 index 000000000..4757118cf --- /dev/null +++ b/scala/private/phases/phase_unused_deps_checker.bzl @@ -0,0 +1,12 @@ +# +# PHASE: unused deps checker +# +# DOCUMENT THIS +# +load( + "@io_bazel_rules_scala//scala/private:rule_impls.bzl", + "get_unused_dependency_checker_mode", +) + +def phase_unused_deps_checker(ctx, p): + return get_unused_dependency_checker_mode(ctx) diff --git a/scala/private/phases/phase_write_executable.bzl b/scala/private/phases/phase_write_executable.bzl new file mode 100644 index 000000000..93a6784b5 --- /dev/null +++ b/scala/private/phases/phase_write_executable.bzl @@ -0,0 +1,72 @@ +# +# PHASE: write executable +# +# DOCUMENT THIS +# +load( + "@io_bazel_rules_scala//scala/private:rule_impls.bzl", + "expand_location", + "first_non_empty", + "write_executable", +) + +def phase_test_write_executable(ctx, p): + # jvm_flags passed in on the target override scala_test_jvm_flags passed in on the + # toolchain + final_jvm_flags = first_non_empty( + ctx.attr.jvm_flags, + ctx.toolchains["@io_bazel_rules_scala//scala:toolchain_type"].scala_test_jvm_flags, + ) + args = struct( + rjars = p.coverage_runfiles.rjars, + jvm_flags = [ + "-DRULES_SCALA_MAIN_WS_NAME=%s" % ctx.workspace_name, + "-DRULES_SCALA_ARGS_FILE=%s" % p.runfiles.args_file.short_path, + ] + expand_location(ctx, final_jvm_flags), + use_jacoco = ctx.configuration.coverage_enabled, + ) + return phase_common_write_executable(ctx, p, args) + +def phase_repl_write_executable(ctx, p): + args = struct( + jvm_flags = ["-Dscala.usejavacp=true"] + ctx.attr.jvm_flags, + main_class = "scala.tools.nsc.MainGenericRunner", + ) + return phase_common_write_executable(ctx, p, args) + +def phase_junit_test_write_executable(ctx, p): + args = struct( + jvm_flags = p.jvm_flags + ctx.attr.jvm_flags, + main_class = "com.google.testing.junit.runner.BazelTestRunner", + ) + return phase_common_write_executable(ctx, p, args) + +def phase_common_write_executable(ctx, p, _args = struct()): + return _phase_write_executable( + ctx, + p, + _args.rjars if hasattr(_args, "rjars") else p.compile.rjars, + _args.jvm_flags if hasattr(_args, "jvm_flags") else ctx.attr.jvm_flags, + _args.use_jacoco if hasattr(_args, "use_jacoco") else False, + _args.main_class if hasattr(_args, "main_class") else ctx.attr.main_class, + ) + +def _phase_write_executable( + ctx, + p, + rjars, + jvm_flags, + use_jacoco, + main_class): + executable = p.declare_executable + wrapper = p.java_wrapper + + return write_executable( + ctx, + executable, + rjars, + main_class, + jvm_flags, + wrapper, + use_jacoco, + ) diff --git a/scala/private/phases/phases.bzl b/scala/private/phases/phases.bzl new file mode 100644 index 000000000..12d03ab3c --- /dev/null +++ b/scala/private/phases/phases.bzl @@ -0,0 +1,127 @@ +load( + "@io_bazel_rules_scala//scala/private:phases/api.bzl", + _run_phases = "run_phases", +) +load( + "@io_bazel_rules_scala//scala/private:phases/phase_write_executable.bzl", + _phase_common_write_executable = "phase_common_write_executable", + _phase_junit_test_write_executable = "phase_junit_test_write_executable", + _phase_repl_write_executable = "phase_repl_write_executable", + _phase_test_write_executable = "phase_test_write_executable", +) +load( + "@io_bazel_rules_scala//scala/private:phases/phase_java_wrapper.bzl", + _phase_common_java_wrapper = "phase_common_java_wrapper", + _phase_repl_java_wrapper = "phase_repl_java_wrapper", +) +load( + "@io_bazel_rules_scala//scala/private:phases/phase_collect_jars.bzl", + _phase_common_collect_jars = "phase_common_collect_jars", + _phase_junit_test_collect_jars = "phase_junit_test_collect_jars", + _phase_library_for_plugin_bootstrapping_collect_jars = "phase_library_for_plugin_bootstrapping_collect_jars", + _phase_macro_library_collect_jars = "phase_macro_library_collect_jars", + _phase_repl_collect_jars = "phase_repl_collect_jars", + _phase_test_collect_jars = "phase_test_collect_jars", +) +load( + "@io_bazel_rules_scala//scala/private:phases/phase_compile.bzl", + _phase_binary_compile = "phase_binary_compile", + _phase_common_compile = "phase_common_compile", + _phase_junit_test_compile = "phase_junit_test_compile", + _phase_library_compile = "phase_library_compile", + _phase_library_for_plugin_bootstrapping_compile = "phase_library_for_plugin_bootstrapping_compile", + _phase_macro_library_compile = "phase_macro_library_compile", + _phase_repl_compile = "phase_repl_compile", + _phase_test_compile = "phase_test_compile", +) +load( + "@io_bazel_rules_scala//scala/private:phases/phase_scala_provider.bzl", + _phase_common_scala_provider = "phase_common_scala_provider", + _phase_library_scala_provider = "phase_library_scala_provider", +) +load( + "@io_bazel_rules_scala//scala/private:phases/phase_runfiles.bzl", + _phase_common_runfiles = "phase_common_runfiles", + _phase_library_runfiles = "phase_library_runfiles", + _phase_test_runfiles = "phase_test_runfiles", +) +load( + "@io_bazel_rules_scala//scala/private:phases/phase_final.bzl", + _phase_binary_final = "phase_binary_final", + _phase_library_final = "phase_library_final", + _phase_test_final = "phase_test_final", +) +load( + "@io_bazel_rules_scala//scala/private:phases/phase_init.bzl", + _phase_common_init = "phase_common_init", + _phase_library_init = "phase_library_init", +) +load("@io_bazel_rules_scala//scala/private:phases/phase_unused_deps_checker.bzl", _phase_unused_deps_checker = "phase_unused_deps_checker") +load("@io_bazel_rules_scala//scala/private:phases/phase_declare_executable.bzl", _phase_declare_executable = "phase_declare_executable") +load("@io_bazel_rules_scala//scala/private:phases/phase_merge_jars.bzl", _phase_merge_jars = "phase_merge_jars") +load("@io_bazel_rules_scala//scala/private:phases/phase_jvm_flags.bzl", _phase_jvm_flags = "phase_jvm_flags") +load("@io_bazel_rules_scala//scala/private:phases/phase_coverage_runfiles.bzl", _phase_coverage_runfiles = "phase_coverage_runfiles") + +# API +run_phases = _run_phases + +# init +phase_common_init = _phase_common_init +phase_library_init = _phase_library_init + +# unused_deps_checker +phase_unused_deps_checker = _phase_unused_deps_checker + +# declare_executable +phase_declare_executable = _phase_declare_executable + +# merge_jars +phase_merge_jars = _phase_merge_jars + +# jvm_flags +phase_jvm_flags = _phase_jvm_flags + +# coverage_runfiles +phase_coverage_runfiles = _phase_coverage_runfiles + +# write_executable +phase_test_write_executable = _phase_test_write_executable +phase_repl_write_executable = _phase_repl_write_executable +phase_junit_test_write_executable = _phase_junit_test_write_executable +phase_common_write_executable = _phase_common_write_executable + +# java_wrapper +phase_repl_java_wrapper = _phase_repl_java_wrapper +phase_common_java_wrapper = _phase_common_java_wrapper + +# collect_jars +phase_test_collect_jars = _phase_test_collect_jars +phase_repl_collect_jars = _phase_repl_collect_jars +phase_macro_library_collect_jars = _phase_macro_library_collect_jars +phase_junit_test_collect_jars = _phase_junit_test_collect_jars +phase_library_for_plugin_bootstrapping_collect_jars = _phase_library_for_plugin_bootstrapping_collect_jars +phase_common_collect_jars = _phase_common_collect_jars + +# compile +phase_binary_compile = _phase_binary_compile +phase_library_compile = _phase_library_compile +phase_library_for_plugin_bootstrapping_compile = _phase_library_for_plugin_bootstrapping_compile +phase_macro_library_compile = _phase_macro_library_compile +phase_junit_test_compile = _phase_junit_test_compile +phase_repl_compile = _phase_repl_compile +phase_test_compile = _phase_test_compile +phase_common_compile = _phase_common_compile + +# scala_provider +phase_library_scala_provider = _phase_library_scala_provider +phase_common_scala_provider = _phase_common_scala_provider + +# runfiles +phase_library_runfiles = _phase_library_runfiles +phase_test_runfiles = _phase_test_runfiles +phase_common_runfiles = _phase_common_runfiles + +# final +phase_binary_final = _phase_binary_final +phase_library_final = _phase_library_final +phase_test_final = _phase_test_final From 33bb583481c53aef3124e4a2c75287a0766d9318 Mon Sep 17 00:00:00 2001 From: Bor Kae Hwang Date: Fri, 25 Oct 2019 16:04:48 -0600 Subject: [PATCH 2/8] Refactor rules implementation into configurable phases --- scala/private/rule_impls.bzl | 73 ---------- scala/private/rules/scala_binary.bzl | 76 ++++------ scala/private/rules/scala_junit_test.bzl | 145 ++++--------------- scala/private/rules/scala_library.bzl | 171 ++++++----------------- scala/private/rules/scala_repl.bzl | 99 ++++--------- scala/private/rules/scala_test.bzl | 158 ++++----------------- 6 files changed, 157 insertions(+), 565 deletions(-) diff --git a/scala/private/rule_impls.bzl b/scala/private/rule_impls.bzl index f57f905e3..925179430 100644 --- a/scala/private/rule_impls.bzl +++ b/scala/private/rule_impls.bzl @@ -811,79 +811,6 @@ def get_unused_dependency_checker_mode(ctx): else: return ctx.toolchains["@io_bazel_rules_scala//scala:toolchain_type"].unused_dependency_checker_mode -# Common code shared by all scala binary implementations. -def scala_binary_common( - ctx, - executable, - cjars, - rjars, - transitive_compile_time_jars, - jars2labels, - java_wrapper, - unused_dependency_checker_mode, - unused_dependency_checker_ignored_targets, - deps_providers, - implicit_junit_deps_needed_for_java_compilation = [], - runfiles_ext = []): - write_manifest(ctx) - outputs = compile_or_empty( - ctx, - ctx.outputs.manifest, - cjars, - depset(), - False, - transitive_compile_time_jars, - jars2labels.jars_to_labels, - implicit_junit_deps_needed_for_java_compilation, - unused_dependency_checker_ignored_targets = - unused_dependency_checker_ignored_targets, - unused_dependency_checker_mode = unused_dependency_checker_mode, - deps_providers = deps_providers, - ) # no need to build an ijar for an executable - rjars = depset(outputs.full_jars, transitive = [rjars]) - - merge_jars( - actions = ctx.actions, - deploy_jar = ctx.outputs.deploy_jar, - singlejar_executable = ctx.executable._singlejar, - jars_list = rjars.to_list(), - main_class = getattr(ctx.attr, "main_class", ""), - progress_message = "Merging Scala binary jar: %s" % ctx.label, - ) - - runfiles = ctx.runfiles( - transitive_files = depset( - [executable, java_wrapper] + ctx.files._java_runtime + runfiles_ext, - transitive = [rjars], - ), - collect_data = True, - ) - - source_jars = pack_source_jars(ctx) + outputs.source_jars - - scalaattr = create_scala_provider( - class_jar = outputs.class_jar, - compile_jars = depset(outputs.ijars), - deploy_jar = ctx.outputs.deploy_jar, - full_jars = outputs.full_jars, - ijar = outputs.class_jar, # we aren't using ijar here - source_jars = source_jars, - statsfile = ctx.outputs.statsfile, - transitive_runtime_jars = rjars, - ) - - return struct( - executable = executable, - coverage = outputs.coverage, - files = depset([executable, ctx.outputs.jar]), - instrumented_files = outputs.coverage.instrumented_files, - providers = [outputs.merged_provider, jars2labels] + outputs.coverage.providers, - runfiles = runfiles, - scala = scalaattr, - transitive_rjars = - rjars, #calling rules need this for the classpath in the launcher - ) - def _pack_source_jar(ctx): # collect .scala sources and pack a source jar for Scala scala_sources = [ diff --git a/scala/private/rules/scala_binary.bzl b/scala/private/rules/scala_binary.bzl index df4dcbea5..cbcadc907 100644 --- a/scala/private/rules/scala_binary.bzl +++ b/scala/private/rules/scala_binary.bzl @@ -9,58 +9,36 @@ load( ) load("@io_bazel_rules_scala//scala/private:common_outputs.bzl", "common_outputs") load( - "@io_bazel_rules_scala//scala/private:rule_impls.bzl", - "collect_jars_from_common_ctx", - "declare_executable", - "get_scalac_provider", - "get_unused_dependency_checker_mode", - "scala_binary_common", - "write_executable", - "write_java_wrapper", + "@io_bazel_rules_scala//scala/private:phases/phases.bzl", + "phase_binary_compile", + "phase_binary_final", + "phase_common_collect_jars", + "phase_common_init", + "phase_common_java_wrapper", + "phase_common_runfiles", + "phase_common_scala_provider", + "phase_common_write_executable", + "phase_declare_executable", + "phase_merge_jars", + "phase_unused_deps_checker", + "run_phases", ) def _scala_binary_impl(ctx): - scalac_provider = get_scalac_provider(ctx) - unused_dependency_checker_mode = get_unused_dependency_checker_mode(ctx) - unused_dependency_checker_is_off = unused_dependency_checker_mode == "off" - - jars = collect_jars_from_common_ctx( - ctx, - scalac_provider.default_classpath, - unused_dependency_checker_is_off = unused_dependency_checker_is_off, - ) - (cjars, transitive_rjars) = (jars.compile_jars, jars.transitive_runtime_jars) - - wrapper = write_java_wrapper(ctx, "", "") - - executable = declare_executable(ctx) - - out = scala_binary_common( - ctx, - executable, - cjars, - transitive_rjars, - jars.transitive_compile_jars, - jars.jars2labels, - wrapper, - unused_dependency_checker_ignored_targets = [ - target.label - for target in scalac_provider.default_classpath + - ctx.attr.unused_dependency_checker_ignored_targets - ], - unused_dependency_checker_mode = unused_dependency_checker_mode, - deps_providers = jars.deps_providers, - ) - write_executable( - ctx = ctx, - executable = executable, - jvm_flags = ctx.attr.jvm_flags, - main_class = ctx.attr.main_class, - rjars = out.transitive_rjars, - use_jacoco = False, - wrapper = wrapper, - ) - return out + return run_phases(ctx, [ + ("init", phase_common_init), + ("unused_deps_checker", phase_unused_deps_checker), + ("collect_jars", phase_common_collect_jars), + ("java_wrapper", phase_common_java_wrapper), + ("declare_executable", phase_declare_executable), + # no need to build an ijar for an executable + ("compile", phase_binary_compile), + ("merge_jars", phase_merge_jars), + ("runfiles", phase_common_runfiles), + ("scala_provider", phase_common_scala_provider), + ("write_executable", phase_common_write_executable), + ("final", phase_binary_final), + ]).final _scala_binary_attrs = { "main_class": attr.string(mandatory = True), diff --git a/scala/private/rules/scala_junit_test.bzl b/scala/private/rules/scala_junit_test.bzl index a36b8082c..d43938be9 100644 --- a/scala/private/rules/scala_junit_test.bzl +++ b/scala/private/rules/scala_junit_test.bzl @@ -8,129 +8,42 @@ load( ) load("@io_bazel_rules_scala//scala/private:common_outputs.bzl", "common_outputs") load( - "@io_bazel_rules_scala//scala/private:rule_impls.bzl", - "collect_jars_from_common_ctx", - "declare_executable", - "get_scalac_provider", - "get_unused_dependency_checker_mode", - "scala_binary_common", - "write_executable", - "write_java_wrapper", + "@io_bazel_rules_scala//scala/private:phases/phases.bzl", + "phase_binary_final", + "phase_common_init", + "phase_common_java_wrapper", + "phase_common_runfiles", + "phase_common_scala_provider", + "phase_declare_executable", + "phase_junit_test_collect_jars", + "phase_junit_test_compile", + "phase_junit_test_write_executable", + "phase_jvm_flags", + "phase_merge_jars", + "phase_unused_deps_checker", + "run_phases", ) -def _gen_test_suite_flags_based_on_prefixes_and_suffixes(ctx, archives): - return struct( - archiveFlag = "-Dbazel.discover.classes.archives.file.paths=%s" % - archives, - prefixesFlag = "-Dbazel.discover.classes.prefixes=%s" % ",".join( - ctx.attr.prefixes, - ), - printFlag = "-Dbazel.discover.classes.print.discovered=%s" % - ctx.attr.print_discovered_classes, - suffixesFlag = "-Dbazel.discover.classes.suffixes=%s" % ",".join( - ctx.attr.suffixes, - ), - testSuiteFlag = "-Dbazel.test_suite=%s" % ctx.attr.suite_class, - ) - -def _serialize_archives_short_path(archives): - archives_short_path = "" - for archive in archives: - archives_short_path += archive.short_path + "," - return archives_short_path[:-1] #remove redundant comma - -def _get_test_archive_jars(ctx, test_archives): - flattened_list = [] - for archive in test_archives: - class_jars = [java_output.class_jar for java_output in archive[JavaInfo].outputs.jars] - flattened_list.extend(class_jars) - return flattened_list - def _scala_junit_test_impl(ctx): if (not (ctx.attr.prefixes) and not (ctx.attr.suffixes)): fail( "Setting at least one of the attributes ('prefixes','suffixes') is required", ) - scalac_provider = get_scalac_provider(ctx) - - unused_dependency_checker_mode = get_unused_dependency_checker_mode(ctx) - unused_dependency_checker_ignored_targets = [ - target.label - for target in scalac_provider.default_classpath + - ctx.attr.unused_dependency_checker_ignored_targets - ] + [ - ctx.attr._junit.label, - ctx.attr._hamcrest.label, - ctx.attr.suite_label.label, - ctx.attr._bazel_test_runner.label, - ] - unused_dependency_checker_is_off = unused_dependency_checker_mode == "off" - - jars = collect_jars_from_common_ctx( - ctx, - scalac_provider.default_classpath, - extra_deps = [ - ctx.attr._junit, - ctx.attr._hamcrest, - ctx.attr.suite_label, - ctx.attr._bazel_test_runner, - ], - unused_dependency_checker_is_off = unused_dependency_checker_is_off, - ) - (cjars, transitive_rjars) = (jars.compile_jars, jars.transitive_runtime_jars) - implicit_junit_deps_needed_for_java_compilation = [ - ctx.attr._junit, - ctx.attr._hamcrest, - ] - - executable = declare_executable(ctx) - - wrapper = write_java_wrapper(ctx, "", "") - out = scala_binary_common( - ctx, - executable, - cjars, - transitive_rjars, - jars.transitive_compile_jars, - jars.jars2labels, - wrapper, - implicit_junit_deps_needed_for_java_compilation = - implicit_junit_deps_needed_for_java_compilation, - unused_dependency_checker_ignored_targets = - unused_dependency_checker_ignored_targets, - unused_dependency_checker_mode = unused_dependency_checker_mode, - deps_providers = jars.deps_providers, - ) - - if ctx.attr.tests_from: - archives = _get_test_archive_jars(ctx, ctx.attr.tests_from) - else: - archives = [archive.class_jar for archive in out.scala.outputs.jars] - - serialized_archives = _serialize_archives_short_path(archives) - test_suite = _gen_test_suite_flags_based_on_prefixes_and_suffixes( - ctx, - serialized_archives, - ) - launcherJvmFlags = [ - "-ea", - test_suite.archiveFlag, - test_suite.prefixesFlag, - test_suite.suffixesFlag, - test_suite.printFlag, - test_suite.testSuiteFlag, - ] - write_executable( - ctx = ctx, - executable = executable, - jvm_flags = launcherJvmFlags + ctx.attr.jvm_flags, - main_class = "com.google.testing.junit.runner.BazelTestRunner", - rjars = out.transitive_rjars, - use_jacoco = False, - wrapper = wrapper, - ) - - return out + return run_phases(ctx, [ + ("init", phase_common_init), + ("unused_deps_checker", phase_unused_deps_checker), + ("collect_jars", phase_junit_test_collect_jars), + ("java_wrapper", phase_common_java_wrapper), + ("declare_executable", phase_declare_executable), + # no need to build an ijar for an executable + ("compile", phase_junit_test_compile), + ("merge_jars", phase_merge_jars), + ("runfiles", phase_common_runfiles), + ("scala_provider", phase_common_scala_provider), + ("jvm_flags", phase_jvm_flags), + ("write_executable", phase_junit_test_write_executable), + ("final", phase_binary_final), + ]).final _scala_junit_test_attrs = { "prefixes": attr.string_list(default = []), diff --git a/scala/private/rules/scala_library.bzl b/scala/private/rules/scala_library.bzl index 5978cb333..d49a6abf0 100644 --- a/scala/private/rules/scala_library.bzl +++ b/scala/private/rules/scala_library.bzl @@ -1,10 +1,6 @@ -load("@io_bazel_rules_scala//scala:providers.bzl", "create_scala_provider") load( "@io_bazel_rules_scala//scala/private:common.bzl", - "collect_jars", - "collect_srcjars", "sanitize_string_for_usage", - "write_manifest", ) load( "@io_bazel_rules_scala//scala/private:common_attributes.bzl", @@ -19,13 +15,20 @@ load( _coverage_replacements_provider = "coverage_replacements_provider", ) load( - "@io_bazel_rules_scala//scala/private:rule_impls.bzl", - "collect_jars_from_common_ctx", - "compile_or_empty", - "get_scalac_provider", - "get_unused_dependency_checker_mode", - "merge_jars", - "pack_source_jars", + "@io_bazel_rules_scala//scala/private:phases/phases.bzl", + "phase_common_collect_jars", + "phase_library_compile", + "phase_library_final", + "phase_library_for_plugin_bootstrapping_collect_jars", + "phase_library_for_plugin_bootstrapping_compile", + "phase_library_init", + "phase_library_runfiles", + "phase_library_scala_provider", + "phase_macro_library_collect_jars", + "phase_macro_library_compile", + "phase_merge_jars", + "phase_unused_deps_checker", + "run_phases", ) ## @@ -40,110 +43,22 @@ _library_attrs = { ), } -def _lib( - ctx, - base_classpath, - non_macro_lib, - unused_dependency_checker_mode, - unused_dependency_checker_ignored_targets): - # Build up information from dependency-like attributes - - # This will be used to pick up srcjars from non-scala library - # targets (like thrift code generation) - srcjars = collect_srcjars(ctx.attr.deps) - - unused_dependency_checker_is_off = unused_dependency_checker_mode == "off" - jars = collect_jars_from_common_ctx( - ctx, - base_classpath, - unused_dependency_checker_is_off = unused_dependency_checker_is_off, - ) - - (cjars, transitive_rjars) = (jars.compile_jars, jars.transitive_runtime_jars) - - write_manifest(ctx) - outputs = compile_or_empty( - ctx, - ctx.outputs.manifest, - cjars, - srcjars, - non_macro_lib, - jars.transitive_compile_jars, - jars.jars2labels.jars_to_labels, - [], - unused_dependency_checker_ignored_targets = [ - target.label - for target in base_classpath + ctx.attr.exports + - unused_dependency_checker_ignored_targets - ], - unused_dependency_checker_mode = unused_dependency_checker_mode, - deps_providers = jars.deps_providers, - ) - - transitive_rjars = depset(outputs.full_jars, transitive = [transitive_rjars]) - - merge_jars( - actions = ctx.actions, - deploy_jar = ctx.outputs.deploy_jar, - singlejar_executable = ctx.executable._singlejar, - jars_list = transitive_rjars.to_list(), - main_class = getattr(ctx.attr, "main_class", ""), - progress_message = "Merging Scala library jar: %s" % ctx.label, - ) - - # Using transitive_files since transitive_rjars a depset and avoiding linearization - runfiles = ctx.runfiles( - transitive_files = transitive_rjars, - collect_data = True, - ) - - # Add information from exports (is key that AFTER all build actions/runfiles analysis) - # Since after, will not show up in deploy_jar or old jars runfiles - # Notice that compile_jars is intentionally transitive for exports - exports_jars = collect_jars(ctx.attr.exports) - transitive_rjars = depset( - transitive = [transitive_rjars, exports_jars.transitive_runtime_jars], - ) - - source_jars = pack_source_jars(ctx) + outputs.source_jars - - scalaattr = create_scala_provider( - class_jar = outputs.class_jar, - compile_jars = depset( - outputs.ijars, - transitive = [exports_jars.compile_jars], - ), - deploy_jar = ctx.outputs.deploy_jar, - full_jars = outputs.full_jars, - ijar = outputs.ijar, - source_jars = source_jars, - statsfile = ctx.outputs.statsfile, - transitive_runtime_jars = transitive_rjars, - ) - - return struct( - files = depset([ctx.outputs.jar] + outputs.full_jars), # Here is the default output - instrumented_files = outputs.coverage.instrumented_files, - jars_to_labels = jars.jars2labels, - providers = [outputs.merged_provider, jars.jars2labels] + outputs.coverage.providers, - runfiles = runfiles, - scala = scalaattr, - ) - ## # scala_library ## def _scala_library_impl(ctx): - scalac_provider = get_scalac_provider(ctx) - unused_dependency_checker_mode = get_unused_dependency_checker_mode(ctx) - return _lib( - ctx, - scalac_provider.default_classpath, - True, - unused_dependency_checker_mode, - ctx.attr.unused_dependency_checker_ignored_targets, - ) + # Build up information from dependency-like attributes + return run_phases(ctx, [ + ("init", phase_library_init), + ("unused_deps_checker", phase_unused_deps_checker), + ("collect_jars", phase_common_collect_jars), + ("compile", phase_library_compile), + ("merge_jars", phase_merge_jars), + ("runfiles", phase_library_runfiles), + ("scala_provider", phase_library_scala_provider), + ("final", phase_library_final), + ]).final _scala_library_attrs = {} @@ -195,14 +110,15 @@ def scala_library_suite( ## def _scala_library_for_plugin_bootstrapping_impl(ctx): - scalac_provider = get_scalac_provider(ctx) - return _lib( - ctx, - scalac_provider.default_classpath, - True, - unused_dependency_checker_ignored_targets = [], - unused_dependency_checker_mode = "off", - ) + return run_phases(ctx, [ + ("init", phase_library_init), + ("collect_jars", phase_library_for_plugin_bootstrapping_collect_jars), + ("compile", phase_library_for_plugin_bootstrapping_compile), + ("merge_jars", phase_merge_jars), + ("runfiles", phase_library_runfiles), + ("scala_provider", phase_library_scala_provider), + ("final", phase_library_final), + ]).final # the scala compiler plugin used for dependency analysis is compiled using `scala_library`. # in order to avoid cyclic dependencies `scala_library_for_plugin_bootstrapping` was created for this purpose, @@ -232,15 +148,16 @@ scala_library_for_plugin_bootstrapping = rule( ## def _scala_macro_library_impl(ctx): - scalac_provider = get_scalac_provider(ctx) - unused_dependency_checker_mode = get_unused_dependency_checker_mode(ctx) - return _lib( - ctx, - scalac_provider.default_macro_classpath, - False, # don't build the ijar for macros - unused_dependency_checker_mode, - ctx.attr.unused_dependency_checker_ignored_targets, - ) + return run_phases(ctx, [ + ("init", phase_library_init), + ("unused_deps_checker", phase_unused_deps_checker), + ("collect_jars", phase_macro_library_collect_jars), + ("compile", phase_macro_library_compile), + ("merge_jars", phase_merge_jars), + ("runfiles", phase_library_runfiles), + ("scala_provider", phase_library_scala_provider), + ("final", phase_library_final), + ]).final _scala_macro_library_attrs = { "main_class": attr.string(), diff --git a/scala/private/rules/scala_repl.bzl b/scala/private/rules/scala_repl.bzl index 78630ff3b..b4e0d1155 100644 --- a/scala/private/rules/scala_repl.bzl +++ b/scala/private/rules/scala_repl.bzl @@ -9,80 +9,37 @@ load( ) load("@io_bazel_rules_scala//scala/private:common_outputs.bzl", "common_outputs") load( - "@io_bazel_rules_scala//scala/private:rule_impls.bzl", - "collect_jars_from_common_ctx", - "declare_executable", - "get_scalac_provider", - "get_unused_dependency_checker_mode", - "scala_binary_common", - "write_executable", - "write_java_wrapper", + "@io_bazel_rules_scala//scala/private:phases/phases.bzl", + "phase_binary_final", + "phase_common_init", + "phase_common_runfiles", + "phase_common_scala_provider", + "phase_declare_executable", + "phase_merge_jars", + "phase_repl_collect_jars", + "phase_repl_compile", + "phase_repl_java_wrapper", + "phase_repl_write_executable", + "phase_unused_deps_checker", + "run_phases", ) def _scala_repl_impl(ctx): - scalac_provider = get_scalac_provider(ctx) - - unused_dependency_checker_mode = get_unused_dependency_checker_mode(ctx) - unused_dependency_checker_is_off = unused_dependency_checker_mode == "off" - - # need scala-compiler for MainGenericRunner below - jars = collect_jars_from_common_ctx( - ctx, - scalac_provider.default_repl_classpath, - unused_dependency_checker_is_off = unused_dependency_checker_is_off, - ) - (cjars, transitive_rjars) = (jars.compile_jars, jars.transitive_runtime_jars) - - args = " ".join(ctx.attr.scalacopts) - - executable = declare_executable(ctx) - - wrapper = write_java_wrapper( - ctx, - args, - wrapper_preamble = """ -# save stty like in bin/scala -saved_stty=$(stty -g 2>/dev/null) -if [[ ! $? ]]; then - saved_stty="" -fi -function finish() { - if [[ "$saved_stty" != "" ]]; then - stty $saved_stty - saved_stty="" - fi -} -trap finish EXIT -""", - ) - - out = scala_binary_common( - ctx, - executable, - cjars, - transitive_rjars, - jars.transitive_compile_jars, - jars.jars2labels, - wrapper, - unused_dependency_checker_ignored_targets = [ - target.label - for target in scalac_provider.default_repl_classpath + - ctx.attr.unused_dependency_checker_ignored_targets - ], - unused_dependency_checker_mode = unused_dependency_checker_mode, - deps_providers = jars.deps_providers, - ) - write_executable( - ctx = ctx, - executable = executable, - jvm_flags = ["-Dscala.usejavacp=true"] + ctx.attr.jvm_flags, - main_class = "scala.tools.nsc.MainGenericRunner", - rjars = out.transitive_rjars, - use_jacoco = False, - wrapper = wrapper, - ) - - return out + return run_phases(ctx, [ + ("init", phase_common_init), + ("unused_deps_checker", phase_unused_deps_checker), + # need scala-compiler for MainGenericRunner below + ("collect_jars", phase_repl_collect_jars), + ("java_wrapper", phase_repl_java_wrapper), + ("declare_executable", phase_declare_executable), + # no need to build an ijar for an executable + ("compile", phase_repl_compile), + ("merge_jars", phase_merge_jars), + ("runfiles", phase_common_runfiles), + ("scala_provider", phase_common_scala_provider), + ("write_executable", phase_repl_write_executable), + ("final", phase_binary_final), + ]).final _scala_repl_attrs = { "jvm_flags": attr.string_list(), diff --git a/scala/private/rules/scala_test.bzl b/scala/private/rules/scala_test.bzl index 7d86b2e75..80b156c38 100644 --- a/scala/private/rules/scala_test.bzl +++ b/scala/private/rules/scala_test.bzl @@ -9,138 +9,38 @@ load( load("@io_bazel_rules_scala//scala/private:common.bzl", "sanitize_string_for_usage") load("@io_bazel_rules_scala//scala/private:common_outputs.bzl", "common_outputs") load( - "@io_bazel_rules_scala//scala/private:coverage_replacements_provider.bzl", - _coverage_replacements_provider = "coverage_replacements_provider", -) -load( - "@io_bazel_rules_scala//scala/private:rule_impls.bzl", - "collect_jars_from_common_ctx", - "declare_executable", - "expand_location", - "first_non_empty", - "get_scalac_provider", - "get_unused_dependency_checker_mode", - "scala_binary_common", - "write_executable", - "write_java_wrapper", + "@io_bazel_rules_scala//scala/private:phases/phases.bzl", + "phase_common_init", + "phase_common_java_wrapper", + "phase_common_scala_provider", + "phase_coverage_runfiles", + "phase_declare_executable", + "phase_merge_jars", + "phase_test_collect_jars", + "phase_test_compile", + "phase_test_final", + "phase_test_runfiles", + "phase_test_write_executable", + "phase_unused_deps_checker", + "run_phases", ) -def _scala_test_flags(ctx): - # output report test duration - flags = "-oD" - if ctx.attr.full_stacktraces: - flags += "F" - else: - flags += "S" - if not ctx.attr.colors: - flags += "W" - return flags - def _scala_test_impl(ctx): - scalac_provider = get_scalac_provider(ctx) - - unused_dependency_checker_mode = get_unused_dependency_checker_mode(ctx) - unused_dependency_checker_ignored_targets = [ - target.label - for target in scalac_provider.default_classpath + - ctx.attr.unused_dependency_checker_ignored_targets - ] - unused_dependency_checker_is_off = unused_dependency_checker_mode == "off" - - scalatest_base_classpath = scalac_provider.default_classpath + [ctx.attr._scalatest] - jars = collect_jars_from_common_ctx( - ctx, - scalatest_base_classpath, - extra_runtime_deps = [ - ctx.attr._scalatest_reporter, - ctx.attr._scalatest_runner, - ], - unused_dependency_checker_is_off = unused_dependency_checker_is_off, - ) - ( - cjars, - transitive_rjars, - transitive_compile_jars, - jars_to_labels, - ) = ( - jars.compile_jars, - jars.transitive_runtime_jars, - jars.transitive_compile_jars, - jars.jars2labels, - ) - - args = "\n".join([ - "-R", - ctx.outputs.jar.short_path, - _scala_test_flags(ctx), - "-C", - "io.bazel.rules.scala.JUnitXmlReporter", - ]) - - argsFile = ctx.actions.declare_file("%s.args" % ctx.label.name) - ctx.actions.write(argsFile, args) - - executable = declare_executable(ctx) - - wrapper = write_java_wrapper(ctx, "", "") - out = scala_binary_common( - ctx, - executable, - cjars, - transitive_rjars, - transitive_compile_jars, - jars_to_labels, - wrapper, - unused_dependency_checker_ignored_targets = - unused_dependency_checker_ignored_targets, - unused_dependency_checker_mode = unused_dependency_checker_mode, - runfiles_ext = [argsFile], - deps_providers = jars.deps_providers, - ) - - rjars = out.transitive_rjars - - coverage_runfiles = [] - if ctx.configuration.coverage_enabled and _coverage_replacements_provider.is_enabled(ctx): - coverage_replacements = _coverage_replacements_provider.from_ctx( - ctx, - base = out.coverage.replacements, - ).replacements - - rjars = depset([ - coverage_replacements[jar] if jar in coverage_replacements else jar - for jar in rjars.to_list() - ]) - coverage_runfiles = ctx.files._jacocorunner + ctx.files._lcov_merger + coverage_replacements.values() - - # jvm_flags passed in on the target override scala_test_jvm_flags passed in on the - # toolchain - final_jvm_flags = first_non_empty( - ctx.attr.jvm_flags, - ctx.toolchains["@io_bazel_rules_scala//scala:toolchain_type"].scala_test_jvm_flags, - ) - - coverage_runfiles.extend(write_executable( - ctx = ctx, - executable = executable, - jvm_flags = [ - "-DRULES_SCALA_MAIN_WS_NAME=%s" % ctx.workspace_name, - "-DRULES_SCALA_ARGS_FILE=%s" % argsFile.short_path, - ] + expand_location(ctx, final_jvm_flags), - main_class = ctx.attr.main_class, - rjars = rjars, - use_jacoco = ctx.configuration.coverage_enabled, - wrapper = wrapper, - )) - - return struct( - executable = executable, - files = out.files, - instrumented_files = out.instrumented_files, - providers = out.providers, - runfiles = ctx.runfiles(coverage_runfiles, transitive_files = out.runfiles.files), - scala = out.scala, - ) + return run_phases(ctx, [ + ("init", phase_common_init), + ("unused_deps_checker", phase_unused_deps_checker), + ("collect_jars", phase_test_collect_jars), + ("java_wrapper", phase_common_java_wrapper), + ("declare_executable", phase_declare_executable), + # no need to build an ijar for an executable + ("compile", phase_test_compile), + ("merge_jars", phase_merge_jars), + ("runfiles", phase_test_runfiles), + ("scala_provider", phase_common_scala_provider), + ("coverage_runfiles", phase_coverage_runfiles), + ("write_executable", phase_test_write_executable), + ("final", phase_test_final), + ]).final _scala_test_attrs = { "main_class": attr.string( From c22d3c0cf49357a3a29b543da3a5b19a50fecf09 Mon Sep 17 00:00:00 2001 From: Bor Kae Hwang Date: Fri, 25 Oct 2019 15:21:45 -0600 Subject: [PATCH 3/8] Customizable phases --- WORKSPACE | 23 ++++---- scala/private/phases/api.bzl | 37 ++++++++++++ scala/private/phases/phases.bzl | 2 + scala/private/rules/scala_binary.bzl | 28 ++++++--- scala/private/rules/scala_junit_test.bzl | 28 ++++++--- scala/private/rules/scala_library.bzl | 74 +++++++++++++++++------- scala/private/rules/scala_repl.bzl | 28 ++++++--- scala/private/rules/scala_test.bzl | 30 +++++++--- scala/providers.bzl | 7 +++ scala/scala.bzl | 15 +++++ 10 files changed, 207 insertions(+), 65 deletions(-) diff --git a/WORKSPACE b/WORKSPACE index e74e13b1e..35b0a9c60 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -2,6 +2,18 @@ workspace(name = "io_bazel_rules_scala") load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository") + +http_archive( + name = "com_github_bazelbuild_buildtools", + sha256 = "cdaac537b56375f658179ee2f27813cac19542443f4722b6730d84e4125355e6", + strip_prefix = "buildtools-f27d1753c8b3210d9e87cdc9c45bc2739ae2c2db", + url = "https://github.com/bazelbuild/buildtools/archive/f27d1753c8b3210d9e87cdc9c45bc2739ae2c2db.zip", +) + +load("@com_github_bazelbuild_buildtools//buildifier:deps.bzl", "buildifier_dependencies") + +buildifier_dependencies() + load("//scala:scala.bzl", "scala_repositories") scala_repositories() @@ -151,13 +163,6 @@ http_archive( url = "https://github.com/bazelbuild/rules_go/releases/download/0.18.7/rules_go-0.18.7.tar.gz", ) -http_archive( - name = "com_github_bazelbuild_buildtools", - sha256 = "cdaac537b56375f658179ee2f27813cac19542443f4722b6730d84e4125355e6", - strip_prefix = "buildtools-f27d1753c8b3210d9e87cdc9c45bc2739ae2c2db", - url = "https://github.com/bazelbuild/buildtools/archive/f27d1753c8b3210d9e87cdc9c45bc2739ae2c2db.zip", -) - load( "@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", @@ -168,10 +173,6 @@ go_rules_dependencies() go_register_toolchains() -load("@com_github_bazelbuild_buildtools//buildifier:deps.bzl", "buildifier_dependencies") - -buildifier_dependencies() - http_archive( name = "bazel_toolchains", sha256 = "5962fe677a43226c409316fcb321d668fc4b7fa97cb1f9ef45e7dc2676097b26", diff --git a/scala/private/phases/api.bzl b/scala/private/phases/api.bzl index afbcee020..76e41c73a 100644 --- a/scala/private/phases/api.bzl +++ b/scala/private/phases/api.bzl @@ -1,4 +1,33 @@ +load( + "@io_bazel_rules_scala//scala:providers.bzl", + _ScalaRulePhase = "ScalaRulePhase", +) + +def _adjust_phases(phases, adjustments): + if len(adjustments) == 0: + return phases + phases = phases[:] + for (relation, peer_name, name, function) in adjustments: + for idx, (needle, _) in enumerate(phases): + if needle == peer_name: + if relation in ["-", "before"]: + phases.insert(idx, (name, function)) + elif relation in ["+", "after"]: + phases.insert(idx + 1, (name, function)) + elif relation in ["=", "replace"]: + phases[idx] = (name, function) + return phases + def run_phases(ctx, phases): + phase_providers = [ + p[_ScalaRulePhase] + for p in ctx.attr._phase_providers + if _ScalaRulePhase in p + ] + + if phase_providers != []: + phases = _adjust_phases(phases, [p for pp in phase_providers for p in pp.phases]) + global_provider = {} current_provider = struct(**global_provider) for (name, function) in phases: @@ -8,3 +37,11 @@ def run_phases(ctx, phases): current_provider = struct(**global_provider) return current_provider + +def extras_phases(extras): + return { + "_phase_providers": attr.label_list( + default = [pp for extra in extras for pp in extra["phase_providers"]], + providers = [_ScalaRulePhase], + ), + } diff --git a/scala/private/phases/phases.bzl b/scala/private/phases/phases.bzl index 12d03ab3c..b41ca1825 100644 --- a/scala/private/phases/phases.bzl +++ b/scala/private/phases/phases.bzl @@ -1,5 +1,6 @@ load( "@io_bazel_rules_scala//scala/private:phases/api.bzl", + _extras_phases = "extras_phases", _run_phases = "run_phases", ) load( @@ -64,6 +65,7 @@ load("@io_bazel_rules_scala//scala/private:phases/phase_coverage_runfiles.bzl", # API run_phases = _run_phases +extras_phases = _extras_phases # init phase_common_init = _phase_common_init diff --git a/scala/private/rules/scala_binary.bzl b/scala/private/rules/scala_binary.bzl index cbcadc907..177fc9c27 100644 --- a/scala/private/rules/scala_binary.bzl +++ b/scala/private/rules/scala_binary.bzl @@ -1,5 +1,6 @@ """Builds Scala binaries""" +load("@bazel_skylib//lib:dicts.bzl", _dicts = "dicts") load( "@io_bazel_rules_scala//scala/private:common_attributes.bzl", "common_attrs", @@ -10,6 +11,7 @@ load( load("@io_bazel_rules_scala//scala/private:common_outputs.bzl", "common_outputs") load( "@io_bazel_rules_scala//scala/private:phases/phases.bzl", + "extras_phases", "phase_binary_compile", "phase_binary_final", "phase_common_collect_jars", @@ -54,11 +56,21 @@ _scala_binary_attrs.update(common_attrs) _scala_binary_attrs.update(resolve_deps) -scala_binary = rule( - attrs = _scala_binary_attrs, - executable = True, - fragments = ["java"], - outputs = common_outputs, - toolchains = ["@io_bazel_rules_scala//scala:toolchain_type"], - implementation = _scala_binary_impl, -) +def make_scala_binary(*extras): + return rule( + attrs = _dicts.add( + _scala_binary_attrs, + extras_phases(extras), + *[extra["attrs"] for extra in extras] + ), + executable = True, + fragments = ["java"], + outputs = _dicts.add( + common_outputs, + *[extra["outputs"] for extra in extras] + ), + toolchains = ["@io_bazel_rules_scala//scala:toolchain_type"], + implementation = _scala_binary_impl, + ) + +scala_binary = make_scala_binary() diff --git a/scala/private/rules/scala_junit_test.bzl b/scala/private/rules/scala_junit_test.bzl index d43938be9..2cab5e168 100644 --- a/scala/private/rules/scala_junit_test.bzl +++ b/scala/private/rules/scala_junit_test.bzl @@ -1,5 +1,6 @@ """Rules for writing tests with JUnit""" +load("@bazel_skylib//lib:dicts.bzl", _dicts = "dicts") load( "@io_bazel_rules_scala//scala/private:common_attributes.bzl", "common_attrs", @@ -9,6 +10,7 @@ load( load("@io_bazel_rules_scala//scala/private:common_outputs.bzl", "common_outputs") load( "@io_bazel_rules_scala//scala/private:phases/phases.bzl", + "extras_phases", "phase_binary_final", "phase_common_init", "phase_common_java_wrapper", @@ -106,11 +108,21 @@ _scala_junit_test_attrs.update({ "tests_from": attr.label_list(providers = [[JavaInfo]]), }) -scala_junit_test = rule( - attrs = _scala_junit_test_attrs, - fragments = ["java"], - outputs = common_outputs, - test = True, - toolchains = ["@io_bazel_rules_scala//scala:toolchain_type"], - implementation = _scala_junit_test_impl, -) +def make_scala_junit_test(*extras): + return rule( + attrs = _dicts.add( + _scala_junit_test_attrs, + extras_phases(extras), + *[extra["attrs"] for extra in extras] + ), + fragments = ["java"], + outputs = _dicts.add( + common_outputs, + *[extra["outputs"] for extra in extras] + ), + test = True, + toolchains = ["@io_bazel_rules_scala//scala:toolchain_type"], + implementation = _scala_junit_test_impl, + ) + +scala_junit_test = make_scala_junit_test() diff --git a/scala/private/rules/scala_library.bzl b/scala/private/rules/scala_library.bzl index d49a6abf0..81adfcd5f 100644 --- a/scala/private/rules/scala_library.bzl +++ b/scala/private/rules/scala_library.bzl @@ -1,3 +1,4 @@ +load("@bazel_skylib//lib:dicts.bzl", _dicts = "dicts") load( "@io_bazel_rules_scala//scala/private:common.bzl", "sanitize_string_for_usage", @@ -16,6 +17,7 @@ load( ) load( "@io_bazel_rules_scala//scala/private:phases/phases.bzl", + "extras_phases", "phase_common_collect_jars", "phase_library_compile", "phase_library_final", @@ -70,13 +72,23 @@ _scala_library_attrs.update(_library_attrs) _scala_library_attrs.update(resolve_deps) -scala_library = rule( - attrs = _scala_library_attrs, - fragments = ["java"], - outputs = common_outputs, - toolchains = ["@io_bazel_rules_scala//scala:toolchain_type"], - implementation = _scala_library_impl, -) +def make_scala_library(*extras): + return rule( + attrs = _dicts.add( + _scala_library_attrs, + extras_phases(extras), + *[extra["attrs"] for extra in extras] + ), + fragments = ["java"], + outputs = _dicts.add( + common_outputs, + *[extra["outputs"] for extra in extras] + ), + toolchains = ["@io_bazel_rules_scala//scala:toolchain_type"], + implementation = _scala_library_impl, + ) + +scala_library = make_scala_library() # Scala library suite generates a series of scala libraries # then it depends on them with a meta one which exports all the sub targets @@ -135,13 +147,23 @@ _scala_library_for_plugin_bootstrapping_attrs.update( common_attrs_for_plugin_bootstrapping, ) -scala_library_for_plugin_bootstrapping = rule( - attrs = _scala_library_for_plugin_bootstrapping_attrs, - fragments = ["java"], - outputs = common_outputs, - toolchains = ["@io_bazel_rules_scala//scala:toolchain_type"], - implementation = _scala_library_for_plugin_bootstrapping_impl, -) +def make_scala_library_for_plugin_bootstrapping(*extras): + return rule( + attrs = _dicts.add( + _scala_library_for_plugin_bootstrapping_attrs, + extras_phases(extras), + *[extra["attrs"] for extra in extras] + ), + fragments = ["java"], + outputs = _dicts.add( + common_outputs, + *[extra["outputs"] for extra in extras] + ), + toolchains = ["@io_bazel_rules_scala//scala:toolchain_type"], + implementation = _scala_library_for_plugin_bootstrapping_impl, + ) + +scala_library_for_plugin_bootstrapping = make_scala_library_for_plugin_bootstrapping() ## # scala_macro_library @@ -184,10 +206,20 @@ _scala_macro_library_attrs["unused_dependency_checker_mode"] = attr.string( mandatory = False, ) -scala_macro_library = rule( - attrs = _scala_macro_library_attrs, - fragments = ["java"], - outputs = common_outputs, - toolchains = ["@io_bazel_rules_scala//scala:toolchain_type"], - implementation = _scala_macro_library_impl, -) +def make_scala_macro_library(*extras): + return rule( + attrs = _dicts.add( + _scala_macro_library_attrs, + extras_phases(extras), + *[extra["attrs"] for extra in extras] + ), + fragments = ["java"], + outputs = _dicts.add( + common_outputs, + *[extra["outputs"] for extra in extras] + ), + toolchains = ["@io_bazel_rules_scala//scala:toolchain_type"], + implementation = _scala_macro_library_impl, + ) + +scala_macro_library = make_scala_macro_library() diff --git a/scala/private/rules/scala_repl.bzl b/scala/private/rules/scala_repl.bzl index b4e0d1155..6ee79c1b4 100644 --- a/scala/private/rules/scala_repl.bzl +++ b/scala/private/rules/scala_repl.bzl @@ -1,5 +1,6 @@ """Rule for launching a Scala REPL with dependencies""" +load("@bazel_skylib//lib:dicts.bzl", _dicts = "dicts") load( "@io_bazel_rules_scala//scala/private:common_attributes.bzl", "common_attrs", @@ -10,6 +11,7 @@ load( load("@io_bazel_rules_scala//scala/private:common_outputs.bzl", "common_outputs") load( "@io_bazel_rules_scala//scala/private:phases/phases.bzl", + "extras_phases", "phase_binary_final", "phase_common_init", "phase_common_runfiles", @@ -53,11 +55,21 @@ _scala_repl_attrs.update(common_attrs) _scala_repl_attrs.update(resolve_deps) -scala_repl = rule( - attrs = _scala_repl_attrs, - executable = True, - fragments = ["java"], - outputs = common_outputs, - toolchains = ["@io_bazel_rules_scala//scala:toolchain_type"], - implementation = _scala_repl_impl, -) +def make_scala_repl(*extras): + return rule( + attrs = _dicts.add( + _scala_repl_attrs, + extras_phases(extras), + *[extra["attrs"] for extra in extras] + ), + executable = True, + fragments = ["java"], + outputs = _dicts.add( + common_outputs, + *[extra["outputs"] for extra in extras] + ), + toolchains = ["@io_bazel_rules_scala//scala:toolchain_type"], + implementation = _scala_repl_impl, + ) + +scala_repl = make_scala_repl() diff --git a/scala/private/rules/scala_test.bzl b/scala/private/rules/scala_test.bzl index 80b156c38..79a86b658 100644 --- a/scala/private/rules/scala_test.bzl +++ b/scala/private/rules/scala_test.bzl @@ -1,5 +1,6 @@ """Rules for writing tests with ScalaTest""" +load("@bazel_skylib//lib:dicts.bzl", _dicts = "dicts") load( "@io_bazel_rules_scala//scala/private:common_attributes.bzl", "common_attrs", @@ -10,6 +11,7 @@ load("@io_bazel_rules_scala//scala/private:common.bzl", "sanitize_string_for_usa load("@io_bazel_rules_scala//scala/private:common_outputs.bzl", "common_outputs") load( "@io_bazel_rules_scala//scala/private:phases/phases.bzl", + "extras_phases", "phase_common_init", "phase_common_java_wrapper", "phase_common_scala_provider", @@ -91,15 +93,25 @@ _scala_test_attrs.update(common_attrs) _scala_test_attrs.update(_test_resolve_deps) -scala_test = rule( - attrs = _scala_test_attrs, - executable = True, - fragments = ["java"], - outputs = common_outputs, - test = True, - toolchains = ["@io_bazel_rules_scala//scala:toolchain_type"], - implementation = _scala_test_impl, -) +def make_scala_test(*extras): + return rule( + attrs = _dicts.add( + _scala_test_attrs, + extras_phases(extras), + *[extra["attrs"] for extra in extras] + ), + executable = True, + fragments = ["java"], + outputs = _dicts.add( + common_outputs, + *[extra["outputs"] for extra in extras] + ), + test = True, + toolchains = ["@io_bazel_rules_scala//scala:toolchain_type"], + implementation = _scala_test_impl, + ) + +scala_test = make_scala_test() # This auto-generates a test suite based on the passed set of targets # we will add a root test_suite with the name of the passed name diff --git a/scala/providers.bzl b/scala/providers.bzl index 5a92d4525..5a23ebfe3 100644 --- a/scala/providers.bzl +++ b/scala/providers.bzl @@ -57,3 +57,10 @@ declare_scalac_provider = rule( "default_macro_classpath": attr.label_list(allow_files = True), }, ) + +ScalaRulePhase = provider( + doc = "A Scala compiler plugin", + fields = { + "phases": "the phases to add", + }, +) diff --git a/scala/scala.bzl b/scala/scala.bzl index fb4a9eeaf..f63e1521b 100644 --- a/scala/scala.bzl +++ b/scala/scala.bzl @@ -8,6 +8,7 @@ load( ) load( "@io_bazel_rules_scala//scala/private:rules/scala_binary.bzl", + _make_scala_binary = "make_scala_binary", _scala_binary = "scala_binary", ) load( @@ -16,10 +17,14 @@ load( ) load( "@io_bazel_rules_scala//scala/private:rules/scala_junit_test.bzl", + _make_scala_junit_test = "make_scala_junit_test", _scala_junit_test = "scala_junit_test", ) load( "@io_bazel_rules_scala//scala/private:rules/scala_library.bzl", + _make_scala_library = "make_scala_library", + _make_scala_library_for_plugin_bootstrapping = "make_scala_library_for_plugin_bootstrapping", + _make_scala_macro_library = "make_scala_macro_library", _scala_library = "scala_library", _scala_library_for_plugin_bootstrapping = "scala_library_for_plugin_bootstrapping", _scala_library_suite = "scala_library_suite", @@ -27,10 +32,12 @@ load( ) load( "@io_bazel_rules_scala//scala/private:rules/scala_repl.bzl", + _make_scala_repl = "make_scala_repl", _scala_repl = "scala_repl", ) load( "@io_bazel_rules_scala//scala/private:rules/scala_test.bzl", + _make_scala_test = "make_scala_test", _scala_test = "scala_test", _scala_test_suite = "scala_test_suite", ) @@ -60,3 +67,11 @@ scala_repl = _scala_repl scala_repositories = _scala_repositories scala_test = _scala_test scala_test_suite = _scala_test_suite + +make_scala_binary = _make_scala_binary +make_scala_library = _make_scala_library +make_scala_library_for_plugin_bootstrapping = _make_scala_library_for_plugin_bootstrapping +make_scala_macro_library = _make_scala_macro_library +make_scala_repl = _make_scala_repl +make_scala_junit_test = _make_scala_junit_test +make_scala_test = _make_scala_test From 7fd8f4c9d575fa0949aaa96b9447e5a79e4c571e Mon Sep 17 00:00:00 2001 From: Bor Kae Hwang Date: Fri, 25 Oct 2019 15:21:58 -0600 Subject: [PATCH 4/8] Customizable phases tests --- test/phase/BUILD | 30 +++++++++++++++ test/phase/HelloBinary.scala | 7 ++++ test/phase/HelloLibrary.scala | 5 +++ test/phase/HelloTest.scala | 10 +++++ test/phase/customizability_test.bzl | 45 ++++++++++++++++++++++ test/phase/phase_customizability_test.bzl | 10 +++++ test/shell/test_phase.sh | 47 +++++++++++++++++++++++ test_rules_scala.sh | 1 + 8 files changed, 155 insertions(+) create mode 100644 test/phase/BUILD create mode 100644 test/phase/HelloBinary.scala create mode 100644 test/phase/HelloLibrary.scala create mode 100644 test/phase/HelloTest.scala create mode 100644 test/phase/customizability_test.bzl create mode 100644 test/phase/phase_customizability_test.bzl create mode 100755 test/shell/test_phase.sh diff --git a/test/phase/BUILD b/test/phase/BUILD new file mode 100644 index 000000000..7c47a162b --- /dev/null +++ b/test/phase/BUILD @@ -0,0 +1,30 @@ +load( + "//test/phase:customizability_test.bzl", + "add_phase_customizability_test_singleton", + "customizability_test_scala_binary", + "customizability_test_scala_library", + "customizability_test_scala_test", +) + +add_phase_customizability_test_singleton( + name = "phase_customizability_test", + visibility = ["//visibility:public"], +) + +customizability_test_scala_binary( + name = "HelloBinary", + srcs = ["HelloBinary.scala"], + main_class = "scalarules.test.phase.HelloBinary", +) + +customizability_test_scala_library( + name = "HelloLibrary", + srcs = ["HelloLibrary.scala"], + custom_content = "This is custom content in library", +) + +customizability_test_scala_test( + name = "HelloTest", + srcs = ["HelloTest.scala"], + custom_content = "This is custom content in test", +) diff --git a/test/phase/HelloBinary.scala b/test/phase/HelloBinary.scala new file mode 100644 index 000000000..4ca6fa9a5 --- /dev/null +++ b/test/phase/HelloBinary.scala @@ -0,0 +1,7 @@ +package scalarules.test.phase + +object HelloBinary { + def main(args: Array[String]) { + val message = "You can customize binary phases!" + } +} diff --git a/test/phase/HelloLibrary.scala b/test/phase/HelloLibrary.scala new file mode 100644 index 000000000..58737692a --- /dev/null +++ b/test/phase/HelloLibrary.scala @@ -0,0 +1,5 @@ +package scalarules.test.phase + +object HelloLibrary { + val message = "You can customize library phases!" +} diff --git a/test/phase/HelloTest.scala b/test/phase/HelloTest.scala new file mode 100644 index 000000000..2df1d5879 --- /dev/null +++ b/test/phase/HelloTest.scala @@ -0,0 +1,10 @@ +package scalarules.test.phase + +import org.scalatest._ + +class HelloTest extends FlatSpec { + val message = "You can customize test phases!" + "HelloTest" should "be able to customize test phases!" in { + assert(message.equals("You can customize test phases!")) + } +} diff --git a/test/phase/customizability_test.bzl b/test/phase/customizability_test.bzl new file mode 100644 index 000000000..05ace37a3 --- /dev/null +++ b/test/phase/customizability_test.bzl @@ -0,0 +1,45 @@ +load( + "//scala:providers.bzl", + _ScalaRulePhase = "ScalaRulePhase", +) +load( + "//test/phase:phase_customizability_test.bzl", + _phase_customizability_test = "phase_customizability_test", +) +load( + "//scala:scala.bzl", + _make_scala_binary = "make_scala_binary", + _make_scala_library = "make_scala_library", + _make_scala_test = "make_scala_test", +) + +ext_add_phase_customizability_test = { + "attrs": { + "custom_content": attr.string( + default = "This is custom content", + ), + }, + "outputs": { + "custom_output": "%{name}.custom-output", + }, + "phase_providers": [ + "//test/phase:phase_customizability_test", + ], +} + +def _add_phase_customizability_test_singleton_implementation(ctx): + return [ + _ScalaRulePhase( + phases = [ + ("-", "final", "customizability_test", _phase_customizability_test), + ], + ), + ] + +add_phase_customizability_test_singleton = rule( + implementation = _add_phase_customizability_test_singleton_implementation, +) + +customizability_test_scala_binary = _make_scala_binary(ext_add_phase_customizability_test) +customizability_test_scala_library = _make_scala_library(ext_add_phase_customizability_test) +customizability_test_scala_test = _make_scala_test(ext_add_phase_customizability_test) diff --git a/test/phase/phase_customizability_test.bzl b/test/phase/phase_customizability_test.bzl new file mode 100644 index 000000000..15f01e09e --- /dev/null +++ b/test/phase/phase_customizability_test.bzl @@ -0,0 +1,10 @@ +# +# PHASE: customizability test +# +# A dummy test phase to make sure rules are customizable +# +def phase_customizability_test(ctx, p): + ctx.actions.write( + output = ctx.outputs.custom_output, + content = ctx.attr.custom_content, + ) diff --git a/test/shell/test_phase.sh b/test/shell/test_phase.sh new file mode 100755 index 000000000..ac5844a1e --- /dev/null +++ b/test/shell/test_phase.sh @@ -0,0 +1,47 @@ +# shellcheck source=./test_runner.sh +dir=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) +. "${dir}"/test_runner.sh +. "${dir}"/test_helper.sh +runner=$(get_test_runner "${1:-local}") + +output_file_should_contain_message() { + set +e + MSG=$1 + TEST_ARG=${@:2} + OUTPUT_FILE=$(echo ${@:3} | sed 's#//#/#g;s#:#/#g') + OUTPUT_PATH=$(bazel info bazel-bin)/$OUTPUT_FILE + bazel $TEST_ARG + RESPONSE_CODE=$? + cat $OUTPUT_PATH | grep -- "$MSG" + GREP_RES=$? + if [ $RESPONSE_CODE -ne 0 ]; then + echo -e "${RED} \"bazel $TEST_ARG\" should pass but failed. $NC" + exit 1 + elif [ $GREP_RES -ne 0 ]; then + echo -e "${RED} \"bazel $TEST_ARG\" should pass with \"$MSG\" in file \"$OUTPUT_FILE\" but did not. $NC" + exit 1 + else + exit 0 + fi +} +test_scala_binary_with_extra_phase() { + output_file_should_contain_message \ + "This is custom content" \ + build //test/phase:HelloBinary.custom-output +} + +test_scala_library_with_extra_phase_and_custom_content() { + output_file_should_contain_message \ + "This is custom content in library" \ + build //test/phase:HelloLibrary.custom-output +} + +test_scala_test_with_extra_phase_and_custom_content() { + output_file_should_contain_message \ + "This is custom content in test" \ + build //test/phase:HelloTest.custom-output +} + +$runner test_scala_binary_with_extra_phase +$runner test_scala_library_with_extra_phase_and_custom_content +$runner test_scala_test_with_extra_phase_and_custom_content diff --git a/test_rules_scala.sh b/test_rules_scala.sh index 04b1ced74..e8456fabf 100755 --- a/test_rules_scala.sh +++ b/test_rules_scala.sh @@ -29,6 +29,7 @@ $runner bazel test //test/... --extra_toolchains="//test_expect_failure/plus_one . "${test_dir}"/test_javac_jvm_flags.sh . "${test_dir}"/test_junit.sh . "${test_dir}"/test_misc.sh +. "${test_dir}"/test_phase.sh . "${test_dir}"/test_scala_binary.sh . "${test_dir}"/test_scalac_jvm_flags.sh . "${test_dir}"/test_scala_classpath.sh From a59620d1d0ec37764ce29bb13c5dbda063960ae4 Mon Sep 17 00:00:00 2001 From: Bor Kae Hwang Date: Thu, 31 Oct 2019 10:47:28 -0600 Subject: [PATCH 5/8] Break up init to more reasonable phases --- .../phases/phase_collect_exports_jars.bzl | 15 +++++++ scala/private/phases/phase_collect_jars.bzl | 8 ++-- .../private/phases/phase_collect_srcjars.bzl | 14 +++++++ scala/private/phases/phase_compile.bzl | 16 ++++---- scala/private/phases/phase_init.bzl | 39 ------------------- scala/private/phases/phase_scala_provider.bzl | 4 +- .../private/phases/phase_scalac_provider.bzl | 12 ++++++ scala/private/phases/phase_write_manifest.bzl | 12 ++++++ scala/private/phases/phases.bzl | 23 +++++++---- scala/private/rules/scala_binary.bzl | 6 ++- scala/private/rules/scala_junit_test.bzl | 6 ++- scala/private/rules/scala_library.bzl | 20 ++++++++-- scala/private/rules/scala_repl.bzl | 6 ++- scala/private/rules/scala_test.bzl | 6 ++- 14 files changed, 114 insertions(+), 73 deletions(-) create mode 100644 scala/private/phases/phase_collect_exports_jars.bzl create mode 100644 scala/private/phases/phase_collect_srcjars.bzl delete mode 100644 scala/private/phases/phase_init.bzl create mode 100644 scala/private/phases/phase_scalac_provider.bzl create mode 100644 scala/private/phases/phase_write_manifest.bzl diff --git a/scala/private/phases/phase_collect_exports_jars.bzl b/scala/private/phases/phase_collect_exports_jars.bzl new file mode 100644 index 000000000..35a83dbe3 --- /dev/null +++ b/scala/private/phases/phase_collect_exports_jars.bzl @@ -0,0 +1,15 @@ +# +# PHASE: collect exports jars +# +# DOCUMENT THIS +# +load( + "@io_bazel_rules_scala//scala/private:common.bzl", + "collect_jars", +) + +def phase_collect_exports_jars(ctx, p): + # Add information from exports (is key that AFTER all build actions/runfiles analysis) + # Since after, will not show up in deploy_jar or old jars runfiles + # Notice that compile_jars is intentionally transitive for exports + return collect_jars(ctx.attr.exports) diff --git a/scala/private/phases/phase_collect_jars.bzl b/scala/private/phases/phase_collect_jars.bzl index 6eac37475..b667158f2 100644 --- a/scala/private/phases/phase_collect_jars.bzl +++ b/scala/private/phases/phase_collect_jars.bzl @@ -10,7 +10,7 @@ load( def phase_test_collect_jars(ctx, p): args = struct( - base_classpath = p.init.scalac_provider.default_classpath + [ctx.attr._scalatest], + base_classpath = p.scalac_provider.default_classpath + [ctx.attr._scalatest], extra_runtime_deps = [ ctx.attr._scalatest_reporter, ctx.attr._scalatest_runner, @@ -20,13 +20,13 @@ def phase_test_collect_jars(ctx, p): def phase_repl_collect_jars(ctx, p): args = struct( - base_classpath = p.init.scalac_provider.default_repl_classpath, + base_classpath = p.scalac_provider.default_repl_classpath, ) return phase_common_collect_jars(ctx, p, args) def phase_macro_library_collect_jars(ctx, p): args = struct( - base_classpath = p.init.scalac_provider.default_macro_classpath, + base_classpath = p.scalac_provider.default_macro_classpath, ) return phase_common_collect_jars(ctx, p, args) @@ -50,7 +50,7 @@ def phase_library_for_plugin_bootstrapping_collect_jars(ctx, p): def phase_common_collect_jars(ctx, p, _args = struct()): return _phase_collect_jars( ctx, - _args.base_classpath if hasattr(_args, "base_classpath") else p.init.scalac_provider.default_classpath, + _args.base_classpath if hasattr(_args, "base_classpath") else p.scalac_provider.default_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_collect_srcjars.bzl b/scala/private/phases/phase_collect_srcjars.bzl new file mode 100644 index 000000000..020ce99cb --- /dev/null +++ b/scala/private/phases/phase_collect_srcjars.bzl @@ -0,0 +1,14 @@ +# +# PHASE: collect srcjars +# +# DOCUMENT THIS +# +load( + "@io_bazel_rules_scala//scala/private:common.bzl", + "collect_srcjars", +) + +def phase_collect_srcjars(ctx, p): + # This will be used to pick up srcjars from non-scala library + # targets (like thrift code generation) + return collect_srcjars(ctx.attr.deps) diff --git a/scala/private/phases/phase_compile.bzl b/scala/private/phases/phase_compile.bzl index 9027c67f4..699b11401 100644 --- a/scala/private/phases/phase_compile.bzl +++ b/scala/private/phases/phase_compile.bzl @@ -13,7 +13,7 @@ def phase_binary_compile(ctx, p): args = struct( unused_dependency_checker_ignored_targets = [ target.label - for target in p.init.scalac_provider.default_classpath + + for target in p.scalac_provider.default_classpath + ctx.attr.unused_dependency_checker_ignored_targets ], ) @@ -21,11 +21,11 @@ def phase_binary_compile(ctx, p): def phase_library_compile(ctx, p): args = struct( - srcjars = p.init.srcjars, + srcjars = p.collect_srcjars, buildijar = True, unused_dependency_checker_ignored_targets = [ target.label - for target in p.init.scalac_provider.default_classpath + ctx.attr.exports + + for target in p.scalac_provider.default_classpath + ctx.attr.exports + ctx.attr.unused_dependency_checker_ignored_targets ], ) @@ -36,7 +36,7 @@ def phase_library_for_plugin_bootstrapping_compile(ctx, p): buildijar = True, unused_dependency_checker_ignored_targets = [ target.label - for target in p.init.scalac_provider.default_classpath + ctx.attr.exports + for target in p.scalac_provider.default_classpath + ctx.attr.exports ], unused_dependency_checker_mode = "off", ) @@ -46,7 +46,7 @@ def phase_macro_library_compile(ctx, p): args = struct( unused_dependency_checker_ignored_targets = [ target.label - for target in p.init.scalac_provider.default_macro_classpath + ctx.attr.exports + + for target in p.scalac_provider.default_macro_classpath + ctx.attr.exports + ctx.attr.unused_dependency_checker_ignored_targets ], ) @@ -60,7 +60,7 @@ def phase_junit_test_compile(ctx, p): ], unused_dependency_checker_ignored_targets = [ target.label - for target in p.init.scalac_provider.default_classpath + + for target in p.scalac_provider.default_classpath + ctx.attr.unused_dependency_checker_ignored_targets ] + [ ctx.attr._junit.label, @@ -75,7 +75,7 @@ def phase_repl_compile(ctx, p): args = struct( unused_dependency_checker_ignored_targets = [ target.label - for target in p.init.scalac_provider.default_repl_classpath + + for target in p.scalac_provider.default_repl_classpath + ctx.attr.unused_dependency_checker_ignored_targets ], ) @@ -85,7 +85,7 @@ def phase_test_compile(ctx, p): args = struct( unused_dependency_checker_ignored_targets = [ target.label - for target in p.init.scalac_provider.default_classpath + + for target in p.scalac_provider.default_classpath + ctx.attr.unused_dependency_checker_ignored_targets ], ) diff --git a/scala/private/phases/phase_init.bzl b/scala/private/phases/phase_init.bzl deleted file mode 100644 index f80494bef..000000000 --- a/scala/private/phases/phase_init.bzl +++ /dev/null @@ -1,39 +0,0 @@ -# -# PHASE: init -# -# DOCUMENT THIS -# -load( - "@io_bazel_rules_scala//scala/private:rule_impls.bzl", - "get_scalac_provider", -) -load( - "@io_bazel_rules_scala//scala/private:common.bzl", - "collect_jars", - "collect_srcjars", - "write_manifest", -) - -def phase_library_init(ctx, p): - # This will be used to pick up srcjars from non-scala library - # targets (like thrift code generation) - srcjars = collect_srcjars(ctx.attr.deps) - - # Add information from exports (is key that AFTER all build actions/runfiles analysis) - # Since after, will not show up in deploy_jar or old jars runfiles - # Notice that compile_jars is intentionally transitive for exports - exports_jars = collect_jars(ctx.attr.exports) - - args = phase_common_init(ctx, p) - - return struct( - srcjars = srcjars, - exports_jars = exports_jars, - scalac_provider = args.scalac_provider, - ) - -def phase_common_init(ctx, p): - write_manifest(ctx) - return struct( - scalac_provider = get_scalac_provider(ctx), - ) diff --git a/scala/private/phases/phase_scala_provider.bzl b/scala/private/phases/phase_scala_provider.bzl index 3a4f821f6..636a9db65 100644 --- a/scala/private/phases/phase_scala_provider.bzl +++ b/scala/private/phases/phase_scala_provider.bzl @@ -11,11 +11,11 @@ load( def phase_library_scala_provider(ctx, p): args = struct( rjars = depset( - transitive = [p.compile.rjars, p.init.exports_jars.transitive_runtime_jars], + transitive = [p.compile.rjars, p.collect_exports_jars.transitive_runtime_jars], ), compile_jars = depset( p.compile.ijars, - transitive = [p.init.exports_jars.compile_jars], + transitive = [p.collect_exports_jars.compile_jars], ), ) return phase_common_scala_provider(ctx, p, args) diff --git a/scala/private/phases/phase_scalac_provider.bzl b/scala/private/phases/phase_scalac_provider.bzl new file mode 100644 index 000000000..86e453618 --- /dev/null +++ b/scala/private/phases/phase_scalac_provider.bzl @@ -0,0 +1,12 @@ +# +# PHASE: scalac provider +# +# DOCUMENT THIS +# +load( + "@io_bazel_rules_scala//scala/private:rule_impls.bzl", + "get_scalac_provider", +) + +def phase_scalac_provider(ctx, p): + return get_scalac_provider(ctx) diff --git a/scala/private/phases/phase_write_manifest.bzl b/scala/private/phases/phase_write_manifest.bzl new file mode 100644 index 000000000..13a9df179 --- /dev/null +++ b/scala/private/phases/phase_write_manifest.bzl @@ -0,0 +1,12 @@ +# +# PHASE: write manifest +# +# DOCUMENT THIS +# +load( + "@io_bazel_rules_scala//scala/private:common.bzl", + "write_manifest", +) + +def phase_write_manifest(ctx, p): + write_manifest(ctx) diff --git a/scala/private/phases/phases.bzl b/scala/private/phases/phases.bzl index b41ca1825..d4ccffbaa 100644 --- a/scala/private/phases/phases.bzl +++ b/scala/private/phases/phases.bzl @@ -52,11 +52,10 @@ load( _phase_library_final = "phase_library_final", _phase_test_final = "phase_test_final", ) -load( - "@io_bazel_rules_scala//scala/private:phases/phase_init.bzl", - _phase_common_init = "phase_common_init", - _phase_library_init = "phase_library_init", -) +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") load("@io_bazel_rules_scala//scala/private:phases/phase_unused_deps_checker.bzl", _phase_unused_deps_checker = "phase_unused_deps_checker") load("@io_bazel_rules_scala//scala/private:phases/phase_declare_executable.bzl", _phase_declare_executable = "phase_declare_executable") load("@io_bazel_rules_scala//scala/private:phases/phase_merge_jars.bzl", _phase_merge_jars = "phase_merge_jars") @@ -67,9 +66,17 @@ load("@io_bazel_rules_scala//scala/private:phases/phase_coverage_runfiles.bzl", run_phases = _run_phases extras_phases = _extras_phases -# init -phase_common_init = _phase_common_init -phase_library_init = _phase_library_init +# scalac_provider +phase_scalac_provider = _phase_scalac_provider + +# collect_srcjars +phase_collect_srcjars = _phase_collect_srcjars + +# collect_exports_jars +phase_collect_exports_jars = _phase_collect_exports_jars + +# write_manifest +phase_write_manifest = _phase_write_manifest # unused_deps_checker phase_unused_deps_checker = _phase_unused_deps_checker diff --git a/scala/private/rules/scala_binary.bzl b/scala/private/rules/scala_binary.bzl index 177fc9c27..777f558b8 100644 --- a/scala/private/rules/scala_binary.bzl +++ b/scala/private/rules/scala_binary.bzl @@ -15,20 +15,22 @@ load( "phase_binary_compile", "phase_binary_final", "phase_common_collect_jars", - "phase_common_init", "phase_common_java_wrapper", "phase_common_runfiles", "phase_common_scala_provider", "phase_common_write_executable", "phase_declare_executable", "phase_merge_jars", + "phase_scalac_provider", "phase_unused_deps_checker", + "phase_write_manifest", "run_phases", ) def _scala_binary_impl(ctx): return run_phases(ctx, [ - ("init", phase_common_init), + ("scalac_provider", phase_scalac_provider), + ("write_manifest", phase_write_manifest), ("unused_deps_checker", phase_unused_deps_checker), ("collect_jars", phase_common_collect_jars), ("java_wrapper", phase_common_java_wrapper), diff --git a/scala/private/rules/scala_junit_test.bzl b/scala/private/rules/scala_junit_test.bzl index 2cab5e168..f2e02ed7b 100644 --- a/scala/private/rules/scala_junit_test.bzl +++ b/scala/private/rules/scala_junit_test.bzl @@ -12,7 +12,6 @@ load( "@io_bazel_rules_scala//scala/private:phases/phases.bzl", "extras_phases", "phase_binary_final", - "phase_common_init", "phase_common_java_wrapper", "phase_common_runfiles", "phase_common_scala_provider", @@ -22,7 +21,9 @@ load( "phase_junit_test_write_executable", "phase_jvm_flags", "phase_merge_jars", + "phase_scalac_provider", "phase_unused_deps_checker", + "phase_write_manifest", "run_phases", ) @@ -32,7 +33,8 @@ def _scala_junit_test_impl(ctx): "Setting at least one of the attributes ('prefixes','suffixes') is required", ) return run_phases(ctx, [ - ("init", phase_common_init), + ("scalac_provider", phase_scalac_provider), + ("write_manifest", phase_write_manifest), ("unused_deps_checker", phase_unused_deps_checker), ("collect_jars", phase_junit_test_collect_jars), ("java_wrapper", phase_common_java_wrapper), diff --git a/scala/private/rules/scala_library.bzl b/scala/private/rules/scala_library.bzl index 81adfcd5f..b547d72f4 100644 --- a/scala/private/rules/scala_library.bzl +++ b/scala/private/rules/scala_library.bzl @@ -18,18 +18,21 @@ load( load( "@io_bazel_rules_scala//scala/private:phases/phases.bzl", "extras_phases", + "phase_collect_exports_jars", + "phase_collect_srcjars", "phase_common_collect_jars", "phase_library_compile", "phase_library_final", "phase_library_for_plugin_bootstrapping_collect_jars", "phase_library_for_plugin_bootstrapping_compile", - "phase_library_init", "phase_library_runfiles", "phase_library_scala_provider", "phase_macro_library_collect_jars", "phase_macro_library_compile", "phase_merge_jars", + "phase_scalac_provider", "phase_unused_deps_checker", + "phase_write_manifest", "run_phases", ) @@ -52,7 +55,10 @@ _library_attrs = { def _scala_library_impl(ctx): # Build up information from dependency-like attributes return run_phases(ctx, [ - ("init", phase_library_init), + ("scalac_provider", phase_scalac_provider), + ("collect_srcjars", phase_collect_srcjars), + ("collect_exports_jars", phase_collect_exports_jars), + ("write_manifest", phase_write_manifest), ("unused_deps_checker", phase_unused_deps_checker), ("collect_jars", phase_common_collect_jars), ("compile", phase_library_compile), @@ -123,7 +129,10 @@ def scala_library_suite( def _scala_library_for_plugin_bootstrapping_impl(ctx): return run_phases(ctx, [ - ("init", phase_library_init), + ("scalac_provider", phase_scalac_provider), + ("collect_srcjars", phase_collect_srcjars), + ("collect_exports_jars", phase_collect_exports_jars), + ("write_manifest", phase_write_manifest), ("collect_jars", phase_library_for_plugin_bootstrapping_collect_jars), ("compile", phase_library_for_plugin_bootstrapping_compile), ("merge_jars", phase_merge_jars), @@ -171,7 +180,10 @@ scala_library_for_plugin_bootstrapping = make_scala_library_for_plugin_bootstrap def _scala_macro_library_impl(ctx): return run_phases(ctx, [ - ("init", phase_library_init), + ("scalac_provider", phase_scalac_provider), + ("collect_srcjars", phase_collect_srcjars), + ("collect_exports_jars", phase_collect_exports_jars), + ("write_manifest", phase_write_manifest), ("unused_deps_checker", phase_unused_deps_checker), ("collect_jars", phase_macro_library_collect_jars), ("compile", phase_macro_library_compile), diff --git a/scala/private/rules/scala_repl.bzl b/scala/private/rules/scala_repl.bzl index 6ee79c1b4..37dbf1e2a 100644 --- a/scala/private/rules/scala_repl.bzl +++ b/scala/private/rules/scala_repl.bzl @@ -13,7 +13,6 @@ load( "@io_bazel_rules_scala//scala/private:phases/phases.bzl", "extras_phases", "phase_binary_final", - "phase_common_init", "phase_common_runfiles", "phase_common_scala_provider", "phase_declare_executable", @@ -22,13 +21,16 @@ load( "phase_repl_compile", "phase_repl_java_wrapper", "phase_repl_write_executable", + "phase_scalac_provider", "phase_unused_deps_checker", + "phase_write_manifest", "run_phases", ) def _scala_repl_impl(ctx): return run_phases(ctx, [ - ("init", phase_common_init), + ("scalac_provider", phase_scalac_provider), + ("write_manifest", phase_write_manifest), ("unused_deps_checker", phase_unused_deps_checker), # need scala-compiler for MainGenericRunner below ("collect_jars", phase_repl_collect_jars), diff --git a/scala/private/rules/scala_test.bzl b/scala/private/rules/scala_test.bzl index 79a86b658..68a38ef53 100644 --- a/scala/private/rules/scala_test.bzl +++ b/scala/private/rules/scala_test.bzl @@ -12,24 +12,26 @@ load("@io_bazel_rules_scala//scala/private:common_outputs.bzl", "common_outputs" load( "@io_bazel_rules_scala//scala/private:phases/phases.bzl", "extras_phases", - "phase_common_init", "phase_common_java_wrapper", "phase_common_scala_provider", "phase_coverage_runfiles", "phase_declare_executable", "phase_merge_jars", + "phase_scalac_provider", "phase_test_collect_jars", "phase_test_compile", "phase_test_final", "phase_test_runfiles", "phase_test_write_executable", "phase_unused_deps_checker", + "phase_write_manifest", "run_phases", ) def _scala_test_impl(ctx): return run_phases(ctx, [ - ("init", phase_common_init), + ("scalac_provider", phase_scalac_provider), + ("write_manifest", phase_write_manifest), ("unused_deps_checker", phase_unused_deps_checker), ("collect_jars", phase_test_collect_jars), ("java_wrapper", phase_common_java_wrapper), From b62efe7f903bf326228fa2a012f0eb26fe62537c Mon Sep 17 00:00:00 2001 From: Bor Kae Hwang Date: Fri, 1 Nov 2019 10:43:46 -0600 Subject: [PATCH 6/8] Move final to non-configurable phase --- scala/private/phases/api.bzl | 12 ++-- scala/private/rules/scala_binary.bzl | 33 +++++---- scala/private/rules/scala_junit_test.bzl | 35 +++++----- scala/private/rules/scala_library.bzl | 85 ++++++++++++++---------- scala/private/rules/scala_repl.bzl | 35 +++++----- scala/private/rules/scala_test.bzl | 35 +++++----- test/phase/customizability_test.bzl | 2 +- 7 files changed, 138 insertions(+), 99 deletions(-) diff --git a/scala/private/phases/api.bzl b/scala/private/phases/api.bzl index 76e41c73a..dcec17aad 100644 --- a/scala/private/phases/api.bzl +++ b/scala/private/phases/api.bzl @@ -9,7 +9,11 @@ def _adjust_phases(phases, adjustments): phases = phases[:] for (relation, peer_name, name, function) in adjustments: for idx, (needle, _) in enumerate(phases): - if needle == peer_name: + if relation in ["^", "first"]: + phases.insert(0, (name, function)) + elif relation in ["$", "last"]: + phases.append((name, function)) + elif needle == peer_name: if relation in ["-", "before"]: phases.insert(idx, (name, function)) elif relation in ["+", "after"]: @@ -18,7 +22,7 @@ def _adjust_phases(phases, adjustments): phases[idx] = (name, function) return phases -def run_phases(ctx, phases): +def run_phases(ctx, customizable_phases, fixed_phase): phase_providers = [ p[_ScalaRulePhase] for p in ctx.attr._phase_providers @@ -26,11 +30,11 @@ def run_phases(ctx, phases): ] if phase_providers != []: - phases = _adjust_phases(phases, [p for pp in phase_providers for p in pp.phases]) + customizable_phases = _adjust_phases(customizable_phases, [p for pp in phase_providers for p in pp.phases]) global_provider = {} current_provider = struct(**global_provider) - for (name, function) in phases: + for (name, function) in customizable_phases + [fixed_phase]: new_provider = function(ctx, current_provider) if new_provider != None: global_provider[name] = new_provider diff --git a/scala/private/rules/scala_binary.bzl b/scala/private/rules/scala_binary.bzl index 777f558b8..bef295df2 100644 --- a/scala/private/rules/scala_binary.bzl +++ b/scala/private/rules/scala_binary.bzl @@ -28,21 +28,26 @@ load( ) def _scala_binary_impl(ctx): - return run_phases(ctx, [ - ("scalac_provider", phase_scalac_provider), - ("write_manifest", phase_write_manifest), - ("unused_deps_checker", phase_unused_deps_checker), - ("collect_jars", phase_common_collect_jars), - ("java_wrapper", phase_common_java_wrapper), - ("declare_executable", phase_declare_executable), - # no need to build an ijar for an executable - ("compile", phase_binary_compile), - ("merge_jars", phase_merge_jars), - ("runfiles", phase_common_runfiles), - ("scala_provider", phase_common_scala_provider), - ("write_executable", phase_common_write_executable), + return run_phases( + ctx, + # customizable phases + [ + ("scalac_provider", phase_scalac_provider), + ("write_manifest", phase_write_manifest), + ("unused_deps_checker", phase_unused_deps_checker), + ("collect_jars", phase_common_collect_jars), + ("java_wrapper", phase_common_java_wrapper), + ("declare_executable", phase_declare_executable), + # no need to build an ijar for an executable + ("compile", phase_binary_compile), + ("merge_jars", phase_merge_jars), + ("runfiles", phase_common_runfiles), + ("scala_provider", phase_common_scala_provider), + ("write_executable", phase_common_write_executable), + ], + # fixed phase ("final", phase_binary_final), - ]).final + ).final _scala_binary_attrs = { "main_class": attr.string(mandatory = True), diff --git a/scala/private/rules/scala_junit_test.bzl b/scala/private/rules/scala_junit_test.bzl index f2e02ed7b..45922eb39 100644 --- a/scala/private/rules/scala_junit_test.bzl +++ b/scala/private/rules/scala_junit_test.bzl @@ -32,22 +32,27 @@ def _scala_junit_test_impl(ctx): fail( "Setting at least one of the attributes ('prefixes','suffixes') is required", ) - return run_phases(ctx, [ - ("scalac_provider", phase_scalac_provider), - ("write_manifest", phase_write_manifest), - ("unused_deps_checker", phase_unused_deps_checker), - ("collect_jars", phase_junit_test_collect_jars), - ("java_wrapper", phase_common_java_wrapper), - ("declare_executable", phase_declare_executable), - # no need to build an ijar for an executable - ("compile", phase_junit_test_compile), - ("merge_jars", phase_merge_jars), - ("runfiles", phase_common_runfiles), - ("scala_provider", phase_common_scala_provider), - ("jvm_flags", phase_jvm_flags), - ("write_executable", phase_junit_test_write_executable), + return run_phases( + ctx, + # customizable phases + [ + ("scalac_provider", phase_scalac_provider), + ("write_manifest", phase_write_manifest), + ("unused_deps_checker", phase_unused_deps_checker), + ("collect_jars", phase_junit_test_collect_jars), + ("java_wrapper", phase_common_java_wrapper), + ("declare_executable", phase_declare_executable), + # no need to build an ijar for an executable + ("compile", phase_junit_test_compile), + ("merge_jars", phase_merge_jars), + ("runfiles", phase_common_runfiles), + ("scala_provider", phase_common_scala_provider), + ("jvm_flags", phase_jvm_flags), + ("write_executable", phase_junit_test_write_executable), + ], + # fixed phase ("final", phase_binary_final), - ]).final + ).final _scala_junit_test_attrs = { "prefixes": attr.string_list(default = []), diff --git a/scala/private/rules/scala_library.bzl b/scala/private/rules/scala_library.bzl index b547d72f4..1792eb9d4 100644 --- a/scala/private/rules/scala_library.bzl +++ b/scala/private/rules/scala_library.bzl @@ -54,19 +54,24 @@ _library_attrs = { def _scala_library_impl(ctx): # Build up information from dependency-like attributes - return run_phases(ctx, [ - ("scalac_provider", phase_scalac_provider), - ("collect_srcjars", phase_collect_srcjars), - ("collect_exports_jars", phase_collect_exports_jars), - ("write_manifest", phase_write_manifest), - ("unused_deps_checker", phase_unused_deps_checker), - ("collect_jars", phase_common_collect_jars), - ("compile", phase_library_compile), - ("merge_jars", phase_merge_jars), - ("runfiles", phase_library_runfiles), - ("scala_provider", phase_library_scala_provider), + return run_phases( + ctx, + # customizable phases + [ + ("scalac_provider", phase_scalac_provider), + ("collect_srcjars", phase_collect_srcjars), + ("collect_exports_jars", phase_collect_exports_jars), + ("write_manifest", phase_write_manifest), + ("unused_deps_checker", phase_unused_deps_checker), + ("collect_jars", phase_common_collect_jars), + ("compile", phase_library_compile), + ("merge_jars", phase_merge_jars), + ("runfiles", phase_library_runfiles), + ("scala_provider", phase_library_scala_provider), + ], + # fixed phase ("final", phase_library_final), - ]).final + ).final _scala_library_attrs = {} @@ -128,18 +133,23 @@ def scala_library_suite( ## def _scala_library_for_plugin_bootstrapping_impl(ctx): - return run_phases(ctx, [ - ("scalac_provider", phase_scalac_provider), - ("collect_srcjars", phase_collect_srcjars), - ("collect_exports_jars", phase_collect_exports_jars), - ("write_manifest", phase_write_manifest), - ("collect_jars", phase_library_for_plugin_bootstrapping_collect_jars), - ("compile", phase_library_for_plugin_bootstrapping_compile), - ("merge_jars", phase_merge_jars), - ("runfiles", phase_library_runfiles), - ("scala_provider", phase_library_scala_provider), + return run_phases( + ctx, + # customizable phases + [ + ("scalac_provider", phase_scalac_provider), + ("collect_srcjars", phase_collect_srcjars), + ("collect_exports_jars", phase_collect_exports_jars), + ("write_manifest", phase_write_manifest), + ("collect_jars", phase_library_for_plugin_bootstrapping_collect_jars), + ("compile", phase_library_for_plugin_bootstrapping_compile), + ("merge_jars", phase_merge_jars), + ("runfiles", phase_library_runfiles), + ("scala_provider", phase_library_scala_provider), + ], + # fixed phase ("final", phase_library_final), - ]).final + ).final # the scala compiler plugin used for dependency analysis is compiled using `scala_library`. # in order to avoid cyclic dependencies `scala_library_for_plugin_bootstrapping` was created for this purpose, @@ -179,19 +189,24 @@ scala_library_for_plugin_bootstrapping = make_scala_library_for_plugin_bootstrap ## def _scala_macro_library_impl(ctx): - return run_phases(ctx, [ - ("scalac_provider", phase_scalac_provider), - ("collect_srcjars", phase_collect_srcjars), - ("collect_exports_jars", phase_collect_exports_jars), - ("write_manifest", phase_write_manifest), - ("unused_deps_checker", phase_unused_deps_checker), - ("collect_jars", phase_macro_library_collect_jars), - ("compile", phase_macro_library_compile), - ("merge_jars", phase_merge_jars), - ("runfiles", phase_library_runfiles), - ("scala_provider", phase_library_scala_provider), + return run_phases( + ctx, + # customizable phases + [ + ("scalac_provider", phase_scalac_provider), + ("collect_srcjars", phase_collect_srcjars), + ("collect_exports_jars", phase_collect_exports_jars), + ("write_manifest", phase_write_manifest), + ("unused_deps_checker", phase_unused_deps_checker), + ("collect_jars", phase_macro_library_collect_jars), + ("compile", phase_macro_library_compile), + ("merge_jars", phase_merge_jars), + ("runfiles", phase_library_runfiles), + ("scala_provider", phase_library_scala_provider), + ], + # fixed phase ("final", phase_library_final), - ]).final + ).final _scala_macro_library_attrs = { "main_class": attr.string(), diff --git a/scala/private/rules/scala_repl.bzl b/scala/private/rules/scala_repl.bzl index 37dbf1e2a..32aae92ac 100644 --- a/scala/private/rules/scala_repl.bzl +++ b/scala/private/rules/scala_repl.bzl @@ -28,22 +28,27 @@ load( ) def _scala_repl_impl(ctx): - return run_phases(ctx, [ - ("scalac_provider", phase_scalac_provider), - ("write_manifest", phase_write_manifest), - ("unused_deps_checker", phase_unused_deps_checker), - # need scala-compiler for MainGenericRunner below - ("collect_jars", phase_repl_collect_jars), - ("java_wrapper", phase_repl_java_wrapper), - ("declare_executable", phase_declare_executable), - # no need to build an ijar for an executable - ("compile", phase_repl_compile), - ("merge_jars", phase_merge_jars), - ("runfiles", phase_common_runfiles), - ("scala_provider", phase_common_scala_provider), - ("write_executable", phase_repl_write_executable), + return run_phases( + 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 + ("collect_jars", phase_repl_collect_jars), + ("java_wrapper", phase_repl_java_wrapper), + ("declare_executable", phase_declare_executable), + # no need to build an ijar for an executable + ("compile", phase_repl_compile), + ("merge_jars", phase_merge_jars), + ("runfiles", phase_common_runfiles), + ("scala_provider", phase_common_scala_provider), + ("write_executable", phase_repl_write_executable), + ], + # fixed phase ("final", phase_binary_final), - ]).final + ).final _scala_repl_attrs = { "jvm_flags": attr.string_list(), diff --git a/scala/private/rules/scala_test.bzl b/scala/private/rules/scala_test.bzl index 68a38ef53..e630be2a8 100644 --- a/scala/private/rules/scala_test.bzl +++ b/scala/private/rules/scala_test.bzl @@ -29,22 +29,27 @@ load( ) def _scala_test_impl(ctx): - return run_phases(ctx, [ - ("scalac_provider", phase_scalac_provider), - ("write_manifest", phase_write_manifest), - ("unused_deps_checker", phase_unused_deps_checker), - ("collect_jars", phase_test_collect_jars), - ("java_wrapper", phase_common_java_wrapper), - ("declare_executable", phase_declare_executable), - # no need to build an ijar for an executable - ("compile", phase_test_compile), - ("merge_jars", phase_merge_jars), - ("runfiles", phase_test_runfiles), - ("scala_provider", phase_common_scala_provider), - ("coverage_runfiles", phase_coverage_runfiles), - ("write_executable", phase_test_write_executable), + return run_phases( + ctx, + # customizable phases + [ + ("scalac_provider", phase_scalac_provider), + ("write_manifest", phase_write_manifest), + ("unused_deps_checker", phase_unused_deps_checker), + ("collect_jars", phase_test_collect_jars), + ("java_wrapper", phase_common_java_wrapper), + ("declare_executable", phase_declare_executable), + # no need to build an ijar for an executable + ("compile", phase_test_compile), + ("merge_jars", phase_merge_jars), + ("runfiles", phase_test_runfiles), + ("scala_provider", phase_common_scala_provider), + ("coverage_runfiles", phase_coverage_runfiles), + ("write_executable", phase_test_write_executable), + ], + # fixed phase ("final", phase_test_final), - ]).final + ).final _scala_test_attrs = { "main_class": attr.string( diff --git a/test/phase/customizability_test.bzl b/test/phase/customizability_test.bzl index 05ace37a3..c1c5d3a6d 100644 --- a/test/phase/customizability_test.bzl +++ b/test/phase/customizability_test.bzl @@ -31,7 +31,7 @@ def _add_phase_customizability_test_singleton_implementation(ctx): return [ _ScalaRulePhase( phases = [ - ("-", "final", "customizability_test", _phase_customizability_test), + ("$", "", "customizability_test", _phase_customizability_test), ], ), ] From 1064b4c67460eae8847ab77c55cd04770bf376cc Mon Sep 17 00:00:00 2001 From: Bor Kae Hwang Date: Mon, 28 Oct 2019 17:06:04 -0600 Subject: [PATCH 7/8] Formatting phase --- .scalafmt.conf | 15 +++ BUILD | 0 WORKSPACE | 32 ++++++ scala/private/phases/phase_scalafmt.bzl | 81 ++++++++++++++ scala/private/phases/phases.bzl | 4 + scala/scalafmt/BUILD | 37 +++++++ scala/scalafmt/ext.bzl | 54 ++++++++++ .../scalafmt/private/format-test.template.sh | 18 ++++ scala/scalafmt/private/format.template.sh | 33 ++++++ scala/scalafmt/scala_with_scalafmt.bzl | 16 +++ scala/scalafmt/scalafmt.bzl | 100 ++++++++++++++++++ scala/scalafmt/scalafmt/ScalafmtRunner.scala | 60 +++++++++++ test/scalafmt/BUILD | 55 ++++++++++ test/scalafmt/formatted-utf8.scala | 13 +++ test/scalafmt/formatted.scala | 7 ++ test/scalafmt/unformatted-utf8.template.scala | 13 +++ test/scalafmt/unformatted.template.scala | 10 ++ test/shell/test_scalafmt.sh | 58 ++++++++++ test_rules_scala.sh | 1 + 19 files changed, 607 insertions(+) create mode 100644 .scalafmt.conf create mode 100644 BUILD create mode 100644 scala/private/phases/phase_scalafmt.bzl create mode 100644 scala/scalafmt/BUILD create mode 100644 scala/scalafmt/ext.bzl create mode 100644 scala/scalafmt/private/format-test.template.sh create mode 100644 scala/scalafmt/private/format.template.sh create mode 100644 scala/scalafmt/scala_with_scalafmt.bzl create mode 100644 scala/scalafmt/scalafmt.bzl create mode 100644 scala/scalafmt/scalafmt/ScalafmtRunner.scala create mode 100644 test/scalafmt/BUILD create mode 100644 test/scalafmt/formatted-utf8.scala create mode 100644 test/scalafmt/formatted.scala create mode 100644 test/scalafmt/unformatted-utf8.template.scala create mode 100644 test/scalafmt/unformatted.template.scala create mode 100755 test/shell/test_scalafmt.sh diff --git a/.scalafmt.conf b/.scalafmt.conf new file mode 100644 index 000000000..5490b5f71 --- /dev/null +++ b/.scalafmt.conf @@ -0,0 +1,15 @@ +align.openParenCallSite = false +align.openParenDefnSite = false +continuationIndent.defnSite = 2 +danglingParentheses = true +docstrings = JavaDoc +importSelectors = singleLine +maxColumn = 120 +newlines.afterImplicitKWInVerticalMultiline = true +rewrite.redundantBraces.stringInterpolation = true +rewrite.rules = [ + RedundantParens, + PreferCurlyFors, + SortImports +] +unindentTopLevelOperators = false diff --git a/BUILD b/BUILD new file mode 100644 index 000000000..e69de29bb diff --git a/WORKSPACE b/WORKSPACE index 35b0a9c60..0ac756e7c 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -39,6 +39,38 @@ load("//specs2:specs2_junit.bzl", "specs2_junit_repositories") specs2_junit_repositories() +load("//scala/scalafmt:scalafmt.bzl", "scalafmt_default_config", "scalafmt_repositories") + +scalafmt_repositories() + +scalafmt_default_config() + +RULES_JVM_EXTERNAL_TAG = "2.9" + +http_archive( + name = "rules_jvm_external", + sha256 = "e5b97a31a3e8feed91636f42e19b11c49487b85e5de2f387c999ea14d77c7f45", + strip_prefix = "rules_jvm_external-{}".format(RULES_JVM_EXTERNAL_TAG), + type = "zip", + url = "https://github.com/bazelbuild/rules_jvm_external/archive/{}.zip".format(RULES_JVM_EXTERNAL_TAG), +) + +load("@rules_jvm_external//:defs.bzl", "maven_install") + +maven_install( + name = "scalafmt", + artifacts = [ + "net.sourceforge.argparse4j:argparse4j:0.8.1", + "org.scalameta:parsers_2.11:4.2.0", + "com.geirsson:metaconfig-core_2.11:0.8.3", + "org.scalameta:scalafmt-core_2.11:jar:2.0.0", + ], + fetch_sources = True, + repositories = [ + "http://central.maven.org/maven2", + ], +) + load("//scala:scala_cross_version.bzl", "default_scala_major_version", "scala_mvn_artifact") # test adding a scala jar: diff --git a/scala/private/phases/phase_scalafmt.bzl b/scala/private/phases/phase_scalafmt.bzl new file mode 100644 index 000000000..3eafd72bc --- /dev/null +++ b/scala/private/phases/phase_scalafmt.bzl @@ -0,0 +1,81 @@ +# +# PHASE: phase scalafmt +# +# Outputs to format the scala files when it is explicitly specified +# +def phase_scalafmt(ctx, p): + if ctx.attr.format: + manifest, files = _build_format(ctx) + _format_runner(ctx, manifest, files) + _format_tester(ctx, manifest, files) + else: + ctx.actions.write( + output = ctx.outputs.scalafmt_runner, + content = "", + is_executable = True, + ) + ctx.actions.write( + output = ctx.outputs.scalafmt_testrunner, + content = "", + is_executable = True, + ) + +def _build_format(ctx): + files = [] + runner_inputs, _, runner_manifests = ctx.resolve_command(tools = [ctx.attr._fmt]) + manifest_content = [] + for src in ctx.files.srcs: + if src.path.endswith(".scala") and src.is_source: + file = ctx.actions.declare_file(src.short_path) + files.append(file) + args = ctx.actions.args() + args.add("--config") + args.add(ctx.file.config.path) + args.add(src.path) + args.add(file.path) + args.set_param_file_format("multiline") + args.use_param_file("@%s", use_always = True) + ctx.actions.run( + arguments = ["--jvm_flag=-Dfile.encoding=UTF-8", args], + executable = ctx.executable._fmt, + outputs = [file], + input_manifests = runner_manifests, + inputs = [ctx.file.config, src], + tools = runner_inputs, + execution_requirements = {"supports-workers": "1"}, + mnemonic = "ScalaFmt", + ) + manifest_content.append("{} {}".format(src.short_path, file.short_path)) + + manifest = ctx.actions.declare_file("format/{}/manifest.txt".format(ctx.label.name)) + ctx.actions.write(manifest, "\n".join(manifest_content) + "\n") + + return manifest, files + +def _format_runner(ctx, manifest, files): + ctx.actions.run_shell( + inputs = [ctx.file._runner, manifest] + files, + outputs = [ctx.outputs.scalafmt_runner], + command = "cat $1 | sed -e s#%workspace%#$2# -e s#%manifest%#$3# > $4", + arguments = [ + ctx.file._runner.path, + ctx.workspace_name, + manifest.short_path, + ctx.outputs.scalafmt_runner.path, + ], + execution_requirements = {}, + ) + +def _format_tester(ctx, manifest, files): + ctx.actions.run_shell( + inputs = [ctx.file._testrunner, manifest] + files, + outputs = [ctx.outputs.scalafmt_testrunner], + command = "cat $1 | sed -e s#%workspace%#$2# -e s#%manifest%#$3# > $4", + arguments = [ + ctx.file._testrunner.path, + ctx.workspace_name, + manifest.short_path, + ctx.outputs.scalafmt_testrunner.path, + ], + execution_requirements = {}, + ) diff --git a/scala/private/phases/phases.bzl b/scala/private/phases/phases.bzl index d4ccffbaa..1eafaedd0 100644 --- a/scala/private/phases/phases.bzl +++ b/scala/private/phases/phases.bzl @@ -61,6 +61,7 @@ load("@io_bazel_rules_scala//scala/private:phases/phase_declare_executable.bzl", load("@io_bazel_rules_scala//scala/private:phases/phase_merge_jars.bzl", _phase_merge_jars = "phase_merge_jars") load("@io_bazel_rules_scala//scala/private:phases/phase_jvm_flags.bzl", _phase_jvm_flags = "phase_jvm_flags") load("@io_bazel_rules_scala//scala/private:phases/phase_coverage_runfiles.bzl", _phase_coverage_runfiles = "phase_coverage_runfiles") +load("@io_bazel_rules_scala//scala/private:phases/phase_scalafmt.bzl", _phase_scalafmt = "phase_scalafmt") # API run_phases = _run_phases @@ -130,6 +131,9 @@ phase_library_runfiles = _phase_library_runfiles phase_test_runfiles = _phase_test_runfiles phase_common_runfiles = _phase_common_runfiles +# scalafmt +phase_scalafmt = _phase_scalafmt + # final phase_binary_final = _phase_binary_final phase_library_final = _phase_library_final diff --git a/scala/scalafmt/BUILD b/scala/scalafmt/BUILD new file mode 100644 index 000000000..2c02a6b7a --- /dev/null +++ b/scala/scalafmt/BUILD @@ -0,0 +1,37 @@ +load("//scala:scala.bzl", "scala_binary") + +filegroup( + name = "runner", + srcs = ["private/format.template.sh"], + visibility = ["//visibility:public"], +) + +filegroup( + name = "testrunner", + srcs = ["private/format-test.template.sh"], + visibility = ["//visibility:public"], +) + +scala_binary( + name = "scalafmt", + srcs = glob(["scalafmt/ScalafmtRunner.scala"]), + main_class = "io.bazel.rules_scala.scalafmt.ScalafmtRunner", + visibility = ["//visibility:public"], + deps = [ + "//src/java/io/bazel/rulesscala/worker", + "@scalafmt//:com_geirsson_metaconfig_core_2_11", + "@scalafmt//:net_sourceforge_argparse4j_argparse4j", + "@scalafmt//:org_scalameta_parsers_2_11", + "@scalafmt//:org_scalameta_scalafmt_core_2_11", + ], +) + +load( + "//scala/scalafmt:ext.bzl", + _add_phase_scalafmt_singleton = "add_phase_scalafmt_singleton", +) + +_add_phase_scalafmt_singleton( + name = "add_phase_scalafmt", + visibility = ["//visibility:public"], +) diff --git a/scala/scalafmt/ext.bzl b/scala/scalafmt/ext.bzl new file mode 100644 index 000000000..77173c889 --- /dev/null +++ b/scala/scalafmt/ext.bzl @@ -0,0 +1,54 @@ +load( + "//scala:providers.bzl", + _ScalaRulePhase = "ScalaRulePhase", +) +load( + "//scala/private:phases/phases.bzl", + _phase_scalafmt = "phase_scalafmt", +) + +ext_add_phase_scalafmt = { + "attrs": { + "config": attr.label( + allow_single_file = [".conf"], + default = "@scalafmt_default//:config", + doc = "The Scalafmt configuration file.", + ), + "_fmt": attr.label( + cfg = "host", + default = "//scala/scalafmt", + executable = True, + ), + "_runner": attr.label( + allow_single_file = True, + default = "//scala/scalafmt:runner", + ), + "_testrunner": attr.label( + allow_single_file = True, + default = "//scala/scalafmt:testrunner", + ), + "format": attr.bool( + default = False, + ), + }, + "outputs": { + "scalafmt_runner": "%{name}.format", + "scalafmt_testrunner": "%{name}.format-test", + }, + "phase_providers": [ + "//scala/scalafmt:add_phase_scalafmt", + ], +} + +def _add_phase_scalafmt_singleton_implementation(ctx): + return [ + _ScalaRulePhase( + phases = [ + ("$", "", "scalafmt", _phase_scalafmt), + ], + ), + ] + +add_phase_scalafmt_singleton = rule( + implementation = _add_phase_scalafmt_singleton_implementation, +) diff --git a/scala/scalafmt/private/format-test.template.sh b/scala/scalafmt/private/format-test.template.sh new file mode 100644 index 000000000..377f251d0 --- /dev/null +++ b/scala/scalafmt/private/format-test.template.sh @@ -0,0 +1,18 @@ +#!/bin/bash -e +RUNPATH="${TEST_SRCDIR-$0.runfiles}"/%workspace% +WORKSPACE_ROOT="${1:-$BUILD_WORKSPACE_DIRECTORY}" +NONDEFAULTPATH=(${RUNPATH//bin/ }) +NONDEFAULTPATH="${NONDEFAULTPATH[0]}"bin + +EXIT=0 +while read original formatted; do + if [[ ! -z "$original" ]] && [[ ! -z "$formatted" ]]; then + if ! cmp -s "$WORKSPACE_ROOT/$original" "$NONDEFAULTPATH/$formatted"; then + echo $original + diff "$WORKSPACE_ROOT/$original" "$NONDEFAULTPATH/$formatted" || true + EXIT=1 + fi + fi +done < "$NONDEFAULTPATH"/%manifest% + +exit $EXIT diff --git a/scala/scalafmt/private/format.template.sh b/scala/scalafmt/private/format.template.sh new file mode 100644 index 000000000..f48148773 --- /dev/null +++ b/scala/scalafmt/private/format.template.sh @@ -0,0 +1,33 @@ +#!/bin/bash -e +RUNPATH="${TEST_SRCDIR-$0.runfiles}"/%workspace% +WORKSPACE_ROOT="${1:-$BUILD_WORKSPACE_DIRECTORY}" + +if [ -f "$RUNPATH"/%manifest% ]; then + while read original formatted; do + if [[ ! -z "$original" ]] && [[ ! -z "$formatted" ]]; then + if ! cmp -s "$RUNPATH/$original" "$RUNPATH/$formatted"; then + if [ -z "$WORKSPACE_ROOT" ]; then + echo "$original" + diff "$RUNPATH/$original" "$RUNPATH/$formatted" || true + EXIT=1 + else + echo "Formatting $original" + cp "$RUNPATH/$formatted" "$WORKSPACE_ROOT/$original" + fi + fi + fi + done < "$RUNPATH"/%manifest% +else + NONDEFAULTPATH=(${RUNPATH//bin/ }) + NONDEFAULTPATH="${NONDEFAULTPATH[0]}"bin + while read original formatted; do + if [[ ! -z "$original" ]] && [[ ! -z "$formatted" ]]; then + if ! cmp -s "$WORKSPACE_ROOT/$original" "$NONDEFAULTPATH/$formatted"; then + echo "Formatting $original" + cp "$NONDEFAULTPATH/$formatted" "$WORKSPACE_ROOT/$original" + fi + fi + done < "$NONDEFAULTPATH"/%manifest% +fi + +exit $EXIT diff --git a/scala/scalafmt/scala_with_scalafmt.bzl b/scala/scalafmt/scala_with_scalafmt.bzl new file mode 100644 index 000000000..df411041e --- /dev/null +++ b/scala/scalafmt/scala_with_scalafmt.bzl @@ -0,0 +1,16 @@ +load( + "//scala:scala.bzl", + "make_scala_binary", + "make_scala_library", + "make_scala_test", +) +load( + "//scala/scalafmt:ext.bzl", + "ext_add_phase_scalafmt", +) + +scala_binary = make_scala_binary(ext_add_phase_scalafmt) + +scala_library = make_scala_library(ext_add_phase_scalafmt) + +scala_test = make_scala_test(ext_add_phase_scalafmt) diff --git a/scala/scalafmt/scalafmt.bzl b/scala/scalafmt/scalafmt.bzl new file mode 100644 index 000000000..0f3299013 --- /dev/null +++ b/scala/scalafmt/scalafmt.bzl @@ -0,0 +1,100 @@ +load( + "//scala:scala_cross_version.bzl", + _default_scala_version = "default_scala_version", + _extract_major_version = "extract_major_version", + _scala_mvn_artifact = "scala_mvn_artifact", +) +load( + "@io_bazel_rules_scala//scala:scala_maven_import_external.bzl", + _scala_maven_import_external = "scala_maven_import_external", +) + +def scalafmt_default_config(path = ".scalafmt.conf"): + build = [] + build.append("filegroup(") + build.append(" name = \"config\",") + build.append(" srcs = [\"{}\"],".format(path)) + build.append(" visibility = [\"//visibility:public\"],") + build.append(")") + native.new_local_repository(name = "scalafmt_default", build_file_content = "\n".join(build), path = "") + +def scalafmt_repositories( + scala_version = _default_scala_version(), + maven_servers = ["http://central.maven.org/maven2"]): + major_version = _extract_major_version(scala_version) + + scala_jar_shas = { + "2.11": { + "scalafmt_parsers": "acde4faa648c61f1d76f7a1152116738c0b0b80ae2fab8ceae83c061c29aadf1", + "metaconfig_core": "8abb4e48507486d0b323b440bb021bddd56366e502002025fdaf10025d2650c2", + "scalafmt_core": "84bac5ed8c85e61851ef427f045b7bfd149d857cb543b41c85b8353fb8c47aff", + }, + "2.12": { + "scalafmt_parsers": "9dc726dab95870b193dee3ed4d11985fa38ca09640768a7c86d8f80c715c5567", + "metaconfig_core": "495817d90ecb4c432ee0afa7e79b4d005e6a6f90a270e113e15fe7d2d5559dfd", + "scalafmt_core": "02562f176a7d070230ef2da6192f2d15afd62ea173eaf8ca02a7afb89262d233", + }, + } + + scala_version_jar_shas = scala_jar_shas[major_version] + + _scala_maven_import_external( + name = "scalafmt_parsers", + artifact = _scala_mvn_artifact( + "org.scalameta:parsers:4.2.0", + major_version, + ), + artifact_sha256 = scala_version_jar_shas["scalafmt_parsers"], + licenses = ["notice"], + server_urls = maven_servers, + ) + + native.bind( + name = "io_bazel_rules_scala/scalafmt/scalafmt_parsers", + actual = "@scalafmt_parsers", + ) + + _scala_maven_import_external( + name = "geirsson_metaconfig_core", + artifact = _scala_mvn_artifact( + "com.geirsson:metaconfig-core:0.8.3", + major_version, + ), + artifact_sha256 = scala_version_jar_shas["metaconfig_core"], + licenses = ["notice"], + server_urls = maven_servers, + ) + + native.bind( + name = "io_bazel_rules_scala/scalafmt/geirsson_metaconfig_core", + actual = "@geirsson_metaconfig_core", + ) + + _scala_maven_import_external( + name = "scalafmt_core", + artifact = _scala_mvn_artifact( + "org.scalameta:scalafmt-core:2.0.0", + major_version, + ), + artifact_sha256 = scala_version_jar_shas["scalafmt_core"], + licenses = ["notice"], + server_urls = maven_servers, + ) + + native.bind( + name = "io_bazel_rules_scala/scalafmt/scalafmt_core", + actual = "@scalafmt_core", + ) + + _scala_maven_import_external( + name = "argparse4j", + artifact = "net.sourceforge.argparse4j:argparse4j:0.8.1", + artifact_sha256 = "98cb5468cac609f3bc07856f2e34088f50dc114181237c48d20ca69c3265d044", + licenses = ["notice"], + server_urls = maven_servers, + ) + + native.bind( + name = "io_bazel_rules_scala/scalafmt/argparse4j", + actual = "@argparse4j", + ) diff --git a/scala/scalafmt/scalafmt/ScalafmtRunner.scala b/scala/scalafmt/scalafmt/ScalafmtRunner.scala new file mode 100644 index 000000000..61546872a --- /dev/null +++ b/scala/scalafmt/scalafmt/ScalafmtRunner.scala @@ -0,0 +1,60 @@ +package io.bazel.rules_scala.scalafmt + +import io.bazel.rulesscala.worker.{GenericWorker, Processor}; +import java.io.File +import java.nio.file.Files +import net.sourceforge.argparse4j.ArgumentParsers +import net.sourceforge.argparse4j.impl.Arguments +import org.scalafmt.Scalafmt +import org.scalafmt.config.Config +import org.scalafmt.util.FileOps +import scala.annotation.tailrec +import scala.io.Codec + +object ScalafmtRunner extends GenericWorker(new ScalafmtProcessor) { + + def main(args: Array[String]) { + try run(args) + catch { + case x: Exception => + x.printStackTrace() + System.exit(1) + } + } +} + +class ScalafmtProcessor extends Processor { + def processRequest(args: java.util.List[String]) { + var argsArrayBuffer = scala.collection.mutable.ArrayBuffer[String]() + for (i <- 0 to args.size-1) { + argsArrayBuffer += args.get(i) + } + val parser = ArgumentParsers.newFor("scalafmt").addHelp(true).defaultFormatWidth(80).fromFilePrefix("@").build + parser.addArgument("--config").required(true).`type`(Arguments.fileType) + parser.addArgument("input").`type`(Arguments.fileType) + parser.addArgument("output").`type`(Arguments.fileType) + + val namespace = parser.parseArgsOrFail(argsArrayBuffer.toArray) + + val source = FileOps.readFile(namespace.get[File]("input"))(Codec.UTF8) + + val config = Config.fromHoconFile(namespace.get[File]("config")).get + @tailrec + def format(code: String): String = { + val formatted = Scalafmt.format(code, config).get + if (code == formatted) code else format(formatted) + } + + val output = try { + format(source) + } catch { + case e @ (_: org.scalafmt.Error | _: scala.meta.parsers.ParseException) => { + System.out.println("Unable to format file due to bug in scalafmt") + System.out.println(e.toString) + source + } + } + + Files.write(namespace.get[File]("output").toPath, output.getBytes) + } +} diff --git a/test/scalafmt/BUILD b/test/scalafmt/BUILD new file mode 100644 index 000000000..46971de3b --- /dev/null +++ b/test/scalafmt/BUILD @@ -0,0 +1,55 @@ +load("//scala/scalafmt:scala_with_scalafmt.bzl", "scala_binary", "scala_library", "scala_test") + +### scala_binary ### +scala_binary( + name = "formatted-binary", + srcs = ["formatted.scala"], + format = True, + main_class = "test.scalafmt.FormatTest", +) + +scala_binary( + name = "unformatted-binary", + srcs = ["unformatted.tmp.scala"], + format = True, + main_class = "test.scalafmt.FormatTest", +) + +### scala_library ### +scala_library( + name = "formatted-library", + srcs = ["formatted.scala"], + format = True, +) + +scala_library( + name = "unformatted-library", + srcs = ["unformatted.tmp.scala"], + format = True, +) + +### scala_test ### +scala_test( + name = "formatted-test", + srcs = ["formatted.scala"], + format = True, +) + +scala_test( + name = "unformatted-test", + srcs = ["unformatted.tmp.scala"], + format = True, +) + +### utf8 encoding test ### +scala_library( + name = "formatted-utf8-library", + srcs = ["formatted-utf8.scala"], + format = True, +) + +scala_library( + name = "unformatted-utf8-library", + srcs = ["unformatted-utf8.tmp.scala"], + format = True, +) diff --git a/test/scalafmt/formatted-utf8.scala b/test/scalafmt/formatted-utf8.scala new file mode 100644 index 000000000..927635b20 --- /dev/null +++ b/test/scalafmt/formatted-utf8.scala @@ -0,0 +1,13 @@ +package test.scalafmt +object Utf8FormatTest { + def main(args: Array[String]) { + val warning1: String = "Be careful with this test" + val warning2: String = "小心這個測試" + val warning3: String = "このテストに注意してください" + val warning4: String = "이 시험에 조심하십시오" + val warning5: String = "كن حذرا مع هذا الاختبار" + val warning6: String = "Hãy cẩn thận với bài kiểm tra này" + val warning7: String = "Будьте осторожны с этим тестом" + val warning8: String = "😁✊🚀🍟💯" + } +} diff --git a/test/scalafmt/formatted.scala b/test/scalafmt/formatted.scala new file mode 100644 index 000000000..c5ded96bf --- /dev/null +++ b/test/scalafmt/formatted.scala @@ -0,0 +1,7 @@ +package test.scalafmt +object FormatTest { + def main(args: Array[String]) { + val greeting: String = + "Hello, world!" + } +} diff --git a/test/scalafmt/unformatted-utf8.template.scala b/test/scalafmt/unformatted-utf8.template.scala new file mode 100644 index 000000000..2034c9b04 --- /dev/null +++ b/test/scalafmt/unformatted-utf8.template.scala @@ -0,0 +1,13 @@ +package test.scalafmt +object Utf8FormatTest { + def main(args: Array[String]) { + val warning1: String = "Be careful with this test" + val warning2: String = "小心這個測試" + val warning3: String = "このテストに注意してください" + val warning4: String = "이 시험에 조심하십시오" + val warning5: String = "كن حذرا مع هذا الاختبار" + val warning6: String = "Hãy cẩn thận với bài kiểm tra này" + val warning7: String = "Будьте осторожны с этим тестом" + val warning8: String = "😁✊🚀🍟💯" + } +} diff --git a/test/scalafmt/unformatted.template.scala b/test/scalafmt/unformatted.template.scala new file mode 100644 index 000000000..39a4c2137 --- /dev/null +++ b/test/scalafmt/unformatted.template.scala @@ -0,0 +1,10 @@ + package test.scalafmt + object FormatTest { + def main ( args: + + + Array [String ]) { + val greeting: String = + "Hello, world!" + } +} diff --git a/test/shell/test_scalafmt.sh b/test/shell/test_scalafmt.sh new file mode 100755 index 000000000..1320a5976 --- /dev/null +++ b/test/shell/test_scalafmt.sh @@ -0,0 +1,58 @@ +# shellcheck source=./test_runner.sh +dir=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) +. "${dir}"/test_runner.sh +. "${dir}"/test_helper.sh +runner=$(get_test_runner "${1:-local}") + +run_non_default_formatting() { + set +e + RULE_TYPE=$1 + FILENAME="formatted" + if [[ $RULE_TYPE = utf8* ]]; then + FILENAME="formatted-utf8" + fi + + bazel run //test/scalafmt:formatted-$RULE_TYPE.format-test + if [ $? -ne 0 ]; then + echo -e "${RED} formatted-$RULE_TYPE.format-test should be a formatted target. $NC" + exit 1 + fi + cp test/scalafmt/un${FILENAME}.template.scala test/scalafmt/un${FILENAME}.tmp.scala + bazel run //test/scalafmt:unformatted-$RULE_TYPE.format-test + if [ $? -eq 0 ]; then + echo -e "${RED} unformatted-$RULE_TYPE.format-test should be an unformatted target. $NC" + exit 1 + fi + bazel run //test/scalafmt:unformatted-$RULE_TYPE.format + if [ $? -ne 0 ]; then + echo -e "${RED} unformatted-$RULE_TYPE.format should run formatting. $NC" + exit 1 + fi + diff test/scalafmt/${FILENAME}.scala test/scalafmt/un${FILENAME}.tmp.scala + if [ $? -ne 0 ]; then + echo -e "${RED} ${FILENAME}.scala should be the same as un${FILENAME}.tmp.scala after formatting. $NC" + exit 1 + fi + rm test/scalafmt/un${FILENAME}.tmp.scala +} + +test_scalafmt_binary() { + run_non_default_formatting binary +} + +test_scalafmt_library() { + run_non_default_formatting library +} + +test_scalafmt_test() { + run_non_default_formatting test +} + +test_scalafmt_utf8_library() { + run_non_default_formatting utf8-library +} + +$runner test_scalafmt_binary +$runner test_scalafmt_library +$runner test_scalafmt_test +$runner test_scalafmt_utf8_library diff --git a/test_rules_scala.sh b/test_rules_scala.sh index e8456fabf..c57f62661 100755 --- a/test_rules_scala.sh +++ b/test_rules_scala.sh @@ -30,6 +30,7 @@ $runner bazel test //test/... --extra_toolchains="//test_expect_failure/plus_one . "${test_dir}"/test_junit.sh . "${test_dir}"/test_misc.sh . "${test_dir}"/test_phase.sh +. "${test_dir}"/test_scalafmt.sh . "${test_dir}"/test_scala_binary.sh . "${test_dir}"/test_scalac_jvm_flags.sh . "${test_dir}"/test_scala_classpath.sh From 1716783827d755b3ec9b3bf44fe84334c9396e5c Mon Sep 17 00:00:00 2001 From: Bor Kae Hwang Date: Thu, 7 Nov 2019 11:24:10 -0700 Subject: [PATCH 8/8] Fix tests --- test/scalafmt/BUILD | 25 +++++-------------- test/scalafmt/formatted-test.scala | 8 ++++++ test/scalafmt/formatted-utf8.scala | 13 ---------- test/scalafmt/formatted.scala | 12 +++++++-- test/scalafmt/unformatted-test.scala | 8 ++++++ test/scalafmt/unformatted-test.template.scala | 8 ++++++ test/scalafmt/unformatted-utf8.template.scala | 13 ---------- test/scalafmt/unformatted.scala | 18 +++++++++++++ test/scalafmt/unformatted.template.scala | 12 +++++++-- test/shell/test_scalafmt.sh | 22 ++++++++-------- 10 files changed, 79 insertions(+), 60 deletions(-) create mode 100644 test/scalafmt/formatted-test.scala delete mode 100644 test/scalafmt/formatted-utf8.scala create mode 100644 test/scalafmt/unformatted-test.scala create mode 100644 test/scalafmt/unformatted-test.template.scala delete mode 100644 test/scalafmt/unformatted-utf8.template.scala create mode 100644 test/scalafmt/unformatted.scala diff --git a/test/scalafmt/BUILD b/test/scalafmt/BUILD index 46971de3b..fcbeb7f25 100644 --- a/test/scalafmt/BUILD +++ b/test/scalafmt/BUILD @@ -5,14 +5,14 @@ scala_binary( name = "formatted-binary", srcs = ["formatted.scala"], format = True, - main_class = "test.scalafmt.FormatTest", + main_class = "scalarules.test.scalafmt.Format", ) scala_binary( name = "unformatted-binary", - srcs = ["unformatted.tmp.scala"], + srcs = ["unformatted.scala"], format = True, - main_class = "test.scalafmt.FormatTest", + main_class = "scalarules.test.scalafmt.Format", ) ### scala_library ### @@ -24,32 +24,19 @@ scala_library( scala_library( name = "unformatted-library", - srcs = ["unformatted.tmp.scala"], + srcs = ["unformatted.scala"], format = True, ) ### scala_test ### scala_test( name = "formatted-test", - srcs = ["formatted.scala"], + srcs = ["formatted-test.scala"], format = True, ) scala_test( name = "unformatted-test", - srcs = ["unformatted.tmp.scala"], - format = True, -) - -### utf8 encoding test ### -scala_library( - name = "formatted-utf8-library", - srcs = ["formatted-utf8.scala"], - format = True, -) - -scala_library( - name = "unformatted-utf8-library", - srcs = ["unformatted-utf8.tmp.scala"], + srcs = ["unformatted-test.scala"], format = True, ) diff --git a/test/scalafmt/formatted-test.scala b/test/scalafmt/formatted-test.scala new file mode 100644 index 000000000..cee6fd871 --- /dev/null +++ b/test/scalafmt/formatted-test.scala @@ -0,0 +1,8 @@ +package scalarules.test.scalafmt +import org.scalatest._ +class FormatTest extends FlatSpec { + val message = "We will format this test!" + "FormatTest" should "be formatted" in { + assert(message.equals("We will format this test!")) + } +} diff --git a/test/scalafmt/formatted-utf8.scala b/test/scalafmt/formatted-utf8.scala deleted file mode 100644 index 927635b20..000000000 --- a/test/scalafmt/formatted-utf8.scala +++ /dev/null @@ -1,13 +0,0 @@ -package test.scalafmt -object Utf8FormatTest { - def main(args: Array[String]) { - val warning1: String = "Be careful with this test" - val warning2: String = "小心這個測試" - val warning3: String = "このテストに注意してください" - val warning4: String = "이 시험에 조심하십시오" - val warning5: String = "كن حذرا مع هذا الاختبار" - val warning6: String = "Hãy cẩn thận với bài kiểm tra này" - val warning7: String = "Будьте осторожны с этим тестом" - val warning8: String = "😁✊🚀🍟💯" - } -} diff --git a/test/scalafmt/formatted.scala b/test/scalafmt/formatted.scala index c5ded96bf..0b6baf5f3 100644 --- a/test/scalafmt/formatted.scala +++ b/test/scalafmt/formatted.scala @@ -1,7 +1,15 @@ -package test.scalafmt -object FormatTest { +package scalarules.test.scalafmt +object Format { def main(args: Array[String]) { val greeting: String = "Hello, world!" + val warning1 = "Be careful with this test" + val warning2 = "小心這個測試" + val warning3 = "このテストに注意してください" + val warning4 = "이 시험에 조심하십시오" + val warning5 = "كن حذرا مع هذا الاختبار" + val warning6 = "Hãy cẩn thận với bài kiểm tra này" + val warning7 = "Будьте осторожны с этим тестом" + val warning8 = "😁✊🚀🍟💯" } } diff --git a/test/scalafmt/unformatted-test.scala b/test/scalafmt/unformatted-test.scala new file mode 100644 index 000000000..c14e2f220 --- /dev/null +++ b/test/scalafmt/unformatted-test.scala @@ -0,0 +1,8 @@ + package scalarules.test.scalafmt + import org.scalatest._ + class FormatTest extends FlatSpec { + val message = "We will format this test!" + "FormatTest" should "be formatted" in { + assert ( message.equals( "We will format this test!" ) ) + } +} diff --git a/test/scalafmt/unformatted-test.template.scala b/test/scalafmt/unformatted-test.template.scala new file mode 100644 index 000000000..c14e2f220 --- /dev/null +++ b/test/scalafmt/unformatted-test.template.scala @@ -0,0 +1,8 @@ + package scalarules.test.scalafmt + import org.scalatest._ + class FormatTest extends FlatSpec { + val message = "We will format this test!" + "FormatTest" should "be formatted" in { + assert ( message.equals( "We will format this test!" ) ) + } +} diff --git a/test/scalafmt/unformatted-utf8.template.scala b/test/scalafmt/unformatted-utf8.template.scala deleted file mode 100644 index 2034c9b04..000000000 --- a/test/scalafmt/unformatted-utf8.template.scala +++ /dev/null @@ -1,13 +0,0 @@ -package test.scalafmt -object Utf8FormatTest { - def main(args: Array[String]) { - val warning1: String = "Be careful with this test" - val warning2: String = "小心這個測試" - val warning3: String = "このテストに注意してください" - val warning4: String = "이 시험에 조심하십시오" - val warning5: String = "كن حذرا مع هذا الاختبار" - val warning6: String = "Hãy cẩn thận với bài kiểm tra này" - val warning7: String = "Будьте осторожны с этим тестом" - val warning8: String = "😁✊🚀🍟💯" - } -} diff --git a/test/scalafmt/unformatted.scala b/test/scalafmt/unformatted.scala new file mode 100644 index 000000000..aae827614 --- /dev/null +++ b/test/scalafmt/unformatted.scala @@ -0,0 +1,18 @@ + package scalarules.test.scalafmt + object Format { + def main ( args: + + + Array [String ]) { + val greeting: String = + "Hello, world!" + val warning1 = "Be careful with this test" + val warning2 = "小心這個測試" + val warning3 = "このテストに注意してください" + val warning4 = "이 시험에 조심하십시오" + val warning5 = "كن حذرا مع هذا الاختبار" + val warning6 = "Hãy cẩn thận với bài kiểm tra này" + val warning7 = "Будьте осторожны с этим тестом" + val warning8 = "😁✊🚀🍟💯" + } +} diff --git a/test/scalafmt/unformatted.template.scala b/test/scalafmt/unformatted.template.scala index 39a4c2137..aae827614 100644 --- a/test/scalafmt/unformatted.template.scala +++ b/test/scalafmt/unformatted.template.scala @@ -1,10 +1,18 @@ - package test.scalafmt - object FormatTest { + package scalarules.test.scalafmt + object Format { def main ( args: Array [String ]) { val greeting: String = "Hello, world!" + val warning1 = "Be careful with this test" + val warning2 = "小心這個測試" + val warning3 = "このテストに注意してください" + val warning4 = "이 시험에 조심하십시오" + val warning5 = "كن حذرا مع هذا الاختبار" + val warning6 = "Hãy cẩn thận với bài kiểm tra này" + val warning7 = "Будьте осторожны с этим тестом" + val warning8 = "😁✊🚀🍟💯" } } diff --git a/test/shell/test_scalafmt.sh b/test/shell/test_scalafmt.sh index 1320a5976..8fd4bd80e 100755 --- a/test/shell/test_scalafmt.sh +++ b/test/shell/test_scalafmt.sh @@ -6,10 +6,12 @@ runner=$(get_test_runner "${1:-local}") run_non_default_formatting() { set +e + + FILE_PATH="$( dirname $( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) )"/scalafmt RULE_TYPE=$1 FILENAME="formatted" - if [[ $RULE_TYPE = utf8* ]]; then - FILENAME="formatted-utf8" + if [[ $RULE_TYPE = test ]]; then + FILENAME="formatted-test" fi bazel run //test/scalafmt:formatted-$RULE_TYPE.format-test @@ -17,23 +19,26 @@ run_non_default_formatting() { echo -e "${RED} formatted-$RULE_TYPE.format-test should be a formatted target. $NC" exit 1 fi - cp test/scalafmt/un${FILENAME}.template.scala test/scalafmt/un${FILENAME}.tmp.scala + bazel run //test/scalafmt:unformatted-$RULE_TYPE.format-test if [ $? -eq 0 ]; then echo -e "${RED} unformatted-$RULE_TYPE.format-test should be an unformatted target. $NC" exit 1 fi + bazel run //test/scalafmt:unformatted-$RULE_TYPE.format if [ $? -ne 0 ]; then echo -e "${RED} unformatted-$RULE_TYPE.format should run formatting. $NC" exit 1 fi - diff test/scalafmt/${FILENAME}.scala test/scalafmt/un${FILENAME}.tmp.scala + + diff $FILE_PATH/un${FILENAME}.scala $FILE_PATH/${FILENAME}.scala if [ $? -ne 0 ]; then - echo -e "${RED} ${FILENAME}.scala should be the same as un${FILENAME}.tmp.scala after formatting. $NC" + echo -e "${RED} un${FILENAME}.scala should be the same as ${FILENAME}.scala after formatting. $NC" exit 1 fi - rm test/scalafmt/un${FILENAME}.tmp.scala + + cp $FILE_PATH/un${FILENAME}.template.scala $FILE_PATH/un${FILENAME}.scala } test_scalafmt_binary() { @@ -48,11 +53,6 @@ test_scalafmt_test() { run_non_default_formatting test } -test_scalafmt_utf8_library() { - run_non_default_formatting utf8-library -} - $runner test_scalafmt_binary $runner test_scalafmt_library $runner test_scalafmt_test -$runner test_scalafmt_utf8_library