Skip to content

Commit

Permalink
Make the Equo-based steps round-trip serializable (#1950 towards #1274)
Browse files Browse the repository at this point in the history
  • Loading branch information
nedtwigg authored Jan 24, 2024
2 parents 26fbd03 + 99eebec commit 33093c7
Show file tree
Hide file tree
Showing 7 changed files with 73 additions and 95 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2016-2023 DiffPlug
* Copyright 2016-2024 DiffPlug
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -34,7 +34,7 @@
import com.diffplug.spotless.FormatterStep;
import com.diffplug.spotless.JarState;
import com.diffplug.spotless.Provisioner;
import com.diffplug.spotless.ThrowingEx;
import com.diffplug.spotless.SerializedFunction;

import dev.equo.solstice.NestedJars;
import dev.equo.solstice.p2.P2ClientCache;
Expand All @@ -48,19 +48,19 @@
public abstract class EquoBasedStepBuilder {
private final String formatterName;
private final Provisioner mavenProvisioner;
private final ThrowingEx.Function<State, FormatterFunc> stateToFormatter;
private final SerializedFunction<State, FormatterFunc> stateToFormatter;
private String formatterVersion;
private Iterable<File> settingsFiles = new ArrayList<>();
private Map<String, String> p2Mirrors = Map.of();

/** @deprecated if you use this constructor you *must* call {@link #setVersion(String)} before calling {@link #build()} */
@Deprecated
public EquoBasedStepBuilder(String formatterName, Provisioner mavenProvisioner, ThrowingEx.Function<State, FormatterFunc> stateToFormatter) {
public EquoBasedStepBuilder(String formatterName, Provisioner mavenProvisioner, SerializedFunction<State, FormatterFunc> stateToFormatter) {
this(formatterName, mavenProvisioner, null, stateToFormatter);
}

/** Initialize valid default configuration, taking latest version */
public EquoBasedStepBuilder(String formatterName, Provisioner mavenProvisioner, @Nullable String defaultVersion, ThrowingEx.Function<State, FormatterFunc> stateToFormatter) {
public EquoBasedStepBuilder(String formatterName, Provisioner mavenProvisioner, @Nullable String defaultVersion, SerializedFunction<State, FormatterFunc> stateToFormatter) {
this.formatterName = formatterName;
this.mavenProvisioner = mavenProvisioner;
this.formatterVersion = defaultVersion;
Expand All @@ -83,11 +83,6 @@ public void setP2Mirrors(Collection<P2Mirror> p2Mirrors) {
this.p2Mirrors = p2Mirrors.stream().collect(toMap(P2Mirror::getPrefix, P2Mirror::getUrl));
}

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

protected abstract P2Model model(String version);

protected void addPlatformRepo(P2Model model, String version) {
Expand All @@ -107,26 +102,28 @@ protected void addPlatformRepo(P2Model model, String version) {
}
}

/** Creates the state of the configuration. */
EquoBasedStepBuilder.State get() throws Exception {
P2QueryResult query;
try {
query = createModelWithMirrors().query(P2ClientCache.PREFER_OFFLINE, P2QueryCache.ALLOW);
} catch (Exception x) {
throw new IOException("Failed to load " + formatterName + ": " + x, x);
}
var classpath = new ArrayList<File>();
var mavenDeps = new ArrayList<String>();
mavenDeps.add("dev.equo.ide:solstice:1.7.4");
mavenDeps.add("com.diffplug.durian:durian-swt.os:4.2.0");
mavenDeps.addAll(query.getJarsOnMavenCentral());
classpath.addAll(mavenProvisioner.provisionWithTransitives(false, mavenDeps));
classpath.addAll(query.getJarsNotOnMavenCentral());
for (var nested : NestedJars.inFiles(query.getJarsNotOnMavenCentral()).extractAllNestedJars()) {
classpath.add(nested.getValue());
}
var jarState = JarState.preserveOrder(classpath);
return new State(formatterVersion, jarState, FileSignature.signAsList(settingsFiles));
/** Returns the FormatterStep (whose state will be calculated lazily). */
public FormatterStep build() {
var roundtrippableState = new EquoStep(formatterVersion, FileSignature.promise(settingsFiles), JarState.promise(() -> {
P2QueryResult query;
try {
query = createModelWithMirrors().query(P2ClientCache.PREFER_OFFLINE, P2QueryCache.ALLOW);
} catch (Exception x) {
throw new IOException("Failed to load " + formatterName + ": " + x, x);
}
var classpath = new ArrayList<File>();
var mavenDeps = new ArrayList<String>();
mavenDeps.add("dev.equo.ide:solstice:1.7.5");
mavenDeps.add("com.diffplug.durian:durian-swt.os:4.2.0");
mavenDeps.addAll(query.getJarsOnMavenCentral());
classpath.addAll(mavenProvisioner.provisionWithTransitives(false, mavenDeps));
classpath.addAll(query.getJarsNotOnMavenCentral());
for (var nested : NestedJars.inFiles(query.getJarsNotOnMavenCentral()).extractAllNestedJars()) {
classpath.add(nested.getValue());
}
return JarState.preserveOrder(classpath);
}));
return FormatterStep.create(formatterName, roundtrippableState, EquoStep::state, stateToFormatter);
}

private P2Model createModelWithMirrors() {
Expand All @@ -152,12 +149,29 @@ private P2Model createModelWithMirrors() {
return model;
}

static class EquoStep implements Serializable {
private static final long serialVersionUID = 1;
private final String semanticVersion;
private final FileSignature.Promised settingsPromise;
private final JarState.Promised jarPromise;

EquoStep(String semanticVersion, FileSignature.Promised settingsPromise, JarState.Promised jarPromise) {
this.semanticVersion = semanticVersion;
this.settingsPromise = settingsPromise;
this.jarPromise = jarPromise;
}

private State state() {
return new State(semanticVersion, jarPromise.get(), settingsPromise.get());
}
}

/**
* State of Eclipse configuration items, providing functionality to derived information
* based on the state.
*/
public static class State implements Serializable {
private static final long serialVersionUID = 584400372246020995L;
private static final long serialVersionUID = 1;
final String semanticVersion;
final JarState jarState;
final FileSignature settingsFiles;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2016-2023 DiffPlug
* Copyright 2016-2024 DiffPlug
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -24,17 +24,16 @@
import com.diffplug.spotless.extra.eclipse.EquoResourceHarness;

class EclipseCdtFormatterStepTest extends EquoResourceHarness {
private final static String INPUT = "#include <a.h>;\nint main(int argc, \nchar *argv[]) {}";
private final static String EXPECTED = "#include <a.h>;\nint main(int argc, char *argv[]) {\n}\n";

public EclipseCdtFormatterStepTest() {
super(EclipseCdtFormatterStep.createBuilder(TestProvisioner.mavenCentral()), INPUT, EXPECTED);
super(EclipseCdtFormatterStep.createBuilder(TestProvisioner.mavenCentral()));
}

@ParameterizedTest
@MethodSource
void formatWithVersion(String version) throws Exception {
assertFormatted(version);
harnessFor(version).test("main.c",
"#include <a.h>;\nint main(int argc, \nchar *argv[]) {}",
"#include <a.h>;\nint main(int argc, char *argv[]) {\n}\n");
}

private static Stream<String> formatWithVersion() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2016-2023 DiffPlug
* Copyright 2016-2024 DiffPlug
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -15,14 +15,12 @@
*/
package com.diffplug.spotless.extra.eclipse;

import static org.assertj.core.api.Assertions.assertThat;

import java.io.File;
import java.util.Arrays;

import com.diffplug.spotless.FormatterStep;
import com.diffplug.spotless.LineEnding;
import com.diffplug.spotless.ResourceHarness;
import com.diffplug.spotless.StepHarnessWithFile;
import com.diffplug.spotless.extra.EquoBasedStepBuilder;

/**
Expand All @@ -43,57 +41,19 @@
*/
public class EquoResourceHarness extends ResourceHarness {
private final EquoBasedStepBuilder stepBuilder;
private final String fileName;
private final String input;
private final String expected;

/**
* Create harness to be used for several versions of the formatter step
* @param builder Eclipse Formatter step builder
* @param unformatted Simple unformatted input
* @param formatted Expected formatted output
*/
public EquoResourceHarness(EquoBasedStepBuilder builder, String unformatted, String formatted) {
this(builder, "someSourceFile", unformatted, formatted);
}

/**
* Create harness to be used for several versions of the formatter step
* @param builder Eclipse Formatter step builder
* @param sourceFileName File name of the source file
* @param unformatted Simple unformatted input
* @param formatted Expected formatted output
*/
public EquoResourceHarness(EquoBasedStepBuilder builder, String sourceFileName, String unformatted, String formatted) {
public EquoResourceHarness(EquoBasedStepBuilder builder) {
stepBuilder = builder;
fileName = sourceFileName;
input = unformatted;
expected = formatted;
}

/**
* Assert that formatting input results in expected output
* @param formatterVersion Formatter version
* @param settingsFiles Formatter settings
* @return Formatted string
*/
protected String assertFormatted(String formatterVersion, File... settingsFiles) throws Exception {
String output = format(formatterVersion, settingsFiles);
assertThat(output).isEqualTo(expected);
return output;
}

/**
* Formatting input results and returns output
* @param formatterVersion Formatter version
* @param settingsFiles Formatter settings
* @return Formatted string
*/
protected String format(String formatterVersion, File... settingsFiles) throws Exception {
File inputFile = setFile(fileName).toContent(input);
protected StepHarnessWithFile harnessFor(String formatterVersion, File... settingsFiles) throws Exception {
stepBuilder.setVersion(formatterVersion);
stepBuilder.setPreferences(Arrays.asList(settingsFiles));
FormatterStep step = stepBuilder.build();
return LineEnding.toUnix(step.format(input, inputFile));
return StepHarnessWithFile.forStep(this, step);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2016-2023 DiffPlug
* Copyright 2016-2024 DiffPlug
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -28,13 +28,14 @@ public class GrEclipseFormatterStepTest extends EquoResourceHarness {
private final static String EXPECTED = "class F{\n\tdef m(){}\n}";

public GrEclipseFormatterStepTest() {
super(GrEclipseFormatterStep.createBuilder(TestProvisioner.mavenCentral()), INPUT, EXPECTED);
super(GrEclipseFormatterStep.createBuilder(TestProvisioner.mavenCentral()));
}

@ParameterizedTest
@MethodSource
void formatWithVersion(String version) throws Exception {
assertFormatted(version);
harnessFor(version).test("test.groovy",
"class F{ def m(){} }", "class F{\n\tdef m(){}\n}");
}

private static Stream<String> formatWithVersion() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2016-2023 DiffPlug
* Copyright 2016-2024 DiffPlug
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -15,7 +15,6 @@
*/
package com.diffplug.spotless.extra.java;

import java.io.File;
import java.util.stream.Stream;

import org.junit.jupiter.api.Nested;
Expand All @@ -28,21 +27,20 @@
import com.diffplug.spotless.extra.eclipse.EquoResourceHarness;

class EclipseJdtFormatterStepTest extends EquoResourceHarness {
private final static String INPUT = "package p; class C{}";
private final static String EXPECTED = "package p;\nclass C {\n}";

private static EquoBasedStepBuilder createBuilder() {
return EclipseJdtFormatterStep.createBuilder(TestProvisioner.mavenCentral());
}

public EclipseJdtFormatterStepTest() {
super(createBuilder(), INPUT, EXPECTED);
super(createBuilder());
}

@ParameterizedTest
@MethodSource
void formatWithVersion(String version) throws Exception {
assertFormatted(version);
harnessFor(version).test("test.java",
"package p; class C{}",
"package p;\nclass C {\n}");
}

private static Stream<String> formatWithVersion() {
Expand All @@ -53,13 +51,13 @@ private static Stream<String> formatWithVersion() {
@Nested
class NewFormatInterface extends EquoResourceHarness {
public NewFormatInterface() {
super(createBuilder(), "module-info.java", getTestResource("java/eclipse/ModuleInfoUnformatted.test"), getTestResource("java/eclipse/ModuleInfoFormatted.test"));
super(createBuilder());
}

@Test
void formatModuleInfo() throws Exception {
File settingsFile = createTestFile("java/eclipse/ModuleInfo.prefs");
assertFormatted("4.11", settingsFile);
harnessFor("4.11", createTestFile("java/eclipse/ModuleInfo.prefs"))
.testResource("module-info.java", "java/eclipse/ModuleInfoUnformatted.test", "java/eclipse/ModuleInfoFormatted.test");
}
}
}
4 changes: 4 additions & 0 deletions lib/src/main/java/com/diffplug/spotless/FileSignature.java
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,10 @@ public Promised asPromise() {
return new Promised(files, this);
}

public static Promised promise(Iterable<File> files) {
return new Promised(MoreIterables.toNullHostileList(files), null);
}

/** Returns all of the files in this signature, throwing an exception if there are more or less than 1 file. */
public Collection<File> files() {
return Collections.unmodifiableList(files);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ protected StepHarnessBase(Formatter formatter) {
supportsRoundTrip = true;
} else if (onlyStepName.equals("diktat")) {
supportsRoundTrip = true;
} else if (onlyStepName.equals("eclipse jdt formatter") || onlyStepName.equals("eclipse cdt formatter") || onlyStepName.equals("eclipse groovy formatter")) {
supportsRoundTrip = true;
}
}
}
Expand Down

0 comments on commit 33093c7

Please sign in to comment.