Skip to content

Commit 28a6073

Browse files
authored
Applied common Spotless Eclipse framework to Groovy-Eclipse (#244)
Upgraded from groovy-eclipse version 2.9.1 to 2.9.2. Using Spotless Eclipse Framework. Introduced property to ignore formatter warnings/errors.
1 parent aa04c02 commit 28a6073

File tree

17 files changed

+952
-923
lines changed

17 files changed

+952
-923
lines changed
File renamed without changes.

Diff for: _ext/eclipse-groovy/README.md

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# spotless-eclipse-groovy
2+
3+
Groovy-Eclipse is not available in a form which can be easily consumed by maven or gradle.
4+
To fix this, we publish Groovy-Eclipse's formatter and all its dependencies, along with a small amount of glue code, into the `com.diffplug.gradle.spotless:spotless-eclipse-groovy` artifact.
5+
6+
## Build
7+
8+
To publish a new version, update the `_ext/eclipse-groovy/gradle.properties` appropriately and run this from the root directory:
9+
10+
```
11+
gradlew -b _ext/eclipse-groovy/build.gradle publish
12+
```
13+
14+
Spotless at large is under the Apache 2.0 license, but this jar is under the EPL v1.

Diff for: _ext/eclipse-groovy/build.gradle

+179
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
import java.io.File
2+
3+
import org.apache.commons.io.filefilter.DirectoryFileFilter
4+
5+
plugins {
6+
// p2 dependencies
7+
id 'com.diffplug.gradle.p2.asmaven' version '3.9.0'
8+
}
9+
10+
apply from: rootProject.file('../gradle/java-setup.gradle')
11+
apply from: rootProject.file('../gradle/java-publish.gradle')
12+
13+
// The dependencies to pull from GrEclipse's p2 repositories
14+
def grEclipseDeps = [
15+
'org.codehaus.groovy.eclipse.refactoring':'+', // GroovyFormatter and related
16+
17+
// The following lists does not reflect the complete transitive required packages, but
18+
// the once used during code formatting
19+
'org.codehaus.groovy':'+', // Groovy compiler patches supporting use within GrEclipse and Groovy itself
20+
'org.codehaus.groovy.eclipse.core':'+', // Groovy core classes (provides central logging used by formatter)
21+
'org.eclipse.jdt.core':"${VER_JDT_PATCH}", // Patches org.eclipse.jdt.core classes supporting use within GrEclipse (provides AST generator)
22+
'org.eclipse.jdt.groovy.core':'+' // Extends org.eclipse.jdt.core for Groovy
23+
]
24+
25+
ext {
26+
developers = [
27+
fvgh: [ name: 'Frank Vennemeyer', email: '[email protected]' ],
28+
]
29+
30+
//Include/Excludes form the JARs, which goes into a fat-jar with the spottless formatter interface.
31+
jarInclude = [
32+
'**/*.class', // Take all classes
33+
'**/*.java', // ... and sources.
34+
'**/*.properties', // Text resources (for messages, etc)
35+
'**/*.xml', // Plugin XML and other resources
36+
'*.html', // License information about the included JARs,
37+
'META-INF/**' // Information about the origin of the individual class files
38+
]
39+
jarExclude = [
40+
'META-INF/*.RSA', // The eclipse jars are signed, and our fat-jar breaks the signatures
41+
'META-INF/*.SF', // ... so all signatures are filtered
42+
]
43+
44+
//Some JARs include JARs themselfs
45+
internalJars = [
46+
//Jars included by org.codehaus.groovy
47+
"**/groovy-all-${VER_GROOVY}-indy", // Use Groovy compiler compatible with GrEclipse instead of localGroovy
48+
'**/groovy-eclipse', // Patches/Overrides some of the Groovy compiler classes
49+
'**/eclipse-trace', // Provides logging capabilities for groovy-eclipse
50+
51+
//Jars included by org.eclipse.jdt.groovy.core
52+
'**/nlcl' //Non locking class loader used by groovy compiler
53+
]
54+
55+
// The directory contains all external classes for the fat-jar
56+
embeddedClassesDirName = 'build/embeddedClasses'
57+
embeddedClassesDir = project.file(embeddedClassesDirName)
58+
embeddedClassesLibDirName = 'build/embeddedClasses/lib'
59+
embeddedClassesLibDir = project.file(embeddedClassesLibDirName)
60+
}
61+
62+
// build a maven repo in our build folder containing these artifacts
63+
p2AsMaven {
64+
group 'p2', {
65+
repo "http://dist.springsource.org/release/GRECLIPSE/e${VER_ECLIPSE}"
66+
grEclipseDeps.keySet.each { p2.addIU(it) }
67+
}
68+
}
69+
70+
configurations {
71+
embeddedJars // GrEclipse JARs the fat-jar is based uppon
72+
}
73+
74+
dependencies {
75+
grEclipseDeps.each { groupArtifact, version ->
76+
embeddedJars "p2:${groupArtifact}:${version}"
77+
}
78+
79+
// The resulting fat-jar includes the classes from GRECLIPSE.
80+
compile files(embeddedClassesDir)
81+
82+
compile "com.diffplug.spotless:spotless-eclipse-base:${VER_SPOTLESS_ECLISPE_BASE}"
83+
// Provides text partitioners for formatters
84+
compile ("org.eclipse.platform:org.eclipse.jface.text:${VER_ECLISPE_JFACE}") {
85+
exclude group: 'org.eclipse.platform', module: 'org.eclipse.swt'
86+
}
87+
}
88+
89+
jar {
90+
// this embeds the Eclipse-Groovy clases into our "fat JAR"
91+
from embeddedClassesDir
92+
}
93+
94+
//////////
95+
// Test //
96+
//////////
97+
sourceSets {
98+
// Use JAR file with all resources for Eclipse-Groovy integration-tests
99+
test.runtimeClasspath = jar.outputs.files + sourceSets.test.output + sourceSets.test.compileClasspath
100+
}
101+
102+
///////////////////
103+
// External Deps //
104+
///////////////////
105+
106+
task unjarEmbeddedClasses {
107+
description = "Copies filtered set of embedded classes from the Eclise/GrEclipse dependencies to '${project.relativePath(embeddedClassesDir)}'."
108+
inputs.files(configurations.embeddedJars)
109+
inputs.property('internalJars', internalJars)
110+
inputs.property('jarInclude', jarInclude)
111+
inputs.property('jarExclude', jarExclude)
112+
outputs.file(embeddedClassesDir)
113+
114+
doLast {
115+
embeddedClassesDir.deleteDir()
116+
embeddedClassesDir.mkdirs()
117+
embeddedClassesLibDir.deleteDir()
118+
embeddedClassesLibDir.mkdirs()
119+
configurations.embeddedJars.each {
120+
unjar(it, embeddedClassesDir)
121+
}
122+
//Unpack internal JARs. Maintain the order defined in internalJars
123+
internalJars.each {
124+
fileTree(embeddedClassesDir).include("${it}.jar").each {
125+
unjar(it, embeddedClassesDir)
126+
delete(it)
127+
}
128+
}
129+
}
130+
}
131+
132+
def unjar(File jarFile, File destDir) {
133+
ant.unjar(src: jarFile, dest: destDir) {
134+
patternset {
135+
jarInclude.each {
136+
include(name: "${it}")
137+
}
138+
internalJars.each {
139+
include(name: "**/${it}.jar")
140+
}
141+
jarExclude.each {
142+
exclude(name: "${it}")
143+
}
144+
}
145+
}
146+
//Provide Fat JAR resources (following naming convention of spotless-eclipse-base)
147+
def fat_jar_resource_dir = jarFile.getName().split('-')[0]
148+
ant.move(todir: "${destDir}/${fat_jar_resource_dir}/META-INF", quiet: 'true', failonerror: 'false') {
149+
fileset(dir: "${destDir}/META-INF")
150+
}
151+
//Keep licenses and other human readable information for transparency
152+
ant.move(todir: "${destDir}/${fat_jar_resource_dir}", quiet: 'true') {
153+
fileset(dir: destDir) {
154+
include(name: 'META-INF')
155+
include(name: '*')
156+
type(type: 'file')
157+
exclude(name: '*jar-*')
158+
exclude(name: '*.jar')
159+
}
160+
}
161+
}
162+
163+
tasks.compileJava.dependsOn(unjarEmbeddedClasses)
164+
165+
/////////
166+
// IDE //
167+
/////////
168+
169+
apply plugin: 'eclipse'
170+
171+
// always create fresh projects
172+
tasks.eclipse.dependsOn(cleanEclipse)
173+
// Encure that the dependent classes are preovided for compilation if project is build via Eclipse instead of command line
174+
tasks.eclipseClasspath.dependsOn(unjarEmbeddedClasses)
175+
176+
apply plugin: 'idea'
177+
178+
// Encure that the dependent classes are preovided for compilation if project is build via Eclipse instead of command line
179+
tasks.idea.dependsOn(unjarEmbeddedClasses)

Diff for: _ext/eclipse-groovy/gradle.properties

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Versions correspond to the Eclipse-Groovy version used for th FAT JAR
2+
# See https://github.com/groovy/groovy-eclipse/releases for further information about Eclipse-Groovy versions.
3+
# Patch version can be is incremented independently for backward compatible patches of this library.
4+
ext_version=2.9.2
5+
ext_artifactId=spotless-eclipse-groovy
6+
ext_description=Groovy Eclipse's formatter bundled for Spotless
7+
8+
ext_org=diffplug
9+
ext_group=com.diffplug.spotless
10+
11+
# Build requirements
12+
ext_VER_JAVA=1.8
13+
14+
# Compile
15+
VER_ECLIPSE=4.7
16+
VER_SPOTLESS_ECLISPE_BASE=[3.0.0,4.0.0[
17+
VER_ECLISPE_JFACE=[3.12.0,4.0.0[
18+
VER_GROOVY=2.5.0
19+
VER_JDT_PATCH=3.13.100.xx-201801041714-e47-RELEASE

Diff for: _ext/greclipse/src/main/java/com/diffplug/gradle/spotless/groovy/eclipse/GrEclipseFormatterStepImpl.java renamed to _ext/eclipse-groovy/src/main/java/com/diffplug/spotless/extra/eclipse/groovy/GrEclipseFormatterStepImpl.java

+60-8
Original file line numberDiff line numberDiff line change
@@ -13,70 +13,106 @@
1313
* See the License for the specific language governing permissions and
1414
* limitations under the License.
1515
*/
16-
package com.diffplug.gradle.spotless.groovy.eclipse;
16+
package com.diffplug.spotless.extra.eclipse.groovy;
1717

1818
import java.io.ByteArrayInputStream;
1919
import java.io.ByteArrayOutputStream;
2020
import java.io.IOException;
21-
import java.util.LinkedList;
21+
import java.util.ArrayList;
22+
import java.util.Collections;
2223
import java.util.List;
2324
import java.util.Properties;
2425

26+
import org.codehaus.groovy.eclipse.GroovyLogManager;
27+
import org.codehaus.groovy.eclipse.IGroovyLogger;
28+
import org.codehaus.groovy.eclipse.TraceCategory;
2529
import org.codehaus.groovy.eclipse.core.GroovyCoreActivator;
2630
import org.codehaus.groovy.eclipse.refactoring.formatter.DefaultGroovyFormatter;
2731
import org.codehaus.groovy.eclipse.refactoring.formatter.FormatterPreferencesOnStore;
2832
import org.codehaus.groovy.eclipse.refactoring.formatter.GroovyFormatter;
2933
import org.eclipse.core.runtime.ILog;
3034
import org.eclipse.core.runtime.ILogListener;
3135
import org.eclipse.core.runtime.IStatus;
36+
import org.eclipse.equinox.log.ExtendedLogReaderService;
37+
import org.eclipse.equinox.log.ExtendedLogService;
3238
import org.eclipse.jface.preference.PreferenceStore;
3339
import org.eclipse.jface.text.Document;
3440
import org.eclipse.jface.text.IDocument;
3541
import org.eclipse.jface.text.TextSelection;
3642
import org.eclipse.text.edits.TextEdit;
3743

44+
import com.diffplug.spotless.extra.eclipse.base.SpotlessEclipseFramework;
45+
3846
/** Spotless-Formatter step which calls out to the Groovy-Eclipse formatter. */
3947
public class GrEclipseFormatterStepImpl {
48+
/**
49+
* Groovy compiler problems can be ignored.
50+
* <p>
51+
* Value is either 'true' or 'false'
52+
* </p>
53+
*/
54+
public static final String IGNORE_FORMATTER_PROBLEMS = "ignoreFormatterProblems";
55+
4056
private final FormatterPreferencesOnStore preferencesStore;
57+
private final boolean ignoreFormatterProblems;
4158

4259
public GrEclipseFormatterStepImpl(final Properties properties) throws Exception {
60+
SpotlessLogService logService = new SpotlessLogService();
61+
if (SpotlessEclipseFramework.setup(
62+
config -> {
63+
config.applyDefault();
64+
config.add(ExtendedLogService.class, logService);
65+
config.add(ExtendedLogReaderService.class, logService);
66+
},
67+
plugins -> {
68+
plugins.add(new GroovyCoreActivator());
69+
})) {}
4370
PreferenceStore preferences = createPreferences(properties);
4471
preferencesStore = new FormatterPreferencesOnStore(preferences);
72+
ignoreFormatterProblems = Boolean.parseBoolean(properties.getProperty(IGNORE_FORMATTER_PROBLEMS, "false"));
4573
}
4674

75+
/** Formatting Groovy string */
4776
public String format(String raw) throws Exception {
4877
IDocument doc = new Document(raw);
4978
GroovyErrorListener errorListener = new GroovyErrorListener();
5079
TextSelection selectAll = new TextSelection(doc, 0, doc.getLength());
5180
GroovyFormatter codeFormatter = new DefaultGroovyFormatter(selectAll, doc, preferencesStore, false);
5281
TextEdit edit = codeFormatter.format();
53-
if (errorListener.errorsDetected()) {
82+
if (!ignoreFormatterProblems && errorListener.errorsDetected()) {
5483
throw new IllegalArgumentException(errorListener.toString());
5584
}
5685
edit.apply(doc);
5786
return doc.get();
5887
}
5988

60-
private static class GroovyErrorListener implements ILogListener {
89+
/**
90+
* Eclipse Groovy formatter does not signal problems by its return value, but by logging errors.
91+
*/
92+
private static class GroovyErrorListener implements ILogListener, IGroovyLogger {
6193

6294
private final List<String> errors;
6395

6496
public GroovyErrorListener() {
65-
errors = new LinkedList<String>();
97+
/*
98+
* We need a synchronized list here, in case multiple instantiations
99+
* run in parallel.
100+
*/
101+
errors = Collections.synchronizedList(new ArrayList<String>());
66102
ILog groovyLogger = GroovyCoreActivator.getDefault().getLog();
67103
groovyLogger.addLogListener(this);
104+
GroovyLogManager.manager.addLogger(this);
68105
}
69106

70107
@Override
71108
public void logging(final IStatus status, final String plugin) {
72-
if (!status.isOK()) {
73-
errors.add(status.getMessage());
74-
}
109+
errors.add(status.getMessage());
75110
}
76111

77112
public boolean errorsDetected() {
78113
ILog groovyLogger = GroovyCoreActivator.getDefault().getLog();
79114
groovyLogger.removeLogListener(this);
115+
GroovyLogManager.manager.removeLogger(this);
80116
return 0 != errors.size();
81117
}
82118

@@ -96,6 +132,22 @@ public String toString() {
96132
return string.toString();
97133
}
98134

135+
@Override
136+
public boolean isCategoryEnabled(TraceCategory cat) {
137+
/*
138+
* Note that the compiler errors are just additionally caught here.
139+
* They are also printed directly to System.err.
140+
* See org.codehaus.jdt.groovy.internal.compiler.ast.GroovyCompilationUnitDeclaration.recordProblems
141+
* for details.
142+
*/
143+
return TraceCategory.COMPILER.equals(cat);
144+
}
145+
146+
@Override
147+
public void log(TraceCategory arg0, String arg1) {
148+
errors.add(arg1);
149+
}
150+
99151
}
100152

101153
private static PreferenceStore createPreferences(final Properties properties) throws IOException {

0 commit comments

Comments
 (0)