diff --git a/_ext/eclipse-jdt/README.md b/_ext/eclipse-jdt/README.md index 63849966da..0657924bb0 100644 --- a/_ext/eclipse-jdt/README.md +++ b/_ext/eclipse-jdt/README.md @@ -1,6 +1,8 @@ -# spotless-eclipse +# spotless-eclipse-jdt -Eclipse is not available in a form which can be easily consumed by maven or gradle. To fix this, we publish Eclipse's formatter and all its dependencies, along with a small amount of glue code, into the `com.diffplug.gradle.spotless:spotless-eclipse` artifact. +Eclipse JDT and its dependencies require a large amount of byte code. +Hence they should not be directly be required by the Spotless, but only be requested in case +they are configured by the Spotless configuration. Hence we publish Eclipse's formatter and all its dependencies, along with a small amount of glue code, into the `com.diffplug.gradle.spotless:spotless-eclipse-jdt` artifact. To publish a new version, update the `_ext/eclipse-jdt/gradle.properties` appropriately and run this from the root directory: diff --git a/_ext/eclipse-jdt/build.gradle b/_ext/eclipse-jdt/build.gradle index 992594c240..e079a42c41 100644 --- a/_ext/eclipse-jdt/build.gradle +++ b/_ext/eclipse-jdt/build.gradle @@ -1,180 +1,18 @@ -plugins { - // bintray uploading - id 'com.jfrog.bintray' version '1.3.1' - // p2 dependencies - id 'com.diffplug.gradle.p2.asmaven' version '3.9.0' -} - -apply plugin: 'java' - -// The dependencies we'd like to pull from Eclipse's p2 repositories -def eclipseDeps = [ - // The dependencies we actually use - 'org.eclipse.jdt.core', - 'org.eclipse.text', - - // Their transitives - 'org.eclipse.core.contenttype', - 'org.eclipse.core.jobs', - 'org.eclipse.core.runtime', - 'org.eclipse.core.resources', - 'org.eclipse.equinox.common', - 'org.eclipse.equinox.preferences', - 'org.eclipse.osgi' -] -// build a maven repo in our build folder containing these artifacts -p2AsMaven { - group 'p2', { - repoEclipse jdt_VER_ECLIPSE - eclipseDeps.each { p2.addIU(it) } - eclipseDeps.each { p2.addIU(it + '.source') } - } -} +apply from: rootProject.file('../gradle/java-setup.gradle') +apply from: rootProject.file('../gradle/java-publish.gradle') -configurations { - embeddedJars // we will embed these into the binary artifact - compile.extendsFrom(embeddedJars) +ext { + developers = [ + fvgh: [ name: 'Frank Vennemeyer', email: 'frankgh@zoho.com' ], + nedtwigg: [ name: 'Ned Twigg', email: 'ned.twigg@diffplug.com' ], + ] } dependencies { - // add the eclipse jars to the embedded configuration - eclipseDeps.each { embeddedJars "p2:${it}:+" } -} - -jar { - // this embeds the eclipse jars into our "fat jar" - from { - configurations.embeddedJars.collect{ it.isDirectory() ? it : zipTree(it) } + compile "com.diffplug.spotless:spotless-eclipse-base:${VER_SPOTLESS_ECLISPE_BASE}" + compile("org.eclipse.jdt:org.eclipse.jdt.core:${VER_ECLIPSE_JDT_CORE}") { + exclude group: 'org.eclipse.platform', module: 'org.eclipse.ant.core' + exclude group: 'org.eclipse.platform', module: 'org.eclipse.core.expressions' + exclude group: 'org.eclipse.platform', module: 'org.eclipse.core.filesystem' } - // the eclipse jars are signed, and our fat jar breaks the signatures - // so we've gotta be sure to filter out the signatures - exclude 'META-INF/*.RSA' - exclude 'META-INF/*.SF' -} - -apply plugin: 'eclipse' -eclipse { - classpath { - downloadSources true - downloadJavadoc true - } -} -// always create fresh projects -tasks.eclipse.dependsOn(cleanEclipse) - -/////////// -// MAVEN // -/////////// -apply plugin: 'maven-publish' - -task sourcesJar(type: Jar) { - classifier = 'sources' - from sourceSets.main.allJava -} - -task javadocJar(type: Jar, dependsOn: javadoc) { - classifier = 'javadoc' - from javadoc.destinationDir -} - -//////////////// -// PUBLISHING // -//////////////// -def isSnapshot = project.jdt_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.jdt_group - artifactId project.jdt_artifactId - version project.jdt_version - - pom.withXml { - // remove the p2 dependencies because they are embedded - // also remove 'com.diffplug' dependencies so that we can use spotless on its dependencies - asNode().dependencies.'*'.each() { - if (it.groupId.text() == 'p2') { - it.parent().remove(it) - } - } - // add MavenCentral requirements to the POM - asNode().children().last() + { - resolveStrategy = Closure.DELEGATE_FIRST - name project.jdt_artifactId - description project.jdt_description - url "https://github.com/${project.jdt_org}/${project.name}" - scm { - url "https://github.com/${project.jdt_org}/${project.name}" - connection "scm:git:git://github.com/${project.jdt_org}/${project.name}" - developerConnection "scm:git:ssh:git@github.com/${project.jdt_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 'nedtwigg' - name 'Ned Twigg' - email 'ned.twigg@diffplug.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.jdt_artifactId - userOrg = project.jdt_org - version { - name = project.jdt_version - mavenCentralSync { - user = cred('nexus_user') - password = cred('nexus_pass') - } - } - } - } - - publish.dependsOn(bintrayUpload) - bintrayUpload.dependsOn(['generatePomFileForMavenJavaPublication', jar, sourcesJar, javadocJar]) -} +} \ No newline at end of file diff --git a/_ext/eclipse-jdt/gradle.properties b/_ext/eclipse-jdt/gradle.properties index 87bf8bc434..3b035ebd6b 100644 --- a/_ext/eclipse-jdt/gradle.properties +++ b/_ext/eclipse-jdt/gradle.properties @@ -1,13 +1,15 @@ -# jdt_ to ensure gradle.properties in project root doesn't clobber -jdt_version=4.7.2 -jdt_artifactId=spotless-ext-eclipse-jdt -jdt_description=Eclipse's formatter bundled for Spotless +# Mayor/Minor versions correspond to the minimum Eclipse version supported/tested. +# Patch version is incremented for backward compatible patches of this library. +ext_version=4.8.0 +ext_artifactId=spotless-eclipse-jdt +ext_description=Eclipse's JDT formatter bundled for Spotless -jdt_org=diffplug -jdt_group=com.diffplug.spotless +ext_org=diffplug +ext_group=com.diffplug.spotless # Build requirements -jdt_VER_JAVA=1.8 +ext_VER_JAVA=1.8 # Compile -jdt_VER_ECLIPSE=4.7.2 +VER_ECLIPSE_JDT_CORE=[3.12.0,4.0.0[ +VER_SPOTLESS_ECLISPE_BASE=[3.0.0,4.0.0[ diff --git a/_ext/eclipse-jdt/src/main/java/com/diffplug/gradle/spotless/java/eclipse/EclipseFormatterStepImpl.java b/_ext/eclipse-jdt/src/main/java/com/diffplug/spotless/extra/eclipse/java/EclipseJdtFormatterStepImpl.java similarity index 72% rename from _ext/eclipse-jdt/src/main/java/com/diffplug/gradle/spotless/java/eclipse/EclipseFormatterStepImpl.java rename to _ext/eclipse-jdt/src/main/java/com/diffplug/spotless/extra/eclipse/java/EclipseJdtFormatterStepImpl.java index 61d447254b..932a41d0ce 100644 --- a/_ext/eclipse-jdt/src/main/java/com/diffplug/gradle/spotless/java/eclipse/EclipseFormatterStepImpl.java +++ b/_ext/eclipse-jdt/src/main/java/com/diffplug/spotless/extra/eclipse/java/EclipseJdtFormatterStepImpl.java @@ -13,29 +13,35 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.diffplug.gradle.spotless.java.eclipse; +package com.diffplug.spotless.extra.eclipse.java; import java.util.Properties; +import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.ToolFactory; import org.eclipse.jdt.core.formatter.CodeFormatter; import org.eclipse.jface.text.Document; import org.eclipse.jface.text.IDocument; import org.eclipse.text.edits.TextEdit; -/** Formatter step which calls out to the Eclipse formatter. */ -public class EclipseFormatterStepImpl { +import com.diffplug.spotless.extra.eclipse.base.SpotlessEclipseFramework; + +/** Formatter step which calls out to the Eclipse JDT formatter. */ +public class EclipseJdtFormatterStepImpl { private final CodeFormatter codeFormatter; - public EclipseFormatterStepImpl(Properties settings) { + public EclipseJdtFormatterStepImpl(Properties settings) throws Exception { + SpotlessEclipseFramework.setup( + plugins -> { + plugins.applyDefault(); + plugins.add(new JavaCore()); + }); this.codeFormatter = ToolFactory.createCodeFormatter(settings, ToolFactory.M_FORMAT_EXISTING); } - private static final String UNIX = "\n"; - public String format(String raw) throws Exception { - TextEdit edit = codeFormatter.format(CodeFormatter.K_COMPILATION_UNIT | CodeFormatter.F_INCLUDE_COMMENTS, raw, 0, raw.length(), 0, UNIX); + TextEdit edit = codeFormatter.format(CodeFormatter.K_COMPILATION_UNIT | CodeFormatter.F_INCLUDE_COMMENTS, raw, 0, raw.length(), 0, SpotlessEclipseFramework.LINE_DELIMITER); if (edit == null) { throw new IllegalArgumentException("Invalid java syntax for formatting."); } else { @@ -44,4 +50,5 @@ public String format(String raw) throws Exception { return doc.get(); } } + } diff --git a/_ext/eclipse-jdt/src/main/java/com/diffplug/spotless/extra/eclipse/java/package-info.java b/_ext/eclipse-jdt/src/main/java/com/diffplug/spotless/extra/eclipse/java/package-info.java new file mode 100644 index 0000000000..190557cc74 --- /dev/null +++ b/_ext/eclipse-jdt/src/main/java/com/diffplug/spotless/extra/eclipse/java/package-info.java @@ -0,0 +1,20 @@ +/* + * 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. + */ +/** Eclipse JDT based Spotless formatter */ +@ParametersAreNonnullByDefault +package com.diffplug.spotless.extra.eclipse.java; + +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/_ext/eclipse-jdt/src/test/java/com/diffplug/spotless/extra/eclipse/java/EclipseJdtFormatterStepImplTest.java b/_ext/eclipse-jdt/src/test/java/com/diffplug/spotless/extra/eclipse/java/EclipseJdtFormatterStepImplTest.java new file mode 100644 index 0000000000..d7105539a7 --- /dev/null +++ b/_ext/eclipse-jdt/src/test/java/com/diffplug/spotless/extra/eclipse/java/EclipseJdtFormatterStepImplTest.java @@ -0,0 +1,97 @@ +/* + * 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.java; + +import static com.diffplug.spotless.extra.eclipse.base.SpotlessEclipseFramework.LINE_DELIMITER; +import static org.junit.Assert.*; + +import java.util.Properties; +import java.util.function.Consumer; + +import org.eclipse.jdt.core.JavaCore; +import org.eclipse.jdt.core.formatter.DefaultCodeFormatterConstants; +import org.junit.Test; + +/** Eclipse JDT wrapper integration tests */ +public class EclipseJdtFormatterStepImplTest { + + private final static String UNFORMATTED = "package com.diffplug.gradle.spotless;\n" + + "public class C {\n" + + " static void hello() {" + + " System.out.println(\"Hello World!\");\n" + + " }\n" + + "}".replaceAll("\n", LINE_DELIMITER); + private final static String FORMATTED = "package com.diffplug.gradle.spotless;\n" + + "public class C {\n" + + "\tstatic void hello() {\n" + + "\t\tSystem.out.println(\"Hello World!\");\n" + + "\t}\n" + + "}".replaceAll("\n", LINE_DELIMITER); + + private final static String PRE_UNFORMATTED = "/**
void f(){}*/\n".replaceAll("\n", LINE_DELIMITER); + private final static String PRE_FORMATTED = "/**\n *
\n * void f() {\n * }\n *\n */\n".replaceAll("\n", LINE_DELIMITER); + + private final static String ILLEGAL_CHAR = Character.toString((char) 254); + + @Test + public void defaultFormat() throws Throwable { + String output = format(UNFORMATTED, config -> {}); + assertEquals("Unexpected formatting with default preferences.", + FORMATTED, output); + } + + @Test + public void invalidFormat() throws Throwable { + String output = format(FORMATTED.replace("void hello() {", "void hello() "), config -> {}); + assertTrue("Incomplete Java not formatted on best effort basis.", output.contains("void hello() " + LINE_DELIMITER)); + } + + @Test + public void invalidCharater() throws Throwable { + String output = format(FORMATTED.replace("void hello() {", "void hello()" + ILLEGAL_CHAR + " {"), config -> {}); + assertTrue("Invalid charater not formatted on best effort basis.", output.contains("void hello()" + ILLEGAL_CHAR + " {" + LINE_DELIMITER)); + } + + @Test + public void invalidConfiguration() throws Throwable { + String output = format(FORMATTED, config -> { + config.setProperty(DefaultCodeFormatterConstants.FORMATTER_TAB_CHAR, JavaCore.SPACE); + config.setProperty(DefaultCodeFormatterConstants.FORMATTER_TAB_SIZE, "noInteger"); + }); + assertEquals("Invalid indentation configuration not replaced by default value (4 spaces)", + FORMATTED.replace("\t", " "), output); + } + + @Test + /** Test that an internal code formatter can be created to format the Java code within HTML pre-tags. (see also Spotless issue #191) */ + public void internalCodeFormatter() throws Throwable { + String output = format(PRE_UNFORMATTED + UNFORMATTED, config -> { + config.setProperty( + DefaultCodeFormatterConstants.FORMATTER_COMMENT_FORMAT_HEADER, + DefaultCodeFormatterConstants.TRUE); + }); + assertEquals("Code within HTML
tag not formatted.", + PRE_FORMATTED + FORMATTED, output); + } + + private static String format(final String input, final Consumerconfig) throws Exception { + Properties properties = new Properties(); + config.accept(properties); + EclipseJdtFormatterStepImpl formatter = new EclipseJdtFormatterStepImpl(properties); + return formatter.format(input); + } + +}