From 38d5e78aa71b2f1fedfcacd14200338c2256d979 Mon Sep 17 00:00:00 2001 From: anna-skrodzka Date: Tue, 26 Nov 2024 17:18:14 +0100 Subject: [PATCH] script embedded --- rules/scalafix/BUILD | 15 ++- rules/scalafix/scalafix_runner.bzl | 162 ++++++++++++++++------------- 2 files changed, 102 insertions(+), 75 deletions(-) diff --git a/rules/scalafix/BUILD b/rules/scalafix/BUILD index 5dca530..334b674 100644 --- a/rules/scalafix/BUILD +++ b/rules/scalafix/BUILD @@ -1,7 +1,20 @@ load("//rules/scalafix:scalafix_runner.bzl", "scalafix_runner") +load("@rules_scala3//deps:scala_deps.bzl", "scala_deps") + +filegroup( + name = "dependencies", + srcs = ["Dependencies.scala"], + visibility = ["//visibility:public"], +) + +scala_deps( + name = "scala_deps", + src = "//rules/scalafix:dependencies", + dependencies = "rules_scala3.rules.scalafix.Dependencies", +) scalafix_runner( name = "run_scalafix", toolchain = "//:scalafix_toolchain", targets = ["//deps:deps"], -) +) \ No newline at end of file diff --git a/rules/scalafix/scalafix_runner.bzl b/rules/scalafix/scalafix_runner.bzl index 3566466..f78c7fc 100644 --- a/rules/scalafix/scalafix_runner.bzl +++ b/rules/scalafix/scalafix_runner.bzl @@ -1,90 +1,104 @@ def _scalafix_runner_impl(ctx): - - toolchain = ctx.attr.toolchain.label - scalafix_opts = ctx.attr.opts or "" - - targets = " ".join(['"%s"' % t.label for t in ctx.attr.targets]) - excluded_targets = " ".join(['"%s"' % ("-" + et.label) for et in ctx.attr.excluded_targets]) - + # Dynamically generate the script content script_content = """#!/usr/bin/env bash -set -e - +# Navigate to the Bazel workspace workspace="$BUILD_WORKSPACE_DIRECTORY" - cd "$workspace" -toolchain="%s" -scalafix_opts="%s" - -targets=(%s) -excluded_targets=(%s) +# Variables +toolchain="{toolchain}" +opts="{opts}" +targets=({targets}) +excluded_targets=({excluded_targets}) # Filter targets -echo "Targets: ${targets[*]}" -echo "Excluded Targets: ${excluded_targets[*]}" -filtered_targets=$( - bazel query \\ - "kind('scala(_binary|_library|_test|js_library)', set(${targets[@]}) except set(${excluded_targets[@]}))" \\ - 2>/dev/null -) +echo "Filtering targets..." +readarray -t filtered_targets < <(bazel query \ + "kind('scala(_binary|_library|_test|js_library)', set(${targets[*]}) except set(${excluded_targets[*]}))" --output=label 2>/dev/null) -if [[ -z "$filtered_targets" ]]; then - echo "No matching targets found." - exit 0 +if [[ ${#filtered_targets[@]} -eq 0 ]]; then + echo "No valid targets found to build." + exit 1 fi +# Debug filtered targets +echo "Filtered targets: ${filtered_targets[@]}" + # Build targets +build_cmd="bazel build --extra_toolchains='$toolchain' -- ${filtered_targets[@]}" echo "Building targets..." -bazel build --extra_toolchains="$toolchain" -- $filtered_targets +echo "Command: $build_cmd" +if ! eval "$build_cmd"; then + echo "BUILD FAILED, FIX AND TRY AGAIN" + kill -INT $$ +fi # Run scalafix -exec_root=$(bazel info execution_root 2>/dev/null) -for target in $filtered_targets; do - echo "Running scalafix for $target..." - files=$( - bazel query "$target" --output=streamed_jsonproto 2>/dev/null | \\ - jq -r '.rule.attribute[]? | select(.name=="srcs" and .stringListValue!=null) | .stringListValue[]' - ) - - if [[ -z "$files" ]]; then - continue - fi - - # Get the source files for the target - files=$( - bazel query "kind('source file', deps($target))" --output=label 2>/dev/null | \ - sed 's|^//|./|' | sed 's|:|/|' - ) - - if [[ -z "$files" ]]; then - echo "No source files found for $target" - continue - fi - - scalac_opts=$( - bazel query "$toolchain" --output=streamed_jsonproto 2>/dev/null | \ - jq -r '.rule.attribute[] | select(.name=="global_scalacopts" and .stringListValue!=null) | .stringListValue[]' - ) - - required_options="-Wunused:all" - if [[ "$scalac_opts" != *"$required_options"* ]]; then - scalac_opts="$scalac_opts $required_options" - fi - - scala_version=$( - bazel cquery "$target" --output=starlark --starlark:expr \\ - 'providers(target).get("java").scala_info.toolchain.scala_version' 2>/dev/null - ) - - classpath="--classpath $exec_root/$(bazel cquery "$target.jar" --output files 2>/dev/null)" - sourceroot="--sourceroot $workspace" - - scalafix_cmd="scalafix ${scalafix_opts//:/ } --scala-version $scala_version $sourceroot $classpath ${scalac_opts[*]/#/--scalac-options } $files" - echo "$scalafix_cmd" - eval "$scalafix_cmd" +exec_root="$(bazel info execution_root 2>/dev/null)" +toolchain_impl="$( + bazel query "$toolchain" --output=streamed_jsonproto 2>/dev/null | + jq -r '.rule.attribute[] | select(.name=="toolchain" and .explicitlySpecified==true) | .stringValue' +)" +for target in "${filtered_targets[@]}"; do + target_json="$(bazel query "$target" --output=streamed_jsonproto 2>/dev/null)" + + readarray -t files < <( + echo "$target_json" | + jq -r '.rule.attribute[]? | select(.name=="srcs" and .stringListValue!=null) | .stringListValue[]' | + while read -r source; do + printf -- "--files %s\n" "$(bazel query "$source" --output location 2>/dev/null)" + done + ) + + if [[ ${#files[@]} -eq 0 ]]; then + continue + fi + + if echo "$target_json" | + jq -e '.rule.attribute[] | select(.name=="scala" and .explicitlySpecified==true)' >/dev/null; then + actual_toolchain="$(echo "$target_json" | jq -r '.rule.attribute[] | select(.name=="scala") | .stringValue')" + else + actual_toolchain=$toolchain_impl + fi + + readarray -t scalac_opts < <( + # if 'enable_semanticdb = True' toolchain adds this under the hood + if bazel query "$toolchain_impl" --output streamed_jsonproto 2>/dev/null | + jq -e '.rule.attribute[] | select(.name=="enable_semanticdb" and .stringValue=="true")' >/dev/null; then + echo "-Xsemanticdb" + fi + # scalacopts from toolchain + bazel query "$actual_toolchain" --output streamed_jsonproto 2>/dev/null | + jq -r '.rule.attribute[] | select(.name=="global_scalacopts" and .stringListValue!=null) | .stringListValue[]' + # scalacopts passed when defining the target + echo "$target_json" | + jq -r '.rule.attribute[] | select(.name=="scalacopts" and .stringListValue!=null) | .stringListValue[]' + ) + + scala_version="$( + bazel cquery "$target" --output starlark --starlark:expr \ + 'providers(target).get("java").scala_info.toolchain.scala_version' 2>/dev/null + )" + + cs="--classpath $exec_root/$(bazel cquery "$target.jar" --output files 2>/dev/null)" + + sr="--sourceroot $(bazel info workspace 2>/dev/null)" + + scalafix_cmd="scalafix ${scalafix_opts//:/ } --scala-version $scala_version $sr $cs ${scalac_opts[*]/#/--scalac-options } ${files[*]%%:*}" + echo "\nTrying to fix $target" + echo "Command: $scalafix_cmd" + eval "$scalafix_cmd" done -""" % (toolchain, scalafix_opts, targets, excluded_targets) +""".replace( + "{toolchain}", str(ctx.attr.toolchain.label) + ).replace( + "{opts}", ctx.attr.opts + ).replace( + "{targets}", " ".join(['"%s"' % t for t in ctx.attr.targets]) + ).replace( + "{excluded_targets}", " ".join(['"%s"' % t for t in ctx.attr.excluded_targets]) + ) # Write the script to an output file script_file = ctx.actions.declare_file("run_scalafix.sh") @@ -100,9 +114,9 @@ scalafix_runner = rule( implementation=_scalafix_runner_impl, attrs={ "toolchain": attr.label(mandatory=True), - "opts": attr.string(default=":--verbose:--config .scalafix.conf"), - "targets": attr.label_list(mandatory=True, allow_files=False), - "excluded_targets": attr.label_list(default=[], allow_files=False), + "opts": attr.string(default="--verbose --config .scalafix.conf"), + "targets": attr.string_list(mandatory=True), # String list for patterns + "excluded_targets": attr.string_list(default=[]), }, executable=True, )