Skip to content
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

Convert GJF to compile only dependency #1630

Merged
merged 15 commits into from
Mar 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ This document is intended for Spotless developers.
We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (starting after version `1.27.0`).

## [Unreleased]
### Changes
* **POTENTIALLY BREAKING** Converted `googleJavaFormat` to a compile-only dependency and drop support for versions < `1.8`. ([#1630](https://github.com/diffplug/spotless/pull/1630))
* Bump default `googleJavaFormat` version `1.15.0` -> `1.16.0`. ([#1630](https://github.com/diffplug/spotless/pull/1630))

## [2.37.0] - 2023-03-13
### Added
Expand Down
3 changes: 3 additions & 0 deletions lib/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ apply from: rootProject.file('gradle/java-publish.gradle')
def NEEDS_GLUE = [
'sortPom',
'palantirJavaFormat',
'googleJavaFormat',
'ktfmt',
'ktlint',
'flexmark',
Expand Down Expand Up @@ -70,6 +71,8 @@ dependencies {

palantirJavaFormatCompileOnly 'com.palantir.javaformat:palantir-java-format:1.1.0' // this version needs to stay compilable against Java 8 for CI Job testNpm

googleJavaFormatCompileOnly 'com.google.googlejavaformat:google-java-format:1.8' // minimum required version due to api changes before then

// used jackson-based formatters
jacksonCompileOnly 'com.fasterxml.jackson.core:jackson-databind:2.14.2'
jacksonCompileOnly 'com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.14.2'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*
* Copyright 2023 DiffPlug
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.diffplug.spotless.glue.java;

import java.util.Objects;

import javax.annotation.Nonnull;

import com.google.googlejavaformat.java.Formatter;
import com.google.googlejavaformat.java.FormatterException;
import com.google.googlejavaformat.java.ImportOrderer;
import com.google.googlejavaformat.java.JavaFormatterOptions;
import com.google.googlejavaformat.java.RemoveUnusedImports;
import com.google.googlejavaformat.java.StringWrapper;

import com.diffplug.spotless.FormatterFunc;

public class GoogleJavaFormatFormatterFunc implements FormatterFunc {

@Nonnull
private final Formatter formatter;

@Nonnull
private final String version;

@Nonnull
private final JavaFormatterOptions.Style formatterStyle;

private final boolean reflowStrings;

public GoogleJavaFormatFormatterFunc(@Nonnull String version, @Nonnull String style, boolean reflowStrings) {
this.version = Objects.requireNonNull(version);
this.formatterStyle = JavaFormatterOptions.Style.valueOf(Objects.requireNonNull(style));
this.reflowStrings = reflowStrings;

this.formatter = new Formatter(JavaFormatterOptions.builder()
.style(formatterStyle)
.build());
}

@Override
@Nonnull
public String apply(@Nonnull String input) throws Exception {
String formatted = formatter.formatSource(input);
String removedUnused = RemoveUnusedImports.removeUnusedImports(formatted);
String sortedImports = ImportOrderer.reorderImports(removedUnused, formatterStyle);
return reflowLongStrings(sortedImports);
}

private String reflowLongStrings(String input) throws FormatterException {
if (reflowStrings) {
return StringWrapper.wrap(input, formatter);
} else {
return input;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* Copyright 2023 DiffPlug
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.diffplug.spotless.glue.java;

import java.util.Objects;

import javax.annotation.Nonnull;

import com.google.googlejavaformat.java.RemoveUnusedImports;

import com.diffplug.spotless.FormatterFunc;

public class GoogleJavaFormatRemoveUnusedImporterFormatterFunc implements FormatterFunc {

@Nonnull
private final String version;

public GoogleJavaFormatRemoveUnusedImporterFormatterFunc(@Nonnull String version) {
this.version = Objects.requireNonNull(version);
}

@Override
@Nonnull
public String apply(@Nonnull String input) throws Exception {
return RemoveUnusedImports.removeUnusedImports(input);
}
}
89 changes: 63 additions & 26 deletions lib/src/main/java/com/diffplug/spotless/Jvm.java
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,9 @@ public static int version() {
public static class Support<V> {
private final String fmtName;
private final Comparator<? super V> fmtVersionComparator;
private final NavigableMap<Integer, V> jvm2fmtVersion;
private final NavigableMap<V, Integer> fmt2jvmVersion;
private final NavigableMap<Integer, V> jvm2fmtMaxVersion;
private final NavigableMap<Integer, V> jvm2fmtMinVersion;
private final NavigableMap<V, Integer> fmtMaxVersion2jvmVersion;

private Support(String fromatterName) {
this(fromatterName, new SemanticVersionComparator<V>());
Expand All @@ -73,40 +74,60 @@ private Support(String fromatterName) {
private Support(String formatterName, Comparator<? super V> formatterVersionComparator) {
fmtName = formatterName;
fmtVersionComparator = formatterVersionComparator;
jvm2fmtVersion = new TreeMap<Integer, V>();
fmt2jvmVersion = new TreeMap<V, Integer>(formatterVersionComparator);
jvm2fmtMaxVersion = new TreeMap<>();
jvm2fmtMinVersion = new TreeMap<>();
fmtMaxVersion2jvmVersion = new TreeMap<>(formatterVersionComparator);
}

/**
* Add supported formatter version
* Add maximum supported formatter version
* @param minimumJvmVersion Minimum Java version required
* @param maxFormatterVersion Maximum formatter version supported by the Java version
* @return this
*/
public Support<V> add(int minimumJvmVersion, V maxFormatterVersion) {
Objects.requireNonNull(maxFormatterVersion);
if (null != jvm2fmtVersion.put(minimumJvmVersion, maxFormatterVersion)) {
if (null != jvm2fmtMaxVersion.put(minimumJvmVersion, maxFormatterVersion)) {
throw new IllegalArgumentException(String.format("Added duplicate entry for JVM %d+.", minimumJvmVersion));
}
if (null != fmt2jvmVersion.put(maxFormatterVersion, minimumJvmVersion)) {
if (null != fmtMaxVersion2jvmVersion.put(maxFormatterVersion, minimumJvmVersion)) {
throw new IllegalArgumentException(String.format("Added duplicate entry for formatter version %s.", maxFormatterVersion));
}
verifyVersionRangesDoNotIntersect(jvm2fmtMaxVersion, minimumJvmVersion, maxFormatterVersion);
return this;
}

public Support<V> addMin(int minimumJvmVersion, V minFormatterVersion) {
Objects.requireNonNull(minFormatterVersion);
if (null != jvm2fmtMinVersion.put(minimumJvmVersion, minFormatterVersion)) {
throw new IllegalArgumentException(String.format("Added duplicate entry for JVM %d+.", minimumJvmVersion));
}
verifyVersionRangesDoNotIntersect(jvm2fmtMinVersion, minimumJvmVersion, minFormatterVersion);
return this;
}

private void verifyVersionRangesDoNotIntersect(NavigableMap<Integer, V> jvm2fmtVersion, int minimumJvmVersion, V formatterVersion) {
Map.Entry<Integer, V> lower = jvm2fmtVersion.lowerEntry(minimumJvmVersion);
if ((null != lower) && (fmtVersionComparator.compare(maxFormatterVersion, lower.getValue()) <= 0)) {
throw new IllegalArgumentException(String.format("%d/%s should be lower than %d/%s", minimumJvmVersion, maxFormatterVersion, lower.getKey(), lower.getValue()));
if ((null != lower) && (fmtVersionComparator.compare(formatterVersion, lower.getValue()) <= 0)) {
throw new IllegalArgumentException(String.format("%d/%s should be lower than %d/%s", minimumJvmVersion, formatterVersion, lower.getKey(), lower.getValue()));
}
Map.Entry<Integer, V> higher = jvm2fmtVersion.higherEntry(minimumJvmVersion);
if ((null != higher) && (fmtVersionComparator.compare(maxFormatterVersion, higher.getValue()) >= 0)) {
throw new IllegalArgumentException(String.format("%d/%s should be higher than %d/%s", minimumJvmVersion, maxFormatterVersion, higher.getKey(), higher.getValue()));
if ((null != higher) && (fmtVersionComparator.compare(formatterVersion, higher.getValue()) >= 0)) {
throw new IllegalArgumentException(String.format("%d/%s should be higher than %d/%s", minimumJvmVersion, formatterVersion, higher.getKey(), higher.getValue()));
}
return this;
}

/** @return Highest formatter version recommended for this JVM (null, if JVM not supported) */
@Nullable
public V getRecommendedFormatterVersion() {
Integer configuredJvmVersionOrNull = jvm2fmtVersion.floorKey(Jvm.version());
return (null == configuredJvmVersionOrNull) ? null : jvm2fmtVersion.get(configuredJvmVersionOrNull);
Integer configuredJvmVersionOrNull = jvm2fmtMaxVersion.floorKey(Jvm.version());
return (null == configuredJvmVersionOrNull) ? null : jvm2fmtMaxVersion.get(configuredJvmVersionOrNull);
}

@Nullable
public V getMinimumRequiredFormatterVersion() {
Integer configuredJvmVersionOrNull = jvm2fmtMinVersion.floorKey(Jvm.version());
return (null == configuredJvmVersionOrNull) ? null : jvm2fmtMinVersion.get(configuredJvmVersionOrNull);
}

/**
Expand All @@ -123,10 +144,17 @@ public void assertFormatterSupported(V formatterVersion) {
}

private String buildUnsupportedFormatterMessage(V fmtVersion) {
// check if the jvm version is to low for the formatter version
int requiredJvmVersion = getRequiredJvmVersion(fmtVersion);
if (Jvm.version() < requiredJvmVersion) {
return buildUpgradeJvmMessage(fmtVersion) + "Upgrade your JVM or try " + toString();
}
// check if the formatter version is too low for the jvm version
V minimumFormatterVersion = getMinimumRequiredFormatterVersion();
if ((null != minimumFormatterVersion) && (fmtVersionComparator.compare(fmtVersion, minimumFormatterVersion) < 0)) {
return String.format("You are running Spotless on JVM %d. This requires %s of at least %s (you are using %s).%n", Jvm.version(), fmtName, minimumFormatterVersion, fmtVersion);
}
// otherwise all is well
return "";
}

Expand All @@ -137,7 +165,7 @@ private String buildUpgradeJvmMessage(V fmtVersion) {
if (null != recommendedFmtVersionOrNull) {
builder.append(String.format(", which limits you to %s %s.%n", fmtName, recommendedFmtVersionOrNull));
} else {
Entry<V, Integer> nextFmtVersionOrNull = fmt2jvmVersion.ceilingEntry(fmtVersion);
Entry<V, Integer> nextFmtVersionOrNull = fmtMaxVersion2jvmVersion.ceilingEntry(fmtVersion);
if (null != nextFmtVersionOrNull) {
builder.append(String.format(". %s %s requires JVM %d+", fmtName, fmtVersion, nextFmtVersionOrNull.getValue()));
}
Expand All @@ -147,12 +175,12 @@ private String buildUpgradeJvmMessage(V fmtVersion) {
}

private int getRequiredJvmVersion(V fmtVersion) {
Entry<V, Integer> entry = fmt2jvmVersion.ceilingEntry(fmtVersion);
Entry<V, Integer> entry = fmtMaxVersion2jvmVersion.ceilingEntry(fmtVersion);
if (null == entry) {
entry = fmt2jvmVersion.lastEntry();
entry = fmtMaxVersion2jvmVersion.lastEntry();
}
if (null != entry) {
V maxKnownFmtVersion = jvm2fmtVersion.get(entry.getValue());
V maxKnownFmtVersion = jvm2fmtMaxVersion.get(entry.getValue());
if (fmtVersionComparator.compare(fmtVersion, maxKnownFmtVersion) <= 0) {
return entry.getValue();
}
Expand All @@ -170,15 +198,15 @@ public FormatterFunc suggestLaterVersionOnError(V formatterVersion, FormatterFun
Objects.requireNonNull(formatterVersion);
Objects.requireNonNull(originalFunc);
final String hintUnsupportedProblem = buildUnsupportedFormatterMessage(formatterVersion);
final String proposeDiffererntFormatter = hintUnsupportedProblem.isEmpty() ? buildUpgradeFormatterMessage(formatterVersion) : hintUnsupportedProblem;
return proposeDiffererntFormatter.isEmpty() ? originalFunc : new FormatterFunc() {
final String proposeDifferentFormatter = hintUnsupportedProblem.isEmpty() ? buildUpgradeFormatterMessage(formatterVersion) : hintUnsupportedProblem;
return proposeDifferentFormatter.isEmpty() ? originalFunc : new FormatterFunc() {

@Override
public String apply(String unix, File file) throws Exception {
try {
return originalFunc.apply(unix, file);
} catch (Exception e) {
throw new Exception(proposeDiffererntFormatter, e);
throw new Exception(proposeDifferentFormatter, e);
}
}

Expand All @@ -187,7 +215,7 @@ public String apply(String input) throws Exception {
try {
return originalFunc.apply(input);
} catch (Exception e) {
throw new Exception(proposeDiffererntFormatter, e);
throw new Exception(proposeDifferentFormatter, e);
}
}

Expand All @@ -196,16 +224,25 @@ public String apply(String input) throws Exception {

private String buildUpgradeFormatterMessage(V fmtVersion) {
StringBuilder builder = new StringBuilder();
// check if the formatter is not supported on this jvm
V minimumFormatterVersion = getMinimumRequiredFormatterVersion();
V recommendedFmtVersionOrNull = getRecommendedFormatterVersion();
if (null != recommendedFmtVersionOrNull && (fmtVersionComparator.compare(fmtVersion, recommendedFmtVersionOrNull) < 0)) {
if ((null != minimumFormatterVersion) && (fmtVersionComparator.compare(fmtVersion, minimumFormatterVersion) < 0)) {
builder.append(String.format("You are running Spotless on JVM %d. This requires %s of at least %s.%n", Jvm.version(), fmtName, minimumFormatterVersion));
builder.append(String.format("You are using %s %s.%n", fmtName, fmtVersion));
if (null != recommendedFmtVersionOrNull) {
builder.append(String.format("%s %s is the recommended version, which may have fixed this problem.%n", fmtName, recommendedFmtVersionOrNull));
}
// check if the formatter is outdated on this jvm
} else if (null != recommendedFmtVersionOrNull && (fmtVersionComparator.compare(fmtVersion, recommendedFmtVersionOrNull) < 0)) {
builder.append(String.format("%s %s is currently being used, but outdated.%n", fmtName, fmtVersion));
builder.append(String.format("%s %s is the recommended version, which may have fixed this problem.%n", fmtName, recommendedFmtVersionOrNull));
builder.append(String.format("%s %s requires JVM %d+.", fmtName, recommendedFmtVersionOrNull, getRequiredJvmVersion(recommendedFmtVersionOrNull)));
} else {
V higherFormatterVersionOrNull = fmt2jvmVersion.higherKey(fmtVersion);
V higherFormatterVersionOrNull = fmtMaxVersion2jvmVersion.higherKey(fmtVersion);
if (null != higherFormatterVersionOrNull) {
builder.append(buildUpgradeJvmMessage(fmtVersion));
Integer higherJvmVersion = fmt2jvmVersion.get(higherFormatterVersionOrNull);
Integer higherJvmVersion = fmtMaxVersion2jvmVersion.get(higherFormatterVersionOrNull);
builder.append(String.format("If you upgrade your JVM to %d+, then you can use %s %s, which may have fixed this problem.", higherJvmVersion, fmtName, higherFormatterVersionOrNull));
}
}
Expand All @@ -215,7 +252,7 @@ private String buildUpgradeFormatterMessage(V fmtVersion) {
@Override
public String toString() {
return String.format("%s alternatives:%n", fmtName) +
jvm2fmtVersion.entrySet().stream().map(
jvm2fmtMaxVersion.entrySet().stream().map(
e -> String.format("- Version %s requires JVM %d+", e.getValue(), e.getKey())).collect(Collectors.joining(System.lineSeparator()));
}

Expand Down
Loading