-
-
Notifications
You must be signed in to change notification settings - Fork 358
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added plugin for formatting Java sources using Palantir (#3531)
Added `contrib.palantir.JavafmtModule` for formatting Java sources using [Palantir](https://github.com/palantir/palantir-java-format/). The plugin also supports command line arguments for - checking for formatting errors with `--check` flag - formatting specific files or folders Resolves #3448.
- Loading branch information
1 parent
b50c600
commit 09d7784
Showing
13 changed files
with
608 additions
and
0 deletions.
There are no files selected for viewing
This file contains 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,26 @@ | ||
package build | ||
|
||
import mill._ | ||
import mill.javalib.palantirformat._ | ||
|
||
object `package` extends RootModule with PalantirFormatModule { | ||
} | ||
|
||
/** See Also: src/A.java */ | ||
|
||
/** Usage | ||
|
||
> ./mill palantirformat --check # check should fail initially | ||
...checking format in java sources ... | ||
...src/A.java | ||
error: ...palantirformat aborted due to format error(s) (or invalid plugin settings/palantirformat options) | ||
|
||
> ./mill palantirformat # format all Java source files | ||
...formatting java sources ... | ||
|
||
> ./mill palantirformat --check # check should succeed now | ||
...checking format in java sources ... | ||
|
||
> ./mill mill.javalib.palantirformat.PalantirFormatModule/ __.sources # alternatively, use external module to check/format | ||
...formatting java sources ... | ||
*/ |
This file contains 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,6 @@ | ||
public class A { | ||
|
||
public static void main(String[] args) { | ||
System.out.println("hello"); // indentation should be fixed | ||
} | ||
} |
190 changes: 190 additions & 0 deletions
190
scalalib/src/mill/javalib/palantirformat/PalantirFormatModule.scala
This file contains 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,190 @@ | ||
package mill | ||
package javalib.palantirformat | ||
|
||
import mill.api.{Loose, PathRef} | ||
import mill.define.{Discover, ExternalModule} | ||
import mill.main.Tasks | ||
import mill.scalalib.{CoursierModule, DepSyntax, JavaModule} | ||
import mill.util.Jvm | ||
|
||
trait PalantirFormatBaseModule extends CoursierModule { | ||
|
||
/** | ||
* Classpath for running Palantir Java Format. | ||
*/ | ||
def palantirformatClasspath: T[Loose.Agg[PathRef]] = T { | ||
defaultResolver().resolveDeps( | ||
Agg(ivy"com.palantir.javaformat:palantir-java-format:${palantirformatVersion()}") | ||
) | ||
} | ||
|
||
/** | ||
* JVM arguments for running Palantir Java Format. Defaults to values prescribed in | ||
* "[[https://github.com/palantir/palantir-java-format/issues/548 Broken on Java 16]]". | ||
*/ | ||
def palantirformatJvmArgs: T[Seq[String]] = T { | ||
Seq( | ||
"--add-exports", | ||
"jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED", | ||
"--add-exports", | ||
"jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED", | ||
"--add-exports", | ||
"jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED", | ||
"--add-exports", | ||
"jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED", | ||
"--add-exports", | ||
"jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED" | ||
) | ||
} | ||
|
||
/** | ||
* Path to options file for Palantir Java Format CLI. Defaults to `millSourcePath` `/` `palantirformat.options`. | ||
*/ | ||
def palantirformatOptions: T[PathRef] = Task.Source( | ||
millSourcePath / "palantirformat.options" | ||
) | ||
|
||
/** | ||
* Palantir Java Format version. Defaults to `2.50.0`. | ||
*/ | ||
def palantirformatVersion: T[String] = T { | ||
"2.50.0" | ||
} | ||
} | ||
|
||
/** | ||
* Formats Java source files using [[https://github.com/palantir/palantir-java-format Palantir Java Format]]. | ||
*/ | ||
trait PalantirFormatModule extends JavaModule with PalantirFormatBaseModule { | ||
|
||
/** | ||
* Formats Java source files. | ||
* | ||
* @param check if an exception should be raised when formatting errors are found | ||
* - when set, files are not formatted | ||
* @param sources list of file or folder path(s) to be processed | ||
* - path must be relative to [[millSourcePath]] | ||
* - when empty, all [[sources]] are processed | ||
*/ | ||
def palantirformat( | ||
check: mainargs.Flag = mainargs.Flag(value = false), | ||
sources: mainargs.Leftover[String] | ||
): Command[Unit] = Task.Command { | ||
|
||
val _sources = | ||
if (sources.value.isEmpty) this.sources() | ||
else sources.value.iterator.map(rel => PathRef(millSourcePath / os.RelPath(rel))) | ||
|
||
PalantirFormatModule.palantirAction( | ||
_sources, | ||
check.value, | ||
palantirformatOptions(), | ||
palantirformatClasspath(), | ||
palantirformatJvmArgs() | ||
) | ||
} | ||
} | ||
object PalantirFormatModule extends ExternalModule with PalantirFormatBaseModule with TaskModule { | ||
|
||
override def defaultCommandName(): String = "formatAll" | ||
|
||
/** | ||
* Formats Java source files. | ||
* | ||
* @param check if an exception should be raised when formatting errors are found | ||
* - when set, files are not formatted | ||
* @param sources list of [[JavaModule]] sources to process | ||
*/ | ||
def formatAll( | ||
check: mainargs.Flag = mainargs.Flag(value = false), | ||
@mainargs.arg(positional = true) sources: Tasks[Seq[PathRef]] | ||
): Command[Unit] = Task.Command { | ||
|
||
val _sources = T.sequence(sources.value)().iterator.flatten | ||
|
||
palantirAction( | ||
_sources, | ||
check.value, | ||
palantirformatOptions(), | ||
palantirformatClasspath(), | ||
palantirformatJvmArgs() | ||
) | ||
} | ||
|
||
lazy val millDiscover: Discover = Discover[this.type] | ||
|
||
private[palantirformat] def palantirAction( | ||
sources: IterableOnce[PathRef], | ||
check: Boolean, | ||
options: PathRef, | ||
classPath: Loose.Agg[PathRef], | ||
jvmArgs: Seq[String] | ||
)(implicit ctx: api.Ctx): Unit = { | ||
|
||
if (check) { | ||
ctx.log.info("checking format in java sources ...") | ||
} else { | ||
ctx.log.info("formatting java sources ...") | ||
} | ||
|
||
val mainArgs = palantirArgs(sources, check, options) | ||
|
||
ctx.log.debug(s"running palantirformat with $mainArgs") | ||
|
||
val exitCode = Jvm.callSubprocess( | ||
mainClass = "com.palantir.javaformat.java.Main", | ||
classPath = classPath.map(_.path), | ||
jvmArgs = jvmArgs, | ||
mainArgs = mainArgs, | ||
workingDir = ctx.dest, | ||
check = false | ||
).exitCode | ||
|
||
if (check && exitCode != 0) { | ||
ctx.log.error( | ||
"palantirformat aborted due to format error(s) (or invalid plugin settings/palantirformat options)" | ||
) | ||
throw new RuntimeException(s"palantirformat exit($exitCode)") | ||
} | ||
} | ||
|
||
private def palantirArgs( | ||
sources: IterableOnce[PathRef], | ||
check: Boolean, | ||
options: PathRef | ||
): Seq[String] = { | ||
|
||
val args = Seq.newBuilder[String] | ||
|
||
// https://github.com/palantir/palantir-java-format/blob/dae9be4b84e2bd4d7ea346c6374fda47eee7118f/palantir-java-format/src/main/java/com/palantir/javaformat/java/CommandLineOptionsParser.java#L199 | ||
if (os.exists(options.path)) args += s"@${options.path}" | ||
|
||
// https://github.com/palantir/palantir-java-format/blob/dae9be4b84e2bd4d7ea346c6374fda47eee7118f/palantir-java-format/src/main/java/com/palantir/javaformat/java/CommandLineOptions.java#L27 | ||
if (check) { | ||
// do not overwrite files and exit(1) if formatting changes were detected | ||
args += "--dry-run" += "--set-exit-if-changed" | ||
} else { | ||
// format in place | ||
args += "--replace" | ||
} | ||
|
||
// https://github.com/palantir/palantir-java-format/blob/dae9be4b84e2bd4d7ea346c6374fda47eee7118f/palantir-java-format/src/main/java/com/palantir/javaformat/java/CommandLineOptionsParser.java#L49 | ||
args ++= | ||
sources | ||
.iterator | ||
.map(_.path) | ||
.flatMap(os.walk(_, includeTarget = true)) | ||
.filter(os.isFile) | ||
.filter(_.ext == "java") | ||
.map(_.toString()) | ||
|
||
args.result() | ||
} | ||
|
||
/** | ||
* Path to options file for Palantir Java Format CLI at `T.workspace` `/` `palantirformat.options`. | ||
*/ | ||
override def palantirformatOptions: T[PathRef] = Task.Source( | ||
T.workspace / "palantirformat.options" | ||
) | ||
} |
6 changes: 6 additions & 0 deletions
6
scalalib/test/resources/javalib/palantirformat/after/example/A.java
This file contains 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,6 @@ | ||
public class A { | ||
|
||
public static void main(String[] args) { | ||
System.out.println("hello"); // indentation should be fixed | ||
} | ||
} |
76 changes: 76 additions & 0 deletions
76
scalalib/test/resources/javalib/palantirformat/after/google/A.java
This file contains 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,76 @@ | ||
package com.google.googlejavaformat.java.test; | ||
|
||
/** | ||
* Tests for AbstractTypeDeclarations, AnnotationTypeDeclarations, AnnotationTypeMemberDeclarations, | ||
* Annotations, AnonymousClassDeclarations, ArrayAccesses, ArrayCreations, ArrayInitializers, | ||
* ArrayTypes, AssertStatements, and Assignments. | ||
*/ | ||
class A { | ||
public @interface X { | ||
int x(); | ||
|
||
int y() default | ||
1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 | ||
+ 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1; | ||
} | ||
|
||
@X(x = 1) | ||
private @interface Y {} | ||
|
||
// TODO(jdd): Add annotation declaration with empty body. | ||
|
||
@X(x = 1) | ||
@Y | ||
protected @interface Z {} | ||
|
||
// TODO(jdd): Include type annotations once we can include a higher language level. | ||
|
||
int[] array1 = new int[5]; | ||
int[] array2 = new int[] { | ||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, | ||
26, 27, 28, 29, 30, 31 | ||
}; | ||
int[] array3 = { | ||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, | ||
26, 27, 28, 29, 30, 31 | ||
}; | ||
int[][] array4 = { | ||
{0, 1}, {2, 3}, {4, 5}, {6, 7}, {8, 9}, {10, 11}, {12, 13}, {14, 15}, {16, 17}, {18, 19}, | ||
{20, 21}, {22, 23} | ||
}; | ||
int[][][] arrayWithLongName = new int | ||
[0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 | ||
+ 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0] | ||
[0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 | ||
+ 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0] | ||
[]; | ||
|
||
A a1 = new A() { | ||
int x = array1[ | ||
0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 | ||
+ 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0] | ||
+ array2[ | ||
0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 | ||
+ 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0] | ||
+ array3[ | ||
0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 | ||
+ 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0] | ||
+ array4[0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0][ | ||
0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0]; | ||
}; | ||
|
||
void f(int something) { | ||
assert 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 | ||
== 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1; | ||
assert 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 | ||
== 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 | ||
: "that was certainly unexpected!"; | ||
arrayWithLongName[ | ||
0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0] = | ||
arrayWithLongName[ | ||
0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0]; | ||
something = 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 | ||
+ 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 | ||
+ 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2; | ||
} | ||
} |
7 changes: 7 additions & 0 deletions
7
scalalib/test/resources/javalib/palantirformat/after/google/A.scala
This file contains 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,7 @@ | ||
package com.google.googlejavaformat.java.test | ||
|
||
object A { | ||
|
||
// plugin should ignore non Java file | ||
// introduce a compile error to trigger failure in case this file is processed | ||
//} |
33 changes: 33 additions & 0 deletions
33
scalalib/test/resources/javalib/palantirformat/after/palantir/Main.java
This file contains 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,33 @@ | ||
package a; | ||
|
||
// imports should be sorted | ||
// unsed imports should be removed | ||
import some.Configuration; | ||
import some.GradleException; | ||
import some.MavenPublication; | ||
import some.Project; | ||
import some.PublishingExtension; | ||
import some.VariantVersionMappingStrategy; | ||
|
||
public class Main { | ||
|
||
private static void configureResolvedVersionsWithVersionMapping(Project project) { | ||
project.getPluginManager().withPlugin("maven-publish", plugin -> { | ||
project.getExtensions() | ||
.getByType(PublishingExtension.class) | ||
.getPublications() | ||
.withType(MavenPublication.class) | ||
.configureEach(publication -> publication.versionMapping(mapping -> { | ||
mapping.allVariants(VariantVersionMappingStrategy::fromResolutionResult); | ||
})); | ||
}); | ||
} | ||
|
||
private static GradleException notFound(String group, String name, Configuration configuration) { | ||
String actual = configuration.getIncoming().getResolutionResult().getAllComponents().stream() | ||
.map(ResolvedComponentResult::getModuleVersion) | ||
.map(mvi -> String.format("\t- %s:%s:%s", mvi.getGroup(), mvi.getName(), mvi.getVersion())) | ||
.collect(Collectors.joining("\n")); | ||
// ... | ||
} | ||
} |
6 changes: 6 additions & 0 deletions
6
scalalib/test/resources/javalib/palantirformat/before/example/src/A.java
This file contains 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,6 @@ | ||
public class A { | ||
|
||
public static void main(String[] args) { | ||
System.out.println("hello"); // indentation should be fixed | ||
} | ||
} |
Oops, something went wrong.