-
-
Notifications
You must be signed in to change notification settings - Fork 287
Phase Scalafmt #912
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Phase Scalafmt #912
Changes from all commits
Commits
Show all changes
38 commits
Select commit
Hold shift + click to select a range
54200b6
Phase Scalafmt
borkaehw 930287e
Reuse formatter
borkaehw 17dc7f3
Remove glob
borkaehw 1ecd77c
Remove rules_jvm_external
borkaehw 079c387
Rename argparse
borkaehw dcf7922
Remove executable
borkaehw 1c9f3de
Use shared code
borkaehw 4448f56
Remove imports
borkaehw 5664976
Add comment
borkaehw 8ce301c
Change file name
borkaehw 26fcdca
Move args to private function
borkaehw f71478f
Change to true
borkaehw 7845a78
Change conf location
borkaehw 93de448
Change default conf
borkaehw 6fb863d
Test custom conf
borkaehw 82a5097
Fix lint
borkaehw 444629d
Fix build
borkaehw da78069
Remove trailing commas
borkaehw 7a4d7ff
Add formatted and unformatted folder
borkaehw 3b7507c
Rename test function
borkaehw 4d529b0
Remove template file
borkaehw b90c10e
Better handle failing case
borkaehw c935d83
Drop argparser
borkaehw 0353a7d
Remove resolve_command
borkaehw 05d70f5
Add comments
borkaehw 1334d7a
Remove unnecessary code
borkaehw 7585fbf
Change to RUNPATH
borkaehw 19fb8b9
Rename gitignore backup
borkaehw 9c387a2
Remove comment
borkaehw 7988a24
Move conf file
borkaehw feeb970
Add doc to attribute
borkaehw 10ee6d6
Switch to match readme
borkaehw 36f4e3c
Add doc
borkaehw e856593
Move doc to separate md
borkaehw 162e987
Fix wording
borkaehw 271d7ff
Fix lint
borkaehw ec9f5ea
Add url
borkaehw a417b8b
Add url
borkaehw File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,3 +7,4 @@ hash2 | |
.bazel_cache | ||
.ijwb | ||
.metals | ||
unformatted-*.backup.scala |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
align.openParenCallSite = false | ||
align.openParenDefnSite = false | ||
continuationIndent.defnSite = 2 | ||
danglingParentheses = true | ||
docstrings = JavaDoc | ||
importSelectors = singleLine | ||
maxColumn = 120 | ||
verticalMultiline.newlineBeforeImplicitKW = true | ||
rewrite.redundantBraces.stringInterpolation = true | ||
rewrite.rules = [ | ||
RedundantParens, | ||
PreferCurlyFors, | ||
SortImports | ||
] | ||
unindentTopLevelOperators = false |
Empty file.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
# Phase Scalafmt | ||
|
||
## Contents | ||
* [Overview](#overview) | ||
* [How to set up](#how-to-set-up) | ||
|
||
## Overview | ||
A phase extension `phase_scalafmt` can format Scala source code via [Scalafmt](https://scalameta.org/scalafmt/). | ||
|
||
## How to set up | ||
Add this snippet to `WORKSPACE` | ||
``` | ||
load("//scala/scalafmt:scalafmt_repositories.bzl", "scalafmt_default_config", "scalafmt_repositories") | ||
scalafmt_default_config() | ||
scalafmt_repositories() | ||
``` | ||
|
||
To add this phase to a rule, you have to pass the extension to a rule macro. Take `scala_binary` for example, | ||
``` | ||
load("//scala:advanced_usage/scala.bzl", "make_scala_binary") | ||
load("//scala/scalafmt:phase_scalafmt_ext.bzl", "ext_scalafmt") | ||
|
||
scalafmt_scala_binary = make_scala_binary(ext_scalafmt) | ||
``` | ||
Then use `scalafmt_scala_binary` as normal. | ||
|
||
The extension adds 2 additional attributes to the rule | ||
- `format`: enable formatting | ||
- `config`: the Scalafmt configuration file | ||
|
||
When `format` is set to `true`, you can do | ||
``` | ||
bazel run <TARGET>.format | ||
``` | ||
to format the source code, and do | ||
``` | ||
bazel run <TARGET>.format-test | ||
``` | ||
to check the format (without modifying source code). | ||
|
||
The extension provides default configuration, but there are 2 ways to use custom configuration | ||
- Put `.scalafmt.conf` at root of your workspace | ||
- Pass `.scalafmt.conf` in via `config` attribute |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
# | ||
# 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) | ||
_formatter(ctx, manifest, files, ctx.file._runner, ctx.outputs.scalafmt_runner) | ||
_formatter(ctx, manifest, files, ctx.file._testrunner, ctx.outputs.scalafmt_testrunner) | ||
else: | ||
_write_empty_content(ctx, ctx.outputs.scalafmt_runner) | ||
_write_empty_content(ctx, ctx.outputs.scalafmt_testrunner) | ||
|
||
def _build_format(ctx): | ||
files = [] | ||
manifest_content = [] | ||
for src in ctx.files.srcs: | ||
# only format scala source files, not generated files | ||
if src.path.endswith(".scala") and src.is_source: | ||
file = ctx.actions.declare_file("{}.fmt.output".format(src.short_path)) | ||
files.append(file) | ||
ctx.actions.run( | ||
arguments = ["--jvm_flag=-Dfile.encoding=UTF-8", _format_args(ctx, src, file)], | ||
executable = ctx.executable._fmt, | ||
outputs = [file], | ||
inputs = [ctx.file.config, src], | ||
execution_requirements = {"supports-workers": "1"}, | ||
mnemonic = "ScalaFmt", | ||
) | ||
manifest_content.append("{} {}".format(src.short_path, file.short_path)) | ||
|
||
# record the source path and the formatted file path | ||
# so that we know where to copy the formatted file to replace the source file | ||
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 _formatter(ctx, manifest, files, template, output_runner): | ||
ctx.actions.run_shell( | ||
inputs = [template, manifest] + files, | ||
outputs = [output_runner], | ||
# replace %workspace% and %manifest% in template and rewrite it to output_runner | ||
command = "cat $1 | sed -e s#%workspace%#$2# -e s#%manifest%#$3# > $4", | ||
borkaehw marked this conversation as resolved.
Show resolved
Hide resolved
|
||
arguments = [ | ||
template.path, | ||
ctx.workspace_name, | ||
manifest.short_path, | ||
output_runner.path, | ||
], | ||
execution_requirements = {}, | ||
) | ||
|
||
def _write_empty_content(ctx, output_runner): | ||
ctx.actions.write( | ||
output = output_runner, | ||
content = "", | ||
) | ||
|
||
def _format_args(ctx, src, file): | ||
args = ctx.actions.args() | ||
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) | ||
return args |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
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 = ["scalafmt/ScalafmtRunner.scala"], | ||
main_class = "io.bazel.rules_scala.scalafmt.ScalafmtRunner", | ||
visibility = ["//visibility:public"], | ||
ittaiz marked this conversation as resolved.
Show resolved
Hide resolved
|
||
deps = [ | ||
"//src/java/io/bazel/rulesscala/worker", | ||
"@com_geirsson_metaconfig_core_2_11", | ||
"@org_scalameta_parsers_2_11", | ||
"@org_scalameta_scalafmt_core_2_11", | ||
], | ||
) | ||
|
||
load( | ||
"//scala/scalafmt:phase_scalafmt_ext.bzl", | ||
"scalafmt_singleton", | ||
) | ||
|
||
scalafmt_singleton( | ||
ittaiz marked this conversation as resolved.
Show resolved
Hide resolved
|
||
name = "phase_scalafmt", | ||
ittaiz marked this conversation as resolved.
Show resolved
Hide resolved
|
||
visibility = ["//visibility:public"], | ||
) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
load( | ||
ittaiz marked this conversation as resolved.
Show resolved
Hide resolved
|
||
"//scala:advanced_usage/providers.bzl", | ||
_ScalaRulePhase = "ScalaRulePhase", | ||
) | ||
load( | ||
"//scala/private:phases/phases.bzl", | ||
_phase_scalafmt = "phase_scalafmt", | ||
) | ||
|
||
ext_scalafmt = { | ||
"attrs": { | ||
"config": attr.label( | ||
allow_single_file = [".conf"], | ||
default = "@scalafmt_default//:config", | ||
doc = "The Scalafmt configuration file.", | ||
), | ||
"format": attr.bool( | ||
default = False, | ||
doc = "Switch of enabling formatting.", | ||
), | ||
"_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", | ||
), | ||
}, | ||
"outputs": { | ||
"scalafmt_runner": "%{name}.format", | ||
"scalafmt_testrunner": "%{name}.format-test", | ||
}, | ||
"phase_providers": [ | ||
"//scala/scalafmt:phase_scalafmt", | ||
], | ||
} | ||
|
||
def _scalafmt_singleton_implementation(ctx): | ||
return [ | ||
_ScalaRulePhase( | ||
custom_phases = [ | ||
("$", "", "scalafmt", _phase_scalafmt), | ||
], | ||
), | ||
] | ||
|
||
scalafmt_singleton = rule( | ||
implementation = _scalafmt_singleton_implementation, | ||
) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
#!/bin/bash -e | ||
WORKSPACE_ROOT="${1:-$BUILD_WORKSPACE_DIRECTORY}" | ||
RUNPATH="${TEST_SRCDIR-$0.runfiles}"/%workspace% | ||
RUNPATH=(${RUNPATH//bin/ }) | ||
RUNPATH="${RUNPATH[0]}"bin | ||
|
||
EXIT=0 | ||
while read original formatted; do | ||
if [[ ! -z "$original" ]] && [[ ! -z "$formatted" ]]; then | ||
if ! cmp -s "$WORKSPACE_ROOT/$original" "$RUNPATH/$formatted"; then | ||
echo $original | ||
diff "$WORKSPACE_ROOT/$original" "$RUNPATH/$formatted" || true | ||
EXIT=1 | ||
fi | ||
fi | ||
done < "$RUNPATH"/%manifest% | ||
|
||
exit $EXIT |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
#!/bin/bash -e | ||
WORKSPACE_ROOT="${1:-$BUILD_WORKSPACE_DIRECTORY}" | ||
RUNPATH="${TEST_SRCDIR-$0.runfiles}"/%workspace% | ||
RUNPATH=(${RUNPATH//bin/ }) | ||
RUNPATH="${RUNPATH[0]}"bin | ||
|
||
while read original formatted; do | ||
if [[ ! -z "$original" ]] && [[ ! -z "$formatted" ]]; then | ||
if ! cmp -s "$WORKSPACE_ROOT/$original" "$RUNPATH/$formatted"; then | ||
echo "Formatting $original" | ||
cp "$RUNPATH/$formatted" "$WORKSPACE_ROOT/$original" | ||
fi | ||
fi | ||
done < "$RUNPATH"/%manifest% |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
package io.bazel.rules_scala.scalafmt | ||
|
||
import io.bazel.rulesscala.worker.{GenericWorker, Processor}; | ||
import java.io.File | ||
import java.nio.file.Files | ||
import org.scalafmt.Scalafmt | ||
import org.scalafmt.config.Config | ||
import org.scalafmt.util.FileOps | ||
import scala.annotation.tailrec | ||
import scala.collection.JavaConverters._ | ||
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]) { | ||
val argName = List("config", "input", "output") | ||
val argFile = args.asScala.map{x => new File(x)} | ||
val namespace = argName.zip(argFile).toMap | ||
|
||
val source = FileOps.readFile(namespace.getOrElse("input", new File("")))(Codec.UTF8) | ||
|
||
val config = Config.fromHoconFile(namespace.getOrElse("config", new File(""))).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.getOrElse("output", new File("")).toPath, output.getBytes) | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.