Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
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
2 changes: 2 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ You might be looking for:

### Version 1.14.0-SNAPSHOT - TBD (javadoc [lib](https://diffplug.github.io/spotless/javadoc/spotless-lib/snapshot/) [lib-extra](https://diffplug.github.io/spotless/javadoc/spotless-lib-extra/snapshot/), [snapshot repo](https://oss.sonatype.org/content/repositories/snapshots/com/diffplug/spotless/))

* Eclipse formatter versions decoupled from Spotless formatter step implementations to allow independent updates of M2 based Eclipse dependencies. ([#253](https://github.com/diffplug/spotless/pull/253))

### Version 1.13.0 - June 1st 2018 (javadoc [lib](https://diffplug.github.io/spotless/javadoc/spotless-lib/1.11.0/) [lib-extra](https://diffplug.github.io/spotless/javadoc/spotless-lib-extra/1.13.0/), artifact [lib]([jcenter](https://bintray.com/diffplug/opensource/spotless-lib), [lib-extra]([jcenter](https://bintray.com/diffplug/opensource/spotless-lib-extra)))

* Add line and column numbers to ktlint errors. ([#251](https://github.com/diffplug/spotless/pull/251))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
/*
* Copyright 2016 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.extra;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Properties;

import com.diffplug.common.base.Errors;
import com.diffplug.spotless.FileSignature;
import com.diffplug.spotless.FormatterFunc;
import com.diffplug.spotless.FormatterProperties;
import com.diffplug.spotless.FormatterStep;
import com.diffplug.spotless.JarState;
import com.diffplug.spotless.Provisioner;
import com.diffplug.spotless.ThrowingEx;

/**
* Generic Eclipse based formatter step {@link State} builder.
*/
public class EclipseBasedStepBuilder {
private final String formatterName;
private final ThrowingEx.Function<State, FormatterFunc> stateToFormatter;
private final Provisioner jarProvisioner;

/**
* Resource location of Spotless Eclipse Formatter Maven coordinate lists.
* <p>
* Spotless Eclipse Formatter dependencies have fixed transitive versions, since Spotless Eclipse Formatter
* implementations access internal methods of the Eclipse plugins, which may change with every
* version change, including minor and patch version changes.
* At the resource location for each supported Spotless Eclipse Formatter, a text file is provided, containing
* the fixed versions for the formatter and its transitive dependencies.
* Each line is either a comment starting with {@code #} or corresponds to the format
* {@code <groupId>:<artifactId>[:packaging][:classifier]:<versionRestriction>}
* </p>
*/
private static final String ECLIPSE_FORMATTER_RESOURCES = EclipseBasedStepBuilder.class.getPackage().getName().replace('.', '/');

private List<String> dependencies = new ArrayList<>();
private Iterable<File> settingsFiles = new ArrayList<>();

/** Initialize valid default configuration, taking latest version */
public EclipseBasedStepBuilder(String formatterName, Provisioner jarProvisioner, ThrowingEx.Function<State, FormatterFunc> stateToFormatter) {
this.formatterName = Objects.requireNonNull(formatterName, "formatterName");
this.jarProvisioner = Objects.requireNonNull(jarProvisioner, "jarProvisioner");
this.stateToFormatter = Objects.requireNonNull(stateToFormatter, "stateToFormatter");
}

/** Returns the FormatterStep (whose state will be calculated lazily). */
public FormatterStep build() {
return FormatterStep.createLazy(formatterName, this::get, stateToFormatter);
}

/** Set dependencies for the corresponding Eclipse version */
public void setVersion(String version) {
String url = "/" + ECLIPSE_FORMATTER_RESOURCES + "/" + formatterName.replace(' ', '_') + "/v" + version + ".lockfile";
InputStream depsFile = EclipseBasedStepBuilder.class.getResourceAsStream(url);
if (depsFile == null) {
throw new IllegalArgumentException("No such version " + version + ", expected at " + url);
}
byte[] content = toByteArray(depsFile);
String allLines = new String(content, StandardCharsets.UTF_8);
String[] lines = allLines.split("\n");
dependencies.clear();
for (String line : lines) {
if (!line.startsWith("#")) {
dependencies.add(line);
}
}
}

private static byte[] toByteArray(InputStream in) {
ByteArrayOutputStream to = new ByteArrayOutputStream();
byte[] buf = new byte[8192];
try {
while (true) {
int r = in.read(buf);
if (r == -1) {
break;
}
to.write(buf, 0, r);
}
return to.toByteArray();
} catch (IOException e) {
throw Errors.asRuntime(e);
}
}

/** Set settings files containing Eclipse preferences */
public void setPreferences(Iterable<File> settingsFiles) {
this.settingsFiles = settingsFiles;
}

/** Creates the state of the configuration. */
EclipseBasedStepBuilder.State get() throws IOException {
/*
* The current use case is tailored for Gradle.
* Gradle calls this method only once per execution
* and compares the State with the one of a previous run
* for incremental building.
* Hence a lazy construction is not required.
*/
return new State(
jarProvisioner,
dependencies,
settingsFiles);
}

/**
* State of Eclipse configuration items, providing functionality to derived information
* based on the state.
*/
public static class State implements Serializable {
// Not used, only the serialization output is required to determine whether the object has changed
private static final long serialVersionUID = 1L;

private final JarState jarState;
private final FileSignature settingsFiles;

/** State constructor expects that all passed items are not modified afterwards */
protected State(Provisioner jarProvisioner, List<String> dependencies, Iterable<File> settingsFiles) throws IOException {
this.jarState = JarState.from(dependencies, jarProvisioner);
this.settingsFiles = FileSignature.signAsList(settingsFiles);
}

/** Get formatter preferences */
public Properties getPreferences() {
//Keep the IllegalArgumentException since it contains detailed information
FormatterProperties preferences = FormatterProperties.from(settingsFiles.files());
return preferences.getProperties();
}

/** Load class based on the given configuration of JAR provider and Maven coordinates. */
public Class<?> loadClass(String name) {
try {
return jarState.getClassLoader().loadClass(name);
} catch (ClassNotFoundException e) {
throw Errors.asRuntime(e);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
@ParametersAreNonnullByDefault
@ReturnValuesAreNonnullByDefault
package com.diffplug.spotless.extra.config;

import javax.annotation.ParametersAreNonnullByDefault;

import com.diffplug.spotless.annotations.ReturnValuesAreNonnullByDefault;
Original file line number Diff line number Diff line change
Expand Up @@ -16,76 +16,62 @@
package com.diffplug.spotless.extra.groovy;

import java.io.File;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Objects;
import java.util.Properties;

import com.diffplug.spotless.FileSignature;
import com.diffplug.spotless.FormatterFunc;
import com.diffplug.spotless.FormatterProperties;
import com.diffplug.spotless.FormatterStep;
import com.diffplug.spotless.JarState;
import com.diffplug.spotless.Provisioner;
import com.diffplug.spotless.extra.EclipseBasedStepBuilder;

/** Formatter step which calls out to the Groovy-Eclipse formatter. */
public class GrEclipseFormatterStep {
private static final String NAME = "groovy-eclipse formatter";
public final class GrEclipseFormatterStep {
// prevent direct instantiation
private GrEclipseFormatterStep() {}

private static final String NAME = "groovy eclipse formatter";
private static final String FORMATTER_CLASS = "com.diffplug.gradle.spotless.groovy.eclipse.GrEclipseFormatterStepImpl";
private static final String DEFAULT_VERSION = "2.3.0";
private static final String MAVEN_COORDINATE = "com.diffplug.spotless:spotless-ext-greclipse:";
private static final String DEFAULT_VERSION = "4.6.3";
private static final String FORMATTER_METHOD = "format";

/** Creates a formatter step using the default version for the given settings file. */
@Deprecated
public static FormatterStep create(Iterable<File> settingsFiles, Provisioner provisioner) {
return create(defaultVersion(), settingsFiles, provisioner);
}

/** Creates a formatter step for the given version and settings file. */
@Deprecated
public static FormatterStep create(String version, Iterable<File> settingsFiles, Provisioner provisioner) {
return FormatterStep.createLazy(
NAME,
() -> new State(JarState.from(MAVEN_COORDINATE + version, provisioner), settingsFiles),
State::createFormat);
EclipseBasedStepBuilder builder = createBuilder(provisioner);
builder.setVersion(version);
builder.setPreferences(settingsFiles);
return builder.build();
}

public static String defaultVersion() {
return DEFAULT_VERSION;
}

private static class State implements Serializable {
private static final long serialVersionUID = 1L;

/** The jar that contains the eclipse formatter. */
final JarState jarState;
/** The signature of the settings file. */
final FileSignature settings;

State(JarState jar, final Iterable<File> settingsFiles) throws Exception {
this.jarState = Objects.requireNonNull(jar);
this.settings = FileSignature.signAsList(settingsFiles);
}

FormatterFunc createFormat() throws Exception {
FormatterProperties preferences = FormatterProperties.from(settings.files());

ClassLoader classLoader = jarState.getClassLoader();
/** Provides default configuration */
public static EclipseBasedStepBuilder createBuilder(Provisioner provisioner) {
return new EclipseBasedStepBuilder(NAME, provisioner, GrEclipseFormatterStep::apply);
}

// instantiate the formatter and get its format method
Class<?> formatterClazz = classLoader.loadClass(FORMATTER_CLASS);
Object formatter = formatterClazz.getConstructor(Properties.class).newInstance(preferences.getProperties());
Method method = formatterClazz.getMethod(FORMATTER_METHOD, String.class);
return input -> {
try {
return (String) method.invoke(formatter, input);
} catch (InvocationTargetException exceptionWrapper) {
Throwable throwable = exceptionWrapper.getTargetException();
Exception exception = (throwable instanceof Exception) ? (Exception) throwable : null;
throw (null == exception) ? exceptionWrapper : exception;
}
};
}
private static FormatterFunc apply(EclipseBasedStepBuilder.State state) throws Exception {
Class<?> formatterClazz = state.loadClass(FORMATTER_CLASS);
Object formatter = formatterClazz.getConstructor(Properties.class).newInstance(state.getPreferences());
Method method = formatterClazz.getMethod(FORMATTER_METHOD, String.class);
return input -> {
try {
return (String) method.invoke(formatter, input);
} catch (InvocationTargetException exceptionWrapper) {
Throwable throwable = exceptionWrapper.getTargetException();
Exception exception = (throwable instanceof Exception) ? (Exception) throwable : null;
throw (null == exception) ? exceptionWrapper : exception;
}
};
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -16,29 +16,23 @@
package com.diffplug.spotless.extra.java;

import java.io.File;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.Objects;
import java.util.Properties;

import com.diffplug.spotless.FileSignature;
import com.diffplug.spotless.FormatterFunc;
import com.diffplug.spotless.FormatterProperties;
import com.diffplug.spotless.FormatterStep;
import com.diffplug.spotless.JarState;
import com.diffplug.spotless.Provisioner;
import com.diffplug.spotless.extra.EclipseBasedStepBuilder;

/** Formatter step which calls out to the Eclipse formatter. */
/**
* Formatter step which calls out to the Eclipse formatter.
* This class is deprecated. Use {@link EclipseJdtFormatterStep} instead.
*/
@Deprecated
public final class EclipseFormatterStep {
// prevent direct instantiation
private EclipseFormatterStep() {}

private static final String DEFAULT_VERSION = "4.7.2";
private static final String NAME = "eclipse formatter";
private static final String MAVEN_COORDINATE = "com.diffplug.spotless:spotless-ext-eclipse-jdt:";
private static final String FORMATTER_CLASS = "com.diffplug.gradle.spotless.java.eclipse.EclipseFormatterStepImpl";
private static final String FORMATTER_METHOD = "format";

/** Creates a formatter step for the given version and settings file.
* Formatter steps based on property configuration should support zero (default configuration)
Expand Down Expand Up @@ -66,39 +60,14 @@ public static FormatterStep create(String version, Iterable<File> settingsFiles,
Objects.requireNonNull(version, "version");
Objects.requireNonNull(settingsFiles, "settingsFiles");
Objects.requireNonNull(provisioner, "provisioner");
return FormatterStep.createLazy(NAME,
() -> new State(JarState.from(MAVEN_COORDINATE + version, provisioner), settingsFiles),
State::createFormat);
EclipseBasedStepBuilder builder = EclipseJdtFormatterStep.createBuilder(provisioner);
builder.setPreferences(settingsFiles);
builder.setVersion(DEFAULT_VERSION);
return builder.build();
}

public static String defaultVersion() {
return DEFAULT_VERSION;
}

private static class State implements Serializable {
private static final long serialVersionUID = 1L;

/** The jar that contains the eclipse formatter. */
final JarState jarState;
/** The signature of the settings file. */
final FileSignature settings;

State(JarState jar, final Iterable<File> settingsFiles) throws Exception {
this.jarState = jar;
this.settings = FileSignature.signAsList(settingsFiles);
}

FormatterFunc createFormat() throws Exception {
FormatterProperties preferences = FormatterProperties.from(settings.files());

ClassLoader classLoader = jarState.getClassLoader();

// instantiate the formatter and get its format method
Class<?> formatterClazz = classLoader.loadClass(FORMATTER_CLASS);
Object formatter = formatterClazz.getConstructor(Properties.class).newInstance(preferences.getProperties());
Method method = formatterClazz.getMethod(FORMATTER_METHOD, String.class);
return input -> (String) method.invoke(formatter, input);
}
}

}
Loading