diff --git a/_ext/greclipse/LICENSE.txt b/_ext/eclipse-groovy/LICENSE.txt similarity index 100% rename from _ext/greclipse/LICENSE.txt rename to _ext/eclipse-groovy/LICENSE.txt diff --git a/_ext/eclipse-groovy/README.md b/_ext/eclipse-groovy/README.md new file mode 100644 index 0000000000..8850ecd75c --- /dev/null +++ b/_ext/eclipse-groovy/README.md @@ -0,0 +1,14 @@ +# spotless-eclipse-groovy + +Groovy-Eclipse is not available in a form which can be easily consumed by maven or gradle. +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. + +## Build + +To publish a new version, update the `_ext/eclipse-groovy/gradle.properties` appropriately and run this from the root directory: + +``` +gradlew -b _ext/eclipse-groovy/build.gradle publish +``` + +Spotless at large is under the Apache 2.0 license, but this jar is under the EPL v1. diff --git a/_ext/eclipse-groovy/build.gradle b/_ext/eclipse-groovy/build.gradle new file mode 100644 index 0000000000..bb2c6a9a22 --- /dev/null +++ b/_ext/eclipse-groovy/build.gradle @@ -0,0 +1,179 @@ +import java.io.File + +import org.apache.commons.io.filefilter.DirectoryFileFilter + +plugins { + // p2 dependencies + id 'com.diffplug.gradle.p2.asmaven' version '3.9.0' +} + +apply from: rootProject.file('../gradle/java-setup.gradle') +apply from: rootProject.file('../gradle/java-publish.gradle') + +// The dependencies to pull from GrEclipse's p2 repositories +def grEclipseDeps = [ + 'org.codehaus.groovy.eclipse.refactoring':'+', // GroovyFormatter and related + + // The following lists does not reflect the complete transitive required packages, but + // the once used during code formatting + 'org.codehaus.groovy':'+', // Groovy compiler patches supporting use within GrEclipse and Groovy itself + 'org.codehaus.groovy.eclipse.core':'+', // Groovy core classes (provides central logging used by formatter) + 'org.eclipse.jdt.core':"${VER_JDT_PATCH}", // Patches org.eclipse.jdt.core classes supporting use within GrEclipse (provides AST generator) + 'org.eclipse.jdt.groovy.core':'+' // Extends org.eclipse.jdt.core for Groovy +] + +ext { + developers = [ + fvgh: [ name: 'Frank Vennemeyer', email: 'frankgh@zoho.com' ], + ] + + //Include/Excludes form the JARs, which goes into a fat-jar with the spottless formatter interface. + jarInclude = [ + '**/*.class', // Take all classes + '**/*.java', // ... and sources. + '**/*.properties', // Text resources (for messages, etc) + '**/*.xml', // Plugin XML and other resources + '*.html', // License information about the included JARs, + 'META-INF/**' // Information about the origin of the individual class files + ] + jarExclude = [ + 'META-INF/*.RSA', // The eclipse jars are signed, and our fat-jar breaks the signatures + 'META-INF/*.SF', // ... so all signatures are filtered + ] + + //Some JARs include JARs themselfs + internalJars = [ + //Jars included by org.codehaus.groovy + "**/groovy-all-${VER_GROOVY}-indy", // Use Groovy compiler compatible with GrEclipse instead of localGroovy + '**/groovy-eclipse', // Patches/Overrides some of the Groovy compiler classes + '**/eclipse-trace', // Provides logging capabilities for groovy-eclipse + + //Jars included by org.eclipse.jdt.groovy.core + '**/nlcl' //Non locking class loader used by groovy compiler + ] + + // The directory contains all external classes for the fat-jar + embeddedClassesDirName = 'build/embeddedClasses' + embeddedClassesDir = project.file(embeddedClassesDirName) + embeddedClassesLibDirName = 'build/embeddedClasses/lib' + embeddedClassesLibDir = project.file(embeddedClassesLibDirName) +} + +// build a maven repo in our build folder containing these artifacts +p2AsMaven { + group 'p2', { + repo "http://dist.springsource.org/release/GRECLIPSE/e${VER_ECLIPSE}" + grEclipseDeps.keySet.each { p2.addIU(it) } + } +} + +configurations { + embeddedJars // GrEclipse JARs the fat-jar is based uppon +} + +dependencies { + grEclipseDeps.each { groupArtifact, version -> + embeddedJars "p2:${groupArtifact}:${version}" + } + + // The resulting fat-jar includes the classes from GRECLIPSE. + compile files(embeddedClassesDir) + + compile "com.diffplug.spotless:spotless-eclipse-base:${VER_SPOTLESS_ECLISPE_BASE}" + // Provides text partitioners for formatters + compile ("org.eclipse.platform:org.eclipse.jface.text:${VER_ECLISPE_JFACE}") { + exclude group: 'org.eclipse.platform', module: 'org.eclipse.swt' + } +} + +jar { + // this embeds the Eclipse-Groovy clases into our "fat JAR" + from embeddedClassesDir +} + +////////// +// Test // +////////// +sourceSets { + // Use JAR file with all resources for Eclipse-Groovy integration-tests + test.runtimeClasspath = jar.outputs.files + sourceSets.test.output + sourceSets.test.compileClasspath +} + +/////////////////// +// External Deps // +/////////////////// + +task unjarEmbeddedClasses { + description = "Copies filtered set of embedded classes from the Eclise/GrEclipse dependencies to '${project.relativePath(embeddedClassesDir)}'." + inputs.files(configurations.embeddedJars) + inputs.property('internalJars', internalJars) + inputs.property('jarInclude', jarInclude) + inputs.property('jarExclude', jarExclude) + outputs.file(embeddedClassesDir) + + doLast { + embeddedClassesDir.deleteDir() + embeddedClassesDir.mkdirs() + embeddedClassesLibDir.deleteDir() + embeddedClassesLibDir.mkdirs() + configurations.embeddedJars.each { + unjar(it, embeddedClassesDir) + } + //Unpack internal JARs. Maintain the order defined in internalJars + internalJars.each { + fileTree(embeddedClassesDir).include("${it}.jar").each { + unjar(it, embeddedClassesDir) + delete(it) + } + } + } +} + +def unjar(File jarFile, File destDir) { + ant.unjar(src: jarFile, dest: destDir) { + patternset { + jarInclude.each { + include(name: "${it}") + } + internalJars.each { + include(name: "**/${it}.jar") + } + jarExclude.each { + exclude(name: "${it}") + } + } + } + //Provide Fat JAR resources (following naming convention of spotless-eclipse-base) + def fat_jar_resource_dir = jarFile.getName().split('-')[0] + ant.move(todir: "${destDir}/${fat_jar_resource_dir}/META-INF", quiet: 'true', failonerror: 'false') { + fileset(dir: "${destDir}/META-INF") + } + //Keep licenses and other human readable information for transparency + ant.move(todir: "${destDir}/${fat_jar_resource_dir}", quiet: 'true') { + fileset(dir: destDir) { + include(name: 'META-INF') + include(name: '*') + type(type: 'file') + exclude(name: '*jar-*') + exclude(name: '*.jar') + } + } +} + +tasks.compileJava.dependsOn(unjarEmbeddedClasses) + +///////// +// IDE // +///////// + +apply plugin: 'eclipse' + +// always create fresh projects +tasks.eclipse.dependsOn(cleanEclipse) +// Encure that the dependent classes are preovided for compilation if project is build via Eclipse instead of command line +tasks.eclipseClasspath.dependsOn(unjarEmbeddedClasses) + +apply plugin: 'idea' + +// Encure that the dependent classes are preovided for compilation if project is build via Eclipse instead of command line +tasks.idea.dependsOn(unjarEmbeddedClasses) diff --git a/_ext/eclipse-groovy/gradle.properties b/_ext/eclipse-groovy/gradle.properties new file mode 100644 index 0000000000..766a0c9639 --- /dev/null +++ b/_ext/eclipse-groovy/gradle.properties @@ -0,0 +1,19 @@ +# Versions correspond to the Eclipse-Groovy version used for th FAT JAR +# See https://github.com/groovy/groovy-eclipse/releases for further information about Eclipse-Groovy versions. +# Patch version can be is incremented independently for backward compatible patches of this library. +ext_version=2.9.2 +ext_artifactId=spotless-eclipse-groovy +ext_description=Groovy Eclipse's formatter bundled for Spotless + +ext_org=diffplug +ext_group=com.diffplug.spotless + +# Build requirements +ext_VER_JAVA=1.8 + +# Compile +VER_ECLIPSE=4.7 +VER_SPOTLESS_ECLISPE_BASE=[3.0.0,4.0.0[ +VER_ECLISPE_JFACE=[3.12.0,4.0.0[ +VER_GROOVY=2.5.0 +VER_JDT_PATCH=3.13.100.xx-201801041714-e47-RELEASE diff --git a/_ext/greclipse/src/main/java/com/diffplug/gradle/spotless/groovy/eclipse/GrEclipseFormatterStepImpl.java b/_ext/eclipse-groovy/src/main/java/com/diffplug/spotless/extra/eclipse/groovy/GrEclipseFormatterStepImpl.java similarity index 62% rename from _ext/greclipse/src/main/java/com/diffplug/gradle/spotless/groovy/eclipse/GrEclipseFormatterStepImpl.java rename to _ext/eclipse-groovy/src/main/java/com/diffplug/spotless/extra/eclipse/groovy/GrEclipseFormatterStepImpl.java index 815f5f1226..2c507a34d9 100644 --- a/_ext/greclipse/src/main/java/com/diffplug/gradle/spotless/groovy/eclipse/GrEclipseFormatterStepImpl.java +++ b/_ext/eclipse-groovy/src/main/java/com/diffplug/spotless/extra/eclipse/groovy/GrEclipseFormatterStepImpl.java @@ -13,15 +13,19 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.diffplug.gradle.spotless.groovy.eclipse; +package com.diffplug.spotless.extra.eclipse.groovy; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; -import java.util.LinkedList; +import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Properties; +import org.codehaus.groovy.eclipse.GroovyLogManager; +import org.codehaus.groovy.eclipse.IGroovyLogger; +import org.codehaus.groovy.eclipse.TraceCategory; import org.codehaus.groovy.eclipse.core.GroovyCoreActivator; import org.codehaus.groovy.eclipse.refactoring.formatter.DefaultGroovyFormatter; import org.codehaus.groovy.eclipse.refactoring.formatter.FormatterPreferencesOnStore; @@ -29,54 +33,86 @@ import org.eclipse.core.runtime.ILog; import org.eclipse.core.runtime.ILogListener; import org.eclipse.core.runtime.IStatus; +import org.eclipse.equinox.log.ExtendedLogReaderService; +import org.eclipse.equinox.log.ExtendedLogService; import org.eclipse.jface.preference.PreferenceStore; import org.eclipse.jface.text.Document; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.TextSelection; import org.eclipse.text.edits.TextEdit; +import com.diffplug.spotless.extra.eclipse.base.SpotlessEclipseFramework; + /** Spotless-Formatter step which calls out to the Groovy-Eclipse formatter. */ public class GrEclipseFormatterStepImpl { + /** + * Groovy compiler problems can be ignored. + *

+ * Value is either 'true' or 'false' + *

+ */ + public static final String IGNORE_FORMATTER_PROBLEMS = "ignoreFormatterProblems"; + private final FormatterPreferencesOnStore preferencesStore; + private final boolean ignoreFormatterProblems; public GrEclipseFormatterStepImpl(final Properties properties) throws Exception { + SpotlessLogService logService = new SpotlessLogService(); + if (SpotlessEclipseFramework.setup( + config -> { + config.applyDefault(); + config.add(ExtendedLogService.class, logService); + config.add(ExtendedLogReaderService.class, logService); + }, + plugins -> { + plugins.add(new GroovyCoreActivator()); + })) {} PreferenceStore preferences = createPreferences(properties); preferencesStore = new FormatterPreferencesOnStore(preferences); + ignoreFormatterProblems = Boolean.parseBoolean(properties.getProperty(IGNORE_FORMATTER_PROBLEMS, "false")); } + /** Formatting Groovy string */ public String format(String raw) throws Exception { IDocument doc = new Document(raw); GroovyErrorListener errorListener = new GroovyErrorListener(); TextSelection selectAll = new TextSelection(doc, 0, doc.getLength()); GroovyFormatter codeFormatter = new DefaultGroovyFormatter(selectAll, doc, preferencesStore, false); TextEdit edit = codeFormatter.format(); - if (errorListener.errorsDetected()) { + if (!ignoreFormatterProblems && errorListener.errorsDetected()) { throw new IllegalArgumentException(errorListener.toString()); } edit.apply(doc); return doc.get(); } - private static class GroovyErrorListener implements ILogListener { + /** + * Eclipse Groovy formatter does not signal problems by its return value, but by logging errors. + */ + private static class GroovyErrorListener implements ILogListener, IGroovyLogger { private final List errors; public GroovyErrorListener() { - errors = new LinkedList(); + /* + * We need a synchronized list here, in case multiple instantiations + * run in parallel. + */ + errors = Collections.synchronizedList(new ArrayList()); ILog groovyLogger = GroovyCoreActivator.getDefault().getLog(); groovyLogger.addLogListener(this); + GroovyLogManager.manager.addLogger(this); } @Override public void logging(final IStatus status, final String plugin) { - if (!status.isOK()) { - errors.add(status.getMessage()); - } + errors.add(status.getMessage()); } public boolean errorsDetected() { ILog groovyLogger = GroovyCoreActivator.getDefault().getLog(); groovyLogger.removeLogListener(this); + GroovyLogManager.manager.removeLogger(this); return 0 != errors.size(); } @@ -96,6 +132,22 @@ public String toString() { return string.toString(); } + @Override + public boolean isCategoryEnabled(TraceCategory cat) { + /* + * Note that the compiler errors are just additionally caught here. + * They are also printed directly to System.err. + * See org.codehaus.jdt.groovy.internal.compiler.ast.GroovyCompilationUnitDeclaration.recordProblems + * for details. + */ + return TraceCategory.COMPILER.equals(cat); + } + + @Override + public void log(TraceCategory arg0, String arg1) { + errors.add(arg1); + } + } private static PreferenceStore createPreferences(final Properties properties) throws IOException { diff --git a/_ext/eclipse-groovy/src/main/java/com/diffplug/spotless/extra/eclipse/groovy/SpotlessLogService.java b/_ext/eclipse-groovy/src/main/java/com/diffplug/spotless/extra/eclipse/groovy/SpotlessLogService.java new file mode 100644 index 0000000000..1dc27b09b2 --- /dev/null +++ b/_ext/eclipse-groovy/src/main/java/com/diffplug/spotless/extra/eclipse/groovy/SpotlessLogService.java @@ -0,0 +1,467 @@ +/* + * 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.eclipse.groovy; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.Arrays; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.Optional; +import java.util.Set; + +import org.eclipse.core.internal.runtime.InternalPlatform; +import org.eclipse.equinox.log.ExtendedLogReaderService; +import org.eclipse.equinox.log.ExtendedLogService; +import org.eclipse.equinox.log.LogFilter; +import org.eclipse.equinox.log.Logger; +import org.osgi.framework.Bundle; +import org.osgi.framework.ServiceReference; +import org.osgi.service.log.LogEntry; +import org.osgi.service.log.LogLevel; +import org.osgi.service.log.LogListener; +import org.osgi.service.log.LogService; +import org.osgi.service.log.LoggerConsumer; + +/** + * Simple log service for errors and warnings. + * Unsupported methods are marked as deprecated and throw an {@link UnsupportedOperationException} + */ +public class SpotlessLogService implements ExtendedLogService, ExtendedLogReaderService { + + public final static Set FATAL_SEVERITIES = Collections.unmodifiableSet(new HashSet(Arrays.asList(LogLevel.ERROR, LogLevel.WARN))); + private final Set listener = new HashSet(); + + @Override + @Deprecated + //Backward compatibility with Eclipse OSGI 3.12 + public void log(int level, String message) {} + + @Override + @Deprecated + //Backward compatibility with Eclipse OSGI 3.12 + public void log(int level, String message, Throwable exception) { + log(level, message); + } + + @SuppressWarnings("rawtypes") + @Override + @Deprecated + //Backward compatibility with Eclipse OSGI 3.12 + public void log(ServiceReference sr, int level, String message) { + log(level, message); + } + + @SuppressWarnings("rawtypes") + @Override + @Deprecated + //Backward compatibility with Eclipse OSGI 3.12 + public void log(ServiceReference sr, int level, String message, Throwable exception) { + log(level, message, exception); + } + + @Override + public void log(Object context, int level, String message) { + log(level, message); + } + + @SuppressWarnings("deprecation") ////Backward compatibility with Eclipse OSGI 3.12 + @Override + public void log(Object context, int level, String message, Throwable exception) { + LogLevel logLevel; + switch (level) { + case LogService.LOG_DEBUG: + logLevel = LogLevel.DEBUG; + break; + case LogService.LOG_INFO: + logLevel = LogLevel.INFO; + break; + case LogService.LOG_ERROR: + logLevel = LogLevel.ERROR; + break; + case LogService.LOG_WARNING: + logLevel = LogLevel.WARN; + break; + default: + logLevel = LogLevel.AUDIT; + } + log(new SimpleLogEntry(logLevel, message, exception)); + } + + @Override + public boolean isLoggable(int level) { + return true; + } + + @Override + public String getName() { + return SpotlessLogService.class.getSimpleName(); + } + + @Override + public Logger getLogger(String loggerName) { + return this; + } + + @Override + public Logger getLogger(Bundle bundle, String loggerName) { + return this; + } + + @Override + public void addLogListener(LogListener listener) { + synchronized (this.listener) { + this.listener.add(listener); + } + } + + @Override + public void removeLogListener(LogListener listener) { + synchronized (this.listener) { + this.listener.remove(listener); + } + } + + public void log(LogEntry entry) { + if (FATAL_SEVERITIES.contains(entry.getLogLevel())) { + synchronized (listener) { + if (0 != listener.size()) { + System.err.println(entry.toString()); + listener.stream().forEach(l -> l.logged(entry)); + } + } + } + } + + @Override + @Deprecated + //Backward compatibility with Eclipse OSGI 3.12 + public Enumeration getLog() { + return Collections.emptyEnumeration(); //We do not provide historical information + } + + @Override + public void addLogListener(LogListener listener, LogFilter filter) { + addLogListener(listener); //Listener must filter if required + + } + + @Override + public org.osgi.service.log.Logger getLogger(Class clazz) { + return this; + } + + @Override + @Deprecated + public L getLogger(String name, Class loggerType) { + throw new UnsupportedOperationException("Logger Factory currently not supported."); + } + + @Override + @Deprecated + public L getLogger(Class clazz, Class loggerType) { + return getLogger(getName(), loggerType); + } + + @Override + @Deprecated + public L getLogger(Bundle bundle, String name, Class loggerType) { + return getLogger(getName(), loggerType); + } + + @Override + public boolean isTraceEnabled() { + return false; + } + + @Override + public void trace(String message) { + log(new SimpleLogEntry(LogLevel.TRACE, message)); + } + + @Override + public void trace(String format, Object arg) { + trace(String.format(format, arg)); + } + + @Override + public void trace(String format, Object arg1, Object arg2) { + trace(String.format(format, arg1, arg2)); + } + + @Override + public void trace(String format, Object... arguments) { + trace(String.format(format, arguments)); + } + + @Override + @Deprecated + public void trace(LoggerConsumer consumer) throws E { + throw new UnsupportedOperationException("Logger Consumer currently not supported."); + } + + @Override + public boolean isDebugEnabled() { + return false; + } + + @Override + public void debug(String message) { + log(new SimpleLogEntry(LogLevel.DEBUG, message)); + } + + @Override + public void debug(String format, Object arg) { + debug(String.format(format, arg)); + } + + @Override + public void debug(String format, Object arg1, Object arg2) { + debug(String.format(format, arg1, arg2)); + } + + @Override + public void debug(String format, Object... arguments) { + trace(String.format(format, arguments)); + } + + @Override + @Deprecated + public void debug(LoggerConsumer consumer) throws E { + throw new UnsupportedOperationException("Logger Consumer currently not supported."); + } + + @Override + public boolean isInfoEnabled() { + return false; + } + + @Override + public void info(String message) { + log(new SimpleLogEntry(LogLevel.INFO, message)); + } + + @Override + public void info(String format, Object arg) { + info(String.format(format, arg)); + } + + @Override + public void info(String format, Object arg1, Object arg2) { + info(String.format(format, arg1, arg2)); + } + + @Override + public void info(String format, Object... arguments) { + info(String.format(format, arguments)); + } + + @Override + @Deprecated + public void info(LoggerConsumer consumer) throws E { + throw new UnsupportedOperationException("Logger Consumer currently not supported."); + } + + @Override + public boolean isWarnEnabled() { + return true; + } + + @Override + public void warn(String message) { + log(new SimpleLogEntry(LogLevel.WARN, message)); + } + + @Override + public void warn(String format, Object arg) { + warn(String.format(format, arg)); + } + + @Override + public void warn(String format, Object arg1, Object arg2) { + warn(String.format(format, arg1, arg2)); + } + + @Override + public void warn(String format, Object... arguments) { + warn(String.format(format, arguments)); + } + + @Override + @Deprecated + public void warn(LoggerConsumer consumer) throws E { + throw new UnsupportedOperationException("Logger Consumer currently not supported."); + } + + @Override + public boolean isErrorEnabled() { + return true; + } + + @Override + public void error(String message) { + log(new SimpleLogEntry(LogLevel.ERROR, message)); + } + + @Override + public void error(String format, Object arg) { + error(String.format(format, arg)); + } + + @Override + public void error(String format, Object arg1, Object arg2) { + error(String.format(format, arg1, arg2)); + } + + @Override + public void error(String format, Object... arguments) { + error(String.format(format, arguments)); + } + + @Override + @Deprecated + public void error(LoggerConsumer consumer) throws E { + throw new UnsupportedOperationException("Logger Consumer currently not supported."); + } + + @Override + public void audit(String message) { + log(new SimpleLogEntry(LogLevel.AUDIT, message)); + } + + @Override + public void audit(String format, Object arg) { + audit(String.format(format, arg)); + } + + @Override + public void audit(String format, Object arg1, Object arg2) { + audit(String.format(format, arg1, arg2)); + } + + @Override + public void audit(String format, Object... arguments) { + audit(String.format(format, arguments)); + } + + public static class SimpleLogEntry implements LogEntry { + + private final LogLevel level; + private final String message; + private final Optional execption; + + public SimpleLogEntry(LogLevel level, String message) { + this(level, message, Optional.empty()); + } + + public SimpleLogEntry(LogLevel level, String message, Throwable execption) { + this(level, message, Optional.of(execption)); + } + + private SimpleLogEntry(LogLevel level, String message, Optional execption) { + this.level = level; + this.message = message; + this.execption = execption; + } + + @Override + public Bundle getBundle() { + //Return the spotless framework bundle + return InternalPlatform.getDefault().getBundleContext().getBundle(); + } + + @SuppressWarnings({"rawtypes", "unchecked"}) + @Override + public ServiceReference getServiceReference() { + return null; + } + + @Override + @Deprecated + //Backward compatibility with Eclipse OSGI 3.12 + public int getLevel() { + switch (level) { + case DEBUG: + case TRACE: + return LogService.LOG_DEBUG; + case AUDIT: + case INFO: + return LogService.LOG_INFO; + case ERROR: + return LogService.LOG_ERROR; + case WARN: + return LogService.LOG_WARNING; + } + return LogService.LOG_ERROR; //Don't fail here. Just log it as error. This is anyway just for debugging internal problems. + } + + @Override + public String getMessage() { + return message; + } + + @Override + public Throwable getException() { + return execption.orElse(null); + } + + @Override + public long getTime() { + return 0; + } + + @Override + public String toString() { + StringWriter result = new StringWriter(); + result.write(message); + if (execption.isPresent()) { + result.write('\n'); + result.write(execption.get().toString()); + result.write('\n'); + execption.get().printStackTrace(new PrintWriter(result)); + } + return result.toString(); + } + + @Override + public LogLevel getLogLevel() { + return level; + } + + @Override + public String getLoggerName() { + return this.getClass().getSimpleName(); + } + + @Override + public long getSequence() { + return 0; + } + + @Override + public String getThreadInfo() { + return null; + } + + @Override + public StackTraceElement getLocation() { + return null; + } + + } + +} diff --git a/_ext/eclipse-groovy/src/test/java/com/diffplug/spotless/extra/eclipse/groovy/GrEclipseFormatterStepImplTest.java b/_ext/eclipse-groovy/src/test/java/com/diffplug/spotless/extra/eclipse/groovy/GrEclipseFormatterStepImplTest.java new file mode 100644 index 0000000000..aaf26a8352 --- /dev/null +++ b/_ext/eclipse-groovy/src/test/java/com/diffplug/spotless/extra/eclipse/groovy/GrEclipseFormatterStepImplTest.java @@ -0,0 +1,98 @@ +/* + * 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.eclipse.groovy; + +import static com.diffplug.spotless.extra.eclipse.groovy.GrEclipseFormatterStepImpl.IGNORE_FORMATTER_PROBLEMS; +import static org.codehaus.groovy.eclipse.refactoring.PreferenceConstants.*; +import static org.junit.Assert.assertEquals; + +import java.util.Properties; +import java.util.function.Consumer; + +import org.eclipse.jdt.core.JavaCore; +import org.junit.Test; + +/** Smoke test checking that transitive dependencies are complete. */ +public class GrEclipseFormatterStepImplTest { + + private final static TestData TEST_DATA = TestData.getTestDataOnFileSystem(); + private final static String PARSER_EXCEPTION = "class Test { void method() {} "; + private final static String SCANNER_EXCEPTION = "{"; + private final static String BOUNDED_WILDCARDS = "foo(Map e) {}"; + + @Test + public void defaultFormat() throws Throwable { + String output = format(TEST_DATA.input("nominal.test"), config -> {}); + assertEquals("Unexpected default formatting.", + TEST_DATA.expected("nominal.test"), output); + } + + @Test + public void validConfiguration() throws Throwable { + String output = format(TEST_DATA.input("nominal.test"), config -> { + config.put(GROOVY_FORMATTER_REMOVE_UNNECESSARY_SEMICOLONS, "true"); + }); + assertEquals("Unexpected formatting fro custom configuration.", + TEST_DATA.expected("nominal.test").replace(";", ""), output); + } + + @Test + public void invalidConfiguration() throws Throwable { + String output = format(TEST_DATA.input("nominal.test"), config -> { + config.put(GROOVY_FORMATTER_INDENTATION, JavaCore.SPACE); + config.put(GROOVY_FORMATTER_INDENTATION_SIZE, "noInteger"); + }); + assertEquals("Groovy formatter does not replace invalid preferences by their defaults.", + TEST_DATA.expected("nominal.test").replace("\t", " "), output); + } + + /** Test the handling AntlrParserPlugin exceptions by GroovyLogManager.manager logging */ + @Test(expected = IllegalArgumentException.class) + public void parserException() throws Throwable { + format(PARSER_EXCEPTION, config -> {}); + } + + /** Test the handling GroovyDocumentScanner exceptions by GroovyCore logging */ + @Test(expected = IllegalArgumentException.class) + public void scannerException() throws Throwable { + format(SCANNER_EXCEPTION, config -> {}); + } + + /** Test the handling bounded wildcards templates */ + @Test(expected = IllegalArgumentException.class) + public void boundedWildCards() throws Throwable { + format(BOUNDED_WILDCARDS, config -> {}); + } + + @Test + public void ignoreCompilerProblems() throws Throwable { + Consumer ignoreCompilerProblems = config -> { + config.setProperty(IGNORE_FORMATTER_PROBLEMS, "true"); + }; + format(PARSER_EXCEPTION, ignoreCompilerProblems); + format(SCANNER_EXCEPTION, ignoreCompilerProblems); + format(BOUNDED_WILDCARDS, ignoreCompilerProblems); + //Test is passed if it does not throw an exception. See issue 237. + } + + private static String format(final String input, final Consumer config) throws Exception { + Properties properties = new Properties(); + config.accept(properties); + GrEclipseFormatterStepImpl formatter = new GrEclipseFormatterStepImpl(properties); + return formatter.format(input); + } + +} diff --git a/_ext/eclipse-groovy/src/test/java/com/diffplug/spotless/extra/eclipse/groovy/TestData.java b/_ext/eclipse-groovy/src/test/java/com/diffplug/spotless/extra/eclipse/groovy/TestData.java new file mode 100644 index 0000000000..5fc8bb4571 --- /dev/null +++ b/_ext/eclipse-groovy/src/test/java/com/diffplug/spotless/extra/eclipse/groovy/TestData.java @@ -0,0 +1,82 @@ +/* + * 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.eclipse.groovy; +/* + * 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. + */ + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +public class TestData { + public static TestData getTestDataOnFileSystem() { + final String userDir = System.getProperty("user.dir", "."); + Path dataPath = Paths.get(userDir, "src", "test", "resources"); + if (Files.isDirectory(dataPath)) { + return new TestData(dataPath); + } + return null; + } + + private final Path inputPath; + private final Path expectedPath; + + private TestData(Path dataPath) { + inputPath = dataPath.resolve("input").toAbsolutePath(); + expectedPath = dataPath.resolve("expected").toAbsolutePath(); + for (Path testDataDir : new Path[]{inputPath, expectedPath}) { + if (!Files.isDirectory(testDataDir)) { + throw new IllegalArgumentException(String.format("'%1$s' is not a directory.", testDataDir)); + } + } + } + + public String input(final String fileName) throws Exception { + return read(inputPath.resolve(fileName)); + } + + public String expected(final String fileName) { + Path path = expectedPath.resolve(fileName); + return read(path); + } + + private String read(final Path xmlPath) { + if (!Files.isRegularFile(xmlPath)) { + throw new IllegalArgumentException(String.format("'%1$s' is not a regular file.", xmlPath)); + } + try { + String checkedOutFileContent = new String(java.nio.file.Files.readAllBytes(xmlPath), "UTF8"); + return checkedOutFileContent.replace("\r", ""); //Align GIT end-of-line normalization + } catch (IOException e) { + throw new IllegalArgumentException(String.format("Failed to read '%1$s'.", xmlPath), e); + } + } + +} diff --git a/_ext/eclipse-groovy/src/test/resources/expected/nominal.test b/_ext/eclipse-groovy/src/test/resources/expected/nominal.test new file mode 100644 index 0000000000..a40d247bad --- /dev/null +++ b/_ext/eclipse-groovy/src/test/resources/expected/nominal.test @@ -0,0 +1,13 @@ +class TestClass { + def a; + + TestClass(String s) { + this.a = s + } + def methodNamedArgs(Map args) { + "named args: $args" + } +} + +def t = new TestClass() +def arr = [4, 'string1', 'string2'] diff --git a/_ext/eclipse-groovy/src/test/resources/input/nominal.test b/_ext/eclipse-groovy/src/test/resources/input/nominal.test new file mode 100644 index 0000000000..85f742677f --- /dev/null +++ b/_ext/eclipse-groovy/src/test/resources/input/nominal.test @@ -0,0 +1,15 @@ +class TestClass { + def a; + +TestClass(String s) { +this.a = s +} + def methodNamedArgs(Map args) { + "named args: $args" + } +} + +def t = new TestClass() +def arr = [4, +'string1', +'string2'] diff --git a/_ext/gradle/java-setup.gradle b/_ext/gradle/java-setup.gradle index ea5e5dc1f6..96a56e3d50 100644 --- a/_ext/gradle/java-setup.gradle +++ b/_ext/gradle/java-setup.gradle @@ -14,7 +14,11 @@ apply plugin: 'java' sourceCompatibility = ext_VER_JAVA targetCompatibility = ext_VER_JAVA -tasks.withType(JavaCompile) { options.encoding = 'UTF-8' } +tasks.withType(JavaCompile) { + options.encoding = 'UTF-8' + options.compilerArgs << "-Xlint:unchecked" + options.compilerArgs << "-Xlint:deprecation" +} // Use file locking configurations { diff --git a/_ext/greclipse/README.md b/_ext/greclipse/README.md deleted file mode 100644 index 99c06e21bb..0000000000 --- a/_ext/greclipse/README.md +++ /dev/null @@ -1,41 +0,0 @@ -# spotless-groovy-eclipse - -Groovy-Eclipse is not available in a form which can be easily consumed by maven or gradle. -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-greclipse` artifact. - -## Build - -To publish a new version, update the `_ext/greclipse/gradle.properties` appropriately and run this from the root directory: - -``` -gradlew -b _ext/greclipse/build.gradle publish -``` - -Spotless at large is under the Apache 2.0 license, but this jar is under the EPL v1. - -## IDE - -For IDE support the JAR dependencies and their sources are downloaded from P2 repositories. -This can, due to restrictions on server side, take up to half an hour. - - -### Eclipse - -Run the `eclipse` task: - -``` -gradlew -b _ext/greclipse/build.gradle eclipse -``` - -Import the existing general project (NOT the Gradle project) from `_ext/greclipse` into your workspace. - - -### IntelliJ IDEA - -Run the `idea` task: - -``` -gradlew -b _ext/greclipse/build.gradle idea -``` - -Import the project from `_ext/greclipse` using the external Gradle model. diff --git a/_ext/greclipse/build.gradle b/_ext/greclipse/build.gradle deleted file mode 100644 index 180a7e9d3c..0000000000 --- a/_ext/greclipse/build.gradle +++ /dev/null @@ -1,452 +0,0 @@ -import java.io.File - -import org.apache.commons.io.filefilter.DirectoryFileFilter - -plugins { - // bintray uploading - id 'com.jfrog.bintray' version '1.3.1' - // p2 dependencies - id 'com.diffplug.gradle.p2.asmaven' version '3.3.0' -} - -repositories { - maven { url 'https://plugins.gradle.org/m2/' } -} - -apply plugin: 'java' - -/////////////////// -// Configuration // -/////////////////// - -// The dependencies to pull from GrEclipse's p2 repositories -def grEclipseDeps = [ - 'org.codehaus.groovy.eclipse.refactoring':'+', // GroovyFormatter and related - - // The following lists does not reflect the complete transitive required packages, but - // the once used during code formatting - 'org.codehaus.groovy':'+', // Groovy compiler patches supporting use within GrEclipse and Groovy itself - 'org.codehaus.groovy.eclipse.core':'+', // Groovy core classes (provides central logging used by formatter) - 'org.eclipse.jdt.core':"${grec_VER_JDT_PATCH}", // Patches org.eclipse.jdt.core classes supporting use within GrEclipse (provides AST generator) - 'org.eclipse.jdt.groovy.core':'+' // Extends org.eclipse.jdt.core for Groovy -] - -// The dependencies to pull from Eclipse's p2 repositories -def eclipseDeps = [ - 'org.eclipse.core.commands':'+', // Event manager required by preference store - 'org.eclipse.core.contenttype':'+', // Required by JavaCore options - 'org.eclipse.core.jobs':'+', // Required by JavaCore options - 'org.eclipse.core.runtime':'+', // Provides central logging interface - 'org.eclipse.core.resources':'+', // GrEclipse parser checks workspace resources - 'org.eclipse.equinox.common':'+', // Provides runtime status used during exception reporting - 'org.eclipse.equinox.preferences':'+', // Preferences used for formatter configuration - 'org.eclipse.jface':'+', // PreferenceStore for creating preferences from properties - 'org.eclipse.jface.text':'+', // Only required for ITextSelection (never used for our calls) - 'org.eclipse.osgi':'+', // GroovyCore accesses OSGI bundle (but not effectively used) - 'org.eclipse.text':'+' // Provides Document data structure for formatter -] - -ext { - //Include/Excludes form the JARs, which goes into a fat-jar with the spottless formatter interface. - jarInclude = [ - '**/*.class', // Take all classes - '**/*.java', // ... and sources. - '**/*.properties', // Text resources (for messages, etc) - '*.html', // License information about the included JARs, - 'META-INF/**' // Information about the origin of the individual class files - ] - jarExclude = [ - 'META-INF/*.RSA', // The eclipse jars are signed, and our fat-jar breaks the signatures - 'META-INF/*.SF', // ... so all signatures are filtered - 'org/codehaus/groovy/eclipse/core/GroovyCoreActivator.*', // Is replaced to use the plugin code without Eclipse - 'org/codehaus/groovy/antlr/ErrorRecoveredCSTParserPluginFactory.*' // Is replaced to allow parser error handling - ] - - //Some JARs include JARs themselfs - internalJars = [ - //Jars included by org.codehaus.groovy - "**/groovy-all-${grec_VER_GROOVY}", // Use Groovy compiler compatible with GrEclipse instead of localGroovy - "**/groovy-${grec_VER_GROOVY}", // Groovy compiler sources do not follow the same name pattern of groovy-all - '**/groovy-eclipse', // Patches/Overrides some of the Groovy compiler classes - '**/eclipse-trace', // Provides logging capabilities for groovy-eclipse - - //Jars included by org.eclipse.jdt.groovy.core - '**/nlcl' //Non locking class loader used by groovy compiler - ] - - // GrEclipse source bundle (not available as dedicated source JARs) - grEclipseSourceUrl = "https://github.com/groovy/groovy-eclipse/archive/v${grec_VER_GRECLIPSE}.tar.gz" - grEclipseSourceTgz = project.file("build/greclipse-archive/v${grec_VER_GRECLIPSE}.tar.gz") - grEclipseSourceDir = project.file('build/greclipse-archive/grEclipseSource') - // Sources of GrEclipse dependencies for... - verGroovySource = grec_VER_GROOVY.substring(0, grec_VER_GROOVY.lastIndexOf('.')).replace('.', '') - grEclipseDepsSource = [ - "base/org.codehaus.groovy${verGroovySource}/src", // org.codehaus.groovy unit - "base/org.codehaus.groovy${verGroovySource}/src-trace", // eclipse-trace internal JAR - 'base/org.eclipse.jdt.groovy.core/src', // org.eclipse.jdt.groovy.core unit - 'ide/org.codehaus.groovy.eclipse.core/src', // org.codehaus.groovy.eclipse.core unit - 'ide/org.codehaus.groovy.eclipse.refactoring/src', // org.codehaus.groovy.eclipse.refactoring unit - ] - //The jdt-patch is organised in sub-modules patching existing code - jdtPatchDepsSourceDir = new File("${grEclipseSourceDir}/jdt-patch/e${grec_VER_ECLIPSE.replace('.', '')}/org.eclipse.jdt.core") - - // The directory contains all external classes for the fat-jar - embeddedClassesDirName = 'build/embeddedClasses' - embeddedClassesDir = project.file(embeddedClassesDirName) - - // The directory contains all external source files the fat-jar is based on - embeddedSourcesDirName = 'build/embeddedSources' - embeddedSourcesDir = project.file(embeddedSourcesDirName) - -} - -// build a maven repo in our build folder containing these artifacts -p2AsMaven { - group 'p2', { - repoEclipse grec_VER_ECLIPSE - eclipseDeps.keySet.each { p2.addIU(it) } - eclipseDeps.keySet.each { p2.addIU(it + '.source') } - repo "http://dist.springsource.org/release/GRECLIPSE/${grec_VER_GRECLIPSE}/e${grec_VER_ECLIPSE}" - grEclipseDeps.keySet.each { p2.addIU(it) } - } -} - -configurations { - embeddedJars // JARs (Eclipse and GrEclipse) the fat-jar is based uppon - eclipseSource // Source for Eclipse JARS (GrEclipse provides no source packages) -} - -/////////////////// -// External Deps // -/////////////////// - -task grEclipseSource { - description = 'Download GrEclipse from GitHub archive.' - inputs.property('url', grEclipseSourceUrl.toString()) - outputs.file(grEclipseSourceDir) - - doLast { - grEclipseSourceDir.deleteDir() - grEclipseSourceDir.mkdirs() - ant.get(src: grEclipseSourceUrl, dest: grEclipseSourceTgz, skipexisting: 'true') - ant.untar(src: grEclipseSourceTgz, dest: grEclipseSourceDir, compression: 'gzip') { - cutdirsmapper(dirs: '1') - } - } -} - -task copyEmbeddedSources(dependsOn: grEclipseSource) { - description = "Copies filtered set of source files from the Eclise/GrEclipse dependencies to '${project.relativePath(embeddedSourcesDir)}'." - inputs.files(configurations.eclipseSource) - inputs.file(grEclipseSourceDir) - inputs.property('internalJars', internalJars) - inputs.property('jarInclude', jarInclude) - inputs.property('jarExclude', jarExclude) - outputs.file(embeddedSourcesDir) - - doLast { - embeddedSourcesDir.deleteDir() - embeddedSourcesDir.mkdirs() - configurations.eclipseSource.each { - unjar(it, embeddedSourcesDir) - } - - // Incorparate the Eclipse patches/extensions into default source directory structure - copy("${embeddedSourcesDir}/ant_tasks/resources-antsrc", embeddedSourcesDir, 'move') - - // Extract source JARs provided with GrEcslipse (for exampel the compiler) - def jarSourceIncludes = [] - internalJars.each { - def jarFilter = it - ['sources', 'source', 'src'].each { - jarSourceIncludes << "${jarFilter}-${it}.jar" - } - } - def tree = fileTree(dir: grEclipseSourceDir, includes: jarSourceIncludes) - tree.each { - unjar(it, embeddedSourcesDir) - } - - grEclipseDepsSource.each { - copy("${grEclipseSourceDir}/${it}", embeddedSourcesDir) - } - //The jdt-patch is organised in sub-modules patching existing code - jdtPatchDepsSourceDir.list(DirectoryFileFilter.DIRECTORY).each { - copy("${jdtPatchDepsSourceDir}/${it}", embeddedSourcesDir) - } - - //Clean up empty directories and class files - ant.delete(includeemptydirs: 'true') { - fileset(dir: embeddedSourcesDir) { - or { - and { - size(value: '0') - type(type: 'dir') - } - filename(name: '**/*.class') - filename(name: '*.java') - } - } - } - } - -} - -def copy(fromDir, toDir, method='copy') { - logger.debug("${method} ${fromDir} to ${toDir}") - ant."$method"(todir: toDir, includeEmptyDirs: 'false', overwrite: 'true') { - fileset(dir: fromDir) { - jarInclude.each { - include(name: "${it}") - } - jarExclude.each { - exclude(name: "${it}") - } - } - } -} - -task unjarEmbeddedClasses { - description = "Copies filtered set of embedded classes from the Eclise/GrEclipse dependencies to '${project.relativePath(embeddedClassesDir)}'." - inputs.files(configurations.embeddedJars) - inputs.property('internalJars', internalJars) - inputs.property('jarInclude', jarInclude) - inputs.property('jarExclude', jarExclude) - outputs.file(embeddedClassesDir) - - doLast { - embeddedClassesDir.deleteDir() - embeddedClassesDir.mkdirs() - configurations.embeddedJars.each { - unjar(it, embeddedClassesDir) - } - //Unpack internal JARs. Maintain the order defined in internalJars - internalJars.each { - fileTree(embeddedClassesDir).include("${it}.jar").each { - unjar(it, embeddedClassesDir) - delete(it) - } - } - } -} - -def unjar(File jarFile, File destDir) { - ant.unjar(src: jarFile, dest: destDir) { - patternset { - jarInclude.each { - include(name: "${it}") - } - internalJars.each { - include(name: "**/${it}.jar") - } - jarExclude.each { - exclude(name: "${it}") - } - } - } - //Keep the manifest for transparency - ant.move(file: "${destDir}/META-INF/MANIFEST.MF", tofile: "${destDir}/META-INF/${jarFile.getName()}-MANIFEST.MF", quiet: 'true', failonerror: 'false') - //Keep licenses and other human readable information for transparency - ant.move(todir: destDir, quiet: 'true') { - fileset(dir: destDir) { - include(name: '*') - type(type: 'file') - exclude(name: '*jar-*') - exclude(name: '*.jar') - } - mapper(type: 'glob', from: '*', to: "${jarFile.getName()}-*") - } -} - - -///////////// -// Compile // -///////////// - -dependencies { - // Add the Eclipse and GrEclipse jars to the embedded configuration. - eclipseDeps.each { groupArtifact, version -> - embeddedJars "p2:${groupArtifact}:${version}" - eclipseSource "p2:${groupArtifact}:${version}:sources" - } - // Some grEclipseDeps classes patch/override the eclipseDeps once. Hence grEclipseDeps - // must added to embeddedJars after eclipseDeps. - grEclipseDeps.each { groupArtifact, version -> - embeddedJars "p2:${groupArtifact}:${version}" - } - - // The resulting fat-jar will have no transitive dependencies itself. - compile files(embeddedClassesDir) - - // testing - testCompile "junit:junit:${grec_VER_JUNIT}" -} - -tasks.compileJava.dependsOn(unjarEmbeddedClasses) - - -///////// -// IDE // -///////// - -apply plugin: 'eclipse' - -eclipse { - classpath { - downloadSources true - downloadJavadoc true - file { - withXml { xmlProvider -> - def classpathNode = xmlProvider.asNode() - def embeddedClassesPath = embeddedClassesDir.absolutePath - def embeddedNode = classpathNode.find { it.@path == embeddedClassesPath } - embeddedNode.@sourcepath = embeddedSourcesDir - } - } - } -} - -// always create fresh projects -tasks.eclipse.dependsOn(cleanEclipse) -// Encure that the dependent classes and sources are preovided for compilation if project is build via Eclipse instead of command line -tasks.eclipseClasspath.dependsOn(unjarEmbeddedClasses, copyEmbeddedSources) - -apply plugin: 'idea' - -// Encure that the dependent classes and sources are preovided for compilation if project is build via Eclipse instead of command line -tasks.idea.dependsOn(unjarEmbeddedClasses, copyEmbeddedSources) - - -tasks.idea.doLast { - def ideaEmbeddedLibTableFile = project.file('.idea/libraries/embeddedClasses.xml') - def ideaEmbeddedLibTableDir = ideaEmbeddedLibTableFile.parentFile - ideaEmbeddedLibTableDir.parentFile.mkdir() - ideaEmbeddedLibTableDir.mkdir() - ideaEmbeddedLibTableFile.delete() - ideaEmbeddedLibTableFile << """ - - - - - - - - - - - - """ -} - -//////////////// -// Publishing // -//////////////// -apply plugin: 'maven-publish' - -jar { - dependsOn << unjarEmbeddedClasses - from (embeddedClassesDir) -} - -task sourcesJar(type: Jar, dependsOn: copyEmbeddedSources) { - classifier = 'sources' - from ([sourceSets.main.allJava, embeddedSourcesDir]) -} - -task javadocJar(type: Jar, dependsOn: javadoc) { - classifier = 'javadoc' - from javadoc.destinationDir -} - -def isSnapshot = grec_version.endsWith('-SNAPSHOT') -// pulls the credentials from either the environment variable or gradle.properties -def cred = { - if (System.env[it] != null) { - return System.env[it] - } else if (project.hasProperty(it)) { - return project[it] - } else { - return 'unknown_' + it - } -} - -model { - publishing { - publications { - mavenJava(MavenPublication) { - artifact jar - artifact sourcesJar - artifact javadocJar - - groupId project.grec_group - artifactId project.grec_artifactId - version project.grec_version - - pom.withXml { - - // add MavenCentral requirements to the POM - asNode().children().last() + { - resolveStrategy = Closure.DELEGATE_FIRST - name project.grec_artifactId - description project.grec_description - url "https://github.com/${project.grec_org}/${project.name}" - scm { - url "https://github.com/${project.grec_org}/${project.name}" - connection "scm:git:git://github.com/${project.grec_org}/${project.name}" - developerConnection "scm:git:ssh:git@github.com/${project.grec_org}/${project.name}" - } - licenses { - license { - name 'Eclipse Public License - v 1.0' - url 'https://www.eclipse.org/legal/epl-v10.html' - distribution 'repo' - } - } - developers { - developer { - id 'fvgh' - name 'Frank Vennemeyer' - email 'frankgh@zoho.com' - } - } - } - } - } - } - if (isSnapshot) { - // upload snapshots to oss.sonatype.org - repositories { maven { - url = 'https://oss.sonatype.org/content/repositories/snapshots' - credentials { - username = cred('nexus_user') - password = cred('nexus_pass') - } - } } - } - } -} - -if (!isSnapshot) { - // upload releases to bintray and then mavenCentral - bintray { - user = cred('bintray_user') - key = cred('bintray_pass') - publications = ['mavenJava'] - publish = true - pkg { - repo = 'opensource' - name = project.grec_artifactId - userOrg = project.grec_org - version { - name = project.grec_version - mavenCentralSync { - user = cred('nexus_user') - password = cred('nexus_pass') - } - } - } - } - - publish.dependsOn(bintrayUpload) - bintrayUpload.dependsOn(['generatePomFileForMavenJavaPublication', jar, sourcesJar, javadocJar]) -} diff --git a/_ext/greclipse/gradle.properties b/_ext/greclipse/gradle.properties deleted file mode 100644 index dbffb524cd..0000000000 --- a/_ext/greclipse/gradle.properties +++ /dev/null @@ -1,17 +0,0 @@ -# Mayor/Minor versions are in line with the Groovy version values. -# Patch version is an incremental counter for the Spotless plugin. -grec_version=2.3.0 -grec_artifactId=spotless-ext-greclipse -grec_description=Groovy Eclipse's formatter bundled for Spotless - -grec_org=diffplug -grec_group=com.diffplug.spotless - -# Compile -grec_VER_ECLIPSE=4.4 -grec_VER_GRECLIPSE=2.9.1 -grec_VER_GROOVY=2.3.7 -grec_VER_JDT_PATCH=3.10.0.xx-201411061335-e44-RELEASE - -# Test -grec_VER_JUNIT=4.12 diff --git a/_ext/greclipse/src/main/java/org/codehaus/groovy/antlr/ErrorRecoveredCSTParserPluginFactory.java b/_ext/greclipse/src/main/java/org/codehaus/groovy/antlr/ErrorRecoveredCSTParserPluginFactory.java deleted file mode 100644 index d26283015d..0000000000 --- a/_ext/greclipse/src/main/java/org/codehaus/groovy/antlr/ErrorRecoveredCSTParserPluginFactory.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * 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 org.codehaus.groovy.antlr; - -import java.util.List; - -import org.codehaus.groovy.control.ParserPlugin; -import org.codehaus.groovy.control.ParserPluginFactory; -import org.codehaus.groovy.eclipse.core.GroovyCoreActivator; -import org.eclipse.core.runtime.ILog; -import org.eclipse.core.runtime.Status; - -/** - * Overrides original class allowing spotless formatter to handle parser errors. - *

- * Compiler Parser errors in GrEclipse are treated as warnings, directed to the "standard" - * error output stream, if less than 'groovy.errors.tolerance' are detected. - * The 'groovy.errors.tolerance' is set to the fixed value 10 by the GrEclipse patch of - * the original codehaus groovy, which is convenient within Eclipse editor on 'unfinished' code. - * For Spotless is can be assumed that the plugin is applied after successful compilation. - * Hence for all compiler errors, it can be assumed that the eclipse-groovy parser is not - * able to cope with the code and therefore should not alter it. - * Furthermore, in the default GrEclipse warnings, the source file name is replaced by - * "Hello.groovy" (see GroovySnippetParser), which is not helpful for a spotless error report. - *

- * This patch is used as the least intrusive work-around. - */ -public class ErrorRecoveredCSTParserPluginFactory extends ParserPluginFactory { - - @Override - public ParserPlugin createParserPlugin() { - return new ErrorRecoveredCSTParserPlugin(new SpotlessCstReporter()); - } - - private static class SpotlessCstReporter implements ICSTReporter { - - @Override - public void generatedCST(String fileName, GroovySourceAST ast) { - //Always called when an AST has been generated. Nothing to do. - } - - @Override - public void reportErrors(String fileName, @SuppressWarnings("rawtypes") List errors) { - ILog log = GroovyCoreActivator.getDefault().getLog(); - for (Object error : errors) { - log.log(new Status(Status.ERROR, GroovyCoreActivator.PLUGIN_ID, error.toString())); - } - } - - }; -} diff --git a/_ext/greclipse/src/main/java/org/codehaus/groovy/eclipse/core/GroovyCoreActivator.java b/_ext/greclipse/src/main/java/org/codehaus/groovy/eclipse/core/GroovyCoreActivator.java deleted file mode 100644 index 4a54531748..0000000000 --- a/_ext/greclipse/src/main/java/org/codehaus/groovy/eclipse/core/GroovyCoreActivator.java +++ /dev/null @@ -1,273 +0,0 @@ -/* - * 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 org.codehaus.groovy.eclipse.core; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.net.URL; -import java.security.cert.X509Certificate; -import java.util.Arrays; -import java.util.Dictionary; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.codehaus.groovy.eclipse.GroovyLogManager; -import org.eclipse.core.runtime.ILog; -import org.eclipse.core.runtime.ILogListener; -import org.eclipse.core.runtime.IStatus; -import org.osgi.framework.Bundle; -import org.osgi.framework.BundleContext; -import org.osgi.framework.BundleException; -import org.osgi.framework.ServiceReference; -import org.osgi.framework.Version; - -/** - * Overrides original class allowing Spotless to run formatter without activating Eclipse core. - *

- * Class provides access to central logger as required by GroovyCore. - * Furthermore GroovyCore requires a OSGI bundle, which is just used for accessing the plug-in id. - * This class provides a corresponding mock for the bundle. - */ -public class GroovyCoreActivator { - - public static final String PLUGIN_ID = "com.diffplug.gradle.spotless.groovy.eclipse"; - - private static GroovyCoreActivator INSTANCE = null; - - private final ILog logger; - private final Bundle bundle; - - public GroovyCoreActivator() { - bundle = new MockOsgiBundle(); - logger = new LogAdapter(bundle); - GroovyLogManager.manager.setUseDefaultLogger(false); - } - - /** Lazy constructor returning the shared activator instance */ - public static GroovyCoreActivator getDefault() { - if (null == INSTANCE) { - INSTANCE = new GroovyCoreActivator(); - } - return INSTANCE; - } - - /** Returns a OSIG bundle mock for GroovyCore, just providing functionality for Groovy error handling */ - public Bundle getBundle() { - return bundle; - } - - /** Provides Eclipse logger interface without requiring an active Eclipse core */ - public ILog getLog() { - return logger; - } - - private static class LogAdapter implements ILog { - - private final static Integer[] QUIET_SEVERITY_VALUES = new Integer[]{IStatus.CANCEL, IStatus.INFO, IStatus.OK}; - private final static Set QUIET_SEVERITIES = new HashSet(Arrays.asList(QUIET_SEVERITY_VALUES)); - - private final Set listeners; - private final Bundle bundle; - - public LogAdapter(Bundle bundle) { - listeners = new HashSet(); - this.bundle = bundle; - } - - @Override - public void addLogListener(ILogListener arg0) { - listeners.add(arg0); - } - - @Override - public Bundle getBundle() { - return bundle; - } - - @Override - public void log(IStatus status) { - for (ILogListener listener : listeners) { - listener.logging(status, PLUGIN_ID); - } - if (QUIET_SEVERITIES.contains(status.getSeverity())) { - System.out.println(status.getMessage()); - } else { - System.err.println(status.getMessage()); - } - } - - @Override - public void removeLogListener(ILogListener arg0) { - listeners.remove(arg0); - } - - } - - private static class MockOsgiBundle implements Bundle { - - @Override - public int compareTo(Bundle arg0) { - return 0; //Always equal. There is only one bundle - } - - @Override - public A adapt(Class arg0) { - throw new UnsupportedOperationException(); - } - - @Override - public Enumeration findEntries(String arg0, String arg1, boolean arg2) { - throw new UnsupportedOperationException(); - } - - @Override - public BundleContext getBundleContext() { - throw new UnsupportedOperationException(); - } - - @Override - public long getBundleId() { - return 0; - } - - @Override - public File getDataFile(String arg0) { - throw new UnsupportedOperationException(); - } - - @Override - public URL getEntry(String arg0) { - throw new UnsupportedOperationException(); - } - - @Override - public Enumeration getEntryPaths(String arg0) { - throw new UnsupportedOperationException(); - } - - @Override - public Dictionary getHeaders() { - throw new UnsupportedOperationException(); - } - - @Override - public Dictionary getHeaders(String arg0) { - throw new UnsupportedOperationException(); - } - - @Override - public long getLastModified() { - return 0; //No modifications - } - - @Override - public String getLocation() { - return PLUGIN_ID; - } - - @Override - public ServiceReference[] getRegisteredServices() { - return new ServiceReference[0]; - } - - @Override - public URL getResource(String arg0) { - throw new UnsupportedOperationException(); - } - - @Override - public Enumeration getResources(String arg0) throws IOException { - throw new UnsupportedOperationException(); - } - - @Override - public ServiceReference[] getServicesInUse() { - return new ServiceReference[0]; - } - - @Override - public Map> getSignerCertificates(int arg0) { - return new HashMap>(); - } - - @Override - public int getState() { - return Bundle.ACTIVE; - } - - @Override - public String getSymbolicName() { - return PLUGIN_ID; - } - - @Override - public Version getVersion() { - return new Version(0, 0, 0); - } - - @Override - public boolean hasPermission(Object arg0) { - return true; - } - - @Override - public Class loadClass(String arg0) throws ClassNotFoundException { - throw new UnsupportedOperationException(); - } - - @Override - public void start() throws BundleException { - //Nothing to do - } - - @Override - public void start(int arg0) throws BundleException { - //Nothing to do - } - - @Override - public void stop() throws BundleException { - //Nothing to do - } - - @Override - public void stop(int arg0) throws BundleException { - //Nothing to do - } - - @Override - public void uninstall() throws BundleException { - //Nothing to do - } - - @Override - public void update() throws BundleException { - //Nothing to do - } - - @Override - public void update(InputStream arg0) throws BundleException { - //Nothing to do - } - - } - -} diff --git a/_ext/greclipse/src/test/java/com/diffplug/gradle/spotless/groovy/eclipse/GrEclipseFormatterStepImplTest.java b/_ext/greclipse/src/test/java/com/diffplug/gradle/spotless/groovy/eclipse/GrEclipseFormatterStepImplTest.java deleted file mode 100644 index c60605fc74..0000000000 --- a/_ext/greclipse/src/test/java/com/diffplug/gradle/spotless/groovy/eclipse/GrEclipseFormatterStepImplTest.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * 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.gradle.spotless.groovy.eclipse; - -import static org.junit.Assert.assertTrue; - -import java.util.Properties; - -import org.junit.BeforeClass; -import org.junit.Test; - -/** Smoke test checking that transitive dependencies are complete. */ -public class GrEclipseFormatterStepImplTest { - - private final static String INPUT = "class Test { void method() {} }"; - private final static String OUTPUT = "class Test {\n\tvoid method() {}\n}"; - private final static String PARSER_EXCEPTION = "class Test { void method() {} "; - private final static String SCANNER_EXCEPTION = "{"; - private static GrEclipseFormatterStepImpl FORMATTER = null; - - @BeforeClass - public static void initializeTestData() throws Exception { - FORMATTER = new GrEclipseFormatterStepImpl(new Properties()); - } - - /** - * Test nominal scenario - * @throws Throwable No exception is expected - */ - @Test - public void formatDefault() throws Throwable { - String output = FORMATTER.format(INPUT); - assertTrue(output.equals(OUTPUT)); - } - - /** - * Test the handling AntlrParserPlugin exceptions by SpotlessCstReporter logging - * @throws Throwable IllegalArgumentException is expected - */ - @Test(expected = IllegalArgumentException.class) - public void parserException() throws Throwable { - FORMATTER.format(PARSER_EXCEPTION); - } - - /** - * Test the handling GroovyDocumentScanner exceptions by GroovyCore logging - * @throws Throwable IllegalArgumentException is expected - */ - @Test(expected = IllegalArgumentException.class) - public void scannerException() throws Throwable { - FORMATTER.format(SCANNER_EXCEPTION); - } - -}