From 7faf8f58608c86f70061127ffac2df3cf525dc23 Mon Sep 17 00:00:00 2001 From: Tamas Cservenak Date: Thu, 22 Feb 2024 12:06:06 +0100 Subject: [PATCH] Example of updating to new parent 53 (unreleased yet) Changes: * parent POM updated (53 not released yet!) * changed header as this is ASL2 project (default is EPL1) * mvn spotless:apply * mvn license:format --- pom.xml | 35 +- takari-lifecycle-plugin-its/pom.xml | 7 +- .../plugins/test/AbstractIntegrationTest.java | 20 +- .../tesla/maven/plugins/test/BasicTest.java | 322 +- .../test/CompileAnnotationProcessingTest.java | 40 +- .../plugins/test/CompileClasspathTest.java | 30 +- .../plugins/test/CompileMultimoduleTest.java | 28 +- .../maven/plugins/test/DeployAtEndTest.java | 102 +- .../plugins/test/FilteringResourcesTest.java | 116 +- .../MultimoduleSkipInstallDeployTest.java | 45 +- .../maven/plugins/test/PomPackagingTest.java | 39 +- takari-lifecycle-plugin/pom.xml | 8 +- .../java/io/takari/maven/plugins/Deploy.java | 177 +- .../java/io/takari/maven/plugins/Install.java | 67 +- .../maven/plugins/TakariLifecycleFlags.java | 9 +- .../maven/plugins/TakariLifecycleMojo.java | 125 +- .../maven/plugins/TakariLifecycles.java | 41 +- .../plugins/compile/AbstractCompileMojo.java | 1133 +++---- .../plugins/compile/AbstractCompiler.java | 269 +- .../maven/plugins/compile/ArtifactFile.java | 64 +- .../plugins/compile/ArtifactFileHolder.java | 52 +- .../maven/plugins/compile/CompileMojo.java | 269 +- .../plugins/compile/CompilerBuildContext.java | 484 +-- .../compile/ProcessorpathResolver.java | 136 +- .../compile/ProjectClasspathDigester.java | 290 +- .../plugins/compile/ReactorProjects.java | 37 +- .../plugins/compile/TestCompileMojo.java | 245 +- .../compile/javac/AbstractCompilerJavac.java | 457 +-- .../plugins/compile/javac/CompilerJavac.java | 246 +- .../compile/javac/CompilerJavacForked.java | 510 ++-- .../compile/javac/CompilerJavacLauncher.java | 261 +- .../plugins/compile/javac/FileObjects.java | 31 +- .../javac/IncrementalFileOutputStream.java | 142 +- .../javac/RecordingJavaFileManager.java | 100 +- .../jdt/AccessRestrictionClasspathEntry.java | 87 +- .../jdt/AnnotationProcessingState.java | 24 +- .../jdt/AnnotationProcessorManager.java | 415 +-- .../compile/jdt/ClassfileDigester.java | 507 ++-- .../compile/jdt/ClasspathDigester.java | 247 +- .../compile/jdt/ClasspathEntryCache.java | 168 +- .../plugins/compile/jdt/CompilerJdt.java | 1667 +++++------ .../maven/plugins/compile/jdt/FilerImpl.java | 255 +- .../plugins/compile/jdt/MessagerImpl.java | 102 +- .../jdt/OutputDirectoryClasspathEntry.java | 92 +- .../compile/jdt/ProcessingEnvImpl.java | 231 +- .../compile/jdt/ReferenceCollection.java | 408 +-- .../classpath/AbstractClasspathDirectory.java | 108 +- .../compile/jdt/classpath/Classpath.java | 141 +- .../jdt/classpath/ClasspathDirectory.java | 59 +- .../compile/jdt/classpath/ClasspathEntry.java | 13 +- .../compile/jdt/classpath/ClasspathJar.java | 119 +- .../classpath/DependencyClasspathEntry.java | 156 +- .../jdt/classpath/JavaInstallation.java | 114 +- .../jdt/classpath/MutableClasspathEntry.java | 8 +- .../compile/jdt/classpath/PathNormalizer.java | 27 +- .../jdt/classpath/SourcepathDirectory.java | 79 +- .../MojoConfigurationProcessor.java | 121 +- .../configurator/MojoConfigurator.java | 24 +- .../TakariMojoExecutionConfigurator.java | 111 +- .../exportpackage/ExportPackageMojo.java | 138 +- .../install_deploy/DeployParticipant.java | 155 +- .../maven/plugins/jar/AggregateSource.java | 66 +- .../plugins/jar/ArchiveConfiguration.java | 43 +- .../takari/maven/plugins/jar/BytesEntry.java | 184 +- .../java/io/takari/maven/plugins/jar/Jar.java | 443 +-- .../maven/plugins/jar/PomPropertiesMojo.java | 38 +- .../maven/plugins/pgp/SignArtifactMojo.java | 123 +- .../takari/maven/plugins/pgp/SignedFile.java | 76 +- .../plugin/AddPluginArtifactMetadataMojo.java | 62 +- .../maven/plugins/plugin/GeneratorUtils.java | 173 +- .../plugin/GroupRepositoryMetadata.java | 149 +- .../plugin/LegacyPluginDescriptors.java | 180 +- .../plugin/MojoAnnotationProcessorMojo.java | 47 +- .../plugins/plugin/MojoDescriptorGleaner.java | 397 +-- .../plugins/plugin/PluginDescriptorMojo.java | 525 ++-- .../plugin/PluginDescriptorWriter.java | 350 +-- .../takari/maven/plugins/plugin/Sorting.java | 62 +- .../AbstractProcessResourcesMojo.java | 171 +- .../plugins/resources/ProcessResources.java | 30 +- .../resources/ProcessTestResources.java | 29 +- .../plugins/sisu/AbstractSisuIndexMojo.java | 110 +- .../maven/plugins/sisu/SisuIndexMojo.java | 34 +- .../maven/plugins/sisu/SisuTestIndexMojo.java | 34 +- .../testproperties/TestPropertiesMojo.java | 552 ++-- .../maven/plugins/util/AetherUtils.java | 483 +-- .../maven/plugins/util/PropertiesWriter.java | 40 +- .../filtering/AbstractResourceProcessor.java | 23 +- .../filtering/CopyResourcesProcessor.java | 51 +- .../filtering/FilterResourcesProcessor.java | 283 +- .../filtering/MissingPropertyAction.java | 39 +- .../filtering/ResourcesProcessor.java | 84 +- .../main/m2e/lifecycle-mapping-metadata.xml | 4 +- .../src/main/mdo/mojos.xml | 9 + .../META-INF/plexus/components.xml | 4 +- .../src/main/org/codehaus/foo/Bad.java | 6 +- .../main/org/codehaus/foo/Deprecation.java | 6 +- .../main/org/codehaus/foo/ExternalDeps.java | 6 +- .../src/main/org/codehaus/foo/Person.java | 6 +- .../main/org/codehaus/foo/ReservedWord.java | 6 +- .../main/org/codehaus/foo/UnknownSymbol.java | 6 +- .../main/org/codehaus/foo/WrongClassname.java | 6 +- .../plugins/compile/AbstractCompileTest.java | 157 +- .../compile/AnnotationProcessingTest.java | 2598 +++++++++-------- .../plugins/compile/ClassfileMatchers.java | 370 +-- .../compile/CompileIncrementalTest.java | 391 +-- .../CompileJavacClasspathVisibilityTest.java | 67 +- .../maven/plugins/compile/CompileRule.java | 92 +- .../maven/plugins/compile/CompileTest.java | 795 ++--- .../maven/plugins/compile/ErrorMessage.java | 68 +- .../plugins/compile/ForkedCompileTest.java | 84 +- .../compile/MixedCompilerBackendTest.java | 52 +- .../compile/ProcessorpathResolverTest.java | 83 +- .../plugins/compile/SimpleReactorReader.java | 223 +- .../compile/jdt/AbstractCompileJdtTest.java | 46 +- .../compile/jdt/CompileJdtClasspathTest.java | 300 +- .../CompileJdtClasspathVisibilityTest.java | 284 +- .../plugins/compile/jdt/CompileJdtTest.java | 516 ++-- .../compile/jdt/EclipseFileManagerTest.java | 24 +- .../plugins/compile/jdt/FilerImplTest.java | 261 +- .../compile/jdt/classpath/ClasspathTest.java | 53 +- .../maven/plugins/configurator/JarTest.java | 68 +- .../MojoConfigurationMergerTest.java | 243 +- .../exportpackage/ExportPackageMojoTest.java | 203 +- .../install_deploy/InstallDeployTest.java | 258 +- .../io/takari/maven/plugins/jar/JarTest.java | 579 ++-- .../maven/plugins/jar/PomPropertiesTest.java | 42 +- .../plugin/MojoDescriptorGleanerTest.java | 153 +- .../plugin/PluginDescriptorMojoTest.java | 623 ++-- .../plugins/resources/ResourcesTest.java | 348 ++- .../plugins/resources/TestResourcesTest.java | 70 +- .../maven/plugins/sisu/SisuIndexTest.java | 124 +- .../TestPropertiesMojoTest.java | 478 +-- 132 files changed, 13489 insertions(+), 12617 deletions(-) diff --git a/pom.xml b/pom.xml index 78cee8d2..f201e531 100644 --- a/pom.xml +++ b/pom.xml @@ -1,21 +1,20 @@ - 4.0.0 io.takari takari - 52 + 53-SNAPSHOT io.takari.maven.plugins @@ -23,6 +22,19 @@ 2.1.4-SNAPSHOT pom + + takari-lifecycle-plugin + + takari-lifecycle-plugin-its + + + + scm:git:git@github.com/takari/takari-lifecycle-plugin.git + scm:git:ssh://git@github.com/takari/takari-lifecycle-plugin.git + takari-lifecycle-2.1.2 + http://github.com/takari/takari-lifecycle-plugin + + 3.9.6 1.9.18 @@ -35,27 +47,14 @@ 3.0.1 - - scm:git:git@github.com/takari/takari-lifecycle-plugin.git - scm:git:ssh://git@github.com/takari/takari-lifecycle-plugin.git - http://github.com/takari/takari-lifecycle-plugin - takari-lifecycle-2.1.2 - - - - takari-lifecycle-plugin - - takari-lifecycle-plugin-its - - src/main/resources - src/main/resources-filtered true + src/main/resources-filtered diff --git a/takari-lifecycle-plugin-its/pom.xml b/takari-lifecycle-plugin-its/pom.xml index 96fe42ff..4dff11b2 100644 --- a/takari-lifecycle-plugin-its/pom.xml +++ b/takari-lifecycle-plugin-its/pom.xml @@ -1,14 +1,13 @@ - 4.0.0 @@ -80,8 +79,8 @@ - src/test/resources-filtered true + src/test/resources-filtered diff --git a/takari-lifecycle-plugin-its/src/test/java/io/tesla/maven/plugins/test/AbstractIntegrationTest.java b/takari-lifecycle-plugin-its/src/test/java/io/tesla/maven/plugins/test/AbstractIntegrationTest.java index 78e2407c..488d6569 100644 --- a/takari-lifecycle-plugin-its/src/test/java/io/tesla/maven/plugins/test/AbstractIntegrationTest.java +++ b/takari-lifecycle-plugin-its/src/test/java/io/tesla/maven/plugins/test/AbstractIntegrationTest.java @@ -1,28 +1,26 @@ package io.tesla.maven.plugins.test; -import org.junit.Rule; -import org.junit.runner.RunWith; - import io.takari.maven.testing.TestProperties; import io.takari.maven.testing.TestResources; import io.takari.maven.testing.executor.MavenRuntime; import io.takari.maven.testing.executor.MavenRuntime.MavenRuntimeBuilder; import io.takari.maven.testing.executor.MavenVersions; import io.takari.maven.testing.executor.junit.MavenJUnitTestRunner; +import org.junit.Rule; +import org.junit.runner.RunWith; @RunWith(MavenJUnitTestRunner.class) @MavenVersions({"3.6.3", "3.8.8", "3.9.6"}) public abstract class AbstractIntegrationTest { - @Rule - public final TestResources resources = new TestResources(); - - public final TestProperties properties = new TestProperties(); + @Rule + public final TestResources resources = new TestResources(); - public final MavenRuntime verifier; + public final TestProperties properties = new TestProperties(); - public AbstractIntegrationTest(MavenRuntimeBuilder verifierBuilder) throws Exception { - this.verifier = verifierBuilder.withCliOptions("-U", "-B").build(); - } + public final MavenRuntime verifier; + public AbstractIntegrationTest(MavenRuntimeBuilder verifierBuilder) throws Exception { + this.verifier = verifierBuilder.withCliOptions("-U", "-B").build(); + } } diff --git a/takari-lifecycle-plugin-its/src/test/java/io/tesla/maven/plugins/test/BasicTest.java b/takari-lifecycle-plugin-its/src/test/java/io/tesla/maven/plugins/test/BasicTest.java index 9331b416..9cde1142 100644 --- a/takari-lifecycle-plugin-its/src/test/java/io/tesla/maven/plugins/test/BasicTest.java +++ b/takari-lifecycle-plugin-its/src/test/java/io/tesla/maven/plugins/test/BasicTest.java @@ -2,190 +2,188 @@ import static io.takari.maven.testing.TestResources.assertFilesPresent; +import com.google.common.io.ByteStreams; +import com.google.common.io.Files; +import io.takari.maven.testing.executor.MavenExecutionResult; +import io.takari.maven.testing.executor.MavenRuntime.MavenRuntimeBuilder; import java.io.File; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; - import org.junit.Assert; import org.junit.Test; -import com.google.common.io.ByteStreams; -import com.google.common.io.Files; - -import io.takari.maven.testing.executor.MavenExecutionResult; -import io.takari.maven.testing.executor.MavenRuntime.MavenRuntimeBuilder; - public class BasicTest extends AbstractIntegrationTest { - public BasicTest(MavenRuntimeBuilder verifierBuilder) throws Exception { - super(verifierBuilder); - } - - @Test - public void testBasic() throws Exception { - File basedir = resources.getBasedir("basic"); - - File remoterepo = new File(basedir, "remoterepo"); - Assert.assertTrue(remoterepo.mkdirs()); - - File localrepo = properties.getLocalRepository(); - - MavenExecutionResult result = verifier.forProject(basedir) // - .withCliOption("-Drepopath=" + remoterepo.getCanonicalPath()) // - .withCliOption("-X") // - .execute("deploy"); - - result.assertErrorFreeLog(); - - // TODO assert expected mojos were executed - // TODO assertFileExist, etc - // TODO assert jar content - Assert.assertTrue(new File(basedir, "target/basic-1.0.jar").canRead()); - Assert.assertTrue(new File(basedir, "target/basic-1.0-sources.jar").canRead()); - Assert.assertTrue(new File(basedir, "target/basic-1.0-tests.jar").canRead()); - - File localGroup = new File(localrepo, "io/takari/lifecycle/its/basic"); - Assert.assertTrue(new File(localGroup, "basic/1.0/basic-1.0.pom").canRead()); - Assert.assertTrue(new File(localGroup, "basic/1.0/basic-1.0.jar").canRead()); - Assert.assertTrue(new File(localGroup, "basic/1.0/basic-1.0-sources.jar").canRead()); - Assert.assertTrue(new File(localGroup, "basic/1.0/basic-1.0-tests.jar").canRead()); - - File remoteGroup = new File(remoterepo, "io/takari/lifecycle/its/basic"); - Assert.assertTrue(new File(remoteGroup, "basic/1.0/basic-1.0.pom").canRead()); - Assert.assertTrue(new File(remoteGroup, "basic/1.0/basic-1.0.jar").canRead()); - Assert.assertTrue(new File(remoteGroup, "basic/1.0/basic-1.0-sources.jar").canRead()); - Assert.assertTrue(new File(remoteGroup, "basic/1.0/basic-1.0-tests.jar").canRead()); - } - - @Test - public void testBasicPlugin() throws Exception { - File basedir = resources.getBasedir("basic-plugin"); - - File remoterepo = new File(basedir, "remoterepo"); - Assert.assertTrue(remoterepo.mkdirs()); - - File localrepo = properties.getLocalRepository(); - - MavenExecutionResult result = verifier.forProject(basedir) // - .withCliOption("-Drepopath=" + remoterepo.getCanonicalPath()) // - .execute("deploy"); - - result.assertErrorFreeLog(); - - // TODO assert expected mojos were executed - // TODO assertFileExist, etc - // TODO assert jar content - Assert.assertTrue(new File(basedir, "target/basic-plugin-1.0.jar").canRead()); - Assert.assertTrue(new File(basedir, "target/basic-plugin-1.0-sources.jar").canRead()); - Assert.assertTrue(new File(basedir, "target/basic-plugin-1.0-tests.jar").canRead()); - - File localGroup = new File(localrepo, "io/takari/lifecycle/its/basic"); - Assert.assertTrue(new File(localGroup, "basic-plugin/1.0/basic-plugin-1.0.pom").canRead()); - Assert.assertTrue(new File(localGroup, "basic-plugin/1.0/basic-plugin-1.0.jar").canRead()); - Assert.assertTrue(new File(localGroup, "basic-plugin/1.0/basic-plugin-1.0-sources.jar").canRead()); - Assert.assertTrue(new File(localGroup, "basic-plugin/1.0/basic-plugin-1.0-tests.jar").canRead()); - - File remoteGroup = new File(remoterepo, "io/takari/lifecycle/its/basic"); - Assert.assertTrue(new File(remoteGroup, "basic-plugin/1.0/basic-plugin-1.0.pom").canRead()); - Assert.assertTrue(new File(remoteGroup, "basic-plugin/1.0/basic-plugin-1.0.jar").canRead()); - Assert.assertTrue(new File(remoteGroup, "basic-plugin/1.0/basic-plugin-1.0-sources.jar").canRead()); - Assert.assertTrue(new File(remoteGroup, "basic-plugin/1.0/basic-plugin-1.0-tests.jar").canRead()); - - // assert m2e metadata - Assert.assertEquals(readFileUTF8(new File(basedir, "src/main/m2e/lifecycle-mapping-metadata.xml")), // - readZipFileEntryUTF8(new File(basedir, "target/basic-plugin-1.0.jar"), "META-INF/m2e/lifecycle-mapping-metadata.xml")); - } - - private String readZipFileEntryUTF8(File zipFile, String entryPath) throws IOException { - try (ZipFile zip = new ZipFile(zipFile)) { - ZipEntry entry = zip.getEntry(entryPath); - return new String(ByteStreams.toByteArray(zip.getInputStream(entry)), StandardCharsets.UTF_8); + public BasicTest(MavenRuntimeBuilder verifierBuilder) throws Exception { + super(verifierBuilder); } - } - - private String readFileUTF8(File file) throws IOException { - return Files.toString(file, StandardCharsets.UTF_8); - } - - @Test - public void testBasicBuilder() throws Exception { - File basedir = resources.getBasedir("basic-builder"); - File remoterepo = new File(basedir, "remoterepo"); - Assert.assertTrue(remoterepo.mkdirs()); + @Test + public void testBasic() throws Exception { + File basedir = resources.getBasedir("basic"); - File localrepo = properties.getLocalRepository(); + File remoterepo = new File(basedir, "remoterepo"); + Assert.assertTrue(remoterepo.mkdirs()); - MavenExecutionResult result = verifier.forProject(basedir) // - .withCliOption("-Drepopath=" + remoterepo.getCanonicalPath()) // - .withCliOption("-Dincrementalbuild.version=" + properties.get("incrementalbuild.version")) // - .execute("deploy"); + File localrepo = properties.getLocalRepository(); - result.assertErrorFreeLog(); + MavenExecutionResult result = verifier.forProject(basedir) // + .withCliOption("-Drepopath=" + remoterepo.getCanonicalPath()) // + .withCliOption("-X") // + .execute("deploy"); - // TODO assert expected mojos were executed - // TODO assertFileExist, etc - // TODO assert jar content - Assert.assertTrue(new File(basedir, "target/basic-builder-1.0.jar").canRead()); - Assert.assertTrue(new File(basedir, "target/basic-builder-1.0-sources.jar").canRead()); - Assert.assertTrue(new File(basedir, "target/basic-builder-1.0-tests.jar").canRead()); - Assert.assertTrue(new File(basedir, "target/classes/META-INF/m2e/lifecycle-mapping-metadata.xml").canRead()); + result.assertErrorFreeLog(); - File localGroup = new File(localrepo, "io/takari/lifecycle/its/basic"); - Assert.assertTrue(new File(localGroup, "basic-builder/1.0/basic-builder-1.0.pom").canRead()); - Assert.assertTrue(new File(localGroup, "basic-builder/1.0/basic-builder-1.0.jar").canRead()); - Assert.assertTrue(new File(localGroup, "basic-builder/1.0/basic-builder-1.0-sources.jar").canRead()); - Assert.assertTrue(new File(localGroup, "basic-builder/1.0/basic-builder-1.0-tests.jar").canRead()); + // TODO assert expected mojos were executed + // TODO assertFileExist, etc + // TODO assert jar content + Assert.assertTrue(new File(basedir, "target/basic-1.0.jar").canRead()); + Assert.assertTrue(new File(basedir, "target/basic-1.0-sources.jar").canRead()); + Assert.assertTrue(new File(basedir, "target/basic-1.0-tests.jar").canRead()); - File remoteGroup = new File(remoterepo, "io/takari/lifecycle/its/basic"); - Assert.assertTrue(new File(remoteGroup, "basic-builder/1.0/basic-builder-1.0.pom").canRead()); - Assert.assertTrue(new File(remoteGroup, "basic-builder/1.0/basic-builder-1.0.jar").canRead()); - Assert.assertTrue(new File(remoteGroup, "basic-builder/1.0/basic-builder-1.0-sources.jar").canRead()); - Assert.assertTrue(new File(remoteGroup, "basic-builder/1.0/basic-builder-1.0-tests.jar").canRead()); + File localGroup = new File(localrepo, "io/takari/lifecycle/its/basic"); + Assert.assertTrue(new File(localGroup, "basic/1.0/basic-1.0.pom").canRead()); + Assert.assertTrue(new File(localGroup, "basic/1.0/basic-1.0.jar").canRead()); + Assert.assertTrue(new File(localGroup, "basic/1.0/basic-1.0-sources.jar").canRead()); + Assert.assertTrue(new File(localGroup, "basic/1.0/basic-1.0-tests.jar").canRead()); + File remoteGroup = new File(remoterepo, "io/takari/lifecycle/its/basic"); + Assert.assertTrue(new File(remoteGroup, "basic/1.0/basic-1.0.pom").canRead()); + Assert.assertTrue(new File(remoteGroup, "basic/1.0/basic-1.0.jar").canRead()); + Assert.assertTrue(new File(remoteGroup, "basic/1.0/basic-1.0-sources.jar").canRead()); + Assert.assertTrue(new File(remoteGroup, "basic/1.0/basic-1.0-tests.jar").canRead()); + } - } - - @Test - public void testBasicComponent() throws Exception { - File basedir = resources.getBasedir("basic-component"); - - File remoterepo = new File(basedir, "remoterepo"); - Assert.assertTrue(remoterepo.mkdirs()); - - File localrepo = properties.getLocalRepository(); - - MavenExecutionResult result = verifier.forProject(basedir) // - .withCliOption("-Drepopath=" + remoterepo.getCanonicalPath()) // - .execute("deploy"); - - result.assertErrorFreeLog(); - - assertFilesPresent(basedir, // - "target/classes/META-INF/sisu/javax.inject.Named", // - "target/test-classes/META-INF/sisu/javax.inject.Named", // - "target/test-classes/test.properties"); + @Test + public void testBasicPlugin() throws Exception { + File basedir = resources.getBasedir("basic-plugin"); + + File remoterepo = new File(basedir, "remoterepo"); + Assert.assertTrue(remoterepo.mkdirs()); + + File localrepo = properties.getLocalRepository(); + + MavenExecutionResult result = verifier.forProject(basedir) // + .withCliOption("-Drepopath=" + remoterepo.getCanonicalPath()) // + .execute("deploy"); + + result.assertErrorFreeLog(); + + // TODO assert expected mojos were executed + // TODO assertFileExist, etc + // TODO assert jar content + Assert.assertTrue(new File(basedir, "target/basic-plugin-1.0.jar").canRead()); + Assert.assertTrue(new File(basedir, "target/basic-plugin-1.0-sources.jar").canRead()); + Assert.assertTrue(new File(basedir, "target/basic-plugin-1.0-tests.jar").canRead()); + + File localGroup = new File(localrepo, "io/takari/lifecycle/its/basic"); + Assert.assertTrue(new File(localGroup, "basic-plugin/1.0/basic-plugin-1.0.pom").canRead()); + Assert.assertTrue(new File(localGroup, "basic-plugin/1.0/basic-plugin-1.0.jar").canRead()); + Assert.assertTrue(new File(localGroup, "basic-plugin/1.0/basic-plugin-1.0-sources.jar").canRead()); + Assert.assertTrue(new File(localGroup, "basic-plugin/1.0/basic-plugin-1.0-tests.jar").canRead()); + + File remoteGroup = new File(remoterepo, "io/takari/lifecycle/its/basic"); + Assert.assertTrue(new File(remoteGroup, "basic-plugin/1.0/basic-plugin-1.0.pom").canRead()); + Assert.assertTrue(new File(remoteGroup, "basic-plugin/1.0/basic-plugin-1.0.jar").canRead()); + Assert.assertTrue(new File(remoteGroup, "basic-plugin/1.0/basic-plugin-1.0-sources.jar").canRead()); + Assert.assertTrue(new File(remoteGroup, "basic-plugin/1.0/basic-plugin-1.0-tests.jar").canRead()); + + // assert m2e metadata + Assert.assertEquals( + readFileUTF8(new File(basedir, "src/main/m2e/lifecycle-mapping-metadata.xml")), // + readZipFileEntryUTF8( + new File(basedir, "target/basic-plugin-1.0.jar"), + "META-INF/m2e/lifecycle-mapping-metadata.xml")); + } + private String readZipFileEntryUTF8(File zipFile, String entryPath) throws IOException { + try (ZipFile zip = new ZipFile(zipFile)) { + ZipEntry entry = zip.getEntry(entryPath); + return new String(ByteStreams.toByteArray(zip.getInputStream(entry)), StandardCharsets.UTF_8); + } + } - // TODO assert expected mojos were executed - // TODO assertFileExist, etc - // TODO assert jar content - Assert.assertTrue(new File(basedir, "target/basic-component-1.0.jar").canRead()); - Assert.assertTrue(new File(basedir, "target/basic-component-1.0-sources.jar").canRead()); - Assert.assertTrue(new File(basedir, "target/basic-component-1.0-tests.jar").canRead()); + private String readFileUTF8(File file) throws IOException { + return Files.toString(file, StandardCharsets.UTF_8); + } - File localGroup = new File(localrepo, "io/takari/lifecycle/its/basic"); - Assert.assertTrue(new File(localGroup, "basic-component/1.0/basic-component-1.0.pom").canRead()); - Assert.assertTrue(new File(localGroup, "basic-component/1.0/basic-component-1.0.jar").canRead()); - Assert.assertTrue(new File(localGroup, "basic-component/1.0/basic-component-1.0-sources.jar").canRead()); - Assert.assertTrue(new File(localGroup, "basic-component/1.0/basic-component-1.0-tests.jar").canRead()); + @Test + public void testBasicBuilder() throws Exception { + File basedir = resources.getBasedir("basic-builder"); + + File remoterepo = new File(basedir, "remoterepo"); + Assert.assertTrue(remoterepo.mkdirs()); + + File localrepo = properties.getLocalRepository(); + + MavenExecutionResult result = verifier.forProject(basedir) // + .withCliOption("-Drepopath=" + remoterepo.getCanonicalPath()) // + .withCliOption("-Dincrementalbuild.version=" + properties.get("incrementalbuild.version")) // + .execute("deploy"); + + result.assertErrorFreeLog(); + + // TODO assert expected mojos were executed + // TODO assertFileExist, etc + // TODO assert jar content + Assert.assertTrue(new File(basedir, "target/basic-builder-1.0.jar").canRead()); + Assert.assertTrue(new File(basedir, "target/basic-builder-1.0-sources.jar").canRead()); + Assert.assertTrue(new File(basedir, "target/basic-builder-1.0-tests.jar").canRead()); + Assert.assertTrue(new File(basedir, "target/classes/META-INF/m2e/lifecycle-mapping-metadata.xml").canRead()); + + File localGroup = new File(localrepo, "io/takari/lifecycle/its/basic"); + Assert.assertTrue(new File(localGroup, "basic-builder/1.0/basic-builder-1.0.pom").canRead()); + Assert.assertTrue(new File(localGroup, "basic-builder/1.0/basic-builder-1.0.jar").canRead()); + Assert.assertTrue(new File(localGroup, "basic-builder/1.0/basic-builder-1.0-sources.jar").canRead()); + Assert.assertTrue(new File(localGroup, "basic-builder/1.0/basic-builder-1.0-tests.jar").canRead()); + + File remoteGroup = new File(remoterepo, "io/takari/lifecycle/its/basic"); + Assert.assertTrue(new File(remoteGroup, "basic-builder/1.0/basic-builder-1.0.pom").canRead()); + Assert.assertTrue(new File(remoteGroup, "basic-builder/1.0/basic-builder-1.0.jar").canRead()); + Assert.assertTrue(new File(remoteGroup, "basic-builder/1.0/basic-builder-1.0-sources.jar").canRead()); + Assert.assertTrue(new File(remoteGroup, "basic-builder/1.0/basic-builder-1.0-tests.jar").canRead()); + } - File remoteGroup = new File(remoterepo, "io/takari/lifecycle/its/basic"); - Assert.assertTrue(new File(remoteGroup, "basic-component/1.0/basic-component-1.0.pom").canRead()); - Assert.assertTrue(new File(remoteGroup, "basic-component/1.0/basic-component-1.0.jar").canRead()); - Assert.assertTrue(new File(remoteGroup, "basic-component/1.0/basic-component-1.0-sources.jar").canRead()); - Assert.assertTrue(new File(remoteGroup, "basic-component/1.0/basic-component-1.0-tests.jar").canRead()); - } + @Test + public void testBasicComponent() throws Exception { + File basedir = resources.getBasedir("basic-component"); + + File remoterepo = new File(basedir, "remoterepo"); + Assert.assertTrue(remoterepo.mkdirs()); + + File localrepo = properties.getLocalRepository(); + + MavenExecutionResult result = verifier.forProject(basedir) // + .withCliOption("-Drepopath=" + remoterepo.getCanonicalPath()) // + .execute("deploy"); + + result.assertErrorFreeLog(); + + assertFilesPresent( + basedir, // + "target/classes/META-INF/sisu/javax.inject.Named", // + "target/test-classes/META-INF/sisu/javax.inject.Named", // + "target/test-classes/test.properties"); + + // TODO assert expected mojos were executed + // TODO assertFileExist, etc + // TODO assert jar content + Assert.assertTrue(new File(basedir, "target/basic-component-1.0.jar").canRead()); + Assert.assertTrue(new File(basedir, "target/basic-component-1.0-sources.jar").canRead()); + Assert.assertTrue(new File(basedir, "target/basic-component-1.0-tests.jar").canRead()); + + File localGroup = new File(localrepo, "io/takari/lifecycle/its/basic"); + Assert.assertTrue(new File(localGroup, "basic-component/1.0/basic-component-1.0.pom").canRead()); + Assert.assertTrue(new File(localGroup, "basic-component/1.0/basic-component-1.0.jar").canRead()); + Assert.assertTrue(new File(localGroup, "basic-component/1.0/basic-component-1.0-sources.jar").canRead()); + Assert.assertTrue(new File(localGroup, "basic-component/1.0/basic-component-1.0-tests.jar").canRead()); + + File remoteGroup = new File(remoterepo, "io/takari/lifecycle/its/basic"); + Assert.assertTrue(new File(remoteGroup, "basic-component/1.0/basic-component-1.0.pom").canRead()); + Assert.assertTrue(new File(remoteGroup, "basic-component/1.0/basic-component-1.0.jar").canRead()); + Assert.assertTrue(new File(remoteGroup, "basic-component/1.0/basic-component-1.0-sources.jar").canRead()); + Assert.assertTrue(new File(remoteGroup, "basic-component/1.0/basic-component-1.0-tests.jar").canRead()); + } } diff --git a/takari-lifecycle-plugin-its/src/test/java/io/tesla/maven/plugins/test/CompileAnnotationProcessingTest.java b/takari-lifecycle-plugin-its/src/test/java/io/tesla/maven/plugins/test/CompileAnnotationProcessingTest.java index ef4c8d72..2236aac0 100644 --- a/takari-lifecycle-plugin-its/src/test/java/io/tesla/maven/plugins/test/CompileAnnotationProcessingTest.java +++ b/takari-lifecycle-plugin-its/src/test/java/io/tesla/maven/plugins/test/CompileAnnotationProcessingTest.java @@ -3,35 +3,33 @@ import io.takari.maven.testing.TestResources; import io.takari.maven.testing.executor.MavenExecutionResult; import io.takari.maven.testing.executor.MavenRuntime.MavenRuntimeBuilder; - import java.io.File; - import org.junit.Test; public class CompileAnnotationProcessingTest extends AbstractIntegrationTest { - public CompileAnnotationProcessingTest(MavenRuntimeBuilder verifierBuilder) throws Exception { - super(verifierBuilder); - } - - private void test(String compilerId) throws Exception { - File basedir = resources.getBasedir("compile-proc"); - - MavenExecutionResult result = verifier.forProject(basedir).withCliOption("-DcompilerId=" + compilerId).execute("package"); - result.assertErrorFreeLog(); + public CompileAnnotationProcessingTest(MavenRuntimeBuilder verifierBuilder) throws Exception { + super(verifierBuilder); + } - TestResources.assertFilesPresent(basedir, "project/target/classes/project/MyMyAnnotationClient.class"); - } + private void test(String compilerId) throws Exception { + File basedir = resources.getBasedir("compile-proc"); - @Test - public void testBasicJdt() throws Exception { - test("jdt"); - } + MavenExecutionResult result = verifier.forProject(basedir) + .withCliOption("-DcompilerId=" + compilerId) + .execute("package"); + result.assertErrorFreeLog(); - @Test - public void testBasicJavac() throws Exception { - test("javac"); - } + TestResources.assertFilesPresent(basedir, "project/target/classes/project/MyMyAnnotationClient.class"); + } + @Test + public void testBasicJdt() throws Exception { + test("jdt"); + } + @Test + public void testBasicJavac() throws Exception { + test("javac"); + } } diff --git a/takari-lifecycle-plugin-its/src/test/java/io/tesla/maven/plugins/test/CompileClasspathTest.java b/takari-lifecycle-plugin-its/src/test/java/io/tesla/maven/plugins/test/CompileClasspathTest.java index 0ed74e52..fedd9b82 100644 --- a/takari-lifecycle-plugin-its/src/test/java/io/tesla/maven/plugins/test/CompileClasspathTest.java +++ b/takari-lifecycle-plugin-its/src/test/java/io/tesla/maven/plugins/test/CompileClasspathTest.java @@ -2,27 +2,25 @@ import io.takari.maven.testing.executor.MavenExecutionResult; import io.takari.maven.testing.executor.MavenRuntime.MavenRuntimeBuilder; - import java.io.File; - import org.junit.Test; public class CompileClasspathTest extends AbstractIntegrationTest { - public CompileClasspathTest(MavenRuntimeBuilder verifierBuilder) throws Exception { - super(verifierBuilder); - } + public CompileClasspathTest(MavenRuntimeBuilder verifierBuilder) throws Exception { + super(verifierBuilder); + } - @Test - public void testClasspath() throws Exception { - File basedir = resources.getBasedir("compile-classpath"); + @Test + public void testClasspath() throws Exception { + File basedir = resources.getBasedir("compile-classpath"); - MavenExecutionResult result = verifier.forProject(basedir).execute("compile"); - result.assertErrorFreeLog(); - // Logging change in 3.9 "takari-lifecycle-plugin" vs "takari-lifecycle" - // Maven 3.9 shows prefix, vs artifactId in previous versions - result.assertLogText("takari-lifecycle"); - result.assertLogText(":" + properties.getPluginVersion() + ":compile"); - // TODO assert the class file(s) were actually created - } + MavenExecutionResult result = verifier.forProject(basedir).execute("compile"); + result.assertErrorFreeLog(); + // Logging change in 3.9 "takari-lifecycle-plugin" vs "takari-lifecycle" + // Maven 3.9 shows prefix, vs artifactId in previous versions + result.assertLogText("takari-lifecycle"); + result.assertLogText(":" + properties.getPluginVersion() + ":compile"); + // TODO assert the class file(s) were actually created + } } diff --git a/takari-lifecycle-plugin-its/src/test/java/io/tesla/maven/plugins/test/CompileMultimoduleTest.java b/takari-lifecycle-plugin-its/src/test/java/io/tesla/maven/plugins/test/CompileMultimoduleTest.java index 0a33cac5..398eb249 100644 --- a/takari-lifecycle-plugin-its/src/test/java/io/tesla/maven/plugins/test/CompileMultimoduleTest.java +++ b/takari-lifecycle-plugin-its/src/test/java/io/tesla/maven/plugins/test/CompileMultimoduleTest.java @@ -1,28 +1,26 @@ package io.tesla.maven.plugins.test; import io.takari.maven.testing.executor.MavenRuntime.MavenRuntimeBuilder; - import java.io.File; - import org.junit.Test; public class CompileMultimoduleTest extends AbstractIntegrationTest { - public CompileMultimoduleTest(MavenRuntimeBuilder verifierBuilder) throws Exception { - super(verifierBuilder); - } + public CompileMultimoduleTest(MavenRuntimeBuilder verifierBuilder) throws Exception { + super(verifierBuilder); + } - @Test - public void testCompile() throws Exception { - File basedir = resources.getBasedir("compile-multimodule"); + @Test + public void testCompile() throws Exception { + File basedir = resources.getBasedir("compile-multimodule"); - verifier.forProject(basedir).execute("compile").assertErrorFreeLog(); - } + verifier.forProject(basedir).execute("compile").assertErrorFreeLog(); + } - @Test - public void testTestCompile() throws Exception { - File basedir = resources.getBasedir("compile-multimodule"); + @Test + public void testTestCompile() throws Exception { + File basedir = resources.getBasedir("compile-multimodule"); - verifier.forProject(basedir).execute("test-compile").assertErrorFreeLog(); - } + verifier.forProject(basedir).execute("test-compile").assertErrorFreeLog(); + } } diff --git a/takari-lifecycle-plugin-its/src/test/java/io/tesla/maven/plugins/test/DeployAtEndTest.java b/takari-lifecycle-plugin-its/src/test/java/io/tesla/maven/plugins/test/DeployAtEndTest.java index e167d93c..31f1cfdc 100644 --- a/takari-lifecycle-plugin-its/src/test/java/io/tesla/maven/plugins/test/DeployAtEndTest.java +++ b/takari-lifecycle-plugin-its/src/test/java/io/tesla/maven/plugins/test/DeployAtEndTest.java @@ -1,61 +1,59 @@ package io.tesla.maven.plugins.test; +import io.takari.maven.testing.executor.MavenExecutionResult; +import io.takari.maven.testing.executor.MavenRuntime.MavenRuntimeBuilder; import java.io.File; - import org.junit.Assert; import org.junit.Test; -import io.takari.maven.testing.executor.MavenExecutionResult; -import io.takari.maven.testing.executor.MavenRuntime.MavenRuntimeBuilder; - public class DeployAtEndTest extends AbstractIntegrationTest { - public DeployAtEndTest(MavenRuntimeBuilder verifierBuilder) throws Exception { - super(verifierBuilder); - } - - @Test - public void testGood() throws Exception { - File basedir = resources.getBasedir("multimodule-deploy-at-end"); - - File remoterepo = new File(basedir, "remoterepo"); - Assert.assertTrue(remoterepo.mkdirs()); - - MavenExecutionResult result = verifier.forProject(basedir) // - .withCliOption("-Drepopath=" + remoterepo.getCanonicalPath()) // - .execute("deploy"); - - result.assertErrorFreeLog(); - result.assertLogText("Performing deploy at end"); - - File group = new File(remoterepo, "io/takari/lifecycle/its/multimodule-deploy-at-end"); - Assert.assertTrue(new File(group, "parent/1.0/parent-1.0.pom").canRead()); - Assert.assertTrue(new File(group, "modulea/1.0/modulea-1.0.pom").canRead()); - Assert.assertTrue(new File(group, "modulea/1.0/modulea-1.0.jar").canRead()); - Assert.assertTrue(new File(group, "moduleb/1.0/moduleb-1.0.pom").canRead()); - Assert.assertTrue(new File(group, "moduleb/1.0/moduleb-1.0.jar").canRead()); - } - - @Test - public void testBad() throws Exception { - File basedir = resources.getBasedir("multimodule-deploy-at-end-bad"); - - File remoterepo = new File(basedir, "remoterepo"); - Assert.assertTrue(remoterepo.mkdirs()); - - MavenExecutionResult result = verifier.forProject(basedir) // - .withCliOption("-Drepopath=" + remoterepo.getCanonicalPath()) // - .execute("deploy"); - - result.assertLogText("[ERROR]"); - result.assertLogText("Basic.java:[10,24] expected"); - result.assertLogText("Not performing deploy at end due to errors"); - - File group = new File(remoterepo, "io/takari/lifecycle/its/multimodule-deploy-at-end-bad"); - Assert.assertFalse(new File(group, "parent/1.0/parent-1.0.pom").canRead()); - Assert.assertFalse(new File(group, "modulea/1.0/modulea-1.0.pom").canRead()); - Assert.assertFalse(new File(group, "modulea/1.0/modulea-1.0.jar").canRead()); - Assert.assertFalse(new File(group, "moduleb/1.0/moduleb-1.0.pom").canRead()); - Assert.assertFalse(new File(group, "moduleb/1.0/moduleb-1.0.jar").canRead()); - } + public DeployAtEndTest(MavenRuntimeBuilder verifierBuilder) throws Exception { + super(verifierBuilder); + } + + @Test + public void testGood() throws Exception { + File basedir = resources.getBasedir("multimodule-deploy-at-end"); + + File remoterepo = new File(basedir, "remoterepo"); + Assert.assertTrue(remoterepo.mkdirs()); + + MavenExecutionResult result = verifier.forProject(basedir) // + .withCliOption("-Drepopath=" + remoterepo.getCanonicalPath()) // + .execute("deploy"); + + result.assertErrorFreeLog(); + result.assertLogText("Performing deploy at end"); + + File group = new File(remoterepo, "io/takari/lifecycle/its/multimodule-deploy-at-end"); + Assert.assertTrue(new File(group, "parent/1.0/parent-1.0.pom").canRead()); + Assert.assertTrue(new File(group, "modulea/1.0/modulea-1.0.pom").canRead()); + Assert.assertTrue(new File(group, "modulea/1.0/modulea-1.0.jar").canRead()); + Assert.assertTrue(new File(group, "moduleb/1.0/moduleb-1.0.pom").canRead()); + Assert.assertTrue(new File(group, "moduleb/1.0/moduleb-1.0.jar").canRead()); + } + + @Test + public void testBad() throws Exception { + File basedir = resources.getBasedir("multimodule-deploy-at-end-bad"); + + File remoterepo = new File(basedir, "remoterepo"); + Assert.assertTrue(remoterepo.mkdirs()); + + MavenExecutionResult result = verifier.forProject(basedir) // + .withCliOption("-Drepopath=" + remoterepo.getCanonicalPath()) // + .execute("deploy"); + + result.assertLogText("[ERROR]"); + result.assertLogText("Basic.java:[10,24] expected"); + result.assertLogText("Not performing deploy at end due to errors"); + + File group = new File(remoterepo, "io/takari/lifecycle/its/multimodule-deploy-at-end-bad"); + Assert.assertFalse(new File(group, "parent/1.0/parent-1.0.pom").canRead()); + Assert.assertFalse(new File(group, "modulea/1.0/modulea-1.0.pom").canRead()); + Assert.assertFalse(new File(group, "modulea/1.0/modulea-1.0.jar").canRead()); + Assert.assertFalse(new File(group, "moduleb/1.0/moduleb-1.0.pom").canRead()); + Assert.assertFalse(new File(group, "moduleb/1.0/moduleb-1.0.jar").canRead()); + } } diff --git a/takari-lifecycle-plugin-its/src/test/java/io/tesla/maven/plugins/test/FilteringResourcesTest.java b/takari-lifecycle-plugin-its/src/test/java/io/tesla/maven/plugins/test/FilteringResourcesTest.java index 5e1a42fe..09f18c83 100644 --- a/takari-lifecycle-plugin-its/src/test/java/io/tesla/maven/plugins/test/FilteringResourcesTest.java +++ b/takari-lifecycle-plugin-its/src/test/java/io/tesla/maven/plugins/test/FilteringResourcesTest.java @@ -5,7 +5,6 @@ import io.takari.maven.testing.executor.MavenRuntime; import io.takari.maven.testing.executor.MavenRuntime.ForkedMavenRuntimeBuilder; import io.takari.maven.testing.executor.MavenRuntime.MavenRuntimeBuilder; - import java.io.File; import java.io.FileInputStream; import java.io.InputStream; @@ -14,7 +13,6 @@ import java.util.HashMap; import java.util.Map; import java.util.Properties; - import org.junit.Assert; import org.junit.Test; @@ -22,71 +20,71 @@ // various mojo parameters public class FilteringResourcesTest extends AbstractIntegrationTest { - private final ForkedMavenRuntimeBuilder verifierForkedBuilder; + private final ForkedMavenRuntimeBuilder verifierForkedBuilder; - public FilteringResourcesTest(MavenRuntimeBuilder verifierBuilder) throws Exception { - super(verifierBuilder); - this.verifierForkedBuilder = verifierBuilder.forkedBuilder(); - } + public FilteringResourcesTest(MavenRuntimeBuilder verifierBuilder) throws Exception { + super(verifierBuilder); + this.verifierForkedBuilder = verifierBuilder.forkedBuilder(); + } - private Properties filter(String project) throws Exception { - File basedir = resources.getBasedir(project); - MavenExecution verifierBuilder = verifier.forProject(basedir); - return filter(verifierBuilder); - } + private Properties filter(String project) throws Exception { + File basedir = resources.getBasedir(project); + MavenExecution verifierBuilder = verifier.forProject(basedir); + return filter(verifierBuilder); + } - private Properties filter(MavenExecution verifierBuilder) throws Exception { - MavenExecutionResult result = verifierBuilder.execute("process-resources"); + private Properties filter(MavenExecution verifierBuilder) throws Exception { + MavenExecutionResult result = verifierBuilder.execute("process-resources"); - result.assertErrorFreeLog(); + result.assertErrorFreeLog(); - Properties properties = new Properties(); - InputStream is = new FileInputStream(new File(result.getBasedir(), "target/classes/filtered.properties")); - Reader reader = new InputStreamReader(is, "UTF-8"); - try { - properties.load(reader); - } finally { - is.close(); - } + Properties properties = new Properties(); + InputStream is = new FileInputStream(new File(result.getBasedir(), "target/classes/filtered.properties")); + Reader reader = new InputStreamReader(is, "UTF-8"); + try { + properties.load(reader); + } finally { + is.close(); + } - return properties; - } + return properties; + } - @Test - public void testLocalRepository() throws Exception { - String localRepository = filter("filtering-reflective-settings").getProperty("localRepository"); - Assert.assertTrue(localRepository != null && !localRepository.isEmpty()); - Assert.assertTrue(new File(localRepository).isDirectory()); - } + @Test + public void testLocalRepository() throws Exception { + String localRepository = filter("filtering-reflective-settings").getProperty("localRepository"); + Assert.assertTrue(localRepository != null && !localRepository.isEmpty()); + Assert.assertTrue(new File(localRepository).isDirectory()); + } - @Test - public void testUserSettingsFile() throws Exception { - String userSettingsFile = filter("filtering-reflective-settings").getProperty("userSettingsFile"); - Assert.assertTrue(userSettingsFile != null && !userSettingsFile.isEmpty()); - // note that settings.xml may not exist - } + @Test + public void testUserSettingsFile() throws Exception { + String userSettingsFile = filter("filtering-reflective-settings").getProperty("userSettingsFile"); + Assert.assertTrue(userSettingsFile != null && !userSettingsFile.isEmpty()); + // note that settings.xml may not exist + } - @Test - public void testCommandLineParameters() throws Exception { - File basedir = resources.getBasedir("filtering-command-line-parameters"); - MavenExecution verifierBuilder = verifier.forProject(basedir).withCliOption("-DcommandLineParameter=value"); - String commandLineParameter = filter(verifierBuilder).getProperty("commandLineParameter"); - Assert.assertEquals("value", commandLineParameter); - } + @Test + public void testCommandLineParameters() throws Exception { + File basedir = resources.getBasedir("filtering-command-line-parameters"); + MavenExecution verifierBuilder = verifier.forProject(basedir).withCliOption("-DcommandLineParameter=value"); + String commandLineParameter = filter(verifierBuilder).getProperty("commandLineParameter"); + Assert.assertEquals("value", commandLineParameter); + } - @Test - public void testSourceEncoding() throws Exception { - File basedir = resources.getBasedir("filtering-source-encoding"); - // command line -Dfile.encoding=... not work. It must be first params. withCliOptions add it to the end - // need use JAVA_TOOL_OPTIONS - Map env = new HashMap<>(); - // for test data need encoding windows-1251 - env.put("JAVA_TOOL_OPTIONS", "-Dfile.encoding=windows-1251"); - // default charset cached on first access, so need new process on every test run - MavenRuntime forkedVerifier = verifierForkedBuilder.withEnvironment(env).build(); - MavenExecution verifierBuilder = forkedVerifier.forProject(basedir); - Properties props = filter(verifierBuilder); - String test = props.getProperty("test"); - Assert.assertEquals("'Идентификатор'", test); - } + @Test + public void testSourceEncoding() throws Exception { + File basedir = resources.getBasedir("filtering-source-encoding"); + // command line -Dfile.encoding=... not work. It must be first params. withCliOptions add it to the end + // need use JAVA_TOOL_OPTIONS + Map env = new HashMap<>(); + // for test data need encoding windows-1251 + env.put("JAVA_TOOL_OPTIONS", "-Dfile.encoding=windows-1251"); + // default charset cached on first access, so need new process on every test run + MavenRuntime forkedVerifier = verifierForkedBuilder.withEnvironment(env).build(); + MavenExecution verifierBuilder = forkedVerifier.forProject(basedir); + Properties props = filter(verifierBuilder); + String test = props.getProperty("test"); + Assert.assertEquals("'Идентификатор'", test); + } } diff --git a/takari-lifecycle-plugin-its/src/test/java/io/tesla/maven/plugins/test/MultimoduleSkipInstallDeployTest.java b/takari-lifecycle-plugin-its/src/test/java/io/tesla/maven/plugins/test/MultimoduleSkipInstallDeployTest.java index 4d90ae73..742d6d1f 100644 --- a/takari-lifecycle-plugin-its/src/test/java/io/tesla/maven/plugins/test/MultimoduleSkipInstallDeployTest.java +++ b/takari-lifecycle-plugin-its/src/test/java/io/tesla/maven/plugins/test/MultimoduleSkipInstallDeployTest.java @@ -1,39 +1,36 @@ package io.tesla.maven.plugins.test; +import io.takari.maven.testing.executor.MavenExecutionResult; +import io.takari.maven.testing.executor.MavenRuntime.MavenRuntimeBuilder; import java.io.File; - import org.junit.Assert; import org.junit.Test; -import io.takari.maven.testing.executor.MavenExecutionResult; -import io.takari.maven.testing.executor.MavenRuntime.MavenRuntimeBuilder; - public class MultimoduleSkipInstallDeployTest extends AbstractIntegrationTest { - public MultimoduleSkipInstallDeployTest(MavenRuntimeBuilder verifierBuilder) throws Exception { - super(verifierBuilder); - } - - @Test - public void testBasic() throws Exception { - File basedir = resources.getBasedir("multimodule-skip-install-deploy"); + public MultimoduleSkipInstallDeployTest(MavenRuntimeBuilder verifierBuilder) throws Exception { + super(verifierBuilder); + } - File remoterepo = new File(basedir, "remoterepo"); - Assert.assertTrue(remoterepo.mkdirs()); + @Test + public void testBasic() throws Exception { + File basedir = resources.getBasedir("multimodule-skip-install-deploy"); - MavenExecutionResult result = verifier.forProject(basedir) // - .withCliOption("-Drepopath=" + remoterepo.getCanonicalPath()) // - .execute("deploy"); + File remoterepo = new File(basedir, "remoterepo"); + Assert.assertTrue(remoterepo.mkdirs()); - result.assertErrorFreeLog(); + MavenExecutionResult result = verifier.forProject(basedir) // + .withCliOption("-Drepopath=" + remoterepo.getCanonicalPath()) // + .execute("deploy"); - File group = new File(remoterepo, "io/takari/lifecycle/its/multimodule-skip-install-deploy"); - Assert.assertTrue(new File(group, "parent/1.0/parent-1.0.pom").canRead()); - Assert.assertTrue(new File(group, "modulea/1.0/modulea-1.0.pom").canRead()); - Assert.assertTrue(new File(group, "modulea/1.0/modulea-1.0.jar").canRead()); + result.assertErrorFreeLog(); - Assert.assertFalse(new File(group, "moduleb/1.0/moduleb-1.0.pom").canRead()); - Assert.assertFalse(new File(group, "moduleb/1.0/moduleb-1.0.jar").canRead()); - } + File group = new File(remoterepo, "io/takari/lifecycle/its/multimodule-skip-install-deploy"); + Assert.assertTrue(new File(group, "parent/1.0/parent-1.0.pom").canRead()); + Assert.assertTrue(new File(group, "modulea/1.0/modulea-1.0.pom").canRead()); + Assert.assertTrue(new File(group, "modulea/1.0/modulea-1.0.jar").canRead()); + Assert.assertFalse(new File(group, "moduleb/1.0/moduleb-1.0.pom").canRead()); + Assert.assertFalse(new File(group, "moduleb/1.0/moduleb-1.0.jar").canRead()); + } } diff --git a/takari-lifecycle-plugin-its/src/test/java/io/tesla/maven/plugins/test/PomPackagingTest.java b/takari-lifecycle-plugin-its/src/test/java/io/tesla/maven/plugins/test/PomPackagingTest.java index 3c61f42f..6fc0227b 100644 --- a/takari-lifecycle-plugin-its/src/test/java/io/tesla/maven/plugins/test/PomPackagingTest.java +++ b/takari-lifecycle-plugin-its/src/test/java/io/tesla/maven/plugins/test/PomPackagingTest.java @@ -2,36 +2,33 @@ import io.takari.maven.testing.executor.MavenExecutionResult; import io.takari.maven.testing.executor.MavenRuntime.MavenRuntimeBuilder; - import java.io.File; - import org.junit.Assert; import org.junit.Test; public class PomPackagingTest extends AbstractIntegrationTest { - public PomPackagingTest(MavenRuntimeBuilder verifierBuilder) throws Exception { - super(verifierBuilder); - } - - @Test - public void testPomPackaging() throws Exception { - File basedir = resources.getBasedir("pom-packaging"); + public PomPackagingTest(MavenRuntimeBuilder verifierBuilder) throws Exception { + super(verifierBuilder); + } - File remoterepo = new File(basedir, "remoterepo"); - Assert.assertTrue(remoterepo.mkdirs()); + @Test + public void testPomPackaging() throws Exception { + File basedir = resources.getBasedir("pom-packaging"); - File localrepo = properties.getLocalRepository(); + File remoterepo = new File(basedir, "remoterepo"); + Assert.assertTrue(remoterepo.mkdirs()); - MavenExecutionResult result = verifier.forProject(basedir) // - .withCliOption("-Drepopath=" + remoterepo.getCanonicalPath()) // - .execute("deploy"); - result.assertErrorFreeLog(); + File localrepo = properties.getLocalRepository(); - File localGroup = new File(localrepo, "io/takari/lifecycle/its/pom-packaging"); - Assert.assertTrue(new File(localGroup, "1.0/pom-packaging-1.0.pom").canRead()); + MavenExecutionResult result = verifier.forProject(basedir) // + .withCliOption("-Drepopath=" + remoterepo.getCanonicalPath()) // + .execute("deploy"); + result.assertErrorFreeLog(); - File remoteGroup = new File(remoterepo, "io/takari/lifecycle/its/pom-packaging"); - Assert.assertTrue(new File(remoteGroup, "1.0/pom-packaging-1.0.pom").canRead()); - } + File localGroup = new File(localrepo, "io/takari/lifecycle/its/pom-packaging"); + Assert.assertTrue(new File(localGroup, "1.0/pom-packaging-1.0.pom").canRead()); + File remoteGroup = new File(remoterepo, "io/takari/lifecycle/its/pom-packaging"); + Assert.assertTrue(new File(remoteGroup, "1.0/pom-packaging-1.0.pom").canRead()); + } } diff --git a/takari-lifecycle-plugin/pom.xml b/takari-lifecycle-plugin/pom.xml index 9ae23198..ded10243 100644 --- a/takari-lifecycle-plugin/pom.xml +++ b/takari-lifecycle-plugin/pom.xml @@ -1,14 +1,13 @@ - 4.0.0 @@ -101,7 +100,8 @@ org.apache.maven.plugin-tools maven-plugin-annotations ${mavenPluginPluginVersion} - compile + compile + org.apache.maven diff --git a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/Deploy.java b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/Deploy.java index 805dd43d..e8383ca1 100644 --- a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/Deploy.java +++ b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/Deploy.java @@ -1,17 +1,19 @@ -/** - * Copyright (c) 2014 Takari, Inc. +/* + * Copyright (c) 2014-2024 Takari, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * https://www.eclipse.org/legal/epl-v10.html */ package io.takari.maven.plugins; +import io.takari.incrementalbuild.Incremental; +import io.takari.incrementalbuild.Incremental.Configuration; +import io.takari.maven.plugins.install_deploy.DeployParticipant; +import io.takari.maven.plugins.util.AetherUtils; import java.util.regex.Matcher; import java.util.regex.Pattern; - import javax.inject.Inject; - import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugins.annotations.LifecyclePhase; import org.apache.maven.plugins.annotations.Mojo; @@ -26,105 +28,104 @@ import org.eclipse.aether.util.artifact.ArtifactIdUtils; import org.eclipse.aether.util.artifact.SubArtifact; -import io.takari.incrementalbuild.Incremental; -import io.takari.incrementalbuild.Incremental.Configuration; -import io.takari.maven.plugins.install_deploy.DeployParticipant; -import io.takari.maven.plugins.util.AetherUtils; - /** * @author Jason van Zyl */ @Mojo(name = "deploy", defaultPhase = LifecyclePhase.DEPLOY, configurator = "takari", threadSafe = true) public class Deploy extends TakariLifecycleMojo { - // TODO deploy at the end to prevent corruption - - // polyglot conversion to detect the project type and convert on the way out the door - - /** - * Specifies an alternative repository to which the project artifacts should be deployed (other than those specified in {@code }). - *

- * Format: id::layout::url - */ - @Parameter(property = "altDeploymentRepository") - private String altDeploymentRepository; - - @Parameter(defaultValue = "false", property = "deployAtEnd") - @Incremental(configuration = Configuration.ignore) - protected boolean deployAtEnd; + // TODO deploy at the end to prevent corruption - @Inject - private DeployParticipant deployParticipant; + // polyglot conversion to detect the project type and convert on the way out the door - @Override - public void executeMojo() throws MojoExecutionException { - deployProject(project); - } + /** + * Specifies an alternative repository to which the project artifacts should be deployed (other than those specified in {@code }). + *

+ * Format: id::layout::url + */ + @Parameter(property = "altDeploymentRepository") + private String altDeploymentRepository; - private void deployProject(MavenProject project) throws MojoExecutionException { - DeployRequest deployRequest = new DeployRequest(); + @Parameter(defaultValue = "false", property = "deployAtEnd") + @Incremental(configuration = Configuration.ignore) + protected boolean deployAtEnd; - Artifact projectArtifact = AetherUtils.toArtifact(project.getArtifact()); - Artifact pomArtifact = new SubArtifact(projectArtifact, "", "pom"); - pomArtifact = pomArtifact.setFile(project.getFile()); + @Inject + private DeployParticipant deployParticipant; - if (ArtifactIdUtils.equalsId(pomArtifact, projectArtifact)) { - if (isFile(projectArtifact.getFile())) { - pomArtifact = projectArtifact; - } - projectArtifact = null; + @Override + public void executeMojo() throws MojoExecutionException { + deployProject(project); } - deployRequest.addArtifact(pomArtifact); - if (projectArtifact != null) { - deployRequest.addArtifact(projectArtifact); + private void deployProject(MavenProject project) throws MojoExecutionException { + DeployRequest deployRequest = new DeployRequest(); + + Artifact projectArtifact = AetherUtils.toArtifact(project.getArtifact()); + Artifact pomArtifact = new SubArtifact(projectArtifact, "", "pom"); + pomArtifact = pomArtifact.setFile(project.getFile()); + + if (ArtifactIdUtils.equalsId(pomArtifact, projectArtifact)) { + if (isFile(projectArtifact.getFile())) { + pomArtifact = projectArtifact; + } + projectArtifact = null; + } + + deployRequest.addArtifact(pomArtifact); + if (projectArtifact != null) { + deployRequest.addArtifact(projectArtifact); + } + + // + // Attached artifacts + // + for (org.apache.maven.artifact.Artifact attachedArtifact : project.getAttachedArtifacts()) { + deployRequest.addArtifact(AetherUtils.toArtifact(attachedArtifact)); + } + + deployRequest.setRepository(remoteRepository(project)); + + if (!deployAtEnd) { + try { + deployParticipant.deploy(repositorySystemSession, deployRequest); + } catch (DeploymentException e) { + throw new MojoExecutionException(e.getMessage(), e); + } + } else { + getLog().info("Will deploy " + project.getGroupId() + ":" + project.getArtifactId() + ":" + + project.getVersion() + " at the end of build"); + deployParticipant.deployAtEnd(deployRequest); + } } // - // Attached artifacts + // All this logic about finding the right repository needs to be standardized // - for (org.apache.maven.artifact.Artifact attachedArtifact : project.getAttachedArtifacts()) { - deployRequest.addArtifact(AetherUtils.toArtifact(attachedArtifact)); + public RemoteRepository remoteRepository(MavenProject project) throws MojoExecutionException { + if (altDeploymentRepository != null) { + Matcher matcher = Pattern.compile("(.+)::(.+)::(.+)").matcher(altDeploymentRepository); + if (!matcher.matches()) { + throw new MojoExecutionException( + altDeploymentRepository, + "Invalid syntax for repository.", + "Invalid syntax for alternative repository. Use \"id::layout::url\"."); + } + + String id = matcher.group(1).trim(); + String layout = matcher.group(2).trim(); + String url = matcher.group(3).trim(); + + RemoteRepository.Builder builder = new RemoteRepository.Builder(id, layout, url); + + // Retrieve the appropriate authentication + final AuthenticationSelector authenticationSelector = repositorySystemSession.getAuthenticationSelector(); + final Authentication authentication = authenticationSelector.getAuthentication(builder.build()); + builder.setAuthentication(authentication); + + return builder.build(); + } + + return AetherUtils.toRepo(project.getDistributionManagementArtifactRepository()); } - - deployRequest.setRepository(remoteRepository(project)); - - if (!deployAtEnd) { - try { - deployParticipant.deploy(repositorySystemSession, deployRequest); - } catch (DeploymentException e) { - throw new MojoExecutionException(e.getMessage(), e); - } - } else { - getLog().info("Will deploy " + project.getGroupId() + ":" + project.getArtifactId() + ":" + project.getVersion() + " at the end of build"); - deployParticipant.deployAtEnd(deployRequest); - } - } - - // - // All this logic about finding the right repository needs to be standardized - // - public RemoteRepository remoteRepository(MavenProject project) throws MojoExecutionException { - if (altDeploymentRepository != null) { - Matcher matcher = Pattern.compile("(.+)::(.+)::(.+)").matcher(altDeploymentRepository); - if (!matcher.matches()) { - throw new MojoExecutionException(altDeploymentRepository, "Invalid syntax for repository.", "Invalid syntax for alternative repository. Use \"id::layout::url\"."); - } - - String id = matcher.group(1).trim(); - String layout = matcher.group(2).trim(); - String url = matcher.group(3).trim(); - - RemoteRepository.Builder builder = new RemoteRepository.Builder(id, layout, url); - - // Retrieve the appropriate authentication - final AuthenticationSelector authenticationSelector = repositorySystemSession.getAuthenticationSelector(); - final Authentication authentication = authenticationSelector.getAuthentication(builder.build()); - builder.setAuthentication(authentication); - - return builder.build(); - } - - return AetherUtils.toRepo(project.getDistributionManagementArtifactRepository()); - } } diff --git a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/Install.java b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/Install.java index 56e68050..449aa3e6 100644 --- a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/Install.java +++ b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/Install.java @@ -1,14 +1,13 @@ -/** - * Copyright (c) 2014 Takari, Inc. +/* + * Copyright (c) 2014-2024 Takari, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * https://www.eclipse.org/legal/epl-v10.html */ package io.takari.maven.plugins; import io.takari.maven.plugins.util.AetherUtils; - import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugins.annotations.LifecyclePhase; import org.apache.maven.plugins.annotations.Mojo; @@ -25,41 +24,41 @@ @Mojo(name = "install", defaultPhase = LifecyclePhase.INSTALL, configurator = "takari", threadSafe = true) public class Install extends TakariLifecycleMojo { - @Override - public void executeMojo() throws MojoExecutionException { - installProject(project); - } + @Override + public void executeMojo() throws MojoExecutionException { + installProject(project); + } - private void installProject(MavenProject project) throws MojoExecutionException { - InstallRequest installRequest = new InstallRequest(); + private void installProject(MavenProject project) throws MojoExecutionException { + InstallRequest installRequest = new InstallRequest(); - Artifact projectArtifact = AetherUtils.toArtifact(project.getArtifact()); - Artifact pomArtifact = new SubArtifact(projectArtifact, "", "pom"); - pomArtifact = pomArtifact.setFile(project.getFile()); + Artifact projectArtifact = AetherUtils.toArtifact(project.getArtifact()); + Artifact pomArtifact = new SubArtifact(projectArtifact, "", "pom"); + pomArtifact = pomArtifact.setFile(project.getFile()); - if (ArtifactIdUtils.equalsId(pomArtifact, projectArtifact)) { - if (isFile(projectArtifact.getFile())) { - pomArtifact = projectArtifact; - } - projectArtifact = null; - } + if (ArtifactIdUtils.equalsId(pomArtifact, projectArtifact)) { + if (isFile(projectArtifact.getFile())) { + pomArtifact = projectArtifact; + } + projectArtifact = null; + } - installRequest.addArtifact(pomArtifact); - if (projectArtifact != null) { - installRequest.addArtifact(projectArtifact); - } + installRequest.addArtifact(pomArtifact); + if (projectArtifact != null) { + installRequest.addArtifact(projectArtifact); + } - // - // Attached artifacts - // - for (org.apache.maven.artifact.Artifact attachedArtifact : project.getAttachedArtifacts()) { - installRequest.addArtifact(AetherUtils.toArtifact(attachedArtifact)); - } + // + // Attached artifacts + // + for (org.apache.maven.artifact.Artifact attachedArtifact : project.getAttachedArtifacts()) { + installRequest.addArtifact(AetherUtils.toArtifact(attachedArtifact)); + } - try { - repositorySystem.install(repositorySystemSession, installRequest); - } catch (InstallationException e) { - throw new MojoExecutionException(e.getMessage(), e); + try { + repositorySystem.install(repositorySystemSession, installRequest); + } catch (InstallationException e) { + throw new MojoExecutionException(e.getMessage(), e); + } } - } } diff --git a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/TakariLifecycleFlags.java b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/TakariLifecycleFlags.java index a1f147a8..136b5dd5 100644 --- a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/TakariLifecycleFlags.java +++ b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/TakariLifecycleFlags.java @@ -1,5 +1,12 @@ +/* + * Copyright (c) 2014-2024 Takari, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v10.html + */ package io.takari.maven.plugins; public interface TakariLifecycleFlags { - String ALTERNATE_LIFECYCLE_PROVIDING_PRIMARY_ARTIFACT = "@ALTERNATE_LIFECYCLE_PROVIDING_PRIMARY_ARTIFACT@"; + String ALTERNATE_LIFECYCLE_PROVIDING_PRIMARY_ARTIFACT = "@ALTERNATE_LIFECYCLE_PROVIDING_PRIMARY_ARTIFACT@"; } diff --git a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/TakariLifecycleMojo.java b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/TakariLifecycleMojo.java index e4381f05..e43b9fbf 100644 --- a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/TakariLifecycleMojo.java +++ b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/TakariLifecycleMojo.java @@ -1,17 +1,17 @@ -/** - * Copyright (c) 2014 Takari, Inc. +/* + * Copyright (c) 2014-2024 Takari, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * https://www.eclipse.org/legal/epl-v10.html */ package io.takari.maven.plugins; +import io.takari.incrementalbuild.Incremental; +import io.takari.incrementalbuild.Incremental.Configuration; import java.io.File; import java.util.List; - import javax.inject.Inject; - import org.apache.maven.execution.MavenSession; import org.apache.maven.plugin.AbstractMojo; import org.apache.maven.plugin.MojoExecution; @@ -27,9 +27,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import io.takari.incrementalbuild.Incremental; -import io.takari.incrementalbuild.Incremental.Configuration; - // integrate buildinfo: really this can't be packaged up in the JAR as it will prevent being // idempotent // how can we skip whole phases or at least be consistent @@ -41,79 +38,81 @@ // public abstract class TakariLifecycleMojo extends AbstractMojo { - protected final Logger logger = LoggerFactory.getLogger(getClass()); + protected final Logger logger = LoggerFactory.getLogger(getClass()); - @Inject - protected RepositorySystem repositorySystem; + @Inject + protected RepositorySystem repositorySystem; - @Inject - protected MavenProjectHelper projectHelper; + @Inject + protected MavenProjectHelper projectHelper; - @Parameter(defaultValue = "${project}", readonly = true) - @Incremental(configuration = Configuration.ignore) - protected MavenProject project; + @Parameter(defaultValue = "${project}", readonly = true) + @Incremental(configuration = Configuration.ignore) + protected MavenProject project; - @Parameter(defaultValue = "${session}") - @Incremental(configuration = Configuration.ignore) - private MavenSession session; + @Parameter(defaultValue = "${session}") + @Incremental(configuration = Configuration.ignore) + private MavenSession session; - @Parameter(defaultValue = "${reactorProjects}", readonly = true) - @Incremental(configuration = Configuration.ignore) - protected List reactorProjects; + @Parameter(defaultValue = "${reactorProjects}", readonly = true) + @Incremental(configuration = Configuration.ignore) + protected List reactorProjects; - @Parameter(defaultValue = "${repositorySystemSession}", readonly = true) - @Incremental(configuration = Configuration.ignore) - protected RepositorySystemSession repositorySystemSession; + @Parameter(defaultValue = "${repositorySystemSession}", readonly = true) + @Incremental(configuration = Configuration.ignore) + protected RepositorySystemSession repositorySystemSession; - @Parameter(defaultValue = "${project.remoteRepositories}", readonly = true) - @Incremental(configuration = Configuration.ignore) - protected List remoteRepositories; + @Parameter(defaultValue = "${project.remoteRepositories}", readonly = true) + @Incremental(configuration = Configuration.ignore) + protected List remoteRepositories; - @Parameter(defaultValue = "${mojoExecution}", readonly = true) - @Incremental(configuration = Configuration.ignore) - protected MojoExecution mojoExecution; + @Parameter(defaultValue = "${mojoExecution}", readonly = true) + @Incremental(configuration = Configuration.ignore) + protected MojoExecution mojoExecution; - @Parameter(defaultValue = "${mojoExecution.mojoDescriptor}", readonly = true) - @Incremental(configuration = Configuration.ignore) - protected MojoDescriptor mojoDescriptor; + @Parameter(defaultValue = "${mojoExecution.mojoDescriptor}", readonly = true) + @Incremental(configuration = Configuration.ignore) + protected MojoDescriptor mojoDescriptor; - @Parameter(defaultValue = "${settings}", readonly = true) - @Incremental(configuration = Configuration.ignore) - protected Settings settings; + @Parameter(defaultValue = "${settings}", readonly = true) + @Incremental(configuration = Configuration.ignore) + protected Settings settings; - @Parameter(defaultValue = "false", property = "skip") - @Incremental(configuration = Configuration.ignore) - protected boolean skip; + @Parameter(defaultValue = "false", property = "skip") + @Incremental(configuration = Configuration.ignore) + protected boolean skip; - protected abstract void executeMojo() throws MojoExecutionException; + protected abstract void executeMojo() throws MojoExecutionException; - protected void skipMojo() throws MojoExecutionException { - // do nothing by default - } + protected void skipMojo() throws MojoExecutionException { + // do nothing by default + } - @Override - public final void execute() throws MojoExecutionException { + @Override + public final void execute() throws MojoExecutionException { - // skip actually doesn't work here because it's on a per mojo basis + // skip actually doesn't work here because it's on a per mojo basis - if (skip) { - logger.info(String.format("Skipping %s goal", mojoDescriptor.getGoal())); - skipMojo(); - return; - } + if (skip) { + logger.info(String.format("Skipping %s goal", mojoDescriptor.getGoal())); + skipMojo(); + return; + } - executeMojo(); - } + executeMojo(); + } - protected boolean alternateLifecycleProvidingPrimaryArtifact() { - String alternateLifecycleProvidingPrimaryArtifact = session.getUserProperties().getProperty(TakariLifecycleFlags.ALTERNATE_LIFECYCLE_PROVIDING_PRIMARY_ARTIFACT); - if(alternateLifecycleProvidingPrimaryArtifact != null && alternateLifecycleProvidingPrimaryArtifact.equals("true")) { - return true; + protected boolean alternateLifecycleProvidingPrimaryArtifact() { + String alternateLifecycleProvidingPrimaryArtifact = session.getUserProperties() + .getProperty(TakariLifecycleFlags.ALTERNATE_LIFECYCLE_PROVIDING_PRIMARY_ARTIFACT); + if (alternateLifecycleProvidingPrimaryArtifact != null + && alternateLifecycleProvidingPrimaryArtifact.equals("true")) { + return true; + } + return false; } - return false; - } - protected boolean isFile(File file) { - return file != null && file.isFile(); - } + protected boolean isFile(File file) { + return file != null && file.isFile(); + } } diff --git a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/TakariLifecycles.java b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/TakariLifecycles.java index 8674e536..7f163937 100644 --- a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/TakariLifecycles.java +++ b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/TakariLifecycles.java @@ -1,24 +1,31 @@ +/* + * Copyright (c) 2014-2024 Takari, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v10.html + */ package io.takari.maven.plugins; public enum TakariLifecycles { - TAKARI_JAR("takari-jar"), - TAKARI_MAVEN_PLUGIN("takari-maven-plugin"), - TAKARI_MAVEN_COMPONENT("takari-maven-component"), - // while testing we're not setting any specific Takari lifecycle explicitly in our tests so many - // of the JAR Mojo tests fail because we now explicitly want one of the Takari lifecycles to make - // the JAR produced by the JAR Mojo the primary artifact. - TAKARI_TESTING("jar"); + TAKARI_JAR("takari-jar"), + TAKARI_MAVEN_PLUGIN("takari-maven-plugin"), + TAKARI_MAVEN_COMPONENT("takari-maven-component"), + // while testing we're not setting any specific Takari lifecycle explicitly in our tests so many + // of the JAR Mojo tests fail because we now explicitly want one of the Takari lifecycles to make + // the JAR produced by the JAR Mojo the primary artifact. + TAKARI_TESTING("jar"); - private String lifecycle; + private String lifecycle; - TakariLifecycles(String lifecycle) { - this.lifecycle = lifecycle; - } + TakariLifecycles(String lifecycle) { + this.lifecycle = lifecycle; + } - public static boolean isJarProducingTakariLifecycle(String lifecycle) { - return TAKARI_JAR.lifecycle.equals(lifecycle) - || TAKARI_MAVEN_PLUGIN.lifecycle.equals(lifecycle) - || TAKARI_MAVEN_COMPONENT.lifecycle.equals(lifecycle) - || TAKARI_TESTING.lifecycle.equals(lifecycle); - } + public static boolean isJarProducingTakariLifecycle(String lifecycle) { + return TAKARI_JAR.lifecycle.equals(lifecycle) + || TAKARI_MAVEN_PLUGIN.lifecycle.equals(lifecycle) + || TAKARI_MAVEN_COMPONENT.lifecycle.equals(lifecycle) + || TAKARI_TESTING.lifecycle.equals(lifecycle); + } } diff --git a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/AbstractCompileMojo.java b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/AbstractCompileMojo.java index 8b7dc338..8414160f 100644 --- a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/AbstractCompileMojo.java +++ b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/AbstractCompileMojo.java @@ -1,9 +1,9 @@ -/** - * Copyright (c) 2014 Takari, Inc. +/* + * Copyright (c) 2014-2024 Takari, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * https://www.eclipse.org/legal/epl-v10.html */ package io.takari.maven.plugins.compile; @@ -14,6 +14,18 @@ import io.takari.maven.plugins.compile.jdt.ClasspathEntryCache.CacheMode; import io.takari.maven.plugins.compile.jdt.CompilerJdt; import io.takari.maven.plugins.exportpackage.ExportPackageMojo; +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.util.*; +import java.util.stream.Collectors; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; +import javax.tools.JavaFileObject.Kind; import org.apache.maven.artifact.Artifact; import org.apache.maven.model.Dependency; import org.apache.maven.plugin.AbstractMojo; @@ -26,614 +38,623 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.tools.JavaFileObject.Kind; +public abstract class AbstractCompileMojo extends AbstractMojo { -import java.io.BufferedReader; -import java.io.File; -import java.io.IOException; -import java.io.InputStreamReader; -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.util.*; -import java.util.stream.Collectors; -import java.util.zip.ZipEntry; -import java.util.zip.ZipFile; + private static final String DEFAULT_COMPILER_LEVEL = "8"; + + // I much prefer slf4j over plexus logger api + private final Logger log = LoggerFactory.getLogger(getClass()); + + public static enum Proc { + proc, + only, + none, + + /** + * Same as {@link #proc} + * + * @deprecated use {@link #proc} + */ + procEX, + + /** + * Same as {@link #only} + * + * @deprecated use {@link #only} + */ + onlyEX + } -public abstract class AbstractCompileMojo extends AbstractMojo { + public static enum Debug { + all, + none, + source, + lines, + vars; + } - private static final String DEFAULT_COMPILER_LEVEL = "8"; + public static enum AccessRulesViolation { + error, + ignore; + } - // I much prefer slf4j over plexus logger api - private final Logger log = LoggerFactory.getLogger(getClass()); + public static enum Sourcepath { + disable, + reactorDependencies; + } - public static enum Proc { - proc, only, none, + /** + * The -encoding argument for the Java compiler. + */ + @Parameter(property = "encoding", defaultValue = "${project.build.sourceEncoding}") + private String encoding; /** - * Same as {@link #proc} - * - * @deprecated use {@link #proc} + * The -source argument for the Java compiler. */ - procEX, + @Parameter(property = "maven.compiler.source", defaultValue = DEFAULT_COMPILER_LEVEL) + private String source; /** - * Same as {@link #only} - * - * @deprecated use {@link #only} + * The -target argument for the Java compiler. The default depends on the value of {@code source} as defined in javac documentation. + * + * @see release argument for compiler - */ - @Parameter(property = "maven.compiler.release") - private String release; - - /** - * The compiler id of the compiler to use, one of {@code javac}, {@code forked-javac} or {@code jdt}. - */ - @Parameter(property = "maven.compiler.compilerId", defaultValue = "javac") - protected String compilerId; - - /** - * Initial size, in megabytes, of the memory allocation pool, ex. "64", "64m" if {{@code forked-javac} is used. - */ - @Parameter(property = "maven.compiler.meminitial") - private String meminitial; - - /** - * Sets the maximum size, in megabytes, of the memory allocation pool, ex. "128", "128m" if {{@code forked-javac} is used.. - */ - @Parameter(property = "maven.compiler.maxmem") - private String maxmem; - - /** - *

- * Sets whether annotation processing is performed or not. This parameter is required if annotation processors are present on compile classpath. - *

- *

- * Allowed values are: - *

- *
    - *
  • proc - both compilation and annotation processing are performed at the same time.
  • - *
  • none - no annotation processing is performed.
  • - *
  • only - only annotation processing is done, no compilation.
  • - *
- */ - @Parameter - protected Proc proc; - - /** - *

- * Names of annotation processors to run. If not set, the default annotation processors discovery process applies. - *

- */ - @Parameter - protected String[] annotationProcessors; - - /** - * Annotation processors options - */ - @Parameter - private Map annotationProcessorOptions; - - /** - * Set to true to show messages about what the compiler is doing. - */ - @Parameter(property = "maven.compiler.verbose", defaultValue = "false") - private boolean verbose; - - /** - * Set to true to store formal parameter names of constructors and methods in the generated class file so that the method java.lang.reflect.Executable.getParameters from the Reflection - * API can retrieve them. - */ - @Parameter(property = "maven.compiler.parameters", defaultValue = "false") - private boolean parameters; - - /** - * Sets whether generated class files include debug information or not. - *

- * Allowed values - *

    - *
  • all or true Generate all debugging information, including local variables. This is the default.
  • - *
  • none or false Do not generate any debugging information.
  • - *
  • Comma-separated list of - *
      - *
    • source Source file debugging information.
    • - *
    • lines Line number debugging information.
    • - *
    • vars Local variable debugging information.
    • - *
    - *
  • - *
- */ - @Parameter(property = "maven.compiler.debug", defaultValue = "all") - private String debug; - - /** - * Set to true to show compilation warnings. - */ - @Parameter(property = "maven.compiler.showWarnings", defaultValue = "false") - private boolean showWarnings; - - /** - * Sets "transitive dependency reference" policy violation action. - *

- * If {@code error}, only references to types defined in dependencies declared in project pom.xml file (or inherited from parent pom.xml) are allowed. References to types defined in transitive - * dependencies will be result in compilation errors. If {@code ignore} (the default) references to types defined in all project dependencies are allowed. - * - * @see The Takari Lifecycle documentation for more details - * @since 1.9 - */ - @Parameter(defaultValue = "ignore") - private AccessRulesViolation transitiveDependencyReference; - - /** - * Sets "private package reference" policy violation action. - *

- * If {@code error}, only references to types defined in dependency exported packages are allowed. References to types defined in private packages will be result in compilation errors. If - * {@code ignore} (the default) references to types in all packages are allowed. - * - * @see ExportPackageMojo - * @see The Takari Lifecycle documentation for more details - * @since 1.9 - */ - @Parameter(defaultValue = "ignore") - private AccessRulesViolation privatePackageReference; - - /** - * Controls compilation sourcepath. If set to {@code disable}, compilation sourcepath will be empty. If set to {@code reactorProjects}, compilation sourcepath will be set to compile source roots (or - * test compile source roots) of dependency projects of the same reactor build. The default is {@code reactorProjects} if {@code proc=only}, otherwise the default is {@code disable}. - * - *

- * The main usecase is {@code proc:only} annotation processing bound to generate-sources build phase. During {@code mvn clean generate-sources} execution, the reactor dependencies classes are not - * available and referenced types can only be resolved from java sources. - * - * @see documentation - * @since 1.12 - */ - @Parameter - protected Sourcepath sourcepath; - - // - - @Parameter(defaultValue = "${project.file}", readonly = true) - @Incremental(configuration = Configuration.ignore) - private File pom; - - @Parameter(defaultValue = "${project.basedir}", readonly = true) - @Incremental(configuration = Configuration.ignore) - private File basedir; - - @Parameter(defaultValue = "${project.build.directory}", readonly = true) - @Incremental(configuration = Configuration.ignore) - private File buildDirectory; - - @Parameter(defaultValue = "${plugin.pluginArtifact}", readonly = true) - @Incremental(configuration = Configuration.ignore) - private Artifact pluginArtifact; - - @Parameter(defaultValue = "${project.dependencyArtifacts}", readonly = true) - @Incremental(configuration = Configuration.ignore) - private Set directDependencies; - - @Parameter(defaultValue = "${project}", readonly = true) - @Incremental(configuration = Configuration.ignore) - protected MavenProject project; - - @Parameter(defaultValue = "${repositorySystemSession}", readonly = true) - @Incremental(configuration = Configuration.ignore) - protected RepositorySystemSession repositorySession; - - /** - * Indicates whether the build will continue even if there are compilation errors. - * - */ - @Parameter(property = "failOnError", defaultValue = "true") - protected boolean failOnError = true; - - /** - * Tells jdt compiler not to cache certain classpath/sourcepath elements which are subject to change in a dynamic environment (IDEs, for instance) - */ - @Parameter - protected boolean pessimisticClasspathCache; - - // - - @Component - private Map compilers; - - @Component - private CompilerBuildContext context; - - @Component - private ReactorProjects reactorProjects; - - @Component - private ProcessorpathResolver processorpathResolver; - - public Charset getSourceEncoding() { - return encoding == null ? null : Charset.forName(encoding); - } - - private List> getSources() throws IOException, MojoExecutionException { - List> sources = new ArrayList>(); - StringBuilder msg = new StringBuilder(); - for (String sourcePath : getSourceRoots()) { - File sourceRoot = new File(sourcePath); - msg.append("\n").append(sourcePath); - if (!sourceRoot.isDirectory()) { - msg.append("\n does not exist or not a directory, skiped"); - continue; - } - // TODO this is a bug in project model, includes/excludes should be per sourceRoot - Set includes = getIncludes(); - if (includes == null || includes.isEmpty()) { - includes = Collections.singleton("**/*.java"); - } else { - for (String include : includes) { - Set illegal = new LinkedHashSet<>(); - if (!include.endsWith(Kind.SOURCE.extension)) { - illegal.add(include); - } - if (!illegal.isEmpty()) { - throw new MojoExecutionException(String.format(" patterns must end with %s. Illegal patterns: %s", Kind.SOURCE.extension, illegal.toString())); - } - } - } - Set excludes = getExcludes(); - int sourceCount = 0; - for (ResourceMetadata source : context.registerSources(sourceRoot, includes, excludes)) { - sources.add(source); - sourceCount++; - } - if (log.isDebugEnabled()) { - msg.append("\n includes=").append(includes.toString()); - msg.append(" excludes=").append(excludes != null ? excludes.toString() : "[]"); - msg.append(" matched=").append(sourceCount); - } - } - if (log.isDebugEnabled()) { - log.debug("Compile source roots:{}", msg); - } - return sources; - } + @Parameter(property = "maven.compiler.target") + private String target; - protected Set getDirectDependencies() { - Set result = new LinkedHashSet<>(); - for (Artifact artofact : directDependencies) { - result.add(artofact.getFile()); - } - return result; - } + /** + * The --release argument for the Java compiler. + * @see release argument for compiler + */ + @Parameter(property = "maven.compiler.release") + private String release; - protected abstract Set getSourceRoots(); + /** + * The compiler id of the compiler to use, one of {@code javac}, {@code forked-javac} or {@code jdt}. + */ + @Parameter(property = "maven.compiler.compilerId", defaultValue = "javac") + protected String compilerId; - protected abstract Set getIncludes(); + /** + * Initial size, in megabytes, of the memory allocation pool, ex. "64", "64m" if {{@code forked-javac} is used. + */ + @Parameter(property = "maven.compiler.meminitial") + private String meminitial; - protected abstract Set getExcludes(); + /** + * Sets the maximum size, in megabytes, of the memory allocation pool, ex. "128", "128m" if {{@code forked-javac} is used.. + */ + @Parameter(property = "maven.compiler.maxmem") + private String maxmem; - protected abstract File getOutputDirectory(); + /** + *

+ * Sets whether annotation processing is performed or not. This parameter is required if annotation processors are present on compile classpath. + *

+ *

+ * Allowed values are: + *

+ *
    + *
  • proc - both compilation and annotation processing are performed at the same time.
  • + *
  • none - no annotation processing is performed.
  • + *
  • only - only annotation processing is done, no compilation.
  • + *
+ */ + @Parameter + protected Proc proc; - protected abstract List getClasspathArtifacts(); + /** + *

+ * Names of annotation processors to run. If not set, the default annotation processors discovery process applies. + *

+ */ + @Parameter + protected String[] annotationProcessors; - protected abstract File getGeneratedSourcesDirectory(); + /** + * Annotation processors options + */ + @Parameter + private Map annotationProcessorOptions; - protected abstract boolean isSkip(); + /** + * Set to true to show messages about what the compiler is doing. + */ + @Parameter(property = "maven.compiler.verbose", defaultValue = "false") + private boolean verbose; - protected abstract File getMainOutputDirectory(); + /** + * Set to true to store formal parameter names of constructors and methods in the generated class file so that the method java.lang.reflect.Executable.getParameters from the Reflection + * API can retrieve them. + */ + @Parameter(property = "maven.compiler.parameters", defaultValue = "false") + private boolean parameters; - protected abstract Set getMainSourceRoots(); + /** + * Sets whether generated class files include debug information or not. + *

+ * Allowed values + *

    + *
  • all or true Generate all debugging information, including local variables. This is the default.
  • + *
  • none or false Do not generate any debugging information.
  • + *
  • Comma-separated list of + *
      + *
    • source Source file debugging information.
    • + *
    • lines Line number debugging information.
    • + *
    • vars Local variable debugging information.
    • + *
    + *
  • + *
+ */ + @Parameter(property = "maven.compiler.debug", defaultValue = "all") + private String debug; - protected abstract List getProcessorpathDependencies(); + /** + * Set to true to show compilation warnings. + */ + @Parameter(property = "maven.compiler.showWarnings", defaultValue = "false") + private boolean showWarnings; - @Override - public void execute() throws MojoExecutionException, MojoFailureException { + /** + * Sets "transitive dependency reference" policy violation action. + *

+ * If {@code error}, only references to types defined in dependencies declared in project pom.xml file (or inherited from parent pom.xml) are allowed. References to types defined in transitive + * dependencies will be result in compilation errors. If {@code ignore} (the default) references to types defined in all project dependencies are allowed. + * + * @see The Takari Lifecycle documentation for more details + * @since 1.9 + */ + @Parameter(defaultValue = "ignore") + private AccessRulesViolation transitiveDependencyReference; - long started = System.currentTimeMillis(); - context.setFailOnError(failOnError); - if (isSkip()) { - log.info("Skipping compilation"); - context.markSkipExecution(); - return; - } + /** + * Sets "private package reference" policy violation action. + *

+ * If {@code error}, only references to types defined in dependency exported packages are allowed. References to types defined in private packages will be result in compilation errors. If + * {@code ignore} (the default) references to types in all packages are allowed. + * + * @see ExportPackageMojo + * @see The Takari Lifecycle documentation for more details + * @since 1.9 + */ + @Parameter(defaultValue = "ignore") + private AccessRulesViolation privatePackageReference; + + /** + * Controls compilation sourcepath. If set to {@code disable}, compilation sourcepath will be empty. If set to {@code reactorProjects}, compilation sourcepath will be set to compile source roots (or + * test compile source roots) of dependency projects of the same reactor build. The default is {@code reactorProjects} if {@code proc=only}, otherwise the default is {@code disable}. + * + *

+ * The main usecase is {@code proc:only} annotation processing bound to generate-sources build phase. During {@code mvn clean generate-sources} execution, the reactor dependencies classes are not + * available and referenced types can only be resolved from java sources. + * + * @see documentation + * @since 1.12 + */ + @Parameter + protected Sourcepath sourcepath; + + // + + @Parameter(defaultValue = "${project.file}", readonly = true) + @Incremental(configuration = Configuration.ignore) + private File pom; + + @Parameter(defaultValue = "${project.basedir}", readonly = true) + @Incremental(configuration = Configuration.ignore) + private File basedir; + + @Parameter(defaultValue = "${project.build.directory}", readonly = true) + @Incremental(configuration = Configuration.ignore) + private File buildDirectory; + + @Parameter(defaultValue = "${plugin.pluginArtifact}", readonly = true) + @Incremental(configuration = Configuration.ignore) + private Artifact pluginArtifact; + + @Parameter(defaultValue = "${project.dependencyArtifacts}", readonly = true) + @Incremental(configuration = Configuration.ignore) + private Set directDependencies; + + @Parameter(defaultValue = "${project}", readonly = true) + @Incremental(configuration = Configuration.ignore) + protected MavenProject project; + + @Parameter(defaultValue = "${repositorySystemSession}", readonly = true) + @Incremental(configuration = Configuration.ignore) + protected RepositorySystemSession repositorySession; + + /** + * Indicates whether the build will continue even if there are compilation errors. + * + */ + @Parameter(property = "failOnError", defaultValue = "true") + protected boolean failOnError = true; + + /** + * Tells jdt compiler not to cache certain classpath/sourcepath elements which are subject to change in a dynamic environment (IDEs, for instance) + */ + @Parameter + protected boolean pessimisticClasspathCache; + + // + + @Component + private Map compilers; + + @Component + private CompilerBuildContext context; - final AbstractCompiler compiler = compilers.get(compilerId); - if (compiler == null) { - throw new MojoExecutionException("Unsupported compilerId" + compilerId); + @Component + private ReactorProjects reactorProjects; + + @Component + private ProcessorpathResolver processorpathResolver; + + public Charset getSourceEncoding() { + return encoding == null ? null : Charset.forName(encoding); } - try { - final List> sources = getSources(); - - if (!sources.isEmpty()) { - mkdirs(getOutputDirectory()); - } - - final List classpath = getClasspath(); - final List processorpath = getProcessorpath(); - Proc proc = getEffectiveProc(classpath, processorpath); - - if (proc != Proc.none && !sources.isEmpty()) { - mkdirs(getGeneratedSourcesDirectory()); - } - - - compiler.setOutputDirectory(getOutputDirectory()); - compiler.setSource(source); - compiler.setTarget(getTarget(target, source)); - compiler.setRelease(release); - compiler.setProc(proc); - compiler.setGeneratedSourcesDirectory(getGeneratedSourcesDirectory()); - compiler.setAnnotationProcessors(annotationProcessors); - compiler.setAnnotationProcessorOptions(annotationProcessorOptions); - compiler.setVerbose(verbose); - compiler.setParameters(parameters); - compiler.setPom(pom); - compiler.setSourceEncoding(getSourceEncoding()); - compiler.setDebug(parseDebug(debug)); - compiler.setShowWarnings(showWarnings); - compiler.setTransitiveDependencyReference(transitiveDependencyReference); - compiler.setPrivatePackageReference(privatePackageReference); - - if (compiler instanceof CompilerJavacLauncher) { - ((CompilerJavacLauncher) compiler).setBasedir(basedir); - ((CompilerJavacLauncher) compiler).setJar(pluginArtifact.getFile()); - ((CompilerJavacLauncher) compiler).setBuildDirectory(buildDirectory); - ((CompilerJavacLauncher) compiler).setMeminitial(meminitial); - ((CompilerJavacLauncher) compiler).setMaxmem(maxmem); - } - - if (compiler instanceof CompilerJdt) { - if (pessimisticClasspathCache) { - ((CompilerJdt) compiler).setClasspathCacheMode(CacheMode.PESSIMISTIC); + private List> getSources() throws IOException, MojoExecutionException { + List> sources = new ArrayList>(); + StringBuilder msg = new StringBuilder(); + for (String sourcePath : getSourceRoots()) { + File sourceRoot = new File(sourcePath); + msg.append("\n").append(sourcePath); + if (!sourceRoot.isDirectory()) { + msg.append("\n does not exist or not a directory, skiped"); + continue; + } + // TODO this is a bug in project model, includes/excludes should be per sourceRoot + Set includes = getIncludes(); + if (includes == null || includes.isEmpty()) { + includes = Collections.singleton("**/*.java"); + } else { + for (String include : includes) { + Set illegal = new LinkedHashSet<>(); + if (!include.endsWith(Kind.SOURCE.extension)) { + illegal.add(include); + } + if (!illegal.isEmpty()) { + throw new MojoExecutionException(String.format( + " patterns must end with %s. Illegal patterns: %s", + Kind.SOURCE.extension, illegal.toString())); + } + } + } + Set excludes = getExcludes(); + int sourceCount = 0; + for (ResourceMetadata source : context.registerSources(sourceRoot, includes, excludes)) { + sources.add(source); + sourceCount++; + } + if (log.isDebugEnabled()) { + msg.append("\n includes=").append(includes.toString()); + msg.append(" excludes=").append(excludes != null ? excludes.toString() : "[]"); + msg.append(" matched=").append(sourceCount); + } } - } - - boolean sourcesChanged = compiler.setSources(sources); - boolean classpathChanged = compiler.setClasspath(classpath, getMainOutputDirectory(), getDirectDependencies()); - boolean sourcepathChanged = compiler.setSourcepath(getSourcepath(proc), toFileSet(getSourceRoots())); - boolean processorpathChanged = proc != Proc.none ? compiler.setProcessorpath(processorpath) : false; - - if (sourcesChanged || classpathChanged || sourcepathChanged || processorpathChanged) { - log.info("Compiling {} sources to {}", sources.size(), getOutputDirectory()); - int compiled = compiler.compile(); - log.info("Compiled {} out of {} sources ({} ms)", compiled, sources.size(), System.currentTimeMillis() - started); - } else { - compiler.skipCompile(); - log.info("Skipped compilation, all {} classes are up to date", sources.size()); - } - - if (proc != Proc.none && !sources.isEmpty()) { - addGeneratedSources(project); - } - - } catch (IOException e) { - throw new MojoExecutionException("Could not compile project", e); - } - } - - private static Set toFileSet(Set paths) { - Set files = new LinkedHashSet<>(); - paths.forEach(path -> files.add(new File(path))); - return files; - } - - private List getClasspath() { - List classpath = new ArrayList(); - for (Artifact artifact : getClasspathArtifacts()) { - File file = artifact.getFile(); - if (file != null) { - classpath.add(file); - } + if (log.isDebugEnabled()) { + log.debug("Compile source roots:{}", msg); + } + return sources; } - return classpath; - } - private List getSourcepath(Proc proc) throws MojoExecutionException { - if (sourcepath == Sourcepath.disable) { - return Collections.emptyList(); - } - if (sourcepath == null && proc != Proc.only) { - return Collections.emptyList(); + protected Set getDirectDependencies() { + Set result = new LinkedHashSet<>(); + for (Artifact artofact : directDependencies) { + result.add(artofact.getFile()); + } + return result; } - if (privatePackageReference != AccessRulesViolation.ignore) { - // dependency export-packages are calculated for classes folder, information is not available for source folders - throw new MojoExecutionException(" parameter is not compatible with "); + protected abstract Set getSourceRoots(); + + protected abstract Set getIncludes(); + + protected abstract Set getExcludes(); + + protected abstract File getOutputDirectory(); + + protected abstract List getClasspathArtifacts(); + + protected abstract File getGeneratedSourcesDirectory(); + + protected abstract boolean isSkip(); + + protected abstract File getMainOutputDirectory(); + + protected abstract Set getMainSourceRoots(); + + protected abstract List getProcessorpathDependencies(); + + @Override + public void execute() throws MojoExecutionException, MojoFailureException { + + long started = System.currentTimeMillis(); + context.setFailOnError(failOnError); + if (isSkip()) { + log.info("Skipping compilation"); + context.markSkipExecution(); + return; + } + + final AbstractCompiler compiler = compilers.get(compilerId); + if (compiler == null) { + throw new MojoExecutionException("Unsupported compilerId" + compilerId); + } + + try { + final List> sources = getSources(); + + if (!sources.isEmpty()) { + mkdirs(getOutputDirectory()); + } + + final List classpath = getClasspath(); + final List processorpath = getProcessorpath(); + Proc proc = getEffectiveProc(classpath, processorpath); + + if (proc != Proc.none && !sources.isEmpty()) { + mkdirs(getGeneratedSourcesDirectory()); + } + + compiler.setOutputDirectory(getOutputDirectory()); + compiler.setSource(source); + compiler.setTarget(getTarget(target, source)); + compiler.setRelease(release); + compiler.setProc(proc); + compiler.setGeneratedSourcesDirectory(getGeneratedSourcesDirectory()); + compiler.setAnnotationProcessors(annotationProcessors); + compiler.setAnnotationProcessorOptions(annotationProcessorOptions); + compiler.setVerbose(verbose); + compiler.setParameters(parameters); + compiler.setPom(pom); + compiler.setSourceEncoding(getSourceEncoding()); + compiler.setDebug(parseDebug(debug)); + compiler.setShowWarnings(showWarnings); + compiler.setTransitiveDependencyReference(transitiveDependencyReference); + compiler.setPrivatePackageReference(privatePackageReference); + + if (compiler instanceof CompilerJavacLauncher) { + ((CompilerJavacLauncher) compiler).setBasedir(basedir); + ((CompilerJavacLauncher) compiler).setJar(pluginArtifact.getFile()); + ((CompilerJavacLauncher) compiler).setBuildDirectory(buildDirectory); + ((CompilerJavacLauncher) compiler).setMeminitial(meminitial); + ((CompilerJavacLauncher) compiler).setMaxmem(maxmem); + } + + if (compiler instanceof CompilerJdt) { + if (pessimisticClasspathCache) { + ((CompilerJdt) compiler).setClasspathCacheMode(CacheMode.PESSIMISTIC); + } + } + + boolean sourcesChanged = compiler.setSources(sources); + boolean classpathChanged = + compiler.setClasspath(classpath, getMainOutputDirectory(), getDirectDependencies()); + boolean sourcepathChanged = compiler.setSourcepath(getSourcepath(proc), toFileSet(getSourceRoots())); + boolean processorpathChanged = proc != Proc.none ? compiler.setProcessorpath(processorpath) : false; + + if (sourcesChanged || classpathChanged || sourcepathChanged || processorpathChanged) { + log.info("Compiling {} sources to {}", sources.size(), getOutputDirectory()); + int compiled = compiler.compile(); + log.info( + "Compiled {} out of {} sources ({} ms)", + compiled, + sources.size(), + System.currentTimeMillis() - started); + } else { + compiler.skipCompile(); + log.info("Skipped compilation, all {} classes are up to date", sources.size()); + } + + if (proc != Proc.none && !sources.isEmpty()) { + addGeneratedSources(project); + } + + } catch (IOException e) { + throw new MojoExecutionException("Could not compile project", e); + } } - Set sourcepath = new LinkedHashSet<>(); - for (String sourceRoot : getSourceRoots()) { - addIfExists(sourcepath, sourceRoot); + private static Set toFileSet(Set paths) { + Set files = new LinkedHashSet<>(); + paths.forEach(path -> files.add(new File(path))); + return files; } - for (String sourceRoot : getMainSourceRoots()) { - addIfExists(sourcepath, sourceRoot); + + private List getClasspath() { + List classpath = new ArrayList(); + for (Artifact artifact : getClasspathArtifacts()) { + File file = artifact.getFile(); + if (file != null) { + classpath.add(file); + } + } + return classpath; } - List unsupportedDependencies = new ArrayList<>(); - for (Artifact artifact : getClasspathArtifacts()) { - MavenProject other = reactorProjects.get(artifact); - if (other != null) { - if (artifact.getClassifier() != null && !"tests".equals(artifact.getClassifier())) { - // generally, can't tell anything about classified artifacts - unsupportedDependencies.add(artifact); - } else { - // TODO assert encoding is the same - for (String sourceRoot : getSourceRoots(other, artifact)) { + + private List getSourcepath(Proc proc) throws MojoExecutionException { + if (sourcepath == Sourcepath.disable) { + return Collections.emptyList(); + } + if (sourcepath == null && proc != Proc.only) { + return Collections.emptyList(); + } + + if (privatePackageReference != AccessRulesViolation.ignore) { + // dependency export-packages are calculated for classes folder, information is not available for source + // folders + throw new MojoExecutionException(" parameter is not compatible with "); + } + + Set sourcepath = new LinkedHashSet<>(); + for (String sourceRoot : getSourceRoots()) { addIfExists(sourcepath, sourceRoot); - } } - } - } + for (String sourceRoot : getMainSourceRoots()) { + addIfExists(sourcepath, sourceRoot); + } + List unsupportedDependencies = new ArrayList<>(); + for (Artifact artifact : getClasspathArtifacts()) { + MavenProject other = reactorProjects.get(artifact); + if (other != null) { + if (artifact.getClassifier() != null && !"tests".equals(artifact.getClassifier())) { + // generally, can't tell anything about classified artifacts + unsupportedDependencies.add(artifact); + } else { + // TODO assert encoding is the same + for (String sourceRoot : getSourceRoots(other, artifact)) { + addIfExists(sourcepath, sourceRoot); + } + } + } + } - if (!unsupportedDependencies.isEmpty()) { - throw new MojoExecutionException("Unsupported classified reactor dependencies: " + unsupportedDependencies); - } + if (!unsupportedDependencies.isEmpty()) { + throw new MojoExecutionException( + "Unsupported classified reactor dependencies: " + unsupportedDependencies); + } - if (log.isDebugEnabled()) { - StringBuilder msg = new StringBuilder(); - for (File element : sourcepath) { - msg.append("\n   ").append(element.getAbsolutePath()); - } - log.debug("Compile sourcepath: {} entries{}", sourcepath.size(), msg.toString()); - } + if (log.isDebugEnabled()) { + StringBuilder msg = new StringBuilder(); + for (File element : sourcepath) { + msg.append("\n   ").append(element.getAbsolutePath()); + } + log.debug("Compile sourcepath: {} entries{}", sourcepath.size(), msg.toString()); + } - return Collections.unmodifiableList(new ArrayList<>(sourcepath)); - } + return Collections.unmodifiableList(new ArrayList<>(sourcepath)); + } - private static void addIfExists(Set sourcepath, String path) { - File file = new File(path); - if (file.exists()) { - sourcepath.add(file); + private static void addIfExists(Set sourcepath, String path) { + File file = new File(path); + if (file.exists()) { + sourcepath.add(file); + } } - } - - private Collection getSourceRoots(MavenProject other, Artifact artifact) { - Set sourceRoots = new LinkedHashSet<>(); - // always add main sources, they may be needed to resolve types referenced from test-jar dependencies - // TODO does this mean testCompile sourcepath is wider than classpath in some cases? - sourceRoots.addAll(other.getCompileSourceRoots()); - if ("test-jar".equals(artifact.getType())) { - sourceRoots.addAll(other.getTestCompileSourceRoots()); + + private Collection getSourceRoots(MavenProject other, Artifact artifact) { + Set sourceRoots = new LinkedHashSet<>(); + // always add main sources, they may be needed to resolve types referenced from test-jar dependencies + // TODO does this mean testCompile sourcepath is wider than classpath in some cases? + sourceRoots.addAll(other.getCompileSourceRoots()); + if ("test-jar".equals(artifact.getType())) { + sourceRoots.addAll(other.getTestCompileSourceRoots()); + } + return sourceRoots; } - return sourceRoots; - } - - private Proc getEffectiveProc(List classpath, List processorpath) { - Proc proc = this.proc; - if (proc == null) { - Map> processors = new TreeMap<>(); - for (File jar : processorpath != null ? processorpath : classpath) { - if (jar.isFile()) { - try (ZipFile zip = new ZipFile(jar)) { - ZipEntry entry = zip.getEntry("META-INF/services/javax.annotation.processing.Processor"); - if (entry != null) { - try (BufferedReader r = new BufferedReader(new InputStreamReader(zip.getInputStream(entry), StandardCharsets.UTF_8))) { - List lines = r.lines().collect(Collectors.toList()); - if (!lines.isEmpty()) { - processors.computeIfAbsent( jar, k -> new ArrayList<>() ).addAll(lines); + + private Proc getEffectiveProc(List classpath, List processorpath) { + Proc proc = this.proc; + if (proc == null) { + Map> processors = new TreeMap<>(); + for (File jar : processorpath != null ? processorpath : classpath) { + if (jar.isFile()) { + try (ZipFile zip = new ZipFile(jar)) { + ZipEntry entry = zip.getEntry("META-INF/services/javax.annotation.processing.Processor"); + if (entry != null) { + try (BufferedReader r = new BufferedReader( + new InputStreamReader(zip.getInputStream(entry), StandardCharsets.UTF_8))) { + List lines = r.lines().collect(Collectors.toList()); + if (!lines.isEmpty()) { + processors + .computeIfAbsent(jar, k -> new ArrayList<>()) + .addAll(lines); + } + } + } + } catch (IOException e) { + // ignore, compiler won't be able to use this jar either + } + } else if (jar.isDirectory()) { + try { + List lines = Files.readAllLines( + new File(jar, "META-INF/services/javax.annotation.processing.Processor").toPath(), + StandardCharsets.UTF_8); + if (!lines.isEmpty()) { + processors + .computeIfAbsent(jar, k -> new ArrayList<>()) + .addAll(lines); + } + } catch (IOException e) { + // ignore, compiler won't be able to use this jar either + } } - } } - } catch (IOException e) { - // ignore, compiler won't be able to use this jar either - } - } else if (jar.isDirectory()) { - try { - List lines = Files.readAllLines( - new File( jar, "META-INF/services/javax.annotation.processing.Processor" ).toPath(), StandardCharsets.UTF_8); - if (!lines.isEmpty()) { - processors.computeIfAbsent( jar, k -> new ArrayList<>() ).addAll(lines); + if (!processors.isEmpty()) { + StringBuilder msg = + new StringBuilder(" must be one of 'none', 'only' or 'proc'. Processors found: "); + for (File jar : processors.keySet()) { + msg.append("\n ").append(jar).append(" ").append(processors.get(jar)); + } + throw new IllegalArgumentException(msg.toString()); } - } catch (IOException e) { - // ignore, compiler won't be able to use this jar either - } + proc = Proc.none; } - } - if (!processors.isEmpty()) { - StringBuilder msg = new StringBuilder(" must be one of 'none', 'only' or 'proc'. Processors found: "); - for (File jar : processors.keySet()) { - msg.append("\n ").append(jar).append(" ").append(processors.get(jar)); + if (proc == Proc.procEX) { + log.warn("proc=procEX is deprecated, use proc=proc."); + proc = Proc.proc; + } else if (proc == Proc.onlyEX) { + log.warn("proc=onlyEX is deprecated, use proc=only."); + proc = Proc.only; } - throw new IllegalArgumentException(msg.toString()); - } - proc = Proc.none; + return proc; } - if (proc == Proc.procEX) { - log.warn("proc=procEX is deprecated, use proc=proc."); - proc = Proc.proc; - } else if (proc == Proc.onlyEX) { - log.warn("proc=onlyEX is deprecated, use proc=only."); - proc = Proc.only; - } - return proc; - } - private static String getTarget(String target, String source) { - if (target != null) { - return target; - } - if (source != null) { - if ("1.2".equals(source) || "1.3".equals(source)) { - return "1.4"; - } - return source; - } - return DEFAULT_COMPILER_LEVEL; - } - - private static Set parseDebug(String debug) { - Set result = new HashSet(); - StringTokenizer st = new StringTokenizer(debug, ","); - while (st.hasMoreTokens()) { - String token = st.nextToken(); - Debug keyword; - if ("true".equalsIgnoreCase(token)) { - keyword = Debug.all; - } else if ("false".equalsIgnoreCase(token)) { - keyword = Debug.none; - } else { - keyword = Debug.valueOf(token); - } - result.add(keyword); + private static String getTarget(String target, String source) { + if (target != null) { + return target; + } + if (source != null) { + if ("1.2".equals(source) || "1.3".equals(source)) { + return "1.4"; + } + return source; + } + return DEFAULT_COMPILER_LEVEL; } - if (result.size() > 1 && (result.contains(Debug.all) || result.contains(Debug.none))) { - throw new IllegalArgumentException("'all' and 'none' must be used alone: " + debug); + + private static Set parseDebug(String debug) { + Set result = new HashSet(); + StringTokenizer st = new StringTokenizer(debug, ","); + while (st.hasMoreTokens()) { + String token = st.nextToken(); + Debug keyword; + if ("true".equalsIgnoreCase(token)) { + keyword = Debug.all; + } else if ("false".equalsIgnoreCase(token)) { + keyword = Debug.none; + } else { + keyword = Debug.valueOf(token); + } + result.add(keyword); + } + if (result.size() > 1 && (result.contains(Debug.all) || result.contains(Debug.none))) { + throw new IllegalArgumentException("'all' and 'none' must be used alone: " + debug); + } + return result; } - return result; - } - private File mkdirs(File dir) throws MojoExecutionException { - if (!dir.isDirectory() && !dir.mkdirs()) { - throw new MojoExecutionException("Could not create directory " + dir); + private File mkdirs(File dir) throws MojoExecutionException { + if (!dir.isDirectory() && !dir.mkdirs()) { + throw new MojoExecutionException("Could not create directory " + dir); + } + return dir; } - return dir; - } - - /** - * Returns possibly empty list of explicitly specified processorpath entries. Returns {@code null} if the project classpath should be searched for annotation processors. - */ - protected List getProcessorpath() throws MojoExecutionException { - List dependencies = getProcessorpathDependencies(); - if (dependencies == null) { - return null; + + /** + * Returns possibly empty list of explicitly specified processorpath entries. Returns {@code null} if the project classpath should be searched for annotation processors. + */ + protected List getProcessorpath() throws MojoExecutionException { + List dependencies = getProcessorpathDependencies(); + if (dependencies == null) { + return null; + } + return processorpathResolver.resolve(repositorySession, project, dependencies); } - return processorpathResolver.resolve(repositorySession, project, dependencies); - } - protected abstract void addGeneratedSources(MavenProject project); + protected abstract void addGeneratedSources(MavenProject project); } diff --git a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/AbstractCompiler.java b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/AbstractCompiler.java index 90367aaa..4970a4be 100644 --- a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/AbstractCompiler.java +++ b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/AbstractCompiler.java @@ -1,210 +1,209 @@ -/** - * Copyright (c) 2014 Takari, Inc. +/* + * Copyright (c) 2014-2024 Takari, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * https://www.eclipse.org/legal/epl-v10.html */ package io.takari.maven.plugins.compile; +import io.takari.incrementalbuild.ResourceMetadata; +import io.takari.maven.plugins.compile.AbstractCompileMojo.AccessRulesViolation; +import io.takari.maven.plugins.compile.AbstractCompileMojo.Debug; +import io.takari.maven.plugins.compile.AbstractCompileMojo.Proc; import java.io.File; import java.io.IOException; import java.nio.charset.Charset; import java.util.List; import java.util.Map; import java.util.Set; - import org.apache.maven.plugin.MojoExecutionException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import io.takari.incrementalbuild.ResourceMetadata; -import io.takari.maven.plugins.compile.AbstractCompileMojo.AccessRulesViolation; -import io.takari.maven.plugins.compile.AbstractCompileMojo.Debug; -import io.takari.maven.plugins.compile.AbstractCompileMojo.Proc; - public abstract class AbstractCompiler { - protected final Logger log = LoggerFactory.getLogger(getClass()); - - protected final CompilerBuildContext context; + protected final Logger log = LoggerFactory.getLogger(getClass()); - private File outputDirectory; + protected final CompilerBuildContext context; - private String source; + private File outputDirectory; - private String target; + private String source; - private String release; + private String target; - private Proc proc; + private String release; - private File generatedSourcesDirectory; + private Proc proc; - private String[] annotationProcessors; + private File generatedSourcesDirectory; - private boolean verbose; + private String[] annotationProcessors; - private boolean parameters; + private boolean verbose; - private File pom; + private boolean parameters; - private Charset sourceEncoding; + private File pom; - private Map annotationProcessorOptions; + private Charset sourceEncoding; - private Set debug; + private Map annotationProcessorOptions; - private boolean showWarnings; + private Set debug; - private AccessRulesViolation transitiveDependencyReference; + private boolean showWarnings; - private AccessRulesViolation privatePackageReference; + private AccessRulesViolation transitiveDependencyReference; - protected AbstractCompiler(CompilerBuildContext context) { - this.context = context; - } + private AccessRulesViolation privatePackageReference; - public void setOutputDirectory(File outputDirectory) { - this.outputDirectory = outputDirectory; - } + protected AbstractCompiler(CompilerBuildContext context) { + this.context = context; + } - protected File getOutputDirectory() { - return outputDirectory; - }; + public void setOutputDirectory(File outputDirectory) { + this.outputDirectory = outputDirectory; + } - public void setSource(String source) { - this.source = source; - } + protected File getOutputDirectory() { + return outputDirectory; + } + ; - protected String getSource() { - return source; - } + public void setSource(String source) { + this.source = source; + } - public void setTarget(String target) { - this.target = target; - } + protected String getSource() { + return source; + } - protected String getTarget() { - return target; - } + public void setTarget(String target) { + this.target = target; + } - public String getRelease() { - return release; - } + protected String getTarget() { + return target; + } - public void setRelease(String release) { - this.release = release; - } + public String getRelease() { + return release; + } - public void setProc(Proc proc) { - this.proc = proc; - } + public void setRelease(String release) { + this.release = release; + } - public void setDebug(Set debug) { - this.debug = debug; - } + public void setProc(Proc proc) { + this.proc = proc; + } - protected Set getDebug() { - return debug; - } + public void setDebug(Set debug) { + this.debug = debug; + } - protected Proc getProc() { - return proc; - } + protected Set getDebug() { + return debug; + } - public void setGeneratedSourcesDirectory(File generatedSourcesDirectory) { - this.generatedSourcesDirectory = generatedSourcesDirectory; - } + protected Proc getProc() { + return proc; + } - protected File getGeneratedSourcesDirectory() { - return generatedSourcesDirectory; - } + public void setGeneratedSourcesDirectory(File generatedSourcesDirectory) { + this.generatedSourcesDirectory = generatedSourcesDirectory; + } - public void setAnnotationProcessors(String[] annotationProcessors) { - this.annotationProcessors = annotationProcessors; - } + protected File getGeneratedSourcesDirectory() { + return generatedSourcesDirectory; + } - protected String[] getAnnotationProcessors() { - return annotationProcessors; - } + public void setAnnotationProcessors(String[] annotationProcessors) { + this.annotationProcessors = annotationProcessors; + } - public void setAnnotationProcessorOptions(Map annotationProcessorOptions) { - this.annotationProcessorOptions = annotationProcessorOptions; - } + protected String[] getAnnotationProcessors() { + return annotationProcessors; + } - protected Map getAnnotationProcessorOptions() { - return annotationProcessorOptions; - } + public void setAnnotationProcessorOptions(Map annotationProcessorOptions) { + this.annotationProcessorOptions = annotationProcessorOptions; + } - public void setVerbose(boolean verbose) { - this.verbose = verbose; - } + protected Map getAnnotationProcessorOptions() { + return annotationProcessorOptions; + } - public void setParameters(boolean parameters) { - this.parameters = parameters; - } + public void setVerbose(boolean verbose) { + this.verbose = verbose; + } - public void setPrivatePackageReference(AccessRulesViolation privatePackageReference) { - this.privatePackageReference = privatePackageReference; - } + public void setParameters(boolean parameters) { + this.parameters = parameters; + } - public AccessRulesViolation getPrivatePackageReference() { - return privatePackageReference; - } + public void setPrivatePackageReference(AccessRulesViolation privatePackageReference) { + this.privatePackageReference = privatePackageReference; + } - protected AccessRulesViolation getTransitiveDependencyReference() { - return transitiveDependencyReference; - } + public AccessRulesViolation getPrivatePackageReference() { + return privatePackageReference; + } - public void setTransitiveDependencyReference(AccessRulesViolation transitiveDependencyReference) { - this.transitiveDependencyReference = transitiveDependencyReference; - } + protected AccessRulesViolation getTransitiveDependencyReference() { + return transitiveDependencyReference; + } - protected boolean isVerbose() { - return verbose; - } + public void setTransitiveDependencyReference(AccessRulesViolation transitiveDependencyReference) { + this.transitiveDependencyReference = transitiveDependencyReference; + } - protected boolean isParameters() { - return parameters; - } + protected boolean isVerbose() { + return verbose; + } - public void setPom(File pom) { - this.pom = pom; - } + protected boolean isParameters() { + return parameters; + } - protected File getPom() { - return pom; - } + public void setPom(File pom) { + this.pom = pom; + } - public void setSourceEncoding(Charset sourceEncoding) { - this.sourceEncoding = sourceEncoding; - } + protected File getPom() { + return pom; + } - protected Charset getSourceEncoding() { - return sourceEncoding; - } + public void setSourceEncoding(Charset sourceEncoding) { + this.sourceEncoding = sourceEncoding; + } - public void setShowWarnings(boolean showWarnings) { - this.showWarnings = showWarnings; - } + protected Charset getSourceEncoding() { + return sourceEncoding; + } - protected boolean isShowWarnings() { - return showWarnings; - } + public void setShowWarnings(boolean showWarnings) { + this.showWarnings = showWarnings; + } - public abstract boolean setProcessorpath(List processorpath) throws IOException; + protected boolean isShowWarnings() { + return showWarnings; + } - public abstract boolean setClasspath(List dependencies, File mainClasses, Set directDependencies) throws IOException; + public abstract boolean setProcessorpath(List processorpath) throws IOException; - public abstract boolean setSourcepath(List dependencies, Set sourceRoots) throws IOException; + public abstract boolean setClasspath(List dependencies, File mainClasses, Set directDependencies) + throws IOException; - public abstract boolean setSources(List> sources) throws IOException; + public abstract boolean setSourcepath(List dependencies, Set sourceRoots) throws IOException; - public abstract int compile() throws MojoExecutionException, IOException; + public abstract boolean setSources(List> sources) throws IOException; - public void skipCompile() { - context.markUptodateExecution(); - } + public abstract int compile() throws MojoExecutionException, IOException; + public void skipCompile() { + context.markUptodateExecution(); + } } diff --git a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/ArtifactFile.java b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/ArtifactFile.java index feaf5225..42c733c2 100644 --- a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/ArtifactFile.java +++ b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/ArtifactFile.java @@ -1,9 +1,9 @@ -/** - * Copyright (c) 2014 Takari, Inc. +/* + * Copyright (c) 2014-2024 Takari, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * https://www.eclipse.org/legal/epl-v10.html */ package io.takari.maven.plugins.compile; @@ -12,42 +12,42 @@ class ArtifactFile implements Serializable { - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 1L; - final File file; + final File file; - final boolean isFile; + final boolean isFile; - final long length; + final long length; - final long lastModified; + final long lastModified; - public ArtifactFile(File file, boolean isFile, long length, long lastModified) { - this.file = file; - this.isFile = isFile; - this.length = length; - this.lastModified = lastModified; - } + public ArtifactFile(File file, boolean isFile, long length, long lastModified) { + this.file = file; + this.isFile = isFile; + this.length = length; + this.lastModified = lastModified; + } - @Override - public int hashCode() { - return file.hashCode(); - } + @Override + public int hashCode() { + return file.hashCode(); + } - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof ArtifactFile)) { + return false; + } + ArtifactFile other = (ArtifactFile) obj; + return file.equals(other.file); } - if (!(obj instanceof ArtifactFile)) { - return false; + + @Override + public String toString() { + return file.toString(); } - ArtifactFile other = (ArtifactFile) obj; - return file.equals(other.file); - } - - @Override - public String toString() { - return file.toString(); - } } diff --git a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/ArtifactFileHolder.java b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/ArtifactFileHolder.java index 672bfa29..447f9061 100644 --- a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/ArtifactFileHolder.java +++ b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/ArtifactFileHolder.java @@ -1,9 +1,9 @@ -/** - * Copyright (c) 2014 Takari, Inc. +/* + * Copyright (c) 2014-2024 Takari, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * https://www.eclipse.org/legal/epl-v10.html */ package io.takari.maven.plugins.compile; @@ -12,33 +12,33 @@ class ArtifactFileHolder implements ResourceHolder { - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 1L; - private final ArtifactFile artifact; + private final ArtifactFile artifact; - public ArtifactFileHolder(ArtifactFile artifact) { - this.artifact = artifact; - } - - @Override - public ArtifactFile getResource() { - return artifact; - } + public ArtifactFileHolder(ArtifactFile artifact) { + this.artifact = artifact; + } - @Override - public ResourceStatus getStatus() { - // dependency changes are handled with in ProjectClasspathDigester - return ResourceStatus.UNMODIFIED; - } + @Override + public ArtifactFile getResource() { + return artifact; + } - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; + @Override + public ResourceStatus getStatus() { + // dependency changes are handled with in ProjectClasspathDigester + return ResourceStatus.UNMODIFIED; } - if (!(obj instanceof ArtifactFileHolder)) { - return false; + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof ArtifactFileHolder)) { + return false; + } + return artifact.equals(((ArtifactFileHolder) obj).artifact); } - return artifact.equals(((ArtifactFileHolder) obj).artifact); - } } diff --git a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/CompileMojo.java b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/CompileMojo.java index 24660601..9340de41 100644 --- a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/CompileMojo.java +++ b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/CompileMojo.java @@ -1,19 +1,20 @@ -/** - * Copyright (c) 2014 Takari, Inc. +/* + * Copyright (c) 2014-2024 Takari, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * https://www.eclipse.org/legal/epl-v10.html */ package io.takari.maven.plugins.compile; +import io.takari.incrementalbuild.Incremental; +import io.takari.incrementalbuild.Incremental.Configuration; import java.io.File; import java.util.Collections; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; - import org.apache.maven.artifact.Artifact; import org.apache.maven.model.Dependency; import org.apache.maven.plugins.annotations.LifecyclePhase; @@ -22,137 +23,139 @@ import org.apache.maven.plugins.annotations.ResolutionScope; import org.apache.maven.project.MavenProject; -import io.takari.incrementalbuild.Incremental; -import io.takari.incrementalbuild.Incremental.Configuration; - -@Mojo(name = "compile", defaultPhase = LifecyclePhase.COMPILE, threadSafe = true, requiresDependencyResolution = ResolutionScope.COMPILE, configurator = "takari") +@Mojo( + name = "compile", + defaultPhase = LifecyclePhase.COMPILE, + threadSafe = true, + requiresDependencyResolution = ResolutionScope.COMPILE, + configurator = "takari") public class CompileMojo extends AbstractCompileMojo { - /** - * The source directories containing the sources to be compiled. - */ - @Parameter(defaultValue = "${project.compileSourceRoots}", readonly = true, required = true) - private List compileSourceRoots; - - /** - * A list of inclusion filters for the compiler. - */ - @Parameter - private Set includes = new HashSet(); - - /** - * A list of exclusion filters for the compiler. - */ - @Parameter - private Set excludes = new HashSet(); - - /** - * Project classpath. - */ - @Parameter(defaultValue = "${project.compileArtifacts}", readonly = true, required = true) - @Incremental(configuration = Configuration.ignore) - private List compileArtifacts; - - /** - * The directory for compiled classes. - */ - @Parameter(defaultValue = "${project.build.outputDirectory}", required = true, readonly = true) - private File outputDirectory; - - /** - *

- * Specify where to place generated source files created by annotation processing. Only applies to JDK 1.6+ - *

- */ - @Parameter(defaultValue = "${project.build.directory}/generated-sources/annotations") - private File generatedSourcesDirectory; - - /** - * Set this to 'true' to bypass compilation of main sources. Its use is NOT RECOMMENDED, but quite convenient on occasion. - */ - @Parameter(property = "maven.main.skip") - @Incremental(configuration = Configuration.ignore) - private boolean skipMain; - - /** - * Processor path defines where to find annotation processors; if not configured, project classpath will be searched for processors. The primary usecase is to avoid unintentional "leakage" of - * build-time tools and their dependencies to production classpath. Additionally, separate processor path is likely to reduce number of incremental builds escalated due to annotation processing - * runtime path change. - * - *

- * Configuration uses the same syntax as project {@code }, and processor path is resolved using {@code compile+runtime} resolution scope. - * - *

- * To help align artifacts versions used by project classpath path and processor path: - *

    - *
  • Project {@code } is used during processor path resolution.
  • - *
  • If processor path dependency {@code } is omitted and project dependencies have artifact with matching (groupId,artifactId) tuple, the project dependency version will be used to - * resolve processor path.
  • - *
- * - * EXPERIMENTAL. This parameter is experimental and can be changed or removed without prior notice. - * - * @since 1.12.6 - */ - @Parameter - @Incremental(configuration = Configuration.ignore) - private List processorpath; - - @Override - public Set getSourceRoots() { - return new LinkedHashSet(compileSourceRoots); - } - - @Override - public Set getIncludes() { - return includes; - } - - @Override - public Set getExcludes() { - return excludes; - } - - @Override - public File getOutputDirectory() { - return outputDirectory; - } - - @Override - public List getClasspathArtifacts() { - return compileArtifacts; - } - - @Override - public File getGeneratedSourcesDirectory() { - return generatedSourcesDirectory; - } - - @Override - protected boolean isSkip() { - return skipMain; - } - - @Override - protected File getMainOutputDirectory() { - return null; // main compile does not have corresponding main classes directory - } - - @Override - protected void addGeneratedSources(MavenProject project) { - List roots = project.getCompileSourceRoots(); - String root = generatedSourcesDirectory.getAbsolutePath(); - if (!roots.contains(root)) { - roots.add(root); + /** + * The source directories containing the sources to be compiled. + */ + @Parameter(defaultValue = "${project.compileSourceRoots}", readonly = true, required = true) + private List compileSourceRoots; + + /** + * A list of inclusion filters for the compiler. + */ + @Parameter + private Set includes = new HashSet(); + + /** + * A list of exclusion filters for the compiler. + */ + @Parameter + private Set excludes = new HashSet(); + + /** + * Project classpath. + */ + @Parameter(defaultValue = "${project.compileArtifacts}", readonly = true, required = true) + @Incremental(configuration = Configuration.ignore) + private List compileArtifacts; + + /** + * The directory for compiled classes. + */ + @Parameter(defaultValue = "${project.build.outputDirectory}", required = true, readonly = true) + private File outputDirectory; + + /** + *

+ * Specify where to place generated source files created by annotation processing. Only applies to JDK 1.6+ + *

+ */ + @Parameter(defaultValue = "${project.build.directory}/generated-sources/annotations") + private File generatedSourcesDirectory; + + /** + * Set this to 'true' to bypass compilation of main sources. Its use is NOT RECOMMENDED, but quite convenient on occasion. + */ + @Parameter(property = "maven.main.skip") + @Incremental(configuration = Configuration.ignore) + private boolean skipMain; + + /** + * Processor path defines where to find annotation processors; if not configured, project classpath will be searched for processors. The primary usecase is to avoid unintentional "leakage" of + * build-time tools and their dependencies to production classpath. Additionally, separate processor path is likely to reduce number of incremental builds escalated due to annotation processing + * runtime path change. + * + *

+ * Configuration uses the same syntax as project {@code }, and processor path is resolved using {@code compile+runtime} resolution scope. + * + *

+ * To help align artifacts versions used by project classpath path and processor path: + *

    + *
  • Project {@code } is used during processor path resolution.
  • + *
  • If processor path dependency {@code } is omitted and project dependencies have artifact with matching (groupId,artifactId) tuple, the project dependency version will be used to + * resolve processor path.
  • + *
+ * + * EXPERIMENTAL. This parameter is experimental and can be changed or removed without prior notice. + * + * @since 1.12.6 + */ + @Parameter + @Incremental(configuration = Configuration.ignore) + private List processorpath; + + @Override + public Set getSourceRoots() { + return new LinkedHashSet(compileSourceRoots); + } + + @Override + public Set getIncludes() { + return includes; + } + + @Override + public Set getExcludes() { + return excludes; + } + + @Override + public File getOutputDirectory() { + return outputDirectory; } - } - @Override - protected Set getMainSourceRoots() { - return Collections.emptySet(); // main compile does not have corresponding main sources - } + @Override + public List getClasspathArtifacts() { + return compileArtifacts; + } + + @Override + public File getGeneratedSourcesDirectory() { + return generatedSourcesDirectory; + } + + @Override + protected boolean isSkip() { + return skipMain; + } + + @Override + protected File getMainOutputDirectory() { + return null; // main compile does not have corresponding main classes directory + } + + @Override + protected void addGeneratedSources(MavenProject project) { + List roots = project.getCompileSourceRoots(); + String root = generatedSourcesDirectory.getAbsolutePath(); + if (!roots.contains(root)) { + roots.add(root); + } + } - @Override - protected List getProcessorpathDependencies() { - return processorpath; - } + @Override + protected Set getMainSourceRoots() { + return Collections.emptySet(); // main compile does not have corresponding main sources + } + + @Override + protected List getProcessorpathDependencies() { + return processorpath; + } } diff --git a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/CompilerBuildContext.java b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/CompilerBuildContext.java index ab92e64c..4b710575 100644 --- a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/CompilerBuildContext.java +++ b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/CompilerBuildContext.java @@ -1,5 +1,22 @@ +/* + * Copyright (c) 2014-2024 Takari, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v10.html + */ package io.takari.maven.plugins.compile; +import io.takari.incrementalbuild.MessageSeverity; +import io.takari.incrementalbuild.Output; +import io.takari.incrementalbuild.Resource; +import io.takari.incrementalbuild.ResourceMetadata; +import io.takari.incrementalbuild.spi.AbstractBuildContext; +import io.takari.incrementalbuild.spi.BuildContextEnvironment; +import io.takari.incrementalbuild.spi.DefaultBuildContextState; +import io.takari.incrementalbuild.spi.DefaultOutput; +import io.takari.incrementalbuild.spi.DefaultResource; +import io.takari.incrementalbuild.spi.DefaultResourceMetadata; import java.io.File; import java.io.IOException; import java.io.Serializable; @@ -8,259 +25,250 @@ import java.util.HashMap; import java.util.List; import java.util.Map; - import javax.inject.Inject; import javax.inject.Named; - import org.apache.maven.execution.scope.MojoExecutionScoped; import org.apache.maven.project.MavenProject; -import io.takari.incrementalbuild.MessageSeverity; -import io.takari.incrementalbuild.Output; -import io.takari.incrementalbuild.Resource; -import io.takari.incrementalbuild.ResourceMetadata; -import io.takari.incrementalbuild.spi.AbstractBuildContext; -import io.takari.incrementalbuild.spi.BuildContextEnvironment; -import io.takari.incrementalbuild.spi.DefaultBuildContextState; -import io.takari.incrementalbuild.spi.DefaultOutput; -import io.takari.incrementalbuild.spi.DefaultResource; -import io.takari.incrementalbuild.spi.DefaultResourceMetadata; - - // TODO replace all Default* implementation types with corresponding API interfaces @Named @MojoExecutionScoped public class CompilerBuildContext extends AbstractBuildContext { - private final File pom; - - @Inject - public CompilerBuildContext(BuildContextEnvironment configuration, MavenProject project) { - super(configuration); - pom = project.getFile(); - } - - // - // overall build context management - // - - @Override - public void markSkipExecution() { - super.markSkipExecution(); - } - - /** - * Marks current build as up-to-date. All input and output resources and their corresponding metadata are carried-over to the next build as-is. All messages produced during previous build are - * replayed. - */ - public void markUptodateExecution() { - // TODO enforce context hasn't been modified yet. - - // copy output ResourceHolders from previous build. this has the same effect as input registration. - // the outputs will be considered up-to-date and all their metadata will be carried-over as-is - for (File outputFile : oldState.getOutputs()) { - markUptodateOutput(outputFile); + private final File pom; + + @Inject + public CompilerBuildContext(BuildContextEnvironment configuration, MavenProject project) { + super(configuration); + pom = project.getFile(); + } + + // + // overall build context management + // + + @Override + public void markSkipExecution() { + super.markSkipExecution(); + } + + /** + * Marks current build as up-to-date. All input and output resources and their corresponding metadata are carried-over to the next build as-is. All messages produced during previous build are + * replayed. + */ + public void markUptodateExecution() { + // TODO enforce context hasn't been modified yet. + + // copy output ResourceHolders from previous build. this has the same effect as input registration. + // the outputs will be considered up-to-date and all their metadata will be carried-over as-is + for (File outputFile : oldState.getOutputs()) { + markUptodateOutput(outputFile); + } + } + + @Override + public void markUptodateOutput(File outputFile) { + super.markUptodateOutput(outputFile); + } + + /** + * Adds messages associated with mojo execution in project pom.xml. This is useful to capture compiler failures, i.e. exception in the compiler itself. These messages are carried-over during + * no-changed rebuild and trigger build failures as expected. These messages are discarded during full or incremental build and must be recreated as needed. + */ + public void addPomMessage(String message, MessageSeverity severity, Throwable cause) { + // TODO execution line/column + super.addMessage(pom, 0, 0, message, severity, cause); + } + + @Override + public boolean isEscalated() { + return super.isEscalated(); + } + + /** + * Returns attribute value set at context-level, i.e. not associated with any particular resource, during previous build. + */ + public V getAttribute(String key, boolean previous, Class clazz) { + return super.getResourceAttribute(oldState, pom, key, clazz); } - } - - @Override - public void markUptodateOutput(File outputFile) { - super.markUptodateOutput(outputFile); - } - - /** - * Adds messages associated with mojo execution in project pom.xml. This is useful to capture compiler failures, i.e. exception in the compiler itself. These messages are carried-over during - * no-changed rebuild and trigger build failures as expected. These messages are discarded during full or incremental build and must be recreated as needed. - */ - public void addPomMessage(String message, MessageSeverity severity, Throwable cause) { - // TODO execution line/column - super.addMessage(pom, 0, 0, message, severity, cause); - } - - @Override - public boolean isEscalated() { - return super.isEscalated(); - } - - /** - * Returns attribute value set at context-level, i.e. not associated with any particular resource, during previous build. - */ - public V getAttribute(String key, boolean previous, Class clazz) { - return super.getResourceAttribute(oldState, pom, key, clazz); - } - - /** - * Sets context-level, i.e. not associated with any particular resource, key/value attribute. Context-level attributes are not automatically carried-over from one build to the next and must be - * explicitly set during each build. - */ - public Serializable setAttribute(String key, V value) { - return super.setResourceAttribute(pom, key, value); - } - - // - // sources tracking - // - - public Collection> registerSources(File basedir, Collection includes, Collection excludes) throws IOException { - return super.registerInputs(basedir, includes, excludes); - } - - /** - * Returns sources removed since previous build. Does not return generated sources. - */ - public Collection> getRemovedSources() { - Collection> sources = new ArrayList<>(); - for (Object resource : oldState.getResources().keySet()) { - if (isJavaSource(resource) && !oldState.isOutput(resource) && !isRegisteredResource(resource)) { - sources.add(newResourceMetadata(oldState, (File) resource)); - } + + /** + * Sets context-level, i.e. not associated with any particular resource, key/value attribute. Context-level attributes are not automatically carried-over from one build to the next and must be + * explicitly set during each build. + */ + public Serializable setAttribute(String key, V value) { + return super.setResourceAttribute(pom, key, value); + } + + // + // sources tracking + // + + public Collection> registerSources( + File basedir, Collection includes, Collection excludes) throws IOException { + return super.registerInputs(basedir, includes, excludes); + } + + /** + * Returns sources removed since previous build. Does not return generated sources. + */ + public Collection> getRemovedSources() { + Collection> sources = new ArrayList<>(); + for (Object resource : oldState.getResources().keySet()) { + if (isJavaSource(resource) && !oldState.isOutput(resource) && !isRegisteredResource(resource)) { + sources.add(newResourceMetadata(oldState, (File) resource)); + } + } + return sources; + } + + /** + * Returns original or generated source processed during this build. Throws {@link IllegalStateException} if no such source. + */ + public Resource getProcessedSource(File sourceFile) { + if (!isProcessedResource(sourceFile) || !isJavaSource(sourceFile)) { + // JDT may decide to compile more sources than it was asked to in some cases + // TODO investigate when this happens and decide what to do about it + throw new IllegalArgumentException(); + } + return newResource(sourceFile); + } + + /** + * Returns sources registered during this build. + */ + public Collection> getRegisteredSources() { + List> sources = new ArrayList<>(); + for (Object resource : state.getResources().keySet()) { + if (isJavaSource(resource)) { + DefaultBuildContextState state = isProcessedResource(resource) ? this.state : this.oldState; + sources.add(newResourceMetadata(state, (File) resource)); + } + } + return sources; + } + + public static boolean isJavaSource(Object resource) { + return resource instanceof File && ((File) resource).getName().endsWith(".java"); // TODO find proper constant + } + + public V getAttribute(File source, String key, Class clazz) { + return getResourceAttribute(getState(source), source, key, clazz); + } + + private DefaultBuildContextState getState(File source) { + return isProcessedResource(source) ? this.state : this.oldState; + } + + public Serializable setAttribute(File source, String key, V value) { + return setResourceAttribute(source, key, value); + } + + // + // output tracking + // + + /** + * Deletes all outputs registered with the build context + */ + public Collection> deleteOutputs() throws IOException { + List> deleted = new ArrayList<>(); + for (File outputFile : oldState.getOutputs()) { + deleteOutput(outputFile); + deleted.add(newResourceMetadata(oldState, outputFile)); + } + return deleted; + } + + /** + * Returns outputs directly or indirectly derived from the source. + */ + public Collection> getAssociatedOutputs(ResourceMetadata source) { + return addAssociatedOutputs(new HashMap>(), source) + .values(); + } + + @Override + protected Collection> getAssociatedOutputs( + DefaultBuildContextState state, Object resource) { + return super.getAssociatedOutputs(state, resource); } - return sources; - } - - /** - * Returns original or generated source processed during this build. Throws {@link IllegalStateException} if no such source. - */ - public Resource getProcessedSource(File sourceFile) { - if (!isProcessedResource(sourceFile) || !isJavaSource(sourceFile)) { - // JDT may decide to compile more sources than it was asked to in some cases - // TODO investigate when this happens and decide what to do about it - throw new IllegalArgumentException(); + + @SuppressWarnings("unchecked") + public Collection> getAssociatedOutputs(File source) { + return (Collection>) super.getAssociatedOutputs(getState(source), source); } - return newResource(sourceFile); - } - - /** - * Returns sources registered during this build. - */ - public Collection> getRegisteredSources() { - List> sources = new ArrayList<>(); - for (Object resource : state.getResources().keySet()) { - if (isJavaSource(resource)) { - DefaultBuildContextState state = isProcessedResource(resource) ? this.state : this.oldState; - sources.add(newResourceMetadata(state, (File) resource)); - } + + private Map> addAssociatedOutputs( + Map> outputs, ResourceMetadata resource) { + for (ResourceMetadata output : + super.getAssociatedOutputs(getState(resource.getResource()), resource.getResource())) { + if (!outputs.containsKey(output.getResource())) { + outputs.put(output.getResource(), output); + addAssociatedOutputs(outputs, output); + } + } + return outputs; } - return sources; - } - - public static boolean isJavaSource(Object resource) { - return resource instanceof File && ((File) resource).getName().endsWith(".java"); // TODO find proper constant - } - - public V getAttribute(File source, String key, Class clazz) { - return getResourceAttribute(getState(source), source, key, clazz); - } - - private DefaultBuildContextState getState(File source) { - return isProcessedResource(source) ? this.state : this.oldState; - } - - public Serializable setAttribute(File source, String key, V value) { - return setResourceAttribute(source, key, value); - } - - // - // output tracking - // - - /** - * Deletes all outputs registered with the build context - */ - public Collection> deleteOutputs() throws IOException { - List> deleted = new ArrayList<>(); - for (File outputFile : oldState.getOutputs()) { - deleteOutput(outputFile); - deleted.add(newResourceMetadata(oldState, outputFile)); + + @Override + public DefaultOutput processOutput(File outputFile) { + return super.processOutput(outputFile); } - return deleted; - } - - /** - * Returns outputs directly or indirectly derived from the source. - */ - public Collection> getAssociatedOutputs(ResourceMetadata source) { - return addAssociatedOutputs(new HashMap>(), source).values(); - } - - @Override - protected Collection> getAssociatedOutputs(DefaultBuildContextState state, Object resource) { - return super.getAssociatedOutputs(state, resource); - } - - @SuppressWarnings("unchecked") - public Collection> getAssociatedOutputs(File source) { - return (Collection>) super.getAssociatedOutputs(getState(source), source); - } - - private Map> addAssociatedOutputs(Map> outputs, ResourceMetadata resource) { - for (ResourceMetadata output : super.getAssociatedOutputs(getState(resource.getResource()), resource.getResource())) { - if (!outputs.containsKey(output.getResource())) { - outputs.put(output.getResource(), output); - addAssociatedOutputs(outputs, output); - } + + /** + * This method is similar to ResourceMetadata.process(), but discards state associated with the inputResource during each invocation. Useful when recompiling the same source multiple times during + * incremental build iterations. + */ + public Resource processInput(ResourceMetadata inputResource) { + super.processResource(inputResource.getResource()); + return inputResource.process(); } - return outputs; - } - - @Override - public DefaultOutput processOutput(File outputFile) { - return super.processOutput(outputFile); - } - - /** - * This method is similar to ResourceMetadata.process(), but discards state associated with the inputResource during each invocation. Useful when recompiling the same source multiple times during - * incremental build iterations. - */ - public Resource processInput(ResourceMetadata inputResource) { - super.processResource(inputResource.getResource()); - return inputResource.process(); - } - - @Override - public void deleteOutput(File outputFile) throws IOException { - super.deleteOutput(outputFile); - } - - public boolean isProcessedOutput(File outputFile) { - return state.isOutput(outputFile) && isProcessedResource(outputFile); - } - - public Output associatedOutput(Resource input, File outputFile) { - return input.associateOutput(outputFile); - } - - // - // context commit - // - - @Override - protected void assertAssociation(DefaultResource resource, DefaultOutput output) { - // allow any input/output association - } - - @Override - protected void finalizeContext() { - for (Object resource : oldState.getResources().keySet()) { - if (isProcessedResource(resource) || isDeletedResource(resource)) { - // known deleted or processed resource, nothing to carry over - continue; - } - - if (!oldState.isOutput(resource) && !state.isResource(resource)) { - // deleted or excluded source, nothing to carry over - continue; - } - - state.putResource(resource, oldState.getResource(resource)); - if (oldState.isOutput(resource)) { - state.addOutput((File) resource); - } - state.setResourceMessages(resource, oldState.getResourceMessages(resource)); - state.setResourceAttributes(resource, oldState.getResourceAttributes(resource)); - state.setResourceOutputs(resource, oldState.getResourceOutputs(resource)); - - // XXX inputs and outputs, which ones do we need here? + + @Override + public void deleteOutput(File outputFile) throws IOException { + super.deleteOutput(outputFile); + } + + public boolean isProcessedOutput(File outputFile) { + return state.isOutput(outputFile) && isProcessedResource(outputFile); + } + + public Output associatedOutput(Resource input, File outputFile) { + return input.associateOutput(outputFile); + } + + // + // context commit + // + + @Override + protected void assertAssociation(DefaultResource resource, DefaultOutput output) { + // allow any input/output association + } + + @Override + protected void finalizeContext() { + for (Object resource : oldState.getResources().keySet()) { + if (isProcessedResource(resource) || isDeletedResource(resource)) { + // known deleted or processed resource, nothing to carry over + continue; + } + + if (!oldState.isOutput(resource) && !state.isResource(resource)) { + // deleted or excluded source, nothing to carry over + continue; + } + + state.putResource(resource, oldState.getResource(resource)); + if (oldState.isOutput(resource)) { + state.addOutput((File) resource); + } + state.setResourceMessages(resource, oldState.getResourceMessages(resource)); + state.setResourceAttributes(resource, oldState.getResourceAttributes(resource)); + state.setResourceOutputs(resource, oldState.getResourceOutputs(resource)); + + // XXX inputs and outputs, which ones do we need here? + } } - } } diff --git a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/ProcessorpathResolver.java b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/ProcessorpathResolver.java index cbfe66e5..c0747b9e 100644 --- a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/ProcessorpathResolver.java +++ b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/ProcessorpathResolver.java @@ -1,9 +1,9 @@ -/** - * Copyright (c) 2017 Salesforce.com, Inc. +/* + * Copyright (c) 2014-2024 Takari, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * https://www.eclipse.org/legal/epl-v10.html */ package io.takari.maven.plugins.compile; @@ -12,10 +12,8 @@ import java.util.Collections; import java.util.List; import java.util.Map; - import javax.inject.Inject; import javax.inject.Named; - import org.apache.maven.RepositoryUtils; import org.apache.maven.artifact.Artifact; import org.apache.maven.artifact.ArtifactUtils; @@ -39,73 +37,77 @@ @Named class ProcessorpathResolver { - private final RepositorySystem aether; - - @Inject - public ProcessorpathResolver(RepositorySystem aether) { - this.aether = aether; - } - - public List resolve(RepositorySystemSession session, MavenProject project, List dependencies) throws MojoExecutionException { - // copy&paste from org.apache.maven.project.DefaultProjectDependenciesResolver.resolve(DependencyResolutionRequest) - // aether is sad, really sad - - ArtifactTypeRegistry stereotypes = session.getArtifactTypeRegistry(); - - CollectRequest collectRequest = new CollectRequest(); - collectRequest.setRootArtifact(RepositoryUtils.toArtifact(project.getArtifact())); - collectRequest.setRequestContext("project"); - collectRequest.setRepositories(project.getRemoteProjectRepositories()); - - Map artifacts = project.getArtifactMap(); - for (Dependency dependency : dependencies) { - String version = dependency.getVersion(); - if (version == null || version.isEmpty()) { - Artifact artifact = artifacts.get(ArtifactUtils.versionlessKey(dependency.getGroupId(), dependency.getArtifactId())); - if (artifact != null) { - dependency = dependency.clone(); - dependency.setVersion(artifact.getVersion()); - } - } - collectRequest.addDependency(RepositoryUtils.toDependency(dependency, stereotypes)); - } + private final RepositorySystem aether; - DependencyManagement depMngt = project.getDependencyManagement(); - if (depMngt != null) { - for (Dependency dependency : depMngt.getDependencies()) { - collectRequest.addManagedDependency(RepositoryUtils.toDependency(dependency, stereotypes)); - } + @Inject + public ProcessorpathResolver(RepositorySystem aether) { + this.aether = aether; } - DependencyFilter collectionFilter = new ScopeDependencyFilter(null, Collections.singleton("test")); - DependencyFilter resolutionFilter = new ScopeDependencyFilter(null, Collections.singleton("test")); - resolutionFilter = AndDependencyFilter.newInstance(collectionFilter, resolutionFilter); - - DependencyRequest depRequest = new DependencyRequest(collectRequest, resolutionFilter); - - try { - DependencyNode node = aether.collectDependencies(session, collectRequest).getRoot(); - depRequest.setRoot(node); - List processorpath = new ArrayList<>(); - List errors = new ArrayList<>(); - for (ArtifactResult artifactResult : aether.resolveDependencies(session, depRequest).getArtifactResults()) { - if (artifactResult.isResolved()) { - processorpath.add(artifactResult.getArtifact().getFile()); - } else { - errors.addAll(artifactResult.getExceptions()); + public List resolve(RepositorySystemSession session, MavenProject project, List dependencies) + throws MojoExecutionException { + // copy&paste from + // org.apache.maven.project.DefaultProjectDependenciesResolver.resolve(DependencyResolutionRequest) + // aether is sad, really sad + + ArtifactTypeRegistry stereotypes = session.getArtifactTypeRegistry(); + + CollectRequest collectRequest = new CollectRequest(); + collectRequest.setRootArtifact(RepositoryUtils.toArtifact(project.getArtifact())); + collectRequest.setRequestContext("project"); + collectRequest.setRepositories(project.getRemoteProjectRepositories()); + + Map artifacts = project.getArtifactMap(); + for (Dependency dependency : dependencies) { + String version = dependency.getVersion(); + if (version == null || version.isEmpty()) { + Artifact artifact = artifacts.get( + ArtifactUtils.versionlessKey(dependency.getGroupId(), dependency.getArtifactId())); + if (artifact != null) { + dependency = dependency.clone(); + dependency.setVersion(artifact.getVersion()); + } + } + collectRequest.addDependency(RepositoryUtils.toDependency(dependency, stereotypes)); } - } - if (!errors.isEmpty()) { - StringBuilder msg = new StringBuilder(); - errors.forEach(e -> msg.append(e.getMessage()).append(", ")); - throw new MojoExecutionException("Could not resolve processorpath: "); - } + DependencyManagement depMngt = project.getDependencyManagement(); + if (depMngt != null) { + for (Dependency dependency : depMngt.getDependencies()) { + collectRequest.addManagedDependency(RepositoryUtils.toDependency(dependency, stereotypes)); + } + } - return processorpath; - } catch (DependencyCollectionException | DependencyResolutionException e) { - throw new MojoExecutionException("Could not resolve processorpath: " + e.getMessage(), e); + DependencyFilter collectionFilter = new ScopeDependencyFilter(null, Collections.singleton("test")); + DependencyFilter resolutionFilter = new ScopeDependencyFilter(null, Collections.singleton("test")); + resolutionFilter = AndDependencyFilter.newInstance(collectionFilter, resolutionFilter); + + DependencyRequest depRequest = new DependencyRequest(collectRequest, resolutionFilter); + + try { + DependencyNode node = + aether.collectDependencies(session, collectRequest).getRoot(); + depRequest.setRoot(node); + List processorpath = new ArrayList<>(); + List errors = new ArrayList<>(); + for (ArtifactResult artifactResult : + aether.resolveDependencies(session, depRequest).getArtifactResults()) { + if (artifactResult.isResolved()) { + processorpath.add(artifactResult.getArtifact().getFile()); + } else { + errors.addAll(artifactResult.getExceptions()); + } + } + + if (!errors.isEmpty()) { + StringBuilder msg = new StringBuilder(); + errors.forEach(e -> msg.append(e.getMessage()).append(", ")); + throw new MojoExecutionException("Could not resolve processorpath: "); + } + + return processorpath; + } catch (DependencyCollectionException | DependencyResolutionException e) { + throw new MojoExecutionException("Could not resolve processorpath: " + e.getMessage(), e); + } } - } - } diff --git a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/ProjectClasspathDigester.java b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/ProjectClasspathDigester.java index e1cccaa2..64e3766a 100644 --- a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/ProjectClasspathDigester.java +++ b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/ProjectClasspathDigester.java @@ -1,9 +1,9 @@ -/** - * Copyright (c) 2014 Takari, Inc. +/* + * Copyright (c) 2014-2024 Takari, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * https://www.eclipse.org/legal/epl-v10.html */ package io.takari.maven.plugins.compile; @@ -17,10 +17,8 @@ import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; - import javax.inject.Inject; import javax.inject.Named; - import org.apache.maven.execution.scope.MojoExecutionScoped; import org.codehaus.plexus.util.DirectoryScanner; import org.slf4j.Logger; @@ -29,163 +27,173 @@ @Named @MojoExecutionScoped public class ProjectClasspathDigester { - private static final String ATTR_CLASSPATH_DIGEST = "compile.classpath.digest"; - private static final String ATTR_SOURCEPATH_DIGEST = "compile.sourcepath.digest"; - private static final String ATTR_PROCESSORPATH_DIGEST = "compile.processorpath.digest"; - - private final Logger log = LoggerFactory.getLogger(getClass()); - - private static final Map CACHE = new ConcurrentHashMap(); - - private final CompilerBuildContext context; - - @Inject - public ProjectClasspathDigester(CompilerBuildContext context) { - this.context = context; - } - - /** - * Detects if classpath dependencies changed compared to the previous build or not. - */ - public boolean digestClasspath(List dependencies) throws IOException { - return digest(ATTR_CLASSPATH_DIGEST, dependencies); - } - - public boolean digestSourcepath(List dependencies) throws IOException { - return digest(ATTR_SOURCEPATH_DIGEST, dependencies); - } - - public boolean digestProcessorpath(List dependencies) throws IOException { - return digest(ATTR_PROCESSORPATH_DIGEST, dependencies); - } - - private boolean digest(String key, List dependencies) { - long started = System.currentTimeMillis(); - - Map previousArtifacts = getPreviousDependencies(key); - LinkedHashMap digest = new LinkedHashMap<>(); - - if (dependencies != null) { - for (final File dependency : dependencies) { - File normalized = normalize(dependency); - ArtifactFile previousArtifact = previousArtifacts.get(normalized); - ArtifactFile artifact = CACHE.get(normalized); - if (artifact == null) { - if (normalized.isFile()) { - artifact = newFileArtifact(normalized, previousArtifact); - } else if (normalized.isDirectory()) { - artifact = newDirectoryArtifact(normalized, previousArtifact); - } else { - // happens with reactor dependencies with empty source folders - continue; - } - CACHE.put(normalized, artifact); - } + private static final String ATTR_CLASSPATH_DIGEST = "compile.classpath.digest"; + private static final String ATTR_SOURCEPATH_DIGEST = "compile.sourcepath.digest"; + private static final String ATTR_PROCESSORPATH_DIGEST = "compile.processorpath.digest"; - digest.put(normalized, artifact); + private final Logger log = LoggerFactory.getLogger(getClass()); - if (!equals(artifact, previousArtifact)) { - log.debug("New or changed classpath entry {}", normalized); - } - } + private static final Map CACHE = new ConcurrentHashMap(); + + private final CompilerBuildContext context; + + @Inject + public ProjectClasspathDigester(CompilerBuildContext context) { + this.context = context; + } + + /** + * Detects if classpath dependencies changed compared to the previous build or not. + */ + public boolean digestClasspath(List dependencies) throws IOException { + return digest(ATTR_CLASSPATH_DIGEST, dependencies); } - for (File reviousDependency : previousArtifacts.keySet()) { - if (!digest.containsKey(reviousDependency)) { - log.debug("Removed classpath entry {}", reviousDependency); - } + public boolean digestSourcepath(List dependencies) throws IOException { + return digest(ATTR_SOURCEPATH_DIGEST, dependencies); } - boolean changed = !equals(digest.values(), previousArtifacts.values()); + public boolean digestProcessorpath(List dependencies) throws IOException { + return digest(ATTR_PROCESSORPATH_DIGEST, dependencies); + } - context.setAttribute(key, new ArrayList<>(digest.values())); + private boolean digest(String key, List dependencies) { + long started = System.currentTimeMillis(); + + Map previousArtifacts = getPreviousDependencies(key); + LinkedHashMap digest = new LinkedHashMap<>(); + + if (dependencies != null) { + for (final File dependency : dependencies) { + File normalized = normalize(dependency); + ArtifactFile previousArtifact = previousArtifacts.get(normalized); + ArtifactFile artifact = CACHE.get(normalized); + if (artifact == null) { + if (normalized.isFile()) { + artifact = newFileArtifact(normalized, previousArtifact); + } else if (normalized.isDirectory()) { + artifact = newDirectoryArtifact(normalized, previousArtifact); + } else { + // happens with reactor dependencies with empty source folders + continue; + } + CACHE.put(normalized, artifact); + } + + digest.put(normalized, artifact); + + if (!equals(artifact, previousArtifact)) { + log.debug("New or changed classpath entry {}", normalized); + } + } + } - log.debug("Analyzed {} classpath dependencies ({} ms)", dependencies != null ? dependencies.size() : 0, System.currentTimeMillis() - started); + for (File reviousDependency : previousArtifacts.keySet()) { + if (!digest.containsKey(reviousDependency)) { + log.debug("Removed classpath entry {}", reviousDependency); + } + } - return changed; - } + boolean changed = !equals(digest.values(), previousArtifacts.values()); - private File normalize(File file) { - try { - return file.getCanonicalFile(); - } catch (IOException e) { - return file.getAbsoluteFile(); - } - } + context.setAttribute(key, new ArrayList<>(digest.values())); - private boolean equals(Collection a, Collection b) { - if (a.size() != b.size()) { - return false; - } - Iterator ia = a.iterator(); - Iterator ib = b.iterator(); - while (ia.hasNext()) { - if (!equals(ia.next(), ib.next())) { - return false; - } - } - return true; - } + log.debug( + "Analyzed {} classpath dependencies ({} ms)", + dependencies != null ? dependencies.size() : 0, + System.currentTimeMillis() - started); - private boolean equals(ArtifactFile a, ArtifactFile b) { - if (a == null) { - return b == null; + return changed; } - if (b == null) { - return false; - } - return a.file.equals(b.file) && a.isFile == b.isFile && a.lastModified == b.lastModified && a.length == b.length; - } - - private ArtifactFile newDirectoryArtifact(File directory, ArtifactFile previousArtifact) { - StringBuilder msg = new StringBuilder(); - DirectoryScanner scanner = new DirectoryScanner(); - scanner.setBasedir(directory); - scanner.setIncludes(new String[] {"**/*"}); - scanner.scan(); - long maxLastModified = 0, fileCount = 0; - for (String path : scanner.getIncludedFiles()) { - File file = new File(directory, path); - long lastModified = file.lastModified(); - maxLastModified = Math.max(maxLastModified, lastModified); - fileCount++; - if (previousArtifact != null && previousArtifact.lastModified < lastModified) { - msg.append("\n new or modfied class folder member ").append(file); - } + + private File normalize(File file) { + try { + return file.getCanonicalFile(); + } catch (IOException e) { + return file.getAbsoluteFile(); + } } - if (previousArtifact != null && previousArtifact.length != fileCount) { - msg.append("\n classfolder member count changed (new ").append(fileCount).append(" previous ").append(previousArtifact.length).append(')'); + private boolean equals(Collection a, Collection b) { + if (a.size() != b.size()) { + return false; + } + Iterator ia = a.iterator(); + Iterator ib = b.iterator(); + while (ia.hasNext()) { + if (!equals(ia.next(), ib.next())) { + return false; + } + } + return true; } - if (msg.length() > 0) { - log.debug("Changed dependency class folder {}: {}", directory, msg.toString()); + private boolean equals(ArtifactFile a, ArtifactFile b) { + if (a == null) { + return b == null; + } + if (b == null) { + return false; + } + return a.file.equals(b.file) + && a.isFile == b.isFile + && a.lastModified == b.lastModified + && a.length == b.length; } - return new ArtifactFile(directory, false, fileCount, maxLastModified); - } + private ArtifactFile newDirectoryArtifact(File directory, ArtifactFile previousArtifact) { + StringBuilder msg = new StringBuilder(); + DirectoryScanner scanner = new DirectoryScanner(); + scanner.setBasedir(directory); + scanner.setIncludes(new String[] {"**/*"}); + scanner.scan(); + long maxLastModified = 0, fileCount = 0; + for (String path : scanner.getIncludedFiles()) { + File file = new File(directory, path); + long lastModified = file.lastModified(); + maxLastModified = Math.max(maxLastModified, lastModified); + fileCount++; + if (previousArtifact != null && previousArtifact.lastModified < lastModified) { + msg.append("\n new or modfied class folder member ").append(file); + } + } + + if (previousArtifact != null && previousArtifact.length != fileCount) { + msg.append("\n classfolder member count changed (new ") + .append(fileCount) + .append(" previous ") + .append(previousArtifact.length) + .append(')'); + } + + if (msg.length() > 0) { + log.debug("Changed dependency class folder {}: {}", directory, msg.toString()); + } + + return new ArtifactFile(directory, false, fileCount, maxLastModified); + } - private ArtifactFile newFileArtifact(File file, ArtifactFile previousArtifact) { - return new ArtifactFile(file, true, file.length(), file.lastModified()); - } + private ArtifactFile newFileArtifact(File file, ArtifactFile previousArtifact) { + return new ArtifactFile(file, true, file.length(), file.lastModified()); + } - @SuppressWarnings("unchecked") - private Map getPreviousDependencies(String key) { - LinkedHashMap digest = new LinkedHashMap<>(); - ArrayList artifacts = context.getAttribute(key, true, ArrayList.class); - if (artifacts == null) { - return Collections.emptyMap(); + @SuppressWarnings("unchecked") + private Map getPreviousDependencies(String key) { + LinkedHashMap digest = new LinkedHashMap<>(); + ArrayList artifacts = context.getAttribute(key, true, ArrayList.class); + if (artifacts == null) { + return Collections.emptyMap(); + } + for (ArtifactFile artifact : artifacts) { + digest.put(artifact.file, artifact); + } + return digest; } - for (ArtifactFile artifact : artifacts) { - digest.put(artifact.file, artifact); + + /** + * @noreference this method is public for test purposes only + */ + public static void flush() { + CACHE.clear(); } - return digest; - } - - /** - * @noreference this method is public for test purposes only - */ - public static void flush() { - CACHE.clear(); - } } diff --git a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/ReactorProjects.java b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/ReactorProjects.java index 2be7bb36..1cffee63 100644 --- a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/ReactorProjects.java +++ b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/ReactorProjects.java @@ -1,13 +1,18 @@ +/* + * Copyright (c) 2014-2024 Takari, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v10.html + */ package io.takari.maven.plugins.compile; import java.util.Collections; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; - import javax.inject.Inject; import javax.inject.Named; - import org.apache.maven.SessionScoped; import org.apache.maven.artifact.Artifact; import org.apache.maven.execution.MavenSession; @@ -17,22 +22,22 @@ @SessionScoped class ReactorProjects { - private final Map projects; + private final Map projects; - @Inject - public ReactorProjects(MavenSession session) { - Map projects = new HashMap<>(); - for (MavenProject project : session.getProjects()) { - projects.put(key(project.getGroupId(), project.getArtifactId(), project.getVersion()), project); + @Inject + public ReactorProjects(MavenSession session) { + Map projects = new HashMap<>(); + for (MavenProject project : session.getProjects()) { + projects.put(key(project.getGroupId(), project.getArtifactId(), project.getVersion()), project); + } + this.projects = Collections.unmodifiableMap(new LinkedHashMap<>(projects)); } - this.projects = Collections.unmodifiableMap(new LinkedHashMap<>(projects)); - } - public MavenProject get(Artifact artifact) { - return projects.get(key(artifact.getGroupId(), artifact.getArtifactId(), artifact.getVersion())); - } + public MavenProject get(Artifact artifact) { + return projects.get(key(artifact.getGroupId(), artifact.getArtifactId(), artifact.getVersion())); + } - private static String key(String groupId, String artifactId, String version) { - return groupId + ":" + artifactId + ":" + version; - } + private static String key(String groupId, String artifactId, String version) { + return groupId + ":" + artifactId + ":" + version; + } } diff --git a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/TestCompileMojo.java b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/TestCompileMojo.java index c8e8e4bb..1cc6045e 100644 --- a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/TestCompileMojo.java +++ b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/TestCompileMojo.java @@ -1,18 +1,19 @@ -/** - * Copyright (c) 2014 Takari, Inc. +/* + * Copyright (c) 2014-2024 Takari, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * https://www.eclipse.org/legal/epl-v10.html */ package io.takari.maven.plugins.compile; +import io.takari.incrementalbuild.Incremental; +import io.takari.incrementalbuild.Incremental.Configuration; import java.io.File; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; - import org.apache.maven.artifact.Artifact; import org.apache.maven.model.Dependency; import org.apache.maven.plugins.annotations.LifecyclePhase; @@ -21,126 +22,128 @@ import org.apache.maven.plugins.annotations.ResolutionScope; import org.apache.maven.project.MavenProject; -import io.takari.incrementalbuild.Incremental; -import io.takari.incrementalbuild.Incremental.Configuration; - -@Mojo(name = "testCompile", defaultPhase = LifecyclePhase.TEST_COMPILE, threadSafe = true, requiresDependencyResolution = ResolutionScope.TEST, configurator = "takari") +@Mojo( + name = "testCompile", + defaultPhase = LifecyclePhase.TEST_COMPILE, + threadSafe = true, + requiresDependencyResolution = ResolutionScope.TEST, + configurator = "takari") public class TestCompileMojo extends AbstractCompileMojo { - /** - * The source directories containing the test-source to be compiled. - */ - @Parameter(defaultValue = "${project.testCompileSourceRoots}", readonly = true, required = true) - private List compileSourceRoots; - - /** - * A list of inclusion filters for the compiler. - */ - @Parameter - private Set testIncludes = new HashSet(); - - /** - * A list of exclusion filters for the compiler. - */ - @Parameter - private Set testExcludes = new HashSet(); - - /** - * Project classpath. - */ - @Parameter(defaultValue = "${project.testArtifacts}", readonly = true, required = true) - @Incremental(configuration = Configuration.ignore) - private List compileArtifacts; - - /** - * Project main output directory, part of test classpath. - */ - @Parameter(defaultValue = "${project.build.outputDirectory}", required = true, readonly = true) - private File mainOutputDirectory; - - /** - * The directory where compiled test classes go. - */ - @Parameter(defaultValue = "${project.build.testOutputDirectory}", required = true, readonly = true) - private File outputDirectory; - - /** - *

- * Specify where to place generated source files created by annotation processing. Only applies to JDK 1.6+ - *

- */ - @Parameter(defaultValue = "${project.build.directory}/generated-test-sources/test-annotations") - private File generatedTestSourcesDirectory; - - /** - * Set this to 'true' to bypass compilation of test sources. Its use is NOT RECOMMENDED, but quite convenient on occasion. - */ - @Parameter(property = "maven.test.skip") - @Incremental(configuration = Configuration.ignore) - private boolean skip; - - /** - * Main compile source roots, part of test sourcepath. - */ - @Parameter(defaultValue = "${project.compileSourceRoots}", readonly = true, required = true) - private List mainCompileSourceRoots; - - @Override - public Set getSourceRoots() { - return new LinkedHashSet(compileSourceRoots); - } - - @Override - public Set getIncludes() { - return testIncludes; - } - - @Override - public Set getExcludes() { - return testExcludes; - } - - @Override - public File getOutputDirectory() { - return outputDirectory; - } - - @Override - public List getClasspathArtifacts() { - return compileArtifacts; - } - - @Override - public File getGeneratedSourcesDirectory() { - return generatedTestSourcesDirectory; - } - - @Override - protected boolean isSkip() { - return skip; - } - - @Override - protected File getMainOutputDirectory() { - return mainOutputDirectory; - } - - @Override - protected void addGeneratedSources(MavenProject project) { - List roots = project.getTestCompileSourceRoots(); - String root = generatedTestSourcesDirectory.getAbsolutePath(); - if (!roots.contains(root)) { - roots.add(root); + /** + * The source directories containing the test-source to be compiled. + */ + @Parameter(defaultValue = "${project.testCompileSourceRoots}", readonly = true, required = true) + private List compileSourceRoots; + + /** + * A list of inclusion filters for the compiler. + */ + @Parameter + private Set testIncludes = new HashSet(); + + /** + * A list of exclusion filters for the compiler. + */ + @Parameter + private Set testExcludes = new HashSet(); + + /** + * Project classpath. + */ + @Parameter(defaultValue = "${project.testArtifacts}", readonly = true, required = true) + @Incremental(configuration = Configuration.ignore) + private List compileArtifacts; + + /** + * Project main output directory, part of test classpath. + */ + @Parameter(defaultValue = "${project.build.outputDirectory}", required = true, readonly = true) + private File mainOutputDirectory; + + /** + * The directory where compiled test classes go. + */ + @Parameter(defaultValue = "${project.build.testOutputDirectory}", required = true, readonly = true) + private File outputDirectory; + + /** + *

+ * Specify where to place generated source files created by annotation processing. Only applies to JDK 1.6+ + *

+ */ + @Parameter(defaultValue = "${project.build.directory}/generated-test-sources/test-annotations") + private File generatedTestSourcesDirectory; + + /** + * Set this to 'true' to bypass compilation of test sources. Its use is NOT RECOMMENDED, but quite convenient on occasion. + */ + @Parameter(property = "maven.test.skip") + @Incremental(configuration = Configuration.ignore) + private boolean skip; + + /** + * Main compile source roots, part of test sourcepath. + */ + @Parameter(defaultValue = "${project.compileSourceRoots}", readonly = true, required = true) + private List mainCompileSourceRoots; + + @Override + public Set getSourceRoots() { + return new LinkedHashSet(compileSourceRoots); + } + + @Override + public Set getIncludes() { + return testIncludes; + } + + @Override + public Set getExcludes() { + return testExcludes; + } + + @Override + public File getOutputDirectory() { + return outputDirectory; } - } - @Override - protected Set getMainSourceRoots() { - return new LinkedHashSet<>(mainCompileSourceRoots); - } + @Override + public List getClasspathArtifacts() { + return compileArtifacts; + } + + @Override + public File getGeneratedSourcesDirectory() { + return generatedTestSourcesDirectory; + } + + @Override + protected boolean isSkip() { + return skip; + } + + @Override + protected File getMainOutputDirectory() { + return mainOutputDirectory; + } + + @Override + protected void addGeneratedSources(MavenProject project) { + List roots = project.getTestCompileSourceRoots(); + String root = generatedTestSourcesDirectory.getAbsolutePath(); + if (!roots.contains(root)) { + roots.add(root); + } + } - @Override - protected List getProcessorpathDependencies() { - return null; - } + @Override + protected Set getMainSourceRoots() { + return new LinkedHashSet<>(mainCompileSourceRoots); + } + + @Override + protected List getProcessorpathDependencies() { + return null; + } } diff --git a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/javac/AbstractCompilerJavac.java b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/javac/AbstractCompilerJavac.java index 3acdb2fd..02e10000 100644 --- a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/javac/AbstractCompilerJavac.java +++ b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/javac/AbstractCompilerJavac.java @@ -1,9 +1,9 @@ -/** - * Copyright (c) 2014 Takari, Inc. +/* + * Copyright (c) 2014-2024 Takari, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * https://www.eclipse.org/legal/epl-v10.html */ package io.takari.maven.plugins.compile.javac; @@ -17,9 +17,6 @@ import io.takari.maven.plugins.compile.CompilerBuildContext; import io.takari.maven.plugins.compile.ProjectClasspathDigester; import io.takari.maven.plugins.compile.jdt.CompilerJdt; -import org.apache.maven.plugin.MojoExecutionException; -import org.codehaus.plexus.languages.java.version.JavaVersion; - import java.io.File; import java.io.IOException; import java.util.ArrayList; @@ -30,256 +27,264 @@ import java.util.Map; import java.util.Set; import java.util.stream.Collectors; +import org.apache.maven.plugin.MojoExecutionException; +import org.codehaus.plexus.languages.java.version.JavaVersion; public abstract class AbstractCompilerJavac extends AbstractCompiler { - protected static final boolean isJava8orBetter; + protected static final boolean isJava8orBetter; - static { - boolean _isJava8orBetter = true; - try { - Class.forName("java.util.Base64"); - } catch (Exception e) { - _isJava8orBetter = false; + static { + boolean _isJava8orBetter = true; + try { + Class.forName("java.util.Base64"); + } catch (Exception e) { + _isJava8orBetter = false; + } + isJava8orBetter = _isJava8orBetter; } - isJava8orBetter = _isJava8orBetter; - } - - private final ProjectClasspathDigester digester; - - private final List> sources = new ArrayList<>(); - - private String classpath; - private String sourcepath = ""; - private String processorpath; - - protected AbstractCompilerJavac(CompilerBuildContext context, ProjectClasspathDigester digester) { - super(context); - this.digester = digester; - } - - protected List getCompilerOptions() { - List options = new ArrayList<>(); - - // output directory - options.add("-d"); - options.add(getOutputDirectory().getAbsolutePath()); - - // The --source and --target option cannot be used with --release - if (getRelease() != null && JavaVersion.JAVA_VERSION.isAtLeast("9")) { - options.add("--release"); - options.add(getRelease()); - } else { - options.add("-source"); - options.add(getSource()); - - if (getTarget() != null) { - options.add("-target"); - options.add(getTarget()); - } - } - - options.add("-classpath"); - options.add(classpath); - - options.add("-Xprefer:source"); - options.add("-sourcepath"); - options.add(sourcepath); - - // http://docs.oracle.com/javase/7/docs/technotes/tools/windows/javac.html#implicit - options.add("-implicit:none"); - - switch (getProc()) { - case only: - options.add("-proc:only"); - break; - case proc: - // this is the javac default - break; - case none: - options.add("-proc:none"); - break; - default: - throw new IllegalArgumentException(); + + private final ProjectClasspathDigester digester; + + private final List> sources = new ArrayList<>(); + + private String classpath; + private String sourcepath = ""; + private String processorpath; + + protected AbstractCompilerJavac(CompilerBuildContext context, ProjectClasspathDigester digester) { + super(context); + this.digester = digester; } - if (getProc() != Proc.none) { - options.add("-s"); - options.add(getGeneratedSourcesDirectory().getAbsolutePath()); - - if (processorpath != null) { - options.add("-processorpath"); - options.add(processorpath); - } - - if (getAnnotationProcessors() != null) { - options.add("-processor"); - StringBuilder processors = new StringBuilder(); - for (String processor : getAnnotationProcessors()) { - if (processors.length() > 0) { - processors.append(','); - } - processors.append(processor); + + protected List getCompilerOptions() { + List options = new ArrayList<>(); + + // output directory + options.add("-d"); + options.add(getOutputDirectory().getAbsolutePath()); + + // The --source and --target option cannot be used with --release + if (getRelease() != null && JavaVersion.JAVA_VERSION.isAtLeast("9")) { + options.add("--release"); + options.add(getRelease()); + } else { + options.add("-source"); + options.add(getSource()); + + if (getTarget() != null) { + options.add("-target"); + options.add(getTarget()); + } } - options.add(processors.toString()); - } - if (getAnnotationProcessorOptions() != null) { - for (Map.Entry option : getAnnotationProcessorOptions().entrySet()) { - options.add("-A" + option.getKey() + "=" + option.getValue()); + options.add("-classpath"); + options.add(classpath); + + options.add("-Xprefer:source"); + options.add("-sourcepath"); + options.add(sourcepath); + + // http://docs.oracle.com/javase/7/docs/technotes/tools/windows/javac.html#implicit + options.add("-implicit:none"); + + switch (getProc()) { + case only: + options.add("-proc:only"); + break; + case proc: + // this is the javac default + break; + case none: + options.add("-proc:none"); + break; + default: + throw new IllegalArgumentException(); + } + if (getProc() != Proc.none) { + options.add("-s"); + options.add(getGeneratedSourcesDirectory().getAbsolutePath()); + + if (processorpath != null) { + options.add("-processorpath"); + options.add(processorpath); + } + + if (getAnnotationProcessors() != null) { + options.add("-processor"); + StringBuilder processors = new StringBuilder(); + for (String processor : getAnnotationProcessors()) { + if (processors.length() > 0) { + processors.append(','); + } + processors.append(processor); + } + options.add(processors.toString()); + } + + if (getAnnotationProcessorOptions() != null) { + for (Map.Entry option : + getAnnotationProcessorOptions().entrySet()) { + options.add("-A" + option.getKey() + "=" + option.getValue()); + } + } } - } - } - if (isVerbose()) { - options.add("-verbose"); - } + if (isVerbose()) { + options.add("-verbose"); + } - if (isParameters()) { - options.add("-parameters"); - } + if (isParameters()) { + options.add("-parameters"); + } - Set debug = getDebug(); - if (debug == null || debug.contains(Debug.all)) { - options.add("-g"); - } else if (debug.contains(Debug.none)) { - options.add("-g:none"); - } else { - StringBuilder keywords = new StringBuilder(); - for (Debug keyword : debug) { - if (keywords.length() > 0) { - keywords.append(','); + Set debug = getDebug(); + if (debug == null || debug.contains(Debug.all)) { + options.add("-g"); + } else if (debug.contains(Debug.none)) { + options.add("-g:none"); + } else { + StringBuilder keywords = new StringBuilder(); + for (Debug keyword : debug) { + if (keywords.length() > 0) { + keywords.append(','); + } + keywords.append(keyword.name()); + } + options.add("-g:" + keywords); + } + + if (isShowWarnings()) { + options.add("-Xlint:all"); + } else { + options.add("-Xlint:none"); } - keywords.append(keyword.name()); - } - options.add("-g:" + keywords); - } - if (isShowWarnings()) { - options.add("-Xlint:all"); - } else { - options.add("-Xlint:none"); + return options; } - return options; - } + @Override + public boolean setClasspath(List dependencies, File mainClasses, Set directDependencies) + throws IOException { + List classpath = new ArrayList<>(); + if (mainClasses != null) { + classpath.add(mainClasses); + } + classpath.addAll(dependencies); + + if (log.isDebugEnabled()) { + StringBuilder msg = new StringBuilder(); + for (File element : classpath) { + msg.append("\n   ").append(element); + } + log.debug("Compile classpath: {} entries{}", classpath.size(), msg); + } - @Override - public boolean setClasspath(List dependencies, File mainClasses, Set directDependencies) throws IOException { - List classpath = new ArrayList<>(); - if (mainClasses != null) { - classpath.add(mainClasses); - } - classpath.addAll(dependencies); - - if (log.isDebugEnabled()) { - StringBuilder msg = new StringBuilder(); - for (File element : classpath) { - msg.append("\n   ").append(element); - } - log.debug("Compile classpath: {} entries{}", classpath.size(), msg); - } + StringBuilder cp = new StringBuilder(); + cp.append(getOutputDirectory().getAbsolutePath()); + for (File dependency : classpath) { + if (dependency != null) { + cp.append(File.pathSeparatorChar).append(dependency.getAbsolutePath()); + } + } + this.classpath = cp.toString(); - StringBuilder cp = new StringBuilder(); - cp.append(getOutputDirectory().getAbsolutePath()); - for (File dependency : classpath) { - if (dependency != null) { - cp.append(File.pathSeparatorChar).append(dependency.getAbsolutePath()); - } + return digester.digestClasspath(classpath); } - this.classpath = cp.toString(); - - return digester.digestClasspath(classpath); - } - - @Override - public boolean setSourcepath(List dependencies, Set sourceRoots) throws IOException { - StringBuilder cp = new StringBuilder(); - for (File dependency : dependencies) { - if (dependency != null) { - cp.append(File.pathSeparatorChar).append(dependency.getAbsolutePath()); - } - } - this.sourcepath = cp.toString(); - - return digester.digestSourcepath(dependencies); - } - - @Override - public boolean setSources(List> sources) { - this.sources.addAll(sources); - - List> modifiedSources = new ArrayList<>(); - List> inputs = new ArrayList<>(); - for (ResourceMetadata input : sources) { - inputs.add(input); - if (input.getStatus() != ResourceStatus.UNMODIFIED) { - modifiedSources.add(input); - } - } - Collection> deletedSources = context.getRemovedSources(); - - if (!context.isEscalated() && log.isDebugEnabled()) { - StringBuilder inputsMsg = new StringBuilder("Modified inputs:"); - for (ResourceMetadata input : modifiedSources) { - inputsMsg.append("\n ").append(input.getStatus()).append(" ").append(input.getResource()); - } - for (ResourceMetadata input : deletedSources) { - inputsMsg.append("\n ").append(input.getStatus()).append(" ").append(input.getResource()); - } - log.debug(inputsMsg.toString()); + + @Override + public boolean setSourcepath(List dependencies, Set sourceRoots) throws IOException { + StringBuilder cp = new StringBuilder(); + for (File dependency : dependencies) { + if (dependency != null) { + cp.append(File.pathSeparatorChar).append(dependency.getAbsolutePath()); + } + } + this.sourcepath = cp.toString(); + + return digester.digestSourcepath(dependencies); } - return !modifiedSources.isEmpty() || !deletedSources.isEmpty(); - } + @Override + public boolean setSources(List> sources) { + this.sources.addAll(sources); + + List> modifiedSources = new ArrayList<>(); + List> inputs = new ArrayList<>(); + for (ResourceMetadata input : sources) { + inputs.add(input); + if (input.getStatus() != ResourceStatus.UNMODIFIED) { + modifiedSources.add(input); + } + } + Collection> deletedSources = context.getRemovedSources(); + + if (!context.isEscalated() && log.isDebugEnabled()) { + StringBuilder inputsMsg = new StringBuilder("Modified inputs:"); + for (ResourceMetadata input : modifiedSources) { + inputsMsg.append("\n ").append(input.getStatus()).append(" ").append(input.getResource()); + } + for (ResourceMetadata input : deletedSources) { + inputsMsg.append("\n ").append(input.getStatus()).append(" ").append(input.getResource()); + } + log.debug(inputsMsg.toString()); + } - @Override - public void setPrivatePackageReference(AccessRulesViolation accessRulesViolation) { - if (accessRulesViolation == AccessRulesViolation.error) { - String msg = String.format("Compiler %s does not support privatePackageReference=error, use compilerId=%s", getCompilerId(), CompilerJdt.ID); - throw new IllegalArgumentException(msg); + return !modifiedSources.isEmpty() || !deletedSources.isEmpty(); } - } - @Override - public void setTransitiveDependencyReference(AccessRulesViolation accessRulesViolation) { - if (accessRulesViolation == AccessRulesViolation.error) { - String msg = String.format("Compiler %s does not support transitiveDependencyReference=error, use compilerId=%s", getCompilerId(), CompilerJdt.ID); - throw new IllegalArgumentException(msg); + @Override + public void setPrivatePackageReference(AccessRulesViolation accessRulesViolation) { + if (accessRulesViolation == AccessRulesViolation.error) { + String msg = String.format( + "Compiler %s does not support privatePackageReference=error, use compilerId=%s", + getCompilerId(), CompilerJdt.ID); + throw new IllegalArgumentException(msg); + } } - } - - @Override - public boolean setProcessorpath(List processorpath) throws IOException { - if (processorpath != null) { - if (log.isDebugEnabled()) { - StringBuilder msg = new StringBuilder(); - for (File element : processorpath) { - msg.append("\n   ").append(element); + + @Override + public void setTransitiveDependencyReference(AccessRulesViolation accessRulesViolation) { + if (accessRulesViolation == AccessRulesViolation.error) { + String msg = String.format( + "Compiler %s does not support transitiveDependencyReference=error, use compilerId=%s", + getCompilerId(), CompilerJdt.ID); + throw new IllegalArgumentException(msg); } - log.debug("Processorpath: {} entries{}", processorpath.size(), msg); - } - this.processorpath = processorpath.stream().map(File::toString).collect(Collectors.joining(File.pathSeparator)); } - return digester.digestProcessorpath(processorpath != null ? processorpath : Collections.emptyList()); - } - - @Override - public final int compile() throws MojoExecutionException, IOException { - // eagerly delete all outputs. - // otherwise javac may use stale outputs and resolve types that will be deleted at the end of the build - context.deleteOutputs(); - - // everything is being rebuilt, mark as processed - Map> files = new LinkedHashMap<>(sources.size()); - for (ResourceMetadata input : sources) { - files.put(input.getResource(), input.process()); + + @Override + public boolean setProcessorpath(List processorpath) throws IOException { + if (processorpath != null) { + if (log.isDebugEnabled()) { + StringBuilder msg = new StringBuilder(); + for (File element : processorpath) { + msg.append("\n   ").append(element); + } + log.debug("Processorpath: {} entries{}", processorpath.size(), msg); + } + this.processorpath = + processorpath.stream().map(File::toString).collect(Collectors.joining(File.pathSeparator)); + } + return digester.digestProcessorpath(processorpath != null ? processorpath : Collections.emptyList()); } - return compile(files); - } + @Override + public final int compile() throws MojoExecutionException, IOException { + // eagerly delete all outputs. + // otherwise javac may use stale outputs and resolve types that will be deleted at the end of the build + context.deleteOutputs(); + + // everything is being rebuilt, mark as processed + Map> files = new LinkedHashMap<>(sources.size()); + for (ResourceMetadata input : sources) { + files.put(input.getResource(), input.process()); + } - protected abstract int compile(Map> sources) throws MojoExecutionException, IOException; + return compile(files); + } - protected abstract String getCompilerId(); + protected abstract int compile(Map> sources) throws MojoExecutionException, IOException; + protected abstract String getCompilerId(); } diff --git a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/javac/CompilerJavac.java b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/javac/CompilerJavac.java index eb26176e..544953f6 100644 --- a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/javac/CompilerJavac.java +++ b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/javac/CompilerJavac.java @@ -1,19 +1,23 @@ -/** - * Copyright (c) 2014 Takari, Inc. +/* + * Copyright (c) 2014-2024 Takari, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * https://www.eclipse.org/legal/epl-v10.html */ package io.takari.maven.plugins.compile.javac; +import io.takari.incrementalbuild.MessageSeverity; +import io.takari.incrementalbuild.Output; +import io.takari.incrementalbuild.Resource; +import io.takari.maven.plugins.compile.CompilerBuildContext; +import io.takari.maven.plugins.compile.ProjectClasspathDigester; import java.io.File; import java.io.IOException; import java.io.PrintWriter; import java.io.Writer; import java.util.HashMap; import java.util.Map; - import javax.inject.Inject; import javax.inject.Named; import javax.tools.Diagnostic; @@ -23,132 +27,144 @@ import javax.tools.JavaFileObject; import javax.tools.StandardJavaFileManager; import javax.tools.ToolProvider; - import org.apache.maven.plugin.MojoExecutionException; -import io.takari.incrementalbuild.MessageSeverity; -import io.takari.incrementalbuild.Output; -import io.takari.incrementalbuild.Resource; -import io.takari.maven.plugins.compile.CompilerBuildContext; -import io.takari.maven.plugins.compile.ProjectClasspathDigester; - @Named(CompilerJavac.ID) public class CompilerJavac extends AbstractCompilerJavac { - public static final String ID = "javac"; + public static final String ID = "javac"; - private static JavaCompiler compiler; + private static JavaCompiler compiler; - static synchronized JavaCompiler getSystemJavaCompiler() throws MojoExecutionException { - if (compiler == null) { - compiler = ToolProvider.getSystemJavaCompiler(); - } - if (compiler == null) { - throw new MojoExecutionException("No compiler is provided in this environment. " + "Perhaps you are running on a JRE rather than a JDK?"); + static synchronized JavaCompiler getSystemJavaCompiler() throws MojoExecutionException { + if (compiler == null) { + compiler = ToolProvider.getSystemJavaCompiler(); + } + if (compiler == null) { + throw new MojoExecutionException("No compiler is provided in this environment. " + + "Perhaps you are running on a JRE rather than a JDK?"); + } + return compiler; } - return compiler; - } - - @Inject - public CompilerJavac(CompilerBuildContext context, ProjectClasspathDigester digester) { - super(context, digester); - } - - @Override - public int compile(Map> sources) throws MojoExecutionException, IOException { - if (sources.isEmpty()) { - return 0; + + @Inject + public CompilerJavac(CompilerBuildContext context, ProjectClasspathDigester digester) { + super(context, digester); } - final JavaCompiler compiler = getSystemJavaCompiler(); - final StandardJavaFileManager javaFileManager = compiler.getStandardFileManager(null, null, getSourceEncoding()); - try { - compile(compiler, javaFileManager, sources); - } finally { - javaFileManager.flush(); - javaFileManager.close(); + @Override + public int compile(Map> sources) throws MojoExecutionException, IOException { + if (sources.isEmpty()) { + return 0; + } + + final JavaCompiler compiler = getSystemJavaCompiler(); + final StandardJavaFileManager javaFileManager = + compiler.getStandardFileManager(null, null, getSourceEncoding()); + try { + compile(compiler, javaFileManager, sources); + } finally { + javaFileManager.flush(); + javaFileManager.close(); + } + return sources.size(); } - return sources.size(); - } - - private void compile(JavaCompiler compiler, StandardJavaFileManager javaFileManager, Map> sources) throws IOException { - final DiagnosticCollector diagnosticCollector = new DiagnosticCollector(); - final Iterable javaSources = javaFileManager.getJavaFileObjectsFromFiles(sources.keySet()); - - final Map> outputs = new HashMap>(); - - final Iterable options = getCompilerOptions(); - final RecordingJavaFileManager recordingFileManager = new RecordingJavaFileManager(javaFileManager, getSourceEncoding()) { - @Override - protected void record(File inputFile, File outputFile) { - outputs.put(outputFile, context.processOutput(outputFile)); - } - }; - - Writer stdout = new PrintWriter(System.out, true); - final JavaCompiler.CompilationTask task = compiler.getTask(stdout, // Writer out - recordingFileManager, // file manager - diagnosticCollector, // diagnostic listener - options, // - null, // Iterable classes to process by annotation processor(s) - javaSources); - - final boolean success = task.call(); - - for (Diagnostic diagnostic : diagnosticCollector.getDiagnostics()) { - final JavaFileObject source = diagnostic.getSource(); - final MessageSeverity severity = toSeverity(diagnostic.getKind(), success); - final String message = diagnostic.getMessage(null); - - if (isShowWarnings() || severity != MessageSeverity.WARNING) { - if (source != null) { - File file = FileObjects.toFile(source); - if (file != null) { - Resource resource = sources.get(file); - if (resource == null) { - resource = outputs.get(file); - } - if (resource != null) { - resource.addMessage((int) diagnostic.getLineNumber(), (int) diagnostic.getColumnNumber(), message, severity, null); - } else { - log.warn("Unexpected java {} resource {}", source.getKind(), source.toUri().toASCIIString()); + + private void compile( + JavaCompiler compiler, StandardJavaFileManager javaFileManager, Map> sources) + throws IOException { + final DiagnosticCollector diagnosticCollector = new DiagnosticCollector(); + final Iterable javaSources = + javaFileManager.getJavaFileObjectsFromFiles(sources.keySet()); + + final Map> outputs = new HashMap>(); + + final Iterable options = getCompilerOptions(); + final RecordingJavaFileManager recordingFileManager = + new RecordingJavaFileManager(javaFileManager, getSourceEncoding()) { + @Override + protected void record(File inputFile, File outputFile) { + outputs.put(outputFile, context.processOutput(outputFile)); + } + }; + + Writer stdout = new PrintWriter(System.out, true); + final JavaCompiler.CompilationTask task = compiler.getTask( + stdout, // Writer out + recordingFileManager, // file manager + diagnosticCollector, // diagnostic listener + options, // + null, // Iterable classes to process by annotation processor(s) + javaSources); + + final boolean success = task.call(); + + for (Diagnostic diagnostic : diagnosticCollector.getDiagnostics()) { + final JavaFileObject source = diagnostic.getSource(); + final MessageSeverity severity = toSeverity(diagnostic.getKind(), success); + final String message = diagnostic.getMessage(null); + + if (isShowWarnings() || severity != MessageSeverity.WARNING) { + if (source != null) { + File file = FileObjects.toFile(source); + if (file != null) { + Resource resource = sources.get(file); + if (resource == null) { + resource = outputs.get(file); + } + if (resource != null) { + resource.addMessage( + (int) diagnostic.getLineNumber(), + (int) diagnostic.getColumnNumber(), + message, + severity, + null); + } else { + log.warn( + "Unexpected java {} resource {}", + source.getKind(), + source.toUri().toASCIIString()); + } + } else { + log.warn( + "Unsupported compiler message on {} resource {}: {}", + source.getKind(), + source.toUri(), + message); + } + } else { + context.addPomMessage(message, severity, null); + } } - } else { - log.warn("Unsupported compiler message on {} resource {}: {}", source.getKind(), source.toUri(), message); - } - } else { - context.addPomMessage(message, severity, null); } - } - } - } - - private MessageSeverity toSeverity(Diagnostic.Kind kind, boolean success) { - // javac appears to report errors even when compilation was success. - // I was only able to reproduce this with annotation processing on java 6 - // for consistency with forked mode, downgrade errors to warning here too - if (success && kind == Kind.ERROR) { - kind = Kind.WARNING; } - MessageSeverity severity; - switch (kind) { - case ERROR: - severity = MessageSeverity.ERROR; - break; - case NOTE: - severity = MessageSeverity.INFO; - break; - default: - severity = MessageSeverity.WARNING; - break; - } + private MessageSeverity toSeverity(Diagnostic.Kind kind, boolean success) { + // javac appears to report errors even when compilation was success. + // I was only able to reproduce this with annotation processing on java 6 + // for consistency with forked mode, downgrade errors to warning here too + if (success && kind == Kind.ERROR) { + kind = Kind.WARNING; + } - return severity; - } + MessageSeverity severity; + switch (kind) { + case ERROR: + severity = MessageSeverity.ERROR; + break; + case NOTE: + severity = MessageSeverity.INFO; + break; + default: + severity = MessageSeverity.WARNING; + break; + } - @Override - protected String getCompilerId() { - return ID; - } + return severity; + } + + @Override + protected String getCompilerId() { + return ID; + } } diff --git a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/javac/CompilerJavacForked.java b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/javac/CompilerJavacForked.java index ef7ee7ec..4ea9fd69 100644 --- a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/javac/CompilerJavacForked.java +++ b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/javac/CompilerJavacForked.java @@ -1,12 +1,13 @@ -/** - * Copyright (c) 2014 Takari, Inc. +/* + * Copyright (c) 2014-2024 Takari, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * https://www.eclipse.org/legal/epl-v10.html */ package io.takari.maven.plugins.compile.javac; +import io.takari.incrementalbuild.MessageSeverity; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; @@ -23,7 +24,6 @@ import java.util.ArrayList; import java.util.List; import java.util.StringTokenizer; - import javax.tools.Diagnostic; import javax.tools.Diagnostic.Kind; import javax.tools.DiagnosticCollector; @@ -32,291 +32,307 @@ import javax.tools.StandardJavaFileManager; import javax.tools.ToolProvider; -import io.takari.incrementalbuild.MessageSeverity; - public class CompilerJavacForked { - private static final String EOL = "\n"; - - private static final String ENCODING = "UTF-8"; + private static final String EOL = "\n"; - public static class CompilerConfiguration { + private static final String ENCODING = "UTF-8"; - private final Charset encoding; + public static class CompilerConfiguration { - private final Iterable options; + private final Charset encoding; - private final Iterable sources; + private final Iterable options; - public CompilerConfiguration(Charset encoding, Iterable options, Iterable sources) { - this.encoding = encoding; - this.options = options; - this.sources = sources; - } + private final Iterable sources; - public Charset getSourceEncoding() { - return encoding; - } - - public Iterable getCompilerOptions() { - return options; - } - - public Iterable getSources() { - return sources; - } + public CompilerConfiguration(Charset encoding, Iterable options, Iterable sources) { + this.encoding = encoding; + this.options = options; + this.sources = sources; + } - public void write(File file) throws IOException { - Writer writer = newWriter(file); - try { - // encoding - if (encoding != null) { - writer.write('C'); - writer.write(encoding.name()); - writer.write(EOL); + public Charset getSourceEncoding() { + return encoding; } - // options - for (String option : options) { - writer.write('O'); - writer.write(option); - writer.write(EOL); + public Iterable getCompilerOptions() { + return options; } - // sources - for (File source : sources) { - writer.write('S'); - writer.write(source.getCanonicalPath()); - writer.write(EOL); + public Iterable getSources() { + return sources; } - } finally { - writer.close(); - } - } - public static CompilerConfiguration read(File file) throws IOException { - Charset encoding = null; - List options = new ArrayList(); - List sources = new ArrayList(); - - BufferedReader reader = newBufferedReader(file); - try { - String str; - while ((str = reader.readLine()) != null) { - String value = str.substring(1); - switch (str.charAt(0)) { - case 'C': - encoding = Charset.forName(value); - break; - case 'O': - options.add(value); - break; - case 'S': - sources.add(new File(value)); - break; - } + public void write(File file) throws IOException { + Writer writer = newWriter(file); + try { + // encoding + if (encoding != null) { + writer.write('C'); + writer.write(encoding.name()); + writer.write(EOL); + } + + // options + for (String option : options) { + writer.write('O'); + writer.write(option); + writer.write(EOL); + } + + // sources + for (File source : sources) { + writer.write('S'); + writer.write(source.getCanonicalPath()); + writer.write(EOL); + } + } finally { + writer.close(); + } } - } finally { - reader.close(); - } - return new CompilerConfiguration(encoding, options, sources); + public static CompilerConfiguration read(File file) throws IOException { + Charset encoding = null; + List options = new ArrayList(); + List sources = new ArrayList(); + + BufferedReader reader = newBufferedReader(file); + try { + String str; + while ((str = reader.readLine()) != null) { + String value = str.substring(1); + switch (str.charAt(0)) { + case 'C': + encoding = Charset.forName(value); + break; + case 'O': + options.add(value); + break; + case 'S': + sources.add(new File(value)); + break; + } + } + } finally { + reader.close(); + } + + return new CompilerConfiguration(encoding, options, sources); + } } - } - public static class CompilerOutput { + public static class CompilerOutput { - private final Writer writer; + private final Writer writer; - public CompilerOutput(File file) throws IOException { - this.writer = newWriter(file); - } + public CompilerOutput(File file) throws IOException { + this.writer = newWriter(file); + } - public void processOutput(File inputFile, File outputFile) { - try { - writer.write('O'); - writer.write(inputFile != null ? URLEncoder.encode(inputFile.getCanonicalPath(), ENCODING) : "."); - writer.write(' '); - writer.write(URLEncoder.encode(outputFile.getCanonicalPath(), ENCODING)); - writer.write(EOL); - } catch (IOException e) { - handleException(e); - } - } + public void processOutput(File inputFile, File outputFile) { + try { + writer.write('O'); + writer.write(inputFile != null ? URLEncoder.encode(inputFile.getCanonicalPath(), ENCODING) : "."); + writer.write(' '); + writer.write(URLEncoder.encode(outputFile.getCanonicalPath(), ENCODING)); + writer.write(EOL); + } catch (IOException e) { + handleException(e); + } + } - public void addMessage(String path, int line, int column, String message, Kind kind) { - try { - writer.write('M'); - writer.write(URLEncoder.encode(path, ENCODING)); - writer.write(' '); - writer.write(Integer.toString(line)); - writer.write(' '); - writer.write(Integer.toString(column)); - writer.write(' '); - switch (kind) { - case ERROR: - writer.write('E'); - break; - case NOTE: - writer.write('I'); - break; - default: - writer.write('W'); - break; + public void addMessage(String path, int line, int column, String message, Kind kind) { + try { + writer.write('M'); + writer.write(URLEncoder.encode(path, ENCODING)); + writer.write(' '); + writer.write(Integer.toString(line)); + writer.write(' '); + writer.write(Integer.toString(column)); + writer.write(' '); + switch (kind) { + case ERROR: + writer.write('E'); + break; + case NOTE: + writer.write('I'); + break; + default: + writer.write('W'); + break; + } + writer.write(' '); + writer.write(URLEncoder.encode(message, ENCODING)); + writer.write(EOL); + } catch (IOException e) { + handleException(e); + } } - writer.write(' '); - writer.write(URLEncoder.encode(message, ENCODING)); - writer.write(EOL); - } catch (IOException e) { - handleException(e); - } - } - public void addLogMessage(String message) { - try { - writer.write('L'); - writer.write(message); - writer.write(EOL); - } catch (IOException e) { - handleException(e); - } - } + public void addLogMessage(String message) { + try { + writer.write('L'); + writer.write(message); + writer.write(EOL); + } catch (IOException e) { + handleException(e); + } + } - public void close() throws IOException { - writer.close(); - } + public void close() throws IOException { + writer.close(); + } - private void handleException(IOException e) { - e.printStackTrace(); - System.exit(1); // this will trigger ExecutionException in Maven plugin - } + private void handleException(IOException e) { + e.printStackTrace(); + System.exit(1); // this will trigger ExecutionException in Maven plugin + } - public static void process(File file, CompilerOutputProcessor callback) throws IOException { - BufferedReader reader = newBufferedReader(file); - try { - String str; - while ((str = reader.readLine()) != null) { - String value = str.substring(1); - switch (str.charAt(0)) { - case 'O': { - StringTokenizer st = new StringTokenizer(value, " "); - String inputPath = URLDecoder.decode(st.nextToken(), ENCODING); - String outputPath = URLDecoder.decode(st.nextToken(), ENCODING); - callback.processOutput(!".".equals(inputPath) ? new File(inputPath) : null, new File(outputPath)); - break; - } - case 'M': { - StringTokenizer st = new StringTokenizer(value, " "); - String path = URLDecoder.decode(st.nextToken(), ENCODING); - int line = Integer.parseInt(st.nextToken()); - int column = Integer.parseInt(st.nextToken()); - MessageSeverity severity = toSeverity(st.nextToken()); - String message = URLDecoder.decode(st.nextToken(), ENCODING); - callback.addMessage(path, line, column, message, severity); - break; - } - case 'L': { - callback.addLogMessage(value); - break; + public static void process(File file, CompilerOutputProcessor callback) throws IOException { + BufferedReader reader = newBufferedReader(file); + try { + String str; + while ((str = reader.readLine()) != null) { + String value = str.substring(1); + switch (str.charAt(0)) { + case 'O': { + StringTokenizer st = new StringTokenizer(value, " "); + String inputPath = URLDecoder.decode(st.nextToken(), ENCODING); + String outputPath = URLDecoder.decode(st.nextToken(), ENCODING); + callback.processOutput( + !".".equals(inputPath) ? new File(inputPath) : null, new File(outputPath)); + break; + } + case 'M': { + StringTokenizer st = new StringTokenizer(value, " "); + String path = URLDecoder.decode(st.nextToken(), ENCODING); + int line = Integer.parseInt(st.nextToken()); + int column = Integer.parseInt(st.nextToken()); + MessageSeverity severity = toSeverity(st.nextToken()); + String message = URLDecoder.decode(st.nextToken(), ENCODING); + callback.addMessage(path, line, column, message, severity); + break; + } + case 'L': { + callback.addLogMessage(value); + break; + } + default: + throw new IllegalArgumentException(); + } + } + } finally { + reader.close(); } - default: - throw new IllegalArgumentException(); - } } - } finally { - reader.close(); - } - } - private static MessageSeverity toSeverity(String token) { - switch (token) { - case "E": - return MessageSeverity.ERROR; - case "I": - return MessageSeverity.INFO; - default: - return MessageSeverity.WARNING; - } + private static MessageSeverity toSeverity(String token) { + switch (token) { + case "E": + return MessageSeverity.ERROR; + case "I": + return MessageSeverity.INFO; + default: + return MessageSeverity.WARNING; + } + } } - } - public static interface CompilerOutputProcessor { - public void processOutput(File inputFile, File outputFile); + public static interface CompilerOutputProcessor { + public void processOutput(File inputFile, File outputFile); - public void addMessage(String path, int line, int column, String message, MessageSeverity kind); + public void addMessage(String path, int line, int column, String message, MessageSeverity kind); - public void addLogMessage(String message); - } + public void addLogMessage(String message); + } - static Writer newWriter(File file) throws IOException { - return new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), ENCODING)); - } + static Writer newWriter(File file) throws IOException { + return new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), ENCODING)); + } - static BufferedReader newBufferedReader(File file) throws IOException { - return new BufferedReader(new InputStreamReader(new FileInputStream(file), ENCODING)); - } + static BufferedReader newBufferedReader(File file) throws IOException { + return new BufferedReader(new InputStreamReader(new FileInputStream(file), ENCODING)); + } - public static void main(String[] args) throws IOException { - final CompilerConfiguration config = CompilerConfiguration.read(new File(args[0])); - final CompilerOutput output = new CompilerOutput(new File(args[1])); - try { - compile(config, output); - } finally { - output.close(); + public static void main(String[] args) throws IOException { + final CompilerConfiguration config = CompilerConfiguration.read(new File(args[0])); + final CompilerOutput output = new CompilerOutput(new File(args[1])); + try { + compile(config, output); + } finally { + output.close(); + } } - } - private static void compile(final CompilerConfiguration config, final CompilerOutput output) { + private static void compile(final CompilerConfiguration config, final CompilerOutput output) { + + final JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); + if (compiler == null) { + output.addMessage( + ".", + 0, + 0, + "No compiler is provided in this environment. " + + "Perhaps you are running on a JRE rather than a JDK?", + Kind.ERROR); + return; + } - final JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); - if (compiler == null) { - output.addMessage(".", 0, 0, "No compiler is provided in this environment. " + "Perhaps you are running on a JRE rather than a JDK?", Kind.ERROR); - return; - } + final Charset sourceEncoding = config.getSourceEncoding(); + final DiagnosticCollector diagnosticCollector = new DiagnosticCollector(); + final StandardJavaFileManager standardFileManager = + compiler.getStandardFileManager(diagnosticCollector, null, sourceEncoding); + final Iterable fileObjects = + standardFileManager.getJavaFileObjectsFromFiles(config.getSources()); + final Iterable options = config.getCompilerOptions(); + final RecordingJavaFileManager recordingFileManager = + new RecordingJavaFileManager(standardFileManager, sourceEncoding) { + @Override + protected void record(File inputFile, File outputFile) { + output.processOutput(inputFile, outputFile); + } + }; + + Writer stdout = new PrintWriter(System.out, true); + final JavaCompiler.CompilationTask task = compiler.getTask( + stdout, // Writer out + recordingFileManager, // file manager + diagnosticCollector, // diagnostic listener + options, // + null, // Iterable classes to process by annotation processor(s) + fileObjects); + + boolean success = task.call(); + + for (Diagnostic diagnostic : diagnosticCollector.getDiagnostics()) { + JavaFileObject source = diagnostic.getSource(); + + // when doing annotation processing, javac 6 reports errors when handwritten sources + // depend on generated sources even when overall compilation is reported as success + // to prevent false build failures, never issue ERROR messages after successful compilation + Kind kind = diagnostic.getKind(); + if (success && kind == Kind.ERROR) { + kind = Kind.WARNING; + } - final Charset sourceEncoding = config.getSourceEncoding(); - final DiagnosticCollector diagnosticCollector = new DiagnosticCollector(); - final StandardJavaFileManager standardFileManager = compiler.getStandardFileManager(diagnosticCollector, null, sourceEncoding); - final Iterable fileObjects = standardFileManager.getJavaFileObjectsFromFiles(config.getSources()); - final Iterable options = config.getCompilerOptions(); - final RecordingJavaFileManager recordingFileManager = new RecordingJavaFileManager(standardFileManager, sourceEncoding) { - @Override - protected void record(File inputFile, File outputFile) { - output.processOutput(inputFile, outputFile); - } - }; - - Writer stdout = new PrintWriter(System.out, true); - final JavaCompiler.CompilationTask task = compiler.getTask(stdout, // Writer out - recordingFileManager, // file manager - diagnosticCollector, // diagnostic listener - options, // - null, // Iterable classes to process by annotation processor(s) - fileObjects); - - boolean success = task.call(); - - for (Diagnostic diagnostic : diagnosticCollector.getDiagnostics()) { - JavaFileObject source = diagnostic.getSource(); - - // when doing annotation processing, javac 6 reports errors when handwritten sources - // depend on generated sources even when overall compilation is reported as success - // to prevent false build failures, never issue ERROR messages after successful compilation - Kind kind = diagnostic.getKind(); - if (success && kind == Kind.ERROR) { - kind = Kind.WARNING; - } - - if (source != null) { - File file = FileObjects.toFile(source); - if (file != null) { - output.addMessage(file.getAbsolutePath(), (int) diagnostic.getLineNumber(), (int) diagnostic.getColumnNumber(), diagnostic.getMessage(null), kind); - } else { - output.addLogMessage(String.format("Unsupported compiler message on %s resource %s: %s", source.getKind(), source.toUri(), diagnostic.getMessage(null))); + if (source != null) { + File file = FileObjects.toFile(source); + if (file != null) { + output.addMessage( + file.getAbsolutePath(), + (int) diagnostic.getLineNumber(), + (int) diagnostic.getColumnNumber(), + diagnostic.getMessage(null), + kind); + } else { + output.addLogMessage(String.format( + "Unsupported compiler message on %s resource %s: %s", + source.getKind(), source.toUri(), diagnostic.getMessage(null))); + } + } else { + output.addMessage(".", 0, 0, diagnostic.getMessage(null), kind); + } } - } else { - output.addMessage(".", 0, 0, diagnostic.getMessage(null), kind); - } } - } } diff --git a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/javac/CompilerJavacLauncher.java b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/javac/CompilerJavacLauncher.java index 3a357f2c..ec9d42b8 100644 --- a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/javac/CompilerJavacLauncher.java +++ b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/javac/CompilerJavacLauncher.java @@ -1,173 +1,170 @@ -/** - * Copyright (c) 2014 Takari, Inc. +/* + * Copyright (c) 2014-2024 Takari, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * https://www.eclipse.org/legal/epl-v10.html */ package io.takari.maven.plugins.compile.javac; +import io.takari.incrementalbuild.MessageSeverity; +import io.takari.incrementalbuild.Output; +import io.takari.incrementalbuild.Resource; +import io.takari.maven.plugins.compile.CompilerBuildContext; +import io.takari.maven.plugins.compile.ProjectClasspathDigester; +import io.takari.maven.plugins.compile.javac.CompilerJavacForked.CompilerConfiguration; +import io.takari.maven.plugins.compile.javac.CompilerJavacForked.CompilerOutput; +import io.takari.maven.plugins.compile.javac.CompilerJavacForked.CompilerOutputProcessor; import java.io.File; import java.io.IOException; import java.util.HashMap; import java.util.Map; - import javax.inject.Inject; import javax.inject.Named; - import org.apache.commons.exec.CommandLine; import org.apache.commons.exec.DefaultExecutor; import org.apache.commons.exec.ExecuteException; import org.apache.commons.exec.ShutdownHookProcessDestroyer; -import io.takari.incrementalbuild.MessageSeverity; -import io.takari.incrementalbuild.Output; -import io.takari.incrementalbuild.Resource; -import io.takari.maven.plugins.compile.CompilerBuildContext; -import io.takari.maven.plugins.compile.ProjectClasspathDigester; -import io.takari.maven.plugins.compile.javac.CompilerJavacForked.CompilerConfiguration; -import io.takari.maven.plugins.compile.javac.CompilerJavacForked.CompilerOutput; -import io.takari.maven.plugins.compile.javac.CompilerJavacForked.CompilerOutputProcessor; - @Named(CompilerJavacLauncher.ID) public class CompilerJavacLauncher extends AbstractCompilerJavac { - public static final String ID = "forked-javac"; + public static final String ID = "forked-javac"; - private File jar; + private File jar; - private File basedir; + private File basedir; - private File buildDirectory; + private File buildDirectory; - private String meminitial; + private String meminitial; - private String maxmem; + private String maxmem; - @Inject - public CompilerJavacLauncher(CompilerBuildContext context, ProjectClasspathDigester digester) { - super(context, digester); - } + @Inject + public CompilerJavacLauncher(CompilerBuildContext context, ProjectClasspathDigester digester) { + super(context, digester); + } + + @Override + public int compile(Map> sources) throws IOException { + if (sources.isEmpty()) { + return 0; + } - @Override - public int compile(Map> sources) throws IOException { - if (sources.isEmpty()) { - return 0; + File options = File.createTempFile("javac-forked", ".options", buildDirectory); + File output = File.createTempFile("javac-forked", ".output", buildDirectory); + compile(options, output, sources); + // don't delete temp files in case of an exception + // they maybe useful to debug the problem + options.delete(); + output.delete(); + + return sources.size(); } - File options = File.createTempFile("javac-forked", ".options", buildDirectory); - File output = File.createTempFile("javac-forked", ".output", buildDirectory); - compile(options, output, sources); - // don't delete temp files in case of an exception - // they maybe useful to debug the problem - options.delete(); - output.delete(); + private void compile(File options, File output, final Map> sources) throws IOException { + new CompilerConfiguration(getSourceEncoding(), getCompilerOptions(), sources.keySet()).write(options); + + // use the same JVM as the one used to run Maven (the "java.home" one) + String executable = System.getProperty("java.home") + File.separator + "bin" + File.separator + "java"; + if (File.separatorChar == '\\') { + executable = executable + ".exe"; + } + + CommandLine cli = new CommandLine(executable); - return sources.size(); - } + // jvm options + cli.addArguments(new String[] {"-cp", jar.getAbsolutePath()}); + if (meminitial != null) { + cli.addArgument("-Xms" + meminitial); + } + if (maxmem != null) { + cli.addArgument("-Xmx" + maxmem); + } - private void compile(File options, File output, final Map> sources) throws IOException { - new CompilerConfiguration(getSourceEncoding(), getCompilerOptions(), sources.keySet()).write(options); + // main class and program arguments + cli.addArgument(CompilerJavacForked.class.getName()); + cli.addArgument(options.getAbsolutePath(), false); + cli.addArgument(output.getAbsolutePath(), false); + + DefaultExecutor executor = new DefaultExecutor(); + // ExecuteWatchdog watchdog = null; + // if (forkedProcessTimeoutInSeconds > 0) { + // watchdog = new ExecuteWatchdog(forkedProcessTimeoutInSeconds * 1000L); + // executor.setWatchdog(watchdog); + // } + // best effort to avoid orphaned child process + executor.setProcessDestroyer(new ShutdownHookProcessDestroyer()); + executor.setWorkingDirectory(basedir); + + log.debug("External java process command line:\n {}", cli); + try { + executor.execute(cli); // this throws ExecuteException if process return code != 0 + } catch (ExecuteException e) { + if (!log.isDebugEnabled()) { + log.info("External java process command line:\n {}", cli); + } + throw e; + } + + final Map> outputs = new HashMap>(); + + CompilerOutput.process(output, new CompilerOutputProcessor() { + @Override + public void processOutput(File inputFile, File outputFile) { + outputs.put(outputFile, context.processOutput(outputFile)); + } - // use the same JVM as the one used to run Maven (the "java.home" one) - String executable = System.getProperty("java.home") + File.separator + "bin" + File.separator + "java"; - if (File.separatorChar == '\\') { - executable = executable + ".exe"; + @Override + public void addMessage(String path, int line, int column, String message, MessageSeverity kind) { + if (".".equals(path)) { + context.addPomMessage(message, kind, null); + } else { + File file = new File(path); + Resource resource = sources.get(file); + if (resource == null) { + resource = outputs.get(file); + } + if (resource != null) { + if (isShowWarnings() || kind != MessageSeverity.WARNING) { + resource.addMessage(line, column, message, kind, null); + } + } else { + log.warn("Unexpected java resource {}", file); + } + } + } + + @Override + public void addLogMessage(String message) { + log.warn(message); + } + }); + } + + public void setBasedir(File basedir) { + this.basedir = basedir; } - CommandLine cli = new CommandLine(executable); + public void setJar(File jar) { + this.jar = jar; + } - // jvm options - cli.addArguments(new String[] {"-cp", jar.getAbsolutePath()}); - if (meminitial != null) { - cli.addArgument("-Xms" + meminitial); + public void setBuildDirectory(File buildDirectory) { + this.buildDirectory = buildDirectory; } - if (maxmem != null) { - cli.addArgument("-Xmx" + maxmem); + + public void setMeminitial(String meminitial) { + this.meminitial = meminitial; } - // main class and program arguments - cli.addArgument(CompilerJavacForked.class.getName()); - cli.addArgument(options.getAbsolutePath(), false); - cli.addArgument(output.getAbsolutePath(), false); - - DefaultExecutor executor = new DefaultExecutor(); - // ExecuteWatchdog watchdog = null; - // if (forkedProcessTimeoutInSeconds > 0) { - // watchdog = new ExecuteWatchdog(forkedProcessTimeoutInSeconds * 1000L); - // executor.setWatchdog(watchdog); - // } - // best effort to avoid orphaned child process - executor.setProcessDestroyer(new ShutdownHookProcessDestroyer()); - executor.setWorkingDirectory(basedir); - - log.debug("External java process command line:\n {}", cli); - try { - executor.execute(cli); // this throws ExecuteException if process return code != 0 - } catch (ExecuteException e) { - if (!log.isDebugEnabled()) { - log.info("External java process command line:\n {}", cli); - } - throw e; + public void setMaxmem(String maxmem) { + this.maxmem = maxmem; } - final Map> outputs = new HashMap>(); - - CompilerOutput.process(output, new CompilerOutputProcessor() { - @Override - public void processOutput(File inputFile, File outputFile) { - outputs.put(outputFile, context.processOutput(outputFile)); - } - - @Override - public void addMessage(String path, int line, int column, String message, MessageSeverity kind) { - if (".".equals(path)) { - context.addPomMessage(message, kind, null); - } else { - File file = new File(path); - Resource resource = sources.get(file); - if (resource == null) { - resource = outputs.get(file); - } - if (resource != null) { - if (isShowWarnings() || kind != MessageSeverity.WARNING) { - resource.addMessage(line, column, message, kind, null); - } - } else { - log.warn("Unexpected java resource {}", file); - } - } - } - - @Override - public void addLogMessage(String message) { - log.warn(message); - } - }); - } - - public void setBasedir(File basedir) { - this.basedir = basedir; - } - - public void setJar(File jar) { - this.jar = jar; - } - - public void setBuildDirectory(File buildDirectory) { - this.buildDirectory = buildDirectory; - } - - public void setMeminitial(String meminitial) { - this.meminitial = meminitial; - } - - public void setMaxmem(String maxmem) { - this.maxmem = maxmem; - } - - @Override - protected String getCompilerId() { - return ID; - } + @Override + protected String getCompilerId() { + return ID; + } } diff --git a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/javac/FileObjects.java b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/javac/FileObjects.java index 2b894988..db30800f 100644 --- a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/javac/FileObjects.java +++ b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/javac/FileObjects.java @@ -1,30 +1,29 @@ -/** - * Copyright (c) 2014 Takari, Inc. +/* + * Copyright (c) 2014-2024 Takari, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * https://www.eclipse.org/legal/epl-v10.html */ package io.takari.maven.plugins.compile.javac; import java.io.File; import java.net.URI; - import javax.tools.FileObject; class FileObjects { - public static File toFile(FileObject fileObject) { - // java6 returns non-absolute URI that cannot be used with new File(URI) - // java7/8 produce messages for .class resources with jar:file:/ URIs + public static File toFile(FileObject fileObject) { + // java6 returns non-absolute URI that cannot be used with new File(URI) + // java7/8 produce messages for .class resources with jar:file:/ URIs - URI uri = fileObject.toUri(); - if (uri == null) { - return null; - } - String path = uri.getPath(); - if (path == null) { - return null; + URI uri = fileObject.toUri(); + if (uri == null) { + return null; + } + String path = uri.getPath(); + if (path == null) { + return null; + } + return new File(path); } - return new File(path); - } } diff --git a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/javac/IncrementalFileOutputStream.java b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/javac/IncrementalFileOutputStream.java index a51ca8fb..8486ff25 100644 --- a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/javac/IncrementalFileOutputStream.java +++ b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/javac/IncrementalFileOutputStream.java @@ -1,9 +1,9 @@ -/** - * Copyright (c) 2014 Takari, Inc. +/* + * Copyright (c) 2014-2024 Takari, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * https://www.eclipse.org/legal/epl-v10.html */ package io.takari.maven.plugins.compile.javac; @@ -12,7 +12,6 @@ * materials are made available under the terms of the Eclipse Public License v1.0 which accompanies * this distribution, and is available at http://www.eclipse.org/legal/epl-v10.html *******************************************************************************/ - import java.io.File; import java.io.IOException; import java.io.OutputStream; @@ -22,94 +21,93 @@ // this is necessary to provide IncrementalFileOutputStream for forked compiler executions // ideally, this class should be moved to a helper library also used by incrementalbuild, // but is not currently supported by mojo unit test harness, and likely will never be -// (in order to add helper library to classpath of forked compiler execution during unit tests, +// (in order to add helper library to classpath of forked compiler execution during unit tests, // the test harness will need to resolve the plugin dependency artifacts somehow, something that // can only be done in the "outer" build and then passed into the test. doable, but a lot of work) class IncrementalFileOutputStream extends OutputStream { - public static final int BUF_SIZE = 1024 * 16; + public static final int BUF_SIZE = 1024 * 16; - private final RandomAccessFile raf; + private final RandomAccessFile raf; - private final byte[] buffer; + private final byte[] buffer; - private boolean modified; + private boolean modified; - public IncrementalFileOutputStream(File file) throws IOException { - if (file == null) { - throw new IllegalArgumentException("output file not specified"); - } + public IncrementalFileOutputStream(File file) throws IOException { + if (file == null) { + throw new IllegalArgumentException("output file not specified"); + } - File parent = file.getParentFile(); + File parent = file.getParentFile(); - if (!parent.isDirectory() && !parent.mkdirs()) { - throw new IOException("Could not create directory " + parent); - } + if (!parent.isDirectory() && !parent.mkdirs()) { + throw new IOException("Could not create directory " + parent); + } - modified = !file.exists(); + modified = !file.exists(); - if (file.exists() && !file.canWrite()) { - file.setWritable(true); - } + if (file.exists() && !file.canWrite()) { + file.setWritable(true); + } - raf = new RandomAccessFile(file, "rw"); - buffer = new byte[BUF_SIZE]; - } + raf = new RandomAccessFile(file, "rw"); + buffer = new byte[BUF_SIZE]; + } - @Override - public void close() throws IOException { - long pos = raf.getFilePointer(); - if (pos < raf.length()) { - modified = true; - raf.setLength(pos); + @Override + public void close() throws IOException { + long pos = raf.getFilePointer(); + if (pos < raf.length()) { + modified = true; + raf.setLength(pos); + } + raf.close(); } - raf.close(); - } - - @Override - public void write(byte[] b, int off, int len) throws IOException { - if (modified) { - raf.write(b, off, len); - } else { - for (int n = len; n > 0;) { - int read = raf.read(buffer, 0, Math.min(buffer.length, n)); - if (read < 0 || !arrayEquals(b, off + len - n, buffer, 0, read)) { - modified = true; - if (read > 0) { - raf.seek(raf.getFilePointer() - read); - } - raf.write(b, off + len - n, n); - break; + + @Override + public void write(byte[] b, int off, int len) throws IOException { + if (modified) { + raf.write(b, off, len); } else { - n -= read; + for (int n = len; n > 0; ) { + int read = raf.read(buffer, 0, Math.min(buffer.length, n)); + if (read < 0 || !arrayEquals(b, off + len - n, buffer, 0, read)) { + modified = true; + if (read > 0) { + raf.seek(raf.getFilePointer() - read); + } + raf.write(b, off + len - n, n); + break; + } else { + n -= read; + } + } } - } } - } - private boolean arrayEquals(byte[] a1, int off1, byte[] a2, int off2, int len) { - for (int i = 0; i < len; i++) { - if (a1[off1 + i] != a2[off2 + i]) { - return false; - } - } - return true; - } - - @Override - public void write(int b) throws IOException { - if (modified) { - raf.write(b); - } else { - int i = raf.read(); - if (i < 0 || i != (b & 0xFF)) { - modified = true; - if (i >= 0) { - raf.seek(raf.getFilePointer() - 1); + private boolean arrayEquals(byte[] a1, int off1, byte[] a2, int off2, int len) { + for (int i = 0; i < len; i++) { + if (a1[off1 + i] != a2[off2 + i]) { + return false; + } } - raf.write(b); - } + return true; } - } + @Override + public void write(int b) throws IOException { + if (modified) { + raf.write(b); + } else { + int i = raf.read(); + if (i < 0 || i != (b & 0xFF)) { + modified = true; + if (i >= 0) { + raf.seek(raf.getFilePointer() - 1); + } + raf.write(b); + } + } + } } diff --git a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/javac/RecordingJavaFileManager.java b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/javac/RecordingJavaFileManager.java index bed2afe6..ebde74dc 100644 --- a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/javac/RecordingJavaFileManager.java +++ b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/javac/RecordingJavaFileManager.java @@ -1,9 +1,9 @@ -/** - * Copyright (c) 2014 Takari, Inc. +/* + * Copyright (c) 2014-2024 Takari, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * https://www.eclipse.org/legal/epl-v10.html */ package io.takari.maven.plugins.compile.javac; @@ -13,7 +13,6 @@ import java.io.OutputStreamWriter; import java.io.Writer; import java.nio.charset.Charset; - import javax.tools.FileObject; import javax.tools.ForwardingFileObject; import javax.tools.ForwardingJavaFileManager; @@ -23,54 +22,61 @@ abstract class RecordingJavaFileManager extends ForwardingJavaFileManager { - private final Charset encoding; + private final Charset encoding; - protected RecordingJavaFileManager(StandardJavaFileManager fileManager, Charset encoding) { - super(fileManager); - this.encoding = encoding; - } + protected RecordingJavaFileManager(StandardJavaFileManager fileManager, Charset encoding) { + super(fileManager); + this.encoding = encoding; + } - @Override - public FileObject getFileForOutput(Location location, String packageName, String relativeName, final FileObject sibling) throws IOException { - FileObject fileObject = super.getFileForOutput(location, packageName, relativeName, sibling); - return new ForwardingFileObject(fileObject) { - @Override - public OutputStream openOutputStream() throws IOException { - record(sibling != null ? FileObjects.toFile(sibling) : null, FileObjects.toFile(fileObject)); - return new IncrementalFileOutputStream(FileObjects.toFile(this)); - } + @Override + public FileObject getFileForOutput( + Location location, String packageName, String relativeName, final FileObject sibling) throws IOException { + FileObject fileObject = super.getFileForOutput(location, packageName, relativeName, sibling); + return new ForwardingFileObject(fileObject) { + @Override + public OutputStream openOutputStream() throws IOException { + record(sibling != null ? FileObjects.toFile(sibling) : null, FileObjects.toFile(fileObject)); + return new IncrementalFileOutputStream(FileObjects.toFile(this)); + } - @Override - public Writer openWriter() throws IOException { - return encoding != null ? new OutputStreamWriter(openOutputStream(), encoding) : new OutputStreamWriter(openOutputStream()); - } - }; - } + @Override + public Writer openWriter() throws IOException { + return encoding != null + ? new OutputStreamWriter(openOutputStream(), encoding) + : new OutputStreamWriter(openOutputStream()); + } + }; + } - @Override - public JavaFileObject getJavaFileForOutput(Location location, String className, javax.tools.JavaFileObject.Kind kind, final FileObject sibling) throws IOException { - JavaFileObject fileObject = super.getJavaFileForOutput(location, className, kind, sibling); - return new ForwardingJavaFileObject(fileObject) { - @Override - public OutputStream openOutputStream() throws IOException { - record(sibling != null ? FileObjects.toFile(sibling) : null, FileObjects.toFile(fileObject)); - return new IncrementalFileOutputStream(FileObjects.toFile(this)); - } + @Override + public JavaFileObject getJavaFileForOutput( + Location location, String className, javax.tools.JavaFileObject.Kind kind, final FileObject sibling) + throws IOException { + JavaFileObject fileObject = super.getJavaFileForOutput(location, className, kind, sibling); + return new ForwardingJavaFileObject(fileObject) { + @Override + public OutputStream openOutputStream() throws IOException { + record(sibling != null ? FileObjects.toFile(sibling) : null, FileObjects.toFile(fileObject)); + return new IncrementalFileOutputStream(FileObjects.toFile(this)); + } - @Override - public Writer openWriter() throws IOException { - return encoding != null ? new OutputStreamWriter(openOutputStream(), encoding) : new OutputStreamWriter(openOutputStream()); - } - }; - } + @Override + public Writer openWriter() throws IOException { + return encoding != null + ? new OutputStreamWriter(openOutputStream(), encoding) + : new OutputStreamWriter(openOutputStream()); + } + }; + } - // although JavaFileManager is rather vague about this, - // javac provides input .java file as 'sibling' of output .class file - // javac does not provide sources of files generated by annotation processors - protected abstract void record(File inputFile, File outputFile); + // although JavaFileManager is rather vague about this, + // javac provides input .java file as 'sibling' of output .class file + // javac does not provide sources of files generated by annotation processors + protected abstract void record(File inputFile, File outputFile); - @Override - public boolean isSameFile(FileObject a, FileObject b) { - return a.toUri().equals(b.toUri()); - } + @Override + public boolean isSameFile(FileObject a, FileObject b) { + return a.toUri().equals(b.toUri()); + } } diff --git a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/AccessRestrictionClasspathEntry.java b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/AccessRestrictionClasspathEntry.java index 4032b40c..33e8d3c8 100644 --- a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/AccessRestrictionClasspathEntry.java +++ b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/AccessRestrictionClasspathEntry.java @@ -1,51 +1,58 @@ +/* + * Copyright (c) 2014-2024 Takari, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v10.html + */ package io.takari.maven.plugins.compile.jdt; +import io.takari.maven.plugins.compile.jdt.classpath.ClasspathEntry; +import io.takari.maven.plugins.compile.jdt.classpath.DependencyClasspathEntry; import java.util.Collection; - import org.eclipse.jdt.core.compiler.IProblem; import org.eclipse.jdt.internal.compiler.env.AccessRestriction; import org.eclipse.jdt.internal.compiler.env.AccessRule; import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer; -import io.takari.maven.plugins.compile.jdt.classpath.ClasspathEntry; -import io.takari.maven.plugins.compile.jdt.classpath.DependencyClasspathEntry; - class AccessRestrictionClasspathEntry implements ClasspathEntry { - private final DependencyClasspathEntry entry; - private final AccessRestriction accessRestriction; - - private AccessRestrictionClasspathEntry(DependencyClasspathEntry entry, AccessRestriction accessRestriction) { - this.entry = entry; - this.accessRestriction = accessRestriction; - } - - @Override - public Collection getPackageNames() { - return entry.getPackageNames(); - } - - @Override - public NameEnvironmentAnswer findType(String packageName, String typeName) { - return entry.findType(packageName, typeName, accessRestriction); - } - - @Override - public String getEntryDescription() { - StringBuilder sb = new StringBuilder(); - sb.append(entry.getEntryName()); - if (accessRestriction != null) { - sb.append("[?**/*]"); + private final DependencyClasspathEntry entry; + private final AccessRestriction accessRestriction; + + private AccessRestrictionClasspathEntry(DependencyClasspathEntry entry, AccessRestriction accessRestriction) { + this.entry = entry; + this.accessRestriction = accessRestriction; + } + + @Override + public Collection getPackageNames() { + return entry.getPackageNames(); + } + + @Override + public NameEnvironmentAnswer findType(String packageName, String typeName) { + return entry.findType(packageName, typeName, accessRestriction); + } + + @Override + public String getEntryDescription() { + StringBuilder sb = new StringBuilder(); + sb.append(entry.getEntryName()); + if (accessRestriction != null) { + sb.append("[?**/*]"); + } + return sb.toString(); + } + + public static AccessRestrictionClasspathEntry forbidAll(DependencyClasspathEntry entry) { + AccessRule accessRule = new AccessRule( + null /* pattern */, IProblem.ForbiddenReference, true /* keep looking for accessible type */); + AccessRestriction accessRestriction = + new AccessRestriction(accessRule, AccessRestriction.COMMAND_LINE, entry.getEntryName()); + return new AccessRestrictionClasspathEntry(entry, accessRestriction); + } + + public static AccessRestrictionClasspathEntry allowAll(DependencyClasspathEntry entry) { + return new AccessRestrictionClasspathEntry(entry, null); } - return sb.toString(); - } - - public static AccessRestrictionClasspathEntry forbidAll(DependencyClasspathEntry entry) { - AccessRule accessRule = new AccessRule(null /* pattern */, IProblem.ForbiddenReference, true /* keep looking for accessible type */); - AccessRestriction accessRestriction = new AccessRestriction(accessRule, AccessRestriction.COMMAND_LINE, entry.getEntryName()); - return new AccessRestrictionClasspathEntry(entry, accessRestriction); - } - - public static AccessRestrictionClasspathEntry allowAll(DependencyClasspathEntry entry) { - return new AccessRestrictionClasspathEntry(entry, null); - } } diff --git a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/AnnotationProcessingState.java b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/AnnotationProcessingState.java index 64217523..149a9af4 100644 --- a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/AnnotationProcessingState.java +++ b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/AnnotationProcessingState.java @@ -1,9 +1,9 @@ -/** - * Copyright (c) 2017 Salesforce.com, Inc. +/* + * Copyright (c) 2014-2024 Takari, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * https://www.eclipse.org/legal/epl-v10.html */ package io.takari.maven.plugins.compile.jdt; @@ -18,14 +18,14 @@ */ class AnnotationProcessingState implements Serializable { - public final Set processedSources; - public final ReferenceCollection referencedTypes; - public final Set writtenOutputs; - - public AnnotationProcessingState(Set processedSources, ReferenceCollection referencedTypes, Set writtenOutputs) { - this.processedSources = Collections.unmodifiableSet(new LinkedHashSet<>(processedSources)); - this.referencedTypes = referencedTypes; - this.writtenOutputs = Collections.unmodifiableSet(new LinkedHashSet<>(writtenOutputs)); - } + public final Set processedSources; + public final ReferenceCollection referencedTypes; + public final Set writtenOutputs; + public AnnotationProcessingState( + Set processedSources, ReferenceCollection referencedTypes, Set writtenOutputs) { + this.processedSources = Collections.unmodifiableSet(new LinkedHashSet<>(processedSources)); + this.referencedTypes = referencedTypes; + this.writtenOutputs = Collections.unmodifiableSet(new LinkedHashSet<>(writtenOutputs)); + } } diff --git a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/AnnotationProcessorManager.java b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/AnnotationProcessorManager.java index 43eb7a84..36806845 100644 --- a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/AnnotationProcessorManager.java +++ b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/AnnotationProcessorManager.java @@ -1,5 +1,14 @@ +/* + * Copyright (c) 2014-2024 Takari, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v10.html + */ package io.takari.maven.plugins.compile.jdt; +import io.takari.incrementalbuild.MessageSeverity; +import io.takari.maven.plugins.compile.CompilerBuildContext; import java.io.File; import java.io.PrintWriter; import java.util.Collections; @@ -8,14 +17,12 @@ import java.util.ServiceLoader; import java.util.Set; import java.util.function.Supplier; - import javax.annotation.processing.Processor; import javax.lang.model.element.Element; import javax.lang.model.element.NestingKind; import javax.lang.model.element.TypeElement; import javax.tools.StandardJavaFileManager; import javax.tools.StandardLocation; - import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseAnnotationProcessorManager; import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseProcessingEnvImpl; import org.eclipse.jdt.internal.compiler.apt.dispatch.ProcessorInfo; @@ -29,250 +36,260 @@ import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding; import org.eclipse.jdt.internal.compiler.problem.AbortCompilation; -import io.takari.incrementalbuild.MessageSeverity; -import io.takari.maven.plugins.compile.CompilerBuildContext; - // TODO reconcile with BatchAnnotationProcessorManager class AnnotationProcessorManager extends BaseAnnotationProcessorManager { - private final CompilerBuildContext context; + private final CompilerBuildContext context; - private final Set processedSources = new LinkedHashSet<>(); + private final Set processedSources = new LinkedHashSet<>(); - private boolean recordingReferencedTypes = true; - private final Set referencedTypes = new LinkedHashSet<>(); + private boolean recordingReferencedTypes = true; + private final Set referencedTypes = new LinkedHashSet<>(); - private boolean suppressRegularRounds = false; - private boolean suppressLastRound = false; + private boolean suppressRegularRounds = false; + private boolean suppressLastRound = false; - private final Iterator processors; + private final Iterator processors; - private final CompilerJdt incrementalCompiler; + private final CompilerJdt incrementalCompiler; - private static class SpecifiedProcessors implements Iterator { + private static class SpecifiedProcessors implements Iterator { - private final ClassLoader loader; - private final String[] processors; - private int idx; + private final ClassLoader loader; + private final String[] processors; + private int idx; - public SpecifiedProcessors(ClassLoader loader, String[] processors) { - this.loader = loader; - this.processors = processors; - } + public SpecifiedProcessors(ClassLoader loader, String[] processors) { + this.loader = loader; + this.processors = processors; + } - @Override - public boolean hasNext() { - return idx < processors.length; - } + @Override + public boolean hasNext() { + return idx < processors.length; + } - @Override - public Processor next() { - try { - return (Processor) loader.loadClass(processors[idx++]).newInstance(); - } catch (ReflectiveOperationException e) { - // TODO: better error handling - throw new AbortCompilation(null, e); - } - } + @Override + public Processor next() { + try { + return (Processor) loader.loadClass(processors[idx++]).newInstance(); + } catch (ReflectiveOperationException e) { + // TODO: better error handling + throw new AbortCompilation(null, e); + } + } - @Override - public void remove() { - throw new UnsupportedOperationException(); + @Override + public void remove() { + throw new UnsupportedOperationException(); + } } - } - private static class DiscoveredProcessors implements Iterator { + private static class DiscoveredProcessors implements Iterator { + + private final ServiceLoader loader; + private final Iterator iterator; + + public DiscoveredProcessors(ClassLoader procLoader) { + this.loader = ServiceLoader.load(Processor.class, procLoader); + this.iterator = loader.iterator(); + } + + @Override + public boolean hasNext() { + return iterator.hasNext(); + } + + @Override + public Processor next() { + return iterator.next(); + } - private final ServiceLoader loader; - private final Iterator iterator; + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + } - public DiscoveredProcessors(ClassLoader procLoader) { - this.loader = ServiceLoader.load(Processor.class, procLoader); - this.iterator = loader.iterator(); + public AnnotationProcessorManager( + CompilerBuildContext context, + ProcessingEnvImpl processingEnv, + StandardJavaFileManager fileManager, + String[] processors, + CompilerJdt incrementalCompiler) { + this.context = context; + this._processingEnv = processingEnv; + this.incrementalCompiler = incrementalCompiler; + ClassLoader procLoader = fileManager.getClassLoader(StandardLocation.ANNOTATION_PROCESSOR_PATH); + this.processors = processors != null // + ? new SpecifiedProcessors(procLoader, processors) // + : new DiscoveredProcessors(procLoader); + processingEnv.addReferencedTypeObserver(this::recordReferencedType); } - @Override - public boolean hasNext() { - return iterator.hasNext(); + private void recordReferencedType(String type) { + if (recordingReferencedTypes) { + referencedTypes.add(type); + } } @Override - public Processor next() { - return iterator.next(); + public ProcessorInfo discoverNextProcessor() { + if (processors.hasNext()) { + Processor processor = processors.next(); + processor.init(_processingEnv); + ProcessorInfo procecssorInfo = new ProcessorInfo(processor) { + + // the goal is to notify incrementalCompiler when annotation processing is taking place + // as of jdt.apt 1.3.0 this method is called right before running an annotation processor + // which is close enough to what we need + @Override + public boolean computeSupportedAnnotations(Set annotations, Set result) { + boolean shouldCall = super.computeSupportedAnnotations(annotations, result); + if (shouldCall) { + incrementalCompiler.onAnnotationProcessing(); + } + return shouldCall; + } + }; + _processors.add(procecssorInfo); // TODO this needs to happen in RoundDispatcher.round() + return procecssorInfo; + } + return null; } @Override - public void remove() { - throw new UnsupportedOperationException(); + public void reportProcessorException(Processor p, Exception e) { + String msg = String.format( + "Exception executing annotation processor %s: %s", p.getClass().getName(), e.getMessage()); + context.addPomMessage(msg, MessageSeverity.ERROR, e); + throw new AbortCompilation(null, e); } - } - - public AnnotationProcessorManager(CompilerBuildContext context, ProcessingEnvImpl processingEnv, StandardJavaFileManager fileManager, String[] processors, CompilerJdt incrementalCompiler) { - this.context = context; - this._processingEnv = processingEnv; - this.incrementalCompiler = incrementalCompiler; - ClassLoader procLoader = fileManager.getClassLoader(StandardLocation.ANNOTATION_PROCESSOR_PATH); - this.processors = processors != null // - ? new SpecifiedProcessors(procLoader, processors) // - : new DiscoveredProcessors(procLoader); - processingEnv.addReferencedTypeObserver(this::recordReferencedType); - } - - private void recordReferencedType(String type) { - if (recordingReferencedTypes) { - referencedTypes.add(type); + + /** + * Resets this annotation processor manager between incremental compiler loop iterations. + */ + public void incrementalIterationReset() { + ((ProcessingEnvImpl) _processingEnv).incrementalIterationReset(); } - } - - @Override - public ProcessorInfo discoverNextProcessor() { - if (processors.hasNext()) { - Processor processor = processors.next(); - processor.init(_processingEnv); - ProcessorInfo procecssorInfo = new ProcessorInfo(processor) { - - // the goal is to notify incrementalCompiler when annotation processing is taking place - // as of jdt.apt 1.3.0 this method is called right before running an annotation processor - // which is close enough to what we need + + private class _RoundEnvImpl extends RoundEnvImpl { + + public _RoundEnvImpl( + CompilationUnitDeclaration[] units, + ReferenceBinding[] binaryTypeBindings, + boolean isLastRound, + BaseProcessingEnvImpl env) { + super(units, binaryTypeBindings, isLastRound, env); + } + + // NB getElementsAnnotatedWith(Class) delegates to getElementsAnnotatedWith(TypeElement) + @Override - public boolean computeSupportedAnnotations(Set annotations, Set result) { - boolean shouldCall = super.computeSupportedAnnotations(annotations, result); - if (shouldCall) { - incrementalCompiler.onAnnotationProcessing(); - } - return shouldCall; + public Set getElementsAnnotatedWith(TypeElement a) { + return recordProcessedSources(() -> super.getElementsAnnotatedWith(a)); } - }; - _processors.add(procecssorInfo); // TODO this needs to happen in RoundDispatcher.round() - return procecssorInfo; - } - return null; - } - - @Override - public void reportProcessorException(Processor p, Exception e) { - String msg = String.format("Exception executing annotation processor %s: %s", p.getClass().getName(), e.getMessage()); - context.addPomMessage(msg, MessageSeverity.ERROR, e); - throw new AbortCompilation(null, e); - } - - /** - * Resets this annotation processor manager between incremental compiler loop iterations. - */ - public void incrementalIterationReset() { - ((ProcessingEnvImpl) _processingEnv).incrementalIterationReset(); - } - - private class _RoundEnvImpl extends RoundEnvImpl { - - public _RoundEnvImpl(CompilationUnitDeclaration[] units, ReferenceBinding[] binaryTypeBindings, boolean isLastRound, BaseProcessingEnvImpl env) { - super(units, binaryTypeBindings, isLastRound, env); - } - // NB getElementsAnnotatedWith(Class) delegates to getElementsAnnotatedWith(TypeElement) + @Override + public Set getRootElements() { + return recordProcessedSources(super::getRootElements); + } - @Override - public Set getElementsAnnotatedWith(TypeElement a) { - return recordProcessedSources(() -> super.getElementsAnnotatedWith(a)); + private Set recordProcessedSources(Supplier> elementsSupplier) { + final boolean _recordingReferencedTypes = recordingReferencedTypes; + try { + recordingReferencedTypes = false; + Set elements = elementsSupplier.get(); + if (_recordingReferencedTypes) { + for (Element element : elements) { + File sourceFile = getSourceFile((ElementImpl) element); + if (sourceFile != null) { + processedSources.add(sourceFile); + } + } + } + + return elements; + } finally { + recordingReferencedTypes = _recordingReferencedTypes; + } + } + + /** + * Given {@code Element}, returns source file that defines the element. Returns {@code null} if the element is not defined in a source file. + */ + private File getSourceFile(ElementImpl element) { + TypeElementImpl topLevelType = getTopLevelType(element); + if (topLevelType == null) { + // TODO package-info.java annotation? + return null; + } + Binding binding = topLevelType._binding; + if (binding instanceof SourceTypeBinding) { + return new File(new String(((SourceTypeBinding) binding).getFileName())); + } + return null; + } + + /** + * Returns enclosing top-level type of the element. Returns {@code null} if the element does not have enclosing top-level type. + */ + private TypeElementImpl getTopLevelType(ElementImpl element) { + for (; element != null; element = (ElementImpl) element.getEnclosingElement()) { + if (element instanceof TypeElementImpl + && ((TypeElementImpl) element).getNestingKind() == NestingKind.TOP_LEVEL) { + return (TypeElementImpl) element; + } + } + return null; + } } + // copied from BaseAnnotationProcessorManager in order to create custom RoundEnvImpl impl. boo. @Override - public Set getRootElements() { - return recordProcessedSources( super::getRootElements ); - } + public void processAnnotations( + CompilationUnitDeclaration[] units, ReferenceBinding[] referenceBindings, boolean isLastRound) { + if (!isLastRound && suppressRegularRounds) { + return; + } - private Set recordProcessedSources(Supplier> elementsSupplier) { - final boolean _recordingReferencedTypes = recordingReferencedTypes; - try { - recordingReferencedTypes = false; - Set elements = elementsSupplier.get(); - if (_recordingReferencedTypes) { - for (Element element : elements) { - File sourceFile = getSourceFile((ElementImpl) element); - if (sourceFile != null) { - processedSources.add(sourceFile); - } - } + if (isLastRound && suppressLastRound) { + return; } - return elements; - } finally { - recordingReferencedTypes = _recordingReferencedTypes; - } + RoundEnvImpl roundEnv = new _RoundEnvImpl(units, referenceBindings, isLastRound, _processingEnv); + if (_isFirstRound) { + _isFirstRound = false; + } + PrintWriter traceProcessorInfo = _printProcessorInfo ? _out : null; + PrintWriter traceRounds = _printRounds ? _out : null; + if (traceRounds != null) { + traceRounds.println("Round " + ++_round + ':'); // $NON-NLS-1$ + } + RoundDispatcher dispatcher = + new RoundDispatcher(this, roundEnv, roundEnv.getRootAnnotations(), traceProcessorInfo, traceRounds); + dispatcher.round(); } - /** - * Given {@code Element}, returns source file that defines the element. Returns {@code null} if the element is not defined in a source file. - */ - private File getSourceFile(ElementImpl element) { - TypeElementImpl topLevelType = getTopLevelType(element); - if (topLevelType == null) { - // TODO package-info.java annotation? - return null; - } - Binding binding = topLevelType._binding; - if (binding instanceof SourceTypeBinding) { - return new File(new String(((SourceTypeBinding) binding).getFileName())); - } - return null; + public void suppressRegularRounds(boolean suppress) { + this.suppressRegularRounds = suppress; } - /** - * Returns enclosing top-level type of the element. Returns {@code null} if the element does not have enclosing top-level type. - */ - private TypeElementImpl getTopLevelType(ElementImpl element) { - for (; element != null; element = (ElementImpl) element.getEnclosingElement()) { - if (element instanceof TypeElementImpl && ((TypeElementImpl) element).getNestingKind() == NestingKind.TOP_LEVEL) { - return (TypeElementImpl) element; - } - } - return null; + public void suppressLastRound(boolean suppress) { + this.suppressLastRound = suppress; } - } - // copied from BaseAnnotationProcessorManager in order to create custom RoundEnvImpl impl. boo. - @Override - public void processAnnotations(CompilationUnitDeclaration[] units, ReferenceBinding[] referenceBindings, boolean isLastRound) { - if (!isLastRound && suppressRegularRounds) { - return; + public Set getProcessedSources() { + return Collections.unmodifiableSet(new LinkedHashSet<>(processedSources)); } - if (isLastRound && suppressLastRound) { - return; + public ReferenceCollection getReferencedTypes() { + ReferenceCollection references = new ReferenceCollection(); + references.addDependencies(referencedTypes); + return references; } - RoundEnvImpl roundEnv = new _RoundEnvImpl(units, referenceBindings, isLastRound, _processingEnv); - if (_isFirstRound) { - _isFirstRound = false; - } - PrintWriter traceProcessorInfo = _printProcessorInfo ? _out : null; - PrintWriter traceRounds = _printRounds ? _out : null; - if (traceRounds != null) { - traceRounds.println("Round " + ++_round + ':'); //$NON-NLS-1$ + public Set getWittenOutputs() { + return ((FilerImpl) _processingEnv.getFiler()).getWrittenFiles(); } - RoundDispatcher dispatcher = new RoundDispatcher(this, roundEnv, roundEnv.getRootAnnotations(), traceProcessorInfo, traceRounds); - dispatcher.round(); - } - - public void suppressRegularRounds(boolean suppress) { - this.suppressRegularRounds = suppress; - } - - public void suppressLastRound(boolean suppress) { - this.suppressLastRound = suppress; - } - - public Set getProcessedSources() { - return Collections.unmodifiableSet(new LinkedHashSet<>(processedSources)); - } - - public ReferenceCollection getReferencedTypes() { - ReferenceCollection references = new ReferenceCollection(); - references.addDependencies(referencedTypes); - return references; - } - - public Set getWittenOutputs() { - return ((FilerImpl) _processingEnv.getFiler()).getWrittenFiles(); - } } diff --git a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/ClassfileDigester.java b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/ClassfileDigester.java index d81cfc5a..2b3b3b67 100644 --- a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/ClassfileDigester.java +++ b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/ClassfileDigester.java @@ -1,16 +1,15 @@ -/** - * Copyright (c) 2014 Takari, Inc. +/* + * Copyright (c) 2014-2024 Takari, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * https://www.eclipse.org/legal/epl-v10.html */ package io.takari.maven.plugins.compile.jdt; import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; - import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader; import org.eclipse.jdt.internal.compiler.classfmt.FieldInfo; import org.eclipse.jdt.internal.compiler.classfmt.MethodInfo; @@ -28,290 +27,290 @@ /** * Adopted from {@link ClassFileReader#hasStructuralChanges(byte[], boolean, boolean)} - * + * * Last updated to match JDT I20171206-0800. */ public class ClassfileDigester { - private final MessageDigest digester; + private final MessageDigest digester; - public ClassfileDigester() { - try { - digester = MessageDigest.getInstance("SHA1"); - } catch (NoSuchAlgorithmException e) { - throw new IllegalStateException("Unsupported JVM", e); - } - } - - public byte[] digest(IBinaryType classFile) { - - // type level comparison - // modifiers - updateInt(classFile.getModifiers()); - - // only consider a portion of the tagbits which indicate a structural change for dependents - // e.g. @Override change has no influence outside - long OnlyStructuralTagBits = TagBits.AnnotationTargetMASK // different @Target status ? - | TagBits.AnnotationDeprecated // different @Deprecated status ? - | TagBits.AnnotationRetentionMASK // different @Retention status ? - | TagBits.HierarchyHasProblems; // different hierarchy status ? - - // meta-annotations - updateLong(classFile.getTagBits() & OnlyStructuralTagBits); - // annotations - updateAnnotations(classFile.getAnnotations()); - updateTypeAnnotations(classFile.getTypeAnnotations()); - - // generic signature - updateChars(classFile.getGenericSignature()); - // superclass - updateChars(classFile.getSuperclassName()); - // interfaces - char[][] interfacesNames = classFile.getInterfaceNames(); - if (interfacesNames != null) { - for ( char[] interfacesName : interfacesNames ) { - updateChars( interfacesName ); - } + public ClassfileDigester() { + try { + digester = MessageDigest.getInstance("SHA1"); + } catch (NoSuchAlgorithmException e) { + throw new IllegalStateException("Unsupported JVM", e); + } } - // member types - IBinaryNestedType[] memberTypes = classFile.getMemberTypes(); - if (memberTypes != null) { - for ( IBinaryNestedType memberType : memberTypes ) { - updateChars( memberType.getName() ); - updateInt( memberType.getModifiers() ); - } - } + public byte[] digest(IBinaryType classFile) { + + // type level comparison + // modifiers + updateInt(classFile.getModifiers()); + + // only consider a portion of the tagbits which indicate a structural change for dependents + // e.g. @Override change has no influence outside + long OnlyStructuralTagBits = TagBits.AnnotationTargetMASK // different @Target status ? + | TagBits.AnnotationDeprecated // different @Deprecated status ? + | TagBits.AnnotationRetentionMASK // different @Retention status ? + | TagBits.HierarchyHasProblems; // different hierarchy status ? + + // meta-annotations + updateLong(classFile.getTagBits() & OnlyStructuralTagBits); + // annotations + updateAnnotations(classFile.getAnnotations()); + updateTypeAnnotations(classFile.getTypeAnnotations()); + + // generic signature + updateChars(classFile.getGenericSignature()); + // superclass + updateChars(classFile.getSuperclassName()); + // interfaces + char[][] interfacesNames = classFile.getInterfaceNames(); + if (interfacesNames != null) { + for (char[] interfacesName : interfacesNames) { + updateChars(interfacesName); + } + } - // fields - FieldInfo[] fieldInfos = (FieldInfo[]) classFile.getFields(); - if (fieldInfos != null) { - for ( FieldInfo fieldInfo : fieldInfos ) { - updateField( fieldInfo ); - } - } + // member types + IBinaryNestedType[] memberTypes = classFile.getMemberTypes(); + if (memberTypes != null) { + for (IBinaryNestedType memberType : memberTypes) { + updateChars(memberType.getName()); + updateInt(memberType.getModifiers()); + } + } - // methods - MethodInfo[] methodInfos = (MethodInfo[]) classFile.getMethods(); - if (methodInfos != null) { - for ( MethodInfo methodInfo : methodInfos ) { - updateMethod( classFile, methodInfo ); - } - } + // fields + FieldInfo[] fieldInfos = (FieldInfo[]) classFile.getFields(); + if (fieldInfos != null) { + for (FieldInfo fieldInfo : fieldInfos) { + updateField(fieldInfo); + } + } - // missing types - char[][][] missingTypes = classFile.getMissingTypeNames(); - if (missingTypes != null) { - for (int i = 0; i < missingTypes.length; i++) { - for (int j = 0; j < missingTypes[i].length; j++) { - if (j > 0) { - updateChar('.'); // don't ask why - } - updateChars(missingTypes[i][j]); + // methods + MethodInfo[] methodInfos = (MethodInfo[]) classFile.getMethods(); + if (methodInfos != null) { + for (MethodInfo methodInfo : methodInfos) { + updateMethod(classFile, methodInfo); + } + } + + // missing types + char[][][] missingTypes = classFile.getMissingTypeNames(); + if (missingTypes != null) { + for (int i = 0; i < missingTypes.length; i++) { + for (int j = 0; j < missingTypes[i].length; j++) { + if (j > 0) { + updateChar('.'); // don't ask why + } + updateChars(missingTypes[i][j]); + } + } } - } - } - return digester.digest(); - } - - private void updateMethod(IBinaryType classFile, MethodInfo methodInfo) { - // generic signature - updateChars(methodInfo.getGenericSignature()); - updateInt(methodInfo.getModifiers()); - updateLong(methodInfo.getTagBits() & TagBits.AnnotationDeprecated); - updateAnnotations(methodInfo.getAnnotations()); - // parameter annotations: - for (int i = 0; i < methodInfo.getAnnotatedParametersCount(); i++) { - updateAnnotations(methodInfo.getParameterAnnotations(i, classFile.getName())); + return digester.digest(); } - updateTypeAnnotations(methodInfo.getTypeAnnotations()); - updateChars(methodInfo.getSelector()); - updateChars(methodInfo.getMethodDescriptor()); - updateChars(methodInfo.getGenericSignature()); + private void updateMethod(IBinaryType classFile, MethodInfo methodInfo) { + // generic signature + updateChars(methodInfo.getGenericSignature()); + updateInt(methodInfo.getModifiers()); + updateLong(methodInfo.getTagBits() & TagBits.AnnotationDeprecated); + updateAnnotations(methodInfo.getAnnotations()); + // parameter annotations: + for (int i = 0; i < methodInfo.getAnnotatedParametersCount(); i++) { + updateAnnotations(methodInfo.getParameterAnnotations(i, classFile.getName())); + } + updateTypeAnnotations(methodInfo.getTypeAnnotations()); + + updateChars(methodInfo.getSelector()); + updateChars(methodInfo.getMethodDescriptor()); + updateChars(methodInfo.getGenericSignature()); - char[][] thrownExceptions = methodInfo.getExceptionTypeNames(); - for ( char[] thrownException : thrownExceptions ) { - updateChars( thrownException ); + char[][] thrownExceptions = methodInfo.getExceptionTypeNames(); + for (char[] thrownException : thrownExceptions) { + updateChars(thrownException); + } + } + + private void updateField(FieldInfo fieldInfo) { + // generic signature + updateChars(fieldInfo.getGenericSignature()); + updateInt(fieldInfo.getModifiers()); + updateLong(fieldInfo.getTagBits() & TagBits.AnnotationDeprecated); + updateAnnotations(fieldInfo.getAnnotations()); + updateTypeAnnotations(fieldInfo.getTypeAnnotations()); + updateChars(fieldInfo.getName()); + updateChars(fieldInfo.getTypeName()); + updateBoolean(fieldInfo.hasConstant()); + if (fieldInfo.hasConstant()) { + updateConstant(fieldInfo.getConstant()); + } } - } - - private void updateField(FieldInfo fieldInfo) { - // generic signature - updateChars(fieldInfo.getGenericSignature()); - updateInt(fieldInfo.getModifiers()); - updateLong(fieldInfo.getTagBits() & TagBits.AnnotationDeprecated); - updateAnnotations(fieldInfo.getAnnotations()); - updateTypeAnnotations(fieldInfo.getTypeAnnotations()); - updateChars(fieldInfo.getName()); - updateChars(fieldInfo.getTypeName()); - updateBoolean(fieldInfo.hasConstant()); - if (fieldInfo.hasConstant()) { - updateConstant(fieldInfo.getConstant()); + + private void updateConstant(Constant constant) { + updateInt(constant.typeID()); + updateString(constant.getClass().getName()); + switch (constant.typeID()) { + case TypeIds.T_int: + updateInt(constant.intValue()); + break; + case TypeIds.T_byte: + updateByte(constant.byteValue()); + break; + case TypeIds.T_short: + updateShort(constant.shortValue()); + break; + case TypeIds.T_char: + updateChar(constant.charValue()); + break; + case TypeIds.T_long: + updateLong(constant.longValue()); + break; + case TypeIds.T_float: + updateFloat(constant.floatValue()); + break; + case TypeIds.T_double: + updateDouble(constant.doubleValue()); + break; + case TypeIds.T_boolean: + updateBoolean(constant.booleanValue()); + break; + case TypeIds.T_JavaLangString: + updateString(constant.stringValue()); + break; + default: + throw new IllegalArgumentException("Unexpected constant typeID=" + constant.typeID()); + } } - } - - private void updateConstant(Constant constant) { - updateInt(constant.typeID()); - updateString(constant.getClass().getName()); - switch (constant.typeID()) { - case TypeIds.T_int: - updateInt(constant.intValue()); - break; - case TypeIds.T_byte: - updateByte(constant.byteValue()); - break; - case TypeIds.T_short: - updateShort(constant.shortValue()); - break; - case TypeIds.T_char: - updateChar(constant.charValue()); - break; - case TypeIds.T_long: - updateLong(constant.longValue()); - break; - case TypeIds.T_float: - updateFloat(constant.floatValue()); - break; - case TypeIds.T_double: - updateDouble(constant.doubleValue()); - break; - case TypeIds.T_boolean: - updateBoolean(constant.booleanValue()); - break; - case TypeIds.T_JavaLangString: - updateString(constant.stringValue()); - break; - default: - throw new IllegalArgumentException("Unexpected constant typeID=" + constant.typeID()); + + private void updateAnnotations(IBinaryAnnotation[] annotations) { + if (annotations != null) { + for (IBinaryAnnotation annotation : annotations) { + updateAnnotation(annotation); + } + } } - } - private void updateAnnotations(IBinaryAnnotation[] annotations) { - if (annotations != null) { - for ( IBinaryAnnotation annotation : annotations ) { - updateAnnotation( annotation ); - } + private void updateAnnotation(IBinaryAnnotation annotation) { + updateChars(annotation.getTypeName()); + IBinaryElementValuePair[] pairs = annotation.getElementValuePairs(); + for (int j = 0; j < pairs.length; j++) { + updateChars(pairs[j].getName()); + final Object value = pairs[j].getValue(); + if (value instanceof Object[]) { + Object[] values = (Object[]) value; + for (int n = 0; n < values.length; n++) { + updateAnnotationValue(values[n]); + } + } else { + updateAnnotationValue(value); + } + } } - } - - private void updateAnnotation(IBinaryAnnotation annotation) { - updateChars(annotation.getTypeName()); - IBinaryElementValuePair[] pairs = annotation.getElementValuePairs(); - for (int j = 0; j < pairs.length; j++) { - updateChars(pairs[j].getName()); - final Object value = pairs[j].getValue(); - if (value instanceof Object[]) { - Object[] values = (Object[]) value; - for (int n = 0; n < values.length; n++) { - updateAnnotationValue(values[n]); + + private void updateAnnotationValue(Object object) { + // @see org.eclipse.jdt.internal.compiler.env.IBinaryElementValuePair.getValue() + // @see org.eclipse.jdt.internal.compiler.classfmt.AnnotationInfo.decodeDefaultValue() + if (object instanceof ClassSignature) { + updateChars(((ClassSignature) object).getTypeName()); + } else if (object instanceof Constant) { + updateConstant((Constant) object); + } else if (object instanceof EnumConstantSignature) { + updateChars(((EnumConstantSignature) object).getTypeName()); + updateChars(((EnumConstantSignature) object).getEnumConstantName()); + } else if (object instanceof IBinaryAnnotation) { + updateAnnotation((IBinaryAnnotation) object); + } else { + throw new IllegalArgumentException("Unsupported annotation value " + object.toString()); } - } else { - updateAnnotationValue(value); - } } - } - - private void updateAnnotationValue(Object object) { - // @see org.eclipse.jdt.internal.compiler.env.IBinaryElementValuePair.getValue() - // @see org.eclipse.jdt.internal.compiler.classfmt.AnnotationInfo.decodeDefaultValue() - if (object instanceof ClassSignature) { - updateChars(((ClassSignature) object).getTypeName()); - } else if (object instanceof Constant) { - updateConstant((Constant) object); - } else if (object instanceof EnumConstantSignature) { - updateChars(((EnumConstantSignature) object).getTypeName()); - updateChars(((EnumConstantSignature) object).getEnumConstantName()); - } else if (object instanceof IBinaryAnnotation) { - updateAnnotation((IBinaryAnnotation) object); - } else { - throw new IllegalArgumentException("Unsupported annotation value " + object.toString()); + + private void updateTypeAnnotations(IBinaryTypeAnnotation[] typeAnnotations) { + if (typeAnnotations != null) { + for (IBinaryTypeAnnotation typeAnnotation : typeAnnotations) { + if (!affectsSignature(typeAnnotation)) { + continue; + } + updateAnnotation(typeAnnotation.getAnnotation()); + } + } } - } - private void updateTypeAnnotations(IBinaryTypeAnnotation[] typeAnnotations) { - if (typeAnnotations != null) { - for (IBinaryTypeAnnotation typeAnnotation : typeAnnotations) { - if (!affectsSignature(typeAnnotation)) { - continue; + private boolean affectsSignature(IBinaryTypeAnnotation typeAnnotation) { + int targetType = typeAnnotation.getTargetType(); + if (targetType >= AnnotationTargetTypeConstants.LOCAL_VARIABLE + && targetType <= AnnotationTargetTypeConstants.METHOD_REFERENCE_TYPE_ARGUMENT) { + return false; // affects detail within a block } - updateAnnotation(typeAnnotation.getAnnotation()); - } + return true; } - } - private boolean affectsSignature(IBinaryTypeAnnotation typeAnnotation) { - int targetType = typeAnnotation.getTargetType(); - if (targetType >= AnnotationTargetTypeConstants.LOCAL_VARIABLE && targetType <= AnnotationTargetTypeConstants.METHOD_REFERENCE_TYPE_ARGUMENT) { - return false; // affects detail within a block + // + // TODO move to a general purpose digester? + // + + private void updateLong(long value) { + byte[] tmp = new byte[8]; + tmp[0] = (byte) ((value >> 0x00) & 0xFF); + tmp[1] = (byte) ((value >> 0x08) & 0xFF); + tmp[2] = (byte) ((value >> 0x10) & 0xFF); + tmp[3] = (byte) ((value >> 0x18) & 0xFF); + tmp[4] = (byte) ((value >> 0x20) & 0xFF); + tmp[5] = (byte) ((value >> 0x28) & 0xFF); + tmp[6] = (byte) ((value >> 0x30) & 0xFF); + tmp[7] = (byte) ((value >> 0x38) & 0xFF); + digester.update(tmp); } - return true; - } - - // - // TODO move to a general purpose digester? - // - - private void updateLong(long value) { - byte[] tmp = new byte[8]; - tmp[0] = (byte) ((value >> 0x00) & 0xFF); - tmp[1] = (byte) ((value >> 0x08) & 0xFF); - tmp[2] = (byte) ((value >> 0x10) & 0xFF); - tmp[3] = (byte) ((value >> 0x18) & 0xFF); - tmp[4] = (byte) ((value >> 0x20) & 0xFF); - tmp[5] = (byte) ((value >> 0x28) & 0xFF); - tmp[6] = (byte) ((value >> 0x30) & 0xFF); - tmp[7] = (byte) ((value >> 0x38) & 0xFF); - digester.update(tmp); - } - - private void updateInt(int value) { - byte[] tmp = new byte[4]; - tmp[0] = (byte) ((value >> 0x00) & 0xFF); - tmp[1] = (byte) ((value >> 0x08) & 0xFF); - tmp[2] = (byte) ((value >> 0x10) & 0xFF); - tmp[3] = (byte) ((value >> 0x18) & 0xFF); - digester.update(tmp); - } - - private void updateShort(short value) { - byte[] tmp = new byte[2]; - tmp[0] = (byte) ((value >> 0x00) & 0xFF); - tmp[1] = (byte) ((value >> 0x08) & 0xFF); - digester.update(tmp); - } - - private void updateChars(char[] value) { - if (value != null) { - for ( char c : value ) { - updateChar( c ); - } + + private void updateInt(int value) { + byte[] tmp = new byte[4]; + tmp[0] = (byte) ((value >> 0x00) & 0xFF); + tmp[1] = (byte) ((value >> 0x08) & 0xFF); + tmp[2] = (byte) ((value >> 0x10) & 0xFF); + tmp[3] = (byte) ((value >> 0x18) & 0xFF); + digester.update(tmp); } - } - private void updateString(String value) { - digester.update(value.getBytes(StandardCharsets.UTF_8)); - } + private void updateShort(short value) { + byte[] tmp = new byte[2]; + tmp[0] = (byte) ((value >> 0x00) & 0xFF); + tmp[1] = (byte) ((value >> 0x08) & 0xFF); + digester.update(tmp); + } - private void updateDouble(double value) { - updateLong(Double.doubleToRawLongBits(value)); - } + private void updateChars(char[] value) { + if (value != null) { + for (char c : value) { + updateChar(c); + } + } + } - private void updateFloat(float value) { - updateInt(Float.floatToRawIntBits(value)); - } + private void updateString(String value) { + digester.update(value.getBytes(StandardCharsets.UTF_8)); + } - private void updateChar(char value) { - updateInt(value); - } + private void updateDouble(double value) { + updateLong(Double.doubleToRawLongBits(value)); + } - private void updateByte(byte value) { - digester.update(value); - } + private void updateFloat(float value) { + updateInt(Float.floatToRawIntBits(value)); + } - private void updateBoolean(boolean value) { - digester.update(value ? (byte) 1 : (byte) 0); - } + private void updateChar(char value) { + updateInt(value); + } + + private void updateByte(byte value) { + digester.update(value); + } + private void updateBoolean(boolean value) { + digester.update(value ? (byte) 1 : (byte) 0); + } } diff --git a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/ClasspathDigester.java b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/ClasspathDigester.java index ea40aa9b..efa774f8 100644 --- a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/ClasspathDigester.java +++ b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/ClasspathDigester.java @@ -1,9 +1,9 @@ -/** - * Copyright (c) 2014 Takari, Inc. +/* + * Copyright (c) 2014-2024 Takari, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * https://www.eclipse.org/legal/epl-v10.html */ package io.takari.maven.plugins.compile.jdt; @@ -23,10 +23,8 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.jar.JarEntry; import java.util.jar.JarFile; - import javax.inject.Inject; import javax.inject.Named; - import org.apache.maven.execution.MavenSession; import org.apache.maven.execution.scope.MojoExecutionScoped; import org.apache.maven.project.MavenProject; @@ -40,142 +38,145 @@ @MojoExecutionScoped public class ClasspathDigester { - private final Logger log = LoggerFactory.getLogger(getClass()); + private final Logger log = LoggerFactory.getLogger(getClass()); - private static final Map> CACHE = new ConcurrentHashMap<>(); + private static final Map> CACHE = new ConcurrentHashMap<>(); - private final ClassfileDigester digester; + private final ClassfileDigester digester; - @Inject - public ClasspathDigester(MavenProject project, MavenSession session, ClassfileDigester digester) { - this.digester = digester; + @Inject + public ClasspathDigester(MavenProject project, MavenSession session, ClassfileDigester digester) { + this.digester = digester; - // this is only needed for unit tests, but won't hurt in general - CACHE.remove(new File(project.getBuild().getOutputDirectory())); - CACHE.remove(new File(project.getBuild().getTestOutputDirectory())); - } + // this is only needed for unit tests, but won't hurt in general + CACHE.remove(new File(project.getBuild().getOutputDirectory())); + CACHE.remove(new File(project.getBuild().getTestOutputDirectory())); + } - public HashMap digestDependencies(List dependencies) throws IOException { - long started = System.currentTimeMillis(); + public HashMap digestDependencies(List dependencies) throws IOException { + long started = System.currentTimeMillis(); + + HashMap digest = new HashMap<>(); + + // scan dependencies backwards to properly deal with duplicate type definitions + for (int i = dependencies.size() - 1; i >= 0; i--) { + File file = dependencies.get(i); + if (file.isFile()) { + digest.putAll(digestJar(file)); + } else if (file.isDirectory()) { + digest.putAll(digestDirectory(file)); + } else { + // happens with reactor dependencies with empty source folders + continue; + } + } - HashMap digest = new HashMap<>(); + log.debug( + "Analyzed {} classpath dependencies ({} ms)", + dependencies.size(), + System.currentTimeMillis() - started); - // scan dependencies backwards to properly deal with duplicate type definitions - for (int i = dependencies.size() - 1; i >= 0; i--) { - File file = dependencies.get(i); - if (file.isFile()) { - digest.putAll(digestJar(file)); - } else if (file.isDirectory()) { - digest.putAll(digestDirectory(file)); - } else { - // happens with reactor dependencies with empty source folders - continue; - } + return digest; } - log.debug("Analyzed {} classpath dependencies ({} ms)", dependencies.size(), System.currentTimeMillis() - started); - - return digest; - } - - private Map digestJar(final File file) throws IOException { - Map digest = CACHE.get(file); - if (digest == null) { - digest = new HashMap<>(); - Map sourcesDigest = new HashMap<>(); - try (JarFile jar = new JarFile(file)) { - for (Enumeration entries = jar.entries(); entries.hasMoreElements();) { - JarEntry entry = entries.nextElement(); - String path = entry.getName(); - if (path.endsWith(SUFFIX_STRING_class)) { - String type = toJavaType(path, SUFFIX_STRING_class); - try { - digest.put(type, digester.digest(ClassFileReader.read(jar, path))); - } catch (ClassFormatException e) { - // as far as jdt is concerned, the type does not exist + private Map digestJar(final File file) throws IOException { + Map digest = CACHE.get(file); + if (digest == null) { + digest = new HashMap<>(); + Map sourcesDigest = new HashMap<>(); + try (JarFile jar = new JarFile(file)) { + for (Enumeration entries = jar.entries(); entries.hasMoreElements(); ) { + JarEntry entry = entries.nextElement(); + String path = entry.getName(); + if (path.endsWith(SUFFIX_STRING_class)) { + String type = toJavaType(path, SUFFIX_STRING_class); + try { + digest.put(type, digester.digest(ClassFileReader.read(jar, path))); + } catch (ClassFormatException e) { + // as far as jdt is concerned, the type does not exist + } + } else if (path.endsWith(SUFFIX_STRING_java)) { + String type = toJavaType(path, SUFFIX_STRING_java); + try (InputStream in = jar.getInputStream(entry)) { + sourcesDigest.put(type, sha1bytes(in)); + } + } + } } - } else if (path.endsWith(SUFFIX_STRING_java)) { - String type = toJavaType(path, SUFFIX_STRING_java); - try (InputStream in = jar.getInputStream(entry)) { - sourcesDigest.put(type, sha1bytes(in)); + mergeAll(digest, sourcesDigest); + CACHE.put(file, digest); + } + + return digest; + } + + private Map digestDirectory(final File directory) throws IOException { + Map digest = CACHE.get(directory); + if (digest == null) { + digest = new HashMap<>(); + Map sourcesDigest = new HashMap<>(); + DirectoryScanner scanner = new DirectoryScanner(); + scanner.setBasedir(directory); + scanner.setIncludes(new String[] {"**/*" + SUFFIX_STRING_class, "**/*" + SUFFIX_STRING_java}); + scanner.scan(); + for (String path : scanner.getIncludedFiles()) { + if (path.endsWith(SUFFIX_STRING_class)) { + String type = toJavaType(path, SUFFIX_STRING_class); + try { + digest.put(type, digester.digest(ClassFileReader.read(new File(directory, path)))); + } catch (ClassFormatException e) { + // as far as jdt is concerned, the type does not exist + } + } else { + String type = toJavaType(path, SUFFIX_STRING_java); + try (InputStream inputStream = + Files.newInputStream(directory.toPath().resolve(path))) { + sourcesDigest.put(type, sha1bytes(inputStream)); + } + } } - } + mergeAll(digest, sourcesDigest); + CACHE.put(directory, digest); } - } - mergeAll(digest, sourcesDigest); - CACHE.put(file, digest); + + return digest; } - return digest; - } - - private Map digestDirectory(final File directory) throws IOException { - Map digest = CACHE.get(directory); - if (digest == null) { - digest = new HashMap<>(); - Map sourcesDigest = new HashMap<>(); - DirectoryScanner scanner = new DirectoryScanner(); - scanner.setBasedir(directory); - scanner.setIncludes(new String[] {"**/*" + SUFFIX_STRING_class, "**/*" + SUFFIX_STRING_java}); - scanner.scan(); - for (String path : scanner.getIncludedFiles()) { - if (path.endsWith(SUFFIX_STRING_class)) { - String type = toJavaType(path, SUFFIX_STRING_class); - try { - digest.put(type, digester.digest(ClassFileReader.read(new File(directory, path)))); - } catch (ClassFormatException e) { - // as far as jdt is concerned, the type does not exist - } - } else { - String type = toJavaType(path, SUFFIX_STRING_java); - try (InputStream inputStream = Files.newInputStream(directory.toPath().resolve(path))) { - sourcesDigest.put(type, sha1bytes(inputStream)); - } + private void mergeAll(Map target, Map source) { + for (Map.Entry entry : source.entrySet()) { + byte[] value = target.get(entry.getKey()); + if (value != null) { + byte[] temp = new byte[value.length + entry.getValue().length]; + System.arraycopy(value, 0, temp, 0, value.length); + System.arraycopy(entry.getValue(), 0, temp, value.length, entry.getValue().length); + value = temp; + } else { + value = entry.getValue(); + } + target.put(entry.getKey(), value); } - } - mergeAll(digest, sourcesDigest); - CACHE.put(directory, digest); } - return digest; - } - - private void mergeAll(Map target, Map source) { - for (Map.Entry entry : source.entrySet()) { - byte[] value = target.get(entry.getKey()); - if (value != null) { - byte[] temp = new byte[value.length + entry.getValue().length]; - System.arraycopy(value, 0, temp, 0, value.length); - System.arraycopy(entry.getValue(), 0, temp, value.length, entry.getValue().length); - value = temp; - } else { - value = entry.getValue(); - } - target.put(entry.getKey(), value); + public static String toJavaType(String path, String suffix) { + path = path.substring(0, path.length() - suffix.length()); + return path.replace('/', '.').replace('\\', '.'); } - } - - public static String toJavaType(String path, String suffix) { - path = path.substring(0, path.length() - suffix.length()); - return path.replace('/', '.').replace('\\', '.'); - } - - public static void flush() { - CACHE.clear(); - } - - private static byte[] sha1bytes(final InputStream inputStream) throws IOException { - try { - MessageDigest md = MessageDigest.getInstance("SHA-1"); - byte[] buffer = new byte[8192]; - int read; - while ((read = inputStream.read(buffer)) != -1) { - md.update(buffer, 0, read); - } - return md.digest(); - } catch ( NoSuchAlgorithmException e) { - throw new IllegalStateException("Unsupported JVM: sha1 MessageDigest algorithm unsupported", e); + + public static void flush() { + CACHE.clear(); } - } + private static byte[] sha1bytes(final InputStream inputStream) throws IOException { + try { + MessageDigest md = MessageDigest.getInstance("SHA-1"); + byte[] buffer = new byte[8192]; + int read; + while ((read = inputStream.read(buffer)) != -1) { + md.update(buffer, 0, read); + } + return md.digest(); + } catch (NoSuchAlgorithmException e) { + throw new IllegalStateException("Unsupported JVM: sha1 MessageDigest algorithm unsupported", e); + } + } } diff --git a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/ClasspathEntryCache.java b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/ClasspathEntryCache.java index e7cd4599..0055366b 100644 --- a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/ClasspathEntryCache.java +++ b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/ClasspathEntryCache.java @@ -1,119 +1,119 @@ -/** - * Copyright (c) 2014 Takari, Inc. +/* + * Copyright (c) 2014-2024 Takari, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * https://www.eclipse.org/legal/epl-v10.html */ package io.takari.maven.plugins.compile.jdt; +import io.takari.maven.plugins.compile.jdt.classpath.DependencyClasspathEntry; +import io.takari.maven.plugins.compile.jdt.classpath.PathNormalizer; import java.io.File; import java.nio.file.Path; import java.util.HashMap; import java.util.Map; - import javax.inject.Named; -import io.takari.maven.plugins.compile.jdt.classpath.DependencyClasspathEntry; -import io.takari.maven.plugins.compile.jdt.classpath.PathNormalizer; - @Named public class ClasspathEntryCache { - public static interface Factory { - DependencyClasspathEntry newClasspathEntry(Path location); - } - - private static final Map CACHE = new HashMap<>(); + public static interface Factory { + DependencyClasspathEntry newClasspathEntry(Path location); + } - private static final Map SOURCEPATH_CACHE = new HashMap<>(); + private static final Map CACHE = new HashMap<>(); - public DependencyClasspathEntry get(Path location, CacheMode cacheMode, Factory factory) { - return get(CACHE, location, cacheMode, factory); - } + private static final Map SOURCEPATH_CACHE = new HashMap<>(); - public DependencyClasspathEntry getSourcepathEntry(Path location, CacheMode cacheMode, Factory factory) { - return get(SOURCEPATH_CACHE, location, cacheMode, factory); - } + public DependencyClasspathEntry get(Path location, CacheMode cacheMode, Factory factory) { + return get(CACHE, location, cacheMode, factory); + } - private static DependencyClasspathEntry get(Map cache, Path location, CacheMode cacheMode, Factory factory) { - location = PathNormalizer.getCanonicalPath(location); - synchronized (cache) { - CacheEntry entry = cache.get(location); - CacheEntry newEntry = revalidate(location, entry, cacheMode, factory); - if (entry != newEntry) { - cache.put(location, entry = newEntry); - } - return entry.getCpe(); + public DependencyClasspathEntry getSourcepathEntry(Path location, CacheMode cacheMode, Factory factory) { + return get(SOURCEPATH_CACHE, location, cacheMode, factory); } - } - - private static CacheEntry revalidate(Path location, CacheEntry entry, CacheMode cacheMode, Factory factory) { - // don't reload by default - long length = -1; - long lastModified = -1; - - if (cacheMode == CacheMode.PESSIMISTIC) { - try { - File file = location.toFile(); - if (file.isDirectory()) { - // always reload dir entries - length = 0; - lastModified = System.currentTimeMillis(); - } else { - // check if file has changed - length = file.length(); - lastModified = file.lastModified(); + + private static DependencyClasspathEntry get( + Map cache, Path location, CacheMode cacheMode, Factory factory) { + location = PathNormalizer.getCanonicalPath(location); + synchronized (cache) { + CacheEntry entry = cache.get(location); + CacheEntry newEntry = revalidate(location, entry, cacheMode, factory); + if (entry != newEntry) { + cache.put(location, entry = newEntry); + } + return entry.getCpe(); } - } catch (UnsupportedOperationException e) { - // JRT Path doesn't support toFile --> JDK not expected change so don't reload - } } - if (entry == null || entry.getSize() != length || entry.getTimestamp() != lastModified) { - entry = new CacheEntry(factory.newClasspathEntry(location), lastModified, length); - } + private static CacheEntry revalidate(Path location, CacheEntry entry, CacheMode cacheMode, Factory factory) { + // don't reload by default + long length = -1; + long lastModified = -1; + + if (cacheMode == CacheMode.PESSIMISTIC) { + try { + File file = location.toFile(); + if (file.isDirectory()) { + // always reload dir entries + length = 0; + lastModified = System.currentTimeMillis(); + } else { + // check if file has changed + length = file.length(); + lastModified = file.lastModified(); + } + } catch (UnsupportedOperationException e) { + // JRT Path doesn't support toFile --> JDK not expected change so don't reload + } + } - return entry; - } + if (entry == null || entry.getSize() != length || entry.getTimestamp() != lastModified) { + entry = new CacheEntry(factory.newClasspathEntry(location), lastModified, length); + } - /** - * @noreference this method is public for test purposes only - */ - public static void flush() { - synchronized (CACHE) { - CACHE.clear(); + return entry; } - synchronized (SOURCEPATH_CACHE) { - SOURCEPATH_CACHE.clear(); + + /** + * @noreference this method is public for test purposes only + */ + public static void flush() { + synchronized (CACHE) { + CACHE.clear(); + } + synchronized (SOURCEPATH_CACHE) { + SOURCEPATH_CACHE.clear(); + } } - } - public static class CacheEntry { - private final DependencyClasspathEntry cpe; - private final long timestamp; - private final long size; + public static class CacheEntry { + private final DependencyClasspathEntry cpe; + private final long timestamp; + private final long size; - public CacheEntry(DependencyClasspathEntry cpe, long timestamp, long size) { - this.cpe = cpe; - this.timestamp = timestamp; - this.size = size; - } + public CacheEntry(DependencyClasspathEntry cpe, long timestamp, long size) { + this.cpe = cpe; + this.timestamp = timestamp; + this.size = size; + } - public DependencyClasspathEntry getCpe() { - return cpe; - } + public DependencyClasspathEntry getCpe() { + return cpe; + } - public long getSize() { - return size; - } + public long getSize() { + return size; + } - public long getTimestamp() { - return timestamp; + public long getTimestamp() { + return timestamp; + } } - } - public enum CacheMode { - DEFAULT, PESSIMISTIC; - } + public enum CacheMode { + DEFAULT, + PESSIMISTIC; + } } diff --git a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/CompilerJdt.java b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/CompilerJdt.java index 8670b534..370b3e0b 100644 --- a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/CompilerJdt.java +++ b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/CompilerJdt.java @@ -1,14 +1,34 @@ -/** - * Copyright (c) 2014 Takari, Inc. +/* + * Copyright (c) 2014-2024 Takari, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * https://www.eclipse.org/legal/epl-v10.html */ package io.takari.maven.plugins.compile.jdt; import static io.takari.maven.plugins.compile.CompilerBuildContext.isJavaSource; +import io.takari.incrementalbuild.MessageSeverity; +import io.takari.incrementalbuild.Output; +import io.takari.incrementalbuild.Resource; +import io.takari.incrementalbuild.ResourceMetadata; +import io.takari.incrementalbuild.ResourceStatus; +import io.takari.maven.plugins.compile.AbstractCompileMojo.AccessRulesViolation; +import io.takari.maven.plugins.compile.AbstractCompileMojo.Debug; +import io.takari.maven.plugins.compile.AbstractCompileMojo.Proc; +import io.takari.maven.plugins.compile.AbstractCompiler; +import io.takari.maven.plugins.compile.CompilerBuildContext; +import io.takari.maven.plugins.compile.ProjectClasspathDigester; +import io.takari.maven.plugins.compile.jdt.ClasspathEntryCache.CacheMode; +import io.takari.maven.plugins.compile.jdt.classpath.Classpath; +import io.takari.maven.plugins.compile.jdt.classpath.ClasspathDirectory; +import io.takari.maven.plugins.compile.jdt.classpath.ClasspathEntry; +import io.takari.maven.plugins.compile.jdt.classpath.ClasspathJar; +import io.takari.maven.plugins.compile.jdt.classpath.DependencyClasspathEntry; +import io.takari.maven.plugins.compile.jdt.classpath.JavaInstallation; +import io.takari.maven.plugins.compile.jdt.classpath.MutableClasspathEntry; +import io.takari.maven.plugins.compile.jdt.classpath.SourcepathDirectory; import java.io.BufferedOutputStream; import java.io.File; import java.io.IOException; @@ -26,11 +46,9 @@ import java.util.Locale; import java.util.Map; import java.util.Set; - import javax.inject.Inject; import javax.inject.Named; import javax.tools.StandardLocation; - import org.eclipse.jdt.core.compiler.CategorizedProblem; import org.eclipse.jdt.core.compiler.CharOperation; import org.eclipse.jdt.internal.compiler.ClassFile; @@ -53,27 +71,6 @@ import org.eclipse.jdt.internal.compiler.util.SuffixConstants; import org.eclipse.jdt.internal.core.builder.ProblemFactory; -import io.takari.incrementalbuild.MessageSeverity; -import io.takari.incrementalbuild.Output; -import io.takari.incrementalbuild.Resource; -import io.takari.incrementalbuild.ResourceMetadata; -import io.takari.incrementalbuild.ResourceStatus; -import io.takari.maven.plugins.compile.AbstractCompileMojo.AccessRulesViolation; -import io.takari.maven.plugins.compile.AbstractCompileMojo.Debug; -import io.takari.maven.plugins.compile.AbstractCompileMojo.Proc; -import io.takari.maven.plugins.compile.AbstractCompiler; -import io.takari.maven.plugins.compile.CompilerBuildContext; -import io.takari.maven.plugins.compile.ProjectClasspathDigester; -import io.takari.maven.plugins.compile.jdt.ClasspathEntryCache.CacheMode; -import io.takari.maven.plugins.compile.jdt.classpath.Classpath; -import io.takari.maven.plugins.compile.jdt.classpath.ClasspathDirectory; -import io.takari.maven.plugins.compile.jdt.classpath.ClasspathEntry; -import io.takari.maven.plugins.compile.jdt.classpath.ClasspathJar; -import io.takari.maven.plugins.compile.jdt.classpath.DependencyClasspathEntry; -import io.takari.maven.plugins.compile.jdt.classpath.JavaInstallation; -import io.takari.maven.plugins.compile.jdt.classpath.MutableClasspathEntry; -import io.takari.maven.plugins.compile.jdt.classpath.SourcepathDirectory; - /** * @TODO test classpath order changes triggers rebuild of affected sources (same type name, different classes) * @TODO figure out why JDT needs to worry about duplicate types (maybe related to classpath order above) @@ -82,940 +79,986 @@ */ @Named(CompilerJdt.ID) public class CompilerJdt extends AbstractCompiler implements ICompilerRequestor { - public static final String ID = "jdt"; - - /* - * Notes on build context usage by this compiler implementation. - * - * Classpath, sourcepath and processorpath digests are persisted as context-level attributes (internally, the context associates them with project pom.xml). Classpath (should really be called - * "compile path") "structural" digest algorithm ignores changes to class method bodies and avoids unnecessary recompilations (see ClassfileDigester). Sourcepath and processorpath digest algorithm - * is common for all compiler implementations (see ProjectClasspathDigester). - * - * Java source ReferenceCollection is persisted as input file attribute. - * - * Output .class file "structural" digest is persisted as output file attribute. - * - * Tracking of inputs, outputs and their associations: - * - * - Build context tracks association between java sources and their corresponding class files. - * - * - Build context does NOT track originating elements of source/resources generated during annotation processing. All sources processed by apt and all written outputs are tracked in - * AnnotationProcessingState. Note that build context still tracks association between apt-generated sources and their corresponding class files. Annotation processing is performed "atomically", - * that is, if any source requires (re)processing, all apt outputs generated during previous builds are declared stale (see below) and all sources are (re)processed. - * - * - Outputs associated with modified sources are marked as "stale" before compilation but not physically deleted. At the end of compilation stales outputs that were not overwritten are deleted. - * This is meant to work with IncrementalFileOutputStream, which does not modify filesystem when incremental compilation regenerates exactly the same content. - * - * - Outputs associated with removed inputs are deleted before compilation. - */ - - /** - * Output .class file structure hash - */ - private static final String ATTR_CLASS_DIGEST = "jdt.class.digest"; - - /** - * Classpath digest, map of accessible types to their .class structure hashes. - */ - private static final String ATTR_CLASSPATH_DIGEST = "jdt.classpath.digest"; - - /** - * Annotation processing state - * - * @see AnnotationProcessingState - */ - private static final String ATTR_APTSTATE = "jdt.aptstate"; - - /** - * Java source {@link ReferenceCollection} - */ - private static final String ATTR_REFERENCES = "jdt.references"; - - private List dependencies; - - private List processorpath; - - private List sourcepath = Collections.emptyList(); - - private List dependencypath; - - private final Map> sources = new LinkedHashMap<>(); - - /** - * Set of ICompilationUnit to be compiled. - */ - private final Map compileQueue = new LinkedHashMap<>(); - - private final ClassfileDigester digester = new ClassfileDigester(); - - private final ClasspathEntryCache classpathCache; - - private final ClasspathDigester classpathDigester; - - private final ProjectClasspathDigester processorpathDigester; - - private abstract class CompilationStrategy { + public static final String ID = "jdt"; + + /* + * Notes on build context usage by this compiler implementation. + * + * Classpath, sourcepath and processorpath digests are persisted as context-level attributes (internally, the context associates them with project pom.xml). Classpath (should really be called + * "compile path") "structural" digest algorithm ignores changes to class method bodies and avoids unnecessary recompilations (see ClassfileDigester). Sourcepath and processorpath digest algorithm + * is common for all compiler implementations (see ProjectClasspathDigester). + * + * Java source ReferenceCollection is persisted as input file attribute. + * + * Output .class file "structural" digest is persisted as output file attribute. + * + * Tracking of inputs, outputs and their associations: + * + * - Build context tracks association between java sources and their corresponding class files. + * + * - Build context does NOT track originating elements of source/resources generated during annotation processing. All sources processed by apt and all written outputs are tracked in + * AnnotationProcessingState. Note that build context still tracks association between apt-generated sources and their corresponding class files. Annotation processing is performed "atomically", + * that is, if any source requires (re)processing, all apt outputs generated during previous builds are declared stale (see below) and all sources are (re)processed. + * + * - Outputs associated with modified sources are marked as "stale" before compilation but not physically deleted. At the end of compilation stales outputs that were not overwritten are deleted. + * This is meant to work with IncrementalFileOutputStream, which does not modify filesystem when incremental compilation regenerates exactly the same content. + * + * - Outputs associated with removed inputs are deleted before compilation. + */ /** - * To-be-deleted output files created during prior builds. These files are hidden from compile path. - * - * @see OutputDirectoryClasspathEntry#OutputDirectoryClasspathEntry(File, Collection). + * Output .class file structure hash */ - protected final Set staleOutputs = new HashSet<>(); + private static final String ATTR_CLASS_DIGEST = "jdt.class.digest"; - protected AnnotationProcessingState aptstate; + /** + * Classpath digest, map of accessible types to their .class structure hashes. + */ + private static final String ATTR_CLASSPATH_DIGEST = "jdt.classpath.digest"; - public abstract boolean setSources(List> sources) throws IOException; + /** + * Annotation processing state + * + * @see AnnotationProcessingState + */ + private static final String ATTR_APTSTATE = "jdt.aptstate"; - public abstract void enqueueAffectedSources(HashMap digest, Map oldDigest) throws IOException; + /** + * Java source {@link ReferenceCollection} + */ + private static final String ATTR_REFERENCES = "jdt.references"; - public abstract void enqueueAllSources() throws IOException; + private List dependencies; - public abstract void addDependentsOf(String typeOrPackage); + private List processorpath; - protected abstract void addDependentsOf(File resource); + private List sourcepath = Collections.emptyList(); - public abstract int compile(Classpath namingEnvironment, Compiler compiler) throws IOException; + private List dependencypath; - protected CompilationStrategy() { - if (!isProcNone()) { - aptstate = context.getAttribute(ATTR_APTSTATE, true, AnnotationProcessingState.class); - } - } + private final Map> sources = new LinkedHashMap<>(); - public Classpath createClasspath() throws IOException { - return CompilerJdt.this.createClasspath(staleOutputs); - } + /** + * Set of ICompilationUnit to be compiled. + */ + private final Map compileQueue = new LinkedHashMap<>(); - public abstract void addGeneratedSource(Output generatedSource); + private final ClassfileDigester digester = new ClassfileDigester(); - protected boolean deleteOrphanedOutputs() throws IOException { - boolean changed = false; - for (ResourceMetadata source : context.getRemovedSources()) { - changed = deleteAssociatedOutputs(source) || changed; - } + private final ClasspathEntryCache classpathCache; - return changed; - } + private final ClasspathDigester classpathDigester; - protected boolean deleteAssociatedOutputs(ResourceMetadata resource) throws IOException { - return deleteOutputs(context.getAssociatedOutputs(resource)); - } + private final ProjectClasspathDigester processorpathDigester; - protected boolean deleteAssociatedOutputs(File resource) throws IOException { - return deleteOutputs(context.getAssociatedOutputs(resource)); - } + private abstract class CompilationStrategy { - protected boolean deleteOutputs(Collection> outputs) throws IOException { - for (ResourceMetadata output : outputs) { - deleteOutput(output.getResource()); - } - return !outputs.isEmpty(); - } + /** + * To-be-deleted output files created during prior builds. These files are hidden from compile path. + * + * @see OutputDirectoryClasspathEntry#OutputDirectoryClasspathEntry(File, Collection). + */ + protected final Set staleOutputs = new HashSet<>(); - protected void deleteOutput(File outputFile) throws IOException { - if (isJavaSource(outputFile)) { - deleteAssociatedOutputs(outputFile); - } - context.deleteOutput(outputFile); - addDependentsOf(outputFile); - } + protected AnnotationProcessingState aptstate; - protected boolean deleteStaleOutputs() throws IOException { - boolean changed = false; - for (File staleOutput : staleOutputs) { - // TODO is it possible for an output to be processed in one compilation iteration but become obsolete during the next? - if (!context.isProcessedOutput(staleOutput)) { - deleteOutput(staleOutput); - changed = true; - } - } - staleOutputs.clear(); - return changed; - } + public abstract boolean setSources(List> sources) throws IOException; - /** - * Marks sources as "processed" in the build context. Masks old associated outputs from naming environments by adding them to {@link #staleOutputs}. - */ - protected void processSources() { - for (File sourceFile : compileQueue.keySet()) { - ResourceMetadata source = sources.get(sourceFile); - for (ResourceMetadata output : context.getAssociatedOutputs(source)) { - staleOutputs.add(output.getResource()); - } - sources.put(source.getResource(), context.processInput(source)); - } - } + public abstract void enqueueAffectedSources(HashMap digest, Map oldDigest) + throws IOException; - public abstract void onAnnotationProcessing(); + public abstract void enqueueAllSources() throws IOException; - public void skipCompile() { - if (aptstate != null) { - context.setAttribute(ATTR_APTSTATE, aptstate); - } - } - } + public abstract void addDependentsOf(String typeOrPackage); - private class IncrementalCompilationStrategy extends CompilationStrategy { + protected abstract void addDependentsOf(File resource); - /** - * Set of File that have already been added to the compile queue during this incremental compile loop iteration. - */ - private final Set processedQueue = new HashSet<>(); + public abstract int compile(Classpath namingEnvironment, Compiler compiler) throws IOException; - /** - * Set of File that have already been added to the compile queue (modeled as map of file -> list(file) where key - * file is always being added to list as well). - */ - private final Map> processedSources = new LinkedHashMap<>(); + protected CompilationStrategy() { + if (!isProcNone()) { + aptstate = context.getAttribute(ATTR_APTSTATE, true, AnnotationProcessingState.class); + } + } + public Classpath createClasspath() throws IOException { + return CompilerJdt.this.createClasspath(staleOutputs); + } - private final Set rootNames = new LinkedHashSet<>(); + public abstract void addGeneratedSource(Output generatedSource); - private final Set qualifiedNames = new LinkedHashSet<>(); + protected boolean deleteOrphanedOutputs() throws IOException { + boolean changed = false; + for (ResourceMetadata source : context.getRemovedSources()) { + changed = deleteAssociatedOutputs(source) || changed; + } - private final Set simpleNames = new LinkedHashSet<>(); + return changed; + } - @Override - public int compile(Classpath namingEnvironment, Compiler compiler) throws IOException { - AnnotationProcessorManager aptmanager = (AnnotationProcessorManager) compiler.annotationProcessorManager; - - if (aptmanager != null) { - // suppress APT lastRound during incremental compile loop - aptmanager.suppressLastRound(true); - } - - // incremental compilation loop - // keep calling the compiler while there are sources in the queue - incrementalCompilationLoop(namingEnvironment, compiler, aptmanager); - - // run apt last round iff doing annotation processing and ran regular apt rounds - if (aptmanager != null && aptstate == null) { - // tell apt manager we are running APT lastRound - aptmanager.suppressRegularRounds(true); - aptmanager.suppressLastRound(false); - - // even if a class was processed it would need recompiled once types are generated. - processedQueue.clear(); - - // trick the compiler to run APT without any source or binary types - compiler.referenceBindings = new ReferenceBinding[0]; - compiler.compile(new ICompilationUnit[0]); - namingEnvironment.reset(); - aptmanager.incrementalIterationReset(); - deleteStaleOutputs(); - - enqueueAffectedSources(); - // all apt rounds are now suppressed. - aptmanager.suppressLastRound(true); - // compile class that rely on apt completing - incrementalCompilationLoop(namingEnvironment, compiler, aptmanager); - } - - persistAnnotationProcessingState(compiler, aptstate); - - return processedSources.size(); - } + protected boolean deleteAssociatedOutputs(ResourceMetadata resource) throws IOException { + return deleteOutputs(context.getAssociatedOutputs(resource)); + } - /** - * This loop handles the incremental compilation of classes in the compileQueue. Regular apt rounds may occur in this loop, but the apt final round will not. - * - * This loop will be called once after the apt final round is processed to compile all effected types. All prior error/warn/info messages, referenced types, generated outputs and other per-input - * information tracked by in build context are ignored when a type is recompiled. - */ - private void incrementalCompilationLoop(Classpath namingEnvironment, Compiler compiler, AnnotationProcessorManager aptmanager) throws IOException { - while (!compileQueue.isEmpty() || !staleOutputs.isEmpty()) { - processedQueue.clear(); - processedQueue.addAll(compileQueue.keySet()); + protected boolean deleteAssociatedOutputs(File resource) throws IOException { + return deleteOutputs(context.getAssociatedOutputs(resource)); + } - // All prior error/warn/info messages, referenced types, generated outputs and other per-input information tracked by in build context are wiped away within. - processSources(); + protected boolean deleteOutputs(Collection> outputs) throws IOException { + for (ResourceMetadata output : outputs) { + deleteOutput(output.getResource()); + } + return !outputs.isEmpty(); + } - // invoke the compiler - ICompilationUnit[] compilationUnits = compileQueue.values().toArray(new ICompilationUnit[0]); - compileQueue.clear(); - compiler.compile(compilationUnits); - namingEnvironment.reset(); + protected void deleteOutput(File outputFile) throws IOException { + if (isJavaSource(outputFile)) { + deleteAssociatedOutputs(outputFile); + } + context.deleteOutput(outputFile); + addDependentsOf(outputFile); + } - if (aptmanager != null) { - aptmanager.incrementalIterationReset(); + protected boolean deleteStaleOutputs() throws IOException { + boolean changed = false; + for (File staleOutput : staleOutputs) { + // TODO is it possible for an output to be processed in one compilation iteration but become obsolete + // during the next? + if (!context.isProcessedOutput(staleOutput)) { + deleteOutput(staleOutput); + changed = true; + } + } + staleOutputs.clear(); + return changed; } - deleteStaleOutputs(); // delete stale outputs and enqueue affected sources + /** + * Marks sources as "processed" in the build context. Masks old associated outputs from naming environments by adding them to {@link #staleOutputs}. + */ + protected void processSources() { + for (File sourceFile : compileQueue.keySet()) { + ResourceMetadata source = sources.get(sourceFile); + for (ResourceMetadata output : context.getAssociatedOutputs(source)) { + staleOutputs.add(output.getResource()); + } + sources.put(source.getResource(), context.processInput(source)); + } + } - enqueueAffectedSources(); - } - } + public abstract void onAnnotationProcessing(); - @Override - protected void addDependentsOf(File resource) { - addDependentsOf(getJavaType(resource)); + public void skipCompile() { + if (aptstate != null) { + context.setAttribute(ATTR_APTSTATE, aptstate); + } + } } - @Override - public boolean setSources(List> sources) throws IOException { - for (ResourceMetadata source : sources) { - CompilerJdt.this.sources.put(source.getResource(), source); - if (source.getStatus() != ResourceStatus.UNMODIFIED) { - enqueue(source); + private class IncrementalCompilationStrategy extends CompilationStrategy { + + /** + * Set of File that have already been added to the compile queue during this incremental compile loop iteration. + */ + private final Set processedQueue = new HashSet<>(); + + /** + * Set of File that have already been added to the compile queue (modeled as map of file -> list(file) where key + * file is always being added to list as well). + */ + private final Map> processedSources = new LinkedHashMap<>(); + + private final Set rootNames = new LinkedHashSet<>(); + + private final Set qualifiedNames = new LinkedHashSet<>(); + + private final Set simpleNames = new LinkedHashSet<>(); + + @Override + public int compile(Classpath namingEnvironment, Compiler compiler) throws IOException { + AnnotationProcessorManager aptmanager = (AnnotationProcessorManager) compiler.annotationProcessorManager; + + if (aptmanager != null) { + // suppress APT lastRound during incremental compile loop + aptmanager.suppressLastRound(true); + } + + // incremental compilation loop + // keep calling the compiler while there are sources in the queue + incrementalCompilationLoop(namingEnvironment, compiler, aptmanager); + + // run apt last round iff doing annotation processing and ran regular apt rounds + if (aptmanager != null && aptstate == null) { + // tell apt manager we are running APT lastRound + aptmanager.suppressRegularRounds(true); + aptmanager.suppressLastRound(false); + + // even if a class was processed it would need recompiled once types are generated. + processedQueue.clear(); + + // trick the compiler to run APT without any source or binary types + compiler.referenceBindings = new ReferenceBinding[0]; + compiler.compile(new ICompilationUnit[0]); + namingEnvironment.reset(); + aptmanager.incrementalIterationReset(); + deleteStaleOutputs(); + + enqueueAffectedSources(); + // all apt rounds are now suppressed. + aptmanager.suppressLastRound(true); + // compile class that rely on apt completing + incrementalCompilationLoop(namingEnvironment, compiler, aptmanager); + } + + persistAnnotationProcessingState(compiler, aptstate); + + return processedSources.size(); } - } - // delete orphaned outputs and rebuild all sources that reference them - boolean compilationRequired = deleteOrphanedOutputs(); + /** + * This loop handles the incremental compilation of classes in the compileQueue. Regular apt rounds may occur in this loop, but the apt final round will not. + * + * This loop will be called once after the apt final round is processed to compile all effected types. All prior error/warn/info messages, referenced types, generated outputs and other per-input + * information tracked by in build context are ignored when a type is recompiled. + */ + private void incrementalCompilationLoop( + Classpath namingEnvironment, Compiler compiler, AnnotationProcessorManager aptmanager) + throws IOException { + while (!compileQueue.isEmpty() || !staleOutputs.isEmpty()) { + processedQueue.clear(); + processedQueue.addAll(compileQueue.keySet()); + + // All prior error/warn/info messages, referenced types, generated outputs and other per-input + // information tracked by in build context are wiped away within. + processSources(); + + // invoke the compiler + ICompilationUnit[] compilationUnits = compileQueue.values().toArray(new ICompilationUnit[0]); + compileQueue.clear(); + compiler.compile(compilationUnits); + namingEnvironment.reset(); + + if (aptmanager != null) { + aptmanager.incrementalIterationReset(); + } + + deleteStaleOutputs(); // delete stale outputs and enqueue affected sources + + enqueueAffectedSources(); + } + } - enqueueAffectedSources(); + @Override + protected void addDependentsOf(File resource) { + addDependentsOf(getJavaType(resource)); + } - return compilationRequired || !compileQueue.isEmpty(); - } + @Override + public boolean setSources(List> sources) throws IOException { + for (ResourceMetadata source : sources) { + CompilerJdt.this.sources.put(source.getResource(), source); + if (source.getStatus() != ResourceStatus.UNMODIFIED) { + enqueue(source); + } + } - private void enqueueAllAnnotatedSources() { - Set annotatedSources = aptstate.processedSources; - Set writtenOutputs = aptstate.writtenOutputs; - aptstate = null; // this needs to be before enqueue(File) to avoid recursion - for (File annotatedSource : annotatedSources) { - if (annotatedSource.isFile()) { - enqueue(annotatedSource); - } - } - for (File writtenOutput : writtenOutputs) { - staleOutputs.add(writtenOutput); - context.getAssociatedOutputs(writtenOutput).forEach(output -> staleOutputs.add(output.getResource())); - } - } + // delete orphaned outputs and rebuild all sources that reference them + boolean compilationRequired = deleteOrphanedOutputs(); - private void enqueueAffectedSources() { - if (aptstate != null && aptstate.referencedTypes.includes(qualifiedNames, simpleNames, rootNames)) { - enqueueAllAnnotatedSources(); - } - for (ResourceMetadata input : sources.values()) { - final File resource = input.getResource(); - if (!processedQueue.contains(resource) && resource.canRead()) { - ReferenceCollection references = context.getAttribute(resource, ATTR_REFERENCES, ReferenceCollection.class); - if (references != null && references.includes(qualifiedNames, simpleNames, rootNames)) { - enqueue(input); - } - } - } - - qualifiedNames.clear(); - simpleNames.clear(); - rootNames.clear(); - } + enqueueAffectedSources(); - private String getJavaType(File outputFile) { - String outputDirectory = getOutputDirectory().getAbsolutePath(); - String path = outputFile.getAbsolutePath(); - if (!path.startsWith(outputDirectory) || !path.endsWith(".class")) { - return null; - } - path = path.substring(outputDirectory.length(), path.length() - ".class".length()); - if (path.startsWith(File.separator)) { - path = path.substring(1); - } - return path.replace(File.separatorChar, '.'); - } + return compilationRequired || !compileQueue.isEmpty(); + } - @Override - public void enqueueAllSources() { - for (ResourceMetadata input : sources.values()) { - final File resource = input.getResource(); - if (!processedQueue.contains(resource) && resource.canRead()) { - enqueue(input); + private void enqueueAllAnnotatedSources() { + Set annotatedSources = aptstate.processedSources; + Set writtenOutputs = aptstate.writtenOutputs; + aptstate = null; // this needs to be before enqueue(File) to avoid recursion + for (File annotatedSource : annotatedSources) { + if (annotatedSource.isFile()) { + enqueue(annotatedSource); + } + } + for (File writtenOutput : writtenOutputs) { + staleOutputs.add(writtenOutput); + context.getAssociatedOutputs(writtenOutput).forEach(output -> staleOutputs.add(output.getResource())); + } } - } - qualifiedNames.clear(); - simpleNames.clear(); - rootNames.clear(); - } + private void enqueueAffectedSources() { + if (aptstate != null && aptstate.referencedTypes.includes(qualifiedNames, simpleNames, rootNames)) { + enqueueAllAnnotatedSources(); + } + for (ResourceMetadata input : sources.values()) { + final File resource = input.getResource(); + if (!processedQueue.contains(resource) && resource.canRead()) { + ReferenceCollection references = + context.getAttribute(resource, ATTR_REFERENCES, ReferenceCollection.class); + if (references != null && references.includes(qualifiedNames, simpleNames, rootNames)) { + enqueue(input); + } + } + } + + qualifiedNames.clear(); + simpleNames.clear(); + rootNames.clear(); + } - @Override - public void addDependentsOf(String typeOrPackage) { - if (typeOrPackage != null) { - // adopted from org.eclipse.jdt.internal.core.builder.IncrementalImageBuilder.addDependentsOf - // TODO deal with package-info - int idx = typeOrPackage.indexOf('.'); - if (idx > 0) { - rootNames.add(typeOrPackage.substring(0, idx)); - idx = typeOrPackage.lastIndexOf('.'); - qualifiedNames.add(typeOrPackage.substring(0, idx)); - simpleNames.add(typeOrPackage.substring(idx + 1)); - } else { - rootNames.add(typeOrPackage); - simpleNames.add(typeOrPackage); + private String getJavaType(File outputFile) { + String outputDirectory = getOutputDirectory().getAbsolutePath(); + String path = outputFile.getAbsolutePath(); + if (!path.startsWith(outputDirectory) || !path.endsWith(".class")) { + return null; + } + path = path.substring(outputDirectory.length(), path.length() - ".class".length()); + if (path.startsWith(File.separator)) { + path = path.substring(1); + } + return path.replace(File.separatorChar, '.'); } - } - } - private void enqueue(ResourceMetadata input) { - enqueue(input.getResource()); - } + @Override + public void enqueueAllSources() { + for (ResourceMetadata input : sources.values()) { + final File resource = input.getResource(); + if (!processedQueue.contains(resource) && resource.canRead()) { + enqueue(input); + } + } + + qualifiedNames.clear(); + simpleNames.clear(); + rootNames.clear(); + } - private void enqueue(File sourceFile) { - if (processedSources.computeIfAbsent(sourceFile, k -> new ArrayList<>()).size() > 15) { - // this is meant to prevent endless recompiles and exact number of recompiles is not important - // note that processedSources can be incremented multiple times for the same source during compilation bootstrap - // - the source has changed - // - any type referenced by the source has changed - // - any annotated source has changed - // - any typed referenced during annotation processing has changed - throw new IllegalStateException("Too many recompiles " + sourceFile); - } - if (aptstate != null && aptstate.processedSources.contains(sourceFile)) { - enqueueAllAnnotatedSources(); - } else { - processedSources.computeIfAbsent(sourceFile, k -> new ArrayList<>()).add(sourceFile); - compileQueue.put(sourceFile, newSourceFile(sourceFile)); - } - } + @Override + public void addDependentsOf(String typeOrPackage) { + if (typeOrPackage != null) { + // adopted from org.eclipse.jdt.internal.core.builder.IncrementalImageBuilder.addDependentsOf + // TODO deal with package-info + int idx = typeOrPackage.indexOf('.'); + if (idx > 0) { + rootNames.add(typeOrPackage.substring(0, idx)); + idx = typeOrPackage.lastIndexOf('.'); + qualifiedNames.add(typeOrPackage.substring(0, idx)); + simpleNames.add(typeOrPackage.substring(idx + 1)); + } else { + rootNames.add(typeOrPackage); + simpleNames.add(typeOrPackage); + } + } + } + private void enqueue(ResourceMetadata input) { + enqueue(input.getResource()); + } - @Override - public void enqueueAffectedSources(HashMap digest, Map oldDigest) { - if (oldDigest != null) { - Set changedPackages = new HashSet<>(); + private void enqueue(File sourceFile) { + if (processedSources + .computeIfAbsent(sourceFile, k -> new ArrayList<>()) + .size() + > 15) { + // this is meant to prevent endless recompiles and exact number of recompiles is not important + // note that processedSources can be incremented multiple times for the same source during compilation + // bootstrap + // - the source has changed + // - any type referenced by the source has changed + // - any annotated source has changed + // - any typed referenced during annotation processing has changed + throw new IllegalStateException("Too many recompiles " + sourceFile); + } + if (aptstate != null && aptstate.processedSources.contains(sourceFile)) { + enqueueAllAnnotatedSources(); + } else { + processedSources + .computeIfAbsent(sourceFile, k -> new ArrayList<>()) + .add(sourceFile); + compileQueue.put(sourceFile, newSourceFile(sourceFile)); + } + } - for (Map.Entry entry : digest.entrySet()) { - String type = entry.getKey(); - byte[] hash = entry.getValue(); - if (!Arrays.equals(hash, oldDigest.get(type))) { - addDependentsOf(type); - } - changedPackages.add(getPackage(type)); + @Override + public void enqueueAffectedSources(HashMap digest, Map oldDigest) { + if (oldDigest != null) { + Set changedPackages = new HashSet<>(); + + for (Map.Entry entry : digest.entrySet()) { + String type = entry.getKey(); + byte[] hash = entry.getValue(); + if (!Arrays.equals(hash, oldDigest.get(type))) { + addDependentsOf(type); + } + changedPackages.add(getPackage(type)); + } + + for (String oldType : oldDigest.keySet()) { + if (!digest.containsKey(oldType)) { + addDependentsOf(oldType); + } + changedPackages.remove(getPackage(oldType)); + } + + for (String changedPackage : changedPackages) { + addDependentsOf(changedPackage); + } + + enqueueAffectedSources(); + } } - for (String oldType : oldDigest.keySet()) { - if (!digest.containsKey(oldType)) { - addDependentsOf(oldType); - } - changedPackages.remove(getPackage(oldType)); + private String getPackage(String type) { + int idx = type.lastIndexOf('.'); + return idx > 0 ? type.substring(0, idx) : null; } - for (String changedPackage : changedPackages) { - addDependentsOf(changedPackage); + @Override + public void addGeneratedSource(Output generatedSource) { + sources.put(generatedSource.getResource(), generatedSource); + processedQueue.add(generatedSource.getResource()); } - enqueueAffectedSources(); - } - } + @Override + public void onAnnotationProcessing() { + if (aptstate != null) { + enqueueAllAnnotatedSources(); + } + } - private String getPackage(String type) { - int idx = type.lastIndexOf('.'); - return idx > 0 ? type.substring(0, idx) : null; + @Override + protected boolean deleteAssociatedOutputs(ResourceMetadata resource) throws IOException { + boolean changed = false; + if (aptstate != null && aptstate.processedSources.contains(resource.getResource())) { + enqueueAllAnnotatedSources(); + changed = true; + } + return super.deleteAssociatedOutputs(resource) || changed; + } } - @Override - public void addGeneratedSource(Output generatedSource) { - sources.put(generatedSource.getResource(), generatedSource); - processedQueue.add(generatedSource.getResource()); - } + private class FullCompilationStrategy extends CompilationStrategy { - @Override - public void onAnnotationProcessing() { - if (aptstate != null) { - enqueueAllAnnotatedSources(); - } - } + @Override + public boolean setSources(List> sources) throws IOException { + for (ResourceMetadata source : sources) { + File sourceFile = source.getResource(); + CompilerJdt.this.sources.put(sourceFile, source); + compileQueue.put(sourceFile, newSourceFile(sourceFile)); + } - @Override - protected boolean deleteAssociatedOutputs(ResourceMetadata resource) throws IOException { - boolean changed = false; - if (aptstate != null && aptstate.processedSources.contains(resource.getResource())) { - enqueueAllAnnotatedSources(); - changed = true; - } - return super.deleteAssociatedOutputs(resource) || changed; - } - } + deleteOrphanedOutputs(); - private class FullCompilationStrategy extends CompilationStrategy { + return true; + } - @Override - public boolean setSources(List> sources) throws IOException { - for (ResourceMetadata source : sources) { - File sourceFile = source.getResource(); - CompilerJdt.this.sources.put(sourceFile, source); - compileQueue.put(sourceFile, newSourceFile(sourceFile)); - } + @Override + public void enqueueAffectedSources(HashMap digest, Map oldDigest) { + // full strategy compiles all sources in one pass + } - deleteOrphanedOutputs(); + @Override + public void enqueueAllSources() { + // full strategy compiles all sources in one pass + } - return true; - } + @Override + public void addDependentsOf(String string) { + // full strategy compiles all sources in one pass + } - @Override - public void enqueueAffectedSources(HashMap digest, Map oldDigest) { - // full strategy compiles all sources in one pass - } + @Override + protected void addDependentsOf(File resource) { + // full strategy compiles all sources in one pass + } - @Override - public void enqueueAllSources() { - // full strategy compiles all sources in one pass - } + @Override + public int compile(Classpath namingEnvironment, Compiler compiler) throws IOException { + processSources(); - @Override - public void addDependentsOf(String string) { - // full strategy compiles all sources in one pass - } + if (aptstate != null) { + staleOutputs.addAll(aptstate.writtenOutputs); + aptstate = null; + } - @Override - protected void addDependentsOf(File resource) { - // full strategy compiles all sources in one pass - } + if (!compileQueue.isEmpty()) { + ICompilationUnit[] compilationUnits = compileQueue.values().toArray(new ICompilationUnit[0]); + compiler.compile(compilationUnits); + } - @Override - public int compile(Classpath namingEnvironment, Compiler compiler) throws IOException { - processSources(); + persistAnnotationProcessingState(compiler, null); + + deleteStaleOutputs(); + + return compileQueue.size(); + } - if (aptstate != null) { - staleOutputs.addAll(aptstate.writtenOutputs); - aptstate = null; - } + @Override + public void addGeneratedSource(Output generatedSource) { + // full strategy compiles all sources in one pass + } + + @Override + public void onAnnotationProcessing() { + // full strategy compiles all sources in one pass + } + } - if (!compileQueue.isEmpty()) { - ICompilationUnit[] compilationUnits = compileQueue.values().toArray(new ICompilationUnit[0]); - compiler.compile(compilationUnits); - } + private CompilationStrategy strategy; - persistAnnotationProcessingState(compiler, null); + private CacheMode cacheMode = CacheMode.DEFAULT; - deleteStaleOutputs(); + @Inject + public CompilerJdt( + CompilerBuildContext context, + ClasspathEntryCache classpathCache, + ClasspathDigester classpathDigester, + ProjectClasspathDigester processorpathDigester) { + super(context); + this.classpathCache = classpathCache; + this.classpathDigester = classpathDigester; + this.processorpathDigester = processorpathDigester; - return compileQueue.size(); + this.strategy = context.isEscalated() ? new FullCompilationStrategy() : new IncrementalCompilationStrategy(); } - @Override - public void addGeneratedSource(Output generatedSource) { - // full strategy compiles all sources in one pass + public void setClasspathCacheMode(CacheMode cacheMode) { + this.cacheMode = cacheMode; } @Override - public void onAnnotationProcessing() { - // full strategy compiles all sources in one pass - } - } - - private CompilationStrategy strategy; - - private CacheMode cacheMode = CacheMode.DEFAULT; - - @Inject - public CompilerJdt(CompilerBuildContext context, ClasspathEntryCache classpathCache, ClasspathDigester classpathDigester, ProjectClasspathDigester processorpathDigester) { - super(context); - this.classpathCache = classpathCache; - this.classpathDigester = classpathDigester; - this.processorpathDigester = processorpathDigester; - - this.strategy = context.isEscalated() ? new FullCompilationStrategy() : new IncrementalCompilationStrategy(); - } - - public void setClasspathCacheMode(CacheMode cacheMode) { - this.cacheMode = cacheMode; - } - - @Override - public int compile() throws IOException { - Map args = new HashMap<>(); - // XXX figure out how to reuse source/target check from jdt - // org.eclipse.jdt.internal.compiler.batch.Main.validateOptions(boolean) - args.put(CompilerOptions.OPTION_TargetPlatform, getTarget()); // support 5/6/7 aliases - args.put(CompilerOptions.OPTION_Compliance, getTarget()); // support 5/6/7 aliases - args.put(CompilerOptions.OPTION_Source, getSource()); // support 5/6/7 aliases - args.put(CompilerOptions.OPTION_ReportForbiddenReference, CompilerOptions.ERROR); - Set debug = getDebug(); - if (debug == null || debug.contains(Debug.all)) { - args.put(CompilerOptions.OPTION_LocalVariableAttribute, CompilerOptions.GENERATE); - args.put(CompilerOptions.OPTION_LineNumberAttribute, CompilerOptions.GENERATE); - args.put(CompilerOptions.OPTION_SourceFileAttribute, CompilerOptions.GENERATE); - } else if (debug.contains(Debug.none)) { - args.put(CompilerOptions.OPTION_LocalVariableAttribute, CompilerOptions.DO_NOT_GENERATE); - args.put(CompilerOptions.OPTION_LineNumberAttribute, CompilerOptions.DO_NOT_GENERATE); - args.put(CompilerOptions.OPTION_SourceFileAttribute, CompilerOptions.DO_NOT_GENERATE); - } else { - args.put(CompilerOptions.OPTION_LocalVariableAttribute, CompilerOptions.DO_NOT_GENERATE); - args.put(CompilerOptions.OPTION_LineNumberAttribute, CompilerOptions.DO_NOT_GENERATE); - args.put(CompilerOptions.OPTION_SourceFileAttribute, CompilerOptions.DO_NOT_GENERATE); - for (Debug keyword : debug) { - switch (keyword) { - case lines: + public int compile() throws IOException { + Map args = new HashMap<>(); + // XXX figure out how to reuse source/target check from jdt + // org.eclipse.jdt.internal.compiler.batch.Main.validateOptions(boolean) + args.put(CompilerOptions.OPTION_TargetPlatform, getTarget()); // support 5/6/7 aliases + args.put(CompilerOptions.OPTION_Compliance, getTarget()); // support 5/6/7 aliases + args.put(CompilerOptions.OPTION_Source, getSource()); // support 5/6/7 aliases + args.put(CompilerOptions.OPTION_ReportForbiddenReference, CompilerOptions.ERROR); + Set debug = getDebug(); + if (debug == null || debug.contains(Debug.all)) { + args.put(CompilerOptions.OPTION_LocalVariableAttribute, CompilerOptions.GENERATE); args.put(CompilerOptions.OPTION_LineNumberAttribute, CompilerOptions.GENERATE); - break; - case source: args.put(CompilerOptions.OPTION_SourceFileAttribute, CompilerOptions.GENERATE); - break; - case vars: - args.put(CompilerOptions.OPTION_LocalVariableAttribute, CompilerOptions.GENERATE); - break; - default: - throw new IllegalArgumentException(); + } else if (debug.contains(Debug.none)) { + args.put(CompilerOptions.OPTION_LocalVariableAttribute, CompilerOptions.DO_NOT_GENERATE); + args.put(CompilerOptions.OPTION_LineNumberAttribute, CompilerOptions.DO_NOT_GENERATE); + args.put(CompilerOptions.OPTION_SourceFileAttribute, CompilerOptions.DO_NOT_GENERATE); + } else { + args.put(CompilerOptions.OPTION_LocalVariableAttribute, CompilerOptions.DO_NOT_GENERATE); + args.put(CompilerOptions.OPTION_LineNumberAttribute, CompilerOptions.DO_NOT_GENERATE); + args.put(CompilerOptions.OPTION_SourceFileAttribute, CompilerOptions.DO_NOT_GENERATE); + for (Debug keyword : debug) { + switch (keyword) { + case lines: + args.put(CompilerOptions.OPTION_LineNumberAttribute, CompilerOptions.GENERATE); + break; + case source: + args.put(CompilerOptions.OPTION_SourceFileAttribute, CompilerOptions.GENERATE); + break; + case vars: + args.put(CompilerOptions.OPTION_LocalVariableAttribute, CompilerOptions.GENERATE); + break; + default: + throw new IllegalArgumentException(); + } + } } - } - } - class _CompilerOptions extends CompilerOptions { - public void setShowWarnings(boolean showWarnings) { - if (showWarnings) { - warningThreshold = IrritantSet.COMPILER_DEFAULT_WARNINGS; - } else { - warningThreshold = new IrritantSet(0); + class _CompilerOptions extends CompilerOptions { + public void setShowWarnings(boolean showWarnings) { + if (showWarnings) { + warningThreshold = IrritantSet.COMPILER_DEFAULT_WARNINGS; + } else { + warningThreshold = new IrritantSet(0); + } + } + } + _CompilerOptions compilerOptions = new _CompilerOptions(); + + compilerOptions.set(args); + compilerOptions.performMethodsFullRecovery = false; + compilerOptions.performStatementsRecovery = false; + compilerOptions.verbose = isVerbose(); + compilerOptions.produceMethodParameters = isParameters(); + compilerOptions.suppressWarnings = true; + compilerOptions.setShowWarnings(isShowWarnings()); + compilerOptions.docCommentSupport = true; + + if (!sourcepath.isEmpty() && strategy instanceof IncrementalCompilationStrategy) { + strategy.enqueueAllSources(); + strategy = new FullCompilationStrategy(); + } + + Classpath namingEnvironment = strategy.createClasspath(); + IErrorHandlingPolicy errorHandlingPolicy = DefaultErrorHandlingPolicies.exitAfterAllProblems(); + IProblemFactory problemFactory = ProblemFactory.getProblemFactory(Locale.getDefault()); + Compiler compiler = + new Compiler(namingEnvironment, errorHandlingPolicy, compilerOptions, this, problemFactory) { + @Override + protected synchronized void addCompilationUnit( + ICompilationUnit sourceUnit, CompilationUnitDeclaration parsedUnit) { + if (sourceUnit instanceof SourcepathDirectory.ClasspathCompilationUnit) { + // this compilation unit represents dependency .java file + // it is used to resolve type references and must not be processed otherwise + return; + } + // growth of the internal unitsToProcess array is handled via multiplication of it's current + // size, + // so if size is 0, we should just go ahead and handle it here. + if (this.unitsToProcess.length == 0) { + // start out with a size other than 0, so that it can be doubled safely by the super method. + // starting with 4 to prevent the first couple of doublings and corresponding copying. + this.unitsToProcess = new CompilationUnitDeclaration[4]; + this.unitsToProcess[0] = parsedUnit; + // this tracks the units added, it must be incremented ever time a new type is added. + this.totalUnits = 1; + } else { + super.addCompilationUnit(sourceUnit, parsedUnit); + } + } + }; + compiler.options.produceReferenceInfo = true; + + EclipseFileManager fileManager = null; + try { + if (!isProcNone()) { + fileManager = new EclipseFileManager(null, getSourceEncoding()); + fileManager.setLocation(StandardLocation.ANNOTATION_PROCESSOR_PATH, processorpath); + fileManager.setLocation(StandardLocation.CLASS_OUTPUT, Collections.singleton(getOutputDirectory())); + fileManager.setLocation( + StandardLocation.SOURCE_OUTPUT, Collections.singleton(getGeneratedSourcesDirectory())); + + ProcessingEnvImpl processingEnv = + new ProcessingEnvImpl(context, fileManager, getAnnotationProcessorOptions(), compiler, this); + + compiler.annotationProcessorManager = new AnnotationProcessorManager( + context, processingEnv, fileManager, getAnnotationProcessors(), this); + compiler.options.storeAnnotations = true; + } + + return strategy.compile(namingEnvironment, compiler); + } finally { + if (fileManager != null) { + fileManager.flush(); + fileManager.close(); + } } - } - } - _CompilerOptions compilerOptions = new _CompilerOptions(); - - compilerOptions.set(args); - compilerOptions.performMethodsFullRecovery = false; - compilerOptions.performStatementsRecovery = false; - compilerOptions.verbose = isVerbose(); - compilerOptions.produceMethodParameters = isParameters(); - compilerOptions.suppressWarnings = true; - compilerOptions.setShowWarnings(isShowWarnings()); - compilerOptions.docCommentSupport = true; - - if (!sourcepath.isEmpty() && strategy instanceof IncrementalCompilationStrategy) { - strategy.enqueueAllSources(); - strategy = new FullCompilationStrategy(); } - Classpath namingEnvironment = strategy.createClasspath(); - IErrorHandlingPolicy errorHandlingPolicy = DefaultErrorHandlingPolicies.exitAfterAllProblems(); - IProblemFactory problemFactory = ProblemFactory.getProblemFactory(Locale.getDefault()); - Compiler compiler = new Compiler(namingEnvironment, errorHandlingPolicy, compilerOptions, this, problemFactory) { - @Override - protected synchronized void addCompilationUnit(ICompilationUnit sourceUnit, CompilationUnitDeclaration parsedUnit) { - if (sourceUnit instanceof SourcepathDirectory.ClasspathCompilationUnit) { - // this compilation unit represents dependency .java file - // it is used to resolve type references and must not be processed otherwise - return; - } - // growth of the internal unitsToProcess array is handled via multiplication of it's current size, - // so if size is 0, we should just go ahead and handle it here. - if (this.unitsToProcess.length == 0) { - // start out with a size other than 0, so that it can be doubled safely by the super method. - // starting with 4 to prevent the first couple of doublings and corresponding copying. - this.unitsToProcess = new CompilationUnitDeclaration[4]; - this.unitsToProcess[0] = parsedUnit; - // this tracks the units added, it must be incremented ever time a new type is added. - this.totalUnits = 1; + private void persistAnnotationProcessingState(Compiler compiler, AnnotationProcessingState carryOverState) { + if (compiler.annotationProcessorManager == null) { + return; // not processing annotations + } + final AnnotationProcessingState aptstate; + if (carryOverState != null) { + // incremental build did not need to process annotations, carry over the state and outputs to the next build + aptstate = carryOverState; + aptstate.writtenOutputs.forEach(context::markUptodateOutput); } else { - super.addCompilationUnit(sourceUnit, parsedUnit); + AnnotationProcessorManager aptmanager = (AnnotationProcessorManager) compiler.annotationProcessorManager; + aptstate = new AnnotationProcessingState( + aptmanager.getProcessedSources(), aptmanager.getReferencedTypes(), aptmanager.getWittenOutputs()); } - } + context.setAttribute(ATTR_APTSTATE, aptstate); + } + @Override + public boolean setSources(List> sources) throws IOException { + return strategy.setSources(sources); + } - }; - compiler.options.produceReferenceInfo = true; + private CompilationUnit newSourceFile(File source) { + final String fileName = source.getAbsolutePath(); + final String encoding = + getSourceEncoding() != null ? getSourceEncoding().name() : null; + return new CompilationUnit( + null /* contents */, + fileName, + encoding, + getOutputDirectory().getAbsolutePath(), + false /* ignoreOptionalProblems */, + null /* modName */); + } - EclipseFileManager fileManager = null; - try { - if (!isProcNone()) { - fileManager = new EclipseFileManager(null, getSourceEncoding()); - fileManager.setLocation(StandardLocation.ANNOTATION_PROCESSOR_PATH, processorpath); - fileManager.setLocation(StandardLocation.CLASS_OUTPUT, Collections.singleton(getOutputDirectory())); - fileManager.setLocation(StandardLocation.SOURCE_OUTPUT, Collections.singleton(getGeneratedSourcesDirectory())); + /** + * @param staleOutputs is a live collection of output files to ignore. + */ + private Classpath createClasspath(Collection staleOutputs) throws IOException { + final List entries = new ArrayList<>(); + final List mutableentries = new ArrayList<>(); + + // XXX detect change! + for (Path file : JavaInstallation.getDefault().getClasspath()) { + final ClasspathEntry entry = getCPEntry(file); + if (entry != null) { + entries.add(entry); + } + } - ProcessingEnvImpl processingEnv = new ProcessingEnvImpl(context, fileManager, getAnnotationProcessorOptions(), compiler, this); + if (!isProcOnly()) { + OutputDirectoryClasspathEntry output = + new OutputDirectoryClasspathEntry(getOutputDirectory(), staleOutputs); + entries.add(output); + mutableentries.add(output); + } - compiler.annotationProcessorManager = new AnnotationProcessorManager(context, processingEnv, fileManager, getAnnotationProcessors(), this); - compiler.options.storeAnnotations = true; - } + entries.addAll(sourcepath); + entries.addAll(dependencypath); - return strategy.compile(namingEnvironment, compiler); - } finally { - if (fileManager != null) { - fileManager.flush(); - fileManager.close(); - } + return new Classpath(entries, mutableentries); } - } - private void persistAnnotationProcessingState(Compiler compiler, AnnotationProcessingState carryOverState) { - if (compiler.annotationProcessorManager == null) { - return; // not processing annotations + private DependencyClasspathEntry getCPEntry(File location) { + return classpathCache.get(location.toPath(), cacheMode, this::createCPEntry); } - final AnnotationProcessingState aptstate; - if (carryOverState != null) { - // incremental build did not need to process annotations, carry over the state and outputs to the next build - aptstate = carryOverState; - aptstate.writtenOutputs.forEach(context::markUptodateOutput); - } else { - AnnotationProcessorManager aptmanager = (AnnotationProcessorManager) compiler.annotationProcessorManager; - aptstate = new AnnotationProcessingState(aptmanager.getProcessedSources(), aptmanager.getReferencedTypes(), aptmanager.getWittenOutputs()); + + private DependencyClasspathEntry getCPEntry(Path location) { + return classpathCache.get(location, cacheMode, this::createCPEntry); } - context.setAttribute(ATTR_APTSTATE, aptstate); - } - - @Override - public boolean setSources(List> sources) throws IOException { - return strategy.setSources(sources); - } - - private CompilationUnit newSourceFile(File source) { - final String fileName = source.getAbsolutePath(); - final String encoding = getSourceEncoding() != null ? getSourceEncoding().name() : null; - return new CompilationUnit(null /* contents */, fileName, encoding, getOutputDirectory().getAbsolutePath(), false /* ignoreOptionalProblems */, null /* modName */); - } - - /** - * @param staleOutputs is a live collection of output files to ignore. - */ - private Classpath createClasspath(Collection staleOutputs) throws IOException { - final List entries = new ArrayList<>(); - final List mutableentries = new ArrayList<>(); - - // XXX detect change! - for (Path file : JavaInstallation.getDefault().getClasspath()) { - final ClasspathEntry entry = getCPEntry(file); - if (entry != null) { - entries.add(entry); - } + + private DependencyClasspathEntry getSPEntry(File location) { + return classpathCache.getSourcepathEntry(location.toPath(), cacheMode, this::createSPEntry); } - if (!isProcOnly()) { - OutputDirectoryClasspathEntry output = new OutputDirectoryClasspathEntry(getOutputDirectory(), staleOutputs); - entries.add(output); - mutableentries.add(output); + DependencyClasspathEntry createCPEntry(Path location) { + DependencyClasspathEntry entry = null; + if (Files.isDirectory(location)) { + entry = ClasspathDirectory.create(location); + } else if (Files.isRegularFile(location)) { + try { + entry = ClasspathJar.create(location); + } catch (IOException e) { + // not a zip/jar, ignore + } + } + return entry; } - entries.addAll(sourcepath); - entries.addAll(dependencypath); - - return new Classpath(entries, mutableentries); - } - - private DependencyClasspathEntry getCPEntry(File location) { - return classpathCache.get(location.toPath(), cacheMode, this::createCPEntry); - } - - private DependencyClasspathEntry getCPEntry(Path location) { - return classpathCache.get(location, cacheMode, this::createCPEntry); - } - - private DependencyClasspathEntry getSPEntry(File location) { - return classpathCache.getSourcepathEntry(location.toPath(), cacheMode, this::createSPEntry); - } - - DependencyClasspathEntry createCPEntry(Path location) { - DependencyClasspathEntry entry = null; - if (Files.isDirectory(location)) { - entry = ClasspathDirectory.create(location); - } else if (Files.isRegularFile(location)) { - try { - entry = ClasspathJar.create(location); - } catch (IOException e) { - // not a zip/jar, ignore - } + DependencyClasspathEntry createSPEntry(Path location) { + return SourcepathDirectory.create(location, getSourceEncoding()); } - return entry; - } - DependencyClasspathEntry createSPEntry(Path location) { - return SourcepathDirectory.create(location, getSourceEncoding()); - } + @Override + public boolean setClasspath(List dependencies, File mainClasses, Set directDependencies) + throws IOException { + this.dependencies = dependencies; + + final List dependencypath = new ArrayList<>(); + final List files = new ArrayList<>(); + + if (isProcOnly()) { + DependencyClasspathEntry entry = + ClasspathDirectory.create(getOutputDirectory().toPath()); + dependencypath.add(AccessRestrictionClasspathEntry.allowAll(entry)); + files.add(getOutputDirectory()); + } - @Override - public boolean setClasspath(List dependencies, File mainClasses, Set directDependencies) throws IOException { - this.dependencies = dependencies; + if (mainClasses != null) { + DependencyClasspathEntry entry = getCPEntry(mainClasses); + if (entry != null) { + dependencypath.add(AccessRestrictionClasspathEntry.allowAll(entry)); + files.add(mainClasses); + } + } - final List dependencypath = new ArrayList<>(); - final List files = new ArrayList<>(); + for (File dependency : dependencies) { + DependencyClasspathEntry entry = getCPEntry(dependency); + if (entry != null) { + if (getTransitiveDependencyReference() == AccessRulesViolation.error + && !directDependencies.contains(dependency)) { + dependencypath.add(AccessRestrictionClasspathEntry.forbidAll(entry)); + } else if (getPrivatePackageReference() == AccessRulesViolation.ignore) { + dependencypath.add(AccessRestrictionClasspathEntry.allowAll(entry)); + } else { + dependencypath.add(entry); + } + files.add(dependency); + } + } - if (isProcOnly()) { - DependencyClasspathEntry entry = ClasspathDirectory.create(getOutputDirectory().toPath()); - dependencypath.add( AccessRestrictionClasspathEntry.allowAll( entry ) ); - files.add(getOutputDirectory()); - } + if (log.isDebugEnabled()) { + StringBuilder msg = new StringBuilder(); + for (ClasspathEntry element : dependencypath) { + msg.append("\n   ").append(element.getEntryDescription()); + } + log.debug("Compile classpath: {} entries{}", dependencies.size(), msg); + } - if (mainClasses != null) { - DependencyClasspathEntry entry = getCPEntry(mainClasses); - if (entry != null) { - dependencypath.add(AccessRestrictionClasspathEntry.allowAll(entry)); - files.add(mainClasses); - } - } + this.dependencypath = Collections.unmodifiableList(new ArrayList<>(dependencypath)); - for (File dependency : dependencies) { - DependencyClasspathEntry entry = getCPEntry(dependency); - if (entry != null) { - if (getTransitiveDependencyReference() == AccessRulesViolation.error && !directDependencies.contains(dependency)) { - dependencypath.add(AccessRestrictionClasspathEntry.forbidAll(entry)); - } else if (getPrivatePackageReference() == AccessRulesViolation.ignore) { - dependencypath.add(AccessRestrictionClasspathEntry.allowAll(entry)); - } else { - dependencypath.add(entry); - } - files.add(dependency); - } - } + long started = System.currentTimeMillis(); + long typecount = 0, packagecount = 0; - if (log.isDebugEnabled()) { - StringBuilder msg = new StringBuilder(); - for (ClasspathEntry element : dependencypath) { - msg.append("\n   ").append(element.getEntryDescription()); - } - log.debug("Compile classpath: {} entries{}", dependencies.size(), msg); - } + HashMap digest = classpathDigester.digestDependencies(files); - this.dependencypath = Collections.unmodifiableList(new ArrayList<>(dependencypath)); + @SuppressWarnings("unchecked") + Map oldDigest = (Map) context.setAttribute(ATTR_CLASSPATH_DIGEST, digest); - long started = System.currentTimeMillis(); - long typecount = 0, packagecount = 0; + log.debug( + "Digested {} types and {} packages in {} ms", + typecount, + packagecount, + System.currentTimeMillis() - started); - HashMap digest = classpathDigester.digestDependencies(files); + strategy.enqueueAffectedSources(digest, oldDigest); - @SuppressWarnings("unchecked") - Map oldDigest = (Map) context.setAttribute(ATTR_CLASSPATH_DIGEST, digest); + return !compileQueue.isEmpty(); + } - log.debug("Digested {} types and {} packages in {} ms", typecount, packagecount, System.currentTimeMillis() - started); + @Override + public boolean setSourcepath(List dependencies, Set sourceRoots) throws IOException { + List sourcepath = new ArrayList<>(); + for (File dependency : dependencies) { + if (dependency.isDirectory()) { + final DependencyClasspathEntry entry; + if (sourceRoots.contains(dependency)) { + // own source roots can be mutable, don't cache + entry = createSPEntry(dependency.toPath()); + } else { + entry = getSPEntry(dependency); + } + sourcepath.add(entry); + } else if (dependency.isFile()) { + throw new IllegalArgumentException(); + } + } - strategy.enqueueAffectedSources(digest, oldDigest); + this.sourcepath = Collections.unmodifiableList(new ArrayList<>(sourcepath)); - return !compileQueue.isEmpty(); - } + return processorpathDigester.digestSourcepath(dependencies); + } - @Override - public boolean setSourcepath(List dependencies, Set sourceRoots) throws IOException { - List sourcepath = new ArrayList<>(); - for (File dependency : dependencies) { - if (dependency.isDirectory()) { - final DependencyClasspathEntry entry; - if (sourceRoots.contains(dependency)) { - // own source roots can be mutable, don't cache - entry = createSPEntry(dependency.toPath()); + @Override + public boolean setProcessorpath(List processorpath) throws IOException { + if (processorpath == null) { + this.processorpath = dependencies; } else { - entry = getSPEntry(dependency); + this.processorpath = Collections.unmodifiableList(new ArrayList<>(processorpath)); + } + if (!isProcNone() && processorpathDigester.digestProcessorpath(this.processorpath)) { + log.debug("Annotation processor path changed, recompiling all sources"); + strategy.enqueueAllSources(); } - sourcepath.add(entry); - } else if (dependency.isFile()) { - throw new IllegalArgumentException(); - } + return !compileQueue.isEmpty(); } - this.sourcepath = Collections.unmodifiableList(new ArrayList<>(sourcepath)); + @Override + public void acceptResult(CompilationResult result) { + if (result == null) { + return; // ah? + } + + final String sourceName = new String(result.getFileName()); + final File sourceFile = new File(sourceName); + + Resource input = context.getProcessedSource(sourceFile); + + // track type references + if (result.rootReferences != null + && result.qualifiedReferences != null + && result.simpleNameReferences != null) { + context.setAttribute( + input.getResource(), + ATTR_REFERENCES, + new ReferenceCollection( + result.rootReferences, result.qualifiedReferences, result.simpleNameReferences)); + } - return processorpathDigester.digestSourcepath(dependencies); - } + if (result.hasProblems()) { + for (CategorizedProblem problem : result.getProblems()) { + if (problem.isError() || isShowWarnings()) { + MessageSeverity severity = problem.isError() ? MessageSeverity.ERROR : MessageSeverity.WARNING; + input.addMessage( + problem.getSourceLineNumber(), + ((DefaultProblem) problem).column, + problem.getMessage(), + severity, + null /* cause */); + } + } + } - @Override - public boolean setProcessorpath(List processorpath) throws IOException { - if (processorpath == null) { - this.processorpath = dependencies; - } else { - this.processorpath = Collections.unmodifiableList(new ArrayList<>(processorpath)); + try { + if (!result.hasErrors() && !isProcOnly()) { + for (ClassFile classFile : result.getClassFiles()) { + char[] filename = classFile.fileName(); + int length = filename.length; + char[] relativeName = new char[length + 6]; + System.arraycopy(filename, 0, relativeName, 0, length); + System.arraycopy(SuffixConstants.SUFFIX_class, 0, relativeName, length, 6); + CharOperation.replace(relativeName, '/', File.separatorChar); + String relativeStringName = new String(relativeName); + writeClassFile(input, relativeStringName, classFile); + } + } + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + // XXX double check affected sources are recompiled when this source has errors } - if (!isProcNone() && processorpathDigester.digestProcessorpath(this.processorpath)) { - log.debug("Annotation processor path changed, recompiling all sources"); - strategy.enqueueAllSources(); + + private boolean isProcOnly() { + return getProc() == Proc.only; } - return !compileQueue.isEmpty(); - } - @Override - public void acceptResult(CompilationResult result) { - if (result == null) { - return; // ah? + private boolean isProcNone() { + return getProc() == Proc.none; } - final String sourceName = new String(result.getFileName()); - final File sourceFile = new File(sourceName); + private void writeClassFile(Resource input, String relativeStringName, ClassFile classFile) + throws IOException { + final byte[] bytes = classFile.getBytes(); + final File outputFile = new File(getOutputDirectory(), relativeStringName); - Resource input = context.getProcessedSource(sourceFile); + // context.associatedOutput resets output attributes set during earlier iterations of this incremental compile + // so deal with classfile digest before context.associatedOutput + final byte[] oldHash = context.getAttribute(outputFile, ATTR_CLASS_DIGEST, byte[].class); + final byte[] hash = digestClassFile(outputFile, bytes); + boolean significantChange = oldHash == null || hash == null || !Arrays.equals(hash, oldHash); - // track type references - if (result.rootReferences != null && result.qualifiedReferences != null && result.simpleNameReferences != null) { - context.setAttribute(input.getResource(), ATTR_REFERENCES, new ReferenceCollection(result.rootReferences, result.qualifiedReferences, result.simpleNameReferences)); - } + final Output output = context.associatedOutput(input, outputFile); - if (result.hasProblems()) { - for (CategorizedProblem problem : result.getProblems()) { - if (problem.isError() || isShowWarnings()) { - MessageSeverity severity = problem.isError() ? MessageSeverity.ERROR : MessageSeverity.WARNING; - input.addMessage(problem.getSourceLineNumber(), ((DefaultProblem) problem).column, problem.getMessage(), severity, null /* cause */); + if (hash != null) { + // TODO evaluate if this is useful + // trade-off is between storing digest on disk between builds + // and recomputing the hash each time class files are written + context.setAttribute(outputFile, ATTR_CLASS_DIGEST, hash); } - } - } - try { - if (!result.hasErrors() && !isProcOnly()) { - for (ClassFile classFile : result.getClassFiles()) { - char[] filename = classFile.fileName(); - int length = filename.length; - char[] relativeName = new char[length + 6]; - System.arraycopy(filename, 0, relativeName, 0, length); - System.arraycopy(SuffixConstants.SUFFIX_class, 0, relativeName, length, 6); - CharOperation.replace(relativeName, '/', File.separatorChar); - String relativeStringName = new String(relativeName); - writeClassFile(input, relativeStringName, classFile); - } - } - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - // XXX double check affected sources are recompiled when this source has errors - } - - private boolean isProcOnly() { - return getProc() == Proc.only; - } - - private boolean isProcNone() { - return getProc() == Proc.none; - } - - private void writeClassFile(Resource input, String relativeStringName, ClassFile classFile) throws IOException { - final byte[] bytes = classFile.getBytes(); - final File outputFile = new File(getOutputDirectory(), relativeStringName); - - // context.associatedOutput resets output attributes set during earlier iterations of this incremental compile - // so deal with classfile digest before context.associatedOutput - final byte[] oldHash = context.getAttribute(outputFile, ATTR_CLASS_DIGEST, byte[].class); - final byte[] hash = digestClassFile(outputFile, bytes); - boolean significantChange = oldHash == null || hash == null || !Arrays.equals(hash, oldHash); - - final Output output = context.associatedOutput(input, outputFile); - - if (hash != null) { - // TODO evaluate if this is useful - // trade-off is between storing digest on disk between builds - // and recomputing the hash each time class files are written - context.setAttribute(outputFile, ATTR_CLASS_DIGEST, hash); - } + if (significantChange) { + // find all sources that reference this type and put them into work queue + strategy.addDependentsOf(CharOperation.toString(classFile.getCompoundName())); + } - if (significantChange) { - // find all sources that reference this type and put them into work queue - strategy.addDependentsOf(CharOperation.toString(classFile.getCompoundName())); + try (final BufferedOutputStream os = new BufferedOutputStream(output.newOutputStream())) { + os.write(bytes); + os.flush(); + } } - try (final BufferedOutputStream os = new BufferedOutputStream(output.newOutputStream())) { - os.write(bytes); - os.flush(); - } - } - - private byte[] digestClassFile(File outputFile, byte[] definition) { - try { - ClassFileReader reader = new ClassFileReader(definition, outputFile.getAbsolutePath().toCharArray()); - return digester.digest(reader); - } catch (ClassFormatException e) { - // ignore this class + private byte[] digestClassFile(File outputFile, byte[] definition) { + try { + ClassFileReader reader = + new ClassFileReader(definition, outputFile.getAbsolutePath().toCharArray()); + return digester.digest(reader); + } catch (ClassFormatException e) { + // ignore this class + } + return null; } - return null; - } - - public void addGeneratedSource(Output generatedSource) { - strategy.addGeneratedSource(generatedSource); - } - public void onAnnotationProcessing() { - strategy.onAnnotationProcessing(); - } + public void addGeneratedSource(Output generatedSource) { + strategy.addGeneratedSource(generatedSource); + } - @Override - public void skipCompile() { - strategy.skipCompile(); - super.skipCompile(); - } + public void onAnnotationProcessing() { + strategy.onAnnotationProcessing(); + } + @Override + public void skipCompile() { + strategy.skipCompile(); + super.skipCompile(); + } } diff --git a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/FilerImpl.java b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/FilerImpl.java index e896db18..d7bad7b8 100644 --- a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/FilerImpl.java +++ b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/FilerImpl.java @@ -1,5 +1,14 @@ +/* + * Copyright (c) 2014-2024 Takari, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v10.html + */ package io.takari.maven.plugins.compile.jdt; +import io.takari.incrementalbuild.Output; +import io.takari.maven.plugins.compile.CompilerBuildContext; import java.io.File; import java.io.FileNotFoundException; import java.io.FilterOutputStream; @@ -12,7 +21,6 @@ import java.util.HashSet; import java.util.LinkedHashSet; import java.util.Set; - import javax.annotation.processing.Filer; import javax.annotation.processing.FilerException; import javax.lang.model.element.Element; @@ -23,156 +31,159 @@ import javax.tools.JavaFileObject; import javax.tools.StandardJavaFileManager; import javax.tools.StandardLocation; - import org.eclipse.jdt.internal.compiler.batch.CompilationUnit; -import io.takari.incrementalbuild.Output; -import io.takari.maven.plugins.compile.CompilerBuildContext; - class FilerImpl implements Filer { - private final CompilerBuildContext context; - private final StandardJavaFileManager fileManager; - private final ProcessingEnvImpl processingEnv; - private final CompilerJdt incrementalCompiler; - - private final Set createdResources = new HashSet<>(); - private final Set writtenFiles = new HashSet<>(); + private final CompilerBuildContext context; + private final StandardJavaFileManager fileManager; + private final ProcessingEnvImpl processingEnv; + private final CompilerJdt incrementalCompiler; + + private final Set createdResources = new HashSet<>(); + private final Set writtenFiles = new HashSet<>(); + + private class FileObjectDelegate { + public OutputStream openOutputStream(URI uri) throws IOException { + File outputFile = new File(uri); + writtenFiles.add(outputFile); + final Output output = context.processOutput(outputFile); + return new FilterOutputStream(output.newOutputStream()) { + @Override + public void close() throws IOException { + super.close(); + onClose(output); + } + }; + } - private class FileObjectDelegate { - public OutputStream openOutputStream(URI uri) throws IOException { - File outputFile = new File(uri); - writtenFiles.add(outputFile); - final Output output = context.processOutput(outputFile); - return new FilterOutputStream(output.newOutputStream()) { - @Override - public void close() throws IOException { - super.close(); - onClose(output); + public Writer openWriter(URI uri) throws IOException { + return new OutputStreamWriter(openOutputStream(uri)); // XXX encoding } - }; - } - public Writer openWriter(URI uri) throws IOException { - return new OutputStreamWriter(openOutputStream(uri)); // XXX encoding + protected void onClose(Output output) {} } - protected void onClose(Output output) {} + // TODO EclipseFileObject implementation is quite inappropriate for our needs, consider rewrite + private static class JavaFileObjectImpl extends ForwardingJavaFileObject { + private final FileObjectDelegate delegate; - } + public JavaFileObjectImpl(JavaFileObject fileObject, FileObjectDelegate delegate) { + super(fileObject); + this.delegate = delegate; + } - // TODO EclipseFileObject implementation is quite inappropriate for our needs, consider rewrite - private static class JavaFileObjectImpl extends ForwardingJavaFileObject { - private final FileObjectDelegate delegate; + @Override + public OutputStream openOutputStream() throws IOException { + return delegate.openOutputStream(toUri()); + } - public JavaFileObjectImpl(JavaFileObject fileObject, FileObjectDelegate delegate) { - super(fileObject); - this.delegate = delegate; + @Override + public Writer openWriter() throws IOException { + return delegate.openWriter(toUri()); + } } - @Override - public OutputStream openOutputStream() throws IOException { - return delegate.openOutputStream(toUri()); - } + private static class FileObjectImpl extends ForwardingFileObject { - @Override - public Writer openWriter() throws IOException { - return delegate.openWriter(toUri()); - } - } + private final FileObjectDelegate delegate; - private static class FileObjectImpl extends ForwardingFileObject { + protected FileObjectImpl(FileObject fileObject, FileObjectDelegate delegate) { + super(fileObject); + this.delegate = delegate; + } - private final FileObjectDelegate delegate; + @Override + public OutputStream openOutputStream() throws IOException { + return delegate.openOutputStream(toUri()); + } - protected FileObjectImpl(FileObject fileObject, FileObjectDelegate delegate) { - super(fileObject); - this.delegate = delegate; + @Override + public Writer openWriter() throws IOException { + return delegate.openWriter(toUri()); + } } - @Override - public OutputStream openOutputStream() throws IOException { - return delegate.openOutputStream(toUri()); + public FilerImpl( + CompilerBuildContext context, + StandardJavaFileManager fileManager, + CompilerJdt incrementalCompiler, + ProcessingEnvImpl processingEnv) { + this.context = context; + this.fileManager = fileManager; + this.incrementalCompiler = incrementalCompiler; + this.processingEnv = processingEnv; } @Override - public Writer openWriter() throws IOException { - return delegate.openWriter(toUri()); + public JavaFileObject createSourceFile(CharSequence name, Element... originatingElements) throws IOException { + JavaFileObject sourceFile = fileManager.getJavaFileForOutput( + StandardLocation.SOURCE_OUTPUT, name.toString(), JavaFileObject.Kind.SOURCE, null); + if (!createdResources.add(sourceFile.toUri())) { + throw new FilerException("Attempt to recreate file for type " + name); + } + return new JavaFileObjectImpl(sourceFile, new FileObjectDelegate() { + + private boolean closed = false; + + @Override + protected void onClose(Output generatedSource) { + if (!closed) { + closed = true; + // TODO optimize if the regenerated sources didn't change compared the previous build + CompilationUnit unit = new CompilationUnit( + null, generatedSource.getResource().getAbsolutePath(), null /* encoding */); + processingEnv.addNewUnit(unit); + incrementalCompiler.addGeneratedSource(generatedSource); + } + } + }); } - } - - public FilerImpl(CompilerBuildContext context, StandardJavaFileManager fileManager, CompilerJdt incrementalCompiler, ProcessingEnvImpl processingEnv) { - this.context = context; - this.fileManager = fileManager; - this.incrementalCompiler = incrementalCompiler; - this.processingEnv = processingEnv; - } - - @Override - public JavaFileObject createSourceFile(CharSequence name, Element... originatingElements) throws IOException { - JavaFileObject sourceFile = fileManager.getJavaFileForOutput(StandardLocation.SOURCE_OUTPUT, name.toString(), JavaFileObject.Kind.SOURCE, null); - if (!createdResources.add(sourceFile.toUri())) { - throw new FilerException("Attempt to recreate file for type " + name); - } - return new JavaFileObjectImpl(sourceFile, new FileObjectDelegate() { - - private boolean closed = false; - - @Override - protected void onClose(Output generatedSource) { - if (!closed) { - closed = true; - // TODO optimize if the regenerated sources didn't change compared the previous build - CompilationUnit unit = new CompilationUnit(null, generatedSource.getResource().getAbsolutePath(), null /* encoding */); - processingEnv.addNewUnit(unit); - incrementalCompiler.addGeneratedSource(generatedSource); + @Override + public JavaFileObject createClassFile(CharSequence name, Element... originatingElements) throws IOException { + JavaFileObject classFile = fileManager.getJavaFileForOutput( + StandardLocation.CLASS_OUTPUT, name.toString(), JavaFileObject.Kind.CLASS, null); + if (!createdResources.add(classFile.toUri())) { + throw new FilerException("Attempt to recreate file for class " + name); } - } - }); - } - - @Override - public JavaFileObject createClassFile(CharSequence name, Element... originatingElements) throws IOException { - JavaFileObject classFile = fileManager.getJavaFileForOutput(StandardLocation.CLASS_OUTPUT, name.toString(), JavaFileObject.Kind.CLASS, null); - if (!createdResources.add(classFile.toUri())) { - throw new FilerException("Attempt to recreate file for class " + name); + return new JavaFileObjectImpl(classFile, new FileObjectDelegate() { + @Override + protected void onClose(Output generatedClass) { + // TODO processingEnv.addNewClassFile + throw new UnsupportedOperationException(); + } + }); } - return new JavaFileObjectImpl(classFile, new FileObjectDelegate() { - @Override - protected void onClose(Output generatedClass) { - // TODO processingEnv.addNewClassFile - throw new UnsupportedOperationException(); - } - }); - } - - @Override - public FileObject createResource(Location location, CharSequence pkg, CharSequence relativeName, Element... originatingElements) throws IOException { - FileObject file = fileManager.getFileForOutput(location, pkg.toString(), relativeName.toString(), null); - if (!createdResources.add(file.toUri())) { - throw new FilerException("Attempt to recreate file for resource " + pkg + "." + relativeName); - } - return new FileObjectImpl(file, new FileObjectDelegate()); - } - - @Override - public FileObject getResource(Location location, CharSequence pkg, CharSequence relativeName) throws IOException { - FileObject file = fileManager.getFileForInput(location, pkg.toString(), relativeName.toString()); - if (file == null) { - throw new FileNotFoundException("Resource does not exist " + location + '/' + pkg + '/' + relativeName); + + @Override + public FileObject createResource( + Location location, CharSequence pkg, CharSequence relativeName, Element... originatingElements) + throws IOException { + FileObject file = fileManager.getFileForOutput(location, pkg.toString(), relativeName.toString(), null); + if (!createdResources.add(file.toUri())) { + throw new FilerException("Attempt to recreate file for resource " + pkg + "." + relativeName); + } + return new FileObjectImpl(file, new FileObjectDelegate()); } - if (createdResources.contains(file.toUri())) { - throw new FilerException("Resource already created " + pkg + "." + relativeName); + + @Override + public FileObject getResource(Location location, CharSequence pkg, CharSequence relativeName) throws IOException { + FileObject file = fileManager.getFileForInput(location, pkg.toString(), relativeName.toString()); + if (file == null) { + throw new FileNotFoundException("Resource does not exist " + location + '/' + pkg + '/' + relativeName); + } + if (createdResources.contains(file.toUri())) { + throw new FilerException("Resource already created " + pkg + "." + relativeName); + } + return file; } - return file; - } - public void incrementalIterationReset() { - this.createdResources.clear(); - } + public void incrementalIterationReset() { + this.createdResources.clear(); + } - public Set getWrittenFiles() { - return Collections.unmodifiableSet(new LinkedHashSet<>(writtenFiles)); - } + public Set getWrittenFiles() { + return Collections.unmodifiableSet(new LinkedHashSet<>(writtenFiles)); + } } diff --git a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/MessagerImpl.java b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/MessagerImpl.java index 99560612..3eb87b76 100644 --- a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/MessagerImpl.java +++ b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/MessagerImpl.java @@ -1,70 +1,78 @@ +/* + * Copyright (c) 2014-2024 Takari, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v10.html + */ package io.takari.maven.plugins.compile.jdt; +import io.takari.incrementalbuild.MessageSeverity; +import io.takari.incrementalbuild.Resource; +import io.takari.maven.plugins.compile.CompilerBuildContext; import java.io.File; - import javax.annotation.processing.Messager; import javax.lang.model.element.AnnotationMirror; import javax.lang.model.element.AnnotationValue; import javax.lang.model.element.Element; import javax.tools.Diagnostic.Kind; - import org.eclipse.jdt.internal.compiler.apt.dispatch.AptProblem; import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseMessagerImpl; import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseProcessingEnvImpl; -import io.takari.incrementalbuild.MessageSeverity; -import io.takari.incrementalbuild.Resource; -import io.takari.maven.plugins.compile.CompilerBuildContext; - class MessagerImpl extends BaseMessagerImpl implements Messager { - private final CompilerBuildContext context; - private final BaseProcessingEnvImpl _processingEnv; - - public MessagerImpl(CompilerBuildContext context, BaseProcessingEnvImpl _processingEnv) { - this.context = context; - this._processingEnv = _processingEnv; - } + private final CompilerBuildContext context; + private final BaseProcessingEnvImpl _processingEnv; - @Override - public void printMessage(Kind kind, CharSequence msg) { - printMessage(kind, msg, null, null, null); - } - - @Override - public void printMessage(Kind kind, CharSequence msg, Element e) { - printMessage(kind, msg, e, null, null); - } + public MessagerImpl(CompilerBuildContext context, BaseProcessingEnvImpl _processingEnv) { + this.context = context; + this._processingEnv = _processingEnv; + } - @Override - public void printMessage(Kind kind, CharSequence msg, Element e, AnnotationMirror a) { - printMessage(kind, msg, e, null, null); - } + @Override + public void printMessage(Kind kind, CharSequence msg) { + printMessage(kind, msg, null, null, null); + } - @Override - public void printMessage(Kind kind, CharSequence msg, Element e, AnnotationMirror a, AnnotationValue v) { - if (kind == Kind.ERROR) { - _processingEnv.setErrorRaised(true); + @Override + public void printMessage(Kind kind, CharSequence msg, Element e) { + printMessage(kind, msg, e, null, null); } - AptProblem problem = createProblem(kind, msg, e, a, v); - if (problem != null && problem.getOriginatingFileName() != null) { - Resource input = context.getProcessedSource(new File(new String(problem.getOriginatingFileName()))); - input.addMessage(problem.getSourceLineNumber(), problem.getSourceColumnNumber(), problem.getMessage(), getSeverity(kind), null); - } else { - context.addPomMessage(msg.toString(), getSeverity(kind), null); + + @Override + public void printMessage(Kind kind, CharSequence msg, Element e, AnnotationMirror a) { + printMessage(kind, msg, e, null, null); } - } - private MessageSeverity getSeverity(Kind kind) { - switch (kind) { - case ERROR: - return MessageSeverity.ERROR; - case WARNING: - case MANDATORY_WARNING: - return MessageSeverity.WARNING; - default: - return MessageSeverity.INFO; + @Override + public void printMessage(Kind kind, CharSequence msg, Element e, AnnotationMirror a, AnnotationValue v) { + if (kind == Kind.ERROR) { + _processingEnv.setErrorRaised(true); + } + AptProblem problem = createProblem(kind, msg, e, a, v); + if (problem != null && problem.getOriginatingFileName() != null) { + Resource input = context.getProcessedSource(new File(new String(problem.getOriginatingFileName()))); + input.addMessage( + problem.getSourceLineNumber(), + problem.getSourceColumnNumber(), + problem.getMessage(), + getSeverity(kind), + null); + } else { + context.addPomMessage(msg.toString(), getSeverity(kind), null); + } } - } + private MessageSeverity getSeverity(Kind kind) { + switch (kind) { + case ERROR: + return MessageSeverity.ERROR; + case WARNING: + case MANDATORY_WARNING: + return MessageSeverity.WARNING; + default: + return MessageSeverity.INFO; + } + } } diff --git a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/OutputDirectoryClasspathEntry.java b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/OutputDirectoryClasspathEntry.java index 24b7eba9..d7f06817 100644 --- a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/OutputDirectoryClasspathEntry.java +++ b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/OutputDirectoryClasspathEntry.java @@ -1,72 +1,70 @@ -/** - * Copyright (c) 2014 Takari, Inc. +/* + * Copyright (c) 2014-2024 Takari, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * https://www.eclipse.org/legal/epl-v10.html */ package io.takari.maven.plugins.compile.jdt; +import io.takari.maven.plugins.compile.jdt.classpath.ClasspathDirectory; +import io.takari.maven.plugins.compile.jdt.classpath.ClasspathEntry; +import io.takari.maven.plugins.compile.jdt.classpath.MutableClasspathEntry; import java.io.File; import java.nio.file.Path; import java.util.Collection; - import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer; -import io.takari.maven.plugins.compile.jdt.classpath.ClasspathDirectory; -import io.takari.maven.plugins.compile.jdt.classpath.ClasspathEntry; -import io.takari.maven.plugins.compile.jdt.classpath.MutableClasspathEntry; - class OutputDirectoryClasspathEntry implements ClasspathEntry, MutableClasspathEntry { - // TODO convert to nio Path. for consistency + // TODO convert to nio Path. for consistency - private final File directory; + private final File directory; - /** - * Live collection of output files to ignore. New files are added to the collection during lifespan of this OutputDirectoryClasspathEntry instance. The idea is to hide to-be-deleted - * files from classpath. - */ - private final Collection staleOutputs; + /** + * Live collection of output files to ignore. New files are added to the collection during lifespan of this OutputDirectoryClasspathEntry instance. The idea is to hide to-be-deleted + * files from classpath. + */ + private final Collection staleOutputs; - private ClasspathDirectory delegate; + private ClasspathDirectory delegate; - /** - * @param staleOutputs is a live collection of output files to ignore. - */ - public OutputDirectoryClasspathEntry(File directory, Collection staleOutputs) { - this.directory = directory; - this.staleOutputs = staleOutputs; + /** + * @param staleOutputs is a live collection of output files to ignore. + */ + public OutputDirectoryClasspathEntry(File directory, Collection staleOutputs) { + this.directory = directory; + this.staleOutputs = staleOutputs; - this.delegate = ClasspathDirectory.create(directory.toPath()); - } + this.delegate = ClasspathDirectory.create(directory.toPath()); + } - @Override - public Collection getPackageNames() { - return delegate.getPackageNames(); - } + @Override + public Collection getPackageNames() { + return delegate.getPackageNames(); + } - @Override - public NameEnvironmentAnswer findType(String packageName, String typeName) { - Path file = delegate.getFile(packageName, typeName); - if (file != null && !staleOutputs.contains(file.toFile())) { - return delegate.findType(packageName, typeName, null); + @Override + public NameEnvironmentAnswer findType(String packageName, String typeName) { + Path file = delegate.getFile(packageName, typeName); + if (file != null && !staleOutputs.contains(file.toFile())) { + return delegate.findType(packageName, typeName, null); + } + return null; } - return null; - } - @Override - public void reset() { - this.delegate = ClasspathDirectory.create(directory.toPath()); - } + @Override + public void reset() { + this.delegate = ClasspathDirectory.create(directory.toPath()); + } - @Override - public String toString() { - return "Classpath for output directory " + directory; - } + @Override + public String toString() { + return "Classpath for output directory " + directory; + } - @Override - public String getEntryDescription() { - return directory.getAbsolutePath(); - } + @Override + public String getEntryDescription() { + return directory.getAbsolutePath(); + } } diff --git a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/ProcessingEnvImpl.java b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/ProcessingEnvImpl.java index 9e166fa8..9225391c 100644 --- a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/ProcessingEnvImpl.java +++ b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/ProcessingEnvImpl.java @@ -1,19 +1,25 @@ +/* + * Copyright (c) 2014-2024 Takari, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v10.html + */ package io.takari.maven.plugins.compile.jdt; +import io.takari.maven.plugins.compile.CompilerBuildContext; import java.util.Collections; import java.util.LinkedHashSet; import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.function.Consumer; - import javax.lang.model.element.Element; import javax.lang.model.element.ElementKind; import javax.lang.model.element.PackageElement; import javax.lang.model.element.TypeElement; import javax.lang.model.type.TypeMirror; import javax.tools.StandardJavaFileManager; - import org.eclipse.jdt.core.compiler.CharOperation; import org.eclipse.jdt.internal.compiler.Compiler; import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseProcessingEnvImpl; @@ -26,116 +32,119 @@ import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; -import io.takari.maven.plugins.compile.CompilerBuildContext; - // TODO reconcile with BatchProcessingEnvImpl class ProcessingEnvImpl extends BaseProcessingEnvImpl { - private Set> referencedTypeObservers = new LinkedHashSet<>(); - - // TODO this shadows private member of the superclass, not pretty - private final Factory _factory; - - public ProcessingEnvImpl(CompilerBuildContext context, StandardJavaFileManager fileManager, Map processorOptions, Compiler compiler, CompilerJdt incrementalCompiler) { - this._filer = new FilerImpl(context, fileManager, incrementalCompiler, this); - this._messager = new MessagerImpl(context, this); - this._processorOptions = processorOptions != null ? processorOptions : Collections.emptyMap(); - this._compiler = compiler; - - this._elementUtils = new ElementsImpl(this) { - @Override - public TypeElement getTypeElement(CharSequence name) { - observeType(name.toString()); - return super.getTypeElement(name); - } - - @Override - public PackageElement getPackageElement(CharSequence name) { - observeType(name.toString()); - return super.getPackageElement(name); - } - }; - - this._factory = new Factory(this) { - private void observeType(Binding binding) { - if (binding instanceof ImportBinding) { - observeType(((ImportBinding) binding).compoundName); - } else if (binding instanceof PackageBinding) { - observeType(((PackageBinding) binding).compoundName); - } else if (binding instanceof TypeBinding) { - observeType((TypeBinding) binding); - } - - // no need to explicitly handle variable references - // - variable elements can only obtained through enclosing type, - // which means the enclosing type is already observed - // - to obtain type of the variable itself, processors need - // to call Element.asType, which triggers subsequent calls here - - // ditto method references - } - - private void observeType(TypeBinding binding) { - binding = binding.leafComponentType().erasure(); - if (binding instanceof ReferenceBinding) { - ReferenceBinding referenceBinding = (ReferenceBinding) binding; - observeType(referenceBinding.compoundName); - // TODO only track referenced member types (requires jdt.apt changes) - for (ReferenceBinding memberType : referenceBinding.memberTypes()) { - observeType(memberType.compoundName); - } - } - } - - private void observeType(char[][] compoundName) { - ProcessingEnvImpl.this.observeType(CharOperation.toString(compoundName)); - } - - @Override - public Element newElement(Binding binding, ElementKind kindHint) { - observeType(binding); - return super.newElement(binding, kindHint); - } - - @Override - public TypeMirror newTypeMirror(Binding binding) { - observeType(binding); - return super.newTypeMirror(binding); - } - - // TODO newTypeParameterElement - // TODO newPackageElement - }; - } - - private void observeType(String type) { - referencedTypeObservers.forEach(o -> o.accept(type)); - } - - @Override - public Locale getLocale() { - return Locale.getDefault(); // TODO - } - - @Override - public Factory getFactory() { - return _factory; - } - - public void incrementalIterationReset() { - reset(); - setErrorRaised(false); - - ((FilerImpl) _filer).incrementalIterationReset(); - } - - public void addReferencedTypeObserver(Consumer observer) { - referencedTypeObservers.add(observer); - } - - @Override - public LookupEnvironment getLookupEnvironment() { - LookupEnvironment _le = super.getLookupEnvironment(); - return _le; - } + private Set> referencedTypeObservers = new LinkedHashSet<>(); + + // TODO this shadows private member of the superclass, not pretty + private final Factory _factory; + + public ProcessingEnvImpl( + CompilerBuildContext context, + StandardJavaFileManager fileManager, + Map processorOptions, + Compiler compiler, + CompilerJdt incrementalCompiler) { + this._filer = new FilerImpl(context, fileManager, incrementalCompiler, this); + this._messager = new MessagerImpl(context, this); + this._processorOptions = processorOptions != null ? processorOptions : Collections.emptyMap(); + this._compiler = compiler; + + this._elementUtils = new ElementsImpl(this) { + @Override + public TypeElement getTypeElement(CharSequence name) { + observeType(name.toString()); + return super.getTypeElement(name); + } + + @Override + public PackageElement getPackageElement(CharSequence name) { + observeType(name.toString()); + return super.getPackageElement(name); + } + }; + + this._factory = new Factory(this) { + private void observeType(Binding binding) { + if (binding instanceof ImportBinding) { + observeType(((ImportBinding) binding).compoundName); + } else if (binding instanceof PackageBinding) { + observeType(((PackageBinding) binding).compoundName); + } else if (binding instanceof TypeBinding) { + observeType((TypeBinding) binding); + } + + // no need to explicitly handle variable references + // - variable elements can only obtained through enclosing type, + // which means the enclosing type is already observed + // - to obtain type of the variable itself, processors need + // to call Element.asType, which triggers subsequent calls here + + // ditto method references + } + + private void observeType(TypeBinding binding) { + binding = binding.leafComponentType().erasure(); + if (binding instanceof ReferenceBinding) { + ReferenceBinding referenceBinding = (ReferenceBinding) binding; + observeType(referenceBinding.compoundName); + // TODO only track referenced member types (requires jdt.apt changes) + for (ReferenceBinding memberType : referenceBinding.memberTypes()) { + observeType(memberType.compoundName); + } + } + } + + private void observeType(char[][] compoundName) { + ProcessingEnvImpl.this.observeType(CharOperation.toString(compoundName)); + } + + @Override + public Element newElement(Binding binding, ElementKind kindHint) { + observeType(binding); + return super.newElement(binding, kindHint); + } + + @Override + public TypeMirror newTypeMirror(Binding binding) { + observeType(binding); + return super.newTypeMirror(binding); + } + + // TODO newTypeParameterElement + // TODO newPackageElement + }; + } + + private void observeType(String type) { + referencedTypeObservers.forEach(o -> o.accept(type)); + } + + @Override + public Locale getLocale() { + return Locale.getDefault(); // TODO + } + + @Override + public Factory getFactory() { + return _factory; + } + + public void incrementalIterationReset() { + reset(); + setErrorRaised(false); + + ((FilerImpl) _filer).incrementalIterationReset(); + } + + public void addReferencedTypeObserver(Consumer observer) { + referencedTypeObservers.add(observer); + } + + @Override + public LookupEnvironment getLookupEnvironment() { + LookupEnvironment _le = super.getLookupEnvironment(); + return _le; + } } diff --git a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/ReferenceCollection.java b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/ReferenceCollection.java index 50fbb2d6..8c6971cd 100644 --- a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/ReferenceCollection.java +++ b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/ReferenceCollection.java @@ -1,15 +1,10 @@ -/******************************************************************************* - * Copyright (c) 2000, 2010 IBM Corporation and others. +/* + * Copyright (c) 2014-2024 Takari, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - * Tim Hanson - fix for https://bugs.eclipse.org/bugs/show_bug.cgi?id=137634 - * Takari, Inc - adopted for use in takari-lifecycle-plugin - *******************************************************************************/ + * https://www.eclipse.org/legal/epl-v10.html + */ package io.takari.maven.plugins.compile.jdt; import java.io.Serializable; @@ -18,231 +13,238 @@ import java.util.Iterator; import java.util.LinkedHashSet; import java.util.Set; - import org.eclipse.jdt.core.compiler.BuildContext; import org.eclipse.jdt.core.compiler.CharOperation; import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; import org.eclipse.jdt.internal.core.builder.NameSet; import org.eclipse.jdt.internal.core.builder.QualifiedNameSet; - // adopted from org.eclipse.jdt.internal.core.builder.ReferenceCollection because we need Serializable class ReferenceCollection implements Serializable { - // contains no simple names as in just 'a' which is kept in simpleNameReferences instead - final Set qualifiedNameReferences; - final Set simpleNameReferences; - final Set rootReferences; - - public ReferenceCollection(char[][] rootReferences, char[][][] qualifiedNameReferences, char[][] simpleNameReferences) { - this.qualifiedNameReferences = Collections.unmodifiableSet(toStringSet(qualifiedNameReferences)); - this.simpleNameReferences = Collections.unmodifiableSet(toStringSet(simpleNameReferences)); - this.rootReferences = Collections.unmodifiableSet(toStringSet(rootReferences)); - } - - public ReferenceCollection() { - this.qualifiedNameReferences = new LinkedHashSet<>(); - this.simpleNameReferences = new LinkedHashSet<>(); - this.rootReferences = new LinkedHashSet<>(); - } - - private Set toStringSet(char[][] strings) { - Set set = new LinkedHashSet<>(); - for (char[] string : strings) { - set.add(new String(string)); + // contains no simple names as in just 'a' which is kept in simpleNameReferences instead + final Set qualifiedNameReferences; + final Set simpleNameReferences; + final Set rootReferences; + + public ReferenceCollection( + char[][] rootReferences, char[][][] qualifiedNameReferences, char[][] simpleNameReferences) { + this.qualifiedNameReferences = Collections.unmodifiableSet(toStringSet(qualifiedNameReferences)); + this.simpleNameReferences = Collections.unmodifiableSet(toStringSet(simpleNameReferences)); + this.rootReferences = Collections.unmodifiableSet(toStringSet(rootReferences)); } - return set; - } - private Set toStringSet(char[][][] arrays) { - Set set = new LinkedHashSet<>(); - for (char[][] array : arrays) { - set.add(CharOperation.toString(array)); + public ReferenceCollection() { + this.qualifiedNameReferences = new LinkedHashSet<>(); + this.simpleNameReferences = new LinkedHashSet<>(); + this.rootReferences = new LinkedHashSet<>(); } - return set; - } - public boolean includes(Collection qualifiedNames, Collection simpleNames, Collection rootNames) { + private Set toStringSet(char[][] strings) { + Set set = new LinkedHashSet<>(); + for (char[] string : strings) { + set.add(new String(string)); + } + return set; + } - if (rootNames != null) { - boolean foundRoot = false; - for (String rootName : rootNames) { - foundRoot = rootReferences.contains(rootName); - if (foundRoot) { - break; + private Set toStringSet(char[][][] arrays) { + Set set = new LinkedHashSet<>(); + for (char[][] array : arrays) { + set.add(CharOperation.toString(array)); } - } - if (!foundRoot) { - return false; - } + return set; } - for (String simpleName : simpleNames) { - if (simpleNameReferences.contains(simpleName)) { - for (String qualifiedName : qualifiedNames) { - if (qualifiedName.indexOf('.') > 0 ? qualifiedNameReferences.contains(qualifiedName) : simpleNameReferences.contains(qualifiedName)) { - return true; - } + public boolean includes( + Collection qualifiedNames, Collection simpleNames, Collection rootNames) { + + if (rootNames != null) { + boolean foundRoot = false; + for (String rootName : rootNames) { + foundRoot = rootReferences.contains(rootName); + if (foundRoot) { + break; + } + } + if (!foundRoot) { + return false; + } + } + + for (String simpleName : simpleNames) { + if (simpleNameReferences.contains(simpleName)) { + for (String qualifiedName : qualifiedNames) { + if (qualifiedName.indexOf('.') > 0 + ? qualifiedNameReferences.contains(qualifiedName) + : simpleNameReferences.contains(qualifiedName)) { + return true; + } + } + return false; + } } + return false; - } } - return false; - } - - // - // the code below does unnecessary String<->char[] conversion (sloppy copy&paste job) - // TODO decide if we want to fully switch to String or go back to char[] (the latter will be almost vanilla jdt source) - // - - /** - * Adds the fully-qualified type names of any new dependencies, each name is of the form "p1.p2.A.B". - * - * @see BuildContext#recordDependencies(String[]) - */ - public void addDependencies(Collection typeNameDependencies) { - // if each qualified type name is already known then all of its subNames can be skipped - // and its expected that very few qualified names in typeNameDependencies need to be added - // but could always take 'p1.p2.p3.X' and make all qualified names 'p1' 'p1.p2' 'p1.p2.p3' 'p1.p2.p3.X', then intern - char[][][] qNames = new char[typeNameDependencies.size()][][]; - Iterator typeNameDependency = typeNameDependencies.iterator(); - for (int i = 0; typeNameDependency.hasNext(); i++) { - qNames[i] = CharOperation.splitOn('.', typeNameDependency.next().toCharArray()); + // + // the code below does unnecessary String<->char[] conversion (sloppy copy&paste job) + // TODO decide if we want to fully switch to String or go back to char[] (the latter will be almost vanilla jdt + // source) + // + + /** + * Adds the fully-qualified type names of any new dependencies, each name is of the form "p1.p2.A.B". + * + * @see BuildContext#recordDependencies(String[]) + */ + public void addDependencies(Collection typeNameDependencies) { + // if each qualified type name is already known then all of its subNames can be skipped + // and its expected that very few qualified names in typeNameDependencies need to be added + // but could always take 'p1.p2.p3.X' and make all qualified names 'p1' 'p1.p2' 'p1.p2.p3' 'p1.p2.p3.X', then + // intern + char[][][] qNames = new char[typeNameDependencies.size()][][]; + Iterator typeNameDependency = typeNameDependencies.iterator(); + for (int i = 0; typeNameDependency.hasNext(); i++) { + qNames[i] = CharOperation.splitOn('.', typeNameDependency.next().toCharArray()); + } + qNames = internQualifiedNames(qNames, false); + + next: + for (int i = qNames.length; --i >= 0; ) { + char[][] qualifiedTypeName = qNames[i]; + while (!includes(qualifiedTypeName)) { + if (!includes(qualifiedTypeName[qualifiedTypeName.length - 1])) { + this.simpleNameReferences.add(new String(qualifiedTypeName[qualifiedTypeName.length - 1])); + } + if (!insideRoot(qualifiedTypeName[0])) { + this.rootReferences.add(new String(qualifiedTypeName[0])); + } + this.qualifiedNameReferences.add(CharOperation.toString(qualifiedTypeName)); + + qualifiedTypeName = CharOperation.subarray(qualifiedTypeName, 0, qualifiedTypeName.length - 1); + char[][][] temp = internQualifiedNames(new char[][][] {qualifiedTypeName}, false); + if (temp == EmptyQualifiedNames) continue next; // qualifiedTypeName is a well known name + qualifiedTypeName = temp[0]; + } + } } - qNames = internQualifiedNames(qNames, false); - next: for (int i = qNames.length; --i >= 0;) { - char[][] qualifiedTypeName = qNames[i]; - while (!includes(qualifiedTypeName)) { - if (!includes(qualifiedTypeName[qualifiedTypeName.length - 1])) { - this.simpleNameReferences.add(new String(qualifiedTypeName[qualifiedTypeName.length - 1])); + private static char[][][] internQualifiedNames(char[][][] qualifiedNames, boolean keepWellKnown) { + if (qualifiedNames == null) return EmptyQualifiedNames; + int length = qualifiedNames.length; + if (length == 0) return EmptyQualifiedNames; + + char[][][] keepers = new char[length][][]; + int index = 0; + next: + for (int i = 0; i < length; i++) { + char[][] qualifiedName = qualifiedNames[i]; + int qLength = qualifiedName.length; + for (int j = 0, m = WellKnownQualifiedNames.length; j < m; j++) { + char[][] wellKnownName = WellKnownQualifiedNames[j]; + if (qLength > wellKnownName.length) break; // all remaining well known names are shorter + if (CharOperation.equals(qualifiedName, wellKnownName)) { + if (keepWellKnown) { + keepers[index++] = wellKnownName; + } + continue next; + } + } + + // InternedQualifiedNames[0] is for the rest (> 7 & 1) + // InternedQualifiedNames[1] is for size 2... + // InternedQualifiedNames[6] is for size 7 + QualifiedNameSet internedNames = InternedQualifiedNames[qLength <= MaxQualifiedNames ? qLength - 1 : 0]; + qualifiedName = internSimpleNames(qualifiedName, false); + keepers[index++] = internedNames.add(qualifiedName); } - if (!insideRoot(qualifiedTypeName[0])) { - this.rootReferences.add(new String(qualifiedTypeName[0])); + if (length > index) { + if (index == 0) return EmptyQualifiedNames; + System.arraycopy(keepers, 0, keepers = new char[index][][], 0, index); } - this.qualifiedNameReferences.add(CharOperation.toString(qualifiedTypeName)); - - qualifiedTypeName = CharOperation.subarray(qualifiedTypeName, 0, qualifiedTypeName.length - 1); - char[][][] temp = internQualifiedNames(new char[][][] {qualifiedTypeName}, false); - if (temp == EmptyQualifiedNames) continue next; // qualifiedTypeName is a well known name - qualifiedTypeName = temp[0]; - } + return keepers; } - } - - private static char[][][] internQualifiedNames(char[][][] qualifiedNames, boolean keepWellKnown) { - if (qualifiedNames == null) return EmptyQualifiedNames; - int length = qualifiedNames.length; - if (length == 0) return EmptyQualifiedNames; - - char[][][] keepers = new char[length][][]; - int index = 0; - next: for (int i = 0; i < length; i++) { - char[][] qualifiedName = qualifiedNames[i]; - int qLength = qualifiedName.length; - for (int j = 0, m = WellKnownQualifiedNames.length; j < m; j++) { - char[][] wellKnownName = WellKnownQualifiedNames[j]; - if (qLength > wellKnownName.length) break; // all remaining well known names are shorter - if (CharOperation.equals(qualifiedName, wellKnownName)) { - if (keepWellKnown) { - keepers[index++] = wellKnownName; - } - continue next; + + private static char[][] internSimpleNames(char[][] simpleNames, boolean removeWellKnown) { + if (simpleNames == null) return EmptySimpleNames; + int length = simpleNames.length; + if (length == 0) return EmptySimpleNames; + + char[][] keepers = new char[length][]; + int index = 0; + next: + for (int i = 0; i < length; i++) { + char[] name = simpleNames[i]; + int sLength = name.length; + for (int j = 0, m = WellKnownSimpleNames.length; j < m; j++) { + char[] wellKnownName = WellKnownSimpleNames[j]; + if (sLength > wellKnownName.length) break; // all remaining well known names are shorter + if (CharOperation.equals(name, wellKnownName)) { + if (!removeWellKnown) keepers[index++] = WellKnownSimpleNames[j]; + continue next; + } + } + + // InternedSimpleNames[0] is for the rest (> 29) + // InternedSimpleNames[1] is for size 1... + // InternedSimpleNames[29] is for size 29 + NameSet internedNames = InternedSimpleNames[sLength < MaxSimpleNames ? sLength : 0]; + keepers[index++] = internedNames.add(name); + } + if (length > index) { + if (index == 0) return EmptySimpleNames; + System.arraycopy(keepers, 0, keepers = new char[index][], 0, index); } - } - - // InternedQualifiedNames[0] is for the rest (> 7 & 1) - // InternedQualifiedNames[1] is for size 2... - // InternedQualifiedNames[6] is for size 7 - QualifiedNameSet internedNames = InternedQualifiedNames[qLength <= MaxQualifiedNames ? qLength - 1 : 0]; - qualifiedName = internSimpleNames(qualifiedName, false); - keepers[index++] = internedNames.add(qualifiedName); + return keepers; } - if (length > index) { - if (index == 0) return EmptyQualifiedNames; - System.arraycopy(keepers, 0, keepers = new char[index][][], 0, index); + + private boolean includes(char[][] qualifiedName) { + return this.qualifiedNameReferences.contains(CharOperation.toString(qualifiedName)); } - return keepers; - } - - private static char[][] internSimpleNames(char[][] simpleNames, boolean removeWellKnown) { - if (simpleNames == null) return EmptySimpleNames; - int length = simpleNames.length; - if (length == 0) return EmptySimpleNames; - - char[][] keepers = new char[length][]; - int index = 0; - next: for (int i = 0; i < length; i++) { - char[] name = simpleNames[i]; - int sLength = name.length; - for (int j = 0, m = WellKnownSimpleNames.length; j < m; j++) { - char[] wellKnownName = WellKnownSimpleNames[j]; - if (sLength > wellKnownName.length) break; // all remaining well known names are shorter - if (CharOperation.equals(name, wellKnownName)) { - if (!removeWellKnown) keepers[index++] = WellKnownSimpleNames[j]; - continue next; - } - } - // InternedSimpleNames[0] is for the rest (> 29) - // InternedSimpleNames[1] is for size 1... - // InternedSimpleNames[29] is for size 29 - NameSet internedNames = InternedSimpleNames[sLength < MaxSimpleNames ? sLength : 0]; - keepers[index++] = internedNames.add(name); + private boolean includes(char[] simpleName) { + return this.simpleNameReferences.contains(new String(simpleName)); } - if (length > index) { - if (index == 0) return EmptySimpleNames; - System.arraycopy(keepers, 0, keepers = new char[index][], 0, index); + + private boolean insideRoot(char[] rootName) { + return this.rootReferences.contains(new String(rootName)); } - return keepers; - } - - private boolean includes(char[][] qualifiedName) { - return this.qualifiedNameReferences.contains(CharOperation.toString(qualifiedName)); - } - - private boolean includes(char[] simpleName) { - return this.simpleNameReferences.contains(new String(simpleName)); - } - - private boolean insideRoot(char[] rootName) { - return this.rootReferences.contains(new String(rootName)); - } - - private static final char[][][] EmptyQualifiedNames = new char[0][][]; - private static final char[][] EmptySimpleNames = CharOperation.NO_CHAR_CHAR; - - private static final char[][][] WellKnownQualifiedNames = new char[][][] {TypeConstants.JAVA_LANG_RUNTIMEEXCEPTION, // - TypeConstants.JAVA_LANG_THROWABLE, // - TypeConstants.JAVA_LANG_OBJECT, // - TypeConstants.JAVA_LANG, // - new char[][] {TypeConstants.JAVA}, // - new char[][] {new char[] {'o', 'r', 'g'}}, // - new char[][] {new char[] {'c', 'o', 'm'}}, // - CharOperation.NO_CHAR_CHAR // default package - }; - private static final char[][] WellKnownSimpleNames = new char[][] {TypeConstants.JAVA_LANG_RUNTIMEEXCEPTION[2], // - TypeConstants.JAVA_LANG_THROWABLE[2], // - TypeConstants.JAVA_LANG_OBJECT[2], // - TypeConstants.JAVA, // - TypeConstants.LANG, // - new char[] {'o', 'r', 'g'}, // - new char[] {'c', 'o', 'm'} // - }; - - // each array contains qualified char[][], one for size 2, 3, 4, 5, 6, 7 & the rest - private static final int MaxQualifiedNames = 7; - private static final QualifiedNameSet[] InternedQualifiedNames = new QualifiedNameSet[MaxQualifiedNames]; - - // each array contains simple char[], one for size 1 to 29 & the rest - static final int MaxSimpleNames = 30; - static NameSet[] InternedSimpleNames = new NameSet[MaxSimpleNames]; - static { - for (int i = 0; i < MaxQualifiedNames; i++) - InternedQualifiedNames[i] = new QualifiedNameSet(37); - for (int i = 0; i < MaxSimpleNames; i++) - InternedSimpleNames[i] = new NameSet(37); - } + private static final char[][][] EmptyQualifiedNames = new char[0][][]; + private static final char[][] EmptySimpleNames = CharOperation.NO_CHAR_CHAR; + + private static final char[][][] WellKnownQualifiedNames = new char[][][] { + TypeConstants.JAVA_LANG_RUNTIMEEXCEPTION, // + TypeConstants.JAVA_LANG_THROWABLE, // + TypeConstants.JAVA_LANG_OBJECT, // + TypeConstants.JAVA_LANG, // + new char[][] {TypeConstants.JAVA}, // + new char[][] {new char[] {'o', 'r', 'g'}}, // + new char[][] {new char[] {'c', 'o', 'm'}}, // + CharOperation.NO_CHAR_CHAR // default package + }; + private static final char[][] WellKnownSimpleNames = new char[][] { + TypeConstants.JAVA_LANG_RUNTIMEEXCEPTION[2], // + TypeConstants.JAVA_LANG_THROWABLE[2], // + TypeConstants.JAVA_LANG_OBJECT[2], // + TypeConstants.JAVA, // + TypeConstants.LANG, // + new char[] {'o', 'r', 'g'}, // + new char[] {'c', 'o', 'm'} // + }; + + // each array contains qualified char[][], one for size 2, 3, 4, 5, 6, 7 & the rest + private static final int MaxQualifiedNames = 7; + private static final QualifiedNameSet[] InternedQualifiedNames = new QualifiedNameSet[MaxQualifiedNames]; + + // each array contains simple char[], one for size 1 to 29 & the rest + static final int MaxSimpleNames = 30; + static NameSet[] InternedSimpleNames = new NameSet[MaxSimpleNames]; + + static { + for (int i = 0; i < MaxQualifiedNames; i++) InternedQualifiedNames[i] = new QualifiedNameSet(37); + for (int i = 0; i < MaxSimpleNames; i++) InternedSimpleNames[i] = new NameSet(37); + } } diff --git a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/classpath/AbstractClasspathDirectory.java b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/classpath/AbstractClasspathDirectory.java index ec0893e4..20c696d7 100644 --- a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/classpath/AbstractClasspathDirectory.java +++ b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/classpath/AbstractClasspathDirectory.java @@ -1,3 +1,10 @@ +/* + * Copyright (c) 2014-2024 Takari, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v10.html + */ package io.takari.maven.plugins.compile.jdt.classpath; import java.io.IOException; @@ -14,66 +21,67 @@ import java.util.LinkedHashMap; import java.util.Map; import java.util.Set; - import org.osgi.framework.BundleException; abstract class AbstractClasspathDirectory extends DependencyClasspathEntry implements ClasspathEntry { - private final Map files; + private final Map files; - protected AbstractClasspathDirectory(Path directory, Set packages, Map files) { - super(directory, packages, getExportedPackages(directory)); - this.files = Collections.unmodifiableMap(new LinkedHashMap<>(files)); - } + protected AbstractClasspathDirectory(Path directory, Set packages, Map files) { + super(directory, packages, getExportedPackages(directory)); + this.files = Collections.unmodifiableMap(new LinkedHashMap<>(files)); + } - protected static void scanDirectory(Path basedir, String suffix, Set packages, Map files) { - try { - Files.walkFileTree(basedir, new SimpleFileVisitor() { - @Override - public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) { - String relpath = basedir.relativize(dir).toString(); - if (!relpath.isEmpty()) { - packages.add(relpath.replace('\\', '/')); - } - return FileVisitResult.CONTINUE; - } + protected static void scanDirectory(Path basedir, String suffix, Set packages, Map files) { + try { + Files.walkFileTree(basedir, new SimpleFileVisitor() { + @Override + public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) { + String relpath = basedir.relativize(dir).toString(); + if (!relpath.isEmpty()) { + packages.add(relpath.replace('\\', '/')); + } + return FileVisitResult.CONTINUE; + } - @Override - public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) { - String relpath = basedir.relativize(file).toString(); - if (relpath.endsWith(suffix)) { - files.put(relpath.substring(0, relpath.length() - suffix.length()).replace('\\', '/'), file); - } - return FileVisitResult.CONTINUE; + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) { + String relpath = basedir.relativize(file).toString(); + if (relpath.endsWith(suffix)) { + files.put( + relpath.substring(0, relpath.length() - suffix.length()) + .replace('\\', '/'), + file); + } + return FileVisitResult.CONTINUE; + } + }); + } catch (NoSuchFileException expected) { + // the directory does not exist, nothing to be alarmed about + } catch (IOException e) { + throw new UncheckedIOException(e); } - }); - } catch (NoSuchFileException expected) { - // the directory does not exist, nothing to be alarmed about - } catch (IOException e) { - throw new UncheckedIOException(e); } - } - private static Collection getExportedPackages(Path directory) { - Collection exportedPackages = null; - try (InputStream is = Files.newInputStream(directory.resolve(PATH_EXPORT_PACKAGE))) { - exportedPackages = parseExportPackage(is); - } catch (IOException e) { - // silently ignore missing/bad export-package files - } - if (exportedPackages == null) { - try (InputStream is = Files.newInputStream(directory.resolve(PATH_MANIFESTMF))) { - exportedPackages = parseBundleManifest(is); - } catch (IOException | BundleException e) { - // silently ignore missing/bad export-package files - } + private static Collection getExportedPackages(Path directory) { + Collection exportedPackages = null; + try (InputStream is = Files.newInputStream(directory.resolve(PATH_EXPORT_PACKAGE))) { + exportedPackages = parseExportPackage(is); + } catch (IOException e) { + // silently ignore missing/bad export-package files + } + if (exportedPackages == null) { + try (InputStream is = Files.newInputStream(directory.resolve(PATH_MANIFESTMF))) { + exportedPackages = parseBundleManifest(is); + } catch (IOException | BundleException e) { + // silently ignore missing/bad export-package files + } + } + return exportedPackages; } - return exportedPackages; - } - - public Path getFile(String packageName, String typeName) { - String qualifiedFileName = packageName + "/" + typeName; - return files.get(qualifiedFileName); - } + public Path getFile(String packageName, String typeName) { + String qualifiedFileName = packageName + "/" + typeName; + return files.get(qualifiedFileName); + } } diff --git a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/classpath/Classpath.java b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/classpath/Classpath.java index c94cbec4..49342d25 100644 --- a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/classpath/Classpath.java +++ b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/classpath/Classpath.java @@ -1,9 +1,9 @@ -/** - * Copyright (c) 2014 Takari, Inc. +/* + * Copyright (c) 2014-2024 Takari, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * https://www.eclipse.org/legal/epl-v10.html */ package io.takari.maven.plugins.compile.jdt.classpath; @@ -14,94 +14,95 @@ import java.util.List; import java.util.Map; import java.util.stream.Collectors; - import org.eclipse.jdt.core.compiler.CharOperation; import org.eclipse.jdt.internal.compiler.env.INameEnvironment; import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer; public class Classpath implements INameEnvironment { - private final List entries; + private final List entries; - private final List mutableentries; + private final List mutableentries; - private Map> packages; + private Map> packages; - public Classpath(List entries, List localentries) { - this.entries = entries; - this.mutableentries = localentries; - this.packages = newPackageIndex(entries); - } + public Classpath(List entries, List localentries) { + this.entries = entries; + this.mutableentries = localentries; + this.packages = newPackageIndex(entries); + } - private static Map> newPackageIndex(List entries) { - Map> classpath = new LinkedHashMap<>(); // preserves order - for (ClasspathEntry entry : entries) { - for (String packageName : entry.getPackageNames()) { - classpath.computeIfAbsent(packageName, k -> new ArrayList<>()).add(entry); - } + private static Map> newPackageIndex(List entries) { + Map> classpath = new LinkedHashMap<>(); // preserves order + for (ClasspathEntry entry : entries) { + for (String packageName : entry.getPackageNames()) { + classpath.computeIfAbsent(packageName, k -> new ArrayList<>()).add(entry); + } + } + return classpath.entrySet().stream() + .collect(Collectors.toUnmodifiableMap( + Map.Entry::getKey, e -> Collections.unmodifiableList(e.getValue()))); } - return classpath.entrySet().stream().collect(Collectors.toUnmodifiableMap( - Map.Entry::getKey, e -> Collections.unmodifiableList( e.getValue()))); - } - @Override - public NameEnvironmentAnswer findType(char[][] compoundTypeName) { - if (compoundTypeName == null) { - return null; + @Override + public NameEnvironmentAnswer findType(char[][] compoundTypeName) { + if (compoundTypeName == null) { + return null; + } + int typeNameIndex = compoundTypeName.length - 1; + char[][] packageName = CharOperation.subarray(compoundTypeName, 0, typeNameIndex); + return findType( + new String(CharOperation.concatWith(packageName, '/')), new String(compoundTypeName[typeNameIndex])); } - int typeNameIndex = compoundTypeName.length - 1; - char[][] packageName = CharOperation.subarray(compoundTypeName, 0, typeNameIndex); - return findType(new String(CharOperation.concatWith(packageName, '/')), new String(compoundTypeName[typeNameIndex])); - } - @Override - public NameEnvironmentAnswer findType(char[] typeName, char[][] packageName) { - return findType(new String(CharOperation.concatWith(packageName, '/')), new String(typeName)); - } + @Override + public NameEnvironmentAnswer findType(char[] typeName, char[][] packageName) { + return findType(new String(CharOperation.concatWith(packageName, '/')), new String(typeName)); + } - private NameEnvironmentAnswer findType(String packageName, String typeName) { - NameEnvironmentAnswer suggestedAnswer = null; - Collection entries = !packageName.isEmpty() ? packages.get(packageName) : this.entries; - if (entries != null) { - for (ClasspathEntry entry : entries) { - NameEnvironmentAnswer answer = entry.findType(packageName, typeName); - if (answer != null) { - if (!answer.ignoreIfBetter()) { - if (answer.isBetter(suggestedAnswer)) { - return answer; + private NameEnvironmentAnswer findType(String packageName, String typeName) { + NameEnvironmentAnswer suggestedAnswer = null; + Collection entries = !packageName.isEmpty() ? packages.get(packageName) : this.entries; + if (entries != null) { + for (ClasspathEntry entry : entries) { + NameEnvironmentAnswer answer = entry.findType(packageName, typeName); + if (answer != null) { + if (!answer.ignoreIfBetter()) { + if (answer.isBetter(suggestedAnswer)) { + return answer; + } + } else if (answer.isBetter(suggestedAnswer)) { + // remember suggestion and keep looking + suggestedAnswer = answer; + } + } } - } else if (answer.isBetter(suggestedAnswer)) { - // remember suggestion and keep looking - suggestedAnswer = answer; - } } - } + return suggestedAnswer; } - return suggestedAnswer; - } - @Override - public boolean isPackage(char[][] parentPackageName, char[] packageName) { - String name = new String(CharOperation.concatWith(parentPackageName, packageName, '/')); - return packages.containsKey(name); - } - - @Override - public void cleanup() { - // TODO - } + @Override + public boolean isPackage(char[][] parentPackageName, char[] packageName) { + String name = new String(CharOperation.concatWith(parentPackageName, packageName, '/')); + return packages.containsKey(name); + } - public void reset() { - if (mutableentries == null) { - return; + @Override + public void cleanup() { + // TODO } - for (MutableClasspathEntry entry : mutableentries) { - entry.reset(); + + public void reset() { + if (mutableentries == null) { + return; + } + for (MutableClasspathEntry entry : mutableentries) { + entry.reset(); + } + packages = newPackageIndex(entries); } - packages = newPackageIndex(entries); - } - public List getEntries() { - return entries; - } + public List getEntries() { + return entries; + } } diff --git a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/classpath/ClasspathDirectory.java b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/classpath/ClasspathDirectory.java index b8272ca5..af826794 100644 --- a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/classpath/ClasspathDirectory.java +++ b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/classpath/ClasspathDirectory.java @@ -1,9 +1,9 @@ -/** - * Copyright (c) 2014 Takari, Inc. +/* + * Copyright (c) 2014-2024 Takari, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * https://www.eclipse.org/legal/epl-v10.html */ package io.takari.maven.plugins.compile.jdt.classpath; @@ -17,7 +17,6 @@ import java.util.HashSet; import java.util.Map; import java.util.Set; - import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader; import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException; import org.eclipse.jdt.internal.compiler.env.AccessRestriction; @@ -25,35 +24,35 @@ public class ClasspathDirectory extends AbstractClasspathDirectory implements ClasspathEntry { - private ClasspathDirectory(Path directory, Set packages, Map files) { - super(directory, packages, files); - } + private ClasspathDirectory(Path directory, Set packages, Map files) { + super(directory, packages, files); + } - @Override - public NameEnvironmentAnswer findType(String packageName, String typeName, AccessRestriction accessRestriction) { - try { - Path classFile = getFile(packageName, typeName); - if (classFile != null) { - try (InputStream is = Files.newInputStream(classFile)) { - return new NameEnvironmentAnswer(ClassFileReader.read(is, classFile.getFileName().toString(), false), accessRestriction); + @Override + public NameEnvironmentAnswer findType(String packageName, String typeName, AccessRestriction accessRestriction) { + try { + Path classFile = getFile(packageName, typeName); + if (classFile != null) { + try (InputStream is = Files.newInputStream(classFile)) { + return new NameEnvironmentAnswer( + ClassFileReader.read(is, classFile.getFileName().toString(), false), accessRestriction); + } + } + } catch (ClassFormatException | IOException e) { + // treat as if type is missing } - } - } catch (ClassFormatException | IOException e) { - // treat as if type is missing + return null; } - return null; - } - - @Override - public String toString() { - return "Classpath for directory " + file; - } - public static ClasspathDirectory create(Path directory) { - Set packages = new HashSet<>(); - Map files = new HashMap<>(); - scanDirectory(directory, SUFFIX_STRING_class, packages, files); - return new ClasspathDirectory(directory, packages, files); - } + @Override + public String toString() { + return "Classpath for directory " + file; + } + public static ClasspathDirectory create(Path directory) { + Set packages = new HashSet<>(); + Map files = new HashMap<>(); + scanDirectory(directory, SUFFIX_STRING_class, packages, files); + return new ClasspathDirectory(directory, packages, files); + } } diff --git a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/classpath/ClasspathEntry.java b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/classpath/ClasspathEntry.java index 8b70d3a5..5727a98a 100644 --- a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/classpath/ClasspathEntry.java +++ b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/classpath/ClasspathEntry.java @@ -1,21 +1,20 @@ -/** - * Copyright (c) 2014 Takari, Inc. +/* + * Copyright (c) 2014-2024 Takari, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * https://www.eclipse.org/legal/epl-v10.html */ package io.takari.maven.plugins.compile.jdt.classpath; import java.util.Collection; - import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer; public interface ClasspathEntry { - Collection getPackageNames(); + Collection getPackageNames(); - NameEnvironmentAnswer findType(String packageName, String typeName); + NameEnvironmentAnswer findType(String packageName, String typeName); - String getEntryDescription(); + String getEntryDescription(); } diff --git a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/classpath/ClasspathJar.java b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/classpath/ClasspathJar.java index a22397df..4fbf0fda 100644 --- a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/classpath/ClasspathJar.java +++ b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/classpath/ClasspathJar.java @@ -1,9 +1,9 @@ -/** - * Copyright (c) 2014 Takari, Inc. +/* + * Copyright (c) 2014-2024 Takari, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * https://www.eclipse.org/legal/epl-v10.html */ package io.takari.maven.plugins.compile.jdt.classpath; @@ -18,7 +18,6 @@ import java.util.Set; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; - import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader; import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException; import org.eclipse.jdt.internal.compiler.env.AccessRestriction; @@ -27,68 +26,70 @@ public class ClasspathJar extends DependencyClasspathEntry implements ClasspathEntry { - private final ZipFile zipFile; - - private ClasspathJar(Path file, ZipFile zipFile, Collection packageNames, Collection exportedPackages) throws IOException { - super(file, packageNames, exportedPackages); - this.zipFile = zipFile; - } + private final ZipFile zipFile; - private static Set getPackageNames(ZipFile zipFile) { - Set result = new HashSet(); - for (Enumeration e = zipFile.entries(); e.hasMoreElements();) { - ZipEntry entry = (ZipEntry) e.nextElement(); - String name = entry.getName(); - int last = name.lastIndexOf('/'); - while (last > 0) { - name = name.substring(0, last); - result.add(name); - last = name.lastIndexOf('/'); - } + private ClasspathJar( + Path file, ZipFile zipFile, Collection packageNames, Collection exportedPackages) + throws IOException { + super(file, packageNames, exportedPackages); + this.zipFile = zipFile; } - return result; - } - @Override - public NameEnvironmentAnswer findType(String packageName, String typeName, AccessRestriction accessRestriction) { - try { - String qualifiedFileName = packageName + "/" + typeName + SUFFIX_STRING_class; - ClassFileReader reader = ClassFileReader.read(this.zipFile, qualifiedFileName); - if (reader != null) { - return new NameEnvironmentAnswer(reader, accessRestriction); - } - } catch (ClassFormatException | IOException e) { - // treat as if class file is missing + private static Set getPackageNames(ZipFile zipFile) { + Set result = new HashSet(); + for (Enumeration e = zipFile.entries(); e.hasMoreElements(); ) { + ZipEntry entry = (ZipEntry) e.nextElement(); + String name = entry.getName(); + int last = name.lastIndexOf('/'); + while (last > 0) { + name = name.substring(0, last); + result.add(name); + last = name.lastIndexOf('/'); + } + } + return result; } - return null; - } - @Override - public String toString() { - return "Classpath for jar file " + file.toString(); //$NON-NLS-1$ - } + @Override + public NameEnvironmentAnswer findType(String packageName, String typeName, AccessRestriction accessRestriction) { + try { + String qualifiedFileName = packageName + "/" + typeName + SUFFIX_STRING_class; + ClassFileReader reader = ClassFileReader.read(this.zipFile, qualifiedFileName); + if (reader != null) { + return new NameEnvironmentAnswer(reader, accessRestriction); + } + } catch (ClassFormatException | IOException e) { + // treat as if class file is missing + } + return null; + } - public static ClasspathJar create(Path file) throws IOException { - ZipFile zipFile = new ZipFile(file.toFile()); - Set packageNames = getPackageNames(zipFile); - Collection exportedPackages = null; - // TODO do not look for exported packages in java standard library - ZipEntry entry = zipFile.getEntry(PATH_EXPORT_PACKAGE); - if (entry != null) { - try (InputStream is = zipFile.getInputStream(entry)) { - exportedPackages = parseExportPackage(is); - } + @Override + public String toString() { + return "Classpath for jar file " + file.toString(); // $NON-NLS-1$ } - if (exportedPackages == null) { - entry = zipFile.getEntry(PATH_MANIFESTMF); - if (entry != null) { - try (InputStream is = zipFile.getInputStream(entry)) { - exportedPackages = parseBundleManifest(is); - } catch (BundleException e) { - // silently ignore bundle manifest parsing problems + + public static ClasspathJar create(Path file) throws IOException { + ZipFile zipFile = new ZipFile(file.toFile()); + Set packageNames = getPackageNames(zipFile); + Collection exportedPackages = null; + // TODO do not look for exported packages in java standard library + ZipEntry entry = zipFile.getEntry(PATH_EXPORT_PACKAGE); + if (entry != null) { + try (InputStream is = zipFile.getInputStream(entry)) { + exportedPackages = parseExportPackage(is); + } + } + if (exportedPackages == null) { + entry = zipFile.getEntry(PATH_MANIFESTMF); + if (entry != null) { + try (InputStream is = zipFile.getInputStream(entry)) { + exportedPackages = parseBundleManifest(is); + } catch (BundleException e) { + // silently ignore bundle manifest parsing problems + } + } } - } + return new ClasspathJar(file, zipFile, packageNames, exportedPackages); } - return new ClasspathJar(file, zipFile, packageNames, exportedPackages); - } } diff --git a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/classpath/DependencyClasspathEntry.java b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/classpath/DependencyClasspathEntry.java index d96434c3..e9af6a36 100644 --- a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/classpath/DependencyClasspathEntry.java +++ b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/classpath/DependencyClasspathEntry.java @@ -1,5 +1,13 @@ +/* + * Copyright (c) 2014-2024 Takari, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v10.html + */ package io.takari.maven.plugins.compile.jdt.classpath; +import io.takari.maven.plugins.exportpackage.ExportPackageMojo; import java.io.BufferedReader; import java.io.File; import java.io.IOException; @@ -14,7 +22,6 @@ import java.util.Map; import java.util.Set; import java.util.stream.Collectors; - import org.eclipse.jdt.core.compiler.IProblem; import org.eclipse.jdt.internal.compiler.env.AccessRestriction; import org.eclipse.jdt.internal.compiler.env.AccessRule; @@ -24,96 +31,99 @@ import org.osgi.framework.BundleException; import org.osgi.framework.Constants; -import io.takari.maven.plugins.exportpackage.ExportPackageMojo; - public abstract class DependencyClasspathEntry implements ClasspathEntry { - protected static final String PATH_EXPORT_PACKAGE = ExportPackageMojo.PATH_EXPORT_PACKAGE; + protected static final String PATH_EXPORT_PACKAGE = ExportPackageMojo.PATH_EXPORT_PACKAGE; - protected static final String PATH_MANIFESTMF = "META-INF/MANIFEST.MF"; + protected static final String PATH_MANIFESTMF = "META-INF/MANIFEST.MF"; - protected final Path file; + protected final Path file; - protected final Set packageNames; + protected final Set packageNames; - protected final Set exportedPackages; + protected final Set exportedPackages; - protected DependencyClasspathEntry(Path file, Collection packageNames, Collection exportedPackages) { - this.file = PathNormalizer.getCanonicalPath(file); - this.packageNames = Collections.unmodifiableSet(new LinkedHashSet<>(packageNames)); - this.exportedPackages = exportedPackages != null ? Collections.unmodifiableSet(new LinkedHashSet<>(exportedPackages)) : null; - } - - protected AccessRestriction getAccessRestriction(String packageName) { - if (exportedPackages != null && !exportedPackages.contains(packageName)) { - AccessRule rule = new AccessRule(null /* pattern */, IProblem.ForbiddenReference, true /* keep looking for accessible type */); - return new AccessRestriction(rule, AccessRestriction.COMMAND_LINE, getEntryName()); + protected DependencyClasspathEntry( + Path file, Collection packageNames, Collection exportedPackages) { + this.file = PathNormalizer.getCanonicalPath(file); + this.packageNames = Collections.unmodifiableSet(new LinkedHashSet<>(packageNames)); + this.exportedPackages = + exportedPackages != null ? Collections.unmodifiableSet(new LinkedHashSet<>(exportedPackages)) : null; } - return null; - } - @Override - public Collection getPackageNames() { - return packageNames; - } + protected AccessRestriction getAccessRestriction(String packageName) { + if (exportedPackages != null && !exportedPackages.contains(packageName)) { + AccessRule rule = new AccessRule( + null /* pattern */, IProblem.ForbiddenReference, true /* keep looking for accessible type */); + return new AccessRestriction(rule, AccessRestriction.COMMAND_LINE, getEntryName()); + } + return null; + } - protected static Collection parseExportPackage(InputStream is) throws IOException { - try (BufferedReader reader = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8))) { - return reader.lines().map(l -> l.replace( '.', '/')).collect(Collectors.toList()); + @Override + public Collection getPackageNames() { + return packageNames; } - } - protected static Collection parseBundleManifest(InputStream is) throws IOException, BundleException { - Map headers = parseManifest(is); - if (!headers.containsKey(Constants.BUNDLE_SYMBOLICNAME)) { - return null; // not an OSGi bundle + protected static Collection parseExportPackage(InputStream is) throws IOException { + try (BufferedReader reader = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8))) { + return reader.lines().map(l -> l.replace('.', '/')).collect(Collectors.toList()); + } } - String exportPackageHeader = headers.get(Constants.EXPORT_PACKAGE); - if (exportPackageHeader == null) { - return Collections.emptySet(); // nothing is exported + + protected static Collection parseBundleManifest(InputStream is) throws IOException, BundleException { + Map headers = parseManifest(is); + if (!headers.containsKey(Constants.BUNDLE_SYMBOLICNAME)) { + return null; // not an OSGi bundle + } + String exportPackageHeader = headers.get(Constants.EXPORT_PACKAGE); + if (exportPackageHeader == null) { + return Collections.emptySet(); // nothing is exported + } + Set packages = new HashSet<>(); + for (ManifestElement element : ManifestElement.parseHeader(Constants.EXPORT_PACKAGE, exportPackageHeader)) { + packages.add(element.getValue().replace('.', '/')); + } + return packages; } - Set packages = new HashSet<>(); - for (ManifestElement element : ManifestElement.parseHeader(Constants.EXPORT_PACKAGE, exportPackageHeader)) { - packages.add(element.getValue().replace('.', '/')); + + private static CaseInsensitiveDictionaryMap parseManifest(InputStream is) + throws IOException, BundleException { + CaseInsensitiveDictionaryMap headers = new CaseInsensitiveDictionaryMap<>(); + ManifestElement.parseBundleManifest(is, headers); + return headers; } - return packages; - } - - private static CaseInsensitiveDictionaryMap parseManifest(InputStream is) throws IOException, BundleException { - CaseInsensitiveDictionaryMap headers = new CaseInsensitiveDictionaryMap<>(); - ManifestElement.parseBundleManifest(is, headers); - return headers; - } - - @Override - public String getEntryDescription() { - StringBuilder sb = new StringBuilder(getEntryName()); - if (exportedPackages != null) { - sb.append("["); - int idx = 0; - for (String exportedPackage : exportedPackages) { - if (idx++ > 0) { - sb.append(File.pathSeparatorChar); + + @Override + public String getEntryDescription() { + StringBuilder sb = new StringBuilder(getEntryName()); + if (exportedPackages != null) { + sb.append("["); + int idx = 0; + for (String exportedPackage : exportedPackages) { + if (idx++ > 0) { + sb.append(File.pathSeparatorChar); + } + sb.append('+').append(exportedPackage).append("/*"); + } + if (idx > 0) { + sb.append(File.pathSeparatorChar); + } + sb.append("?**/*"); + sb.append(']'); } - sb.append('+').append(exportedPackage).append("/*"); - } - if (idx > 0) { - sb.append(File.pathSeparatorChar); - } - sb.append("?**/*"); - sb.append(']'); + return sb.toString(); } - return sb.toString(); - } - @Override - public NameEnvironmentAnswer findType(String packageName, String typeName) { - return findType(packageName, typeName, getAccessRestriction(packageName)); - } + @Override + public NameEnvironmentAnswer findType(String packageName, String typeName) { + return findType(packageName, typeName, getAccessRestriction(packageName)); + } - public abstract NameEnvironmentAnswer findType(String packageName, String typeName, AccessRestriction accessRestriction); + public abstract NameEnvironmentAnswer findType( + String packageName, String typeName, AccessRestriction accessRestriction); - public String getEntryName() { - return file.toString(); - } + public String getEntryName() { + return file.toString(); + } } diff --git a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/classpath/JavaInstallation.java b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/classpath/JavaInstallation.java index 8c88673a..8e778638 100644 --- a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/classpath/JavaInstallation.java +++ b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/classpath/JavaInstallation.java @@ -1,9 +1,9 @@ -/** - * Copyright (c) 2014 Takari, Inc. +/* + * Copyright (c) 2014-2024 Takari, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * https://www.eclipse.org/legal/epl-v10.html */ package io.takari.maven.plugins.compile.jdt.classpath; @@ -18,75 +18,75 @@ import java.util.Collections; import java.util.List; import java.util.function.Predicate; - import org.eclipse.jdt.internal.compiler.util.Util; public class JavaInstallation { - private static final Predicate POTENTIAL_ZIP_FILTER = p -> Util.isPotentialZipArchive(p.getFileName().toString()); + private static final Predicate POTENTIAL_ZIP_FILTER = + p -> Util.isPotentialZipArchive(p.getFileName().toString()); - private final List classpath; + private final List classpath; - private JavaInstallation(List classpath) { - this.classpath = Collections.unmodifiableList(new ArrayList<>(classpath)); - } + private JavaInstallation(List classpath) { + this.classpath = Collections.unmodifiableList(new ArrayList<>(classpath)); + } - /** - * Returns default classpath associated with this java installation. The classpath includes bootstrap, extendion and endorsed entries. - */ - public List getClasspath() { - return classpath; - } + /** + * Returns default classpath associated with this java installation. The classpath includes bootstrap, extendion and endorsed entries. + */ + public List getClasspath() { + return classpath; + } - private static List getJava8() throws IOException { - // mostly copy&paste from tycho - // See org.eclipse.jdt.internal.compiler.batch.Main.setPaths + private static List getJava8() throws IOException { + // mostly copy&paste from tycho + // See org.eclipse.jdt.internal.compiler.batch.Main.setPaths - List classpath = new ArrayList<>(); + List classpath = new ArrayList<>(); - Path javaHome = Util.getJavaHome().toPath(); + Path javaHome = Util.getJavaHome().toPath(); - // boot classpath - scanForArchives(classpath, javaHome.resolve("lib")); + // boot classpath + scanForArchives(classpath, javaHome.resolve("lib")); - // endorsed libraries - scanForArchives(classpath, javaHome.resolve("lib/endorsed")); + // endorsed libraries + scanForArchives(classpath, javaHome.resolve("lib/endorsed")); - // extension libraries - scanForArchives(classpath, javaHome.resolve("lib/ext")); + // extension libraries + scanForArchives(classpath, javaHome.resolve("lib/ext")); - return classpath; - } + return classpath; + } - private static void scanForArchives(List classPathList, Path dir) throws IOException { - if (Files.isDirectory(dir)) { - Files.list(dir).filter(POTENTIAL_ZIP_FILTER).forEach(classPathList::add); + private static void scanForArchives(List classPathList, Path dir) throws IOException { + if (Files.isDirectory(dir)) { + Files.list(dir).filter(POTENTIAL_ZIP_FILTER).forEach(classPathList::add); + } } - } - - private static List getJrtFs() throws IOException { - // http://openjdk.java.net/jeps/220 - FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/")); - List classpath = new ArrayList<>(); - for (Path root : fs.getRootDirectories()) { - Files.list(root.resolve("modules")).forEach(classpath::add); + + private static List getJrtFs() throws IOException { + // http://openjdk.java.net/jeps/220 + FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/")); + List classpath = new ArrayList<>(); + for (Path root : fs.getRootDirectories()) { + Files.list(root.resolve("modules")).forEach(classpath::add); + } + // technically, this leaks open FileSystem instance + // which is okay, since singleton #instance is never released + return classpath; } - // technically, this leaks open FileSystem instance - // which is okay, since singleton #instance is never released - return classpath; - } - - private static JavaInstallation instance; - - public static synchronized JavaInstallation getDefault() throws IOException { - if (instance == null) { - List cp; - try { - cp = getJrtFs(); - } catch (ProviderNotFoundException e) { - cp = getJava8(); - } - instance = new JavaInstallation(cp); + + private static JavaInstallation instance; + + public static synchronized JavaInstallation getDefault() throws IOException { + if (instance == null) { + List cp; + try { + cp = getJrtFs(); + } catch (ProviderNotFoundException e) { + cp = getJava8(); + } + instance = new JavaInstallation(cp); + } + return instance; } - return instance; - } } diff --git a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/classpath/MutableClasspathEntry.java b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/classpath/MutableClasspathEntry.java index f36abaec..1daea982 100644 --- a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/classpath/MutableClasspathEntry.java +++ b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/classpath/MutableClasspathEntry.java @@ -1,12 +1,12 @@ -/** - * Copyright (c) 2014 Takari, Inc. +/* + * Copyright (c) 2014-2024 Takari, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * https://www.eclipse.org/legal/epl-v10.html */ package io.takari.maven.plugins.compile.jdt.classpath; public interface MutableClasspathEntry { - void reset(); + void reset(); } diff --git a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/classpath/PathNormalizer.java b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/classpath/PathNormalizer.java index a269928e..d2a1209d 100644 --- a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/classpath/PathNormalizer.java +++ b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/classpath/PathNormalizer.java @@ -1,3 +1,10 @@ +/* + * Copyright (c) 2014-2024 Takari, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v10.html + */ package io.takari.maven.plugins.compile.jdt.classpath; import java.io.IOException; @@ -6,15 +13,15 @@ import java.nio.file.Path; public class PathNormalizer { - public static Path getCanonicalPath(Path file) { - try { - return file.toRealPath(); - } catch (NoSuchFileException e) { - // Path#toRealPath() only works for existing files - // return file.toFile().getCanonicalFile().toPath(); - return file.toAbsolutePath().normalize(); - } catch (IOException e) { - throw new UncheckedIOException(e); + public static Path getCanonicalPath(Path file) { + try { + return file.toRealPath(); + } catch (NoSuchFileException e) { + // Path#toRealPath() only works for existing files + // return file.toFile().getCanonicalFile().toPath(); + return file.toAbsolutePath().normalize(); + } catch (IOException e) { + throw new UncheckedIOException(e); + } } - } } diff --git a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/classpath/SourcepathDirectory.java b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/classpath/SourcepathDirectory.java index fce9e9ac..44475e7d 100644 --- a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/classpath/SourcepathDirectory.java +++ b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/compile/jdt/classpath/SourcepathDirectory.java @@ -1,3 +1,10 @@ +/* + * Copyright (c) 2014-2024 Takari, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v10.html + */ package io.takari.maven.plugins.compile.jdt.classpath; import static org.eclipse.jdt.internal.compiler.util.SuffixConstants.SUFFIX_STRING_java; @@ -8,53 +15,57 @@ import java.util.HashSet; import java.util.Map; import java.util.Set; - import org.eclipse.jdt.internal.compiler.batch.CompilationUnit; import org.eclipse.jdt.internal.compiler.env.AccessRestriction; import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer; public class SourcepathDirectory extends AbstractClasspathDirectory { - public static class ClasspathCompilationUnit extends CompilationUnit { - public ClasspathCompilationUnit(Path file, String encoding) { - super(null /* contents */, file.toAbsolutePath().toString(), encoding, null /* destinationPath */, false /* ignoreOptionalProblems */, null /* modName */); + public static class ClasspathCompilationUnit extends CompilationUnit { + public ClasspathCompilationUnit(Path file, String encoding) { + super( + null /* contents */, + file.toAbsolutePath().toString(), + encoding, + null /* destinationPath */, + false /* ignoreOptionalProblems */, + null /* modName */); + } } - } - private final String encoding; + private final String encoding; - private SourcepathDirectory(Path directory, Set packages, Map files, Charset encoding) { - super(directory, packages, files); - this.encoding = encoding != null ? encoding.name() : null; - } + private SourcepathDirectory(Path directory, Set packages, Map files, Charset encoding) { + super(directory, packages, files); + this.encoding = encoding != null ? encoding.name() : null; + } - @Override - public NameEnvironmentAnswer findType(String packageName, String typeName, AccessRestriction accessRestriction) { - Path javaFile = getFile(packageName, typeName); + @Override + public NameEnvironmentAnswer findType(String packageName, String typeName, AccessRestriction accessRestriction) { + Path javaFile = getFile(packageName, typeName); - // Could be looking for a nested class, so try using outer class file name. - // ASSUMPTION: '$' is ONLY used in a compiler generated class file names. - if (javaFile == null && typeName.indexOf("$") > 0) { - javaFile = getFile(packageName, typeName.split("\\$")[0]); - } + // Could be looking for a nested class, so try using outer class file name. + // ASSUMPTION: '$' is ONLY used in a compiler generated class file names. + if (javaFile == null && typeName.indexOf("$") > 0) { + javaFile = getFile(packageName, typeName.split("\\$")[0]); + } - if (javaFile != null) { - CompilationUnit cu = new ClasspathCompilationUnit(javaFile, encoding); - return new NameEnvironmentAnswer(cu, accessRestriction); + if (javaFile != null) { + CompilationUnit cu = new ClasspathCompilationUnit(javaFile, encoding); + return new NameEnvironmentAnswer(cu, accessRestriction); + } + return null; } - return null; - } - @Override - public String toString() { - return "Sourcepath for directory " + file; - } - - public static SourcepathDirectory create(Path directory, Charset encoding) { - Set packages = new HashSet<>(); - Map files = new HashMap<>(); - scanDirectory(directory, SUFFIX_STRING_java, packages, files); - return new SourcepathDirectory(directory, packages, files, encoding); - } + @Override + public String toString() { + return "Sourcepath for directory " + file; + } + public static SourcepathDirectory create(Path directory, Charset encoding) { + Set packages = new HashSet<>(); + Map files = new HashMap<>(); + scanDirectory(directory, SUFFIX_STRING_java, packages, files); + return new SourcepathDirectory(directory, packages, files, encoding); + } } diff --git a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/configurator/MojoConfigurationProcessor.java b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/configurator/MojoConfigurationProcessor.java index 20c25991..868ac6a8 100644 --- a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/configurator/MojoConfigurationProcessor.java +++ b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/configurator/MojoConfigurationProcessor.java @@ -1,9 +1,9 @@ -/** - * Copyright (c) 2014 Takari, Inc. +/* + * Copyright (c) 2014-2024 Takari, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * https://www.eclipse.org/legal/epl-v10.html */ package io.takari.maven.plugins.configurator; @@ -11,7 +11,6 @@ import java.io.InputStreamReader; import java.io.StringReader; import java.util.List; - import org.apache.maven.plugin.descriptor.MojoDescriptor; import org.apache.maven.plugin.descriptor.PluginDescriptor; import org.apache.maven.plugin.descriptor.PluginDescriptorBuilder; @@ -23,70 +22,80 @@ // // The normal process in Maven does merging of default Mojo configuration with the configuration -// provided by the POM, but we need to change the procesing in order to support the namespacing of configuration in the POM -// configuraiton. So we take the original configuration, take the POM configuration and take out the configuration that is namespaced to +// provided by the POM, but we need to change the procesing in order to support the namespacing of configuration in the +// POM +// configuraiton. So we take the original configuration, take the POM configuration and take out the configuration that +// is namespaced to // the Mojo we are executing and create a configuration that looks normal to the standard Maven process. // public class MojoConfigurationProcessor { - private static PluginDescriptorBuilder pluginDescriptorBuilder = new PluginDescriptorBuilder(); + private static PluginDescriptorBuilder pluginDescriptorBuilder = new PluginDescriptorBuilder(); - public PlexusConfiguration mojoConfigurationFor(Object mojoInstance, PlexusConfiguration pluginConfigurationFromMaven) throws ComponentConfigurationException { - try (InputStream is = mojoInstance.getClass().getResourceAsStream("/META-INF/maven/plugin.xml")) { - PluginDescriptor pd = pluginDescriptorBuilder.build(new InputStreamReader(is, "UTF-8")); // closes input stream too - String goal = determineGoal(mojoInstance.getClass().getName(), pd); - PlexusConfiguration defaultMojoConfiguration = pd.getMojo(goal).getMojoConfiguration(); - PlexusConfiguration mojoConfiguration = extractAndMerge(goal, pluginConfigurationFromMaven, defaultMojoConfiguration); - return mojoConfiguration; - } catch (Exception e) { - throw new ComponentConfigurationException(e); + public PlexusConfiguration mojoConfigurationFor( + Object mojoInstance, PlexusConfiguration pluginConfigurationFromMaven) + throws ComponentConfigurationException { + try (InputStream is = mojoInstance.getClass().getResourceAsStream("/META-INF/maven/plugin.xml")) { + PluginDescriptor pd = + pluginDescriptorBuilder.build(new InputStreamReader(is, "UTF-8")); // closes input stream too + String goal = determineGoal(mojoInstance.getClass().getName(), pd); + PlexusConfiguration defaultMojoConfiguration = pd.getMojo(goal).getMojoConfiguration(); + PlexusConfiguration mojoConfiguration = + extractAndMerge(goal, pluginConfigurationFromMaven, defaultMojoConfiguration); + return mojoConfiguration; + } catch (Exception e) { + throw new ComponentConfigurationException(e); + } } - } - /** - * Extract the Mojo specific configuration from the incoming plugin configuration from Maven by looking at an enclosing element with the goal name. Use this and merge it with the default Mojo - * configuration and use this to apply values to the Mojo. - * - * @param goal - * @param pluginConfigurationFromMaven - * @param defaultMojoConfiguration - * @return - * @throws ComponentConfigurationException - */ - PlexusConfiguration extractAndMerge(String goal, PlexusConfiguration pluginConfigurationFromMaven, PlexusConfiguration defaultMojoConfiguration) throws ComponentConfigurationException { - // - // We need to extract the specific configuration for this goal out of the POM configuration - // - PlexusConfiguration mojoConfigurationFromPom = new XmlPlexusConfiguration("configuration"); - for (PlexusConfiguration element : pluginConfigurationFromMaven.getChildren()) { - if (element.getName().equals(goal)) { - for (PlexusConfiguration goalConfigurationElements : element.getChildren()) { - mojoConfigurationFromPom.addChild(goalConfigurationElements); + /** + * Extract the Mojo specific configuration from the incoming plugin configuration from Maven by looking at an enclosing element with the goal name. Use this and merge it with the default Mojo + * configuration and use this to apply values to the Mojo. + * + * @param goal + * @param pluginConfigurationFromMaven + * @param defaultMojoConfiguration + * @return + * @throws ComponentConfigurationException + */ + PlexusConfiguration extractAndMerge( + String goal, PlexusConfiguration pluginConfigurationFromMaven, PlexusConfiguration defaultMojoConfiguration) + throws ComponentConfigurationException { + // + // We need to extract the specific configuration for this goal out of the POM configuration + // + PlexusConfiguration mojoConfigurationFromPom = new XmlPlexusConfiguration("configuration"); + for (PlexusConfiguration element : pluginConfigurationFromMaven.getChildren()) { + if (element.getName().equals(goal)) { + for (PlexusConfiguration goalConfigurationElements : element.getChildren()) { + mojoConfigurationFromPom.addChild(goalConfigurationElements); + } + } } - } + return new XmlPlexusConfiguration( + Xpp3Dom.mergeXpp3Dom(convert(mojoConfigurationFromPom), convert(defaultMojoConfiguration))); } - return new XmlPlexusConfiguration(Xpp3Dom.mergeXpp3Dom(convert(mojoConfigurationFromPom), convert(defaultMojoConfiguration))); - } - PlexusConfiguration mergePlexusConfiguration(PlexusConfiguration dominant, PlexusConfiguration recessive) throws ComponentConfigurationException { - return new XmlPlexusConfiguration(Xpp3Dom.mergeXpp3Dom(convert(dominant), convert(recessive))); - } + PlexusConfiguration mergePlexusConfiguration(PlexusConfiguration dominant, PlexusConfiguration recessive) + throws ComponentConfigurationException { + return new XmlPlexusConfiguration(Xpp3Dom.mergeXpp3Dom(convert(dominant), convert(recessive))); + } - Xpp3Dom convert(PlexusConfiguration c) throws ComponentConfigurationException { - try { - return Xpp3DomBuilder.build(new StringReader(c.toString())); - } catch (Exception e) { - throw new ComponentConfigurationException("Failure converting PlexusConfiguration to Xpp3Dom.", e); + Xpp3Dom convert(PlexusConfiguration c) throws ComponentConfigurationException { + try { + return Xpp3DomBuilder.build(new StringReader(c.toString())); + } catch (Exception e) { + throw new ComponentConfigurationException("Failure converting PlexusConfiguration to Xpp3Dom.", e); + } } - } - String determineGoal(String className, PluginDescriptor pluginDescriptor) throws ComponentConfigurationException { - List mojos = pluginDescriptor.getMojos(); - for (MojoDescriptor mojo : mojos) { - if (className.equals(mojo.getImplementation())) { - return mojo.getGoal(); - } + String determineGoal(String className, PluginDescriptor pluginDescriptor) throws ComponentConfigurationException { + List mojos = pluginDescriptor.getMojos(); + for (MojoDescriptor mojo : mojos) { + if (className.equals(mojo.getImplementation())) { + return mojo.getGoal(); + } + } + throw new ComponentConfigurationException("Cannot find the goal implementation with " + className); } - throw new ComponentConfigurationException("Cannot find the goal implementation with " + className); - } } diff --git a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/configurator/MojoConfigurator.java b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/configurator/MojoConfigurator.java index f05b88cb..f07dd3c8 100644 --- a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/configurator/MojoConfigurator.java +++ b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/configurator/MojoConfigurator.java @@ -1,9 +1,9 @@ -/** - * Copyright (c) 2014 Takari, Inc. +/* + * Copyright (c) 2014-2024 Takari, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * https://www.eclipse.org/legal/epl-v10.html */ package io.takari.maven.plugins.configurator; @@ -16,13 +16,15 @@ public class MojoConfigurator extends BasicComponentConfigurator { - @Override - public void configureComponent(final Object mojoInstance, // - final PlexusConfiguration pluginConfigurationFromMaven, // - final ExpressionEvaluator evaluator, // - final ClassRealm realm, // - final ConfigurationListener listener) throws ComponentConfigurationException { + @Override + public void configureComponent( + final Object mojoInstance, // + final PlexusConfiguration pluginConfigurationFromMaven, // + final ExpressionEvaluator evaluator, // + final ClassRealm realm, // + final ConfigurationListener listener) + throws ComponentConfigurationException { - super.configureComponent(mojoInstance, pluginConfigurationFromMaven, evaluator, realm, listener); - } + super.configureComponent(mojoInstance, pluginConfigurationFromMaven, evaluator, realm, listener); + } } diff --git a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/configurator/TakariMojoExecutionConfigurator.java b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/configurator/TakariMojoExecutionConfigurator.java index 4e3979f8..3809d022 100644 --- a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/configurator/TakariMojoExecutionConfigurator.java +++ b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/configurator/TakariMojoExecutionConfigurator.java @@ -1,7 +1,13 @@ +/* + * Copyright (c) 2014-2024 Takari, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v10.html + */ package io.takari.maven.plugins.configurator; import java.util.Collection; - import org.apache.maven.lifecycle.MojoExecutionConfigurator; import org.apache.maven.model.Plugin; import org.apache.maven.model.PluginExecution; @@ -12,61 +18,70 @@ public class TakariMojoExecutionConfigurator implements MojoExecutionConfigurator { - @Override - public void configure(MavenProject project, MojoExecution mojoExecution, boolean allowPluginLevelConfig) { + @Override + public void configure(MavenProject project, MojoExecution mojoExecution, boolean allowPluginLevelConfig) { - String groupId = mojoExecution.getGroupId(); - String artifactId = mojoExecution.getArtifactId(); - Plugin plugin = findPlugin(groupId, artifactId, project.getBuildPlugins()); + String groupId = mojoExecution.getGroupId(); + String artifactId = mojoExecution.getArtifactId(); + Plugin plugin = findPlugin(groupId, artifactId, project.getBuildPlugins()); - if (plugin == null && project.getPluginManagement() != null) { - plugin = findPlugin(groupId, artifactId, project.getPluginManagement().getPlugins()); - } + if (plugin == null && project.getPluginManagement() != null) { + plugin = findPlugin( + groupId, artifactId, project.getPluginManagement().getPlugins()); + } - if (plugin != null) { - PluginExecution pluginExecution = findPluginExecution(mojoExecution.getExecutionId(), plugin.getExecutions()); - Xpp3Dom pomConfiguration = null; - if (pluginExecution != null) { - pomConfiguration = (Xpp3Dom) pluginExecution.getConfiguration(); - } else if (allowPluginLevelConfig) { - pomConfiguration = (Xpp3Dom) plugin.getConfiguration(); - } - Xpp3Dom mojoConfigurationFromPom = (pomConfiguration != null) ? new Xpp3Dom(pomConfiguration) : null; + if (plugin != null) { + PluginExecution pluginExecution = + findPluginExecution(mojoExecution.getExecutionId(), plugin.getExecutions()); + Xpp3Dom pomConfiguration = null; + if (pluginExecution != null) { + pomConfiguration = (Xpp3Dom) pluginExecution.getConfiguration(); + } else if (allowPluginLevelConfig) { + pomConfiguration = (Xpp3Dom) plugin.getConfiguration(); + } + Xpp3Dom mojoConfigurationFromPom = (pomConfiguration != null) ? new Xpp3Dom(pomConfiguration) : null; - // - // If we have a configuration that is scoped the by the goal name then extract it. It needs to be an - // element that matches the mojoExecution.getGoal() and the element must have children. - // - if (mojoConfigurationFromPom != null && mojoConfigurationFromPom.getChild(mojoExecution.getGoal()) != null && mojoConfigurationFromPom.getChild(mojoExecution.getGoal()).getChildCount() > 0) { - mojoConfigurationFromPom = mojoConfigurationFromPom.getChild(mojoExecution.getGoal()); - } - // - // There seems to be an issue in Maven where the merging is done with the default configuration from the the plugin.xml as - // the dominant part of the merge which seems incorrect. One would assume that the configuration from the POM woul dbe - // the dominant part of the merge. - // - mojoConfigurationFromPom = Xpp3Dom.mergeXpp3Dom(mojoConfigurationFromPom, mojoExecution.getConfiguration()); - mojoExecution.setConfiguration(mojoConfigurationFromPom); + // + // If we have a configuration that is scoped the by the goal name then extract it. It needs to be an + // element that matches the mojoExecution.getGoal() and the element must have children. + // + if (mojoConfigurationFromPom != null + && mojoConfigurationFromPom.getChild(mojoExecution.getGoal()) != null + && mojoConfigurationFromPom + .getChild(mojoExecution.getGoal()) + .getChildCount() + > 0) { + mojoConfigurationFromPom = mojoConfigurationFromPom.getChild(mojoExecution.getGoal()); + } + // + // There seems to be an issue in Maven where the merging is done with the default configuration from the the + // plugin.xml as + // the dominant part of the merge which seems incorrect. One would assume that the configuration from the + // POM woul dbe + // the dominant part of the merge. + // + mojoConfigurationFromPom = Xpp3Dom.mergeXpp3Dom(mojoConfigurationFromPom, mojoExecution.getConfiguration()); + mojoExecution.setConfiguration(mojoConfigurationFromPom); + } } - } - private Plugin findPlugin(String groupId, String artifactId, Collection plugins) { - for (Plugin plugin : plugins) { - if (artifactId.equals(plugin.getArtifactId()) && groupId.equals(plugin.getGroupId())) { - return plugin; - } + private Plugin findPlugin(String groupId, String artifactId, Collection plugins) { + for (Plugin plugin : plugins) { + if (artifactId.equals(plugin.getArtifactId()) && groupId.equals(plugin.getGroupId())) { + return plugin; + } + } + return null; } - return null; - } - private PluginExecution findPluginExecution(String executionId, Collection executions) { - if (StringUtils.isNotEmpty(executionId)) { - for (PluginExecution execution : executions) { - if (executionId.equals(execution.getId())) { - return execution; + private PluginExecution findPluginExecution(String executionId, Collection executions) { + if (StringUtils.isNotEmpty(executionId)) { + for (PluginExecution execution : executions) { + if (executionId.equals(execution.getId())) { + return execution; + } + } } - } + return null; } - return null; - } } diff --git a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/exportpackage/ExportPackageMojo.java b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/exportpackage/ExportPackageMojo.java index 1d4f0680..0cf86958 100644 --- a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/exportpackage/ExportPackageMojo.java +++ b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/exportpackage/ExportPackageMojo.java @@ -1,5 +1,17 @@ +/* + * Copyright (c) 2014-2024 Takari, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v10.html + */ package io.takari.maven.plugins.exportpackage; +import io.takari.incrementalbuild.Output; +import io.takari.incrementalbuild.aggregator.AggregatorBuildContext; +import io.takari.incrementalbuild.aggregator.InputSet; +import io.takari.incrementalbuild.aggregator.MetadataAggregator; +import io.takari.maven.plugins.TakariLifecycleMojo; import java.io.BufferedWriter; import java.io.File; import java.io.IOException; @@ -13,92 +25,86 @@ import java.util.Map; import java.util.Set; import java.util.TreeSet; - import javax.inject.Inject; - import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugins.annotations.LifecyclePhase; import org.apache.maven.plugins.annotations.Mojo; import org.apache.maven.plugins.annotations.Parameter; -import io.takari.incrementalbuild.Output; -import io.takari.incrementalbuild.aggregator.AggregatorBuildContext; -import io.takari.incrementalbuild.aggregator.InputSet; -import io.takari.incrementalbuild.aggregator.MetadataAggregator; -import io.takari.maven.plugins.TakariLifecycleMojo; - @Mojo(name = "export-package", defaultPhase = LifecyclePhase.PROCESS_CLASSES, threadSafe = true) public class ExportPackageMojo extends TakariLifecycleMojo { - public static final String PATH_EXPORT_PACKAGE = "META-INF/takari/export-package"; + public static final String PATH_EXPORT_PACKAGE = "META-INF/takari/export-package"; - public static final char EOL = '\n'; + public static final char EOL = '\n'; - @Parameter(defaultValue = "${project.build.outputDirectory}/" + PATH_EXPORT_PACKAGE) - private File outputFile; + @Parameter(defaultValue = "${project.build.outputDirectory}/" + PATH_EXPORT_PACKAGE) + private File outputFile; - @Parameter(defaultValue = "${project.build.outputDirectory}") - private File classesDirectory; + @Parameter(defaultValue = "${project.build.outputDirectory}") + private File classesDirectory; - @Parameter - private Set exportIncludes = Collections.emptySet(); + @Parameter + private Set exportIncludes = Collections.emptySet(); - @Parameter - private Set exportExcludes = Collections.unmodifiableSet(new LinkedHashSet<>(Arrays.asList("**/internal/**", "**/impl/**"))); + @Parameter + private Set exportExcludes = + Collections.unmodifiableSet(new LinkedHashSet<>(Arrays.asList("**/internal/**", "**/impl/**"))); - @Inject - private AggregatorBuildContext buildContext; + @Inject + private AggregatorBuildContext buildContext; - @Override - protected void executeMojo() throws MojoExecutionException { - try { - classesDirectory = classesDirectory.getCanonicalFile(); - generateOutput(); - } catch (IOException e) { - throw new MojoExecutionException("Could not generate export-package file", e); + @Override + protected void executeMojo() throws MojoExecutionException { + try { + classesDirectory = classesDirectory.getCanonicalFile(); + generateOutput(); + } catch (IOException e) { + throw new MojoExecutionException("Could not generate export-package file", e); + } } - } - private void generateOutput() throws IOException { - InputSet output = buildContext.newInputSet(); - output.addInputs(classesDirectory, getIncludes(), exportExcludes); - output.aggregateIfNecessary(outputFile, new MetadataAggregator() { - @Override - public Map glean(File input) { - return Collections.singletonMap(getPackageName(classesDirectory, input), null); - } + private void generateOutput() throws IOException { + InputSet output = buildContext.newInputSet(); + output.addInputs(classesDirectory, getIncludes(), exportExcludes); + output.aggregateIfNecessary(outputFile, new MetadataAggregator() { + @Override + public Map glean(File input) { + return Collections.singletonMap(getPackageName(classesDirectory, input), null); + } + + @Override + public void aggregate(Output output, Map metadata) throws IOException { + Set exportedPackages = new TreeSet<>(metadata.keySet()); + try (BufferedWriter w = + new BufferedWriter(new OutputStreamWriter(output.newOutputStream(), StandardCharsets.UTF_8))) { + for (String exportedPackage : exportedPackages) { + w.write(exportedPackage); + w.write(EOL); + } + } + } + }); + } - @Override - public void aggregate(Output output, Map metadata) throws IOException { - Set exportedPackages = new TreeSet<>(metadata.keySet()); - try (BufferedWriter w = new BufferedWriter(new OutputStreamWriter(output.newOutputStream(), StandardCharsets.UTF_8))) { - for (String exportedPackage : exportedPackages) { - w.write(exportedPackage); - w.write(EOL); - } + private Collection getIncludes() { + if (exportIncludes.isEmpty()) { + return Collections.singleton("**/*.class"); } - } - }); - } - - private Collection getIncludes() { - if (exportIncludes.isEmpty()) { - return Collections.singleton("**/*.class"); - } - Set includes = new HashSet<>(); - for (String include : this.exportIncludes) { - include = include.replace('\\', '/'); - if (!include.endsWith("/")) { - include = include + "/"; - } - include = include + "*.class"; + Set includes = new HashSet<>(); + for (String include : this.exportIncludes) { + include = include.replace('\\', '/'); + if (!include.endsWith("/")) { + include = include + "/"; + } + include = include + "*.class"; + } + return includes; } - return includes; - } - - static String getPackageName(File basedir, File file) { - String relpath = basedir.toPath().relativize(file.getParentFile().toPath()).toString(); - return relpath.replace('\\', '/').replace('/', '.'); - } + static String getPackageName(File basedir, File file) { + String relpath = + basedir.toPath().relativize(file.getParentFile().toPath()).toString(); + return relpath.replace('\\', '/').replace('/', '.'); + } } diff --git a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/install_deploy/DeployParticipant.java b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/install_deploy/DeployParticipant.java index f90b63e9..5b04f3b3 100644 --- a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/install_deploy/DeployParticipant.java +++ b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/install_deploy/DeployParticipant.java @@ -1,3 +1,10 @@ +/* + * Copyright (c) 2014-2024 Takari, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v10.html + */ package io.takari.maven.plugins.install_deploy; import java.io.IOException; @@ -7,11 +14,9 @@ import java.util.HashMap; import java.util.List; import java.util.Properties; - import javax.inject.Inject; import javax.inject.Named; import javax.inject.Singleton; - import org.apache.maven.AbstractMavenLifecycleParticipant; import org.apache.maven.Maven; import org.apache.maven.MavenExecutionException; @@ -29,92 +34,92 @@ @Singleton public class DeployParticipant extends AbstractMavenLifecycleParticipant { - private static final Logger log = LoggerFactory.getLogger(AbstractMavenLifecycleParticipant.class); + private static final Logger log = LoggerFactory.getLogger(AbstractMavenLifecycleParticipant.class); - protected RepositorySystem repoSystem; - private final List deployAtEndRequests = Collections.synchronizedList(new ArrayList<>()); + protected RepositorySystem repoSystem; + private final List deployAtEndRequests = Collections.synchronizedList(new ArrayList<>()); - @Inject - public DeployParticipant(RepositorySystem repoSystem) { - this.repoSystem = repoSystem; - } - - @Override - public void afterSessionEnd(MavenSession session) throws MavenExecutionException { - boolean errors = !session.getResult().getExceptions().isEmpty(); + @Inject + public DeployParticipant(RepositorySystem repoSystem) { + this.repoSystem = repoSystem; + } - if (!deployAtEndRequests.isEmpty()) { + @Override + public void afterSessionEnd(MavenSession session) throws MavenExecutionException { + boolean errors = !session.getResult().getExceptions().isEmpty(); - log.info(""); - log.info("------------------------------------------------------------------------"); + if (!deployAtEndRequests.isEmpty()) { - if (errors) { - log.info("-- Not performing deploy at end due to errors --"); - } else { - log.info("-- Performing deploy at end --"); - log.info("------------------------------------------------------------------------"); + log.info(""); + log.info("------------------------------------------------------------------------"); - synchronized (deployAtEndRequests) { - HashMap batched = new HashMap<>(); - for (DeployRequest deployRequest : deployAtEndRequests) { - if (!batched.containsKey(deployRequest.getRepository())) { - batched.put(deployRequest.getRepository(), deployRequest); + if (errors) { + log.info("-- Not performing deploy at end due to errors --"); } else { - DeployRequest dr = batched.get(deployRequest.getRepository()); - deployRequest.getArtifacts().forEach(dr::addArtifact); - deployRequest.getMetadata().forEach(dr::addMetadata); + log.info("-- Performing deploy at end --"); + log.info("------------------------------------------------------------------------"); + + synchronized (deployAtEndRequests) { + HashMap batched = new HashMap<>(); + for (DeployRequest deployRequest : deployAtEndRequests) { + if (!batched.containsKey(deployRequest.getRepository())) { + batched.put(deployRequest.getRepository(), deployRequest); + } else { + DeployRequest dr = batched.get(deployRequest.getRepository()); + deployRequest.getArtifacts().forEach(dr::addArtifact); + deployRequest.getMetadata().forEach(dr::addMetadata); + } + } + try { + for (DeployRequest dr : batched.values()) { + deploy(session.getRepositorySession(), dr); + } + } catch (DeploymentException e) { + log.error(e.getMessage(), e); + throw new MavenExecutionException(e.getMessage(), e); + } + deployAtEndRequests.clear(); + } } - } - try { - for (DeployRequest dr : batched.values()) { - deploy(session.getRepositorySession(), dr); - } - } catch (DeploymentException e) { - log.error(e.getMessage(), e); - throw new MavenExecutionException(e.getMessage(), e); - } - deployAtEndRequests.clear(); + + log.info("------------------------------------------------------------------------"); } - } + } - log.info("------------------------------------------------------------------------"); + List getDeployAtEndRequests() { + return Collections.unmodifiableList(deployAtEndRequests); } - } - - List getDeployAtEndRequests() { - return Collections.unmodifiableList(deployAtEndRequests); - } - - public void deploy(RepositorySystemSession session, DeployRequest deployRequest) throws DeploymentException { - repoSystem.deploy(session, deployRequest); - } - - public void deployAtEnd(DeployRequest deployRequest) { - checkSupport(); - deployAtEndRequests.add(deployRequest); - } - - private void checkSupport() { - Properties properties = new Properties(); - - try (InputStream in = Maven.class.getResourceAsStream("/META-INF/maven/org.apache.maven/maven-core/pom.properties")) { - if (in != null) { - properties.load(in); - } - } catch (IOException e) { - log.error("Unable determine maven version, deploy at end might fail", e); - return; + + public void deploy(RepositorySystemSession session, DeployRequest deployRequest) throws DeploymentException { + repoSystem.deploy(session, deployRequest); } - String mavenVersion = properties.getProperty("version"); - if (mavenVersion != null) { - int c = new DefaultArtifactVersion(mavenVersion).compareTo(new DefaultArtifactVersion("3.3.1")); - if (c < 0) { - throw new IllegalStateException("Deploy-at-end is not supported on maven versions <3.3.1"); - } - } else { - log.error("Unable determine maven version, deploy at end might fail"); + public void deployAtEnd(DeployRequest deployRequest) { + checkSupport(); + deployAtEndRequests.add(deployRequest); } - } + private void checkSupport() { + Properties properties = new Properties(); + + try (InputStream in = + Maven.class.getResourceAsStream("/META-INF/maven/org.apache.maven/maven-core/pom.properties")) { + if (in != null) { + properties.load(in); + } + } catch (IOException e) { + log.error("Unable determine maven version, deploy at end might fail", e); + return; + } + + String mavenVersion = properties.getProperty("version"); + if (mavenVersion != null) { + int c = new DefaultArtifactVersion(mavenVersion).compareTo(new DefaultArtifactVersion("3.3.1")); + if (c < 0) { + throw new IllegalStateException("Deploy-at-end is not supported on maven versions <3.3.1"); + } + } else { + log.error("Unable determine maven version, deploy at end might fail"); + } + } } diff --git a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/jar/AggregateSource.java b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/jar/AggregateSource.java index 75c0a3cc..628d8186 100644 --- a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/jar/AggregateSource.java +++ b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/jar/AggregateSource.java @@ -1,15 +1,14 @@ -/** - * Copyright (c) 2014 Takari, Inc. +/* + * Copyright (c) 2014-2024 Takari, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * https://www.eclipse.org/legal/epl-v10.html */ package io.takari.maven.plugins.jar; import ca.vanzyl.provisio.archive.ExtendedArchiveEntry; import ca.vanzyl.provisio.archive.Source; - import java.io.IOException; import java.util.HashSet; import java.util.List; @@ -18,7 +17,6 @@ import java.util.stream.Collectors; import java.util.stream.StreamSupport; - /** * Archive source that wraps provided archive entries. *

@@ -26,33 +24,33 @@ */ class AggregateSource implements Source { - private final List> sources; - - public AggregateSource(List> sources) { - this.sources = sources; - } - - @Override - public Iterable entries() { - final Predicate uniquePathFilter = new Predicate() { - private final Set entryNames = new HashSet<>(); - - @Override - public boolean test(ExtendedArchiveEntry input) { - return entryNames.add(input.getName()); - } - }; - return sources.stream() - .flatMap(e -> StreamSupport.stream(e.spliterator(), false)) - .filter(uniquePathFilter) - .collect(Collectors.toList()); - } - - @Override - public boolean isDirectory() { - return false; - } - - @Override - public void close() throws IOException {} + private final List> sources; + + public AggregateSource(List> sources) { + this.sources = sources; + } + + @Override + public Iterable entries() { + final Predicate uniquePathFilter = new Predicate() { + private final Set entryNames = new HashSet<>(); + + @Override + public boolean test(ExtendedArchiveEntry input) { + return entryNames.add(input.getName()); + } + }; + return sources.stream() + .flatMap(e -> StreamSupport.stream(e.spliterator(), false)) + .filter(uniquePathFilter) + .collect(Collectors.toList()); + } + + @Override + public boolean isDirectory() { + return false; + } + + @Override + public void close() throws IOException {} } diff --git a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/jar/ArchiveConfiguration.java b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/jar/ArchiveConfiguration.java index d3517afc..4fae0506 100644 --- a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/jar/ArchiveConfiguration.java +++ b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/jar/ArchiveConfiguration.java @@ -1,9 +1,9 @@ -/** - * Copyright (c) 2014 Takari, Inc. +/* + * Copyright (c) 2014-2024 Takari, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * https://www.eclipse.org/legal/epl-v10.html */ package io.takari.maven.plugins.jar; @@ -12,29 +12,28 @@ import java.util.Map; public class ArchiveConfiguration { - // see http://maven.apache.org/shared/maven-archiver/index.html + // see http://maven.apache.org/shared/maven-archiver/index.html - private File manifestFile; - private Map manifestEntries = new LinkedHashMap<>(); + private File manifestFile; + private Map manifestEntries = new LinkedHashMap<>(); - public File getManifestFile() { - return manifestFile; - } + public File getManifestFile() { + return manifestFile; + } - public void addManifestEntry(String key, String value) { - manifestEntries.put(key, value); - } + public void addManifestEntry(String key, String value) { + manifestEntries.put(key, value); + } - public void addManifestEntries(Map map) { - manifestEntries.putAll(map); - } + public void addManifestEntries(Map map) { + manifestEntries.putAll(map); + } - public Map getManifestEntries() { - return manifestEntries; - } - - public void setManifestEntries(Map manifestEntries) { - this.manifestEntries = manifestEntries; - } + public Map getManifestEntries() { + return manifestEntries; + } + public void setManifestEntries(Map manifestEntries) { + this.manifestEntries = manifestEntries; + } } diff --git a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/jar/BytesEntry.java b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/jar/BytesEntry.java index 151c473c..c0634abf 100644 --- a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/jar/BytesEntry.java +++ b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/jar/BytesEntry.java @@ -1,113 +1,99 @@ -/** - * Copyright (c) 2014 Takari, Inc. +/* + * Copyright (c) 2014-2024 Takari, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * https://www.eclipse.org/legal/epl-v10.html */ package io.takari.maven.plugins.jar; +import ca.vanzyl.provisio.archive.ExtendedArchiveEntry; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.Date; -import ca.vanzyl.provisio.archive.ExtendedArchiveEntry; - class BytesEntry implements ExtendedArchiveEntry { - private final String entryName; - private final byte[] contents; - - public BytesEntry(String entryName, byte[] contents) { - this.entryName = entryName; - this.contents = contents; - } - - @Override - public String getName() { - return entryName; - } - - @Override - public InputStream getInputStream() throws IOException { - return new ByteArrayInputStream(contents); - } - - @Override - public long getSize() { - return contents.length; - } - - @Override - public void writeEntry(OutputStream outputStream) throws IOException { - outputStream.write(contents); - } - - @Override - public int getFileMode() { - return -1; - } - - @Override - public boolean isDirectory() { - return false; - } - - @Override - public boolean isExecutable() { - return false; - } - - @Override - public long getTime() { - return -1; - } - - @Override - public void setFileMode( int i ) - { - } - - @Override - public void setSize( long l ) - { - - } - - @Override - public void setTime( long l ) - { - - } - - @Override - public boolean isSymbolicLink() - { - return false; - } - - @Override - public String getSymbolicLinkPath() - { - return null; - } - - @Override - public boolean isHardLink() - { - return false; - } - - @Override - public String getHardLinkPath() - { - return null; - } - - @Override - public Date getLastModifiedDate() - { - return null; - } + private final String entryName; + private final byte[] contents; + + public BytesEntry(String entryName, byte[] contents) { + this.entryName = entryName; + this.contents = contents; + } + + @Override + public String getName() { + return entryName; + } + + @Override + public InputStream getInputStream() throws IOException { + return new ByteArrayInputStream(contents); + } + + @Override + public long getSize() { + return contents.length; + } + + @Override + public void writeEntry(OutputStream outputStream) throws IOException { + outputStream.write(contents); + } + + @Override + public int getFileMode() { + return -1; + } + + @Override + public boolean isDirectory() { + return false; + } + + @Override + public boolean isExecutable() { + return false; + } + + @Override + public long getTime() { + return -1; + } + + @Override + public void setFileMode(int i) {} + + @Override + public void setSize(long l) {} + + @Override + public void setTime(long l) {} + + @Override + public boolean isSymbolicLink() { + return false; + } + + @Override + public String getSymbolicLinkPath() { + return null; + } + + @Override + public boolean isHardLink() { + return false; + } + + @Override + public String getHardLinkPath() { + return null; + } + + @Override + public Date getLastModifiedDate() { + return null; + } } diff --git a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/jar/Jar.java b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/jar/Jar.java index 66688fca..75fe9cb0 100644 --- a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/jar/Jar.java +++ b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/jar/Jar.java @@ -1,16 +1,25 @@ -/** - * Copyright (c) 2014 Takari, Inc. +/* + * Copyright (c) 2014-2024 Takari, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * https://www.eclipse.org/legal/epl-v10.html */ package io.takari.maven.plugins.jar; +import static io.takari.maven.plugins.TakariLifecycles.isJarProducingTakariLifecycle; import static java.util.Arrays.asList; import static java.util.Collections.singleton; -import static io.takari.maven.plugins.TakariLifecycles.isJarProducingTakariLifecycle; +import ca.vanzyl.provisio.archive.Archiver; +import ca.vanzyl.provisio.archive.ExtendedArchiveEntry; +import ca.vanzyl.provisio.archive.source.FileEntry; +import io.takari.incrementalbuild.Output; +import io.takari.incrementalbuild.aggregator.AggregatorBuildContext; +import io.takari.incrementalbuild.aggregator.InputAggregator; +import io.takari.incrementalbuild.aggregator.InputSet; +import io.takari.maven.plugins.TakariLifecycleMojo; +import io.takari.maven.plugins.util.PropertiesWriter; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; @@ -24,264 +33,264 @@ import java.util.jar.Manifest; import java.util.stream.Collectors; import java.util.stream.StreamSupport; - import javax.inject.Inject; - import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugins.annotations.LifecyclePhase; import org.apache.maven.plugins.annotations.Mojo; import org.apache.maven.plugins.annotations.Parameter; import org.apache.maven.project.MavenProject; -import io.takari.incrementalbuild.Output; -import io.takari.incrementalbuild.aggregator.AggregatorBuildContext; -import io.takari.incrementalbuild.aggregator.InputAggregator; -import io.takari.incrementalbuild.aggregator.InputSet; -import io.takari.maven.plugins.TakariLifecycleMojo; -import io.takari.maven.plugins.util.PropertiesWriter; -import ca.vanzyl.provisio.archive.Archiver; -import ca.vanzyl.provisio.archive.ExtendedArchiveEntry; -import ca.vanzyl.provisio.archive.source.FileEntry; - @Mojo(name = "jar", defaultPhase = LifecyclePhase.PACKAGE, configurator = "takari", threadSafe = true) public class Jar extends TakariLifecycleMojo { - @Parameter(defaultValue = "${project.build.outputDirectory}") - protected File classesDirectory; + @Parameter(defaultValue = "${project.build.outputDirectory}") + protected File classesDirectory; - @Parameter(defaultValue = "${project.build.finalName}") - private String finalName; + @Parameter(defaultValue = "${project.build.finalName}") + private String finalName; - @Parameter(defaultValue = "${project.build.directory}") - private File outputDirectory; + @Parameter(defaultValue = "${project.build.directory}") + private File outputDirectory; - @Parameter(defaultValue = "true", property = "mainJar") - private boolean mainJar; + @Parameter(defaultValue = "true", property = "mainJar") + private boolean mainJar; - @Parameter(defaultValue = "false", property = "sourceJar") - private boolean sourceJar; + @Parameter(defaultValue = "false", property = "sourceJar") + private boolean sourceJar; - @Parameter(defaultValue = "false", property = "testJar") - private boolean testJar; + @Parameter(defaultValue = "false", property = "testJar") + private boolean testJar; - @Parameter(defaultValue = "${project.build.testOutputDirectory}") - private File testClassesDirectory; + @Parameter(defaultValue = "${project.build.testOutputDirectory}") + private File testClassesDirectory; - @Parameter - private ArchiveConfiguration archive; + @Parameter + private ArchiveConfiguration archive; - @Inject - private AggregatorBuildContext buildContext; + @Inject + private AggregatorBuildContext buildContext; - private static final String MANIFEST_PATH = "META-INF/MANIFEST.MF"; + private static final String MANIFEST_PATH = "META-INF/MANIFEST.MF"; - @Override - protected void executeMojo() throws MojoExecutionException { + @Override + protected void executeMojo() throws MojoExecutionException { - if (!outputDirectory.exists()) { - outputDirectory.mkdir(); - } - - if (mainJar) { - File jar = new File(outputDirectory, String.format("%s.jar", finalName)); - InputSet registeredOutput = buildContext.newInputSet(); - try { - if (classesDirectory.isDirectory()) { - classesDirectory = classesDirectory.getCanonicalFile(); - Iterable inputs = registeredOutput.addInputs(classesDirectory, null, null); - logger.debug("Analyzing main classes directory {} with {} entries", classesDirectory, size(inputs)); - } else { - logger.warn("Main classes directory {} does not exist", classesDirectory); + if (!outputDirectory.exists()) { + outputDirectory.mkdir(); } - // XXX this does not detect changes in archive#manifestFile. - boolean processingRequired = registeredOutput.aggregateIfNecessary(jar, new InputAggregator() { - @Override - public void aggregate(Output output, Iterable inputs) throws IOException { - logger.info("Building main JAR."); - - List> sources = new ArrayList<>(); - if (archive != null && archive.getManifestFile() != null) { - sources.add(jarManifestSource(archive.getManifestFile())); + + if (mainJar) { + File jar = new File(outputDirectory, String.format("%s.jar", finalName)); + InputSet registeredOutput = buildContext.newInputSet(); + try { + if (classesDirectory.isDirectory()) { + classesDirectory = classesDirectory.getCanonicalFile(); + Iterable inputs = registeredOutput.addInputs(classesDirectory, null, null); + logger.debug("Analyzing main classes directory {} with {} entries", classesDirectory, size(inputs)); + } else { + logger.warn("Main classes directory {} does not exist", classesDirectory); + } + // XXX this does not detect changes in archive#manifestFile. + boolean processingRequired = registeredOutput.aggregateIfNecessary(jar, new InputAggregator() { + @Override + public void aggregate(Output output, Iterable inputs) throws IOException { + logger.info("Building main JAR."); + + List> sources = new ArrayList<>(); + if (archive != null && archive.getManifestFile() != null) { + sources.add(jarManifestSource(archive.getManifestFile())); + } + sources.add(inputsSource(classesDirectory, inputs)); + sources.add(singleton(pomPropertiesSource(project))); + sources.add(jarManifestSource(project)); + archive(output.getResource(), sources); + } + }); + if (!processingRequired) { + logger.info("Main JAR is up-to-date"); + } + + if (!isJarProducingTakariLifecycle(project.getPackaging()) + && alternateLifecycleProvidingPrimaryArtifact()) { + // We have a non-Takari lifecycle and a property in the MavenSession has been explicity set to + // indicate the lifecycle + // executing will produce the primary artifact. + projectHelper.attachArtifact(project, "jar", jar); + logger.info( + "The '{}' lifecycle has indicated it will produce the primary artifact. Attaching JAR as a secondary artifact.", + project.getPackaging()); + } else { + // We have a standard Takari lifecycle so set the JAR created here as the primary artifact. + project.getArtifact().setFile(jar); + } + } catch (IOException e) { + throw new MojoExecutionException(e.getMessage(), e); } - sources.add(inputsSource(classesDirectory, inputs)); - sources.add(singleton(pomPropertiesSource(project))); - sources.add(jarManifestSource(project)); - archive(output.getResource(), sources); - } - }); - if (!processingRequired) { - logger.info("Main JAR is up-to-date"); } - if (!isJarProducingTakariLifecycle(project.getPackaging()) && alternateLifecycleProvidingPrimaryArtifact()) { - // We have a non-Takari lifecycle and a property in the MavenSession has been explicity set to indicate the lifecycle - // executing will produce the primary artifact. - projectHelper.attachArtifact(project, "jar", jar); - logger.info("The '{}' lifecycle has indicated it will produce the primary artifact. Attaching JAR as a secondary artifact.", project.getPackaging()); - } else { - // We have a standard Takari lifecycle so set the JAR created here as the primary artifact. - project.getArtifact().setFile(jar); + if (sourceJar) { + final Map> sources = new LinkedHashMap<>(); + File sourceJar = new File(outputDirectory, String.format("%s-%s.jar", finalName, "sources")); + InputSet registeredOutput = buildContext.newInputSet(); + try { + for (String sourceRoot : project.getCompileSourceRoots()) { + File dir = new File(sourceRoot); + if (dir.isDirectory()) { + dir = dir.getCanonicalFile(); + List inputs = StreamSupport.stream( + registeredOutput + .addInputs(dir, null, null) + .spliterator(), + false) + .collect(Collectors.toList()); + logger.debug("Analyzing sources directory {} with {} entries", dir, inputs.size()); + sources.computeIfAbsent(dir, k -> new ArrayList<>()).addAll(inputs); + } else { + logger.debug("Sources directory {} does not exist", dir); + } + } + boolean processingRequired = registeredOutput.aggregateIfNecessary(sourceJar, new InputAggregator() { + @Override + public void aggregate(Output output, Iterable inputs) throws IOException { + logger.info("Building source JAR."); + + archive(output.getResource(), asList(inputsSource(sources), jarManifestSource(project))); + } + }); + if (!processingRequired) { + logger.info("Source JAR is up-to-date"); + } + projectHelper.attachArtifact(project, "jar", "sources", sourceJar); + } catch (IOException e) { + throw new MojoExecutionException(e.getMessage(), e); + } } - } catch (IOException e) { - throw new MojoExecutionException(e.getMessage(), e); - } - } - if (sourceJar) { - final Map> sources = new LinkedHashMap<>(); - File sourceJar = new File(outputDirectory, String.format("%s-%s.jar", finalName, "sources")); - InputSet registeredOutput = buildContext.newInputSet(); - try { - for (String sourceRoot : project.getCompileSourceRoots()) { - File dir = new File(sourceRoot); - if (dir.isDirectory()) { - dir = dir.getCanonicalFile(); - List inputs = StreamSupport - .stream( registeredOutput.addInputs(dir, null, null).spliterator(), false) - .collect(Collectors.toList()); - logger.debug("Analyzing sources directory {} with {} entries", dir, inputs.size()); - sources.computeIfAbsent(dir, k -> new ArrayList<>()).addAll(inputs); - } else { - logger.debug("Sources directory {} does not exist", dir); - } - } - boolean processingRequired = registeredOutput.aggregateIfNecessary(sourceJar, new InputAggregator() { - @Override - public void aggregate(Output output, Iterable inputs) throws IOException { - logger.info("Building source JAR."); - - archive(output.getResource(), asList(inputsSource(sources), jarManifestSource(project))); - } - }); - if (!processingRequired) { - logger.info("Source JAR is up-to-date"); + if (testJar && testClassesDirectory.isDirectory()) { + File testJar = new File(outputDirectory, String.format("%s-%s.jar", finalName, "tests")); + InputSet registeredOutput = buildContext.newInputSet(); + try { + testClassesDirectory = testClassesDirectory.getCanonicalFile(); + Iterable inputs = registeredOutput.addInputs(testClassesDirectory, null, null); + logger.debug("Analyzing test classes directory {} with {} entries", testClassesDirectory, size(inputs)); + boolean processingRequired = registeredOutput.aggregateIfNecessary(testJar, new InputAggregator() { + @Override + public void aggregate(Output output, Iterable inputs) throws IOException { + logger.info("Building test JAR."); + + archive( + output.getResource(), + asList(inputsSource(testClassesDirectory, inputs), jarManifestSource(project))); + } + }); + if (!processingRequired) { + logger.info("Test JAR is up-to-date"); + } + } catch (IOException e) { + throw new MojoExecutionException(e.getMessage(), e); + } + projectHelper.attachArtifact(project, "jar", "tests", testJar); } - projectHelper.attachArtifact(project, "jar", "sources", sourceJar); - } catch (IOException e) { - throw new MojoExecutionException(e.getMessage(), e); - } } - if (testJar && testClassesDirectory.isDirectory()) { - File testJar = new File(outputDirectory, String.format("%s-%s.jar", finalName, "tests")); - InputSet registeredOutput = buildContext.newInputSet(); - try { - testClassesDirectory = testClassesDirectory.getCanonicalFile(); - Iterable inputs = registeredOutput.addInputs(testClassesDirectory, null, null); - logger.debug("Analyzing test classes directory {} with {} entries", testClassesDirectory, size(inputs)); - boolean processingRequired = registeredOutput.aggregateIfNecessary(testJar, new InputAggregator() { - @Override - public void aggregate(Output output, Iterable inputs) throws IOException { - logger.info("Building test JAR."); - - archive(output.getResource(), asList(inputsSource(testClassesDirectory, inputs), jarManifestSource(project))); - } - }); - if (!processingRequired) { - logger.info("Test JAR is up-to-date"); + private void archive(File jar, List> sources) throws IOException { + Archiver archiver = Archiver.builder() // + .useRoot(false) // + .normalize(true) // + .build(); + archiver.archive(jar, new AggregateSource(sources)); + if (logger.isDebugEnabled()) { + int size = 0; + for (Iterable source : sources) { + size += size(source); + } + logger.debug("Created archive {} with {} entries", jar, size); } - } catch (IOException e) { - throw new MojoExecutionException(e.getMessage(), e); - } - projectHelper.attachArtifact(project, "jar", "tests", testJar); - } - } - - private void archive(File jar, List> sources) throws IOException { - Archiver archiver = Archiver.builder() // - .useRoot(false) // - .normalize(true) // - .build(); - archiver.archive(jar, new AggregateSource(sources)); - if (logger.isDebugEnabled()) { - int size = 0; - for (Iterable source : sources) { - size += size(source); - } - logger.debug("Created archive {} with {} entries", jar, size); } - } - static String getRelativePath(File basedir, File resource) { - return basedir.toPath().relativize(resource.toPath()).toString().replace('\\', '/'); // always use forward slash for path separator - } - - private List inputsSource(Map> inputs) { - final List entries = new ArrayList<>(); - for (File basedir : inputs.keySet()) { - entries.addAll(inputsSource(basedir, inputs.get(basedir))); + static String getRelativePath(File basedir, File resource) { + return basedir.toPath() + .relativize(resource.toPath()) + .toString() + .replace('\\', '/'); // always use forward slash for path separator } - return entries; - } - - private List inputsSource(File basedir, Iterable inputs) { - final List entries = new ArrayList<>(); - for (File input : inputs) { - String entryName = getRelativePath(basedir, input); - entries.add(new FileEntry(entryName, input)); + + private List inputsSource(Map> inputs) { + final List entries = new ArrayList<>(); + for (File basedir : inputs.keySet()) { + entries.addAll(inputsSource(basedir, inputs.get(basedir))); + } + return entries; } - return entries; - } - - public static Iterable jarManifestSource(File file) { - return singleton((ExtendedArchiveEntry) new FileEntry(MANIFEST_PATH, file)); - } - - private Iterable jarManifestSource(MavenProject project) throws IOException { - Manifest manifest = new Manifest(); - Attributes main = manifest.getMainAttributes(); - main.putValue("Manifest-Version", "1.0"); - main.putValue("Archiver-Version", "Provisio Archiver"); - main.putValue("Created-By", "Takari Inc."); - main.putValue("Built-By", System.getProperty("user.name")); - main.putValue("Build-Jdk", System.getProperty("java.version")); - main.putValue("Specification-Title", project.getArtifactId()); - main.putValue("Specification-Version", project.getVersion()); - main.putValue("Implementation-Title", project.getArtifactId()); - main.putValue("Implementation-Version", project.getVersion()); - main.putValue("Implementation-Vendor-Id", project.getGroupId()); - - if (archive != null && archive.getManifestEntries() != null) { - for (Map.Entry extra : archive.getManifestEntries().entrySet()) { - if (extra.getValue() != null) { - main.putValue(extra.getKey(), extra.getValue()); + + private List inputsSource(File basedir, Iterable inputs) { + final List entries = new ArrayList<>(); + for (File input : inputs) { + String entryName = getRelativePath(basedir, input); + entries.add(new FileEntry(entryName, input)); } - } + return entries; } - File manifestFile = new File(project.getBuild().getDirectory(), "MANIFEST.MF"); - if (!manifestFile.getParentFile().exists()) { - manifestFile.getParentFile().mkdirs(); + public static Iterable jarManifestSource(File file) { + return singleton((ExtendedArchiveEntry) new FileEntry(MANIFEST_PATH, file)); } - ByteArrayOutputStream buf = new ByteArrayOutputStream(); - manifest.write(buf); + private Iterable jarManifestSource(MavenProject project) throws IOException { + Manifest manifest = new Manifest(); + Attributes main = manifest.getMainAttributes(); + main.putValue("Manifest-Version", "1.0"); + main.putValue("Archiver-Version", "Provisio Archiver"); + main.putValue("Created-By", "Takari Inc."); + main.putValue("Built-By", System.getProperty("user.name")); + main.putValue("Build-Jdk", System.getProperty("java.version")); + main.putValue("Specification-Title", project.getArtifactId()); + main.putValue("Specification-Version", project.getVersion()); + main.putValue("Implementation-Title", project.getArtifactId()); + main.putValue("Implementation-Version", project.getVersion()); + main.putValue("Implementation-Vendor-Id", project.getGroupId()); + + if (archive != null && archive.getManifestEntries() != null) { + for (Map.Entry extra : archive.getManifestEntries().entrySet()) { + if (extra.getValue() != null) { + main.putValue(extra.getKey(), extra.getValue()); + } + } + } - return singleton((ExtendedArchiveEntry) new BytesEntry(MANIFEST_PATH, buf.toByteArray())); - } + File manifestFile = new File(project.getBuild().getDirectory(), "MANIFEST.MF"); + if (!manifestFile.getParentFile().exists()) { + manifestFile.getParentFile().mkdirs(); + } - protected ExtendedArchiveEntry pomPropertiesSource(MavenProject project) throws IOException { - String entryName = String.format("META-INF/maven/%s/%s/pom.properties", project.getGroupId(), project.getArtifactId()); + ByteArrayOutputStream buf = new ByteArrayOutputStream(); + manifest.write(buf); - ByteArrayOutputStream buf = new ByteArrayOutputStream(); - Properties properties = new Properties(); - properties.setProperty("groupId", project.getGroupId()); - properties.setProperty("artifactId", project.getArtifactId()); - properties.setProperty("version", project.getVersion()); - PropertiesWriter.write(properties, null, buf); + return singleton((ExtendedArchiveEntry) new BytesEntry(MANIFEST_PATH, buf.toByteArray())); + } - return new BytesEntry(entryName, buf.toByteArray()); - } + protected ExtendedArchiveEntry pomPropertiesSource(MavenProject project) throws IOException { + String entryName = + String.format("META-INF/maven/%s/%s/pom.properties", project.getGroupId(), project.getArtifactId()); - private static int size(final Iterable iterable) { - if (iterable instanceof Collection ) { - return ( (Collection) iterable ).size(); - } - int size = 0; - for (Object o : iterable) { - size++; + ByteArrayOutputStream buf = new ByteArrayOutputStream(); + Properties properties = new Properties(); + properties.setProperty("groupId", project.getGroupId()); + properties.setProperty("artifactId", project.getArtifactId()); + properties.setProperty("version", project.getVersion()); + PropertiesWriter.write(properties, null, buf); + + return new BytesEntry(entryName, buf.toByteArray()); } - return size; - } + private static int size(final Iterable iterable) { + if (iterable instanceof Collection) { + return ((Collection) iterable).size(); + } + int size = 0; + for (Object o : iterable) { + size++; + } + return size; + } } diff --git a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/jar/PomPropertiesMojo.java b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/jar/PomPropertiesMojo.java index edeee4ac..a53a63ea 100644 --- a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/jar/PomPropertiesMojo.java +++ b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/jar/PomPropertiesMojo.java @@ -1,23 +1,21 @@ -/** - * Copyright (c) 2015 Takari, Inc. +/* + * Copyright (c) 2014-2024 Takari, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * https://www.eclipse.org/legal/epl-v10.html */ package io.takari.maven.plugins.jar; +import ca.vanzyl.provisio.archive.ExtendedArchiveEntry; +import io.takari.incrementalbuild.BasicBuildContext; import java.io.File; import java.io.IOException; import java.io.OutputStream; - import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugins.annotations.Component; import org.apache.maven.plugins.annotations.Mojo; -import io.takari.incrementalbuild.BasicBuildContext; -import ca.vanzyl.provisio.archive.ExtendedArchiveEntry; - /** * Creates standard maven pom.properties file on filesystem. *

@@ -26,19 +24,19 @@ @Mojo(name = "pom-properties", threadSafe = true) public class PomPropertiesMojo extends Jar { - @Component - private BasicBuildContext context; + @Component + private BasicBuildContext context; - @Override - public void executeMojo() throws MojoExecutionException { - try { - ExtendedArchiveEntry entry = pomPropertiesSource(project); - try (OutputStream os = context.processOutput(new File(classesDirectory, entry.getName())).newOutputStream()) { - entry.writeEntry(os); - } - } catch (IOException e) { - throw new MojoExecutionException("Could not create Maven pom.properties file", e); + @Override + public void executeMojo() throws MojoExecutionException { + try { + ExtendedArchiveEntry entry = pomPropertiesSource(project); + try (OutputStream os = context.processOutput(new File(classesDirectory, entry.getName())) + .newOutputStream()) { + entry.writeEntry(os); + } + } catch (IOException e) { + throw new MojoExecutionException("Could not create Maven pom.properties file", e); + } } - } - } diff --git a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/pgp/SignArtifactMojo.java b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/pgp/SignArtifactMojo.java index f9fb6f9d..808ed046 100644 --- a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/pgp/SignArtifactMojo.java +++ b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/pgp/SignArtifactMojo.java @@ -1,3 +1,10 @@ +/* + * Copyright (c) 2014-2024 Takari, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v10.html + */ package io.takari.maven.plugins.pgp; import static java.nio.file.Files.copy; @@ -22,67 +29,75 @@ @Mojo(name = "signArtifact", configurator = "takari", defaultPhase = LifecyclePhase.VERIFY, threadSafe = true) public class SignArtifactMojo extends TakariLifecycleMojo { - public static final String PGP_SIGNATURE_EXTENSION = ".asc"; - private final Logger logger = LoggerFactory.getLogger(SignArtifactMojo.class); + public static final String PGP_SIGNATURE_EXTENSION = ".asc"; + private final Logger logger = LoggerFactory.getLogger(SignArtifactMojo.class); - @Parameter(property = "gpg.skip", defaultValue = "false") - private boolean skip; + @Parameter(property = "gpg.skip", defaultValue = "false") + private boolean skip; - @Parameter(property = "gpg.passphrase") - private String passphrase; + @Parameter(property = "gpg.passphrase") + private String passphrase; - @Override - protected void executeMojo() throws MojoExecutionException { + @Override + protected void executeMojo() throws MojoExecutionException { - if (skip) { - logger.info("Skipping PGP signature generation as per configuration."); - return; - } + if (skip) { + logger.info("Skipping PGP signature generation as per configuration."); + return; + } - List mavenFilesToSign = new ArrayList<>(); - if (!"pom".equals(project.getPackaging())) { - // - // Primary artifact - // - org.apache.maven.artifact.Artifact artifact = project.getArtifact(); - File file = artifact.getFile(); - if (file == null) { - logger.info("There is no artifact present. Make sure you run this after the package phase."); - return; - } - mavenFilesToSign.add(new SignedFile(file.toPath(), artifact.getArtifactHandler().getExtension())); - } + List mavenFilesToSign = new ArrayList<>(); + if (!"pom".equals(project.getPackaging())) { + // + // Primary artifact + // + org.apache.maven.artifact.Artifact artifact = project.getArtifact(); + File file = artifact.getFile(); + if (file == null) { + logger.info("There is no artifact present. Make sure you run this after the package phase."); + return; + } + mavenFilesToSign.add( + new SignedFile(file.toPath(), artifact.getArtifactHandler().getExtension())); + } - // - // POM - // - File pomToSign = new File(project.getBuild().getDirectory(), project.getBuild().getFinalName() + ".pom"); - try { - createDirectories(pomToSign.getParentFile().toPath()); - copy(project.getFile().toPath(), pomToSign.toPath(), StandardCopyOption.REPLACE_EXISTING); - mavenFilesToSign.add(new SignedFile(pomToSign.toPath(), "pom")); - } catch (IOException e) { - throw new MojoExecutionException("Error copying POM for signing.", e); - } + // + // POM + // + File pomToSign = + new File(project.getBuild().getDirectory(), project.getBuild().getFinalName() + ".pom"); + try { + createDirectories(pomToSign.getParentFile().toPath()); + copy(project.getFile().toPath(), pomToSign.toPath(), StandardCopyOption.REPLACE_EXISTING); + mavenFilesToSign.add(new SignedFile(pomToSign.toPath(), "pom")); + } catch (IOException e) { + throw new MojoExecutionException("Error copying POM for signing.", e); + } - // - // Attached artifacts - // - for (org.apache.maven.artifact.Artifact a : project.getAttachedArtifacts()) { - mavenFilesToSign.add(new SignedFile(a.getFile().toPath(), a.getArtifactHandler().getExtension(), a.getClassifier())); - } + // + // Attached artifacts + // + for (org.apache.maven.artifact.Artifact a : project.getAttachedArtifacts()) { + mavenFilesToSign.add( + new SignedFile(a.getFile().toPath(), a.getArtifactHandler().getExtension(), a.getClassifier())); + } - logger.debug("Signing the following files with PGP:"); - mavenFilesToSign.forEach(s -> logger.debug(s.toString())); - PgpSigner pgpArtifactSigner = new PgpSigner(ImmutablePgpSigningRequest.builder().build()); - for (SignedFile pgpSignedFile : mavenFilesToSign) { - Path file = pgpSignedFile.file(); - try { - File pgpSignature = pgpArtifactSigner.sign(file.toFile()); - projectHelper.attachArtifact(project, pgpSignedFile.extension() + PGP_SIGNATURE_EXTENSION, pgpSignedFile.classifier(), pgpSignature); - } catch (Exception e) { - throw new MojoExecutionException("Error signing artifact " + file + ".", e); - } + logger.debug("Signing the following files with PGP:"); + mavenFilesToSign.forEach(s -> logger.debug(s.toString())); + PgpSigner pgpArtifactSigner = + new PgpSigner(ImmutablePgpSigningRequest.builder().build()); + for (SignedFile pgpSignedFile : mavenFilesToSign) { + Path file = pgpSignedFile.file(); + try { + File pgpSignature = pgpArtifactSigner.sign(file.toFile()); + projectHelper.attachArtifact( + project, + pgpSignedFile.extension() + PGP_SIGNATURE_EXTENSION, + pgpSignedFile.classifier(), + pgpSignature); + } catch (Exception e) { + throw new MojoExecutionException("Error signing artifact " + file + ".", e); + } + } } - } } diff --git a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/pgp/SignedFile.java b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/pgp/SignedFile.java index 8436e414..8074d472 100644 --- a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/pgp/SignedFile.java +++ b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/pgp/SignedFile.java @@ -1,3 +1,10 @@ +/* + * Copyright (c) 2014-2024 Takari, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v10.html + */ package io.takari.maven.plugins.pgp; // @@ -20,38 +27,37 @@ public class SignedFile { - private final Path file; - private final String extension; - private final String classifier; - - public SignedFile(Path file, String extension) { - this(file, extension, null); - } - - public SignedFile(Path file, String extension, String classifier) { - this.file = file; - this.extension = extension; - this.classifier = classifier; - } - - public Path file() { - return file; - } - - public String extension() { - return extension; - } - - public String classifier() { - return classifier; - } - - @Override - public String toString() { - return "SignedFile{" + - "file=" + file + - ", extension='" + extension + '\'' + - ", classifier='" + classifier + '\'' + - '}'; - } -} \ No newline at end of file + private final Path file; + private final String extension; + private final String classifier; + + public SignedFile(Path file, String extension) { + this(file, extension, null); + } + + public SignedFile(Path file, String extension, String classifier) { + this.file = file; + this.extension = extension; + this.classifier = classifier; + } + + public Path file() { + return file; + } + + public String extension() { + return extension; + } + + public String classifier() { + return classifier; + } + + @Override + public String toString() { + return "SignedFile{" + "file=" + + file + ", extension='" + + extension + '\'' + ", classifier='" + + classifier + '\'' + '}'; + } +} diff --git a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/plugin/AddPluginArtifactMetadataMojo.java b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/plugin/AddPluginArtifactMetadataMojo.java index 6acd6851..74279a2d 100644 --- a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/plugin/AddPluginArtifactMetadataMojo.java +++ b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/plugin/AddPluginArtifactMetadataMojo.java @@ -1,3 +1,10 @@ +/* + * Copyright (c) 2014-2024 Takari, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v10.html + */ package io.takari.maven.plugins.plugin; /* @@ -19,6 +26,7 @@ * under the License. */ +import io.takari.maven.plugins.TakariLifecycleMojo; import org.apache.maven.artifact.Artifact; import org.apache.maven.artifact.repository.metadata.ArtifactRepositoryMetadata; import org.apache.maven.artifact.repository.metadata.Versioning; @@ -28,8 +36,6 @@ import org.apache.maven.plugins.annotations.Mojo; import org.apache.maven.plugins.annotations.Parameter; -import io.takari.maven.plugins.TakariLifecycleMojo; - /** * Inject any plugin-specific artifact metadata to the project's artifact, for subsequent installation and deployment. It * is used: @@ -47,36 +53,36 @@ @Mojo(name = "addPluginArtifactMetadata", defaultPhase = LifecyclePhase.PACKAGE, threadSafe = true) public class AddPluginArtifactMetadataMojo extends TakariLifecycleMojo { - /** - * The prefix for the plugin goal. - */ - @Parameter - private String goalPrefix; - - @Override - protected void executeMojo() throws MojoExecutionException { - Artifact projectArtifact = project.getArtifact(); + /** + * The prefix for the plugin goal. + */ + @Parameter + private String goalPrefix; - Versioning versioning = new Versioning(); - versioning.setLatest(projectArtifact.getVersion()); - versioning.updateTimestamp(); - ArtifactRepositoryMetadata metadata = new ArtifactRepositoryMetadata(projectArtifact, versioning); - projectArtifact.addMetadata(metadata); + @Override + protected void executeMojo() throws MojoExecutionException { + Artifact projectArtifact = project.getArtifact(); - GroupRepositoryMetadata groupMetadata = new GroupRepositoryMetadata(project.getGroupId()); - groupMetadata.addPluginMapping(getGoalPrefix(), project.getArtifactId(), project.getName()); + Versioning versioning = new Versioning(); + versioning.setLatest(projectArtifact.getVersion()); + versioning.updateTimestamp(); + ArtifactRepositoryMetadata metadata = new ArtifactRepositoryMetadata(projectArtifact, versioning); + projectArtifact.addMetadata(metadata); - projectArtifact.addMetadata(groupMetadata); - } + GroupRepositoryMetadata groupMetadata = new GroupRepositoryMetadata(project.getGroupId()); + groupMetadata.addPluginMapping(getGoalPrefix(), project.getArtifactId(), project.getName()); - /** - * @return the goal prefix parameter or the goal prefix from the Plugin artifactId. - */ - private String getGoalPrefix() { - if (goalPrefix == null) { - goalPrefix = PluginDescriptor.getGoalPrefixFromArtifactId(project.getArtifactId()); + projectArtifact.addMetadata(groupMetadata); } - return goalPrefix; - } + /** + * @return the goal prefix parameter or the goal prefix from the Plugin artifactId. + */ + private String getGoalPrefix() { + if (goalPrefix == null) { + goalPrefix = PluginDescriptor.getGoalPrefixFromArtifactId(project.getArtifactId()); + } + + return goalPrefix; + } } diff --git a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/plugin/GeneratorUtils.java b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/plugin/GeneratorUtils.java index b3737719..20808f87 100644 --- a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/plugin/GeneratorUtils.java +++ b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/plugin/GeneratorUtils.java @@ -1,3 +1,10 @@ +/* + * Copyright (c) 2014-2024 Takari, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v10.html + */ package io.takari.maven.plugins.plugin; /* @@ -21,102 +28,100 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; - import org.codehaus.plexus.util.StringUtils; // originally copied from org.apache.maven.tools.plugin.generator.GeneratorUtils class GeneratorUtils { - private GeneratorUtils() { - // nop - } - - /** - * Returns a literal replacement String for the specified String. This method produces a String that will work as a literal replacement s in the - * appendReplacement method of the {@link Matcher} class. The String produced will match the sequence of characters in s treated as a literal sequence. Slashes - * ('\') and dollar signs ('$') will be given no special meaning. TODO: copied from Matcher class of Java 1.5, remove once target platform can be upgraded - * - * @see java.util.regex.Matcher - * @param s The string to be literalized - * @return A literal string replacement - */ - private static String quoteReplacement(String s) { - if ((s.indexOf('\\') == -1) && (s.indexOf('$') == -1)) { - return s; + private GeneratorUtils() { + // nop } - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < s.length(); i++) { - char c = s.charAt(i); - if (c == '\\') { - sb.append('\\'); - sb.append('\\'); - } else if (c == '$') { - sb.append('\\'); - sb.append('$'); - } else { - sb.append(c); - } - } + /** + * Returns a literal replacement String for the specified String. This method produces a String that will work as a literal replacement s in the + * appendReplacement method of the {@link Matcher} class. The String produced will match the sequence of characters in s treated as a literal sequence. Slashes + * ('\') and dollar signs ('$') will be given no special meaning. TODO: copied from Matcher class of Java 1.5, remove once target platform can be upgraded + * + * @see java.util.regex.Matcher + * @param s The string to be literalized + * @return A literal string replacement + */ + private static String quoteReplacement(String s) { + if ((s.indexOf('\\') == -1) && (s.indexOf('$') == -1)) { + return s; + } - return sb.toString(); - } + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < s.length(); i++) { + char c = s.charAt(i); + if (c == '\\') { + sb.append('\\'); + sb.append('\\'); + } else if (c == '$') { + sb.append('\\'); + sb.append('$'); + } else { + sb.append(c); + } + } - /** - * Decodes javadoc inline tags into equivalent HTML tags. For instance, the inline tag "{@code }" should be rendered as "<A&B>". - * - * @param description The javadoc description to decode, may be null. - * @return The decoded description, never null. - */ - static String decodeJavadocTags(String description) { - if (StringUtils.isEmpty(description)) { - return ""; + return sb.toString(); } - StringBuffer decoded = new StringBuffer(description.length() + 1024); + /** + * Decodes javadoc inline tags into equivalent HTML tags. For instance, the inline tag "{@code }" should be rendered as "<A&B>". + * + * @param description The javadoc description to decode, may be null. + * @return The decoded description, never null. + */ + static String decodeJavadocTags(String description) { + if (StringUtils.isEmpty(description)) { + return ""; + } - Matcher matcher = Pattern.compile("\\{@(\\w+)\\s*([^\\}]*)\\}").matcher(description); - while (matcher.find()) { - String tag = matcher.group(1); - String text = matcher.group(2); - text = StringUtils.replace(text, "&", "&"); - text = StringUtils.replace(text, "<", "<"); - text = StringUtils.replace(text, ">", ">"); - if ("code".equals(tag)) { - text = "" + text + ""; - } else if ("link".equals(tag) || "linkplain".equals(tag) || "value".equals(tag)) { - String pattern = "(([^#\\.\\s]+\\.)*([^#\\.\\s]+))?" + "(#([^\\(\\s]*)(\\([^\\)]*\\))?\\s*(\\S.*)?)?"; - final int label = 7; - final int clazz = 3; - final int member = 5; - final int args = 6; - Matcher link = Pattern.compile(pattern).matcher(text); - if (link.matches()) { - text = link.group(label); - if (StringUtils.isEmpty(text)) { - text = link.group(clazz); - if (StringUtils.isEmpty(text)) { - text = ""; - } - if (StringUtils.isNotEmpty(link.group(member))) { - if (StringUtils.isNotEmpty(text)) { - text += '.'; - } - text += link.group(member); - if (StringUtils.isNotEmpty(link.group(args))) { - text += "()"; - } + StringBuffer decoded = new StringBuffer(description.length() + 1024); + + Matcher matcher = Pattern.compile("\\{@(\\w+)\\s*([^\\}]*)\\}").matcher(description); + while (matcher.find()) { + String tag = matcher.group(1); + String text = matcher.group(2); + text = StringUtils.replace(text, "&", "&"); + text = StringUtils.replace(text, "<", "<"); + text = StringUtils.replace(text, ">", ">"); + if ("code".equals(tag)) { + text = "" + text + ""; + } else if ("link".equals(tag) || "linkplain".equals(tag) || "value".equals(tag)) { + String pattern = "(([^#\\.\\s]+\\.)*([^#\\.\\s]+))?" + "(#([^\\(\\s]*)(\\([^\\)]*\\))?\\s*(\\S.*)?)?"; + final int label = 7; + final int clazz = 3; + final int member = 5; + final int args = 6; + Matcher link = Pattern.compile(pattern).matcher(text); + if (link.matches()) { + text = link.group(label); + if (StringUtils.isEmpty(text)) { + text = link.group(clazz); + if (StringUtils.isEmpty(text)) { + text = ""; + } + if (StringUtils.isNotEmpty(link.group(member))) { + if (StringUtils.isNotEmpty(text)) { + text += '.'; + } + text += link.group(member); + if (StringUtils.isNotEmpty(link.group(args))) { + text += "()"; + } + } + } + } + if (!"linkplain".equals(tag)) { + text = "" + text + ""; + } } - } - } - if (!"linkplain".equals(tag)) { - text = "" + text + ""; + matcher.appendReplacement(decoded, (text != null) ? quoteReplacement(text) : ""); } - } - matcher.appendReplacement(decoded, (text != null) ? quoteReplacement(text) : ""); - } - matcher.appendTail(decoded); - - return decoded.toString(); - } + matcher.appendTail(decoded); + return decoded.toString(); + } } diff --git a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/plugin/GroupRepositoryMetadata.java b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/plugin/GroupRepositoryMetadata.java index f2b0e47e..0f19bde5 100644 --- a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/plugin/GroupRepositoryMetadata.java +++ b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/plugin/GroupRepositoryMetadata.java @@ -1,3 +1,10 @@ +/* + * Copyright (c) 2014-2024 Takari, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v10.html + */ package io.takari.maven.plugins.plugin; /* @@ -21,7 +28,6 @@ import java.util.Iterator; import java.util.List; - import org.apache.maven.artifact.repository.ArtifactRepository; import org.apache.maven.artifact.repository.metadata.AbstractRepositoryMetadata; import org.apache.maven.artifact.repository.metadata.Metadata; @@ -34,79 +40,78 @@ */ // originally copied from org.apache.maven.artifact.repository.metadata.GroupRepositoryMetadata class GroupRepositoryMetadata extends AbstractRepositoryMetadata { - private final String groupId; - - public GroupRepositoryMetadata(String groupId) { - super(new Metadata()); - this.groupId = groupId; - } - - @Override - public boolean storedInGroupDirectory() { - return true; - } - - @Override - public boolean storedInArtifactVersionDirectory() { - return false; - } - - @Override - public String getGroupId() { - return groupId; - } - - @Override - public String getArtifactId() { - return null; - } - - @Override - public String getBaseVersion() { - return null; - } - - public void addPluginMapping(String goalPrefix, String artifactId) { - addPluginMapping(goalPrefix, artifactId, artifactId); - } - - public void addPluginMapping(String goalPrefix, String artifactId, String name) { - List plugins = getMetadata().getPlugins(); - boolean found = false; - for (Iterator i = plugins.iterator(); i.hasNext() && !found;) { - Plugin plugin = (Plugin) i.next(); - if (plugin.getPrefix().equals(goalPrefix)) { - found = true; - } + private final String groupId; + + public GroupRepositoryMetadata(String groupId) { + super(new Metadata()); + this.groupId = groupId; + } + + @Override + public boolean storedInGroupDirectory() { + return true; + } + + @Override + public boolean storedInArtifactVersionDirectory() { + return false; + } + + @Override + public String getGroupId() { + return groupId; + } + + @Override + public String getArtifactId() { + return null; } - if (!found) { - Plugin plugin = new Plugin(); - plugin.setPrefix(goalPrefix); - plugin.setArtifactId(artifactId); - plugin.setName(name); + @Override + public String getBaseVersion() { + return null; + } + + public void addPluginMapping(String goalPrefix, String artifactId) { + addPluginMapping(goalPrefix, artifactId, artifactId); + } + + public void addPluginMapping(String goalPrefix, String artifactId, String name) { + List plugins = getMetadata().getPlugins(); + boolean found = false; + for (Iterator i = plugins.iterator(); i.hasNext() && !found; ) { + Plugin plugin = (Plugin) i.next(); + if (plugin.getPrefix().equals(goalPrefix)) { + found = true; + } + } + if (!found) { + Plugin plugin = new Plugin(); + plugin.setPrefix(goalPrefix); + plugin.setArtifactId(artifactId); + plugin.setName(name); + + getMetadata().addPlugin(plugin); + } + } + + @Override + public Object getKey() { + return groupId; + } + + @Override + public boolean isSnapshot() { + return false; + } + + @Override + public ArtifactRepository getRepository() { + return null; + } - getMetadata().addPlugin(plugin); + @Override + public void setRepository(ArtifactRepository remoteRepository) { + // intentionally blank } - } - - @Override - public Object getKey() { - return groupId; - } - - @Override - public boolean isSnapshot() { - return false; - } - - @Override - public ArtifactRepository getRepository() { - return null; - } - - @Override - public void setRepository(ArtifactRepository remoteRepository) { - // intentionally blank - } } diff --git a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/plugin/LegacyPluginDescriptors.java b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/plugin/LegacyPluginDescriptors.java index 9361324b..f1f543d1 100644 --- a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/plugin/LegacyPluginDescriptors.java +++ b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/plugin/LegacyPluginDescriptors.java @@ -1,12 +1,21 @@ +/* + * Copyright (c) 2014-2024 Takari, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v10.html + */ package io.takari.maven.plugins.plugin; +import io.takari.maven.plugins.plugin.model.MojoDescriptor; +import io.takari.maven.plugins.plugin.model.MojoParameter; +import io.takari.maven.plugins.plugin.model.MojoRequirement; import java.io.IOException; import java.io.InputStream; import java.io.Reader; import java.util.ArrayList; import java.util.Collection; import java.util.List; - import org.apache.maven.plugin.descriptor.Parameter; import org.apache.maven.plugin.descriptor.PluginDescriptorBuilder; import org.codehaus.plexus.component.repository.ComponentRequirement; @@ -14,102 +23,95 @@ import org.codehaus.plexus.util.ReaderFactory; import org.codehaus.plexus.util.xml.pull.XmlPullParserException; -import io.takari.maven.plugins.plugin.model.MojoDescriptor; -import io.takari.maven.plugins.plugin.model.MojoParameter; -import io.takari.maven.plugins.plugin.model.MojoRequirement; - class LegacyPluginDescriptors { - public static Collection readMojos(InputStream is) throws IOException, XmlPullParserException { - Reader reader = ReaderFactory.newXmlReader(is); - org.apache.maven.plugin.descriptor.PluginDescriptor pluginDescriptor; - try { - pluginDescriptor = new PluginDescriptorBuilder().build(reader); - } catch (PlexusConfigurationException e) { - Throwable cause = e.getCause(); - if ( cause instanceof IOException ) { - throw (IOException) cause; - } - if ( cause instanceof XmlPullParserException ) { - throw (XmlPullParserException) cause; - } - throw new RuntimeException(e); + public static Collection readMojos(InputStream is) throws IOException, XmlPullParserException { + Reader reader = ReaderFactory.newXmlReader(is); + org.apache.maven.plugin.descriptor.PluginDescriptor pluginDescriptor; + try { + pluginDescriptor = new PluginDescriptorBuilder().build(reader); + } catch (PlexusConfigurationException e) { + Throwable cause = e.getCause(); + if (cause instanceof IOException) { + throw (IOException) cause; + } + if (cause instanceof XmlPullParserException) { + throw (XmlPullParserException) cause; + } + throw new RuntimeException(e); + } + List result = new ArrayList<>(); + for (org.apache.maven.plugin.descriptor.MojoDescriptor mojo : pluginDescriptor.getMojos()) { + result.add(toMojoDescriptor(mojo)); + } + return result; } - List result = new ArrayList<>(); - for (org.apache.maven.plugin.descriptor.MojoDescriptor mojo : pluginDescriptor.getMojos()) { - result.add(toMojoDescriptor(mojo)); + + private static MojoDescriptor toMojoDescriptor(org.apache.maven.plugin.descriptor.MojoDescriptor mojo) { + MojoDescriptor result = new MojoDescriptor(); + + result.setGoal(mojo.getGoal()); + result.setDescription(mojo.getDescription()); + result.setSince(mojo.getSince()); + result.setRequiresDependencyResolution(mojo.getDependencyResolutionRequired()); + result.setRequiresDependencyCollection(mojo.getDependencyCollectionRequired()); + result.setRequiresDirectInvocation(mojo.isDirectInvocationOnly()); + result.setRequiresProject(mojo.isProjectRequired()); + result.setRequiresReports(mojo.isRequiresReports()); + result.setAggregator(mojo.isAggregator()); + result.setRequiresOnline(mojo.isOnlineRequired()); + result.setInheritedByDefault(mojo.isInheritedByDefault()); + result.setPhase(mojo.getPhase()); + result.setImplementation(mojo.getImplementation()); + result.setLanguage(mojo.getLanguage()); + result.setConfigurator(mojo.getComponentConfigurator()); + result.setInstantiationStrategy(mojo.getInstantiationStrategy()); + result.setExecutionStrategy(mojo.getExecutionStrategy()); + result.setThreadSafe(mojo.isThreadSafe()); + result.setDeprecated(mojo.getDeprecated()); + + List parameters = new ArrayList<>(); + if (mojo.getParameters() != null) { + for (Parameter parameter : mojo.getParameters()) { + parameters.add(toMojoParameter(parameter)); + } + } + result.setParameters(parameters); + + List requirements = new ArrayList<>(); + for (ComponentRequirement requirement : mojo.getRequirements()) { + requirements.add(toMojoRequirement(requirement)); + } + result.setRequirements(requirements); + + return result; } - return result; - } - private static MojoDescriptor toMojoDescriptor(org.apache.maven.plugin.descriptor.MojoDescriptor mojo) { - MojoDescriptor result = new MojoDescriptor(); + private static MojoRequirement toMojoRequirement(ComponentRequirement requirement) { + MojoRequirement result = new MojoRequirement(); - result.setGoal(mojo.getGoal()); - result.setDescription(mojo.getDescription()); - result.setSince(mojo.getSince()); - result.setRequiresDependencyResolution(mojo.getDependencyResolutionRequired()); - result.setRequiresDependencyCollection(mojo.getDependencyCollectionRequired()); - result.setRequiresDirectInvocation(mojo.isDirectInvocationOnly()); - result.setRequiresProject(mojo.isProjectRequired()); - result.setRequiresReports(mojo.isRequiresReports()); - result.setAggregator(mojo.isAggregator()); - result.setRequiresOnline(mojo.isOnlineRequired()); - result.setInheritedByDefault(mojo.isInheritedByDefault()); - result.setPhase(mojo.getPhase()); - result.setImplementation(mojo.getImplementation()); - result.setLanguage(mojo.getLanguage()); - result.setConfigurator(mojo.getComponentConfigurator()); - result.setInstantiationStrategy(mojo.getInstantiationStrategy()); - result.setExecutionStrategy(mojo.getExecutionStrategy()); - result.setThreadSafe(mojo.isThreadSafe()); - result.setDeprecated(mojo.getDeprecated()); + result.setFieldName(requirement.getFieldName()); + result.setRole(requirement.getRole()); + result.setRoleHint(requirement.getRoleHint()); - List parameters = new ArrayList<>(); - if (mojo.getParameters() != null) { - for (Parameter parameter : mojo.getParameters()) { - parameters.add(toMojoParameter(parameter)); - } + return result; } - result.setParameters(parameters); - List requirements = new ArrayList<>(); - for (ComponentRequirement requirement : mojo.getRequirements()) { - requirements.add(toMojoRequirement(requirement)); + private static MojoParameter toMojoParameter(Parameter parameter) { + MojoParameter result = new MojoParameter(); + + result.setName(parameter.getName()); + result.setAlias(parameter.getAlias()); + result.setType(parameter.getType()); + result.setRequired(parameter.isRequired()); + result.setEditable(parameter.isEditable()); + result.setDescription(parameter.getDescription()); + result.setDeprecated(parameter.getDeprecated()); + result.setSince(parameter.getSince()); + result.setImplementation(parameter.getImplementation()); + result.setDefaultValue(parameter.getDefaultValue()); + result.setExpression(parameter.getExpression()); + + return result; } - result.setRequirements(requirements); - - return result; - } - - private static MojoRequirement toMojoRequirement(ComponentRequirement requirement) { - MojoRequirement result = new MojoRequirement(); - - result.setFieldName(requirement.getFieldName()); - result.setRole(requirement.getRole()); - result.setRoleHint(requirement.getRoleHint()); - - return result; - } - - private static MojoParameter toMojoParameter(Parameter parameter) { - MojoParameter result = new MojoParameter(); - - result.setName(parameter.getName()); - result.setAlias(parameter.getAlias()); - result.setType(parameter.getType()); - result.setRequired(parameter.isRequired()); - result.setEditable(parameter.isEditable()); - result.setDescription(parameter.getDescription()); - result.setDeprecated(parameter.getDeprecated()); - result.setSince(parameter.getSince()); - result.setImplementation(parameter.getImplementation()); - result.setDefaultValue(parameter.getDefaultValue()); - result.setExpression(parameter.getExpression()); - - return result; - } - - - } diff --git a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/plugin/MojoAnnotationProcessorMojo.java b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/plugin/MojoAnnotationProcessorMojo.java index 488c7df9..3aeb36a5 100644 --- a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/plugin/MojoAnnotationProcessorMojo.java +++ b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/plugin/MojoAnnotationProcessorMojo.java @@ -1,34 +1,43 @@ +/* + * Copyright (c) 2014-2024 Takari, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v10.html + */ package io.takari.maven.plugins.plugin; +import io.takari.maven.plugins.compile.CompileMojo; +import io.takari.maven.plugins.compile.jdt.CompilerJdt; import java.io.File; import java.util.Collections; import java.util.List; - import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; import org.apache.maven.plugins.annotations.Mojo; import org.apache.maven.plugins.annotations.ResolutionScope; -import io.takari.maven.plugins.compile.CompileMojo; -import io.takari.maven.plugins.compile.jdt.CompilerJdt; - -@Mojo(name = "mojo-annotation-processor", threadSafe = true, requiresDependencyResolution = ResolutionScope.COMPILE, configurator = "takari") +@Mojo( + name = "mojo-annotation-processor", + threadSafe = true, + requiresDependencyResolution = ResolutionScope.COMPILE, + configurator = "takari") public class MojoAnnotationProcessorMojo extends CompileMojo { - @Override - public void execute() throws MojoExecutionException, MojoFailureException { - this.proc = Proc.only; - if (this.sourcepath == null) { - this.sourcepath = Sourcepath.disable; // assume all dependencies have been already compiled - } - this.compilerId = CompilerJdt.ID; - this.annotationProcessors = new String[] {MojoDescriptorGleaner.class.getName()}; + @Override + public void execute() throws MojoExecutionException, MojoFailureException { + this.proc = Proc.only; + if (this.sourcepath == null) { + this.sourcepath = Sourcepath.disable; // assume all dependencies have been already compiled + } + this.compilerId = CompilerJdt.ID; + this.annotationProcessors = new String[] {MojoDescriptorGleaner.class.getName()}; - super.execute(); - } + super.execute(); + } - @Override - protected List getProcessorpath() { - return Collections.emptyList(); - } + @Override + protected List getProcessorpath() { + return Collections.emptyList(); + } } diff --git a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/plugin/MojoDescriptorGleaner.java b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/plugin/MojoDescriptorGleaner.java index c6ab7205..2dfdeb6f 100644 --- a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/plugin/MojoDescriptorGleaner.java +++ b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/plugin/MojoDescriptorGleaner.java @@ -1,7 +1,19 @@ +/* + * Copyright (c) 2014-2024 Takari, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v10.html + */ package io.takari.maven.plugins.plugin; import static io.takari.maven.plugins.plugin.PluginDescriptorMojo.PATH_MOJOS_XML; +import io.takari.maven.plugins.plugin.model.MojoDescriptor; +import io.takari.maven.plugins.plugin.model.MojoParameter; +import io.takari.maven.plugins.plugin.model.MojoRequirement; +import io.takari.maven.plugins.plugin.model.PluginDescriptor; +import io.takari.maven.plugins.plugin.model.io.xpp3.PluginDescriptorXpp3Writer; import java.io.IOException; import java.io.OutputStream; import java.lang.annotation.Annotation; @@ -10,7 +22,6 @@ import java.util.List; import java.util.Set; import java.util.TreeMap; - import javax.annotation.processing.AbstractProcessor; import javax.annotation.processing.RoundEnvironment; import javax.annotation.processing.SupportedSourceVersion; @@ -27,237 +38,241 @@ import javax.tools.Diagnostic.Kind; import javax.tools.FileObject; import javax.tools.StandardLocation; - import org.apache.maven.plugins.annotations.Component; import org.apache.maven.plugins.annotations.Mojo; import org.apache.maven.plugins.annotations.Parameter; -import io.takari.maven.plugins.plugin.model.MojoDescriptor; -import io.takari.maven.plugins.plugin.model.MojoParameter; -import io.takari.maven.plugins.plugin.model.MojoRequirement; -import io.takari.maven.plugins.plugin.model.PluginDescriptor; -import io.takari.maven.plugins.plugin.model.io.xpp3.PluginDescriptorXpp3Writer; - /** * @TODO access javadoc tag text, like @deprecated and @since */ @SupportedSourceVersion(SourceVersion.RELEASE_7) public class MojoDescriptorGleaner extends AbstractProcessor { - private final TreeMap descriptors = new TreeMap<>(); - - @Override - public boolean process(Set annotations, RoundEnvironment roundEnv) { - for (TypeElement element : getAnnotatedTypes(roundEnv)) { - MojoDescriptor descriptor = processType(element); - descriptors.put(descriptor.getImplementation(), descriptor); - } + private final TreeMap descriptors = new TreeMap<>(); - if (roundEnv.processingOver() && !descriptors.isEmpty()) { - try { - writeMojosXml(descriptors); - } catch (IOException e) { - // TODO it'd be nice to capture IOException somewhere too - processingEnv.getMessager().printMessage(Kind.ERROR, "Could not create aggregate output " + e.getMessage()); - } - } + @Override + public boolean process(Set annotations, RoundEnvironment roundEnv) { + for (TypeElement element : getAnnotatedTypes(roundEnv)) { + MojoDescriptor descriptor = processType(element); + descriptors.put(descriptor.getImplementation(), descriptor); + } - return false; // don't claim the annotations, other processors are welcome to use them - } + if (roundEnv.processingOver() && !descriptors.isEmpty()) { + try { + writeMojosXml(descriptors); + } catch (IOException e) { + // TODO it'd be nice to capture IOException somewhere too + processingEnv + .getMessager() + .printMessage(Kind.ERROR, "Could not create aggregate output " + e.getMessage()); + } + } - private Set getAnnotatedTypes(RoundEnvironment roundEnv) { - Set types = new HashSet<>(); - roundEnv.getElementsAnnotatedWith(Mojo.class).forEach(type -> types.add((TypeElement) type)); - addAnnotatedMembers(types, roundEnv, Parameter.class); - addAnnotatedMembers(types, roundEnv, Component.class); - return types; - } + return false; // don't claim the annotations, other processors are welcome to use them + } - private void addAnnotatedMembers(Set types, RoundEnvironment roundEnv, Class annotation) { - for (Element member : roundEnv.getElementsAnnotatedWith(annotation)) { - Element type = member.getEnclosingElement(); - if (type.getEnclosingElement().getKind() == ElementKind.PACKAGE) { - types.add((TypeElement) type); - } else { - processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, annotation + " only applicable to top-level class members", member); - } + private Set getAnnotatedTypes(RoundEnvironment roundEnv) { + Set types = new HashSet<>(); + roundEnv.getElementsAnnotatedWith(Mojo.class).forEach(type -> types.add((TypeElement) type)); + addAnnotatedMembers(types, roundEnv, Parameter.class); + addAnnotatedMembers(types, roundEnv, Component.class); + return types; } - } - @Override - public Set getSupportedAnnotationTypes() { - Set types = new HashSet<>(); - types.add(Mojo.class.getName()); - types.add(Parameter.class.getName()); - types.add(Component.class.getName()); - return types; - } + private void addAnnotatedMembers( + Set types, RoundEnvironment roundEnv, Class annotation) { + for (Element member : roundEnv.getElementsAnnotatedWith(annotation)) { + Element type = member.getEnclosingElement(); + if (type.getEnclosingElement().getKind() == ElementKind.PACKAGE) { + types.add((TypeElement) type); + } else { + processingEnv + .getMessager() + .printMessage( + Diagnostic.Kind.ERROR, + annotation + " only applicable to top-level class members", + member); + } + } + } - MojoDescriptor processType(TypeElement type) { - MojoDescriptor descriptor = new MojoDescriptor(); + @Override + public Set getSupportedAnnotationTypes() { + Set types = new HashSet<>(); + types.add(Mojo.class.getName()); + types.add(Parameter.class.getName()); + types.add(Component.class.getName()); + return types; + } - descriptor.setImplementation(type.getQualifiedName().toString()); - descriptor.setSuperclasses(getSuperclasses(type, new ArrayList())); + MojoDescriptor processType(TypeElement type) { + MojoDescriptor descriptor = new MojoDescriptor(); + + descriptor.setImplementation(type.getQualifiedName().toString()); + descriptor.setSuperclasses(getSuperclasses(type, new ArrayList())); + + Mojo mojo = type.getAnnotation(Mojo.class); + if (mojo != null) { + // mojo is null for classes that have @Parameter/@Component element annotations + + descriptor.setLanguage("java"); + descriptor.setGoal(mojo.name()); + descriptor.setExecutionStrategy(mojo.executionStrategy()); + descriptor.setRequiresProject(mojo.requiresProject()); + descriptor.setRequiresReports(mojo.requiresReports()); + descriptor.setAggregator(mojo.aggregator()); + descriptor.setRequiresDirectInvocation(mojo.requiresDirectInvocation()); + descriptor.setRequiresOnline(mojo.requiresOnline()); + descriptor.setInheritedByDefault(mojo.inheritByDefault()); + if (!isEmpty(mojo.configurator())) { + descriptor.setConfigurator(mojo.configurator()); + } + descriptor.setThreadSafe(mojo.threadSafe()); + descriptor.setPhase(mojo.defaultPhase().id()); + descriptor.setRequiresDependencyResolution( + mojo.requiresDependencyResolution().id()); + descriptor.setRequiresDependencyCollection( + mojo.requiresDependencyCollection().id()); + descriptor.setInstantiationStrategy(mojo.instantiationStrategy().id()); + + if (getElementUtils().isDeprecated(type)) { + descriptor.setDeprecated("No reason given"); // TODO parse javadoc + } + // This is not ideal + // the proper way would be to add support for processorPath to compiler plugin + // which would allow us to do this as part of takari-builder annotation processing + // without adding takari-builder-apt to the compile classpath + // we intend to do this properly... soon + if (isTakariBuilderMojo(type)) { + descriptor.setTakariBuilder(true); + } + descriptor.setDescription(getDescription(type)); + } - Mojo mojo = type.getAnnotation(Mojo.class); - if (mojo != null) { - // mojo is null for classes that have @Parameter/@Component element annotations + processTypeFields(type, descriptor); - descriptor.setLanguage("java"); - descriptor.setGoal(mojo.name()); - descriptor.setExecutionStrategy(mojo.executionStrategy()); - descriptor.setRequiresProject(mojo.requiresProject()); - descriptor.setRequiresReports(mojo.requiresReports()); - descriptor.setAggregator(mojo.aggregator()); - descriptor.setRequiresDirectInvocation(mojo.requiresDirectInvocation()); - descriptor.setRequiresOnline(mojo.requiresOnline()); - descriptor.setInheritedByDefault(mojo.inheritByDefault()); - if (!isEmpty(mojo.configurator())) { - descriptor.setConfigurator(mojo.configurator()); - } - descriptor.setThreadSafe(mojo.threadSafe()); - descriptor.setPhase(mojo.defaultPhase().id()); - descriptor.setRequiresDependencyResolution(mojo.requiresDependencyResolution().id()); - descriptor.setRequiresDependencyCollection(mojo.requiresDependencyCollection().id()); - descriptor.setInstantiationStrategy(mojo.instantiationStrategy().id()); + Sorting.sortParameters(descriptor.getParameters()); + Sorting.sortRequirements(descriptor.getRequirements()); - if (getElementUtils().isDeprecated(type)) { - descriptor.setDeprecated("No reason given"); // TODO parse javadoc - } - // This is not ideal - // the proper way would be to add support for processorPath to compiler plugin - // which would allow us to do this as part of takari-builder annotation processing - // without adding takari-builder-apt to the compile classpath - // we intend to do this properly... soon - if (isTakariBuilderMojo(type)) { - descriptor.setTakariBuilder(true); - } - descriptor.setDescription(getDescription(type)); + return descriptor; } - processTypeFields(type, descriptor); - - Sorting.sortParameters(descriptor.getParameters()); - Sorting.sortRequirements(descriptor.getRequirements()); - - return descriptor; - } - - private boolean isTakariBuilderMojo(TypeElement type) { - TypeElement abstractIncrementalMojoType = getElementUtils().getTypeElement("io.takari.builder.internal.maven.AbstractIncrementalMojo"); - return abstractIncrementalMojoType != null && getTypeUtils().isSubtype(type.asType(), abstractIncrementalMojoType.asType()); - } + private boolean isTakariBuilderMojo(TypeElement type) { + TypeElement abstractIncrementalMojoType = + getElementUtils().getTypeElement("io.takari.builder.internal.maven.AbstractIncrementalMojo"); + return abstractIncrementalMojoType != null + && getTypeUtils().isSubtype(type.asType(), abstractIncrementalMojoType.asType()); + } - private void processTypeFields(TypeElement type, MojoDescriptor descriptor) { - // non-static fields - for (Element member : type.getEnclosedElements()) { - if (member instanceof VariableElement) { - Parameter parameter = member.getAnnotation(Parameter.class); - Component component = member.getAnnotation(Component.class); - if (parameter != null && component != null) { - // TODO error marker - } - if (parameter != null) { - descriptor.addParameter(toParameterDescriptor((VariableElement) member, parameter)); - } else if (component != null) { - descriptor.addRequirement(toComponentDescriptor((VariableElement) member, component)); + private void processTypeFields(TypeElement type, MojoDescriptor descriptor) { + // non-static fields + for (Element member : type.getEnclosedElements()) { + if (member instanceof VariableElement) { + Parameter parameter = member.getAnnotation(Parameter.class); + Component component = member.getAnnotation(Component.class); + if (parameter != null && component != null) { + // TODO error marker + } + if (parameter != null) { + descriptor.addParameter(toParameterDescriptor((VariableElement) member, parameter)); + } else if (component != null) { + descriptor.addRequirement(toComponentDescriptor((VariableElement) member, component)); + } + } } - } } - } - - private MojoRequirement toComponentDescriptor(VariableElement field, Component component) { - MojoRequirement result = new MojoRequirement(); - result.setFieldName(field.getSimpleName().toString()); - result.setRole(getComponentRole(field, component)); - result.setRoleHint(component.hint()); - return result; - } - private String getComponentRole(VariableElement field, Component component) { - String role; - try { - role = component.role().getName(); - } catch (MirroredTypeException e) { - role = e.getTypeMirror().toString(); + private MojoRequirement toComponentDescriptor(VariableElement field, Component component) { + MojoRequirement result = new MojoRequirement(); + result.setFieldName(field.getSimpleName().toString()); + result.setRole(getComponentRole(field, component)); + result.setRoleHint(component.hint()); + return result; } - if (!Object.class.getName().equals(role)) { - return role; - } - return getTypeString(field.asType()); - } - private String getTypeString(TypeMirror type) { - TypeElement typeElement = (TypeElement) getTypeUtils().asElement(type); - if (typeElement != null) { - // this returns raw parameterized types - return typeElement.getQualifiedName().toString(); + private String getComponentRole(VariableElement field, Component component) { + String role; + try { + role = component.role().getName(); + } catch (MirroredTypeException e) { + role = e.getTypeMirror().toString(); + } + if (!Object.class.getName().equals(role)) { + return role; + } + return getTypeString(field.asType()); } - // this deals with primitive and array types - return type.toString(); - } - private MojoParameter toParameterDescriptor(VariableElement field, Parameter parameter) { - MojoParameter result = new MojoParameter(); - result.setName(field.getSimpleName().toString()); - if (!isEmpty(parameter.alias())) { - result.setAlias(parameter.alias()); - } - if (!isEmpty(parameter.defaultValue())) { - result.setDefaultValue(parameter.defaultValue()); - } - if (!isEmpty(parameter.property())) { - result.setExpression("${" + parameter.property() + "}"); + private String getTypeString(TypeMirror type) { + TypeElement typeElement = (TypeElement) getTypeUtils().asElement(type); + if (typeElement != null) { + // this returns raw parameterized types + return typeElement.getQualifiedName().toString(); + } + // this deals with primitive and array types + return type.toString(); } - result.setEditable(!parameter.readonly()); - result.setRequired(parameter.required()); - result.setType(getTypeString(field.asType())); - result.setDescription(getDescription(field)); - return result; - } + private MojoParameter toParameterDescriptor(VariableElement field, Parameter parameter) { + MojoParameter result = new MojoParameter(); + result.setName(field.getSimpleName().toString()); + if (!isEmpty(parameter.alias())) { + result.setAlias(parameter.alias()); + } + if (!isEmpty(parameter.defaultValue())) { + result.setDefaultValue(parameter.defaultValue()); + } + if (!isEmpty(parameter.property())) { + result.setExpression("${" + parameter.property() + "}"); + } + result.setEditable(!parameter.readonly()); + result.setRequired(parameter.required()); + result.setType(getTypeString(field.asType())); + result.setDescription(getDescription(field)); - private List getSuperclasses(TypeElement type, List superclasses) { - TypeElement superclass = type; - while ((superclass = (TypeElement) getTypeUtils().asElement(superclass.getSuperclass())) != null) { - String qualifiedName = superclass.getQualifiedName().toString(); - if ("java.lang.Object".equals(qualifiedName)) { - break; - } - superclasses.add(qualifiedName); + return result; } - return superclasses; - } - private Types getTypeUtils() { - return processingEnv.getTypeUtils(); - } - - private String getDescription(Element element) { - String description = getElementUtils().getDocComment(element); - if (description != null) { - description = description.trim(); + private List getSuperclasses(TypeElement type, List superclasses) { + TypeElement superclass = type; + while ((superclass = (TypeElement) getTypeUtils().asElement(superclass.getSuperclass())) != null) { + String qualifiedName = superclass.getQualifiedName().toString(); + if ("java.lang.Object".equals(qualifiedName)) { + break; + } + superclasses.add(qualifiedName); + } + return superclasses; } - return !isEmpty(description) ? description : null; - } - private Elements getElementUtils() { - return processingEnv.getElementUtils(); - } + private Types getTypeUtils() { + return processingEnv.getTypeUtils(); + } - private static boolean isEmpty(String str) { - return str == null || str.isEmpty(); - } + private String getDescription(Element element) { + String description = getElementUtils().getDocComment(element); + if (description != null) { + description = description.trim(); + } + return !isEmpty(description) ? description : null; + } - void writeMojosXml(TreeMap descriptors) throws IOException { - PluginDescriptor mojos = new PluginDescriptor(); - for (MojoDescriptor descriptor : descriptors.values()) { - mojos.addMojo(descriptor); + private Elements getElementUtils() { + return processingEnv.getElementUtils(); } - FileObject output = processingEnv.getFiler().createResource(StandardLocation.CLASS_OUTPUT, "", PATH_MOJOS_XML); - try (OutputStream out = output.openOutputStream()) { - new PluginDescriptorXpp3Writer().write(out, mojos); + + private static boolean isEmpty(String str) { + return str == null || str.isEmpty(); } - } + void writeMojosXml(TreeMap descriptors) throws IOException { + PluginDescriptor mojos = new PluginDescriptor(); + for (MojoDescriptor descriptor : descriptors.values()) { + mojos.addMojo(descriptor); + } + FileObject output = processingEnv.getFiler().createResource(StandardLocation.CLASS_OUTPUT, "", PATH_MOJOS_XML); + try (OutputStream out = output.openOutputStream()) { + new PluginDescriptorXpp3Writer().write(out, mojos); + } + } } diff --git a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/plugin/PluginDescriptorMojo.java b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/plugin/PluginDescriptorMojo.java index 2abbe764..47f14303 100644 --- a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/plugin/PluginDescriptorMojo.java +++ b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/plugin/PluginDescriptorMojo.java @@ -1,7 +1,25 @@ +/* + * Copyright (c) 2014-2024 Takari, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v10.html + */ package io.takari.maven.plugins.plugin; import static io.takari.incrementalbuild.Incremental.Configuration.ignore; +import io.takari.incrementalbuild.Incremental; +import io.takari.incrementalbuild.Output; +import io.takari.incrementalbuild.aggregator.AggregatorBuildContext; +import io.takari.incrementalbuild.aggregator.InputAggregator; +import io.takari.incrementalbuild.aggregator.InputSet; +import io.takari.maven.plugins.TakariLifecycleMojo; +import io.takari.maven.plugins.plugin.model.MojoDescriptor; +import io.takari.maven.plugins.plugin.model.MojoParameter; +import io.takari.maven.plugins.plugin.model.MojoRequirement; +import io.takari.maven.plugins.plugin.model.PluginDescriptor; +import io.takari.maven.plugins.plugin.model.io.xpp3.PluginDescriptorXpp3Reader; import java.io.File; import java.io.FileInputStream; import java.io.IOException; @@ -17,7 +35,6 @@ import java.util.stream.Collectors; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; - import org.apache.maven.artifact.Artifact; import org.apache.maven.model.Resource; import org.apache.maven.plugin.MojoExecutionException; @@ -30,307 +47,307 @@ import org.codehaus.plexus.util.xml.XMLWriter; import org.codehaus.plexus.util.xml.pull.XmlPullParserException; -import io.takari.incrementalbuild.Incremental; -import io.takari.incrementalbuild.Output; -import io.takari.incrementalbuild.aggregator.AggregatorBuildContext; -import io.takari.incrementalbuild.aggregator.InputAggregator; -import io.takari.incrementalbuild.aggregator.InputSet; -import io.takari.maven.plugins.TakariLifecycleMojo; -import io.takari.maven.plugins.plugin.model.MojoDescriptor; -import io.takari.maven.plugins.plugin.model.MojoParameter; -import io.takari.maven.plugins.plugin.model.MojoRequirement; -import io.takari.maven.plugins.plugin.model.PluginDescriptor; -import io.takari.maven.plugins.plugin.model.io.xpp3.PluginDescriptorXpp3Reader; - -@Mojo(name = "plugin-descriptor", defaultPhase = LifecyclePhase.PROCESS_CLASSES, threadSafe = true, requiresDependencyResolution = ResolutionScope.COMPILE) +@Mojo( + name = "plugin-descriptor", + defaultPhase = LifecyclePhase.PROCESS_CLASSES, + threadSafe = true, + requiresDependencyResolution = ResolutionScope.COMPILE) public class PluginDescriptorMojo extends TakariLifecycleMojo { - static final String PATH_MOJOS_XML = "META-INF/takari/mojos.xml"; + static final String PATH_MOJOS_XML = "META-INF/takari/mojos.xml"; - private static final String PATH_PLUGIN_XML = "META-INF/maven/plugin.xml"; + private static final String PATH_PLUGIN_XML = "META-INF/maven/plugin.xml"; - private static final String PATH_METADATA_XML = "META-INF/m2e/lifecycle-mapping-metadata.xml"; + private static final String PATH_METADATA_XML = "META-INF/m2e/lifecycle-mapping-metadata.xml"; - @Parameter(defaultValue = "${project.groupId}", readonly = true) - private String groupId; + @Parameter(defaultValue = "${project.groupId}", readonly = true) + private String groupId; - @Parameter(defaultValue = "${project.artifactId}", readonly = true) - private String artifactId; + @Parameter(defaultValue = "${project.artifactId}", readonly = true) + private String artifactId; - @Parameter(defaultValue = "${project.version}", readonly = true) - private String version; + @Parameter(defaultValue = "${project.version}", readonly = true) + private String version; - @Parameter(defaultValue = "${project.name}", readonly = true) - private String name; + @Parameter(defaultValue = "${project.name}", readonly = true) + private String name; - @Parameter(defaultValue = "${project.description}", readonly = true) - private String description; + @Parameter(defaultValue = "${project.description}", readonly = true) + private String description; - /** - * The goal prefix that will appear before the ":". - */ - @Parameter - private String goalPrefix; + /** + * The goal prefix that will appear before the ":". + */ + @Parameter + private String goalPrefix; - @Parameter(defaultValue = "${project.build.outputDirectory}", readonly = true) - private File outputDirectory; + @Parameter(defaultValue = "${project.build.outputDirectory}", readonly = true) + private File outputDirectory; - @Parameter(defaultValue = "${project.compileArtifacts}", readonly = true) - private List dependencies; + @Parameter(defaultValue = "${project.compileArtifacts}", readonly = true) + private List dependencies; - /** - * Hand-written m2e lifecycle mapping xml file location. - */ - @Parameter(defaultValue = "${project.basedir}/src/main/m2e/lifecycle-mapping-metadata.xml") - private File eclipseMetadataFile; + /** + * Hand-written m2e lifecycle mapping xml file location. + */ + @Parameter(defaultValue = "${project.basedir}/src/main/m2e/lifecycle-mapping-metadata.xml") + private File eclipseMetadataFile; - // TODO introduce Resource digester in io.takari.incrementalbuild.maven.internal.digest.Digesters - @Parameter(defaultValue = "${project.build.resources}", readonly = true) - @Incremental(configuration = ignore) - private List resources; + // TODO introduce Resource digester in io.takari.incrementalbuild.maven.internal.digest.Digesters + @Parameter(defaultValue = "${project.build.resources}", readonly = true) + @Incremental(configuration = ignore) + private List resources; - @Component - private AggregatorBuildContext context; + @Component + private AggregatorBuildContext context; + @Override + protected void executeMojo() throws MojoExecutionException { - @Override - protected void executeMojo() throws MojoExecutionException { + try { + File mojosXml = new File(outputDirectory, PATH_MOJOS_XML); + if (!mojosXml.isFile()) { + // the project does not have any mojos, don't create empty plugin.xml + return; + } - try { - File mojosXml = new File(outputDirectory, PATH_MOJOS_XML); - if (!mojosXml.isFile()) { - // the project does not have any mojos, don't create empty plugin.xml - return; - } + InputSet inputSet = context.newInputSet(); + + final Set classpathJars = new LinkedHashSet<>(); + final Set classpathFiles = new LinkedHashSet<>(); + for (Artifact artifact : dependencies) { + if (artifact.getFile().isFile()) { + classpathJars.add(inputSet.addInput(artifact.getFile())); + } else if (artifact.getFile().isDirectory()) { + File file = new File(artifact.getFile(), PATH_MOJOS_XML); + if (file.canRead()) { + classpathFiles.add(inputSet.addInput(file)); + } + } + } + inputSet.addInput(new File(outputDirectory, PATH_MOJOS_XML)); - InputSet inputSet = context.newInputSet(); + if (eclipseMetadataFile.isFile()) { + inputSet.addInput(eclipseMetadataFile); + } - final Set classpathJars = new LinkedHashSet<>(); - final Set classpathFiles = new LinkedHashSet<>(); - for (Artifact artifact : dependencies) { - if (artifact.getFile().isFile()) { - classpathJars.add(inputSet.addInput(artifact.getFile())); - } else if (artifact.getFile().isDirectory()) { - File file = new File(artifact.getFile(), PATH_MOJOS_XML); - if (file.canRead()) { - classpathFiles.add(inputSet.addInput(file)); - } - } - } - inputSet.addInput(new File(outputDirectory, PATH_MOJOS_XML)); - - if (eclipseMetadataFile.isFile()) { - inputSet.addInput(eclipseMetadataFile); - } - - // fail the build if m2e lifecycle mapping metadata is found among project - // the metadata will be overwritten by #createEclipseMetadataXml, which almost certainly not what the user expects - for (Resource resource : resources) { - File otherEclipseMetadataFile = new File(resource.getDirectory(), PATH_METADATA_XML); - if (otherEclipseMetadataFile.isFile()) { - throw new MojoExecutionException(String.format("Unexpected Eclipse m2e metadata found %s. Did you mean to move it to %s", otherEclipseMetadataFile, eclipseMetadataFile)); - } - } + // fail the build if m2e lifecycle mapping metadata is found among project + // the metadata will be overwritten by #createEclipseMetadataXml, which almost certainly not what the user + // expects + for (Resource resource : resources) { + File otherEclipseMetadataFile = new File(resource.getDirectory(), PATH_METADATA_XML); + if (otherEclipseMetadataFile.isFile()) { + throw new MojoExecutionException(String.format( + "Unexpected Eclipse m2e metadata found %s. Did you mean to move it to %s", + otherEclipseMetadataFile, eclipseMetadataFile)); + } + } - inputSet.aggregateIfNecessary(new File(outputDirectory, PATH_PLUGIN_XML), new InputAggregator() { - @Override - public void aggregate(Output output, Iterable inputs) throws IOException { - createPluginXml(output, mojosXml, classpathFiles, classpathJars); + inputSet.aggregateIfNecessary(new File(outputDirectory, PATH_PLUGIN_XML), new InputAggregator() { + @Override + public void aggregate(Output output, Iterable inputs) throws IOException { + createPluginXml(output, mojosXml, classpathFiles, classpathJars); + } + }); + inputSet.aggregateIfNecessary(new File(outputDirectory, PATH_METADATA_XML), new InputAggregator() { + @Override + public void aggregate(Output output, Iterable inputs) throws IOException { + createEclipseMetadataXml(output, mojosXml, eclipseMetadataFile); + } + }); + + } catch (IOException e) { + throw new MojoExecutionException("Could not create plugin descriptor", e); } - }); - inputSet.aggregateIfNecessary(new File(outputDirectory, PATH_METADATA_XML), new InputAggregator() { - @Override - public void aggregate(Output output, Iterable inputs) throws IOException { - createEclipseMetadataXml(output, mojosXml, eclipseMetadataFile); - } - }); - - } catch (IOException e) { - throw new MojoExecutionException("Could not create plugin descriptor", e); } - } - protected void createPluginXml(Output output, File input, Set classpathFiles, Set classpathJars) throws IOException { - Map classpathMojos = loadClasspathMojos(classpathFiles, classpathJars); - Map mojos = loadMojos(input); + protected void createPluginXml(Output output, File input, Set classpathFiles, Set classpathJars) + throws IOException { + Map classpathMojos = loadClasspathMojos(classpathFiles, classpathJars); + Map mojos = loadMojos(input); - PluginDescriptor plugin = newPluginDescriptor(); + PluginDescriptor plugin = newPluginDescriptor(); - for (MojoDescriptor gleaned : mojos.values()) { - MojoDescriptor descriptor = gleaned.clone(); + for (MojoDescriptor gleaned : mojos.values()) { + MojoDescriptor descriptor = gleaned.clone(); - if (descriptor.getGoal() == null) { - continue; // abstract mojo, skip - } - - for (String parent : descriptor.getSuperclasses()) { - MojoDescriptor inherited = mojos.get(parent); - if (inherited == null) { - inherited = classpathMojos.get(parent); - } - if (inherited != null) { - for (MojoParameter parameter : inherited.getParameters()) { - if (!containsField(descriptor, parameter.getName())) { - descriptor.addParameter(parameter.clone()); + if (descriptor.getGoal() == null) { + continue; // abstract mojo, skip } - } - for (MojoRequirement requirement : inherited.getRequirements()) { - if (!containsField(descriptor, requirement.getFieldName())) { - descriptor.addRequirement(requirement.clone()); + + for (String parent : descriptor.getSuperclasses()) { + MojoDescriptor inherited = mojos.get(parent); + if (inherited == null) { + inherited = classpathMojos.get(parent); + } + if (inherited != null) { + for (MojoParameter parameter : inherited.getParameters()) { + if (!containsField(descriptor, parameter.getName())) { + descriptor.addParameter(parameter.clone()); + } + } + for (MojoRequirement requirement : inherited.getRequirements()) { + if (!containsField(descriptor, requirement.getFieldName())) { + descriptor.addRequirement(requirement.clone()); + } + } + } } - } + plugin.addMojo(descriptor); } - } - plugin.addMojo(descriptor); - } - try (OutputStream out = output.newOutputStream()) { - new PluginDescriptorWriter().writeDescriptor(out, plugin); + try (OutputStream out = output.newOutputStream()) { + new PluginDescriptorWriter().writeDescriptor(out, plugin); + } } - } - private boolean containsField(MojoDescriptor descriptor, String fieldName) { - for (MojoParameter parameter : descriptor.getParameters()) { - if (fieldName.equals(parameter.getName())) { - return true; - } - } - for (MojoRequirement requirement : descriptor.getRequirements()) { - if (fieldName.equals(requirement.getFieldName())) { - return true; - } - } - return false; - } - - private Map loadMojos(File mojosXml) throws IOException { - Map mojos = new HashMap<>(); - try (InputStream is = new FileInputStream(mojosXml)) { - readMojosXml(mojos, is); - } catch (XmlPullParserException e) { - throw new IOException(e); - } - return mojos; - } - - private Map loadClasspathMojos(Set files, Set jars) { - Map mojos = new HashMap<>(); - for (File jarFile : jars) { - try (ZipFile zip = new ZipFile(jarFile)) { - ZipEntry entry = zip.getEntry(PATH_MOJOS_XML); - if (entry != null) { - try (InputStream is = zip.getInputStream(entry)) { - readMojosXml(mojos, is); - } - continue; + private boolean containsField(MojoDescriptor descriptor, String fieldName) { + for (MojoParameter parameter : descriptor.getParameters()) { + if (fieldName.equals(parameter.getName())) { + return true; + } } - entry = zip.getEntry(PATH_PLUGIN_XML); - if (entry != null) { - try (InputStream is = zip.getInputStream(entry)) { - readPluginXml(mojos, is); - } - continue; + for (MojoRequirement requirement : descriptor.getRequirements()) { + if (fieldName.equals(requirement.getFieldName())) { + return true; + } } - } catch (XmlPullParserException | IOException e) { - logger.warn("Could not read dependency mojos.xml " + jarFile, e); - } + return false; } - for (File mojosXmlFile : files) { - try (InputStream is = new FileInputStream(mojosXmlFile)) { - readMojosXml(mojos, is); - } catch (XmlPullParserException | IOException e) { - logger.warn("Could not read dependency mojos.xml " + mojosXmlFile, e); - } + + private Map loadMojos(File mojosXml) throws IOException { + Map mojos = new HashMap<>(); + try (InputStream is = new FileInputStream(mojosXml)) { + readMojosXml(mojos, is); + } catch (XmlPullParserException e) { + throw new IOException(e); + } + return mojos; } - return mojos; - } + private Map loadClasspathMojos(Set files, Set jars) { + Map mojos = new HashMap<>(); + for (File jarFile : jars) { + try (ZipFile zip = new ZipFile(jarFile)) { + ZipEntry entry = zip.getEntry(PATH_MOJOS_XML); + if (entry != null) { + try (InputStream is = zip.getInputStream(entry)) { + readMojosXml(mojos, is); + } + continue; + } + entry = zip.getEntry(PATH_PLUGIN_XML); + if (entry != null) { + try (InputStream is = zip.getInputStream(entry)) { + readPluginXml(mojos, is); + } + continue; + } + } catch (XmlPullParserException | IOException e) { + logger.warn("Could not read dependency mojos.xml " + jarFile, e); + } + } + for (File mojosXmlFile : files) { + try (InputStream is = new FileInputStream(mojosXmlFile)) { + readMojosXml(mojos, is); + } catch (XmlPullParserException | IOException e) { + logger.warn("Could not read dependency mojos.xml " + mojosXmlFile, e); + } + } - private void readMojosXml(Map mojos, InputStream is) throws XmlPullParserException, IOException { - PluginDescriptor pluginDescriptor = new PluginDescriptorXpp3Reader().read(is); - for (MojoDescriptor mojo : pluginDescriptor.getMojos()) { - mojos.put(mojo.getImplementation(), mojo); + return mojos; } - } - private void readPluginXml(Map mojos, InputStream is) throws XmlPullParserException, IOException { - for (MojoDescriptor mojo : LegacyPluginDescriptors.readMojos(is)) { - mojos.put(mojo.getImplementation(), mojo); + private void readMojosXml(Map mojos, InputStream is) + throws XmlPullParserException, IOException { + PluginDescriptor pluginDescriptor = new PluginDescriptorXpp3Reader().read(is); + for (MojoDescriptor mojo : pluginDescriptor.getMojos()) { + mojos.put(mojo.getImplementation(), mojo); + } } - } - - private PluginDescriptor newPluginDescriptor() { - String defaultGoalPrefix = org.apache.maven.plugin.descriptor.PluginDescriptor.getGoalPrefixFromArtifactId(artifactId); - if (goalPrefix == null) { - goalPrefix = defaultGoalPrefix; - } else if (!goalPrefix.equals(defaultGoalPrefix)) { - getLog().warn("\n\nGoal prefix is specified as: '" + goalPrefix + "'. " + "Maven currently expects it to be '" + defaultGoalPrefix + "'.\n"); + + private void readPluginXml(Map mojos, InputStream is) + throws XmlPullParserException, IOException { + for (MojoDescriptor mojo : LegacyPluginDescriptors.readMojos(is)) { + mojos.put(mojo.getImplementation(), mojo); + } } - PluginDescriptor pluginDescriptor = new PluginDescriptor(); - pluginDescriptor.setGroupId(groupId); - pluginDescriptor.setArtifactId(artifactId); - pluginDescriptor.setVersion(version); - pluginDescriptor.setGoalPrefix(goalPrefix); - pluginDescriptor.setName(name); - pluginDescriptor.setDescription(description); - pluginDescriptor.setInheritedByDefault(true); // see org.apache.maven.plugin.descriptor.PluginDescriptor.inheritedByDefault - - return pluginDescriptor; - } - - protected void createEclipseMetadataXml(Output output, File mojosXml, File existingEclipseMetadataXml) throws IOException { - try (OutputStream out = output.newOutputStream()) { - if (existingEclipseMetadataXml.isFile()) { - try (InputStream in = Files.newInputStream(existingEclipseMetadataXml.toPath())) { - in.transferTo(out); + private PluginDescriptor newPluginDescriptor() { + String defaultGoalPrefix = + org.apache.maven.plugin.descriptor.PluginDescriptor.getGoalPrefixFromArtifactId(artifactId); + if (goalPrefix == null) { + goalPrefix = defaultGoalPrefix; + } else if (!goalPrefix.equals(defaultGoalPrefix)) { + getLog().warn("\n\nGoal prefix is specified as: '" + goalPrefix + "'. " + + "Maven currently expects it to be '" + defaultGoalPrefix + "'.\n"); } - } else { - Map mojos = loadMojos(mojosXml); - List goals = mojos.values().stream() - .filter( MojoDescriptor::isTakariBuilder ) - .map( MojoDescriptor::getGoal ) - .collect(Collectors.toList()); - - writeEclipseMetadataXml(out, goals); - } + + PluginDescriptor pluginDescriptor = new PluginDescriptor(); + pluginDescriptor.setGroupId(groupId); + pluginDescriptor.setArtifactId(artifactId); + pluginDescriptor.setVersion(version); + pluginDescriptor.setGoalPrefix(goalPrefix); + pluginDescriptor.setName(name); + pluginDescriptor.setDescription(description); + pluginDescriptor.setInheritedByDefault( + true); // see org.apache.maven.plugin.descriptor.PluginDescriptor.inheritedByDefault + + return pluginDescriptor; } - } - - private void writeEclipseMetadataXml(OutputStream out, List goals) throws IOException { - OutputStreamWriter writer = new OutputStreamWriter(out, "UTF-8"); - XMLWriter w = new PrettyPrintXMLWriter(writer, "UTF-8", null); - - w.writeMarkup("\n\n\n"); - - w.startElement("lifecycleMappingMetadata"); - if (!goals.isEmpty()) { - w.startElement("pluginExecutions"); - w.startElement("pluginExecution"); - w.startElement("pluginExecutionFilter"); - w.startElement("goals"); - goals.forEach(g -> writeGoalElement(w, g)); - w.endElement(); // goals - w.endElement(); // pluginExecutionFilter - w.startElement("action"); - w.startElement("configurator"); - w.startElement("id"); - w.writeText("io.takari.m2e.incrementalbuild.builderMojoExecutionConfigurator"); - w.endElement(); // id - w.endElement(); // configurator - w.endElement(); // action - w.endElement(); // pluginExecution - w.endElement(); // pluginExecutions + + protected void createEclipseMetadataXml(Output output, File mojosXml, File existingEclipseMetadataXml) + throws IOException { + try (OutputStream out = output.newOutputStream()) { + if (existingEclipseMetadataXml.isFile()) { + try (InputStream in = Files.newInputStream(existingEclipseMetadataXml.toPath())) { + in.transferTo(out); + } + } else { + Map mojos = loadMojos(mojosXml); + List goals = mojos.values().stream() + .filter(MojoDescriptor::isTakariBuilder) + .map(MojoDescriptor::getGoal) + .collect(Collectors.toList()); + + writeEclipseMetadataXml(out, goals); + } + } } - w.endElement(); // lifecycleMappingMetadata - writer.close(); - } + private void writeEclipseMetadataXml(OutputStream out, List goals) throws IOException { + OutputStreamWriter writer = new OutputStreamWriter(out, "UTF-8"); + XMLWriter w = new PrettyPrintXMLWriter(writer, "UTF-8", null); + + w.writeMarkup("\n\n\n"); + + w.startElement("lifecycleMappingMetadata"); + if (!goals.isEmpty()) { + w.startElement("pluginExecutions"); + w.startElement("pluginExecution"); + w.startElement("pluginExecutionFilter"); + w.startElement("goals"); + goals.forEach(g -> writeGoalElement(w, g)); + w.endElement(); // goals + w.endElement(); // pluginExecutionFilter + w.startElement("action"); + w.startElement("configurator"); + w.startElement("id"); + w.writeText("io.takari.m2e.incrementalbuild.builderMojoExecutionConfigurator"); + w.endElement(); // id + w.endElement(); // configurator + w.endElement(); // action + w.endElement(); // pluginExecution + w.endElement(); // pluginExecutions + } + w.endElement(); // lifecycleMappingMetadata - private void writeGoalElement(XMLWriter w, String goal) { - w.startElement("goal"); - w.writeText(goal); - w.endElement(); - } + writer.close(); + } + private void writeGoalElement(XMLWriter w, String goal) { + w.startElement("goal"); + w.writeText(goal); + w.endElement(); + } } diff --git a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/plugin/PluginDescriptorWriter.java b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/plugin/PluginDescriptorWriter.java index cdbfcba6..66e29452 100644 --- a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/plugin/PluginDescriptorWriter.java +++ b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/plugin/PluginDescriptorWriter.java @@ -1,3 +1,10 @@ +/* + * Copyright (c) 2014-2024 Takari, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v10.html + */ package io.takari.maven.plugins.plugin; /* @@ -19,6 +26,11 @@ * under the License. */ +import io.takari.maven.plugins.plugin.model.MojoDescriptor; +import io.takari.maven.plugins.plugin.model.MojoParameter; +import io.takari.maven.plugins.plugin.model.MojoRequirement; +import io.takari.maven.plugins.plugin.model.PluginDependency; +import io.takari.maven.plugins.plugin.model.PluginDescriptor; import java.io.IOException; import java.io.OutputStream; import java.io.OutputStreamWriter; @@ -26,198 +38,192 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Set; - import org.codehaus.plexus.util.StringUtils; import org.codehaus.plexus.util.xml.PrettyPrintXMLWriter; import org.codehaus.plexus.util.xml.XMLWriter; -import io.takari.maven.plugins.plugin.model.MojoDescriptor; -import io.takari.maven.plugins.plugin.model.MojoParameter; -import io.takari.maven.plugins.plugin.model.MojoRequirement; -import io.takari.maven.plugins.plugin.model.PluginDependency; -import io.takari.maven.plugins.plugin.model.PluginDescriptor; - // originally copied from org.apache.maven.tools.plugin.generator.PluginDescriptorGenerator class PluginDescriptorWriter { - private static final String encoding = "UTF-8"; - - public void writeDescriptor(OutputStream outputStream, PluginDescriptor pluginDescriptor) throws IOException { - OutputStreamWriter writer = new OutputStreamWriter(outputStream, encoding); - - XMLWriter w = new PrettyPrintXMLWriter(writer, encoding, null); - - w.writeMarkup("\n\n\n"); - w.startElement("plugin"); - element(w, "name", pluginDescriptor.getName()); - element(w, "description", pluginDescriptor.getDescription()); - element(w, "groupId", pluginDescriptor.getGroupId()); - element(w, "artifactId", pluginDescriptor.getArtifactId()); - element(w, "version", pluginDescriptor.getVersion()); - element(w, "goalPrefix", pluginDescriptor.getGoalPrefix()); - element(w, "isolatedRealm", String.valueOf(pluginDescriptor.isIsolatedRealm())); - element(w, "inheritedByDefault", String.valueOf(pluginDescriptor.isInheritedByDefault())); - writeMojos(w, pluginDescriptor); - writeDependencies(w, pluginDescriptor); - w.endElement(); - - writer.flush(); - } - - private void writeMojos(XMLWriter w, PluginDescriptor pluginDescriptor) { - w.startElement("mojos"); - List descriptors = new ArrayList<>(pluginDescriptor.getMojos()); - Sorting.sortDescriptors(descriptors); - for (MojoDescriptor descriptor : descriptors) { - writeMojoDescriptor(descriptor, w); + private static final String encoding = "UTF-8"; + + public void writeDescriptor(OutputStream outputStream, PluginDescriptor pluginDescriptor) throws IOException { + OutputStreamWriter writer = new OutputStreamWriter(outputStream, encoding); + + XMLWriter w = new PrettyPrintXMLWriter(writer, encoding, null); + + w.writeMarkup("\n\n\n"); + w.startElement("plugin"); + element(w, "name", pluginDescriptor.getName()); + element(w, "description", pluginDescriptor.getDescription()); + element(w, "groupId", pluginDescriptor.getGroupId()); + element(w, "artifactId", pluginDescriptor.getArtifactId()); + element(w, "version", pluginDescriptor.getVersion()); + element(w, "goalPrefix", pluginDescriptor.getGoalPrefix()); + element(w, "isolatedRealm", String.valueOf(pluginDescriptor.isIsolatedRealm())); + element(w, "inheritedByDefault", String.valueOf(pluginDescriptor.isInheritedByDefault())); + writeMojos(w, pluginDescriptor); + writeDependencies(w, pluginDescriptor); + w.endElement(); + + writer.flush(); } - w.endElement(); - } - - private void writeDependencies(XMLWriter w, PluginDescriptor pluginDescriptor) { - w.startElement("dependencies"); - List deps = pluginDescriptor.getDependencies(); - for (PluginDependency dep : deps) { - w.startElement("dependency"); - element(w, "groupId", dep.getGroupId()); - element(w, "artifactId", dep.getArtifactId()); - element(w, "type", dep.getType()); - element(w, "version", dep.getVersion()); - w.endElement(); + + private void writeMojos(XMLWriter w, PluginDescriptor pluginDescriptor) { + w.startElement("mojos"); + List descriptors = new ArrayList<>(pluginDescriptor.getMojos()); + Sorting.sortDescriptors(descriptors); + for (MojoDescriptor descriptor : descriptors) { + writeMojoDescriptor(descriptor, w); + } + w.endElement(); } - w.endElement(); - } - - private void element(XMLWriter w, String name, String value) { - if (StringUtils.isNotEmpty(value)) { - w.startElement(name); - w.writeText(value != null ? value : ""); - w.endElement(); + + private void writeDependencies(XMLWriter w, PluginDescriptor pluginDescriptor) { + w.startElement("dependencies"); + List deps = pluginDescriptor.getDependencies(); + for (PluginDependency dep : deps) { + w.startElement("dependency"); + element(w, "groupId", dep.getGroupId()); + element(w, "artifactId", dep.getArtifactId()); + element(w, "type", dep.getType()); + element(w, "version", dep.getVersion()); + w.endElement(); + } + w.endElement(); } - } - - /** - * @param mojoDescriptor not null - * @param w not null - * @param helpDescriptor will clean html content from description fields - */ - protected void writeMojoDescriptor(MojoDescriptor mojoDescriptor, XMLWriter w) { - w.startElement("mojo"); - - element(w, "goal", mojoDescriptor.getGoal()); - element(w, "description", mojoDescriptor.getDescription()); - - element(w, "requiresDependencyResolution", mojoDescriptor.getRequiresDependencyResolution()); - element(w, "requiresDependencyCollection", mojoDescriptor.getRequiresDependencyCollection()); - element(w, "requiresDirectInvocation", String.valueOf(mojoDescriptor.isRequiresDirectInvocation())); - element(w, "requiresProject", String.valueOf(mojoDescriptor.isRequiresProject())); - element(w, "requiresReports", String.valueOf(mojoDescriptor.isRequiresReports())); - element(w, "aggregator", String.valueOf(mojoDescriptor.isAggregator())); - element(w, "requiresOnline", String.valueOf(mojoDescriptor.isRequiresOnline())); - element(w, "inheritedByDefault", String.valueOf(mojoDescriptor.isInheritedByDefault())); - element(w, "phase", mojoDescriptor.getPhase()); - element(w, "threadSafe", String.valueOf(mojoDescriptor.isThreadSafe())); - element(w, "implementation", mojoDescriptor.getImplementation()); - element(w, "language", mojoDescriptor.getLanguage()); - element(w, "configurator", mojoDescriptor.getConfigurator()); - element(w, "instantiationStrategy", mojoDescriptor.getInstantiationStrategy()); - - // Strategy for handling repeated reference to mojo in - // the calculated (decorated, resolved) execution stack - element(w, "executionStrategy", mojoDescriptor.getExecutionStrategy()); - - // if (StringUtils.isNotEmpty(mojoDescriptor.getExecutePhase())) { - // element(w, "executePhase", mojoDescriptor.getExecutePhase()); - // } - - // if (StringUtils.isNotEmpty(mojoDescriptor.getExecuteGoal())) { - // element(w, "executeGoal", mojoDescriptor.getExecuteGoal()); - // } - - // if (StringUtils.isNotEmpty(mojoDescriptor.getExecuteLifecycle())) { - // element(w, "executeLifecycle", mojoDescriptor.getExecuteLifecycle()); - // } - - // if (StringUtils.isNotEmpty(mojoDescriptor.getComponentComposer())) { - // w.startElement("composer"); - // w.writeText(mojoDescriptor.getComponentComposer()); - // w.endElement(); - // } - - element(w, "since", mojoDescriptor.getSince()); - element(w, "deprecated", mojoDescriptor.getDeprecated()); - - // ---------------------------------------------------------------------- - // Parameters - // ---------------------------------------------------------------------- - - Set configuration = new LinkedHashSet(); - - w.startElement("parameters"); - List parameters = new ArrayList<>(mojoDescriptor.getParameters()); - Sorting.sortParameters(parameters); - for (MojoParameter parameter : parameters) { - w.startElement("parameter"); - element(w, "name", parameter.getName()); - element(w, "alias", parameter.getAlias()); - element(w, "type", parameter.getType()); - element(w, "since", parameter.getSince()); - element(w, "deprecated", parameter.getDeprecated()); - element(w, "implementation", parameter.getImplementation()); - element(w, "required", Boolean.toString(parameter.isRequired())); - element(w, "editable", Boolean.toString(parameter.isEditable())); - element(w, "description", parameter.getDescription()); - w.endElement(); - - if (StringUtils.isNotEmpty(parameter.getDefaultValue()) || StringUtils.isNotEmpty(parameter.getExpression())) { - configuration.add(parameter); - } + + private void element(XMLWriter w, String name, String value) { + if (StringUtils.isNotEmpty(value)) { + w.startElement(name); + w.writeText(value != null ? value : ""); + w.endElement(); + } } - w.endElement(); + /** + * @param mojoDescriptor not null + * @param w not null + * @param helpDescriptor will clean html content from description fields + */ + protected void writeMojoDescriptor(MojoDescriptor mojoDescriptor, XMLWriter w) { + w.startElement("mojo"); + + element(w, "goal", mojoDescriptor.getGoal()); + element(w, "description", mojoDescriptor.getDescription()); + + element(w, "requiresDependencyResolution", mojoDescriptor.getRequiresDependencyResolution()); + element(w, "requiresDependencyCollection", mojoDescriptor.getRequiresDependencyCollection()); + element(w, "requiresDirectInvocation", String.valueOf(mojoDescriptor.isRequiresDirectInvocation())); + element(w, "requiresProject", String.valueOf(mojoDescriptor.isRequiresProject())); + element(w, "requiresReports", String.valueOf(mojoDescriptor.isRequiresReports())); + element(w, "aggregator", String.valueOf(mojoDescriptor.isAggregator())); + element(w, "requiresOnline", String.valueOf(mojoDescriptor.isRequiresOnline())); + element(w, "inheritedByDefault", String.valueOf(mojoDescriptor.isInheritedByDefault())); + element(w, "phase", mojoDescriptor.getPhase()); + element(w, "threadSafe", String.valueOf(mojoDescriptor.isThreadSafe())); + element(w, "implementation", mojoDescriptor.getImplementation()); + element(w, "language", mojoDescriptor.getLanguage()); + element(w, "configurator", mojoDescriptor.getConfigurator()); + element(w, "instantiationStrategy", mojoDescriptor.getInstantiationStrategy()); + + // Strategy for handling repeated reference to mojo in + // the calculated (decorated, resolved) execution stack + element(w, "executionStrategy", mojoDescriptor.getExecutionStrategy()); + + // if (StringUtils.isNotEmpty(mojoDescriptor.getExecutePhase())) { + // element(w, "executePhase", mojoDescriptor.getExecutePhase()); + // } + + // if (StringUtils.isNotEmpty(mojoDescriptor.getExecuteGoal())) { + // element(w, "executeGoal", mojoDescriptor.getExecuteGoal()); + // } + + // if (StringUtils.isNotEmpty(mojoDescriptor.getExecuteLifecycle())) { + // element(w, "executeLifecycle", mojoDescriptor.getExecuteLifecycle()); + // } + + // if (StringUtils.isNotEmpty(mojoDescriptor.getComponentComposer())) { + // w.startElement("composer"); + // w.writeText(mojoDescriptor.getComponentComposer()); + // w.endElement(); + // } + + element(w, "since", mojoDescriptor.getSince()); + element(w, "deprecated", mojoDescriptor.getDeprecated()); + + // ---------------------------------------------------------------------- + // Parameters + // ---------------------------------------------------------------------- + + Set configuration = new LinkedHashSet(); + + w.startElement("parameters"); + List parameters = new ArrayList<>(mojoDescriptor.getParameters()); + Sorting.sortParameters(parameters); + for (MojoParameter parameter : parameters) { + w.startElement("parameter"); + element(w, "name", parameter.getName()); + element(w, "alias", parameter.getAlias()); + element(w, "type", parameter.getType()); + element(w, "since", parameter.getSince()); + element(w, "deprecated", parameter.getDeprecated()); + element(w, "implementation", parameter.getImplementation()); + element(w, "required", Boolean.toString(parameter.isRequired())); + element(w, "editable", Boolean.toString(parameter.isEditable())); + element(w, "description", parameter.getDescription()); + w.endElement(); + + if (StringUtils.isNotEmpty(parameter.getDefaultValue()) + || StringUtils.isNotEmpty(parameter.getExpression())) { + configuration.add(parameter); + } + } - // ---------------------------------------------------------------------- - // Configuration - // ---------------------------------------------------------------------- + w.endElement(); - if (!configuration.isEmpty()) { - w.startElement("configuration"); + // ---------------------------------------------------------------------- + // Configuration + // ---------------------------------------------------------------------- - for (MojoParameter parameter : configuration) { - w.startElement(parameter.getName()); + if (!configuration.isEmpty()) { + w.startElement("configuration"); - String type = parameter.getType(); - if (StringUtils.isNotEmpty(type)) { - w.addAttribute("implementation", type); - } + for (MojoParameter parameter : configuration) { + w.startElement(parameter.getName()); - if (parameter.getDefaultValue() != null) { - w.addAttribute("default-value", parameter.getDefaultValue()); - } + String type = parameter.getType(); + if (StringUtils.isNotEmpty(type)) { + w.addAttribute("implementation", type); + } - if (StringUtils.isNotEmpty(parameter.getExpression())) { - w.writeText(parameter.getExpression()); - } + if (parameter.getDefaultValue() != null) { + w.addAttribute("default-value", parameter.getDefaultValue()); + } - w.endElement(); - } + if (StringUtils.isNotEmpty(parameter.getExpression())) { + w.writeText(parameter.getExpression()); + } - w.endElement(); - } + w.endElement(); + } + + w.endElement(); + } + + List requirements = new ArrayList<>(mojoDescriptor.getRequirements()); + if (!requirements.isEmpty()) { + Sorting.sortRequirements(requirements); + w.startElement("requirements"); + for (MojoRequirement requirement : requirements) { + w.startElement("requirement"); + element(w, "role", requirement.getRole()); + element(w, "role-hint", requirement.getRoleHint()); + element(w, "field-name", requirement.getFieldName()); + w.endElement(); + } + w.endElement(); + } - List requirements = new ArrayList<>(mojoDescriptor.getRequirements()); - if (!requirements.isEmpty()) { - Sorting.sortRequirements(requirements); - w.startElement("requirements"); - for (MojoRequirement requirement : requirements) { - w.startElement("requirement"); - element(w, "role", requirement.getRole()); - element(w, "role-hint", requirement.getRoleHint()); - element(w, "field-name", requirement.getFieldName()); w.endElement(); - } - w.endElement(); } - - w.endElement(); - } } diff --git a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/plugin/Sorting.java b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/plugin/Sorting.java index 9954dce0..58a46f26 100644 --- a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/plugin/Sorting.java +++ b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/plugin/Sorting.java @@ -1,39 +1,45 @@ +/* + * Copyright (c) 2014-2024 Takari, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v10.html + */ package io.takari.maven.plugins.plugin; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; - import io.takari.maven.plugins.plugin.model.MojoDescriptor; import io.takari.maven.plugins.plugin.model.MojoParameter; import io.takari.maven.plugins.plugin.model.MojoRequirement; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; class Sorting { - public static void sortDescriptors(List descriptors) { - Collections.sort(descriptors, new Comparator() { - @Override - public int compare(MojoDescriptor p1, MojoDescriptor p2) { - return p1.getImplementation().compareTo(p2.getImplementation()); - } - }); - } + public static void sortDescriptors(List descriptors) { + Collections.sort(descriptors, new Comparator() { + @Override + public int compare(MojoDescriptor p1, MojoDescriptor p2) { + return p1.getImplementation().compareTo(p2.getImplementation()); + } + }); + } - public static void sortParameters(List parameters) { - Collections.sort(parameters, new Comparator() { - @Override - public int compare(MojoParameter p1, MojoParameter p2) { - return p1.getName().compareTo(p2.getName()); - } - }); - } + public static void sortParameters(List parameters) { + Collections.sort(parameters, new Comparator() { + @Override + public int compare(MojoParameter p1, MojoParameter p2) { + return p1.getName().compareTo(p2.getName()); + } + }); + } - public static void sortRequirements(List requirements) { - Collections.sort(requirements, new Comparator() { - @Override - public int compare(MojoRequirement p1, MojoRequirement p2) { - return p1.getFieldName().compareTo(p2.getFieldName()); - } - }); - } + public static void sortRequirements(List requirements) { + Collections.sort(requirements, new Comparator() { + @Override + public int compare(MojoRequirement p1, MojoRequirement p2) { + return p1.getFieldName().compareTo(p2.getFieldName()); + } + }); + } } diff --git a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/resources/AbstractProcessResourcesMojo.java b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/resources/AbstractProcessResourcesMojo.java index edf1077f..68576ed1 100644 --- a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/resources/AbstractProcessResourcesMojo.java +++ b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/resources/AbstractProcessResourcesMojo.java @@ -1,12 +1,18 @@ -/** - * Copyright (c) 2014 Takari, Inc. +/* + * Copyright (c) 2014-2024 Takari, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * https://www.eclipse.org/legal/epl-v10.html */ package io.takari.maven.plugins.resources; +import io.takari.incrementalbuild.BuildContext; +import io.takari.incrementalbuild.Incremental; +import io.takari.incrementalbuild.Incremental.Configuration; +import io.takari.maven.plugins.TakariLifecycleMojo; +import io.takari.resources.filtering.MissingPropertyAction; +import io.takari.resources.filtering.ResourcesProcessor; import java.io.File; import java.io.IOException; import java.util.HashMap; @@ -14,98 +20,105 @@ import java.util.Map; import java.util.Properties; import java.util.stream.Collectors; - import org.apache.maven.model.Resource; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugins.annotations.Component; import org.apache.maven.plugins.annotations.Parameter; -import io.takari.incrementalbuild.BuildContext; -import io.takari.incrementalbuild.Incremental; -import io.takari.incrementalbuild.Incremental.Configuration; -import io.takari.maven.plugins.TakariLifecycleMojo; -import io.takari.resources.filtering.MissingPropertyAction; -import io.takari.resources.filtering.ResourcesProcessor; - public abstract class AbstractProcessResourcesMojo extends TakariLifecycleMojo { - /** - * Sets what should be the outcome when filtering hits a missing property. - *

- * Allowed values are: - *

- *
    - *
  • empty - The filtered value will be empty string (default).
  • - *
  • leave - The filtered value will be left as-is, unfiltered (basically the expression itself, mimics maven-resources-plugin).
  • - *
  • fail - Missing property will be reported as error and fails the build.
  • - *
- * - * @since 1.13.4 - */ - @Parameter - protected MissingPropertyAction missingPropertyAction = MissingPropertyAction.DEFAULT; + /** + * Sets what should be the outcome when filtering hits a missing property. + *

+ * Allowed values are: + *

+ *
    + *
  • empty - The filtered value will be empty string (default).
  • + *
  • leave - The filtered value will be left as-is, unfiltered (basically the expression itself, mimics maven-resources-plugin).
  • + *
  • fail - Missing property will be reported as error and fails the build.
  • + *
+ * + * @since 1.13.4 + */ + @Parameter + protected MissingPropertyAction missingPropertyAction = MissingPropertyAction.DEFAULT; - @Parameter(defaultValue = "${project.properties}") - @Incremental(configuration = Configuration.ignore) - private Properties properties; + @Parameter(defaultValue = "${project.properties}") + @Incremental(configuration = Configuration.ignore) + private Properties properties; - @Parameter(defaultValue = "${session.executionProperties}") - @Incremental(configuration = Configuration.ignore) - private Properties sessionProperties; + @Parameter(defaultValue = "${session.executionProperties}") + @Incremental(configuration = Configuration.ignore) + private Properties sessionProperties; - // - // use explicit reflective properties instead of wider objects like MavenSession or Settings - // this way resources will be properly reprocessed whenever the properties change - // + // + // use explicit reflective properties instead of wider objects like MavenSession or Settings + // this way resources will be properly reprocessed whenever the properties change + // - @Parameter(defaultValue = "${session.request.userSettingsFile}") - @Incremental(configuration = Configuration.ignore) - private File userSettingsFile; + @Parameter(defaultValue = "${session.request.userSettingsFile}") + @Incremental(configuration = Configuration.ignore) + private File userSettingsFile; - @Parameter(property = "encoding", defaultValue = "${project.build.sourceEncoding}") - private String encoding; + @Parameter(property = "encoding", defaultValue = "${project.build.sourceEncoding}") + private String encoding; - @Component - private ResourcesProcessor processor; + @Component + private ResourcesProcessor processor; - @Component - private BuildContext context; + @Component + private BuildContext context; - protected void process(List resources, File outputDirectory) throws MojoExecutionException { - for (Resource resource : resources) { - boolean filter = Boolean.parseBoolean(resource.getFiltering()); - try { - File sourceDirectory = new File(resource.getDirectory()); - // Ensure the sourceDirectory is actually present before attempting to process any resources - if (!sourceDirectory.exists()) { - continue; - } - sourceDirectory = sourceDirectory.getCanonicalFile(); - File targetDirectory; - if (resource.getTargetPath() != null) { - targetDirectory = new File(outputDirectory, resource.getTargetPath()); - } else { - targetDirectory = outputDirectory; + protected void process(List resources, File outputDirectory) throws MojoExecutionException { + for (Resource resource : resources) { + boolean filter = Boolean.parseBoolean(resource.getFiltering()); + try { + File sourceDirectory = new File(resource.getDirectory()); + // Ensure the sourceDirectory is actually present before attempting to process any resources + if (!sourceDirectory.exists()) { + continue; + } + sourceDirectory = sourceDirectory.getCanonicalFile(); + File targetDirectory; + if (resource.getTargetPath() != null) { + targetDirectory = new File(outputDirectory, resource.getTargetPath()); + } else { + targetDirectory = outputDirectory; + } + if (filter) { + Map properties = new HashMap(this.properties); + properties.putAll(sessionProperties); // command line parameters win over project properties + properties.put("project", project); + properties.put( + "localRepository", + repositorySystemSession + .getLocalRepository() + .getBasedir() + .getAbsolutePath()); + properties.put("userSettingsFile", userSettingsFile); + List filters = + project.getFilters().stream().map(File::new).collect(Collectors.toList()); + processor.process( + sourceDirectory, + targetDirectory, + resource.getIncludes(), + resource.getExcludes(), + properties, + filters, + encoding, + missingPropertyAction); + } else { + processor.process( + sourceDirectory, targetDirectory, resource.getIncludes(), resource.getExcludes(), encoding); + } + } catch (IOException e) { + throw new MojoExecutionException(e.getMessage(), e); + } } - if (filter) { - Map properties = new HashMap(this.properties); - properties.putAll(sessionProperties); // command line parameters win over project properties - properties.put("project", project); - properties.put("localRepository", repositorySystemSession.getLocalRepository().getBasedir().getAbsolutePath()); - properties.put("userSettingsFile", userSettingsFile); - List filters = project.getFilters().stream().map(File::new).collect(Collectors.toList()); - processor.process(sourceDirectory, targetDirectory, resource.getIncludes(), resource.getExcludes(), properties, filters, encoding, missingPropertyAction); - } else { - processor.process(sourceDirectory, targetDirectory, resource.getIncludes(), resource.getExcludes(), encoding); - } - } catch (IOException e) { - throw new MojoExecutionException(e.getMessage(), e); - } } - } - @Override - protected void skipMojo() throws MojoExecutionException { - context.markSkipExecution(); - } + @Override + protected void skipMojo() throws MojoExecutionException { + context.markSkipExecution(); + } } diff --git a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/resources/ProcessResources.java b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/resources/ProcessResources.java index b46fb1e4..200a860d 100644 --- a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/resources/ProcessResources.java +++ b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/resources/ProcessResources.java @@ -1,33 +1,35 @@ -/** - * Copyright (c) 2014 Takari, Inc. +/* + * Copyright (c) 2014-2024 Takari, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * https://www.eclipse.org/legal/epl-v10.html */ package io.takari.maven.plugins.resources; import java.io.File; import java.util.List; - import org.apache.maven.model.Resource; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugins.annotations.LifecyclePhase; import org.apache.maven.plugins.annotations.Mojo; import org.apache.maven.plugins.annotations.Parameter; -@Mojo(name = "process-resources", defaultPhase = LifecyclePhase.PROCESS_RESOURCES, configurator = "takari", threadSafe = true) +@Mojo( + name = "process-resources", + defaultPhase = LifecyclePhase.PROCESS_RESOURCES, + configurator = "takari", + threadSafe = true) public class ProcessResources extends AbstractProcessResourcesMojo { - @Parameter(defaultValue = "${project.build.outputDirectory}", property = "resources.outputDirectory") - private File outputDirectory; - - @Parameter - private List resources; + @Parameter(defaultValue = "${project.build.outputDirectory}", property = "resources.outputDirectory") + private File outputDirectory; - @Override - protected void executeMojo() throws MojoExecutionException { - process(resources != null ? resources : project.getBuild().getResources(), outputDirectory); - } + @Parameter + private List resources; + @Override + protected void executeMojo() throws MojoExecutionException { + process(resources != null ? resources : project.getBuild().getResources(), outputDirectory); + } } diff --git a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/resources/ProcessTestResources.java b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/resources/ProcessTestResources.java index 813c6ed0..e138c02b 100644 --- a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/resources/ProcessTestResources.java +++ b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/resources/ProcessTestResources.java @@ -1,32 +1,35 @@ -/** - * Copyright (c) 2014 Takari, Inc. +/* + * Copyright (c) 2014-2024 Takari, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * https://www.eclipse.org/legal/epl-v10.html */ package io.takari.maven.plugins.resources; import java.io.File; import java.util.List; - import org.apache.maven.model.Resource; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugins.annotations.LifecyclePhase; import org.apache.maven.plugins.annotations.Mojo; import org.apache.maven.plugins.annotations.Parameter; -@Mojo(name = "process-test-resources", defaultPhase = LifecyclePhase.PROCESS_TEST_RESOURCES, configurator = "takari", threadSafe = true) +@Mojo( + name = "process-test-resources", + defaultPhase = LifecyclePhase.PROCESS_TEST_RESOURCES, + configurator = "takari", + threadSafe = true) public class ProcessTestResources extends AbstractProcessResourcesMojo { - @Parameter(defaultValue = "${project.build.testOutputDirectory}", property = "resources.testOutputDirectory") - private File testOutputDirectory; + @Parameter(defaultValue = "${project.build.testOutputDirectory}", property = "resources.testOutputDirectory") + private File testOutputDirectory; - @Parameter - private List testResources; + @Parameter + private List testResources; - @Override - protected void executeMojo() throws MojoExecutionException { - process(testResources != null ? testResources : project.getBuild().getTestResources(), testOutputDirectory); - } + @Override + protected void executeMojo() throws MojoExecutionException { + process(testResources != null ? testResources : project.getBuild().getTestResources(), testOutputDirectory); + } } diff --git a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/sisu/AbstractSisuIndexMojo.java b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/sisu/AbstractSisuIndexMojo.java index 8f8c3691..6ee72ebd 100644 --- a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/sisu/AbstractSisuIndexMojo.java +++ b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/sisu/AbstractSisuIndexMojo.java @@ -1,5 +1,17 @@ +/* + * Copyright (c) 2014-2024 Takari, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v10.html + */ package io.takari.maven.plugins.sisu; +import io.takari.incrementalbuild.Output; +import io.takari.incrementalbuild.aggregator.AggregatorBuildContext; +import io.takari.incrementalbuild.aggregator.InputSet; +import io.takari.incrementalbuild.aggregator.MetadataAggregator; +import io.takari.maven.plugins.TakariLifecycleMojo; import java.io.BufferedWriter; import java.io.File; import java.io.IOException; @@ -9,76 +21,70 @@ import java.util.Map; import java.util.Set; import java.util.TreeSet; - import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugins.annotations.Component; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader; import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException; import org.eclipse.jdt.internal.compiler.env.IBinaryAnnotation; -import io.takari.incrementalbuild.Output; -import io.takari.incrementalbuild.aggregator.AggregatorBuildContext; -import io.takari.incrementalbuild.aggregator.InputSet; -import io.takari.incrementalbuild.aggregator.MetadataAggregator; -import io.takari.maven.plugins.TakariLifecycleMojo; - abstract class AbstractSisuIndexMojo extends TakariLifecycleMojo { - @Component - private AggregatorBuildContext context; + @Component + private AggregatorBuildContext context; - @Override - protected void executeMojo() throws MojoExecutionException { + @Override + protected void executeMojo() throws MojoExecutionException { - try { - InputSet inputs = context.newInputSet(); - inputs.addInputs(getOutputDirectory(), Collections.singleton("**/*.class"), null); - inputs.aggregateIfNecessary(getOutputFile(), new MetadataAggregator() { - @Override - public Map glean(File input) throws IOException { - return gleanNamedType(input); - } + try { + InputSet inputs = context.newInputSet(); + inputs.addInputs(getOutputDirectory(), Collections.singleton("**/*.class"), null); + inputs.aggregateIfNecessary(getOutputFile(), new MetadataAggregator() { + @Override + public Map glean(File input) throws IOException { + return gleanNamedType(input); + } - @Override - public void aggregate(Output output, Map metadata) throws IOException { - writeIndex(output, metadata.keySet()); + @Override + public void aggregate(Output output, Map metadata) throws IOException { + writeIndex(output, metadata.keySet()); + } + }); + } catch (IOException e) { + throw new MojoExecutionException("Could not create sisu index " + getOutputFile(), e); } - }); - } catch (IOException e) { - throw new MojoExecutionException("Could not create sisu index " + getOutputFile(), e); } - } - void writeIndex(Output output, Set types) throws IOException { - TreeSet sorted = new TreeSet<>(types); - try (BufferedWriter w = new BufferedWriter(new OutputStreamWriter(output.newOutputStream(), StandardCharsets.UTF_8))) { - for (String type : sorted) { - w.write(type); - w.newLine(); - } + void writeIndex(Output output, Set types) throws IOException { + TreeSet sorted = new TreeSet<>(types); + try (BufferedWriter w = + new BufferedWriter(new OutputStreamWriter(output.newOutputStream(), StandardCharsets.UTF_8))) { + for (String type : sorted) { + w.write(type); + w.newLine(); + } + } } - } - Map gleanNamedType(File classfile) throws IOException { - // use jdt class reader to avoid extra runtime dependency, otherwise could use asm + Map gleanNamedType(File classfile) throws IOException { + // use jdt class reader to avoid extra runtime dependency, otherwise could use asm - try { - ClassFileReader type = ClassFileReader.read(classfile); - IBinaryAnnotation[] annotations = type.getAnnotations(); - if (annotations != null) { - for (IBinaryAnnotation annotation : annotations) { - if ("Ljavax/inject/Named;".equals(new String(annotation.getTypeName()))) { - return Collections.singletonMap(new String(type.getName()).replace('/', '.'), null); - } + try { + ClassFileReader type = ClassFileReader.read(classfile); + IBinaryAnnotation[] annotations = type.getAnnotations(); + if (annotations != null) { + for (IBinaryAnnotation annotation : annotations) { + if ("Ljavax/inject/Named;".equals(new String(annotation.getTypeName()))) { + return Collections.singletonMap(new String(type.getName()).replace('/', '.'), null); + } + } + } + } catch (ClassFormatException e) { + // silently ignore classes we can't read/parse } - } - } catch (ClassFormatException e) { - // silently ignore classes we can't read/parse - } - return null; - } + return null; + } - protected abstract File getOutputDirectory(); + protected abstract File getOutputDirectory(); - protected abstract File getOutputFile(); + protected abstract File getOutputFile(); } diff --git a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/sisu/SisuIndexMojo.java b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/sisu/SisuIndexMojo.java index 3aa7a7aa..d993334e 100644 --- a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/sisu/SisuIndexMojo.java +++ b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/sisu/SisuIndexMojo.java @@ -1,7 +1,13 @@ +/* + * Copyright (c) 2014-2024 Takari, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v10.html + */ package io.takari.maven.plugins.sisu; import java.io.File; - import org.apache.maven.plugins.annotations.LifecyclePhase; import org.apache.maven.plugins.annotations.Mojo; import org.apache.maven.plugins.annotations.Parameter; @@ -9,21 +15,21 @@ @Mojo(name = "sisu-index", defaultPhase = LifecyclePhase.PROCESS_CLASSES, threadSafe = true) public class SisuIndexMojo extends AbstractSisuIndexMojo { - public static final String PATH_SISU_INDEX = "META-INF/sisu/javax.inject.Named"; + public static final String PATH_SISU_INDEX = "META-INF/sisu/javax.inject.Named"; - @Parameter(defaultValue = "${project.build.outputDirectory}", readonly = true) - private File outputDirectory; + @Parameter(defaultValue = "${project.build.outputDirectory}", readonly = true) + private File outputDirectory; - @Parameter(defaultValue = "${project.build.outputDirectory}/" + PATH_SISU_INDEX, readonly = true) - private File outputFile; + @Parameter(defaultValue = "${project.build.outputDirectory}/" + PATH_SISU_INDEX, readonly = true) + private File outputFile; - @Override - protected File getOutputDirectory() { - return outputDirectory; - } + @Override + protected File getOutputDirectory() { + return outputDirectory; + } - @Override - protected File getOutputFile() { - return outputFile; - } + @Override + protected File getOutputFile() { + return outputFile; + } } diff --git a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/sisu/SisuTestIndexMojo.java b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/sisu/SisuTestIndexMojo.java index 0c4924fb..fd902520 100644 --- a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/sisu/SisuTestIndexMojo.java +++ b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/sisu/SisuTestIndexMojo.java @@ -1,7 +1,13 @@ +/* + * Copyright (c) 2014-2024 Takari, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v10.html + */ package io.takari.maven.plugins.sisu; import java.io.File; - import org.apache.maven.plugins.annotations.LifecyclePhase; import org.apache.maven.plugins.annotations.Mojo; import org.apache.maven.plugins.annotations.Parameter; @@ -9,21 +15,21 @@ @Mojo(name = "sisu-test-index", defaultPhase = LifecyclePhase.PROCESS_TEST_CLASSES, threadSafe = true) public class SisuTestIndexMojo extends AbstractSisuIndexMojo { - public static final String PATH_SISU_INDEX = "META-INF/sisu/javax.inject.Named"; + public static final String PATH_SISU_INDEX = "META-INF/sisu/javax.inject.Named"; - @Parameter(defaultValue = "${project.build.testOutputDirectory}", readonly = true) - private File outputDirectory; + @Parameter(defaultValue = "${project.build.testOutputDirectory}", readonly = true) + private File outputDirectory; - @Parameter(defaultValue = "${project.build.testOutputDirectory}/" + PATH_SISU_INDEX, readonly = true) - private File outputFile; + @Parameter(defaultValue = "${project.build.testOutputDirectory}/" + PATH_SISU_INDEX, readonly = true) + private File outputFile; - @Override - protected File getOutputDirectory() { - return outputDirectory; - } + @Override + protected File getOutputDirectory() { + return outputDirectory; + } - @Override - protected File getOutputFile() { - return outputFile; - } + @Override + protected File getOutputFile() { + return outputFile; + } } diff --git a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/testproperties/TestPropertiesMojo.java b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/testproperties/TestPropertiesMojo.java index bb44ce63..677c3389 100644 --- a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/testproperties/TestPropertiesMojo.java +++ b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/testproperties/TestPropertiesMojo.java @@ -1,13 +1,21 @@ -/** - * Copyright (c) 2014 Takari, Inc. +/* + * Copyright (c) 2014-2024 Takari, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * https://www.eclipse.org/legal/epl-v10.html */ package io.takari.maven.plugins.testproperties; -import java.io.ByteArrayOutputStream; +import io.takari.incrementalbuild.BasicBuildContext; +import io.takari.incrementalbuild.Incremental; +import io.takari.incrementalbuild.Incremental.Configuration; +import io.takari.incrementalbuild.Output; +import io.takari.incrementalbuild.Resource; +import io.takari.incrementalbuild.ResourceMetadata; +import io.takari.maven.plugins.util.PropertiesWriter; +import io.takari.resources.filtering.MissingPropertyAction; +import io.takari.resources.filtering.ResourcesProcessor; import java.io.File; import java.io.FileInputStream; import java.io.IOException; @@ -23,7 +31,6 @@ import java.util.Map; import java.util.Properties; import java.util.Set; - import org.apache.maven.artifact.Artifact; import org.apache.maven.artifact.repository.ArtifactRepository; import org.apache.maven.execution.ProjectDependencyGraph; @@ -38,279 +45,298 @@ import org.eclipse.aether.RepositorySystemSession; import org.eclipse.m2e.workspace.MutableWorkspaceState; -import io.takari.incrementalbuild.BasicBuildContext; -import io.takari.incrementalbuild.Output; -import io.takari.incrementalbuild.Resource; -import io.takari.incrementalbuild.Incremental; -import io.takari.incrementalbuild.Incremental.Configuration; -import io.takari.incrementalbuild.ResourceMetadata; -import io.takari.maven.plugins.util.PropertiesWriter; -import io.takari.resources.filtering.MissingPropertyAction; -import io.takari.resources.filtering.ResourcesProcessor; - -@Mojo(name = "testProperties", requiresDependencyResolution = ResolutionScope.TEST, configurator = "takari", threadSafe = true) +@Mojo( + name = "testProperties", + requiresDependencyResolution = ResolutionScope.TEST, + configurator = "takari", + threadSafe = true) public class TestPropertiesMojo extends AbstractMojo { - @Parameter(defaultValue = "${project.properties}", readonly = true) - private Properties projectProperties; - - @Parameter(defaultValue = "${session.executionProperties}", readonly = true) - private Properties sessionProperties; - - @Parameter(defaultValue = "${project}", readonly = true) - @Incremental(configuration = Configuration.ignore) - protected MavenProject project; - - @Parameter(defaultValue = "${project.groupId}", readonly = true) - private String groupId; - - @Parameter(defaultValue = "${project.artifactId}", readonly = true) - private String artifactId; - - @Parameter(defaultValue = "${project.version}", readonly = true) - private String version; - - @Parameter(defaultValue = "${session.request.userSettingsFile}", readonly = true) - private File userSettingsFile; - - @Parameter(defaultValue = "${session.request.globalSettingsFile}", readonly = true) - private File globalSettingsFile; - - @Parameter(defaultValue = "${project.basedir}/src/test/test.properties") - private File testProperties; - - @Parameter(defaultValue = "${project.build.testOutputDirectory}/test.properties") - private File outputFile; - - // @Parameter(defaultValue = "${plugin.artifactMap(io.takari.m2e.workspace:org.eclipse.m2e.workspace.cli)}") - @Parameter(defaultValue = "${project.artifactMap(io.takari.m2e.workspace:org.eclipse.m2e.workspace.cli)}", readonly = true) - private Artifact workspaceResolver; - - @Parameter(defaultValue = "${project.build.directory}/workspacestate.properties") - private File workspaceState; - - @Parameter(defaultValue = "${project.build.outputDirectory}", readonly = true) - private File outputDirectory; - - @Parameter(defaultValue = "${project.artifacts}", readonly = true) - private Set dependencies; - - @Parameter(defaultValue = "${session.request.offline}", readonly = true) - private boolean offline; - - @Parameter(defaultValue = "${session.request.updateSnapshots}", readonly = true) - private boolean updateSnapshots; - - @Parameter(defaultValue = "${session.projectDependencyGraph}", readonly = true) - @Incremental(configuration = Configuration.ignore) - private ProjectDependencyGraph reactorDependencies; - - @Parameter(defaultValue = "${repositorySystemSession}", readonly = true) - @Incremental(configuration = Configuration.ignore) - private RepositorySystemSession repositorySystemSession; - - /** - * Sets what should be the outcome when filtering hits a missing property. - *

- * Allowed values are: - *

- *
    - *
  • empty - The filtered value will be empty string (default).
  • - *
  • leave - The filtered value will be left as-is, unfiltered (basically the expression itself, mimics maven-resources-plugin).
  • - *
  • fail - Missing property will be reported as error and fails the build.
  • - *
- * - * @since 1.13.4 - */ - @Parameter - protected MissingPropertyAction missingPropertyAction = MissingPropertyAction.DEFAULT; - - @Component - private BasicBuildContext context; - - @Component - private ResourcesProcessor resourceProcessor; - - @Override - public void execute() throws MojoExecutionException, MojoFailureException { - try { - if (!context.isProcessingRequired()) { - return; - } - - Properties properties = new Properties(); - Output output = context.processOutput(outputFile); - - if (testProperties.canRead()) { - mergeCustomTestProperties(output, properties); - } - - // well-known properties, TODO introduce named constants - putIfAbsent(properties, "localRepository", repositorySystemSession.getLocalRepository().getBasedir().getAbsolutePath()); - if (isAccessible(userSettingsFile)) { - putIfAbsent(properties, "userSettingsFile", userSettingsFile.getAbsolutePath()); - } else { - logWarningNotAccessibleFile(userSettingsFile); - } - if (isAccessible(globalSettingsFile)) { - putIfAbsent(properties, "globalSettingsFile", globalSettingsFile.getAbsolutePath()); - } else { - logWarningNotAccessibleFile(globalSettingsFile); - } - List repositories = project.getRemoteArtifactRepositories(); - for (int i = 0; i < repositories.size(); i++) { - properties.put("repository." + i, toString(repositories.get(i))); - } - putIfAbsent(properties, "offline", Boolean.toString(offline)); - putIfAbsent(properties, "updateSnapshots", Boolean.toString(updateSnapshots)); - putIfAbsent(properties, "project.groupId", groupId); - putIfAbsent(properties, "project.artifactId", artifactId); - putIfAbsent(properties, "project.version", version); - - // project runtime classpath - putIfAbsent(properties, "classpath", getClasspathString()); - - if (workspaceResolver != null && workspaceResolver.getFile() != null) { - putIfAbsent(properties, "workspaceResolver", workspaceResolver.getFile().getAbsolutePath()); - } - - writeWorkspaceState(); - putIfAbsent(properties, "workspaceStateProperties", workspaceState.getAbsolutePath()); - - try (OutputStream os = output.newOutputStream()) { - PropertiesWriter.write(properties, "Generated by " + getClass().getName(), os); - } - } catch (IOException e) { - throw new MojoExecutionException("Could not create test.properties file", e); - } - } - - private String toString(ArtifactRepository repository) { - StringBuilder sb = new StringBuilder(); - sb.append("").append(repository.getId()).append(""); - sb.append("").append(repository.getUrl()).append(""); - sb.append("").append(repository.getReleases().isEnabled()).append(""); - sb.append("").append(repository.getSnapshots().isEnabled()).append(""); - return sb.toString(); - } - - private String getClasspathString() { - Set scopes = Collections.unmodifiableSet(new LinkedHashSet<>(Arrays.asList(Artifact.SCOPE_COMPILE, Artifact.SCOPE_RUNTIME))); - StringBuilder sb = new StringBuilder(); - sb.append(outputDirectory.getAbsolutePath()); - for (Artifact dependency : dependencies) { - if (scopes.contains(dependency.getScope())) { - sb.append(File.pathSeparatorChar); - sb.append(dependency.getFile().getAbsolutePath()); - } + @Parameter(defaultValue = "${project.properties}", readonly = true) + private Properties projectProperties; + + @Parameter(defaultValue = "${session.executionProperties}", readonly = true) + private Properties sessionProperties; + + @Parameter(defaultValue = "${project}", readonly = true) + @Incremental(configuration = Configuration.ignore) + protected MavenProject project; + + @Parameter(defaultValue = "${project.groupId}", readonly = true) + private String groupId; + + @Parameter(defaultValue = "${project.artifactId}", readonly = true) + private String artifactId; + + @Parameter(defaultValue = "${project.version}", readonly = true) + private String version; + + @Parameter(defaultValue = "${session.request.userSettingsFile}", readonly = true) + private File userSettingsFile; + + @Parameter(defaultValue = "${session.request.globalSettingsFile}", readonly = true) + private File globalSettingsFile; + + @Parameter(defaultValue = "${project.basedir}/src/test/test.properties") + private File testProperties; + + @Parameter(defaultValue = "${project.build.testOutputDirectory}/test.properties") + private File outputFile; + + // @Parameter(defaultValue = "${plugin.artifactMap(io.takari.m2e.workspace:org.eclipse.m2e.workspace.cli)}") + @Parameter( + defaultValue = "${project.artifactMap(io.takari.m2e.workspace:org.eclipse.m2e.workspace.cli)}", + readonly = true) + private Artifact workspaceResolver; + + @Parameter(defaultValue = "${project.build.directory}/workspacestate.properties") + private File workspaceState; + + @Parameter(defaultValue = "${project.build.outputDirectory}", readonly = true) + private File outputDirectory; + + @Parameter(defaultValue = "${project.artifacts}", readonly = true) + private Set dependencies; + + @Parameter(defaultValue = "${session.request.offline}", readonly = true) + private boolean offline; + + @Parameter(defaultValue = "${session.request.updateSnapshots}", readonly = true) + private boolean updateSnapshots; + + @Parameter(defaultValue = "${session.projectDependencyGraph}", readonly = true) + @Incremental(configuration = Configuration.ignore) + private ProjectDependencyGraph reactorDependencies; + + @Parameter(defaultValue = "${repositorySystemSession}", readonly = true) + @Incremental(configuration = Configuration.ignore) + private RepositorySystemSession repositorySystemSession; + + /** + * Sets what should be the outcome when filtering hits a missing property. + *

+ * Allowed values are: + *

+ *
    + *
  • empty - The filtered value will be empty string (default).
  • + *
  • leave - The filtered value will be left as-is, unfiltered (basically the expression itself, mimics maven-resources-plugin).
  • + *
  • fail - Missing property will be reported as error and fails the build.
  • + *
+ * + * @since 1.13.4 + */ + @Parameter + protected MissingPropertyAction missingPropertyAction = MissingPropertyAction.DEFAULT; + + @Component + private BasicBuildContext context; + + @Component + private ResourcesProcessor resourceProcessor; + + @Override + public void execute() throws MojoExecutionException, MojoFailureException { + try { + if (!context.isProcessingRequired()) { + return; + } + + Properties properties = new Properties(); + Output output = context.processOutput(outputFile); + + if (testProperties.canRead()) { + mergeCustomTestProperties(output, properties); + } + + // well-known properties, TODO introduce named constants + putIfAbsent( + properties, + "localRepository", + repositorySystemSession.getLocalRepository().getBasedir().getAbsolutePath()); + if (isAccessible(userSettingsFile)) { + putIfAbsent(properties, "userSettingsFile", userSettingsFile.getAbsolutePath()); + } else { + logWarningNotAccessibleFile(userSettingsFile); + } + if (isAccessible(globalSettingsFile)) { + putIfAbsent(properties, "globalSettingsFile", globalSettingsFile.getAbsolutePath()); + } else { + logWarningNotAccessibleFile(globalSettingsFile); + } + List repositories = project.getRemoteArtifactRepositories(); + for (int i = 0; i < repositories.size(); i++) { + properties.put("repository." + i, toString(repositories.get(i))); + } + putIfAbsent(properties, "offline", Boolean.toString(offline)); + putIfAbsent(properties, "updateSnapshots", Boolean.toString(updateSnapshots)); + putIfAbsent(properties, "project.groupId", groupId); + putIfAbsent(properties, "project.artifactId", artifactId); + putIfAbsent(properties, "project.version", version); + + // project runtime classpath + putIfAbsent(properties, "classpath", getClasspathString()); + + if (workspaceResolver != null && workspaceResolver.getFile() != null) { + putIfAbsent( + properties, + "workspaceResolver", + workspaceResolver.getFile().getAbsolutePath()); + } + + writeWorkspaceState(); + putIfAbsent(properties, "workspaceStateProperties", workspaceState.getAbsolutePath()); + + try (OutputStream os = output.newOutputStream()) { + PropertiesWriter.write(properties, "Generated by " + getClass().getName(), os); + } + } catch (IOException e) { + throw new MojoExecutionException("Could not create test.properties file", e); + } } - return sb.toString(); - } - - private void writeWorkspaceState() throws MojoExecutionException { - MutableWorkspaceState state = new MutableWorkspaceState(); - // always include this project's pom and jar artifacts - state.putPom(project.getFile(), project.getGroupId(), project.getArtifactId(), project.getVersion()); - state.putArtifact(outputDirectory, project.getGroupId(), project.getArtifactId(), // - "jar" /* extension */, null/* classifier */, project.getVersion()); - if (reactorDependencies != null) { - // either runs from m2e or from command line with --non-recursive parameter - for (MavenProject other : reactorDependencies.getUpstreamProjects(project, true)) { - putProject(state, other); - } + + private String toString(ArtifactRepository repository) { + StringBuilder sb = new StringBuilder(); + sb.append("").append(repository.getId()).append(""); + sb.append("").append(repository.getUrl()).append(""); + sb.append("") + .append(repository.getReleases().isEnabled()) + .append(""); + sb.append("") + .append(repository.getSnapshots().isEnabled()) + .append(""); + return sb.toString(); } - try (OutputStream os = context.processOutput(workspaceState).newOutputStream()) { - PropertiesWriter.write(state.asProperties(), null, os); - } catch (IOException e) { - throw new MojoExecutionException("Could not create reactor state file " + workspaceState, e); + + private String getClasspathString() { + Set scopes = Collections.unmodifiableSet( + new LinkedHashSet<>(Arrays.asList(Artifact.SCOPE_COMPILE, Artifact.SCOPE_RUNTIME))); + StringBuilder sb = new StringBuilder(); + sb.append(outputDirectory.getAbsolutePath()); + for (Artifact dependency : dependencies) { + if (scopes.contains(dependency.getScope())) { + sb.append(File.pathSeparatorChar); + sb.append(dependency.getFile().getAbsolutePath()); + } + } + return sb.toString(); } - } - private static void putProject(MutableWorkspaceState state, MavenProject other) { - state.putPom(other.getFile(), other.getGroupId(), other.getArtifactId(), other.getVersion()); - if (other.getArtifact().getFile() != null) { - putArtifact(state, other.getArtifact()); + private void writeWorkspaceState() throws MojoExecutionException { + MutableWorkspaceState state = new MutableWorkspaceState(); + // always include this project's pom and jar artifacts + state.putPom(project.getFile(), project.getGroupId(), project.getArtifactId(), project.getVersion()); + state.putArtifact( + outputDirectory, + project.getGroupId(), + project.getArtifactId(), // + "jar" /* extension */, + null /* classifier */, + project.getVersion()); + if (reactorDependencies != null) { + // either runs from m2e or from command line with --non-recursive parameter + for (MavenProject other : reactorDependencies.getUpstreamProjects(project, true)) { + putProject(state, other); + } + } + try (OutputStream os = context.processOutput(workspaceState).newOutputStream()) { + PropertiesWriter.write(state.asProperties(), null, os); + } catch (IOException e) { + throw new MojoExecutionException("Could not create reactor state file " + workspaceState, e); + } } - for (Artifact artifact : other.getAttachedArtifacts()) { - putArtifact(state, artifact); + + private static void putProject(MutableWorkspaceState state, MavenProject other) { + state.putPom(other.getFile(), other.getGroupId(), other.getArtifactId(), other.getVersion()); + if (other.getArtifact().getFile() != null) { + putArtifact(state, other.getArtifact()); + } + for (Artifact artifact : other.getAttachedArtifacts()) { + putArtifact(state, artifact); + } } - } - - private static void putArtifact(MutableWorkspaceState state, Artifact artifact) { - state.putArtifact(artifact.getFile(), artifact.getGroupId(), artifact.getArtifactId(), // - artifact.getArtifactHandler().getExtension(), artifact.getClassifier(), artifact.getBaseVersion()); - } - - private void mergeCustomTestProperties(Output output, Properties properties) throws MojoExecutionException { - ResourceMetadata metadata = context.registerInput(testProperties); - try (InputStream is = new FileInputStream(metadata.getResource())) { - Properties custom = new Properties(); - custom.load(is); - mergeCustomTestProperties(output, properties, custom); - } catch (IOException e) { - // TODO create error marker instead - throw new MojoExecutionException("Could not read test.properties file " + testProperties, e); + + private static void putArtifact(MutableWorkspaceState state, Artifact artifact) { + state.putArtifact( + artifact.getFile(), + artifact.getGroupId(), + artifact.getArtifactId(), // + artifact.getArtifactHandler().getExtension(), + artifact.getClassifier(), + artifact.getBaseVersion()); } - } - - private void mergeCustomTestProperties(Resource resource, Properties properties, Properties custom) { - // resource filtering configuration should match AbstractProcessResourcesMojo - // TODO figure out how to move this to a common component - Map substitutes = new HashMap<>(); - - for (Artifact dependency : dependencies) { - StringBuilder key = new StringBuilder(); - key.append(dependency.getGroupId()); - key.append(':').append(dependency.getArtifactId()); - if (dependency.getClassifier() != null) { - key.append(':').append(dependency.getClassifier()); - } - substitutes.put(key.toString(), dependency.getFile()); + + private void mergeCustomTestProperties(Output output, Properties properties) throws MojoExecutionException { + ResourceMetadata metadata = context.registerInput(testProperties); + try (InputStream is = new FileInputStream(metadata.getResource())) { + Properties custom = new Properties(); + custom.load(is); + mergeCustomTestProperties(output, properties, custom); + } catch (IOException e) { + // TODO create error marker instead + throw new MojoExecutionException("Could not read test.properties file " + testProperties, e); + } } - substitutes.putAll(projectProperties); - substitutes.putAll(sessionProperties); - substitutes.put("project", project); - substitutes.put("localRepository", repositorySystemSession.getLocalRepository().getBasedir().getAbsolutePath()); - substitutes.put("userSettingsFile", userSettingsFile); + private void mergeCustomTestProperties(Resource resource, Properties properties, Properties custom) { + // resource filtering configuration should match AbstractProcessResourcesMojo + // TODO figure out how to move this to a common component + Map substitutes = new HashMap<>(); + + for (Artifact dependency : dependencies) { + StringBuilder key = new StringBuilder(); + key.append(dependency.getGroupId()); + key.append(':').append(dependency.getArtifactId()); + if (dependency.getClassifier() != null) { + key.append(':').append(dependency.getClassifier()); + } + substitutes.put(key.toString(), dependency.getFile()); + } + + substitutes.putAll(projectProperties); + substitutes.putAll(sessionProperties); + substitutes.put("project", project); + substitutes.put( + "localRepository", + repositorySystemSession.getLocalRepository().getBasedir().getAbsolutePath()); + substitutes.put("userSettingsFile", userSettingsFile); + + for (String key : custom.stringPropertyNames()) { + properties.put(key, expand(resource, custom.getProperty(key), substitutes)); + } + } - for (String key : custom.stringPropertyNames()) { - properties.put(key, expand(resource, custom.getProperty(key), substitutes)); + private static void putIfAbsent(Properties properties, String key, String value) { + if (!properties.containsKey(key)) { + properties.put(key, value); + } } - } - private static void putIfAbsent(Properties properties, String key, String value) { - if (!properties.containsKey(key)) { - properties.put(key, value); + private String expand(Resource resource, String value, Map substitutes) { + StringWriter writer = new StringWriter(); + try { + resourceProcessor.filter(resource, new StringReader(value), writer, substitutes, missingPropertyAction); + return writer.toString(); + } catch (IOException e) { + return value; // shouldn't happen + } } - } - - private String expand(Resource resource, String value, Map substitutes) { - StringWriter writer = new StringWriter(); - try { - resourceProcessor.filter(resource, new StringReader(value), writer, substitutes, missingPropertyAction); - return writer.toString(); - } catch (IOException e) { - return value; // shouldn't happen + + private boolean isAccessible(File file) { + return file != null && file.isFile() && file.canRead(); } - } - - private boolean isAccessible(File file) { - return file != null && file.isFile() && file.canRead(); - } - - private void logWarningNotAccessibleFile(File file) { - if (file != null) { - String msg = "File '" + file.getAbsolutePath() + "' "; - if (file.exists() && !file.isFile()) { - msg += "exists, but it is not a regular file!"; - } else if (file.exists() && file.isFile() && !file.canRead()) { - msg += "exists, but can not be read!"; - } else { - msg += "does not exist!"; - } - msg += " It will be ignored."; - getLog().warn(msg); + + private void logWarningNotAccessibleFile(File file) { + if (file != null) { + String msg = "File '" + file.getAbsolutePath() + "' "; + if (file.exists() && !file.isFile()) { + msg += "exists, but it is not a regular file!"; + } else if (file.exists() && file.isFile() && !file.canRead()) { + msg += "exists, but can not be read!"; + } else { + msg += "does not exist!"; + } + msg += " It will be ignored."; + getLog().warn(msg); + } } - } } diff --git a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/util/AetherUtils.java b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/util/AetherUtils.java index 8d70d372..a6adfa02 100644 --- a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/util/AetherUtils.java +++ b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/util/AetherUtils.java @@ -1,9 +1,9 @@ -/** - * Copyright (c) 2014 Takari, Inc. +/* + * Copyright (c) 2014-2024 Takari, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * https://www.eclipse.org/legal/epl-v10.html */ package io.takari.maven.plugins.util; @@ -13,9 +13,9 @@ * copyright ownership. The ASF licenses this file to you 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 @@ -27,7 +27,6 @@ import java.util.Collections; import java.util.List; import java.util.Map; - import org.apache.maven.artifact.handler.ArtifactHandler; import org.apache.maven.artifact.handler.DefaultArtifactHandler; import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager; @@ -53,283 +52,321 @@ /** * Warning: This is an internal utility class that is only public for technical reasons, it is not part of the public API. In particular, this class can be changed or deleted without * prior notice. - * + * * @author Benjamin Bentmann */ public class AetherUtils { - // - // Repository Utils - // + // + // Repository Utils + // - private static String nullify(String string) { - return (string == null || string.length() <= 0) ? null : string; - } - - private static org.apache.maven.artifact.Artifact toArtifact(Dependency dependency) { - if (dependency == null) { - return null; + private static String nullify(String string) { + return (string == null || string.length() <= 0) ? null : string; } - org.apache.maven.artifact.Artifact result = toArtifact(dependency.getArtifact()); - result.setScope(dependency.getScope()); - result.setOptional(dependency.isOptional()); + private static org.apache.maven.artifact.Artifact toArtifact(Dependency dependency) { + if (dependency == null) { + return null; + } - return result; - } + org.apache.maven.artifact.Artifact result = toArtifact(dependency.getArtifact()); + result.setScope(dependency.getScope()); + result.setOptional(dependency.isOptional()); - public static org.apache.maven.artifact.Artifact toArtifact(Artifact artifact) { - if (artifact == null) { - return null; + return result; } - ArtifactHandler handler = newHandler(artifact); - - /* - * NOTE: From Artifact.hasClassifier(), an empty string and a null both denote "no classifier". However, some plugins only check for null, so be sure to nullify an empty classifier. - */ - org.apache.maven.artifact.Artifact result = new org.apache.maven.artifact.DefaultArtifact(artifact.getGroupId(), artifact.getArtifactId(), artifact.getVersion(), null, - artifact.getProperty(ArtifactProperties.TYPE, artifact.getExtension()), nullify(artifact.getClassifier()), handler); + public static org.apache.maven.artifact.Artifact toArtifact(Artifact artifact) { + if (artifact == null) { + return null; + } - result.setFile(artifact.getFile()); - result.setResolved(artifact.getFile() != null); + ArtifactHandler handler = newHandler(artifact); - List trail = new ArrayList(1); - trail.add(result.getId()); - result.setDependencyTrail(trail); + /* + * NOTE: From Artifact.hasClassifier(), an empty string and a null both denote "no classifier". However, some plugins only check for null, so be sure to nullify an empty classifier. + */ + org.apache.maven.artifact.Artifact result = new org.apache.maven.artifact.DefaultArtifact( + artifact.getGroupId(), + artifact.getArtifactId(), + artifact.getVersion(), + null, + artifact.getProperty(ArtifactProperties.TYPE, artifact.getExtension()), + nullify(artifact.getClassifier()), + handler); - return result; - } + result.setFile(artifact.getFile()); + result.setResolved(artifact.getFile() != null); - public static void toArtifacts(Collection artifacts, Collection nodes, List trail, DependencyFilter filter) { - for (DependencyNode node : nodes) { - org.apache.maven.artifact.Artifact artifact = toArtifact(node.getDependency()); + List trail = new ArrayList(1); + trail.add(result.getId()); + result.setDependencyTrail(trail); - List nodeTrail = new ArrayList(trail.size() + 1); - nodeTrail.addAll(trail); - nodeTrail.add(artifact.getId()); + return result; + } - if (filter == null || filter.accept(node, Collections.emptyList())) { - artifact.setDependencyTrail(nodeTrail); - artifacts.add(artifact); - } + public static void toArtifacts( + Collection artifacts, + Collection nodes, + List trail, + DependencyFilter filter) { + for (DependencyNode node : nodes) { + org.apache.maven.artifact.Artifact artifact = toArtifact(node.getDependency()); - toArtifacts(artifacts, node.getChildren(), nodeTrail, filter); - } - } + List nodeTrail = new ArrayList(trail.size() + 1); + nodeTrail.addAll(trail); + nodeTrail.add(artifact.getId()); - public static Artifact toArtifact(org.apache.maven.artifact.Artifact artifact) { - if (artifact == null) { - return null; - } + if (filter == null || filter.accept(node, Collections.emptyList())) { + artifact.setDependencyTrail(nodeTrail); + artifacts.add(artifact); + } - String version = artifact.getVersion(); - if (version == null && artifact.getVersionRange() != null) { - version = artifact.getVersionRange().toString(); + toArtifacts(artifacts, node.getChildren(), nodeTrail, filter); + } } - Map props = null; - if (org.apache.maven.artifact.Artifact.SCOPE_SYSTEM.equals(artifact.getScope())) { - String localPath = (artifact.getFile() != null) ? artifact.getFile().getPath() : ""; - props = Collections.singletonMap(ArtifactProperties.LOCAL_PATH, localPath); - } + public static Artifact toArtifact(org.apache.maven.artifact.Artifact artifact) { + if (artifact == null) { + return null; + } - Artifact result = new DefaultArtifact(artifact.getGroupId(), artifact.getArtifactId(), artifact.getClassifier(), artifact.getArtifactHandler().getExtension(), version, props, - newArtifactType(artifact.getType(), artifact.getArtifactHandler())); - result = result.setFile(artifact.getFile()); + String version = artifact.getVersion(); + if (version == null && artifact.getVersionRange() != null) { + version = artifact.getVersionRange().toString(); + } - return result; - } + Map props = null; + if (org.apache.maven.artifact.Artifact.SCOPE_SYSTEM.equals(artifact.getScope())) { + String localPath = (artifact.getFile() != null) ? artifact.getFile().getPath() : ""; + props = Collections.singletonMap(ArtifactProperties.LOCAL_PATH, localPath); + } - public static Dependency toDependency(org.apache.maven.artifact.Artifact artifact, Collection exclusions) { - if (artifact == null) { - return null; + Artifact result = new DefaultArtifact( + artifact.getGroupId(), + artifact.getArtifactId(), + artifact.getClassifier(), + artifact.getArtifactHandler().getExtension(), + version, + props, + newArtifactType(artifact.getType(), artifact.getArtifactHandler())); + result = result.setFile(artifact.getFile()); + + return result; } - Artifact result = toArtifact(artifact); + public static Dependency toDependency( + org.apache.maven.artifact.Artifact artifact, Collection exclusions) { + if (artifact == null) { + return null; + } + + Artifact result = toArtifact(artifact); - List excl = null; - if (exclusions != null) { - excl = new ArrayList(exclusions.size()); - for (org.apache.maven.model.Exclusion exclusion : exclusions) { - excl.add(toExclusion(exclusion)); - } + List excl = null; + if (exclusions != null) { + excl = new ArrayList(exclusions.size()); + for (org.apache.maven.model.Exclusion exclusion : exclusions) { + excl.add(toExclusion(exclusion)); + } + } + + return new Dependency(result, artifact.getScope(), artifact.isOptional(), excl); } - return new Dependency(result, artifact.getScope(), artifact.isOptional(), excl); - } + public static List toRepos(List repos) { + if (repos == null) { + return null; + } - public static List toRepos(List repos) { - if (repos == null) { - return null; + List results = new ArrayList(repos.size()); + for (ArtifactRepository repo : repos) { + results.add(toRepo(repo)); + } + return results; } - List results = new ArrayList(repos.size()); - for (ArtifactRepository repo : repos) { - results.add(toRepo(repo)); + public static RemoteRepository toRepo(ArtifactRepository repo) { + RemoteRepository result = null; + if (repo != null) { + RemoteRepository.Builder builder = + new RemoteRepository.Builder(repo.getId(), getLayout(repo), repo.getUrl()); + builder.setSnapshotPolicy(toPolicy(repo.getSnapshots())); + builder.setReleasePolicy(toPolicy(repo.getReleases())); + builder.setAuthentication(toAuthentication(repo.getAuthentication())); + builder.setProxy(toProxy(repo.getProxy())); + builder.setMirroredRepositories(toRepos(repo.getMirroredRepositories())); + result = builder.build(); + } + return result; } - return results; - } - - public static RemoteRepository toRepo(ArtifactRepository repo) { - RemoteRepository result = null; - if (repo != null) { - RemoteRepository.Builder builder = new RemoteRepository.Builder(repo.getId(), getLayout(repo), repo.getUrl()); - builder.setSnapshotPolicy(toPolicy(repo.getSnapshots())); - builder.setReleasePolicy(toPolicy(repo.getReleases())); - builder.setAuthentication(toAuthentication(repo.getAuthentication())); - builder.setProxy(toProxy(repo.getProxy())); - builder.setMirroredRepositories(toRepos(repo.getMirroredRepositories())); - result = builder.build(); + + public static String getLayout(ArtifactRepository repo) { + try { + return repo.getLayout().getId(); + } catch (LinkageError e) { + /* + * NOTE: getId() was added in 3.x and is as such not implemented by plugins compiled against 2.x APIs. + */ + String className = repo.getLayout().getClass().getSimpleName(); + if (className.endsWith("RepositoryLayout")) { + String layout = className.substring(0, className.length() - "RepositoryLayout".length()); + if (layout.length() > 0) { + layout = Character.toLowerCase(layout.charAt(0)) + layout.substring(1); + return layout; + } + } + return ""; + } } - return result; - } - - public static String getLayout(ArtifactRepository repo) { - try { - return repo.getLayout().getId(); - } catch (LinkageError e) { - /* - * NOTE: getId() was added in 3.x and is as such not implemented by plugins compiled against 2.x APIs. - */ - String className = repo.getLayout().getClass().getSimpleName(); - if (className.endsWith("RepositoryLayout")) { - String layout = className.substring(0, className.length() - "RepositoryLayout".length()); - if (layout.length() > 0) { - layout = Character.toLowerCase(layout.charAt(0)) + layout.substring(1); - return layout; + + private static RepositoryPolicy toPolicy(ArtifactRepositoryPolicy policy) { + RepositoryPolicy result = null; + if (policy != null) { + result = new RepositoryPolicy(policy.isEnabled(), policy.getUpdatePolicy(), policy.getChecksumPolicy()); } - } - return ""; + return result; } - } - private static RepositoryPolicy toPolicy(ArtifactRepositoryPolicy policy) { - RepositoryPolicy result = null; - if (policy != null) { - result = new RepositoryPolicy(policy.isEnabled(), policy.getUpdatePolicy(), policy.getChecksumPolicy()); + private static Authentication toAuthentication(org.apache.maven.artifact.repository.Authentication auth) { + Authentication result = null; + if (auth != null) { + AuthenticationBuilder authBuilder = new AuthenticationBuilder(); + authBuilder.addUsername(auth.getUsername()).addPassword(auth.getPassword()); + authBuilder.addPrivateKey(auth.getPrivateKey(), auth.getPassphrase()); + result = authBuilder.build(); + } + return result; } - return result; - } - - private static Authentication toAuthentication(org.apache.maven.artifact.repository.Authentication auth) { - Authentication result = null; - if (auth != null) { - AuthenticationBuilder authBuilder = new AuthenticationBuilder(); - authBuilder.addUsername(auth.getUsername()).addPassword(auth.getPassword()); - authBuilder.addPrivateKey(auth.getPrivateKey(), auth.getPassphrase()); - result = authBuilder.build(); + + private static Proxy toProxy(org.apache.maven.repository.Proxy proxy) { + Proxy result = null; + if (proxy != null) { + AuthenticationBuilder authBuilder = new AuthenticationBuilder(); + authBuilder.addUsername(proxy.getUserName()).addPassword(proxy.getPassword()); + result = new Proxy(proxy.getProtocol(), proxy.getHost(), proxy.getPort(), authBuilder.build()); + } + return result; } - return result; - } - - private static Proxy toProxy(org.apache.maven.repository.Proxy proxy) { - Proxy result = null; - if (proxy != null) { - AuthenticationBuilder authBuilder = new AuthenticationBuilder(); - authBuilder.addUsername(proxy.getUserName()).addPassword(proxy.getPassword()); - result = new Proxy(proxy.getProtocol(), proxy.getHost(), proxy.getPort(), authBuilder.build()); + + public static ArtifactHandler newHandler(Artifact artifact) { + String type = artifact.getProperty(ArtifactProperties.TYPE, artifact.getExtension()); + DefaultArtifactHandler handler = new DefaultArtifactHandler(type); + handler.setExtension(artifact.getExtension()); + handler.setLanguage(artifact.getProperty(ArtifactProperties.LANGUAGE, null)); + handler.setAddedToClasspath( + Boolean.parseBoolean(artifact.getProperty(ArtifactProperties.CONSTITUTES_BUILD_PATH, ""))); + handler.setIncludesDependencies( + Boolean.parseBoolean(artifact.getProperty(ArtifactProperties.INCLUDES_DEPENDENCIES, ""))); + return handler; } - return result; - } - - public static ArtifactHandler newHandler(Artifact artifact) { - String type = artifact.getProperty(ArtifactProperties.TYPE, artifact.getExtension()); - DefaultArtifactHandler handler = new DefaultArtifactHandler(type); - handler.setExtension(artifact.getExtension()); - handler.setLanguage(artifact.getProperty(ArtifactProperties.LANGUAGE, null)); - handler.setAddedToClasspath(Boolean.parseBoolean(artifact.getProperty(ArtifactProperties.CONSTITUTES_BUILD_PATH, ""))); - handler.setIncludesDependencies(Boolean.parseBoolean(artifact.getProperty(ArtifactProperties.INCLUDES_DEPENDENCIES, ""))); - return handler; - } - - public static ArtifactType newArtifactType(String id, ArtifactHandler handler) { - return new DefaultArtifactType(id, handler.getExtension(), handler.getClassifier(), handler.getLanguage(), handler.isAddedToClasspath(), handler.isIncludesDependencies()); - } - - public static Dependency toDependency(org.apache.maven.model.Dependency dependency, ArtifactTypeRegistry stereotypes) { - ArtifactType stereotype = stereotypes.get(dependency.getType()); - if (stereotype == null) { - stereotype = new DefaultArtifactType(dependency.getType()); + + public static ArtifactType newArtifactType(String id, ArtifactHandler handler) { + return new DefaultArtifactType( + id, + handler.getExtension(), + handler.getClassifier(), + handler.getLanguage(), + handler.isAddedToClasspath(), + handler.isIncludesDependencies()); } - boolean system = dependency.getSystemPath() != null && dependency.getSystemPath().length() > 0; + public static Dependency toDependency( + org.apache.maven.model.Dependency dependency, ArtifactTypeRegistry stereotypes) { + ArtifactType stereotype = stereotypes.get(dependency.getType()); + if (stereotype == null) { + stereotype = new DefaultArtifactType(dependency.getType()); + } - Map props = null; - if (system) { - props = Collections.singletonMap(ArtifactProperties.LOCAL_PATH, dependency.getSystemPath()); - } + boolean system = + dependency.getSystemPath() != null && dependency.getSystemPath().length() > 0; - Artifact artifact = new DefaultArtifact(dependency.getGroupId(), dependency.getArtifactId(), dependency.getClassifier(), null, dependency.getVersion(), props, stereotype); + Map props = null; + if (system) { + props = Collections.singletonMap(ArtifactProperties.LOCAL_PATH, dependency.getSystemPath()); + } - List exclusions = new ArrayList(dependency.getExclusions().size()); - for (org.apache.maven.model.Exclusion exclusion : dependency.getExclusions()) { - exclusions.add(toExclusion(exclusion)); - } + Artifact artifact = new DefaultArtifact( + dependency.getGroupId(), + dependency.getArtifactId(), + dependency.getClassifier(), + null, + dependency.getVersion(), + props, + stereotype); + + List exclusions = + new ArrayList(dependency.getExclusions().size()); + for (org.apache.maven.model.Exclusion exclusion : dependency.getExclusions()) { + exclusions.add(toExclusion(exclusion)); + } - Dependency result = new Dependency(artifact, dependency.getScope(), dependency.isOptional(), exclusions); + Dependency result = new Dependency(artifact, dependency.getScope(), dependency.isOptional(), exclusions); - return result; - } + return result; + } - private static Exclusion toExclusion(org.apache.maven.model.Exclusion exclusion) { - return new Exclusion(exclusion.getGroupId(), exclusion.getArtifactId(), "*", "*"); - } + private static Exclusion toExclusion(org.apache.maven.model.Exclusion exclusion) { + return new Exclusion(exclusion.getGroupId(), exclusion.getArtifactId(), "*", "*"); + } - public static ArtifactTypeRegistry newArtifactTypeRegistry(ArtifactHandlerManager handlerManager) { - return new MavenArtifactTypeRegistry(handlerManager); - } + public static ArtifactTypeRegistry newArtifactTypeRegistry(ArtifactHandlerManager handlerManager) { + return new MavenArtifactTypeRegistry(handlerManager); + } - static class MavenArtifactTypeRegistry implements ArtifactTypeRegistry { + static class MavenArtifactTypeRegistry implements ArtifactTypeRegistry { - private final ArtifactHandlerManager handlerManager; + private final ArtifactHandlerManager handlerManager; - public MavenArtifactTypeRegistry(ArtifactHandlerManager handlerManager) { - this.handlerManager = handlerManager; - } + public MavenArtifactTypeRegistry(ArtifactHandlerManager handlerManager) { + this.handlerManager = handlerManager; + } - public ArtifactType get(String stereotypeId) { - ArtifactHandler handler = handlerManager.getArtifactHandler(stereotypeId); - return newArtifactType(stereotypeId, handler); + public ArtifactType get(String stereotypeId) { + ArtifactHandler handler = handlerManager.getArtifactHandler(stereotypeId); + return newArtifactType(stereotypeId, handler); + } } - } - // - // ArtifactDescriptor Utils - // + // + // ArtifactDescriptor Utils + // - public static Artifact toPomArtifact(Artifact artifact) { - Artifact pomArtifact = artifact; + public static Artifact toPomArtifact(Artifact artifact) { + Artifact pomArtifact = artifact; - if (pomArtifact.getClassifier().length() > 0 || !"pom".equals(pomArtifact.getExtension())) { - pomArtifact = new DefaultArtifact(artifact.getGroupId(), artifact.getArtifactId(), "pom", artifact.getVersion()); + if (pomArtifact.getClassifier().length() > 0 || !"pom".equals(pomArtifact.getExtension())) { + pomArtifact = + new DefaultArtifact(artifact.getGroupId(), artifact.getArtifactId(), "pom", artifact.getVersion()); + } + + return pomArtifact; } - return pomArtifact; - } - - public static RemoteRepository toRemoteRepository(Repository repository) { - RemoteRepository.Builder builder = new RemoteRepository.Builder(repository.getId(), repository.getLayout(), repository.getUrl()); - builder.setSnapshotPolicy(toRepositoryPolicy(repository.getSnapshots())); - builder.setReleasePolicy(toRepositoryPolicy(repository.getReleases())); - return builder.build(); - } - - public static RepositoryPolicy toRepositoryPolicy(org.apache.maven.model.RepositoryPolicy policy) { - boolean enabled = true; - String checksums = RepositoryPolicy.CHECKSUM_POLICY_WARN; - String updates = RepositoryPolicy.UPDATE_POLICY_DAILY; - - if (policy != null) { - enabled = policy.isEnabled(); - if (policy.getUpdatePolicy() != null) { - updates = policy.getUpdatePolicy(); - } - if (policy.getChecksumPolicy() != null) { - checksums = policy.getChecksumPolicy(); - } + public static RemoteRepository toRemoteRepository(Repository repository) { + RemoteRepository.Builder builder = + new RemoteRepository.Builder(repository.getId(), repository.getLayout(), repository.getUrl()); + builder.setSnapshotPolicy(toRepositoryPolicy(repository.getSnapshots())); + builder.setReleasePolicy(toRepositoryPolicy(repository.getReleases())); + return builder.build(); } - return new RepositoryPolicy(enabled, updates, checksums); - } + public static RepositoryPolicy toRepositoryPolicy(org.apache.maven.model.RepositoryPolicy policy) { + boolean enabled = true; + String checksums = RepositoryPolicy.CHECKSUM_POLICY_WARN; + String updates = RepositoryPolicy.UPDATE_POLICY_DAILY; + + if (policy != null) { + enabled = policy.isEnabled(); + if (policy.getUpdatePolicy() != null) { + updates = policy.getUpdatePolicy(); + } + if (policy.getChecksumPolicy() != null) { + checksums = policy.getChecksumPolicy(); + } + } + + return new RepositoryPolicy(enabled, updates, checksums); + } } diff --git a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/util/PropertiesWriter.java b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/util/PropertiesWriter.java index 827b4d5e..1e14676f 100644 --- a/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/util/PropertiesWriter.java +++ b/takari-lifecycle-plugin/src/main/java/io/takari/maven/plugins/util/PropertiesWriter.java @@ -1,9 +1,9 @@ -/** - * Copyright (c) 2014 Takari, Inc. +/* + * Copyright (c) 2014-2024 Takari, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * https://www.eclipse.org/legal/epl-v10.html */ package io.takari.maven.plugins.util; @@ -23,23 +23,23 @@ * Helper to strip idiotic timestamp comment from properties files */ public class PropertiesWriter { - // properties files are documented to use ISO_8859_1 encoding - private static final Charset ENCODING = StandardCharsets.ISO_8859_1; + // properties files are documented to use ISO_8859_1 encoding + private static final Charset ENCODING = StandardCharsets.ISO_8859_1; - /** - * Writes out provided properties, with or without comment (nullable), to provided output stream. The output stream - * is not closed. - */ - public static void write(Properties properties, String comment, OutputStream out) throws IOException { - StringWriter sw = new StringWriter(); - properties.store(sw, comment); - List lines = new ArrayList<>(Arrays.asList(sw.toString().split("\\R"))); - lines.remove(comment != null ? 1 : 0); - BufferedWriter w = new BufferedWriter(new OutputStreamWriter(out, ENCODING)); - for (String line : lines) { - w.write(line); - w.newLine(); + /** + * Writes out provided properties, with or without comment (nullable), to provided output stream. The output stream + * is not closed. + */ + public static void write(Properties properties, String comment, OutputStream out) throws IOException { + StringWriter sw = new StringWriter(); + properties.store(sw, comment); + List lines = new ArrayList<>(Arrays.asList(sw.toString().split("\\R"))); + lines.remove(comment != null ? 1 : 0); + BufferedWriter w = new BufferedWriter(new OutputStreamWriter(out, ENCODING)); + for (String line : lines) { + w.write(line); + w.newLine(); + } + w.flush(); } - w.flush(); - } } diff --git a/takari-lifecycle-plugin/src/main/java/io/takari/resources/filtering/AbstractResourceProcessor.java b/takari-lifecycle-plugin/src/main/java/io/takari/resources/filtering/AbstractResourceProcessor.java index 195d95c6..99699cb2 100644 --- a/takari-lifecycle-plugin/src/main/java/io/takari/resources/filtering/AbstractResourceProcessor.java +++ b/takari-lifecycle-plugin/src/main/java/io/takari/resources/filtering/AbstractResourceProcessor.java @@ -1,9 +1,9 @@ -/** - * Copyright (c) 2014 Takari, Inc. +/* + * Copyright (c) 2014-2024 Takari, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * https://www.eclipse.org/legal/epl-v10.html */ package io.takari.resources.filtering; @@ -11,14 +11,13 @@ abstract class AbstractResourceProcessor { - protected static File relativize(File sourceDirectory, File targetDirectory, File sourceFile) { - String sourceDir = sourceDirectory.getAbsolutePath(); - String source = sourceFile.getAbsolutePath(); - if (!source.startsWith(sourceDir)) { - throw new IllegalArgumentException(); // can't happen + protected static File relativize(File sourceDirectory, File targetDirectory, File sourceFile) { + String sourceDir = sourceDirectory.getAbsolutePath(); + String source = sourceFile.getAbsolutePath(); + if (!source.startsWith(sourceDir)) { + throw new IllegalArgumentException(); // can't happen + } + String relative = source.substring(sourceDir.length()); + return new File(targetDirectory, relative); } - String relative = source.substring(sourceDir.length()); - return new File(targetDirectory, relative); - } - } diff --git a/takari-lifecycle-plugin/src/main/java/io/takari/resources/filtering/CopyResourcesProcessor.java b/takari-lifecycle-plugin/src/main/java/io/takari/resources/filtering/CopyResourcesProcessor.java index a406b94e..09bee8b8 100644 --- a/takari-lifecycle-plugin/src/main/java/io/takari/resources/filtering/CopyResourcesProcessor.java +++ b/takari-lifecycle-plugin/src/main/java/io/takari/resources/filtering/CopyResourcesProcessor.java @@ -1,12 +1,15 @@ -/** - * Copyright (c) 2014 Takari, Inc. +/* + * Copyright (c) 2014-2024 Takari, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * https://www.eclipse.org/legal/epl-v10.html */ package io.takari.resources.filtering; +import io.takari.incrementalbuild.BuildContext; +import io.takari.incrementalbuild.Output; +import io.takari.incrementalbuild.Resource; import java.io.File; import java.io.FileInputStream; import java.io.IOException; @@ -15,30 +18,34 @@ import java.util.List; import java.util.Map; -import io.takari.incrementalbuild.BuildContext; -import io.takari.incrementalbuild.Output; -import io.takari.incrementalbuild.Resource; - class CopyResourcesProcessor extends AbstractResourceProcessor { - private final BuildContext buildContext; + private final BuildContext buildContext; - public CopyResourcesProcessor(BuildContext buildContext) { - this.buildContext = buildContext; - } - - public void process(File sourceDirectory, File targetDirectory, List includes, List excludes, String encoding) throws IOException { - for (Resource input : buildContext.registerAndProcessInputs(sourceDirectory, includes, excludes)) { - copyResource(input, sourceDirectory, targetDirectory, null, encoding); + public CopyResourcesProcessor(BuildContext buildContext) { + this.buildContext = buildContext; } - } - private void copyResource(Resource input, File sourceDirectory, File targetDirectory, Map filterProperties, String encoding) throws IOException { - File outputFile = relativize(sourceDirectory, targetDirectory, input.getResource()); - Output output = input.associateOutput(outputFile); - try (InputStream is = new FileInputStream(input.getResource()); OutputStream os = output.newOutputStream()) { - is.transferTo(os); + public void process( + File sourceDirectory, File targetDirectory, List includes, List excludes, String encoding) + throws IOException { + for (Resource input : buildContext.registerAndProcessInputs(sourceDirectory, includes, excludes)) { + copyResource(input, sourceDirectory, targetDirectory, null, encoding); + } } - } + private void copyResource( + Resource input, + File sourceDirectory, + File targetDirectory, + Map filterProperties, + String encoding) + throws IOException { + File outputFile = relativize(sourceDirectory, targetDirectory, input.getResource()); + Output output = input.associateOutput(outputFile); + try (InputStream is = new FileInputStream(input.getResource()); + OutputStream os = output.newOutputStream()) { + is.transferTo(os); + } + } } diff --git a/takari-lifecycle-plugin/src/main/java/io/takari/resources/filtering/FilterResourcesProcessor.java b/takari-lifecycle-plugin/src/main/java/io/takari/resources/filtering/FilterResourcesProcessor.java index af66c6eb..3b9a0f25 100644 --- a/takari-lifecycle-plugin/src/main/java/io/takari/resources/filtering/FilterResourcesProcessor.java +++ b/takari-lifecycle-plugin/src/main/java/io/takari/resources/filtering/FilterResourcesProcessor.java @@ -1,12 +1,24 @@ -/** - * Copyright (c) 2014 Takari, Inc. +/* + * Copyright (c) 2014-2024 Takari, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * https://www.eclipse.org/legal/epl-v10.html */ package io.takari.resources.filtering; +import com.github.mustachejava.DefaultMustacheFactory; +import com.github.mustachejava.Mustache; +import com.github.mustachejava.MustacheException; +import com.github.mustachejava.reflect.MissingWrapper; +import com.github.mustachejava.reflect.ReflectionObjectHandler; +import com.github.mustachejava.util.GuardException; +import com.github.mustachejava.util.Wrapper; +import io.takari.incrementalbuild.BuildContext; +import io.takari.incrementalbuild.MessageSeverity; +import io.takari.incrementalbuild.Output; +import io.takari.incrementalbuild.Resource; +import io.takari.incrementalbuild.ResourceMetadata; import java.io.File; import java.io.FileInputStream; import java.io.FileReader; @@ -21,158 +33,161 @@ import java.util.Map; import java.util.Properties; -import com.github.mustachejava.DefaultMustacheFactory; -import com.github.mustachejava.Mustache; -import com.github.mustachejava.MustacheException; -import com.github.mustachejava.reflect.MissingWrapper; -import com.github.mustachejava.reflect.ReflectionObjectHandler; -import com.github.mustachejava.util.GuardException; -import com.github.mustachejava.util.Wrapper; -import io.takari.incrementalbuild.BuildContext; -import io.takari.incrementalbuild.MessageSeverity; -import io.takari.incrementalbuild.Output; -import io.takari.incrementalbuild.Resource; -import io.takari.incrementalbuild.ResourceMetadata; - class FilterResourcesProcessor extends AbstractResourceProcessor { - private static final String M_START = "${"; + private static final String M_START = "${"; - private static final String M_END = "}"; + private static final String M_END = "}"; - private final BuildContext buildContext; + private final BuildContext buildContext; - public FilterResourcesProcessor(BuildContext buildContext) { - this.buildContext = buildContext; - } + public FilterResourcesProcessor(BuildContext buildContext) { + this.buildContext = buildContext; + } - public void process(File sourceDirectory, File targetDirectory, List includes, List excludes, Map filterProperties, List filters, String encoding, - MissingPropertyAction mpa) throws IOException { - Map effectiveProperties = new HashMap<>(filterProperties); - for (File filter : filters) { - readProperties(filter).forEach((key, value) -> { - if (!effectiveProperties.containsKey(key)) { - effectiveProperties.put(key, value); + public void process( + File sourceDirectory, + File targetDirectory, + List includes, + List excludes, + Map filterProperties, + List filters, + String encoding, + MissingPropertyAction mpa) + throws IOException { + Map effectiveProperties = new HashMap<>(filterProperties); + for (File filter : filters) { + readProperties(filter).forEach((key, value) -> { + if (!effectiveProperties.containsKey(key)) { + effectiveProperties.put(key, value); + } + }); + } + for (ResourceMetadata metadata : buildContext.registerInputs(sourceDirectory, includes, excludes)) { + filterResource(metadata.process(), sourceDirectory, targetDirectory, effectiveProperties, encoding, mpa); } - }); } - for (ResourceMetadata metadata : buildContext.registerInputs(sourceDirectory, includes, excludes)) { - filterResource(metadata.process(), sourceDirectory, targetDirectory, effectiveProperties, encoding, mpa); + + private static Map readProperties(File file) { + Properties properties = new Properties(); + try (InputStream is = new FileInputStream(file)) { + properties.load(is); + } catch (IOException e) { + // too bad + } + return new HashMap((Map) properties); } - } - - private static Map readProperties(File file) { - Properties properties = new Properties(); - try (InputStream is = new FileInputStream(file)) { - properties.load(is); - } catch (IOException e) { - // too bad + + private void filterResource( + Resource input, + File sourceDirectory, + File targetDirectory, + Map filterProperties, + String encoding, + MissingPropertyAction mpa) + throws IOException { + File outputFile = relativize(sourceDirectory, targetDirectory, input.getResource()); + Output output = input.associateOutput(outputFile); + try (Reader reader = newReader(input, encoding); + Writer writer = newWriter(output, encoding)) { + filter(input, reader, writer, filterProperties, mpa); + } } - return new HashMap( (Map)properties ); - } - - private void filterResource(Resource input, File sourceDirectory, File targetDirectory, Map filterProperties, String encoding, MissingPropertyAction mpa) throws IOException { - File outputFile = relativize(sourceDirectory, targetDirectory, input.getResource()); - Output output = input.associateOutput(outputFile); - try (Reader reader = newReader(input, encoding); Writer writer = newWriter(output, encoding)) { - filter(input, reader, writer, filterProperties, mpa); + + public void filter( + Resource resource, Reader reader, Writer writer, Map properties, MissingPropertyAction mpa) + throws IOException { + NoEncodingMustacheFactory factory = new NoEncodingMustacheFactory(); + factory.setObjectHandler(new MapReflectionObjectHandler(resource, mpa)); + Mustache mustache = factory.compile(reader, "maven", M_START, M_END); + mustache.execute(writer, properties).close(); } - } - - public void filter(Resource resource, Reader reader, Writer writer, Map properties, MissingPropertyAction mpa) throws IOException { - NoEncodingMustacheFactory factory = new NoEncodingMustacheFactory(); - factory.setObjectHandler(new MapReflectionObjectHandler(resource, mpa)); - Mustache mustache = factory.compile(reader, "maven", M_START, M_END); - mustache.execute(writer, properties).close(); - } - - private Reader newReader(Resource resource, String encoding) throws IOException { - if (encoding == null) { - return new FileReader(resource.getResource()); - } else { - return new InputStreamReader(new FileInputStream(resource.getResource()), encoding); + + private Reader newReader(Resource resource, String encoding) throws IOException { + if (encoding == null) { + return new FileReader(resource.getResource()); + } else { + return new InputStreamReader(new FileInputStream(resource.getResource()), encoding); + } } - } - private Writer newWriter(Output output, String encoding) throws IOException { - if (encoding == null) { - return new OutputStreamWriter(output.newOutputStream()); - } else { - return new OutputStreamWriter(output.newOutputStream(), encoding); + private Writer newWriter(Output output, String encoding) throws IOException { + if (encoding == null) { + return new OutputStreamWriter(output.newOutputStream()); + } else { + return new OutputStreamWriter(output.newOutputStream(), encoding); + } } - } - - private static class NoEncodingMustacheFactory extends DefaultMustacheFactory { - @Override - public void encode(String value, Writer writer) { - // - // TODO: encoding rules - // - try { - writer.write(value); - } catch (IOException e) { - throw new MustacheException(e); - } + + private static class NoEncodingMustacheFactory extends DefaultMustacheFactory { + @Override + public void encode(String value, Writer writer) { + // + // TODO: encoding rules + // + try { + writer.write(value); + } catch (IOException e) { + throw new MustacheException(e); + } + } } - } - // workaround for https://github.com/spullara/mustache.java/issues/92 - // performs full-name map lookup before falling back to dot-notation parsing - private static class MapReflectionObjectHandler extends ReflectionObjectHandler { - private final Resource resource; + // workaround for https://github.com/spullara/mustache.java/issues/92 + // performs full-name map lookup before falling back to dot-notation parsing + private static class MapReflectionObjectHandler extends ReflectionObjectHandler { + private final Resource resource; - private final MissingPropertyAction missingPropertyAction; + private final MissingPropertyAction missingPropertyAction; - public MapReflectionObjectHandler(final Resource resource, final MissingPropertyAction missingPropertyAction) { - this.resource = resource; - this.missingPropertyAction = missingPropertyAction; - } + public MapReflectionObjectHandler(final Resource resource, final MissingPropertyAction missingPropertyAction) { + this.resource = resource; + this.missingPropertyAction = missingPropertyAction; + } - @Override - public Wrapper find(final String name, List scopes) { - Wrapper result = null; - for (final Object scope : scopes) { - if (scope instanceof Map && ((Map) scope).containsKey(name)) { - result = new Wrapper() { - @Override - public Object call(List scopes) throws GuardException { - return ((Map) scope).get(name); + @Override + public Wrapper find(final String name, List scopes) { + Wrapper result = null; + for (final Object scope : scopes) { + if (scope instanceof Map && ((Map) scope).containsKey(name)) { + result = new Wrapper() { + @Override + public Object call(List scopes) throws GuardException { + return ((Map) scope).get(name); + } + }; + break; + } } - }; - break; - } - } - if (result == null) { - result = super.find(name, scopes); - } - if (result instanceof MissingWrapper && missingPropertyAction != MissingPropertyAction.empty) { - if (missingPropertyAction == MissingPropertyAction.fail) { - String message = "Filtering: property '" + name + "' not found"; - if (resource == null) { - throw new MustacheException(message); - } else { - // TODO: get line/col somehow - resource.addMessage(1, 1, message, MessageSeverity.ERROR, null); - } - } else if (missingPropertyAction == MissingPropertyAction.leave) { - result = new Wrapper() { - @Override - public Object call(List scopes) throws GuardException { - return M_START + name + M_END; + if (result == null) { + result = super.find(name, scopes); + } + if (result instanceof MissingWrapper && missingPropertyAction != MissingPropertyAction.empty) { + if (missingPropertyAction == MissingPropertyAction.fail) { + String message = "Filtering: property '" + name + "' not found"; + if (resource == null) { + throw new MustacheException(message); + } else { + // TODO: get line/col somehow + resource.addMessage(1, 1, message, MessageSeverity.ERROR, null); + } + } else if (missingPropertyAction == MissingPropertyAction.leave) { + result = new Wrapper() { + @Override + public Object call(List scopes) throws GuardException { + return M_START + name + M_END; + } + }; + } } - }; + return result; } - } - return result; - } - @Override - public String stringify(Object object) { - if (object instanceof File) { - return object.toString().replace('\\', '/'); // I <3 Windows - } - return object.toString(); + @Override + public String stringify(Object object) { + if (object instanceof File) { + return object.toString().replace('\\', '/'); // I <3 Windows + } + return object.toString(); + } } - - } - } diff --git a/takari-lifecycle-plugin/src/main/java/io/takari/resources/filtering/MissingPropertyAction.java b/takari-lifecycle-plugin/src/main/java/io/takari/resources/filtering/MissingPropertyAction.java index 1826eb05..ea7a6d14 100644 --- a/takari-lifecycle-plugin/src/main/java/io/takari/resources/filtering/MissingPropertyAction.java +++ b/takari-lifecycle-plugin/src/main/java/io/takari/resources/filtering/MissingPropertyAction.java @@ -1,3 +1,10 @@ +/* + * Copyright (c) 2014-2024 Takari, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v10.html + */ package io.takari.resources.filtering; /** @@ -6,23 +13,23 @@ * @since 1.13.4 */ public enum MissingPropertyAction { - /** - * Filtering will result in empty string (this was the default behaviour of Takari Lifecycle). - */ - empty, + /** + * Filtering will result in empty string (this was the default behaviour of Takari Lifecycle). + */ + empty, - /** - * Filtering will leave the expression untouched (mimics maven-resources-plugin). - */ - leave, + /** + * Filtering will leave the expression untouched (mimics maven-resources-plugin). + */ + leave, - /** - * Error will be reported failing the build. - */ - fail; + /** + * Error will be reported failing the build. + */ + fail; - /** - * The default action, to not have it scattered and different across multiple Mojos. - */ - public static final MissingPropertyAction DEFAULT = MissingPropertyAction.empty; + /** + * The default action, to not have it scattered and different across multiple Mojos. + */ + public static final MissingPropertyAction DEFAULT = MissingPropertyAction.empty; } diff --git a/takari-lifecycle-plugin/src/main/java/io/takari/resources/filtering/ResourcesProcessor.java b/takari-lifecycle-plugin/src/main/java/io/takari/resources/filtering/ResourcesProcessor.java index 1f084c19..8a7e5039 100644 --- a/takari-lifecycle-plugin/src/main/java/io/takari/resources/filtering/ResourcesProcessor.java +++ b/takari-lifecycle-plugin/src/main/java/io/takari/resources/filtering/ResourcesProcessor.java @@ -1,12 +1,14 @@ -/** - * Copyright (c) 2014 Takari, Inc. +/* + * Copyright (c) 2014-2024 Takari, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * https://www.eclipse.org/legal/epl-v10.html */ package io.takari.resources.filtering; +import io.takari.incrementalbuild.BuildContext; +import io.takari.incrementalbuild.Resource; import java.io.File; import java.io.IOException; import java.io.Reader; @@ -14,44 +16,66 @@ import java.util.Collections; import java.util.List; import java.util.Map; - import javax.inject.Inject; import javax.inject.Named; import javax.inject.Singleton; -import io.takari.incrementalbuild.BuildContext; -import io.takari.incrementalbuild.Resource; - @Named @Singleton public class ResourcesProcessor { - private final CopyResourcesProcessor copyProcessor; - private final FilterResourcesProcessor filterProcessor; - - @Inject - public ResourcesProcessor(BuildContext buildContext) { - this.copyProcessor = new CopyResourcesProcessor(buildContext); - this.filterProcessor = new FilterResourcesProcessor(buildContext); - } - - public void process(File sourceDirectory, File targetDirectory, List includes, List excludes, String encoding) throws IOException { - copyProcessor.process(sourceDirectory, targetDirectory, includes, excludes, encoding); - } + private final CopyResourcesProcessor copyProcessor; + private final FilterResourcesProcessor filterProcessor; - public void process(File sourceDirectory, File targetDirectory, List includes, List excludes, Map filterProperties, String encoding, MissingPropertyAction mpa) - throws IOException { - filterProcessor.process(sourceDirectory, targetDirectory, includes, excludes, filterProperties, Collections.emptyList(), encoding, mpa); - } + @Inject + public ResourcesProcessor(BuildContext buildContext) { + this.copyProcessor = new CopyResourcesProcessor(buildContext); + this.filterProcessor = new FilterResourcesProcessor(buildContext); + } - public void process(File sourceDirectory, File targetDirectory, List includes, List excludes, Map filterProperties, List filters, String encoding, - MissingPropertyAction mpa) throws IOException { - filterProcessor.process(sourceDirectory, targetDirectory, includes, excludes, filterProperties, filters, encoding, mpa); - } + public void process( + File sourceDirectory, File targetDirectory, List includes, List excludes, String encoding) + throws IOException { + copyProcessor.process(sourceDirectory, targetDirectory, includes, excludes, encoding); + } - public void filter(Resource resource, Reader reader, Writer writer, Map properties, MissingPropertyAction mpa) throws IOException { - filterProcessor.filter(resource, reader, writer, properties, mpa); - } + public void process( + File sourceDirectory, + File targetDirectory, + List includes, + List excludes, + Map filterProperties, + String encoding, + MissingPropertyAction mpa) + throws IOException { + filterProcessor.process( + sourceDirectory, + targetDirectory, + includes, + excludes, + filterProperties, + Collections.emptyList(), + encoding, + mpa); + } + public void process( + File sourceDirectory, + File targetDirectory, + List includes, + List excludes, + Map filterProperties, + List filters, + String encoding, + MissingPropertyAction mpa) + throws IOException { + filterProcessor.process( + sourceDirectory, targetDirectory, includes, excludes, filterProperties, filters, encoding, mpa); + } + public void filter( + Resource resource, Reader reader, Writer writer, Map properties, MissingPropertyAction mpa) + throws IOException { + filterProcessor.filter(resource, reader, writer, properties, mpa); + } } diff --git a/takari-lifecycle-plugin/src/main/m2e/lifecycle-mapping-metadata.xml b/takari-lifecycle-plugin/src/main/m2e/lifecycle-mapping-metadata.xml index 63e43309..55e4eaee 100644 --- a/takari-lifecycle-plugin/src/main/m2e/lifecycle-mapping-metadata.xml +++ b/takari-lifecycle-plugin/src/main/m2e/lifecycle-mapping-metadata.xml @@ -1,10 +1,10 @@ diff --git a/takari-lifecycle-plugin/src/main/mdo/mojos.xml b/takari-lifecycle-plugin/src/main/mdo/mojos.xml index 94083e8b..b1beaaa5 100644 --- a/takari-lifecycle-plugin/src/main/mdo/mojos.xml +++ b/takari-lifecycle-plugin/src/main/mdo/mojos.xml @@ -1,4 +1,13 @@ + diff --git a/takari-lifecycle-plugin/src/main/resources-filtered/META-INF/plexus/components.xml b/takari-lifecycle-plugin/src/main/resources-filtered/META-INF/plexus/components.xml index fa6fec1a..ff8b5482 100644 --- a/takari-lifecycle-plugin/src/main/resources-filtered/META-INF/plexus/components.xml +++ b/takari-lifecycle-plugin/src/main/resources-filtered/META-INF/plexus/components.xml @@ -1,11 +1,11 @@ diff --git a/takari-lifecycle-plugin/src/test-input/src/main/org/codehaus/foo/Bad.java b/takari-lifecycle-plugin/src/test-input/src/main/org/codehaus/foo/Bad.java index 459cf636..60e41758 100644 --- a/takari-lifecycle-plugin/src/test-input/src/main/org/codehaus/foo/Bad.java +++ b/takari-lifecycle-plugin/src/test-input/src/main/org/codehaus/foo/Bad.java @@ -1,9 +1,9 @@ -/** - * Copyright (c) 2014 Takari, Inc. +/* + * Copyright (c) 2014-2024 Takari, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * https://www.eclipse.org/legal/epl-v10.html */ package org.codehaus.foo; diff --git a/takari-lifecycle-plugin/src/test-input/src/main/org/codehaus/foo/Deprecation.java b/takari-lifecycle-plugin/src/test-input/src/main/org/codehaus/foo/Deprecation.java index 2647383b..fb0e81de 100644 --- a/takari-lifecycle-plugin/src/test-input/src/main/org/codehaus/foo/Deprecation.java +++ b/takari-lifecycle-plugin/src/test-input/src/main/org/codehaus/foo/Deprecation.java @@ -1,9 +1,9 @@ -/** - * Copyright (c) 2014 Takari, Inc. +/* + * Copyright (c) 2014-2024 Takari, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * https://www.eclipse.org/legal/epl-v10.html */ package org.codehaus.foo; diff --git a/takari-lifecycle-plugin/src/test-input/src/main/org/codehaus/foo/ExternalDeps.java b/takari-lifecycle-plugin/src/test-input/src/main/org/codehaus/foo/ExternalDeps.java index a61b0654..6efac5d7 100644 --- a/takari-lifecycle-plugin/src/test-input/src/main/org/codehaus/foo/ExternalDeps.java +++ b/takari-lifecycle-plugin/src/test-input/src/main/org/codehaus/foo/ExternalDeps.java @@ -1,9 +1,9 @@ -/** - * Copyright (c) 2014 Takari, Inc. +/* + * Copyright (c) 2014-2024 Takari, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * https://www.eclipse.org/legal/epl-v10.html */ package org.codehaus.foo; diff --git a/takari-lifecycle-plugin/src/test-input/src/main/org/codehaus/foo/Person.java b/takari-lifecycle-plugin/src/test-input/src/main/org/codehaus/foo/Person.java index 1d0d526b..9f39becf 100644 --- a/takari-lifecycle-plugin/src/test-input/src/main/org/codehaus/foo/Person.java +++ b/takari-lifecycle-plugin/src/test-input/src/main/org/codehaus/foo/Person.java @@ -1,9 +1,9 @@ -/** - * Copyright (c) 2014 Takari, Inc. +/* + * Copyright (c) 2014-2024 Takari, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * https://www.eclipse.org/legal/epl-v10.html */ package org.codehaus.foo; diff --git a/takari-lifecycle-plugin/src/test-input/src/main/org/codehaus/foo/ReservedWord.java b/takari-lifecycle-plugin/src/test-input/src/main/org/codehaus/foo/ReservedWord.java index 8d83d416..122ace85 100644 --- a/takari-lifecycle-plugin/src/test-input/src/main/org/codehaus/foo/ReservedWord.java +++ b/takari-lifecycle-plugin/src/test-input/src/main/org/codehaus/foo/ReservedWord.java @@ -1,9 +1,9 @@ -/** - * Copyright (c) 2014 Takari, Inc. +/* + * Copyright (c) 2014-2024 Takari, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * https://www.eclipse.org/legal/epl-v10.html */ package org.codehaus.foo; diff --git a/takari-lifecycle-plugin/src/test-input/src/main/org/codehaus/foo/UnknownSymbol.java b/takari-lifecycle-plugin/src/test-input/src/main/org/codehaus/foo/UnknownSymbol.java index 1e4333d2..b455191e 100644 --- a/takari-lifecycle-plugin/src/test-input/src/main/org/codehaus/foo/UnknownSymbol.java +++ b/takari-lifecycle-plugin/src/test-input/src/main/org/codehaus/foo/UnknownSymbol.java @@ -1,9 +1,9 @@ -/** - * Copyright (c) 2014 Takari, Inc. +/* + * Copyright (c) 2014-2024 Takari, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * https://www.eclipse.org/legal/epl-v10.html */ package org.codehaus.foo; diff --git a/takari-lifecycle-plugin/src/test-input/src/main/org/codehaus/foo/WrongClassname.java b/takari-lifecycle-plugin/src/test-input/src/main/org/codehaus/foo/WrongClassname.java index 664bae1a..e0111945 100644 --- a/takari-lifecycle-plugin/src/test-input/src/main/org/codehaus/foo/WrongClassname.java +++ b/takari-lifecycle-plugin/src/test-input/src/main/org/codehaus/foo/WrongClassname.java @@ -1,9 +1,9 @@ -/** - * Copyright (c) 2014 Takari, Inc. +/* + * Copyright (c) 2014-2024 Takari, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * https://www.eclipse.org/legal/epl-v10.html */ package org.codehaus.foo; diff --git a/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/compile/AbstractCompileTest.java b/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/compile/AbstractCompileTest.java index 498ed518..9806d75b 100644 --- a/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/compile/AbstractCompileTest.java +++ b/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/compile/AbstractCompileTest.java @@ -1,9 +1,9 @@ package io.takari.maven.plugins.compile; +import io.takari.maven.testing.TestResources; import java.io.File; import java.util.Arrays; import java.util.StringTokenizer; - import org.apache.maven.plugin.MojoExecution; import org.apache.maven.project.MavenProject; import org.codehaus.plexus.util.xml.Xpp3Dom; @@ -12,94 +12,95 @@ import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; -import io.takari.maven.testing.TestResources; - @RunWith(Parameterized.class) public abstract class AbstractCompileTest { - public static final boolean isJava8orBetter; - public static final boolean isJava9orBetter; - public static final boolean isJava10orBetter; - public static final boolean isJava11orBetter; - - static { - boolean _isJava8orBetter = false; - boolean _isJava9orBetter = false; - boolean _isJava10orBetter = false; - boolean _isJava11orBetter = false; - - String version = System.getProperty("java.specification.version"); - if (version != null) { - StringTokenizer st = new StringTokenizer(version, "."); - int major = Integer.parseInt(st.nextToken()); - if (major >= 11) { - _isJava8orBetter = true; - _isJava9orBetter = true; - _isJava10orBetter = true; - _isJava11orBetter = true; - } else if (major >= 10) { - _isJava8orBetter = true; - _isJava9orBetter = true; - _isJava10orBetter = true; - } else if (major >= 9) { - _isJava8orBetter = true; - _isJava9orBetter = true; - } else { - int minor = Integer.parseInt(st.nextToken()); - _isJava8orBetter = minor >= 8; - } + public static final boolean isJava8orBetter; + public static final boolean isJava9orBetter; + public static final boolean isJava10orBetter; + public static final boolean isJava11orBetter; + + static { + boolean _isJava8orBetter = false; + boolean _isJava9orBetter = false; + boolean _isJava10orBetter = false; + boolean _isJava11orBetter = false; + + String version = System.getProperty("java.specification.version"); + if (version != null) { + StringTokenizer st = new StringTokenizer(version, "."); + int major = Integer.parseInt(st.nextToken()); + if (major >= 11) { + _isJava8orBetter = true; + _isJava9orBetter = true; + _isJava10orBetter = true; + _isJava11orBetter = true; + } else if (major >= 10) { + _isJava8orBetter = true; + _isJava9orBetter = true; + _isJava10orBetter = true; + } else if (major >= 9) { + _isJava8orBetter = true; + _isJava9orBetter = true; + } else { + int minor = Integer.parseInt(st.nextToken()); + _isJava8orBetter = minor >= 8; + } + } + + isJava8orBetter = _isJava8orBetter; + isJava9orBetter = _isJava9orBetter; + isJava10orBetter = _isJava10orBetter; + isJava11orBetter = _isJava11orBetter; } - isJava8orBetter = _isJava8orBetter; - isJava9orBetter = _isJava9orBetter; - isJava10orBetter = _isJava10orBetter; - isJava11orBetter = _isJava11orBetter; - } - - @Rule - public final TestResources resources = new TestResources(); - - @Rule - public final CompileRule mojos = new CompileRule() { - @Override - public MojoExecution newMojoExecution(String goal, Xpp3Dom... parameters) { - MojoExecution execution = super.newMojoExecution(goal, parameters); - execution.getConfiguration().addChild(newParameter("compilerId", compilerId)); - return execution; + @Rule + public final TestResources resources = new TestResources(); + + @Rule + public final CompileRule mojos = new CompileRule() { + @Override + public MojoExecution newMojoExecution(String goal, Xpp3Dom... parameters) { + MojoExecution execution = super.newMojoExecution(goal, parameters); + execution.getConfiguration().addChild(newParameter("compilerId", compilerId)); + return execution; + } + ; }; - }; - protected final String compilerId; + protected final String compilerId; - protected AbstractCompileTest(String compilerId) { - this.compilerId = compilerId; - } + protected AbstractCompileTest(String compilerId) { + this.compilerId = compilerId; + } - @Parameters(name = "{0}") - public static Iterable compilers() { - return Arrays.asList( // - new Object[] {"javac"} // - , new Object[] {"forked-javac"} // - , new Object[] {"jdt"} // - ); - } + @Parameters(name = "{0}") + public static Iterable compilers() { + return Arrays.asList( // + new Object[] {"javac"} // + , + new Object[] {"forked-javac"} // + , + new Object[] {"jdt"} // + ); + } - protected File compile(String name, Xpp3Dom... parameters) throws Exception { - File basedir = resources.getBasedir(name); - return mojos.compile(basedir, parameters); - } + protected File compile(String name, Xpp3Dom... parameters) throws Exception { + File basedir = resources.getBasedir(name); + return mojos.compile(basedir, parameters); + } - protected File compile(File basedir, Xpp3Dom... parameters) throws Exception { - return mojos.compile(basedir, parameters); - } + protected File compile(File basedir, Xpp3Dom... parameters) throws Exception { + return mojos.compile(basedir, parameters); + } - protected void addDependency(MavenProject project, String artifactId, File file) throws Exception { - mojos.newDependency(file).setArtifactId(artifactId).addTo(project); - } + protected void addDependency(MavenProject project, String artifactId, File file) throws Exception { + mojos.newDependency(file).setArtifactId(artifactId).addTo(project); + } - protected Xpp3Dom newParameter(String name, String value) { - Xpp3Dom child = new Xpp3Dom(name); - child.setValue(value); - return child; - } + protected Xpp3Dom newParameter(String name, String value) { + Xpp3Dom child = new Xpp3Dom(name); + child.setValue(value); + return child; + } } diff --git a/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/compile/AnnotationProcessingTest.java b/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/compile/AnnotationProcessingTest.java index 4e272aa6..7f519788 100644 --- a/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/compile/AnnotationProcessingTest.java +++ b/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/compile/AnnotationProcessingTest.java @@ -6,6 +6,14 @@ import static io.takari.maven.testing.TestResources.touch; import static org.junit.Assert.fail; +import com.squareup.javapoet.AnnotationSpec; +import com.squareup.javapoet.ClassName; +import com.squareup.javapoet.FieldSpec; +import com.squareup.javapoet.JavaFile; +import com.squareup.javapoet.TypeSpec; +import io.takari.maven.plugins.compile.AbstractCompileMojo.Proc; +import io.takari.maven.plugins.compile.javac.CompilerJavac; +import io.takari.maven.plugins.compile.jdt.CompilerJdt; import java.io.File; import java.io.IOException; import java.util.ArrayList; @@ -14,7 +22,6 @@ import java.util.HashSet; import java.util.List; import java.util.Set; - import org.apache.maven.execution.MavenSession; import org.apache.maven.plugin.MojoExecution; import org.apache.maven.plugin.MojoExecutionException; @@ -27,1267 +34,1392 @@ import org.junit.Test; import org.junit.runners.Parameterized.Parameters; -import com.squareup.javapoet.AnnotationSpec; -import com.squareup.javapoet.ClassName; -import com.squareup.javapoet.FieldSpec; -import com.squareup.javapoet.JavaFile; -import com.squareup.javapoet.TypeSpec; +public class AnnotationProcessingTest extends AbstractCompileTest { -import io.takari.maven.plugins.compile.AbstractCompileMojo.Proc; -import io.takari.maven.plugins.compile.javac.CompilerJavac; -import io.takari.maven.plugins.compile.jdt.CompilerJdt; + public AnnotationProcessingTest(String compilerId) { + super(compilerId); + } -public class AnnotationProcessingTest extends AbstractCompileTest { + @Parameters(name = "{0}") + public static Iterable compilers() { + List compilers = new ArrayList(); + compilers.add(new Object[] {"javac"}); + compilers.add(new Object[] {"forked-javac"}); + compilers.add(new Object[] {"jdt"}); + return compilers; + } - public AnnotationProcessingTest(String compilerId) { - super(compilerId); - } - - @Parameters(name = "{0}") - public static Iterable compilers() { - List compilers = new ArrayList(); - compilers.add(new Object[] {"javac"}); - compilers.add(new Object[] {"forked-javac"}); - compilers.add(new Object[] {"jdt"}); - return compilers; - } - - private File procCompile(String projectName, Proc proc, Xpp3Dom... parameters) throws Exception, IOException { - File basedir = resources.getBasedir(projectName); - return procCompile(basedir, proc, parameters); - } - - private File procCompile(File basedir, Proc proc, Xpp3Dom... parameters) throws Exception, IOException { - File processor = compileAnnotationProcessor(); - return processAnnotations(basedir, proc, processor, parameters); - } - - private File processAnnotations(File basedir, Proc proc, File processor, Xpp3Dom... parameters) throws Exception { - MavenProject project = mojos.readMavenProject(basedir); - processAnnotations(project, processor, proc, parameters); - return basedir; - } - - protected void processAnnotations(MavenProject project, File processor, Proc proc, Xpp3Dom... parameters) throws Exception { - MavenSession session = mojos.newMavenSession(project); - processAnnotations(session, project, "compile", processor, proc, parameters); - } - - protected void processAnnotations(MavenSession session, MavenProject project, String goal, File processor, Proc proc, Xpp3Dom... parameters) throws Exception { - MojoExecution execution = mojos.newMojoExecution(goal); - - addDependency(project, "processor", new File(processor, "target/classes")); - - Xpp3Dom configuration = execution.getConfiguration(); - - if (proc != null) { - configuration.addChild(newParameter("proc", proc.name())); + private File procCompile(String projectName, Proc proc, Xpp3Dom... parameters) throws Exception, IOException { + File basedir = resources.getBasedir(projectName); + return procCompile(basedir, proc, parameters); } - if (parameters != null) { - for (Xpp3Dom parameter : parameters) { - configuration.addChild(parameter); - } + + private File procCompile(File basedir, Proc proc, Xpp3Dom... parameters) throws Exception, IOException { + File processor = compileAnnotationProcessor(); + return processAnnotations(basedir, proc, processor, parameters); } - mojos.executeMojo(session, project, execution); - } - - private File compileAnnotationProcessor() throws Exception, IOException { - File processor = compile("compile-proc/processor"); - cp(processor, "src/main/resources/META-INF/services/javax.annotation.processing.Processor", "target/classes/META-INF/services/javax.annotation.processing.Processor"); - return processor; - } - - - @Test - public void testProc_only() throws Exception { - File basedir = procCompile("compile-proc/proc", Proc.only); - mojos.assertBuildOutputs(new File(basedir, "target/generated-sources/annotations"), "proc/GeneratedSource.java", "proc/AnotherGeneratedSource.java"); - } - - @Test - public void testProc_none() throws Exception { - File basedir = procCompile("compile-proc/proc", Proc.none); - mojos.assertBuildOutputs(new File(basedir, "target"), "classes/proc/Source.class"); - } - - @Test - public void testProc_proc() throws Exception { - File basedir = procCompile("compile-proc/proc", Proc.proc); - mojos.assertBuildOutputs(new File(basedir, "target"), // - "classes/proc/Source.class", // - "generated-sources/annotations/proc/GeneratedSource.java", // - "classes/proc/GeneratedSource.class", // - "generated-sources/annotations/proc/AnotherGeneratedSource.java", // - "classes/proc/AnotherGeneratedSource.class"); - } - - @Test - public void testProc_incrementalTypeIndex() throws Exception { - File processor = compileAnnotationProcessor(); - File basedir = resources.getBasedir("compile-proc/proc"); - File src = new File(basedir, "src/main/java"); - - processAnnotations(basedir, Proc.proc, processor, newProcessors("processor.ProcessorLastRound")); - mojos.assertBuildOutputs(new File(basedir, "target/classes"), "proc/Source.class", "types.lst"); - assertFileContents("proc.Source\n", basedir, "target/classes/types.lst"); - - // create new annotated source and run incremental build - JavaFile.builder("proc", // - TypeSpec.classBuilder("AnotherSource") // - .addAnnotation(AnnotationSpec.builder(ClassName.get("processor", "Annotation")).build()) // - .build()) // - .build().writeTo(src); - processAnnotations(basedir, Proc.proc, processor, newProcessors("processor.ProcessorLastRound")); - mojos.assertBuildOutputs(new File(basedir, "target/classes"), "proc/Source.class", "proc/AnotherSource.class", "types.lst"); - assertFileContents("proc.AnotherSource\nproc.Source\n", basedir, "target/classes/types.lst"); - - // delete the new source and run incremental build - rm(src, "proc/AnotherSource.java"); - processAnnotations(basedir, Proc.proc, processor, newProcessors("processor.ProcessorLastRound")); - mojos.assertBuildOutputs(new File(basedir, "target/classes"), "proc/Source.class", "types.lst"); - mojos.assertDeletedOutputs(new File(basedir, "target/classes"), "proc/AnotherSource.class"); - assertFileContents("proc.Source\n", basedir, "target/classes/types.lst"); - } - - @Test - public void testProc_incrementalProcessorChange() throws Exception { - File processor = compileAnnotationProcessor(); - File basedir = resources.getBasedir("compile-proc/proc"); - processAnnotations(basedir, Proc.proc, processor); - mojos.assertBuildOutputs(new File(basedir, "target"), // - "classes/proc/Source.class", // - "generated-sources/annotations/proc/GeneratedSource.java", // - "classes/proc/GeneratedSource.class", // - "generated-sources/annotations/proc/AnotherGeneratedSource.java", // - "classes/proc/AnotherGeneratedSource.class"); - - rm(processor, "target/classes/META-INF/services/javax.annotation.processing.Processor"); - mojos.flushClasspathCaches(); - processAnnotations(basedir, Proc.proc, processor); - mojos.assertBuildOutputs(new File(basedir, "target"), "classes/proc/Source.class"); - mojos.assertDeletedOutputs(new File(basedir, "target"), // - "generated-sources/annotations/proc/GeneratedSource.java", // - "classes/proc/GeneratedSource.class", // - "generated-sources/annotations/proc/AnotherGeneratedSource.java", // - "classes/proc/AnotherGeneratedSource.class"); - } - - @Test - public void testProc_dummyOutput() throws Exception { - File basedir = procCompile("compile-proc/proc", Proc.proc, newProcessors("processor.Processor_dummyOutput")); - mojos.assertBuildOutputs(new File(basedir, "target"), "classes/proc/Source.class"); - } - - @Test - public void testProcTypeReference() throws Exception { - File basedir = procCompile("compile-proc/proc-type-reference", Proc.proc); - mojos.assertBuildOutputs(new File(basedir, "target"), // - "classes/proc/Source.class", // - "classes/proc/GeneratedSourceSubclass.class", // - "generated-sources/annotations/proc/GeneratedSource.java", // - "classes/proc/GeneratedSource.class", // - "generated-sources/annotations/proc/AnotherGeneratedSource.java", // - "classes/proc/AnotherGeneratedSource.class"); - } - - @Test - public void testProc_createResource() throws Exception { - File basedir = procCompile("compile-proc/proc", Proc.proc, newProcessors("processor.ProcessorCreateResource")); - mojos.assertBuildOutputs(new File(basedir, "target"), // - "classes/proc/Source.class", // - "generated-sources/annotations/proc/GeneratedSource.java"); - } - - // The following five tests help test the behavior of the full and incremental - // compile strategies of the CompilerJdt with regards to Annotation Processing. - // Incremental compile is triggered on the last two tests with a second compile step - // to force apt to run in a course grained incremental manner. - // Both final round only and during each round APT code generators are tested. - - /** - * This test compiles with the a non-final round processor. - * - * There are no forward references that attempt to use the newly generated type. - * - * Note the use of "processor.Processor" and the "compile-proc/proc" project in this test. - */ - @Test - public void testProc_annotationProcessors() throws Exception { - Xpp3Dom processors = newProcessors("processor.Processor"); - File basedir = procCompile("compile-proc/proc", Proc.proc, processors); - mojos.assertBuildOutputs(new File(basedir, "target"), // - "classes/proc/Source.class", // - "generated-sources/annotations/proc/GeneratedSource.java", // - "classes/proc/GeneratedSource.class"); - } - - /** - * This test generates code in each round of an apt processor. - * - * There are is a forward reference which attempt to use the newly generated type as a super class. - * - * Any reference to the new type would be sufficient for this test. - * - * Note the use of "processor.Processor" and the "compile-proc/proc-type-reference" project in this test. - */ - @Test - public void testProcRef_annotationProcessors() throws Exception { - Xpp3Dom processors = newProcessors("processor.Processor"); - File basedir = procCompile("compile-proc/proc-type-reference", Proc.proc, processors); - mojos.assertBuildOutputs(new File(basedir, "target"), // - "classes/proc/Source.class", // - "generated-sources/annotations/proc/GeneratedSource.java", // - "classes/proc/GeneratedSource.class", // - "classes/proc/GeneratedSourceSubclass.class"); - } - - - /** - * This test generates code in the final round of an apt processor. - * - * There are is a forward reference which attempt to use the newly generated type as a super class. - * - * Any reference to the new type would be sufficient for this test. - * - * Note the use of "processor.ProcessorImplLastRound" and the "compile-proc/proc-type-reference" project in this test. - */ - @Test - public void testProcRef_annotationProcessors_LastRound() throws Exception { - // javac can't handle forward references in the last round, but jdt can. - Assume.assumeTrue(CompilerJdt.ID.equals(compilerId)); - Xpp3Dom processors = newProcessors("processor.ProcessorImplLastRound"); - File basedir = procCompile("compile-proc/proc-type-reference", Proc.proc, processors); - - mojos.assertBuildOutputs(new File(basedir, "target"), // - "classes/proc/Source.class", // - "generated-sources/annotations/proc/GeneratedSource.java", // - "classes/proc/GeneratedSource.class", // - "classes/proc/GeneratedSourceSubclass.class"); - } - - /** - * This test generates code in each round of an apt processor. - * - * There are is a forward reference which attempt to use the newly generated type as a super class. Any reference to the new type would be sufficient for this test. - * - * This test the touches an annotated type and runs an incremental compile where much of the same code is forced to be recompiled. - * - * Note the use of "processor.Processor" and the "compile-proc/proc-type-reference" project in this test. - */ - @Test - public void testProcRef_annotationProcessors_recompile() throws Exception { - Xpp3Dom processors = newProcessors("processor.Processor"); - File basedir = procCompile("compile-proc/proc-type-reference", Proc.proc, processors); - mojos.assertBuildOutputs(new File(basedir, "target"), // - "classes/proc/Source.class", // - "generated-sources/annotations/proc/GeneratedSource.java", // - "classes/proc/GeneratedSource.class", // - "classes/proc/GeneratedSourceSubclass.class"); - - touch(basedir, "src/main/java/proc/Source.java"); - - procCompile(basedir, Proc.proc, processors); - - String[] expectedOuput; - if (CompilerJdt.ID.equals(compilerId)) { - // incremental in jdt compile means that GeneratedSourceSubclass sees no - // structural change and doesn't need to be recompiled. - expectedOuput = new String[] {// - "classes/proc/Source.class", // - "generated-sources/annotations/proc/GeneratedSource.java", // - "classes/proc/GeneratedSource.class"}; - } else { - expectedOuput = new String[] { // - // everything is recompiled by javac - "classes/proc/Source.class", // - "generated-sources/annotations/proc/GeneratedSource.java", // - "classes/proc/GeneratedSource.class", // - "classes/proc/GeneratedSourceSubclass.class"}; + private File processAnnotations(File basedir, Proc proc, File processor, Xpp3Dom... parameters) throws Exception { + MavenProject project = mojos.readMavenProject(basedir); + processAnnotations(project, processor, proc, parameters); + return basedir; } - mojos.assertBuildOutputs(new File(basedir, "target"), expectedOuput); - } - - /** - * This test generates code in the final round of an apt processor. - * - * There are is a forward reference which attempt to use the newly generated type as a super class. Any reference to the new type would be sufficient for this test. - * - * This test the touches an annotated type and runs an incremental compile where much of the same code is forced to be recompiled. - * - * Note the use of "processor.ProcessorImplLastRound" and the "compile-proc/proc-type-reference" project in this test. - */ - @Test - public void testProcRef_annotationProcessors_LastRound_recompile() throws Exception { - // javac can't handle forward references in the last round, but jdt can. - Assume.assumeTrue(CompilerJdt.ID.equals(compilerId)); - Xpp3Dom processors = newProcessors("processor.ProcessorImplLastRound"); - File basedir = procCompile("compile-proc/proc-type-reference", Proc.proc, processors); - mojos.assertBuildOutputs(new File(basedir, "target"), // - "classes/proc/Source.class", // - "generated-sources/annotations/proc/GeneratedSource.java", // - "classes/proc/GeneratedSource.class", // - "classes/proc/GeneratedSourceSubclass.class"); - - touch(basedir, "src/main/java/proc/Source.java"); - - procCompile(basedir, Proc.proc, processors); - - // okay this is a little wonky. Since source was recompiled, we delete it's - // apt generated type, which is referenced by GeneratedSourceSubclass, once it's - // deleted we then generated the GeneratedSource, compile it, and then have to - // recompile GeneratedSourceSubclass, hence it appears in this test and not - // testProcRef_annotationProcessors_recompile's list of output for jdt. - mojos.assertBuildOutputs(new File(basedir, "target"), // - "classes/proc/Source.class", // - "generated-sources/annotations/proc/GeneratedSource.java", // - "classes/proc/GeneratedSource.class", // - "classes/proc/GeneratedSourceSubclass.class"); - } - - - @Test - public void testProc_processorErrorMessage() throws Exception { - Xpp3Dom processors = newProcessors("processor.ErrorMessageProcessor"); - File basedir = resources.getBasedir("compile-proc/proc"); - try { - procCompile(basedir, Proc.only, processors); - Assert.fail(); - } catch (MojoExecutionException e) { - // expected + + protected void processAnnotations(MavenProject project, File processor, Proc proc, Xpp3Dom... parameters) + throws Exception { + MavenSession session = mojos.newMavenSession(project); + processAnnotations(session, project, "compile", processor, proc, parameters); } - mojos.assertBuildOutputs(new File(basedir, "target"), new String[0]); - - ErrorMessage expected = new ErrorMessage(compilerId); - expected.setSnippets("jdt", "ERROR Source.java [6:14] test error message"); // TODO why 14? - expected.setSnippets("javac", "ERROR Source.java [6:8] test error message"); - mojos.assertMessage(basedir, "src/main/java/proc/Source.java", expected); - - Collection pomMessages = mojos.getBuildContextLog().getMessages(new File(basedir, "pom.xml")); - Assert.assertEquals(3, pomMessages.size()); - // TODO assert actual messages are as expected - } - - @Test - public void testProc_messages() throws Exception { - ErrorMessage expected = new ErrorMessage(compilerId); - expected.setSnippets("javac", "ERROR BrokenSource.java [2:29]", "cannot find symbol"); - expected.setSnippets("jdt", "ERROR BrokenSource.java [2:29]", "cannot be resolved to a type"); - - File processor = compileAnnotationProcessor(); - File basedir = resources.getBasedir("compile-proc/proc"); - - String[] outputs; - if (CompilerJdt.ID.equals(compilerId)) { - outputs = new String[] {"classes/proc/Source.class" // - , "generated-sources/annotations/proc/BrokenSource.java"}; - } else { - // TODO investigate why javac does not generate classes/proc/Source.class - outputs = new String[] {"generated-sources/annotations/proc/BrokenSource.java"}; + + protected void processAnnotations( + MavenSession session, MavenProject project, String goal, File processor, Proc proc, Xpp3Dom... parameters) + throws Exception { + MojoExecution execution = mojos.newMojoExecution(goal); + + addDependency(project, "processor", new File(processor, "target/classes")); + + Xpp3Dom configuration = execution.getConfiguration(); + + if (proc != null) { + configuration.addChild(newParameter("proc", proc.name())); + } + if (parameters != null) { + for (Xpp3Dom parameter : parameters) { + configuration.addChild(parameter); + } + } + + mojos.executeMojo(session, project, execution); } - Xpp3Dom processors = newProcessors("processor.BrokenProcessor"); - try { - processAnnotations(basedir, Proc.proc, processor, processors); - Assert.fail(); - } catch (MojoExecutionException e) { - // expected + private File compileAnnotationProcessor() throws Exception, IOException { + File processor = compile("compile-proc/processor"); + cp( + processor, + "src/main/resources/META-INF/services/javax.annotation.processing.Processor", + "target/classes/META-INF/services/javax.annotation.processing.Processor"); + return processor; } - mojos.assertBuildOutputs(new File(basedir, "target"), outputs); - assertProcMessage(basedir, "target/generated-sources/annotations/proc/BrokenSource.java", expected); - - // no change rebuild should produce the same messages - try { - processAnnotations(basedir, Proc.proc, processor, processors); - Assert.fail(); - } catch (MojoExecutionException e) { - // expected + + @Test + public void testProc_only() throws Exception { + File basedir = procCompile("compile-proc/proc", Proc.only); + mojos.assertBuildOutputs( + new File(basedir, "target/generated-sources/annotations"), + "proc/GeneratedSource.java", + "proc/AnotherGeneratedSource.java"); } - mojos.assertCarriedOverOutputs(new File(basedir, "target"), outputs); - assertProcMessage(basedir, "target/generated-sources/annotations/proc/BrokenSource.java", expected); - } - - private void assertProcMessage(File basedir, String path, ErrorMessage expected) throws Exception { - // javac reports the same compilation error twice when Proc.proc - Set messages = new HashSet(mojos.getBuildContextLog().getMessages(new File(basedir, path))); - Assert.assertEquals(messages.toString(), 1, messages.size()); - String message = messages.iterator().next(); - Assert.assertTrue(expected.isMatch(message)); - } - - @Test - public void testProc_processorOptions() throws Exception { - Xpp3Dom processors = newProcessors("processor.ProcessorWithOptions"); - - Xpp3Dom options = new Xpp3Dom("annotationProcessorOptions"); - options.addChild(newParameter("optionA", "valueA")); - options.addChild(newParameter("optionB", "valueB")); - procCompile("compile-proc/proc", Proc.proc, processors, options); - } - - @Test - public void testProc_staleGeneratedSourcesCleanup() throws Exception { - File processor = compileAnnotationProcessor(); - File basedir = resources.getBasedir("compile-proc/proc"); - - processAnnotations(basedir, Proc.proc, processor); - mojos.assertBuildOutputs(new File(basedir, "target"), // - "classes/proc/Source.class", // - "generated-sources/annotations/proc/GeneratedSource.java", // - "classes/proc/GeneratedSource.class", // - "generated-sources/annotations/proc/AnotherGeneratedSource.java", // - "classes/proc/AnotherGeneratedSource.class"); - - // remove annotation - cp(basedir, "src/main/java/proc/Source.java-remove-annotation", "src/main/java/proc/Source.java"); - processAnnotations(basedir, Proc.proc, processor); - mojos.assertDeletedOutputs(new File(basedir, "target"), // - "generated-sources/annotations/proc/GeneratedSource.java", // - "classes/proc/GeneratedSource.class", // - "generated-sources/annotations/proc/AnotherGeneratedSource.java", // - "classes/proc/AnotherGeneratedSource.class"); - } - - @Test - public void testProc_incrementalDeleteLastAnnotatedSource() throws Exception { - File processor = compileAnnotationProcessor(); - File basedir = resources.getBasedir("compile-proc/proc"); - - Xpp3Dom processors = newProcessors("processor.Processor"); - - // initial compilation - processAnnotations(basedir, Proc.proc, processor, processors); - mojos.assertBuildOutputs(new File(basedir, "target"), // - "classes/proc/Source.class", // - "generated-sources/annotations/proc/GeneratedSource.java", // - "classes/proc/GeneratedSource.class"); - - // no-change rebuild - processAnnotations(basedir, Proc.proc, processor, processors); - mojos.assertCarriedOverOutputs(new File(basedir, "target"), // - "classes/proc/Source.class", // - "generated-sources/annotations/proc/GeneratedSource.java", // - "classes/proc/GeneratedSource.class"); - - // remove annotated class - rm(basedir, "src/main/java/proc/Source.java"); - processAnnotations(basedir, Proc.proc, processor, processors); - mojos.assertDeletedOutputs(new File(basedir, "target"), // - "generated-sources/annotations/proc/GeneratedSource.java", // - "classes/proc/Source.class", // - "classes/proc/GeneratedSource.class"); - } - - @Test - public void testProc_nonIncrementalProcessor_onlyEX_deleteSource() throws Exception { - File processor = compileAnnotationProcessor(); - - File basedir = resources.getBasedir("compile-proc/proc"); - File target = new File(basedir, "target"); - - Xpp3Dom processors = newProcessors("processor.NonIncrementalProcessor"); - - processAnnotations(basedir, Proc.only, processor, processors); - mojos.assertBuildOutputs(target, // - "generated-sources/annotations/proc/NonIncrementalSource.java"); - - rm(basedir, "src/main/java/proc/Source.java"); - - processAnnotations(basedir, Proc.only, processor, processors); - mojos.assertDeletedOutputs(target, // - "generated-sources/annotations/proc/NonIncrementalSource.java"); - } - - @Test - public void testProc_projectSourceRoots() throws Exception { - File processor = compileAnnotationProcessor(); - - File basedir = resources.getBasedir("compile-proc/proc"); - MavenProject project = mojos.readMavenProject(basedir); - addDependency(project, "processor", new File(processor, "target/classes")); - - mojos.compile(project, newParameter("proc", Proc.proc.name()), newProcessors("processor.Processor")); - - Assert.assertTrue(project.getCompileSourceRoots().contains(new File(basedir, "target/generated-sources/annotations").getAbsolutePath())); - - // TODO testCompile - } - - @Test - public void testIncrementalDelete() throws Exception { - File processor = compileAnnotationProcessor(); - File basedir = resources.getBasedir("compile-proc/proc-incremental-delete"); - - Xpp3Dom processors = newProcessors("processor.Processor"); - - // initial compilation - processAnnotations(basedir, Proc.proc, processor, processors); - mojos.assertBuildOutputs(new File(basedir, "target"), // - "classes/proc/Keep.class", // - "classes/proc/Source.class", // - "generated-sources/annotations/proc/GeneratedSource.java", // - "classes/proc/GeneratedSource.class"); - - // no-change rebuild - processAnnotations(basedir, Proc.proc, processor, processors); - mojos.assertCarriedOverOutputs(new File(basedir, "target"), // - "classes/proc/Keep.class", // - "classes/proc/Source.class", // - "generated-sources/annotations/proc/GeneratedSource.java", // - "classes/proc/GeneratedSource.class"); - - // remove annotated source - rm(basedir, "src/main/java/proc/Source.java"); - processAnnotations(basedir, Proc.proc, processor, processors); - mojos.assertDeletedOutputs(new File(basedir, "target"), // - "generated-sources/annotations/proc/GeneratedSource.java", // - "classes/proc/Source.class", // - "classes/proc/GeneratedSource.class"); - } - - @Test - public void testConvertGeneratedSourceToHandwritten() throws Exception { - // this test demonstrates the following scenario - // 1. annotation processor generates java source and the generated source is compiled by the compiler - // 2. annotation is removed from original source and the generated source is moved to a dependency - // assert original generatedSource.java and generatedSource.class are deleted - - File processor = compileAnnotationProcessor(); - File basedir = resources.getBasedir("compile-proc/proc-incremental-move"); - File moduleA = new File(basedir, "module-a"); - File moduleB = new File(basedir, "module-b"); - - Xpp3Dom processors = newProcessors("processor.Processor"); - - mojos.compile(moduleB); - MavenProject projectA = mojos.readMavenProject(moduleA); - addDependency(projectA, "module-b", new File(moduleB, "target/classes")); - processAnnotations(projectA, processor, Proc.proc, processors); - mojos.assertBuildOutputs(new File(moduleA, "target"), // - "classes/proc/Source.class", // - "generated-sources/annotations/proc/GeneratedSource.java", // - "classes/proc/GeneratedSource.class"); - - mojos.flushClasspathCaches(); - - // move generated source to module-b/src/main/java - cp(moduleB, "src/main/java/proc/GeneratedSource.java-moved", "src/main/java/proc/GeneratedSource.java"); - cp(moduleA, "src/main/java/modulea/ModuleA.java-new", "src/main/java/modulea/ModuleA.java"); - cp(moduleA, "src/main/java/proc/Source.java-remove-annotation", "src/main/java/proc/Source.java"); - mojos.compile(moduleB); - mojos.assertBuildOutputs(moduleB, "target/classes/proc/GeneratedSource.class"); - projectA = mojos.readMavenProject(moduleA); - addDependency(projectA, "module-b", new File(moduleB, "target/classes")); - processAnnotations(projectA, processor, Proc.proc, processors); - mojos.assertBuildOutputs(new File(moduleA, "target"), // - "classes/proc/Source.class", "classes/modulea/ModuleA.class"); - mojos.assertDeletedOutputs(new File(moduleA, "target"), // - "generated-sources/annotations/proc/GeneratedSource.java", // - "classes/proc/GeneratedSource.class"); - } - - private Xpp3Dom newProcessors(String... processors) { - Xpp3Dom annotationProcessors = new Xpp3Dom("annotationProcessors"); - for (String processor : processors) { - annotationProcessors.addChild(newParameter("processor", processor)); + + @Test + public void testProc_none() throws Exception { + File basedir = procCompile("compile-proc/proc", Proc.none); + mojos.assertBuildOutputs(new File(basedir, "target"), "classes/proc/Source.class"); } - return annotationProcessors; - } - - @Test - public void testRequireProc() throws Exception { - File processor = compileAnnotationProcessor(); - File basedir = resources.getBasedir("compile-proc/require-proc"); - try { - processAnnotations(basedir, null, processor); - Assert.fail(); - } catch (IllegalArgumentException expected) { - // TODO assert message + + @Test + public void testProc_proc() throws Exception { + File basedir = procCompile("compile-proc/proc", Proc.proc); + mojos.assertBuildOutputs( + new File(basedir, "target"), // + "classes/proc/Source.class", // + "generated-sources/annotations/proc/GeneratedSource.java", // + "classes/proc/GeneratedSource.class", // + "generated-sources/annotations/proc/AnotherGeneratedSource.java", // + "classes/proc/AnotherGeneratedSource.class"); + } + + @Test + public void testProc_incrementalTypeIndex() throws Exception { + File processor = compileAnnotationProcessor(); + File basedir = resources.getBasedir("compile-proc/proc"); + File src = new File(basedir, "src/main/java"); + + processAnnotations(basedir, Proc.proc, processor, newProcessors("processor.ProcessorLastRound")); + mojos.assertBuildOutputs(new File(basedir, "target/classes"), "proc/Source.class", "types.lst"); + assertFileContents("proc.Source\n", basedir, "target/classes/types.lst"); + + // create new annotated source and run incremental build + JavaFile.builder( + "proc", // + TypeSpec.classBuilder("AnotherSource") // + .addAnnotation(AnnotationSpec.builder(ClassName.get("processor", "Annotation")) + .build()) // + .build()) // + .build() + .writeTo(src); + processAnnotations(basedir, Proc.proc, processor, newProcessors("processor.ProcessorLastRound")); + mojos.assertBuildOutputs( + new File(basedir, "target/classes"), "proc/Source.class", "proc/AnotherSource.class", "types.lst"); + assertFileContents("proc.AnotherSource\nproc.Source\n", basedir, "target/classes/types.lst"); + + // delete the new source and run incremental build + rm(src, "proc/AnotherSource.java"); + processAnnotations(basedir, Proc.proc, processor, newProcessors("processor.ProcessorLastRound")); + mojos.assertBuildOutputs(new File(basedir, "target/classes"), "proc/Source.class", "types.lst"); + mojos.assertDeletedOutputs(new File(basedir, "target/classes"), "proc/AnotherSource.class"); + assertFileContents("proc.Source\n", basedir, "target/classes/types.lst"); + } + + @Test + public void testProc_incrementalProcessorChange() throws Exception { + File processor = compileAnnotationProcessor(); + File basedir = resources.getBasedir("compile-proc/proc"); + processAnnotations(basedir, Proc.proc, processor); + mojos.assertBuildOutputs( + new File(basedir, "target"), // + "classes/proc/Source.class", // + "generated-sources/annotations/proc/GeneratedSource.java", // + "classes/proc/GeneratedSource.class", // + "generated-sources/annotations/proc/AnotherGeneratedSource.java", // + "classes/proc/AnotherGeneratedSource.class"); + + rm(processor, "target/classes/META-INF/services/javax.annotation.processing.Processor"); + mojos.flushClasspathCaches(); + processAnnotations(basedir, Proc.proc, processor); + mojos.assertBuildOutputs(new File(basedir, "target"), "classes/proc/Source.class"); + mojos.assertDeletedOutputs( + new File(basedir, "target"), // + "generated-sources/annotations/proc/GeneratedSource.java", // + "classes/proc/GeneratedSource.class", // + "generated-sources/annotations/proc/AnotherGeneratedSource.java", // + "classes/proc/AnotherGeneratedSource.class"); + } + + @Test + public void testProc_dummyOutput() throws Exception { + File basedir = procCompile("compile-proc/proc", Proc.proc, newProcessors("processor.Processor_dummyOutput")); + mojos.assertBuildOutputs(new File(basedir, "target"), "classes/proc/Source.class"); + } + + @Test + public void testProcTypeReference() throws Exception { + File basedir = procCompile("compile-proc/proc-type-reference", Proc.proc); + mojos.assertBuildOutputs( + new File(basedir, "target"), // + "classes/proc/Source.class", // + "classes/proc/GeneratedSourceSubclass.class", // + "generated-sources/annotations/proc/GeneratedSource.java", // + "classes/proc/GeneratedSource.class", // + "generated-sources/annotations/proc/AnotherGeneratedSource.java", // + "classes/proc/AnotherGeneratedSource.class"); } - processAnnotations(basedir, null, null); - } - - @Test - public void testRequireProc_processorpathMasksClasspath() throws Exception { - // assert annotation processors present on project classpath are ignored when processorpath is configured - - File processor = compileAnnotationProcessor(); - File basedir = resources.getBasedir("compile-proc/require-proc"); - processAnnotations(basedir, null, processor, new Xpp3Dom("processorpath")); - mojos.assertBuildOutputs(new File(basedir, "target"), // - "classes/proc/Source.class"); - } - - @Test - public void testRequireProc_processorpath() throws Exception { - MavenProject annotations = mojos.readMavenProject(resources.getBasedir("compile-proc/processorpath-annotation")); - mojos.compile(annotations); - - MavenProject processor = mojos.readMavenProject(resources.getBasedir("compile-proc/processorpath-processor")); - mojos.newDependency(new File(annotations.getBasedir(), "target/classes")).setArtifactId("annotations").addTo(processor); - mojos.compile(processor); - cp(processor.getBasedir(), "src/main/resources/META-INF/services/javax.annotation.processing.Processor", "target/classes/META-INF/services/javax.annotation.processing.Processor"); - - File basedir = resources.getBasedir("compile-proc/proc"); - MavenProject project = mojos.readMavenProject(basedir); - mojos.newDependency(new File(annotations.getBasedir(), "target/classes")).setArtifactId("annotations").addTo(project); - - MavenSession session = mojos.newMavenSession(project); - SimpleReactorReader.builder() // - .addProjects(annotations, processor, project) // - .toSession(session.getRepositorySession()); - - session.setProjects(Arrays.asList(annotations, processor, project)); - session.setCurrentProject(project); - Xpp3Dom processorpath = new Xpp3Dom("processorpath"); - processorpath.addChild(newProcessorpathEntry(processor)); - try { - mojos.compile(session, project, processorpath); - fail(); - } catch (IllegalArgumentException expected) { - // TODO assert message + @Test + public void testProc_createResource() throws Exception { + File basedir = procCompile("compile-proc/proc", Proc.proc, newProcessors("processor.ProcessorCreateResource")); + mojos.assertBuildOutputs( + new File(basedir, "target"), // + "classes/proc/Source.class", // + "generated-sources/annotations/proc/GeneratedSource.java"); } - } - @Test - public void testRecompile() throws Exception { + // The following five tests help test the behavior of the full and incremental + // compile strategies of the CompilerJdt with regards to Annotation Processing. + // Incremental compile is triggered on the last two tests with a second compile step + // to force apt to run in a course grained incremental manner. + // Both final round only and during each round APT code generators are tested. /** - *
-     *    Source.java -> Source.class
-     *      \-> GeneratedSource.java -> GeneratedSource.class
-     *                                      ^
-     *                                Client.java -> Client.class 
-     * 
+ * This test compiles with the a non-final round processor. + * + * There are no forward references that attempt to use the newly generated type. + * + * Note the use of "processor.Processor" and the "compile-proc/proc" project in this test. */ + @Test + public void testProc_annotationProcessors() throws Exception { + Xpp3Dom processors = newProcessors("processor.Processor"); + File basedir = procCompile("compile-proc/proc", Proc.proc, processors); + mojos.assertBuildOutputs( + new File(basedir, "target"), // + "classes/proc/Source.class", // + "generated-sources/annotations/proc/GeneratedSource.java", // + "classes/proc/GeneratedSource.class"); + } + + /** + * This test generates code in each round of an apt processor. + * + * There are is a forward reference which attempt to use the newly generated type as a super class. + * + * Any reference to the new type would be sufficient for this test. + * + * Note the use of "processor.Processor" and the "compile-proc/proc-type-reference" project in this test. + */ + @Test + public void testProcRef_annotationProcessors() throws Exception { + Xpp3Dom processors = newProcessors("processor.Processor"); + File basedir = procCompile("compile-proc/proc-type-reference", Proc.proc, processors); + mojos.assertBuildOutputs( + new File(basedir, "target"), // + "classes/proc/Source.class", // + "generated-sources/annotations/proc/GeneratedSource.java", // + "classes/proc/GeneratedSource.class", // + "classes/proc/GeneratedSourceSubclass.class"); + } + + /** + * This test generates code in the final round of an apt processor. + * + * There are is a forward reference which attempt to use the newly generated type as a super class. + * + * Any reference to the new type would be sufficient for this test. + * + * Note the use of "processor.ProcessorImplLastRound" and the "compile-proc/proc-type-reference" project in this test. + */ + @Test + public void testProcRef_annotationProcessors_LastRound() throws Exception { + // javac can't handle forward references in the last round, but jdt can. + Assume.assumeTrue(CompilerJdt.ID.equals(compilerId)); + Xpp3Dom processors = newProcessors("processor.ProcessorImplLastRound"); + File basedir = procCompile("compile-proc/proc-type-reference", Proc.proc, processors); + + mojos.assertBuildOutputs( + new File(basedir, "target"), // + "classes/proc/Source.class", // + "generated-sources/annotations/proc/GeneratedSource.java", // + "classes/proc/GeneratedSource.class", // + "classes/proc/GeneratedSourceSubclass.class"); + } + + /** + * This test generates code in each round of an apt processor. + * + * There are is a forward reference which attempt to use the newly generated type as a super class. Any reference to the new type would be sufficient for this test. + * + * This test the touches an annotated type and runs an incremental compile where much of the same code is forced to be recompiled. + * + * Note the use of "processor.Processor" and the "compile-proc/proc-type-reference" project in this test. + */ + @Test + public void testProcRef_annotationProcessors_recompile() throws Exception { + Xpp3Dom processors = newProcessors("processor.Processor"); + File basedir = procCompile("compile-proc/proc-type-reference", Proc.proc, processors); + mojos.assertBuildOutputs( + new File(basedir, "target"), // + "classes/proc/Source.class", // + "generated-sources/annotations/proc/GeneratedSource.java", // + "classes/proc/GeneratedSource.class", // + "classes/proc/GeneratedSourceSubclass.class"); + + touch(basedir, "src/main/java/proc/Source.java"); + + procCompile(basedir, Proc.proc, processors); + + String[] expectedOuput; + if (CompilerJdt.ID.equals(compilerId)) { + // incremental in jdt compile means that GeneratedSourceSubclass sees no + // structural change and doesn't need to be recompiled. + expectedOuput = new String[] { // + "classes/proc/Source.class", // + "generated-sources/annotations/proc/GeneratedSource.java", // + "classes/proc/GeneratedSource.class" + }; + } else { + expectedOuput = new String[] { // + // everything is recompiled by javac + "classes/proc/Source.class", // + "generated-sources/annotations/proc/GeneratedSource.java", // + "classes/proc/GeneratedSource.class", // + "classes/proc/GeneratedSourceSubclass.class" + }; + } + mojos.assertBuildOutputs(new File(basedir, "target"), expectedOuput); + } + + /** + * This test generates code in the final round of an apt processor. + * + * There are is a forward reference which attempt to use the newly generated type as a super class. Any reference to the new type would be sufficient for this test. + * + * This test the touches an annotated type and runs an incremental compile where much of the same code is forced to be recompiled. + * + * Note the use of "processor.ProcessorImplLastRound" and the "compile-proc/proc-type-reference" project in this test. + */ + @Test + public void testProcRef_annotationProcessors_LastRound_recompile() throws Exception { + // javac can't handle forward references in the last round, but jdt can. + Assume.assumeTrue(CompilerJdt.ID.equals(compilerId)); + Xpp3Dom processors = newProcessors("processor.ProcessorImplLastRound"); + File basedir = procCompile("compile-proc/proc-type-reference", Proc.proc, processors); + mojos.assertBuildOutputs( + new File(basedir, "target"), // + "classes/proc/Source.class", // + "generated-sources/annotations/proc/GeneratedSource.java", // + "classes/proc/GeneratedSource.class", // + "classes/proc/GeneratedSourceSubclass.class"); + + touch(basedir, "src/main/java/proc/Source.java"); + + procCompile(basedir, Proc.proc, processors); + + // okay this is a little wonky. Since source was recompiled, we delete it's + // apt generated type, which is referenced by GeneratedSourceSubclass, once it's + // deleted we then generated the GeneratedSource, compile it, and then have to + // recompile GeneratedSourceSubclass, hence it appears in this test and not + // testProcRef_annotationProcessors_recompile's list of output for jdt. + mojos.assertBuildOutputs( + new File(basedir, "target"), // + "classes/proc/Source.class", // + "generated-sources/annotations/proc/GeneratedSource.java", // + "classes/proc/GeneratedSource.class", // + "classes/proc/GeneratedSourceSubclass.class"); + } + + @Test + public void testProc_processorErrorMessage() throws Exception { + Xpp3Dom processors = newProcessors("processor.ErrorMessageProcessor"); + File basedir = resources.getBasedir("compile-proc/proc"); + try { + procCompile(basedir, Proc.only, processors); + Assert.fail(); + } catch (MojoExecutionException e) { + // expected + } + mojos.assertBuildOutputs(new File(basedir, "target"), new String[0]); + + ErrorMessage expected = new ErrorMessage(compilerId); + expected.setSnippets("jdt", "ERROR Source.java [6:14] test error message"); // TODO why 14? + expected.setSnippets("javac", "ERROR Source.java [6:8] test error message"); + mojos.assertMessage(basedir, "src/main/java/proc/Source.java", expected); + + Collection pomMessages = mojos.getBuildContextLog().getMessages(new File(basedir, "pom.xml")); + Assert.assertEquals(3, pomMessages.size()); + // TODO assert actual messages are as expected + } - File processor = compileAnnotationProcessor(); - File basedir = resources.getBasedir("compile-proc/proc-incremental-recompile"); - - Xpp3Dom processors = newProcessors("processor.ProcessorSiblingBody"); - Xpp3Dom options = new Xpp3Dom("annotationProcessorOptions"); - options.addChild(newParameter("basedir", new File(basedir, "src/main/java").getCanonicalPath())); - - processAnnotations(basedir, Proc.proc, processor, processors, options); - mojos.assertBuildOutputs(new File(basedir, "target"), // - "classes/proc/Source.class", // - "classes/proc/Client.class", // - "generated-sources/annotations/proc/GeneratedSource.java", // - "classes/proc/GeneratedSource.class"); - - cp(basedir, "src/main/java/proc/GeneratedSource.body-changed", "src/main/java/proc/GeneratedSource.body"); - touch(basedir, "src/main/java/proc/Source.java"); - processAnnotations(basedir, Proc.proc, processor, processors, options); - mojos.assertBuildOutputs(new File(basedir, "target"), // - "classes/proc/Source.class", // - "classes/proc/Client.class", // - "generated-sources/annotations/proc/GeneratedSource.java", // - "classes/proc/GeneratedSource.class"); - } - - @Test - public void testProc_processorLastRound() throws Exception { - Xpp3Dom processors = newProcessors("processor.ProcessorLastRound"); - File basedir = procCompile("compile-proc/proc", Proc.only, processors); - mojos.assertBuildOutputs(new File(basedir, "target"), // - "classes/types.lst"); - - assertFileContents("proc.Source\n", basedir, "target/classes/types.lst"); - } - - @Test - public void testIncremental_proc_only() throws Exception { - // the point of this test is to assert that changes to annotations trigger affected sources reprocessing when proc=only - // note sourcepath=disable, otherwise proc:only is all-or-nothing - - // TODO this test likely becomes redundant when annotation processing is always all-or-nothing - - File processor = compileAnnotationProcessor(); - File basedir = resources.getBasedir("compile-proc/proc-incremental-proconly"); - File generatedSources = new File(basedir, "target/generated-sources/annotations"); - - Xpp3Dom processors = newProcessors("processor.Processor"); - - compile(basedir, processor, "compile-only"); - processAnnotations(basedir, Proc.only, processor, processors, newParameter("sourcepath", "disable")); - mojos.assertBuildOutputs(generatedSources, "proc/GeneratedConcrete.java", "proc/GeneratedAbstract.java", "proc/GeneratedAnother.java"); - - cp(basedir, "src/main/java/proc/Abstract.java-remove-annotation", "src/main/java/proc/Abstract.java"); - compile(basedir, processor, "compile-only"); - processAnnotations(basedir, Proc.only, processor, processors, newParameter("sourcepath", "disable")); - mojos.assertDeletedOutputs(generatedSources, "proc/GeneratedConcrete.java", "proc/GeneratedAbstract.java"); - if (CompilerJdt.ID.equals(compilerId)) { - // annotation processing is always all-or-nothing, all outputs are always recreated - // mojos.assertCarriedOverOutputs(generatedSources, "proc/GeneratedAnother.java"); - mojos.assertBuildOutputs(generatedSources, "proc/GeneratedAnother.java"); - } else { - mojos.assertBuildOutputs(generatedSources, "proc/GeneratedAnother.java"); + @Test + public void testProc_messages() throws Exception { + ErrorMessage expected = new ErrorMessage(compilerId); + expected.setSnippets("javac", "ERROR BrokenSource.java [2:29]", "cannot find symbol"); + expected.setSnippets("jdt", "ERROR BrokenSource.java [2:29]", "cannot be resolved to a type"); + + File processor = compileAnnotationProcessor(); + File basedir = resources.getBasedir("compile-proc/proc"); + + String[] outputs; + if (CompilerJdt.ID.equals(compilerId)) { + outputs = new String[] { + "classes/proc/Source.class" // + , + "generated-sources/annotations/proc/BrokenSource.java" + }; + } else { + // TODO investigate why javac does not generate classes/proc/Source.class + outputs = new String[] {"generated-sources/annotations/proc/BrokenSource.java"}; + } + + Xpp3Dom processors = newProcessors("processor.BrokenProcessor"); + try { + processAnnotations(basedir, Proc.proc, processor, processors); + Assert.fail(); + } catch (MojoExecutionException e) { + // expected + } + mojos.assertBuildOutputs(new File(basedir, "target"), outputs); + assertProcMessage(basedir, "target/generated-sources/annotations/proc/BrokenSource.java", expected); + + // no change rebuild should produce the same messages + try { + processAnnotations(basedir, Proc.proc, processor, processors); + Assert.fail(); + } catch (MojoExecutionException e) { + // expected + } + mojos.assertCarriedOverOutputs(new File(basedir, "target"), outputs); + assertProcMessage(basedir, "target/generated-sources/annotations/proc/BrokenSource.java", expected); } - } - - private void compile(File basedir, File processor, String executionId) throws Exception { - MavenProject project = mojos.readMavenProject(basedir); - MavenSession session = mojos.newMavenSession(project); - MojoExecution execution = mojos.newMojoExecution(); - MojoExecution cloned = new MojoExecution(execution.getMojoDescriptor(), executionId, null); - cloned.setConfiguration(execution.getConfiguration()); - execution.getConfiguration().addChild(newParameter("proc", Proc.none.name())); - addDependency(project, "processor", new File(processor, "target/classes")); - mojos.executeMojo(session, project, cloned); - } - - @Test - public void testMutliround_procOnly() throws Exception { - File basedir = procCompile("compile-proc/multiround", Proc.only); - File generatedSources = new File(basedir, "target/generated-sources/annotations"); - - mojos.assertMessages(basedir, "src/main/java/multiround/Source.java", new String[] {}); - mojos.assertBuildOutputs(generatedSources, "multiround/GeneratedSource.java", "multiround/AnotherGeneratedSource.java"); - } - - @Test - public void testMultiround_processorLastRound() throws Exception { - // processor.ProcessorLastRound creates well-known resource during last round - // the point of this test is to assert this works during incremental build - // when compiler may be invoked several times to compile indirectly affected sources - - File processor = compileAnnotationProcessor(); - File basedir = resources.getBasedir("compile-proc/multiround-type-reference"); - - processAnnotations(basedir, Proc.proc, processor, newProcessors("processor.ProcessorLastRound")); - mojos.assertBuildOutputs(new File(basedir, "target"), // - "classes/proc/Source.class", // - "classes/proc/AnotherSource.class", // - "classes/types.lst"); - - cp(basedir, "src/main/java/proc/Source.java-changed", "src/main/java/proc/Source.java"); - processAnnotations(basedir, Proc.proc, processor, newProcessors("processor.ProcessorLastRound")); - mojos.assertBuildOutputs(new File(basedir, "target"), // - "classes/proc/Source.class", // - "classes/proc/AnotherSource.class", // - "classes/types.lst"); - } - - @Test - public void testLastRound_typeIndex() throws Exception { - // apparently javac can't resolve "forward" references to types generated during apt last round - Assume.assumeTrue(CompilerJdt.ID.equals(compilerId)); - - Xpp3Dom processors = newProcessors("processor.ProcessorLastRound_typeIndex"); - File basedir = procCompile("compile-proc/multiround-type-index", Proc.proc, processors); - File target = new File(basedir, "target"); - mojos.assertBuildOutputs(target, // - "generated-sources/annotations/generated/TypeIndex.java", // - "generated-sources/annotations/generated/TypeIndex2.java", // - "classes/generated/TypeIndex.class", // - "classes/generated/TypeIndex2.class", // - "classes/typeindex/Annotated.class", // - "classes/typeindex/Consumer.class" // - ); - } - - @Test - public void testReprocess() throws Exception { - File processor = compileAnnotationProcessor(); - File basedir = resources.getBasedir("compile-proc/reprocess"); - File target = new File(basedir, "target"); - - processAnnotations(basedir, Proc.proc, processor, newProcessors("processor.ProessorValue")); - mojos.assertBuildOutputs(target, // - "classes/reprocess/Annotated.class", // - "classes/reprocess/Annotated.value", // - "classes/reprocess/SimpleA.class", // - "classes/reprocess/SimpleB.class"); - - Assert.assertEquals("1", FileUtils.fileRead(new File(target, "classes/reprocess/Annotated.value"))); - - cp(basedir, "src/main/java/reprocess/SimpleA.java-changed", "src/main/java/reprocess/SimpleA.java"); - touch(new File(basedir, "src/main/java/reprocess/Annotated.java")); - - processAnnotations(basedir, Proc.proc, processor, newProcessors("processor.ProessorValue")); - mojos.assertBuildOutputs(target, // - "classes/reprocess/Annotated.class", // - "classes/reprocess/Annotated.value", // - "classes/reprocess/SimpleA.class", // - "classes/reprocess/SimpleB.class"); - - Assert.assertEquals("10", FileUtils.fileRead(new File(target, "classes/reprocess/Annotated.value"))); - } - - - @Test - public void testProc_nonIncrementalProcessor() throws Exception { - Assume.assumeTrue(CompilerJdt.ID.equals(compilerId)); - - File processor = compileAnnotationProcessor(); - File basedir = resources.getBasedir("compile-proc/proc"); - File target = new File(basedir, "target"); - - processAnnotations(basedir, Proc.proc, processor, newProcessors("processor.NonIncrementalProcessor")); - mojos.assertBuildOutputs(target, // - "classes/proc/Source.class", // - "generated-sources/annotations/proc/NonIncrementalSource.java", // - "classes/proc/NonIncrementalSource.class"); - - FileUtils.deleteDirectory(target); - processAnnotations(basedir, Proc.only, processor, newProcessors("processor.NonIncrementalProcessor")); - mojos.assertBuildOutputs(target, // - "generated-sources/annotations/proc/NonIncrementalSource.java"); - - FileUtils.deleteDirectory(target); - processAnnotations(basedir, Proc.proc, processor, newProcessors("processor.NonIncrementalProcessor")); - mojos.assertBuildOutputs(target, // - "classes/proc/Source.class", // - "generated-sources/annotations/proc/NonIncrementalSource.java", // - "classes/proc/NonIncrementalSource.class"); - - FileUtils.deleteDirectory(target); - processAnnotations(basedir, Proc.only, processor, newProcessors("processor.NonIncrementalProcessor")); - mojos.assertBuildOutputs(target, // - "generated-sources/annotations/proc/NonIncrementalSource.java"); - } - - @Test - public void testProc_processorpath() throws Exception { - MavenProject annotations = mojos.readMavenProject(resources.getBasedir("compile-proc/processorpath-annotation")); - mojos.compile(annotations); - - MavenProject processor = mojos.readMavenProject(resources.getBasedir("compile-proc/processorpath-processor")); - mojos.newDependency(new File(annotations.getBasedir(), "target/classes")).setArtifactId("annotations").addTo(processor); - mojos.compile(processor); - cp(processor.getBasedir(), "src/main/resources/META-INF/services/javax.annotation.processing.Processor", "target/classes/META-INF/services/javax.annotation.processing.Processor"); - - File basedir = resources.getBasedir("compile-proc/proc"); - MavenProject project = mojos.readMavenProject(basedir); - mojos.newDependency(new File(annotations.getBasedir(), "target/classes")).setArtifactId("annotations").addTo(project); - - MavenSession session = mojos.newMavenSession(project); - SimpleReactorReader.builder() // - .addProjects(annotations, processor, project) // - .toSession(session.getRepositorySession()); - - session.setProjects(Arrays.asList(annotations, processor, project)); - session.setCurrentProject(project); - Xpp3Dom processorpath = new Xpp3Dom("processorpath"); - processorpath.addChild(newProcessorpathEntry(processor)); - mojos.compile(session, project, newParameter("proc", "proc"), processorpath); - mojos.assertBuildOutputs(new File(basedir, "target"), // - "classes/proc/Source.class", // - "generated-sources/annotations/proc/GeneratedSource.java", // - "classes/proc/GeneratedSource.class"); - } - - @Test - public void testProc_emptyProcessorPath() throws Exception { - File basedir = procCompile("compile-proc/proc", Proc.proc, new Xpp3Dom("processorpath")); - mojos.assertBuildOutputs(new File(basedir, "target"), // - "classes/proc/Source.class"); - } - - @Test - public void testProc_incrementalTypeJump() throws Exception { - // assert incremental behaviour when processor uses Elements to access non-annotated types - // jdt is expected to run annotation processor if referenced non-annotated types change - // (obviously still need to run apt when annotated types change, but that is tested elsewhere) - - File processor = compileAnnotationProcessor(); - File basedir = resources.getBasedir("compile-proc/proc"); - File src = new File(basedir, "src/main/java"); - - // processor references non-existing type proc.SourceJump - processAnnotations(basedir, Proc.proc, processor, newProcessors("processor.TypeJumpingProcessor")); - mojos.assertBuildOutputs(new File(basedir, "target"), // - "classes/proc/Source.class"); - - // create proc.SourceJump, assert apt ran as expected - JavaFile.builder("proc", TypeSpec.classBuilder("SourceJump").build()).build().writeTo(src); - processAnnotations(basedir, Proc.proc, processor, newProcessors("processor.TypeJumpingProcessor")); - mojos.assertBuildOutputs(new File(basedir, "target"), // - "classes/proc.SourceJump", // the generated resource - "classes/proc/Source.class", // - "classes/proc/SourceJump.class" // - ); - - // create proc.Unrelated, assert apt did NOT run - JavaFile.builder("proc", TypeSpec.classBuilder("Unrelated").build()).build().writeTo(src); - processAnnotations(basedir, Proc.proc, processor, newProcessors("processor.TypeJumpingProcessor")); - if (CompilerJdt.ID.equals(compilerId)) { - // jdt is supposed to compile the new type but carry-over everything else - mojos.assertBuildOutputs(new File(basedir, "target"), // - "classes/proc/Unrelated.class"); - mojos.assertDeletedOutputs(new File(basedir, "target"), new String[0]); - mojos.assertCarriedOverOutputs(new File(basedir, "target"), // - "classes/proc.SourceJump", // the generated resource - "classes/proc/Source.class", // - "classes/proc/SourceJump.class" // - ); - } else { - // javac recompiles everything - mojos.assertBuildOutputs(new File(basedir, "target"), // - "classes/proc.SourceJump", // the generated resource - "classes/proc/Source.class", // - "classes/proc/SourceJump.class", // - "classes/proc/Unrelated.class" // - ); + + private void assertProcMessage(File basedir, String path, ErrorMessage expected) throws Exception { + // javac reports the same compilation error twice when Proc.proc + Set messages = new HashSet(mojos.getBuildContextLog().getMessages(new File(basedir, path))); + Assert.assertEquals(messages.toString(), 1, messages.size()); + String message = messages.iterator().next(); + Assert.assertTrue(expected.isMatch(message)); + } + + @Test + public void testProc_processorOptions() throws Exception { + Xpp3Dom processors = newProcessors("processor.ProcessorWithOptions"); + + Xpp3Dom options = new Xpp3Dom("annotationProcessorOptions"); + options.addChild(newParameter("optionA", "valueA")); + options.addChild(newParameter("optionB", "valueB")); + procCompile("compile-proc/proc", Proc.proc, processors, options); + } + + @Test + public void testProc_staleGeneratedSourcesCleanup() throws Exception { + File processor = compileAnnotationProcessor(); + File basedir = resources.getBasedir("compile-proc/proc"); + + processAnnotations(basedir, Proc.proc, processor); + mojos.assertBuildOutputs( + new File(basedir, "target"), // + "classes/proc/Source.class", // + "generated-sources/annotations/proc/GeneratedSource.java", // + "classes/proc/GeneratedSource.class", // + "generated-sources/annotations/proc/AnotherGeneratedSource.java", // + "classes/proc/AnotherGeneratedSource.class"); + + // remove annotation + cp(basedir, "src/main/java/proc/Source.java-remove-annotation", "src/main/java/proc/Source.java"); + processAnnotations(basedir, Proc.proc, processor); + mojos.assertDeletedOutputs( + new File(basedir, "target"), // + "generated-sources/annotations/proc/GeneratedSource.java", // + "classes/proc/GeneratedSource.class", // + "generated-sources/annotations/proc/AnotherGeneratedSource.java", // + "classes/proc/AnotherGeneratedSource.class"); + } + + @Test + public void testProc_incrementalDeleteLastAnnotatedSource() throws Exception { + File processor = compileAnnotationProcessor(); + File basedir = resources.getBasedir("compile-proc/proc"); + + Xpp3Dom processors = newProcessors("processor.Processor"); + + // initial compilation + processAnnotations(basedir, Proc.proc, processor, processors); + mojos.assertBuildOutputs( + new File(basedir, "target"), // + "classes/proc/Source.class", // + "generated-sources/annotations/proc/GeneratedSource.java", // + "classes/proc/GeneratedSource.class"); + + // no-change rebuild + processAnnotations(basedir, Proc.proc, processor, processors); + mojos.assertCarriedOverOutputs( + new File(basedir, "target"), // + "classes/proc/Source.class", // + "generated-sources/annotations/proc/GeneratedSource.java", // + "classes/proc/GeneratedSource.class"); + + // remove annotated class + rm(basedir, "src/main/java/proc/Source.java"); + processAnnotations(basedir, Proc.proc, processor, processors); + mojos.assertDeletedOutputs( + new File(basedir, "target"), // + "generated-sources/annotations/proc/GeneratedSource.java", // + "classes/proc/Source.class", // + "classes/proc/GeneratedSource.class"); } - new Object(); - } + @Test + public void testProc_nonIncrementalProcessor_onlyEX_deleteSource() throws Exception { + File processor = compileAnnotationProcessor(); - private Xpp3Dom newProcessorpathEntry(MavenProject processor) { - Xpp3Dom entry = new Xpp3Dom("processor"); - entry.addChild(newParameter("groupId", processor.getGroupId())); - entry.addChild(newParameter("artifactId", processor.getArtifactId())); - entry.addChild(newParameter("version", processor.getVersion())); - return entry; - } + File basedir = resources.getBasedir("compile-proc/proc"); + File target = new File(basedir, "target"); - @Test - public void testSourcepathDependency() throws Exception { - File processor = compileAnnotationProcessor(); - File basedir = resources.getBasedir("compile-proc/proc-sourcepath"); + Xpp3Dom processors = newProcessors("processor.NonIncrementalProcessor"); - File dependencyBasedir = new File(basedir, "dependency"); - File projectBasedir = new File(basedir, "project"); + processAnnotations(basedir, Proc.only, processor, processors); + mojos.assertBuildOutputs( + target, // + "generated-sources/annotations/proc/NonIncrementalSource.java"); - Xpp3Dom processors = newProcessors("processor.Processor"); - Xpp3Dom sourcepath = newParameter("sourcepath", "reactorDependencies"); + rm(basedir, "src/main/java/proc/Source.java"); - MavenProject dependency = mojos.readMavenProject(dependencyBasedir); - MavenProject project = mojos.readMavenProject(projectBasedir); - - mojos.newDependency(new File(dependencyBasedir, "target/classes")) // - .setGroupId(dependency.getGroupId()) // - .setArtifactId(dependency.getArtifactId()) // - .setVersion(dependency.getVersion()) // - .addTo(project); - - MavenSession session = mojos.newMavenSession(project); - session.setProjects(Arrays.asList(project, dependency)); - - processAnnotations(session, project, "compile", processor, Proc.only, processors, sourcepath); - mojos.assertBuildOutputs(new File(projectBasedir, "target"), // - "generated-sources/annotations/sourcepath/project/GeneratedSource.java" // - ); - } - - @Test - public void testSourcepathDependencyNestedTypeThroughBinaryDependency() throws Exception { - File processor = compileAnnotationProcessor(); - File basedir = resources.getBasedir("compile-proc/proc-sourcepath-nestedtype-through-binary"); - - File dependencyBasedir = new File(basedir, "dependency"); - File binaryDependencyBasedir = new File(basedir, "binary-dependency"); - File projectBasedir = new File(basedir, "project"); - - Xpp3Dom processors = newProcessors("processor.EnclosedElementsProcessor"); - Xpp3Dom sourcepath = newParameter("sourcepath", "reactorDependencies"); - - MavenProject dependency = mojos.readMavenProject(dependencyBasedir); - MavenProject project = mojos.readMavenProject(projectBasedir); - - mojos.newDependency(new File(binaryDependencyBasedir, "target/binary-dependency-1.0.jar")).addTo(project); - - mojos.newDependency(new File(dependencyBasedir, "target/classes")) // - .setGroupId(dependency.getGroupId()) // - .setArtifactId(dependency.getArtifactId()) // - .setVersion(dependency.getVersion()) // - .addTo(project); - - MavenSession session = mojos.newMavenSession(project); - session.setProjects(Arrays.asList(project, dependency)); - - processAnnotations(session, project, "compile", processor, Proc.only, processors, sourcepath); - mojos.assertBuildOutputs(new File(projectBasedir, "target"), // - "generated-sources/annotations/sourcepath/nestedtype/project/GeneratedSource.java" // - ); - } - - @Test - public void testSourcepathDependency_incremental() throws Exception { - // the point of this test is assert that changes to sourcepath files are expected to trigger reprocessing of affected sources - - File processor = compileAnnotationProcessor(); - File basedir = resources.getBasedir("compile-proc/proc-sourcepath"); - - File dependencyBasedir = new File(basedir, "dependency"); - File projectBasedir = new File(basedir, "project"); - - Xpp3Dom processors = newProcessors("processor.Processor"); - Xpp3Dom sourcepath = newParameter("sourcepath", "reactorDependencies"); - - MavenProject dependency = mojos.readMavenProject(dependencyBasedir); - MavenProject project = mojos.readMavenProject(projectBasedir); - - mojos.newDependency(new File(dependencyBasedir, "target/classes")) // - .setGroupId(dependency.getGroupId()) // - .setArtifactId(dependency.getArtifactId()) // - .setVersion(dependency.getVersion()) // - .addTo(project); - - MavenSession session = mojos.newMavenSession(project); - session.setProjects(Arrays.asList(project, dependency)); - - processAnnotations(session, project, "compile", processor, Proc.only, processors, sourcepath); - mojos.assertBuildOutputs(new File(projectBasedir, "target"), // - "generated-sources/annotations/sourcepath/project/GeneratedSource.java" // - ); - - // second, incremental, compilation with one of sourcepath files removed - - rm(dependencyBasedir, "src/main/java/sourcepath/dependency/SourcepathDependency.java"); - mojos.flushClasspathCaches(); - - dependency = mojos.readMavenProject(dependencyBasedir); - project = mojos.readMavenProject(projectBasedir); - - mojos.newDependency(new File(dependencyBasedir, "target/classes")) // - .setGroupId(dependency.getGroupId()) // - .setArtifactId(dependency.getArtifactId()) // - .setVersion(dependency.getVersion()) // - .addTo(project); - - session = mojos.newMavenSession(project); - session.setProjects(Arrays.asList(project, dependency)); - try { - processAnnotations(session, project, "compile", processor, Proc.only, processors, sourcepath); - } catch (MojoExecutionException expected) {} - ErrorMessage message = new ErrorMessage(compilerId); - message.setSnippets(CompilerJdt.ID, "sourcepath.dependency.SourcepathDependency cannot be resolved to a type"); - message.setSnippets(CompilerJavac.ID, "package sourcepath.dependency does not exist"); - mojos.assertMessage(projectBasedir, "src/main/java/sourcepath/project/Source.java", message); - // oddly enough, both jdt and javac generate GeneratedSource despite the error - } - - @Test - public void testSourcepathDependency_classifiedDependency() throws Exception { - File processor = compileAnnotationProcessor(); - File basedir = resources.getBasedir("compile-proc/proc-sourcepath"); - - File dependencyBasedir = new File(basedir, "dependency"); - File projectBasedir = new File(basedir, "project"); - - Xpp3Dom processors = newProcessors("processor.Processor"); - Xpp3Dom sourcepath = newParameter("sourcepath", "reactorDependencies"); - - MavenProject dependency = mojos.readMavenProject(dependencyBasedir); - MavenProject project = mojos.readMavenProject(projectBasedir); - - mojos.newDependency(new File(dependencyBasedir, "target/classes")) // - .setGroupId(dependency.getGroupId()) // - .setArtifactId(dependency.getArtifactId()) // - .setVersion(dependency.getVersion()) // - .setClassifier("classifier") // - .addTo(project); - - MavenSession session = mojos.newMavenSession(project); - session.setProjects(Arrays.asList(project, dependency)); - - try { - processAnnotations(session, project, "compile", processor, Proc.only, processors, sourcepath); - Assert.fail(); - } catch (MojoExecutionException expected) { - Assert.assertTrue(expected.getMessage().contains(dependency.getGroupId() + ":" + dependency.getArtifactId())); + processAnnotations(basedir, Proc.only, processor, processors); + mojos.assertDeletedOutputs( + target, // + "generated-sources/annotations/proc/NonIncrementalSource.java"); } - } - - @Test - public void testSourcepathIncludes() throws Exception { - Xpp3Dom includes = new Xpp3Dom("includes"); - includes.addChild(newParameter("include", "sourcepath/project/*.java")); - Xpp3Dom processors = newProcessors("processor.Processor"); - Xpp3Dom sourcepath = newParameter("sourcepath", "reactorDependencies"); - File basedir = procCompile("compile-proc/proc-sourcepath-includes", Proc.only, includes, processors, sourcepath); - mojos.assertBuildOutputs(new File(basedir, "target"), // - "generated-sources/annotations/sourcepath/project/GeneratedSource.java" // - ); - } - - @Test - public void testSourcepathDependency_testCompile() throws Exception { - File processor = compileAnnotationProcessor(); - File basedir = resources.getBasedir("compile-proc/proc-sourcepath"); - - File dependencyBasedir = new File(basedir, "dependency"); - File projectBasedir = new File(basedir, "project"); - - Xpp3Dom processors = newProcessors("processor.Processor"); - Xpp3Dom sourcepath = newParameter("sourcepath", "reactorDependencies"); - - MavenProject dependency = mojos.readMavenProject(dependencyBasedir); - MavenProject project = mojos.readMavenProject(projectBasedir); - - mojos.newDependency(new File(dependencyBasedir, "target/classes")) // - .setGroupId(dependency.getGroupId()) // - .setArtifactId(dependency.getArtifactId()) // - .setVersion(dependency.getVersion()) // - .addTo(project); - - mojos.newDependency(new File(dependencyBasedir, "target/test-classes")) // - .setGroupId(dependency.getGroupId()) // - .setArtifactId(dependency.getArtifactId()) // - .setType("test-jar") // - .setVersion(dependency.getVersion()) // - .addTo(project); - - MavenSession session = mojos.newMavenSession(project); - session.setProjects(Arrays.asList(project, dependency)); - - processAnnotations(session, project, "testCompile", processor, Proc.only, processors, sourcepath); - mojos.assertBuildOutputs(new File(projectBasedir, "target"), // - "generated-test-sources/test-annotations/sourcepath/project/test/GeneratedSourceTest.java" // - ); - } - - @Test - public void testSourcepath_classpathVisibility() throws Exception { - Assume.assumeTrue(CompilerJdt.ID.equals(compilerId)); - - File basedir = resources.getBasedir(); - Xpp3Dom sourcepath = newParameter("sourcepath", "reactorDependencies"); - Xpp3Dom classpathVisibility = newParameter("privatePackageReference", "error"); - try { - procCompile(basedir, Proc.only, sourcepath, classpathVisibility); - Assert.fail(); - } catch (MojoExecutionException expected) { - Assert.assertTrue(expected.getMessage().contains("privatePackageReference")); + + @Test + public void testProc_projectSourceRoots() throws Exception { + File processor = compileAnnotationProcessor(); + + File basedir = resources.getBasedir("compile-proc/proc"); + MavenProject project = mojos.readMavenProject(basedir); + addDependency(project, "processor", new File(processor, "target/classes")); + + mojos.compile(project, newParameter("proc", Proc.proc.name()), newProcessors("processor.Processor")); + + Assert.assertTrue(project.getCompileSourceRoots() + .contains(new File(basedir, "target/generated-sources/annotations").getAbsolutePath())); + + // TODO testCompile + } + + @Test + public void testIncrementalDelete() throws Exception { + File processor = compileAnnotationProcessor(); + File basedir = resources.getBasedir("compile-proc/proc-incremental-delete"); + + Xpp3Dom processors = newProcessors("processor.Processor"); + + // initial compilation + processAnnotations(basedir, Proc.proc, processor, processors); + mojos.assertBuildOutputs( + new File(basedir, "target"), // + "classes/proc/Keep.class", // + "classes/proc/Source.class", // + "generated-sources/annotations/proc/GeneratedSource.java", // + "classes/proc/GeneratedSource.class"); + + // no-change rebuild + processAnnotations(basedir, Proc.proc, processor, processors); + mojos.assertCarriedOverOutputs( + new File(basedir, "target"), // + "classes/proc/Keep.class", // + "classes/proc/Source.class", // + "generated-sources/annotations/proc/GeneratedSource.java", // + "classes/proc/GeneratedSource.class"); + + // remove annotated source + rm(basedir, "src/main/java/proc/Source.java"); + processAnnotations(basedir, Proc.proc, processor, processors); + mojos.assertDeletedOutputs( + new File(basedir, "target"), // + "generated-sources/annotations/proc/GeneratedSource.java", // + "classes/proc/Source.class", // + "classes/proc/GeneratedSource.class"); + } + + @Test + public void testConvertGeneratedSourceToHandwritten() throws Exception { + // this test demonstrates the following scenario + // 1. annotation processor generates java source and the generated source is compiled by the compiler + // 2. annotation is removed from original source and the generated source is moved to a dependency + // assert original generatedSource.java and generatedSource.class are deleted + + File processor = compileAnnotationProcessor(); + File basedir = resources.getBasedir("compile-proc/proc-incremental-move"); + File moduleA = new File(basedir, "module-a"); + File moduleB = new File(basedir, "module-b"); + + Xpp3Dom processors = newProcessors("processor.Processor"); + + mojos.compile(moduleB); + MavenProject projectA = mojos.readMavenProject(moduleA); + addDependency(projectA, "module-b", new File(moduleB, "target/classes")); + processAnnotations(projectA, processor, Proc.proc, processors); + mojos.assertBuildOutputs( + new File(moduleA, "target"), // + "classes/proc/Source.class", // + "generated-sources/annotations/proc/GeneratedSource.java", // + "classes/proc/GeneratedSource.class"); + + mojos.flushClasspathCaches(); + + // move generated source to module-b/src/main/java + cp(moduleB, "src/main/java/proc/GeneratedSource.java-moved", "src/main/java/proc/GeneratedSource.java"); + cp(moduleA, "src/main/java/modulea/ModuleA.java-new", "src/main/java/modulea/ModuleA.java"); + cp(moduleA, "src/main/java/proc/Source.java-remove-annotation", "src/main/java/proc/Source.java"); + mojos.compile(moduleB); + mojos.assertBuildOutputs(moduleB, "target/classes/proc/GeneratedSource.class"); + projectA = mojos.readMavenProject(moduleA); + addDependency(projectA, "module-b", new File(moduleB, "target/classes")); + processAnnotations(projectA, processor, Proc.proc, processors); + mojos.assertBuildOutputs( + new File(moduleA, "target"), // + "classes/proc/Source.class", + "classes/modulea/ModuleA.class"); + mojos.assertDeletedOutputs( + new File(moduleA, "target"), // + "generated-sources/annotations/proc/GeneratedSource.java", // + "classes/proc/GeneratedSource.class"); + } + + private Xpp3Dom newProcessors(String... processors) { + Xpp3Dom annotationProcessors = new Xpp3Dom("annotationProcessors"); + for (String processor : processors) { + annotationProcessors.addChild(newParameter("processor", processor)); + } + return annotationProcessors; + } + + @Test + public void testRequireProc() throws Exception { + File processor = compileAnnotationProcessor(); + File basedir = resources.getBasedir("compile-proc/require-proc"); + try { + processAnnotations(basedir, null, processor); + Assert.fail(); + } catch (IllegalArgumentException expected) { + // TODO assert message + } + + processAnnotations(basedir, null, null); + } + + @Test + public void testRequireProc_processorpathMasksClasspath() throws Exception { + // assert annotation processors present on project classpath are ignored when processorpath is configured + + File processor = compileAnnotationProcessor(); + File basedir = resources.getBasedir("compile-proc/require-proc"); + processAnnotations(basedir, null, processor, new Xpp3Dom("processorpath")); + mojos.assertBuildOutputs( + new File(basedir, "target"), // + "classes/proc/Source.class"); + } + + @Test + public void testRequireProc_processorpath() throws Exception { + MavenProject annotations = + mojos.readMavenProject(resources.getBasedir("compile-proc/processorpath-annotation")); + mojos.compile(annotations); + + MavenProject processor = mojos.readMavenProject(resources.getBasedir("compile-proc/processorpath-processor")); + mojos.newDependency(new File(annotations.getBasedir(), "target/classes")) + .setArtifactId("annotations") + .addTo(processor); + mojos.compile(processor); + cp( + processor.getBasedir(), + "src/main/resources/META-INF/services/javax.annotation.processing.Processor", + "target/classes/META-INF/services/javax.annotation.processing.Processor"); + + File basedir = resources.getBasedir("compile-proc/proc"); + MavenProject project = mojos.readMavenProject(basedir); + mojos.newDependency(new File(annotations.getBasedir(), "target/classes")) + .setArtifactId("annotations") + .addTo(project); + + MavenSession session = mojos.newMavenSession(project); + SimpleReactorReader.builder() // + .addProjects(annotations, processor, project) // + .toSession(session.getRepositorySession()); + + session.setProjects(Arrays.asList(annotations, processor, project)); + session.setCurrentProject(project); + Xpp3Dom processorpath = new Xpp3Dom("processorpath"); + processorpath.addChild(newProcessorpathEntry(processor)); + try { + mojos.compile(session, project, processorpath); + fail(); + } catch (IllegalArgumentException expected) { + // TODO assert message + } + } + + @Test + public void testRecompile() throws Exception { + + /** + *
+         *    Source.java -> Source.class
+         *      \-> GeneratedSource.java -> GeneratedSource.class
+         *                                      ^
+         *                                Client.java -> Client.class
+         * 
+ */ + File processor = compileAnnotationProcessor(); + File basedir = resources.getBasedir("compile-proc/proc-incremental-recompile"); + + Xpp3Dom processors = newProcessors("processor.ProcessorSiblingBody"); + Xpp3Dom options = new Xpp3Dom("annotationProcessorOptions"); + options.addChild(newParameter("basedir", new File(basedir, "src/main/java").getCanonicalPath())); + + processAnnotations(basedir, Proc.proc, processor, processors, options); + mojos.assertBuildOutputs( + new File(basedir, "target"), // + "classes/proc/Source.class", // + "classes/proc/Client.class", // + "generated-sources/annotations/proc/GeneratedSource.java", // + "classes/proc/GeneratedSource.class"); + + cp(basedir, "src/main/java/proc/GeneratedSource.body-changed", "src/main/java/proc/GeneratedSource.body"); + touch(basedir, "src/main/java/proc/Source.java"); + processAnnotations(basedir, Proc.proc, processor, processors, options); + mojos.assertBuildOutputs( + new File(basedir, "target"), // + "classes/proc/Source.class", // + "classes/proc/Client.class", // + "generated-sources/annotations/proc/GeneratedSource.java", // + "classes/proc/GeneratedSource.class"); + } + + @Test + public void testProc_processorLastRound() throws Exception { + Xpp3Dom processors = newProcessors("processor.ProcessorLastRound"); + File basedir = procCompile("compile-proc/proc", Proc.only, processors); + mojos.assertBuildOutputs( + new File(basedir, "target"), // + "classes/types.lst"); + + assertFileContents("proc.Source\n", basedir, "target/classes/types.lst"); + } + + @Test + public void testIncremental_proc_only() throws Exception { + // the point of this test is to assert that changes to annotations trigger affected sources reprocessing when + // proc=only + // note sourcepath=disable, otherwise proc:only is all-or-nothing + + // TODO this test likely becomes redundant when annotation processing is always all-or-nothing + + File processor = compileAnnotationProcessor(); + File basedir = resources.getBasedir("compile-proc/proc-incremental-proconly"); + File generatedSources = new File(basedir, "target/generated-sources/annotations"); + + Xpp3Dom processors = newProcessors("processor.Processor"); + + compile(basedir, processor, "compile-only"); + processAnnotations(basedir, Proc.only, processor, processors, newParameter("sourcepath", "disable")); + mojos.assertBuildOutputs( + generatedSources, + "proc/GeneratedConcrete.java", + "proc/GeneratedAbstract.java", + "proc/GeneratedAnother.java"); + + cp(basedir, "src/main/java/proc/Abstract.java-remove-annotation", "src/main/java/proc/Abstract.java"); + compile(basedir, processor, "compile-only"); + processAnnotations(basedir, Proc.only, processor, processors, newParameter("sourcepath", "disable")); + mojos.assertDeletedOutputs(generatedSources, "proc/GeneratedConcrete.java", "proc/GeneratedAbstract.java"); + if (CompilerJdt.ID.equals(compilerId)) { + // annotation processing is always all-or-nothing, all outputs are always recreated + // mojos.assertCarriedOverOutputs(generatedSources, "proc/GeneratedAnother.java"); + mojos.assertBuildOutputs(generatedSources, "proc/GeneratedAnother.java"); + } else { + mojos.assertBuildOutputs(generatedSources, "proc/GeneratedAnother.java"); + } + } + + private void compile(File basedir, File processor, String executionId) throws Exception { + MavenProject project = mojos.readMavenProject(basedir); + MavenSession session = mojos.newMavenSession(project); + MojoExecution execution = mojos.newMojoExecution(); + MojoExecution cloned = new MojoExecution(execution.getMojoDescriptor(), executionId, null); + cloned.setConfiguration(execution.getConfiguration()); + execution.getConfiguration().addChild(newParameter("proc", Proc.none.name())); + addDependency(project, "processor", new File(processor, "target/classes")); + mojos.executeMojo(session, project, cloned); + } + + @Test + public void testMutliround_procOnly() throws Exception { + File basedir = procCompile("compile-proc/multiround", Proc.only); + File generatedSources = new File(basedir, "target/generated-sources/annotations"); + + mojos.assertMessages(basedir, "src/main/java/multiround/Source.java", new String[] {}); + mojos.assertBuildOutputs( + generatedSources, "multiround/GeneratedSource.java", "multiround/AnotherGeneratedSource.java"); + } + + @Test + public void testMultiround_processorLastRound() throws Exception { + // processor.ProcessorLastRound creates well-known resource during last round + // the point of this test is to assert this works during incremental build + // when compiler may be invoked several times to compile indirectly affected sources + + File processor = compileAnnotationProcessor(); + File basedir = resources.getBasedir("compile-proc/multiround-type-reference"); + + processAnnotations(basedir, Proc.proc, processor, newProcessors("processor.ProcessorLastRound")); + mojos.assertBuildOutputs( + new File(basedir, "target"), // + "classes/proc/Source.class", // + "classes/proc/AnotherSource.class", // + "classes/types.lst"); + + cp(basedir, "src/main/java/proc/Source.java-changed", "src/main/java/proc/Source.java"); + processAnnotations(basedir, Proc.proc, processor, newProcessors("processor.ProcessorLastRound")); + mojos.assertBuildOutputs( + new File(basedir, "target"), // + "classes/proc/Source.class", // + "classes/proc/AnotherSource.class", // + "classes/types.lst"); + } + + @Test + public void testLastRound_typeIndex() throws Exception { + // apparently javac can't resolve "forward" references to types generated during apt last round + Assume.assumeTrue(CompilerJdt.ID.equals(compilerId)); + + Xpp3Dom processors = newProcessors("processor.ProcessorLastRound_typeIndex"); + File basedir = procCompile("compile-proc/multiround-type-index", Proc.proc, processors); + File target = new File(basedir, "target"); + mojos.assertBuildOutputs( + target, // + "generated-sources/annotations/generated/TypeIndex.java", // + "generated-sources/annotations/generated/TypeIndex2.java", // + "classes/generated/TypeIndex.class", // + "classes/generated/TypeIndex2.class", // + "classes/typeindex/Annotated.class", // + "classes/typeindex/Consumer.class" // + ); + } + + @Test + public void testReprocess() throws Exception { + File processor = compileAnnotationProcessor(); + File basedir = resources.getBasedir("compile-proc/reprocess"); + File target = new File(basedir, "target"); + + processAnnotations(basedir, Proc.proc, processor, newProcessors("processor.ProessorValue")); + mojos.assertBuildOutputs( + target, // + "classes/reprocess/Annotated.class", // + "classes/reprocess/Annotated.value", // + "classes/reprocess/SimpleA.class", // + "classes/reprocess/SimpleB.class"); + + Assert.assertEquals("1", FileUtils.fileRead(new File(target, "classes/reprocess/Annotated.value"))); + + cp(basedir, "src/main/java/reprocess/SimpleA.java-changed", "src/main/java/reprocess/SimpleA.java"); + touch(new File(basedir, "src/main/java/reprocess/Annotated.java")); + + processAnnotations(basedir, Proc.proc, processor, newProcessors("processor.ProessorValue")); + mojos.assertBuildOutputs( + target, // + "classes/reprocess/Annotated.class", // + "classes/reprocess/Annotated.value", // + "classes/reprocess/SimpleA.class", // + "classes/reprocess/SimpleB.class"); + + Assert.assertEquals("10", FileUtils.fileRead(new File(target, "classes/reprocess/Annotated.value"))); + } + + @Test + public void testProc_nonIncrementalProcessor() throws Exception { + Assume.assumeTrue(CompilerJdt.ID.equals(compilerId)); + + File processor = compileAnnotationProcessor(); + File basedir = resources.getBasedir("compile-proc/proc"); + File target = new File(basedir, "target"); + + processAnnotations(basedir, Proc.proc, processor, newProcessors("processor.NonIncrementalProcessor")); + mojos.assertBuildOutputs( + target, // + "classes/proc/Source.class", // + "generated-sources/annotations/proc/NonIncrementalSource.java", // + "classes/proc/NonIncrementalSource.class"); + + FileUtils.deleteDirectory(target); + processAnnotations(basedir, Proc.only, processor, newProcessors("processor.NonIncrementalProcessor")); + mojos.assertBuildOutputs( + target, // + "generated-sources/annotations/proc/NonIncrementalSource.java"); + + FileUtils.deleteDirectory(target); + processAnnotations(basedir, Proc.proc, processor, newProcessors("processor.NonIncrementalProcessor")); + mojos.assertBuildOutputs( + target, // + "classes/proc/Source.class", // + "generated-sources/annotations/proc/NonIncrementalSource.java", // + "classes/proc/NonIncrementalSource.class"); + + FileUtils.deleteDirectory(target); + processAnnotations(basedir, Proc.only, processor, newProcessors("processor.NonIncrementalProcessor")); + mojos.assertBuildOutputs( + target, // + "generated-sources/annotations/proc/NonIncrementalSource.java"); + } + + @Test + public void testProc_processorpath() throws Exception { + MavenProject annotations = + mojos.readMavenProject(resources.getBasedir("compile-proc/processorpath-annotation")); + mojos.compile(annotations); + + MavenProject processor = mojos.readMavenProject(resources.getBasedir("compile-proc/processorpath-processor")); + mojos.newDependency(new File(annotations.getBasedir(), "target/classes")) + .setArtifactId("annotations") + .addTo(processor); + mojos.compile(processor); + cp( + processor.getBasedir(), + "src/main/resources/META-INF/services/javax.annotation.processing.Processor", + "target/classes/META-INF/services/javax.annotation.processing.Processor"); + + File basedir = resources.getBasedir("compile-proc/proc"); + MavenProject project = mojos.readMavenProject(basedir); + mojos.newDependency(new File(annotations.getBasedir(), "target/classes")) + .setArtifactId("annotations") + .addTo(project); + + MavenSession session = mojos.newMavenSession(project); + SimpleReactorReader.builder() // + .addProjects(annotations, processor, project) // + .toSession(session.getRepositorySession()); + + session.setProjects(Arrays.asList(annotations, processor, project)); + session.setCurrentProject(project); + Xpp3Dom processorpath = new Xpp3Dom("processorpath"); + processorpath.addChild(newProcessorpathEntry(processor)); + mojos.compile(session, project, newParameter("proc", "proc"), processorpath); + mojos.assertBuildOutputs( + new File(basedir, "target"), // + "classes/proc/Source.class", // + "generated-sources/annotations/proc/GeneratedSource.java", // + "classes/proc/GeneratedSource.class"); + } + + @Test + public void testProc_emptyProcessorPath() throws Exception { + File basedir = procCompile("compile-proc/proc", Proc.proc, new Xpp3Dom("processorpath")); + mojos.assertBuildOutputs( + new File(basedir, "target"), // + "classes/proc/Source.class"); + } + + @Test + public void testProc_incrementalTypeJump() throws Exception { + // assert incremental behaviour when processor uses Elements to access non-annotated types + // jdt is expected to run annotation processor if referenced non-annotated types change + // (obviously still need to run apt when annotated types change, but that is tested elsewhere) + + File processor = compileAnnotationProcessor(); + File basedir = resources.getBasedir("compile-proc/proc"); + File src = new File(basedir, "src/main/java"); + + // processor references non-existing type proc.SourceJump + processAnnotations(basedir, Proc.proc, processor, newProcessors("processor.TypeJumpingProcessor")); + mojos.assertBuildOutputs( + new File(basedir, "target"), // + "classes/proc/Source.class"); + + // create proc.SourceJump, assert apt ran as expected + JavaFile.builder("proc", TypeSpec.classBuilder("SourceJump").build()) + .build() + .writeTo(src); + processAnnotations(basedir, Proc.proc, processor, newProcessors("processor.TypeJumpingProcessor")); + mojos.assertBuildOutputs( + new File(basedir, "target"), // + "classes/proc.SourceJump", // the generated resource + "classes/proc/Source.class", // + "classes/proc/SourceJump.class" // + ); + + // create proc.Unrelated, assert apt did NOT run + JavaFile.builder("proc", TypeSpec.classBuilder("Unrelated").build()) + .build() + .writeTo(src); + processAnnotations(basedir, Proc.proc, processor, newProcessors("processor.TypeJumpingProcessor")); + if (CompilerJdt.ID.equals(compilerId)) { + // jdt is supposed to compile the new type but carry-over everything else + mojos.assertBuildOutputs( + new File(basedir, "target"), // + "classes/proc/Unrelated.class"); + mojos.assertDeletedOutputs(new File(basedir, "target"), new String[0]); + mojos.assertCarriedOverOutputs( + new File(basedir, "target"), // + "classes/proc.SourceJump", // the generated resource + "classes/proc/Source.class", // + "classes/proc/SourceJump.class" // + ); + } else { + // javac recompiles everything + mojos.assertBuildOutputs( + new File(basedir, "target"), // + "classes/proc.SourceJump", // the generated resource + "classes/proc/Source.class", // + "classes/proc/SourceJump.class", // + "classes/proc/Unrelated.class" // + ); + } + + new Object(); + } + + private Xpp3Dom newProcessorpathEntry(MavenProject processor) { + Xpp3Dom entry = new Xpp3Dom("processor"); + entry.addChild(newParameter("groupId", processor.getGroupId())); + entry.addChild(newParameter("artifactId", processor.getArtifactId())); + entry.addChild(newParameter("version", processor.getVersion())); + return entry; + } + + @Test + public void testSourcepathDependency() throws Exception { + File processor = compileAnnotationProcessor(); + File basedir = resources.getBasedir("compile-proc/proc-sourcepath"); + + File dependencyBasedir = new File(basedir, "dependency"); + File projectBasedir = new File(basedir, "project"); + + Xpp3Dom processors = newProcessors("processor.Processor"); + Xpp3Dom sourcepath = newParameter("sourcepath", "reactorDependencies"); + + MavenProject dependency = mojos.readMavenProject(dependencyBasedir); + MavenProject project = mojos.readMavenProject(projectBasedir); + + mojos.newDependency(new File(dependencyBasedir, "target/classes")) // + .setGroupId(dependency.getGroupId()) // + .setArtifactId(dependency.getArtifactId()) // + .setVersion(dependency.getVersion()) // + .addTo(project); + + MavenSession session = mojos.newMavenSession(project); + session.setProjects(Arrays.asList(project, dependency)); + + processAnnotations(session, project, "compile", processor, Proc.only, processors, sourcepath); + mojos.assertBuildOutputs( + new File(projectBasedir, "target"), // + "generated-sources/annotations/sourcepath/project/GeneratedSource.java" // + ); + } + + @Test + public void testSourcepathDependencyNestedTypeThroughBinaryDependency() throws Exception { + File processor = compileAnnotationProcessor(); + File basedir = resources.getBasedir("compile-proc/proc-sourcepath-nestedtype-through-binary"); + + File dependencyBasedir = new File(basedir, "dependency"); + File binaryDependencyBasedir = new File(basedir, "binary-dependency"); + File projectBasedir = new File(basedir, "project"); + + Xpp3Dom processors = newProcessors("processor.EnclosedElementsProcessor"); + Xpp3Dom sourcepath = newParameter("sourcepath", "reactorDependencies"); + + MavenProject dependency = mojos.readMavenProject(dependencyBasedir); + MavenProject project = mojos.readMavenProject(projectBasedir); + + mojos.newDependency(new File(binaryDependencyBasedir, "target/binary-dependency-1.0.jar")) + .addTo(project); + + mojos.newDependency(new File(dependencyBasedir, "target/classes")) // + .setGroupId(dependency.getGroupId()) // + .setArtifactId(dependency.getArtifactId()) // + .setVersion(dependency.getVersion()) // + .addTo(project); + + MavenSession session = mojos.newMavenSession(project); + session.setProjects(Arrays.asList(project, dependency)); + + processAnnotations(session, project, "compile", processor, Proc.only, processors, sourcepath); + mojos.assertBuildOutputs( + new File(projectBasedir, "target"), // + "generated-sources/annotations/sourcepath/nestedtype/project/GeneratedSource.java" // + ); + } + + @Test + public void testSourcepathDependency_incremental() throws Exception { + // the point of this test is assert that changes to sourcepath files are expected to trigger reprocessing of + // affected sources + + File processor = compileAnnotationProcessor(); + File basedir = resources.getBasedir("compile-proc/proc-sourcepath"); + + File dependencyBasedir = new File(basedir, "dependency"); + File projectBasedir = new File(basedir, "project"); + + Xpp3Dom processors = newProcessors("processor.Processor"); + Xpp3Dom sourcepath = newParameter("sourcepath", "reactorDependencies"); + + MavenProject dependency = mojos.readMavenProject(dependencyBasedir); + MavenProject project = mojos.readMavenProject(projectBasedir); + + mojos.newDependency(new File(dependencyBasedir, "target/classes")) // + .setGroupId(dependency.getGroupId()) // + .setArtifactId(dependency.getArtifactId()) // + .setVersion(dependency.getVersion()) // + .addTo(project); + + MavenSession session = mojos.newMavenSession(project); + session.setProjects(Arrays.asList(project, dependency)); + + processAnnotations(session, project, "compile", processor, Proc.only, processors, sourcepath); + mojos.assertBuildOutputs( + new File(projectBasedir, "target"), // + "generated-sources/annotations/sourcepath/project/GeneratedSource.java" // + ); + + // second, incremental, compilation with one of sourcepath files removed + + rm(dependencyBasedir, "src/main/java/sourcepath/dependency/SourcepathDependency.java"); + mojos.flushClasspathCaches(); + + dependency = mojos.readMavenProject(dependencyBasedir); + project = mojos.readMavenProject(projectBasedir); + + mojos.newDependency(new File(dependencyBasedir, "target/classes")) // + .setGroupId(dependency.getGroupId()) // + .setArtifactId(dependency.getArtifactId()) // + .setVersion(dependency.getVersion()) // + .addTo(project); + + session = mojos.newMavenSession(project); + session.setProjects(Arrays.asList(project, dependency)); + try { + processAnnotations(session, project, "compile", processor, Proc.only, processors, sourcepath); + } catch (MojoExecutionException expected) { + } + ErrorMessage message = new ErrorMessage(compilerId); + message.setSnippets(CompilerJdt.ID, "sourcepath.dependency.SourcepathDependency cannot be resolved to a type"); + message.setSnippets(CompilerJavac.ID, "package sourcepath.dependency does not exist"); + mojos.assertMessage(projectBasedir, "src/main/java/sourcepath/project/Source.java", message); + // oddly enough, both jdt and javac generate GeneratedSource despite the error + } + + @Test + public void testSourcepathDependency_classifiedDependency() throws Exception { + File processor = compileAnnotationProcessor(); + File basedir = resources.getBasedir("compile-proc/proc-sourcepath"); + + File dependencyBasedir = new File(basedir, "dependency"); + File projectBasedir = new File(basedir, "project"); + + Xpp3Dom processors = newProcessors("processor.Processor"); + Xpp3Dom sourcepath = newParameter("sourcepath", "reactorDependencies"); + + MavenProject dependency = mojos.readMavenProject(dependencyBasedir); + MavenProject project = mojos.readMavenProject(projectBasedir); + + mojos.newDependency(new File(dependencyBasedir, "target/classes")) // + .setGroupId(dependency.getGroupId()) // + .setArtifactId(dependency.getArtifactId()) // + .setVersion(dependency.getVersion()) // + .setClassifier("classifier") // + .addTo(project); + + MavenSession session = mojos.newMavenSession(project); + session.setProjects(Arrays.asList(project, dependency)); + + try { + processAnnotations(session, project, "compile", processor, Proc.only, processors, sourcepath); + Assert.fail(); + } catch (MojoExecutionException expected) { + Assert.assertTrue( + expected.getMessage().contains(dependency.getGroupId() + ":" + dependency.getArtifactId())); + } + } + + @Test + public void testSourcepathIncludes() throws Exception { + Xpp3Dom includes = new Xpp3Dom("includes"); + includes.addChild(newParameter("include", "sourcepath/project/*.java")); + Xpp3Dom processors = newProcessors("processor.Processor"); + Xpp3Dom sourcepath = newParameter("sourcepath", "reactorDependencies"); + File basedir = + procCompile("compile-proc/proc-sourcepath-includes", Proc.only, includes, processors, sourcepath); + mojos.assertBuildOutputs( + new File(basedir, "target"), // + "generated-sources/annotations/sourcepath/project/GeneratedSource.java" // + ); + } + + @Test + public void testSourcepathDependency_testCompile() throws Exception { + File processor = compileAnnotationProcessor(); + File basedir = resources.getBasedir("compile-proc/proc-sourcepath"); + + File dependencyBasedir = new File(basedir, "dependency"); + File projectBasedir = new File(basedir, "project"); + + Xpp3Dom processors = newProcessors("processor.Processor"); + Xpp3Dom sourcepath = newParameter("sourcepath", "reactorDependencies"); + + MavenProject dependency = mojos.readMavenProject(dependencyBasedir); + MavenProject project = mojos.readMavenProject(projectBasedir); + + mojos.newDependency(new File(dependencyBasedir, "target/classes")) // + .setGroupId(dependency.getGroupId()) // + .setArtifactId(dependency.getArtifactId()) // + .setVersion(dependency.getVersion()) // + .addTo(project); + + mojos.newDependency(new File(dependencyBasedir, "target/test-classes")) // + .setGroupId(dependency.getGroupId()) // + .setArtifactId(dependency.getArtifactId()) // + .setType("test-jar") // + .setVersion(dependency.getVersion()) // + .addTo(project); + + MavenSession session = mojos.newMavenSession(project); + session.setProjects(Arrays.asList(project, dependency)); + + processAnnotations(session, project, "testCompile", processor, Proc.only, processors, sourcepath); + mojos.assertBuildOutputs( + new File(projectBasedir, "target"), // + "generated-test-sources/test-annotations/sourcepath/project/test/GeneratedSourceTest.java" // + ); + } + + @Test + public void testSourcepath_classpathVisibility() throws Exception { + Assume.assumeTrue(CompilerJdt.ID.equals(compilerId)); + + File basedir = resources.getBasedir(); + Xpp3Dom sourcepath = newParameter("sourcepath", "reactorDependencies"); + Xpp3Dom classpathVisibility = newParameter("privatePackageReference", "error"); + try { + procCompile(basedir, Proc.only, sourcepath, classpathVisibility); + Assert.fail(); + } catch (MojoExecutionException expected) { + Assert.assertTrue(expected.getMessage().contains("privatePackageReference")); + } + } + + @Test + @Ignore("Neither javac nor jdt support secondary types on sourcepath") + public void testSourcepathSecondatytype() throws Exception { + File processor = compileAnnotationProcessor(); + File basedir = resources.getBasedir("compile-proc/proc-sourcepath-secondarytype"); + + File dependencyBasedir = new File(basedir, "dependency"); + File projectBasedir = new File(basedir, "project"); + + Xpp3Dom processors = newProcessors("processor.Processor"); + Xpp3Dom sourcepath = newParameter("sourcepath", "reactorDependencies"); + + MavenProject dependency = mojos.readMavenProject(dependencyBasedir); + MavenProject project = mojos.readMavenProject(projectBasedir); + + mojos.newDependency(new File(dependencyBasedir, "target/classes")) // + .setGroupId(dependency.getGroupId()) // + .setArtifactId(dependency.getArtifactId()) // + .setVersion(dependency.getVersion()) // + .addTo(project); + + MavenSession session = mojos.newMavenSession(project); + session.setProjects(Arrays.asList(project, dependency)); + + processAnnotations(session, project, "compile", processor, Proc.only, processors, sourcepath); + } + + @Test + public void testSourcepathCache() throws Exception { + // project-a has its generated sources directory configured as compile source root + // project-b depends on project-a generated sources + // both project-a and project-b run proc=only sourcepath=reactorDependencies + + File processor = compileAnnotationProcessor(); + File basedir = resources.getBasedir("compile-proc/proc-sourcepath-cache"); + + Xpp3Dom processors = newProcessors("processor.Processor"); + Xpp3Dom sourcepath = newParameter("sourcepath", "reactorDependencies"); + Xpp3Dom procOnly = newParameter("proc", Proc.only.name()); + + // setting up project-a + File projectaBasedir = new File(basedir, "project-a"); + MavenProject projecta = mojos.readMavenProject(projectaBasedir); + addDependency(projecta, "processor", new File(processor, "target/classes")); + projecta.addCompileSourceRoot( + new File(projectaBasedir, "target/generated-sources/annotations").getCanonicalPath()); + + // setting up project-b + File projectbBasedir = new File(basedir, "project-b"); + MavenProject projectb = mojos.readMavenProject(projectbBasedir); + addDependency(projectb, "processor", new File(processor, "target/classes")); + mojos.newDependency(new File(projectaBasedir, "target/classes")) // + .setGroupId(projecta.getGroupId()) // + .setArtifactId(projecta.getArtifactId()) // + .setVersion(projecta.getVersion()) // + .addTo(projectb); + + MavenSession session = mojos.newMavenSession(projecta); + session.setProjects(Arrays.asList(projecta, projecta)); + + // process annotations in project-a + mojos.executeMojo(session, projecta, "compile", procOnly, processors, sourcepath); + mojos.assertBuildOutputs( + new File(projectaBasedir, "target"), // + "generated-sources/annotations/sourcepath/projecta/GeneratedSourceA.java" // + ); + + // process annotations in project-b, requires access to project-a generated sources + session.setCurrentProject(projectb); + mojos.executeMojo(session, projectb, "compile", procOnly, processors, sourcepath); + mojos.assertBuildOutputs( + new File(projectbBasedir, "target"), // + "generated-sources/annotations/sourcepath/projectb/GeneratedSourceB.java" // + ); + } + + @Test + public void testAnnotatedMember_incrementalProcessingTrigger() throws Exception { + File processor = compileAnnotationProcessor(); + File basedir = resources.getBasedir(); + File src = new File(basedir, "src/main/java"); + + // initial build, writes annotated field path is written to elements.lst file + AnnotationSpec annotation = + AnnotationSpec.builder(ClassName.get("processor", "Annotation")).build(); + JavaFile.builder( + "proc", // + TypeSpec.classBuilder("AnnotatedMemberSource") // + .addField(FieldSpec.builder(String.class, "annotatedfield") + .addAnnotation(annotation) + .build()) // + .build()) // + .build() + .writeTo(src); + processAnnotations(basedir, Proc.proc, processor, newProcessors("processor.ElementsListProcessor")); + mojos.assertBuildOutputs( + new File(basedir, "target/classes"), "proc/AnnotatedMemberSource.class", "elements.lst"); + assertFileContents( + "/proc/AnnotatedMemberSource/annotatedfield FIELD\n", basedir, "target/classes/elements.lst"); + + // incremental build, introduce new annotated element and assert elements.lst includes both the new and the old + // elements + JavaFile.builder( + "proc", // + TypeSpec.classBuilder("AnnotatedSource") // + .addAnnotation(annotation) // + .build()) // + .build() + .writeTo(src); + processAnnotations(basedir, Proc.proc, processor, newProcessors("processor.ElementsListProcessor")); + mojos.assertBuildOutputs( + new File(basedir, "target/classes"), + "proc/AnnotatedMemberSource.class", + "proc/AnnotatedSource.class", + "elements.lst"); + assertFileContents( + "/proc/AnnotatedMemberSource/annotatedfield FIELD\n/proc/AnnotatedSource CLASS\n", + basedir, + "target/classes/elements.lst"); + } + + @Test + public void testNestedTypeReference() throws Exception { + File processor = compileAnnotationProcessor(); + File basedir = resources.getBasedir(); + File src = new File(basedir, "src/main/java"); + + // initial build + JavaFile.builder( + "proc", // + TypeSpec.classBuilder("Dependency") // + .addType(TypeSpec.classBuilder("Nested").build()) // + .build()) // + .build() + .writeTo(src); + AnnotationSpec annotation = + AnnotationSpec.builder(ClassName.get("processor", "Annotation")).build(); + JavaFile.builder( + "proc", // + TypeSpec.classBuilder("AnnotatedSource") // + .addField(FieldSpec.builder(ClassName.get("proc", "Dependency"), "annotatedfield") + .addAnnotation(annotation) + .build()) // + .build()) // + .build() + .writeTo(src); + processAnnotations(basedir, Proc.proc, processor, newProcessors("processor.ElementsTypeMemberListProcessor")); + mojos.assertBuildOutputs( + new File(basedir, "target/classes"), + "proc/AnnotatedSource.class", + "proc/Dependency.class", + "proc/Dependency$Nested.class", + "elements.lst"); + assertFileContents(" CONSTRUCTOR\n", basedir, "target/classes/elements.lst"); + + // add new member to Dependency.Nested type, run incremental build + JavaFile.builder( + "proc", // + TypeSpec.classBuilder("Dependency") // + .addType(TypeSpec.classBuilder("Nested") // + .addField(FieldSpec.builder(String.class, "nestedTypeField") + .build()) // + .build()) // + .build()) // + .build() + .writeTo(src); + processAnnotations(basedir, Proc.proc, processor, newProcessors("processor.ElementsTypeMemberListProcessor")); + mojos.assertBuildOutputs( + new File(basedir, "target/classes"), + "proc/AnnotatedSource.class", + "proc/Dependency.class", + "proc/Dependency$Nested.class", + "elements.lst"); + assertFileContents(" CONSTRUCTOR\nnestedTypeField FIELD\n", basedir, "target/classes/elements.lst"); } - } - - @Test - @Ignore("Neither javac nor jdt support secondary types on sourcepath") - public void testSourcepathSecondatytype() throws Exception { - File processor = compileAnnotationProcessor(); - File basedir = resources.getBasedir("compile-proc/proc-sourcepath-secondarytype"); - - File dependencyBasedir = new File(basedir, "dependency"); - File projectBasedir = new File(basedir, "project"); - - Xpp3Dom processors = newProcessors("processor.Processor"); - Xpp3Dom sourcepath = newParameter("sourcepath", "reactorDependencies"); - - MavenProject dependency = mojos.readMavenProject(dependencyBasedir); - MavenProject project = mojos.readMavenProject(projectBasedir); - - mojos.newDependency(new File(dependencyBasedir, "target/classes")) // - .setGroupId(dependency.getGroupId()) // - .setArtifactId(dependency.getArtifactId()) // - .setVersion(dependency.getVersion()) // - .addTo(project); - - MavenSession session = mojos.newMavenSession(project); - session.setProjects(Arrays.asList(project, dependency)); - - processAnnotations(session, project, "compile", processor, Proc.only, processors, sourcepath); - } - - @Test - public void testSourcepathCache() throws Exception { - // project-a has its generated sources directory configured as compile source root - // project-b depends on project-a generated sources - // both project-a and project-b run proc=only sourcepath=reactorDependencies - - File processor = compileAnnotationProcessor(); - File basedir = resources.getBasedir("compile-proc/proc-sourcepath-cache"); - - Xpp3Dom processors = newProcessors("processor.Processor"); - Xpp3Dom sourcepath = newParameter("sourcepath", "reactorDependencies"); - Xpp3Dom procOnly = newParameter("proc", Proc.only.name()); - - // setting up project-a - File projectaBasedir = new File(basedir, "project-a"); - MavenProject projecta = mojos.readMavenProject(projectaBasedir); - addDependency(projecta, "processor", new File(processor, "target/classes")); - projecta.addCompileSourceRoot(new File(projectaBasedir, "target/generated-sources/annotations").getCanonicalPath()); - - // setting up project-b - File projectbBasedir = new File(basedir, "project-b"); - MavenProject projectb = mojos.readMavenProject(projectbBasedir); - addDependency(projectb, "processor", new File(processor, "target/classes")); - mojos.newDependency(new File(projectaBasedir, "target/classes")) // - .setGroupId(projecta.getGroupId()) // - .setArtifactId(projecta.getArtifactId()) // - .setVersion(projecta.getVersion()) // - .addTo(projectb); - - MavenSession session = mojos.newMavenSession(projecta); - session.setProjects(Arrays.asList(projecta, projecta)); - - // process annotations in project-a - mojos.executeMojo(session, projecta, "compile", procOnly, processors, sourcepath); - mojos.assertBuildOutputs(new File(projectaBasedir, "target"), // - "generated-sources/annotations/sourcepath/projecta/GeneratedSourceA.java" // - ); - - // process annotations in project-b, requires access to project-a generated sources - session.setCurrentProject(projectb); - mojos.executeMojo(session, projectb, "compile", procOnly, processors, sourcepath); - mojos.assertBuildOutputs(new File(projectbBasedir, "target"), // - "generated-sources/annotations/sourcepath/projectb/GeneratedSourceB.java" // - ); - } - - @Test - public void testAnnotatedMember_incrementalProcessingTrigger() throws Exception { - File processor = compileAnnotationProcessor(); - File basedir = resources.getBasedir(); - File src = new File(basedir, "src/main/java"); - - // initial build, writes annotated field path is written to elements.lst file - AnnotationSpec annotation = AnnotationSpec.builder(ClassName.get("processor", "Annotation")).build(); - JavaFile.builder("proc", // - TypeSpec.classBuilder("AnnotatedMemberSource") // - .addField(FieldSpec.builder(String.class, "annotatedfield").addAnnotation(annotation).build()) // - .build()) // - .build().writeTo(src); - processAnnotations(basedir, Proc.proc, processor, newProcessors("processor.ElementsListProcessor")); - mojos.assertBuildOutputs(new File(basedir, "target/classes"), "proc/AnnotatedMemberSource.class", "elements.lst"); - assertFileContents("/proc/AnnotatedMemberSource/annotatedfield FIELD\n", basedir, "target/classes/elements.lst"); - - // incremental build, introduce new annotated element and assert elements.lst includes both the new and the old elements - JavaFile.builder("proc", // - TypeSpec.classBuilder("AnnotatedSource") // - .addAnnotation(annotation) // - .build()) // - .build().writeTo(src); - processAnnotations(basedir, Proc.proc, processor, newProcessors("processor.ElementsListProcessor")); - mojos.assertBuildOutputs(new File(basedir, "target/classes"), "proc/AnnotatedMemberSource.class", "proc/AnnotatedSource.class", "elements.lst"); - assertFileContents("/proc/AnnotatedMemberSource/annotatedfield FIELD\n/proc/AnnotatedSource CLASS\n", basedir, "target/classes/elements.lst"); - } - - @Test - public void testNestedTypeReference() throws Exception { - File processor = compileAnnotationProcessor(); - File basedir = resources.getBasedir(); - File src = new File(basedir, "src/main/java"); - - // initial build - JavaFile.builder("proc", // - TypeSpec.classBuilder("Dependency") // - .addType(TypeSpec.classBuilder("Nested").build()) // - .build()) // - .build().writeTo(src); - AnnotationSpec annotation = AnnotationSpec.builder(ClassName.get("processor", "Annotation")).build(); - JavaFile.builder("proc", // - TypeSpec.classBuilder("AnnotatedSource") // - .addField(FieldSpec.builder(ClassName.get("proc", "Dependency"), "annotatedfield").addAnnotation(annotation).build()) // - .build()) // - .build().writeTo(src); - processAnnotations(basedir, Proc.proc, processor, newProcessors("processor.ElementsTypeMemberListProcessor")); - mojos.assertBuildOutputs(new File(basedir, "target/classes"), "proc/AnnotatedSource.class", "proc/Dependency.class", "proc/Dependency$Nested.class", "elements.lst"); - assertFileContents(" CONSTRUCTOR\n", basedir, "target/classes/elements.lst"); - - // add new member to Dependency.Nested type, run incremental build - JavaFile.builder("proc", // - TypeSpec.classBuilder("Dependency") // - .addType(TypeSpec.classBuilder("Nested") // - .addField(FieldSpec.builder(String.class, "nestedTypeField").build()) // - .build()) // - .build()) // - .build().writeTo(src); - processAnnotations(basedir, Proc.proc, processor, newProcessors("processor.ElementsTypeMemberListProcessor")); - mojos.assertBuildOutputs(new File(basedir, "target/classes"), "proc/AnnotatedSource.class", "proc/Dependency.class", "proc/Dependency$Nested.class", "elements.lst"); - assertFileContents(" CONSTRUCTOR\nnestedTypeField FIELD\n", basedir, "target/classes/elements.lst"); - } } diff --git a/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/compile/ClassfileMatchers.java b/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/compile/ClassfileMatchers.java index d36a0a32..e7efd64d 100644 --- a/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/compile/ClassfileMatchers.java +++ b/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/compile/ClassfileMatchers.java @@ -1,11 +1,11 @@ package io.takari.maven.plugins.compile; +import com.google.common.io.Files; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.util.HashSet; import java.util.Set; - import org.hamcrest.BaseMatcher; import org.hamcrest.Description; import org.hamcrest.Matcher; @@ -16,224 +16,226 @@ import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; -import com.google.common.io.Files; - class ClassfileMatchers { - private static class TargetVersion extends ClassVisitor { - public TargetVersion() { - super(Opcodes.ASM6); - } + private static class TargetVersion extends ClassVisitor { + public TargetVersion() { + super(Opcodes.ASM6); + } - private int version; + private int version; - @Override - public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { - this.version = version; - } + @Override + public void visit( + int version, int access, String name, String signature, String superName, String[] interfaces) { + this.version = version; + } - public int getVersion() { - return version; + public int getVersion() { + return version; + } } - } - private static class DebugInfo extends ClassVisitor { - private boolean hasSource = false; - private boolean hasLines = false; - private boolean hasVars = false; + private static class DebugInfo extends ClassVisitor { + private boolean hasSource = false; + private boolean hasLines = false; + private boolean hasVars = false; - public DebugInfo() { - super(Opcodes.ASM5); - } - - @Override - public void visitSource(String source, String debug) { - hasSource = true; - } + public DebugInfo() { + super(Opcodes.ASM5); + } - @Override - public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { - return new MethodVisitor(Opcodes.ASM5) { @Override - public void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index) { - hasVars = true; + public void visitSource(String source, String debug) { + hasSource = true; } @Override - public void visitLineNumber(int line, Label start) { - hasLines = true; + public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { + return new MethodVisitor(Opcodes.ASM5) { + @Override + public void visitLocalVariable( + String name, String desc, String signature, Label start, Label end, int index) { + hasVars = true; + } + + @Override + public void visitLineNumber(int line, Label start) { + hasLines = true; + } + }; } - }; - } - public boolean hasSource() { - return hasSource; - } + public boolean hasSource() { + return hasSource; + } - public boolean hasVars() { - return hasVars; - } + public boolean hasVars() { + return hasVars; + } - public boolean hasLines() { - return hasLines; + public boolean hasLines() { + return hasLines; + } } - }; + ; - private static class AnnotationInfo extends ClassVisitor { + private static class AnnotationInfo extends ClassVisitor { - private final Set annotations = new HashSet<>(); + private final Set annotations = new HashSet<>(); - public AnnotationInfo() { - super(Opcodes.ASM5); - } + public AnnotationInfo() { + super(Opcodes.ASM5); + } - @Override - public AnnotationVisitor visitAnnotation(String desc, boolean visible) { - annotations.add(desc); - return null; - } + @Override + public AnnotationVisitor visitAnnotation(String desc, boolean visible) { + annotations.add(desc); + return null; + } - public Set getAnnotations() { - return annotations; + public Set getAnnotations() { + return annotations; + } } - } - - private static class MethodParameterInfo extends ClassVisitor { - private Set methodParameterNames = new HashSet<>(); + private static class MethodParameterInfo extends ClassVisitor { - public MethodParameterInfo() { - super(Opcodes.ASM5); - } + private Set methodParameterNames = new HashSet<>(); - @Override - public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { - return new MethodVisitor(Opcodes.ASM5) { + public MethodParameterInfo() { + super(Opcodes.ASM5); + } @Override - public void visitParameter(String name, int access) { - methodParameterNames.add(name); - super.visitParameter(name, access); + public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { + return new MethodVisitor(Opcodes.ASM5) { + + @Override + public void visitParameter(String name, int access) { + methodParameterNames.add(name); + super.visitParameter(name, access); + } + }; } - }; - } - public boolean hasMethodParameterName(String methodParameterName) { - return methodParameterNames.contains(methodParameterName); + public boolean hasMethodParameterName(String methodParameterName) { + return methodParameterNames.contains(methodParameterName); + } } - }; + ; - private static abstract class ClassfileMatcher extends BaseMatcher { - private String description; + private abstract static class ClassfileMatcher extends BaseMatcher { + private String description; - protected ClassfileMatcher(String description) { - this.description = description; - } + protected ClassfileMatcher(String description) { + this.description = description; + } - @Override - public final boolean matches(Object item) { - File file = (File) item; - try (InputStream is = Files.asByteSource(file).openBufferedStream()) { - T visitor = newClassVisitor(); - new ClassReader(is).accept(visitor, 0); - return matches(visitor); - } catch (IOException e) { - throw new RuntimeException(e); - } - } + @Override + public final boolean matches(Object item) { + File file = (File) item; + try (InputStream is = Files.asByteSource(file).openBufferedStream()) { + T visitor = newClassVisitor(); + new ClassReader(is).accept(visitor, 0); + return matches(visitor); + } catch (IOException e) { + throw new RuntimeException(e); + } + } - @Override - public void describeTo(Description description) { - description.appendText(this.description); - } + @Override + public void describeTo(Description description) { + description.appendText(this.description); + } - protected abstract T newClassVisitor(); - - protected abstract boolean matches(T info); - } - - public static Matcher hasDebugSource() { - return new ClassfileMatcher("include debug source info") { - @Override - protected boolean matches(DebugInfo info) { - return info.hasSource(); - } - - @Override - protected DebugInfo newClassVisitor() { - return new DebugInfo(); - } - }; - } - - public static Matcher hasDebugLines() { - return new ClassfileMatcher("include debug lines info") { - @Override - protected boolean matches(DebugInfo info) { - return info.hasLines(); - } - - @Override - protected DebugInfo newClassVisitor() { - return new DebugInfo(); - } - }; - } - - public static Matcher hasDebugVars() { - return new ClassfileMatcher("include debug lines info") { - @Override - protected boolean matches(DebugInfo info) { - return info.hasVars(); - } - - @Override - protected DebugInfo newClassVisitor() { - return new DebugInfo(); - } - }; - } - - public static Matcher hasAnnotation(final String annotation) { - final String desc = "L" + annotation.replace('.', '/') + ";"; - return new ClassfileMatcher("has annotation " + annotation) { - @Override - protected boolean matches(AnnotationInfo info) { - return info.getAnnotations().contains(desc); - } - - @Override - protected AnnotationInfo newClassVisitor() { - return new AnnotationInfo(); - } - }; - } - - public static Matcher hasMethodParameterWithName(final String parameter) { - return new ClassfileMatcher("has method parameter " + parameter) { - @Override - protected boolean matches(MethodParameterInfo info) { - return info.hasMethodParameterName(parameter); - } - - @Override - protected MethodParameterInfo newClassVisitor() { - return new MethodParameterInfo(); - } - }; - } - - public static Matcher isVersion(int version) { - return new ClassfileMatcher("is version " + version) { - @Override - protected boolean matches(TargetVersion info) { - return info.getVersion() == version; - } - - @Override - protected TargetVersion newClassVisitor() { - return new TargetVersion(); - } - }; - } + protected abstract T newClassVisitor(); + + protected abstract boolean matches(T info); + } + + public static Matcher hasDebugSource() { + return new ClassfileMatcher("include debug source info") { + @Override + protected boolean matches(DebugInfo info) { + return info.hasSource(); + } + + @Override + protected DebugInfo newClassVisitor() { + return new DebugInfo(); + } + }; + } + + public static Matcher hasDebugLines() { + return new ClassfileMatcher("include debug lines info") { + @Override + protected boolean matches(DebugInfo info) { + return info.hasLines(); + } + + @Override + protected DebugInfo newClassVisitor() { + return new DebugInfo(); + } + }; + } + + public static Matcher hasDebugVars() { + return new ClassfileMatcher("include debug lines info") { + @Override + protected boolean matches(DebugInfo info) { + return info.hasVars(); + } + + @Override + protected DebugInfo newClassVisitor() { + return new DebugInfo(); + } + }; + } + + public static Matcher hasAnnotation(final String annotation) { + final String desc = "L" + annotation.replace('.', '/') + ";"; + return new ClassfileMatcher("has annotation " + annotation) { + @Override + protected boolean matches(AnnotationInfo info) { + return info.getAnnotations().contains(desc); + } + + @Override + protected AnnotationInfo newClassVisitor() { + return new AnnotationInfo(); + } + }; + } + + public static Matcher hasMethodParameterWithName(final String parameter) { + return new ClassfileMatcher("has method parameter " + parameter) { + @Override + protected boolean matches(MethodParameterInfo info) { + return info.hasMethodParameterName(parameter); + } + + @Override + protected MethodParameterInfo newClassVisitor() { + return new MethodParameterInfo(); + } + }; + } + + public static Matcher isVersion(int version) { + return new ClassfileMatcher("is version " + version) { + @Override + protected boolean matches(TargetVersion info) { + return info.getVersion() == version; + } + + @Override + protected TargetVersion newClassVisitor() { + return new TargetVersion(); + } + }; + } } diff --git a/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/compile/CompileIncrementalTest.java b/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/compile/CompileIncrementalTest.java index 569b7bc8..510f4621 100644 --- a/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/compile/CompileIncrementalTest.java +++ b/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/compile/CompileIncrementalTest.java @@ -5,7 +5,6 @@ import static io.takari.maven.testing.TestResources.touch; import java.io.File; - import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.project.MavenProject; import org.junit.Assert; @@ -14,200 +13,206 @@ public class CompileIncrementalTest extends AbstractCompileTest { - public CompileIncrementalTest(String compilerId) { - super(compilerId); - } - - @Test - public void testBasic() throws Exception { - - File basedir = compile("compile-incremental/basic"); - File classes = new File(basedir, "target/classes"); - mojos.assertBuildOutputs(classes, "basic/Basic.class"); - - // no-change rebuild - compile(basedir); - mojos.assertBuildOutputs(classes, new String[0]); - mojos.assertDeletedOutputs(classes, new String[0]); - mojos.assertCarriedOverOutputs(classes, "basic/Basic.class"); - - // change - cp(basedir, "src/main/java/basic/Basic.java-modified", "src/main/java/basic/Basic.java"); - compile(basedir); - mojos.assertBuildOutputs(classes, "basic/Basic.class"); - } - - @Test - public void testBasic_identicalClassfile() throws Exception { - Assume.assumeTrue("jdt".equals(compilerId)); // javac eagerly deletes and recreates all outputs - - File basedir = compile("compile-incremental/basic"); - File classes = new File(basedir, "target/classes"); - mojos.assertBuildOutputs(classes, "basic/Basic.class"); - - // move back timestamp, round to 10s to accommodate filesystem timestamp rounding - long timestamp = System.currentTimeMillis() - 20000L; - timestamp = timestamp - (timestamp % 10000L); - new File(classes, "basic/Basic.class").setLastModified(timestamp); - - cp(basedir, "src/main/java/basic/Basic.java-comment", "src/main/java/basic/Basic.java"); - compile(basedir); - mojos.assertBuildOutputs(classes, "basic/Basic.class"); - Assert.assertEquals(timestamp, new File(classes, "basic/Basic.class").lastModified()); - } - - @Test - public void testDelete() throws Exception { - File basedir = compile("compile-incremental/delete"); - mojos.assertBuildOutputs(new File(basedir, "target/classes"), "delete/Delete.class", "delete/Keep.class"); - - Assert.assertTrue(new File(basedir, "src/main/java/delete/Delete.java").delete()); - compile(basedir); - if ("jdt".equals(compilerId)) { - mojos.assertCarriedOverOutputs(new File(basedir, "target/classes"), "delete/Keep.class"); - } else { - mojos.assertBuildOutputs(new File(basedir, "target/classes"), "delete/Keep.class"); + public CompileIncrementalTest(String compilerId) { + super(compilerId); + } + + @Test + public void testBasic() throws Exception { + + File basedir = compile("compile-incremental/basic"); + File classes = new File(basedir, "target/classes"); + mojos.assertBuildOutputs(classes, "basic/Basic.class"); + + // no-change rebuild + compile(basedir); + mojos.assertBuildOutputs(classes, new String[0]); + mojos.assertDeletedOutputs(classes, new String[0]); + mojos.assertCarriedOverOutputs(classes, "basic/Basic.class"); + + // change + cp(basedir, "src/main/java/basic/Basic.java-modified", "src/main/java/basic/Basic.java"); + compile(basedir); + mojos.assertBuildOutputs(classes, "basic/Basic.class"); + } + + @Test + public void testBasic_identicalClassfile() throws Exception { + Assume.assumeTrue("jdt".equals(compilerId)); // javac eagerly deletes and recreates all outputs + + File basedir = compile("compile-incremental/basic"); + File classes = new File(basedir, "target/classes"); + mojos.assertBuildOutputs(classes, "basic/Basic.class"); + + // move back timestamp, round to 10s to accommodate filesystem timestamp rounding + long timestamp = System.currentTimeMillis() - 20000L; + timestamp = timestamp - (timestamp % 10000L); + new File(classes, "basic/Basic.class").setLastModified(timestamp); + + cp(basedir, "src/main/java/basic/Basic.java-comment", "src/main/java/basic/Basic.java"); + compile(basedir); + mojos.assertBuildOutputs(classes, "basic/Basic.class"); + Assert.assertEquals(timestamp, new File(classes, "basic/Basic.class").lastModified()); } - mojos.assertDeletedOutputs(new File(basedir, "target/classes"), "delete/Delete.class"); - } - - @Test - public void testError() throws Exception { - ErrorMessage expected = new ErrorMessage(compilerId); - expected.setSnippets("jdt", "ERROR Error.java [4:11] Errorr cannot be resolved to a type"); - expected.setSnippets("javac", "ERROR Error.java [4:11]", "cannot find symbol", "class Errorr", "location", "class error.Error"); - - File basedir = resources.getBasedir("compile-incremental/error"); - try { - compile(basedir); - Assert.fail(); - } catch (MojoExecutionException e) { - // expected + + @Test + public void testDelete() throws Exception { + File basedir = compile("compile-incremental/delete"); + mojos.assertBuildOutputs(new File(basedir, "target/classes"), "delete/Delete.class", "delete/Keep.class"); + + Assert.assertTrue(new File(basedir, "src/main/java/delete/Delete.java").delete()); + compile(basedir); + if ("jdt".equals(compilerId)) { + mojos.assertCarriedOverOutputs(new File(basedir, "target/classes"), "delete/Keep.class"); + } else { + mojos.assertBuildOutputs(new File(basedir, "target/classes"), "delete/Keep.class"); + } + mojos.assertDeletedOutputs(new File(basedir, "target/classes"), "delete/Delete.class"); + } + + @Test + public void testError() throws Exception { + ErrorMessage expected = new ErrorMessage(compilerId); + expected.setSnippets("jdt", "ERROR Error.java [4:11] Errorr cannot be resolved to a type"); + expected.setSnippets( + "javac", + "ERROR Error.java [4:11]", + "cannot find symbol", + "class Errorr", + "location", + "class error.Error"); + + File basedir = resources.getBasedir("compile-incremental/error"); + try { + compile(basedir); + Assert.fail(); + } catch (MojoExecutionException e) { + // expected + } + mojos.assertBuildOutputs(basedir, new String[0]); + mojos.assertMessage(basedir, "src/main/java/error/Error.java", expected); + + // no change rebuild, should still fail with the same error + try { + compile(basedir); + Assert.fail(); + } catch (MojoExecutionException e) { + // expected + } + mojos.assertBuildOutputs(basedir, new String[0]); + mojos.assertMessage(basedir, "src/main/java/error/Error.java", expected); + + // fixed the error should clear the message during next build + cp(basedir, "src/main/java/error/Error.java-fixed", "src/main/java/error/Error.java"); + compile(basedir); + mojos.assertBuildOutputs(basedir, "target/classes/error/Error.class"); + mojos.assertMessages(basedir, "target/classes/error/Error.class", new String[0]); } - mojos.assertBuildOutputs(basedir, new String[0]); - mojos.assertMessage(basedir, "src/main/java/error/Error.java", expected); - - // no change rebuild, should still fail with the same error - try { - compile(basedir); - Assert.fail(); - } catch (MojoExecutionException e) { - // expected + + @Test + public void testClasspath_reactor() throws Exception { + File basedir = resources.getBasedir("compile-incremental/classpath"); + File moduleB = new File(basedir, "module-b"); + File moduleA = new File(basedir, "module-a"); + + compile(moduleB); + MavenProject projectA = mojos.readMavenProject(moduleA); + addDependency(projectA, "module-b", new File(moduleB, "target/classes")); + mojos.compile(projectA); + mojos.assertBuildOutputs(moduleA, "target/classes/modulea/ModuleA.class"); + + // no change rebuild + mojos.flushClasspathCaches(); + mojos.compile(projectA); + mojos.assertBuildOutputs(moduleA, new String[0]); + + // dependency changed "structurally" + mojos.flushClasspathCaches(); + cp(moduleB, "src/main/java/moduleb/ModuleB.java-method", "src/main/java/moduleb/ModuleB.java"); + touch(moduleB, "src/main/java/moduleb/ModuleB.java"); + compile(moduleB); + mojos.compile(projectA); + mojos.assertBuildOutputs(moduleA, "target/classes/modulea/ModuleA.class"); + } + + @Test + public void testClasspath_dependency() throws Exception { + File basedir = resources.getBasedir("compile-incremental/classpath"); + File moduleB = new File(basedir, "module-b"); + File moduleA = new File(basedir, "module-a"); + + MavenProject projectA = mojos.readMavenProject(moduleA); + addDependency(projectA, "module-b", new File(moduleB, "module-b.jar")); + mojos.compile(projectA); + mojos.assertBuildOutputs(moduleA, "target/classes/modulea/ModuleA.class"); + + // no change rebuild + projectA = mojos.readMavenProject(moduleA); + addDependency(projectA, "module-b", new File(moduleB, "module-b.jar")); + mojos.compile(projectA); + mojos.assertBuildOutputs(moduleA, new String[0]); + + // dependency changed "structurally" + projectA = mojos.readMavenProject(moduleA); + addDependency(projectA, "module-b", new File(moduleB, "module-b-method.jar")); + mojos.compile(projectA); + mojos.assertBuildOutputs(moduleA, "target/classes/modulea/ModuleA.class"); } - mojos.assertBuildOutputs(basedir, new String[0]); - mojos.assertMessage(basedir, "src/main/java/error/Error.java", expected); - - // fixed the error should clear the message during next build - cp(basedir, "src/main/java/error/Error.java-fixed", "src/main/java/error/Error.java"); - compile(basedir); - mojos.assertBuildOutputs(basedir, "target/classes/error/Error.class"); - mojos.assertMessages(basedir, "target/classes/error/Error.class", new String[0]); - } - - @Test - public void testClasspath_reactor() throws Exception { - File basedir = resources.getBasedir("compile-incremental/classpath"); - File moduleB = new File(basedir, "module-b"); - File moduleA = new File(basedir, "module-a"); - - compile(moduleB); - MavenProject projectA = mojos.readMavenProject(moduleA); - addDependency(projectA, "module-b", new File(moduleB, "target/classes")); - mojos.compile(projectA); - mojos.assertBuildOutputs(moduleA, "target/classes/modulea/ModuleA.class"); - - // no change rebuild - mojos.flushClasspathCaches(); - mojos.compile(projectA); - mojos.assertBuildOutputs(moduleA, new String[0]); - - // dependency changed "structurally" - mojos.flushClasspathCaches(); - cp(moduleB, "src/main/java/moduleb/ModuleB.java-method", "src/main/java/moduleb/ModuleB.java"); - touch(moduleB, "src/main/java/moduleb/ModuleB.java"); - compile(moduleB); - mojos.compile(projectA); - mojos.assertBuildOutputs(moduleA, "target/classes/modulea/ModuleA.class"); - } - - @Test - public void testClasspath_dependency() throws Exception { - File basedir = resources.getBasedir("compile-incremental/classpath"); - File moduleB = new File(basedir, "module-b"); - File moduleA = new File(basedir, "module-a"); - - MavenProject projectA = mojos.readMavenProject(moduleA); - addDependency(projectA, "module-b", new File(moduleB, "module-b.jar")); - mojos.compile(projectA); - mojos.assertBuildOutputs(moduleA, "target/classes/modulea/ModuleA.class"); - - // no change rebuild - projectA = mojos.readMavenProject(moduleA); - addDependency(projectA, "module-b", new File(moduleB, "module-b.jar")); - mojos.compile(projectA); - mojos.assertBuildOutputs(moduleA, new String[0]); - - // dependency changed "structurally" - projectA = mojos.readMavenProject(moduleA); - addDependency(projectA, "module-b", new File(moduleB, "module-b-method.jar")); - mojos.compile(projectA); - mojos.assertBuildOutputs(moduleA, "target/classes/modulea/ModuleA.class"); - } - - @Test - public void testClasspath_changedClassMovedFromProjectToDependency() throws Exception { - File basedir = resources.getBasedir("compile-incremental/move"); - File moduleB = new File(basedir, "module-b"); - File moduleA = new File(basedir, "module-a"); - - compile(moduleB); - MavenProject projectA = mojos.readMavenProject(moduleA); - addDependency(projectA, "module-b", new File(moduleB, "target/classes")); - mojos.compile(projectA); - mojos.assertBuildOutputs(moduleA, "target/classes/modulea/ModuleA.class", "target/classes/moving/Moving.class"); - - mojos.flushClasspathCaches(); - - // change and move class to the dependency - rm(moduleA, "src/main/java/moving/Moving.java"); - cp(moduleA, "src/main/java/modulea/ModuleA.java-changed", "src/main/java/modulea/ModuleA.java"); - cp(moduleB, "src/main/java/moving/Moving.java-changed", "src/main/java/moving/Moving.java"); - compile(moduleB); - mojos.compile(projectA); - mojos.assertDeletedOutputs(moduleA, "target/classes/moving/Moving.class"); - } - - @Test - public void testReferenceNested() throws Exception { - File basedir = compile("compile-incremental/reference-nested"); - File classes = new File(basedir, "target/classes"); - mojos.assertBuildOutputs(classes, "nested/A.class", "nested/Asecondary.class", "nested/B.class"); - - cp(basedir, "src/main/java/nested/A.java-changed", "src/main/java/nested/A.java"); - touch(basedir, "src/main/java/nested/B.java"); - try { - compile(basedir); - Assert.fail(); - } catch (MojoExecutionException e) { - // TODO check error message + + @Test + public void testClasspath_changedClassMovedFromProjectToDependency() throws Exception { + File basedir = resources.getBasedir("compile-incremental/move"); + File moduleB = new File(basedir, "module-b"); + File moduleA = new File(basedir, "module-a"); + + compile(moduleB); + MavenProject projectA = mojos.readMavenProject(moduleA); + addDependency(projectA, "module-b", new File(moduleB, "target/classes")); + mojos.compile(projectA); + mojos.assertBuildOutputs(moduleA, "target/classes/modulea/ModuleA.class", "target/classes/moving/Moving.class"); + + mojos.flushClasspathCaches(); + + // change and move class to the dependency + rm(moduleA, "src/main/java/moving/Moving.java"); + cp(moduleA, "src/main/java/modulea/ModuleA.java-changed", "src/main/java/modulea/ModuleA.java"); + cp(moduleB, "src/main/java/moving/Moving.java-changed", "src/main/java/moving/Moving.java"); + compile(moduleB); + mojos.compile(projectA); + mojos.assertDeletedOutputs(moduleA, "target/classes/moving/Moving.class"); + } + + @Test + public void testReferenceNested() throws Exception { + File basedir = compile("compile-incremental/reference-nested"); + File classes = new File(basedir, "target/classes"); + mojos.assertBuildOutputs(classes, "nested/A.class", "nested/Asecondary.class", "nested/B.class"); + + cp(basedir, "src/main/java/nested/A.java-changed", "src/main/java/nested/A.java"); + touch(basedir, "src/main/java/nested/B.java"); + try { + compile(basedir); + Assert.fail(); + } catch (MojoExecutionException e) { + // TODO check error message + } + Assert.assertFalse(new File(classes, "nested/B.class").exists()); + } + + @Test + public void testCrossref() throws Exception { + // two java files reference each other (via private static final members) + // "structural" change in one file causes "structural" in the other and vice versa + // assert incremental compiler does not go into endless loop + + // initial compile + File basedir = compile("compile-incremental/crossref"); + File classes = new File(basedir, "target/classes"); + mojos.assertBuildOutputs(classes, "crossref/A.class", "crossref/B.class"); + + // change one of the files and incrementally recompile + cp(basedir, "src/main/java/crossref/A.java-modified", "src/main/java/crossref/A.java"); + compile(basedir); + mojos.assertBuildOutputs(classes, "crossref/A.class", "crossref/B.class"); } - Assert.assertFalse(new File(classes, "nested/B.class").exists()); - } - - @Test - public void testCrossref() throws Exception { - // two java files reference each other (via private static final members) - // "structural" change in one file causes "structural" in the other and vice versa - // assert incremental compiler does not go into endless loop - - // initial compile - File basedir = compile("compile-incremental/crossref"); - File classes = new File(basedir, "target/classes"); - mojos.assertBuildOutputs(classes, "crossref/A.class", "crossref/B.class"); - - // change one of the files and incrementally recompile - cp(basedir, "src/main/java/crossref/A.java-modified", "src/main/java/crossref/A.java"); - compile(basedir); - mojos.assertBuildOutputs(classes, "crossref/A.class", "crossref/B.class"); - } } diff --git a/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/compile/CompileJavacClasspathVisibilityTest.java b/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/compile/CompileJavacClasspathVisibilityTest.java index 3e16c376..a4e6a4a4 100644 --- a/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/compile/CompileJavacClasspathVisibilityTest.java +++ b/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/compile/CompileJavacClasspathVisibilityTest.java @@ -1,45 +1,46 @@ package io.takari.maven.plugins.compile; import io.takari.maven.testing.TestResources; - import java.io.File; - import org.codehaus.plexus.util.xml.Xpp3Dom; import org.junit.Assert; import org.junit.Rule; import org.junit.Test; public class CompileJavacClasspathVisibilityTest { - @Rule - public final TestResources resources = new TestResources(); - - @Rule - public final CompileRule mojos = new CompileRule(); - - @Test - public void testBasic() throws Exception { - File basedir = resources.getBasedir("compile/basic"); - - Xpp3Dom compilerId = new Xpp3Dom("compilerId"); - compilerId.setValue("javac"); - Xpp3Dom transitiveDependencyReference = new Xpp3Dom("transitiveDependencyReference"); - transitiveDependencyReference.setValue("error"); - Xpp3Dom privatePackageReference = new Xpp3Dom("privatePackageReference"); - privatePackageReference.setValue("error"); - - try { - mojos.compile(basedir, compilerId, transitiveDependencyReference); - Assert.fail(); - } catch (IllegalArgumentException e) { - ErrorMessage.isMatch(e.getMessage(), "Compiler javac does not support transitiveDependencyReference=error, use compilerId=jdt"); - } - - try { - mojos.compile(basedir, compilerId, privatePackageReference); - Assert.fail(); - } catch (IllegalArgumentException e) { - ErrorMessage.isMatch(e.getMessage(), "Compiler javac does not support privatePackageReference=error, use compilerId=jdt"); + @Rule + public final TestResources resources = new TestResources(); + + @Rule + public final CompileRule mojos = new CompileRule(); + + @Test + public void testBasic() throws Exception { + File basedir = resources.getBasedir("compile/basic"); + + Xpp3Dom compilerId = new Xpp3Dom("compilerId"); + compilerId.setValue("javac"); + Xpp3Dom transitiveDependencyReference = new Xpp3Dom("transitiveDependencyReference"); + transitiveDependencyReference.setValue("error"); + Xpp3Dom privatePackageReference = new Xpp3Dom("privatePackageReference"); + privatePackageReference.setValue("error"); + + try { + mojos.compile(basedir, compilerId, transitiveDependencyReference); + Assert.fail(); + } catch (IllegalArgumentException e) { + ErrorMessage.isMatch( + e.getMessage(), + "Compiler javac does not support transitiveDependencyReference=error, use compilerId=jdt"); + } + + try { + mojos.compile(basedir, compilerId, privatePackageReference); + Assert.fail(); + } catch (IllegalArgumentException e) { + ErrorMessage.isMatch( + e.getMessage(), + "Compiler javac does not support privatePackageReference=error, use compilerId=jdt"); + } } - - } } diff --git a/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/compile/CompileRule.java b/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/compile/CompileRule.java index 60a9c693..63d6da49 100644 --- a/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/compile/CompileRule.java +++ b/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/compile/CompileRule.java @@ -1,8 +1,10 @@ package io.takari.maven.plugins.compile; +import io.takari.incrementalbuild.maven.testing.IncrementalBuildRule; +import io.takari.maven.plugins.compile.jdt.ClasspathDigester; +import io.takari.maven.plugins.compile.jdt.ClasspathEntryCache; import java.io.File; import java.util.Collection; - import org.apache.maven.execution.MavenSession; import org.apache.maven.plugin.MojoExecution; import org.apache.maven.project.MavenProject; @@ -10,61 +12,57 @@ import org.junit.Assert; import org.junit.ComparisonFailure; -import io.takari.incrementalbuild.maven.testing.IncrementalBuildRule; -import io.takari.maven.plugins.compile.jdt.ClasspathDigester; -import io.takari.maven.plugins.compile.jdt.ClasspathEntryCache; - public class CompileRule extends IncrementalBuildRule { - public File compile(File basedir, Xpp3Dom... parameters) throws Exception { - MavenProject project = readMavenProject(basedir); - compile(project, parameters); - return basedir; - } - - public void compile(MavenProject project, Xpp3Dom... parameters) throws Exception { - MavenSession session = newMavenSession(project); - compile(session, project, parameters); - } - - public void compile(MavenSession session, MavenProject project, Xpp3Dom... parameters) throws Exception { - MojoExecution execution = newMojoExecution(); + public File compile(File basedir, Xpp3Dom... parameters) throws Exception { + MavenProject project = readMavenProject(basedir); + compile(project, parameters); + return basedir; + } - if (parameters != null) { - Xpp3Dom configuration = execution.getConfiguration(); - for (Xpp3Dom parameter : parameters) { - configuration.addChild(parameter); - } + public void compile(MavenProject project, Xpp3Dom... parameters) throws Exception { + MavenSession session = newMavenSession(project); + compile(session, project, parameters); } - executeMojo(session, project, execution); - } + public void compile(MavenSession session, MavenProject project, Xpp3Dom... parameters) throws Exception { + MojoExecution execution = newMojoExecution(); + + if (parameters != null) { + Xpp3Dom configuration = execution.getConfiguration(); + for (Xpp3Dom parameter : parameters) { + configuration.addChild(parameter); + } + } - public MojoExecution newMojoExecution() { - return newMojoExecution("compile"); - } + executeMojo(session, project, execution); + } - public void assertMessage(File file, String... strings) throws Exception { - Collection messages = getBuildContextLog().getMessages(file); - Assert.assertEquals(messages.toString(), 1, messages.size()); - String message = messages.iterator().next(); - Assert.assertTrue(ErrorMessage.isMatch(message, strings)); - } + public MojoExecution newMojoExecution() { + return newMojoExecution("compile"); + } - public void assertMessage(File basedir, String path, ErrorMessage expected) throws Exception { - Collection messages = getBuildContextLog().getMessages(new File(basedir, path)); - if (messages.size() != 1) { - throw new ComparisonFailure("Number of messages", expected.toString(), messages.toString()); + public void assertMessage(File file, String... strings) throws Exception { + Collection messages = getBuildContextLog().getMessages(file); + Assert.assertEquals(messages.toString(), 1, messages.size()); + String message = messages.iterator().next(); + Assert.assertTrue(ErrorMessage.isMatch(message, strings)); } - String message = messages.iterator().next(); - if (!expected.isMatch(message)) { - throw new ComparisonFailure("", expected.toString(), message); + + public void assertMessage(File basedir, String path, ErrorMessage expected) throws Exception { + Collection messages = getBuildContextLog().getMessages(new File(basedir, path)); + if (messages.size() != 1) { + throw new ComparisonFailure("Number of messages", expected.toString(), messages.toString()); + } + String message = messages.iterator().next(); + if (!expected.isMatch(message)) { + throw new ComparisonFailure("", expected.toString(), message); + } } - } - public void flushClasspathCaches() { - ClasspathEntryCache.flush(); - ProjectClasspathDigester.flush(); - ClasspathDigester.flush(); - } + public void flushClasspathCaches() { + ClasspathEntryCache.flush(); + ProjectClasspathDigester.flush(); + ClasspathDigester.flush(); + } } diff --git a/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/compile/CompileTest.java b/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/compile/CompileTest.java index 9d69247a..9904a56f 100644 --- a/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/compile/CompileTest.java +++ b/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/compile/CompileTest.java @@ -13,10 +13,13 @@ import static org.junit.Assert.assertThat; import static org.junit.Assume.assumeTrue; +import com.google.common.base.Charsets; +import com.google.common.io.Files; +import io.takari.maven.plugins.compile.javac.CompilerJavac; +import io.takari.maven.plugins.compile.jdt.CompilerJdt; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.PrintStream; - import org.apache.maven.execution.MavenSession; import org.apache.maven.plugin.MojoExecution; import org.apache.maven.plugin.MojoExecutionException; @@ -26,400 +29,422 @@ import org.junit.Ignore; import org.junit.Test; -import com.google.common.base.Charsets; -import com.google.common.io.Files; +public class CompileTest extends AbstractCompileTest { -import io.takari.maven.plugins.compile.javac.CompilerJavac; -import io.takari.maven.plugins.compile.jdt.CompilerJdt; + public CompileTest(String compilerId) { + super(compilerId); + } -public class CompileTest extends AbstractCompileTest { + @Test + public void testBasic() throws Exception { + File basedir = compile("compile/basic"); + File classes = new File(basedir, "target/classes"); + mojos.assertBuildOutputs(classes, "basic/Basic.class"); + } + + @Test + public void testBasic_testCompile() throws Exception { + File basedir = compile("compile/basic"); + File testClasses = new File(basedir, "target/test-classes"); - public CompileTest(String compilerId) { - super(compilerId); - } - - @Test - public void testBasic() throws Exception { - File basedir = compile("compile/basic"); - File classes = new File(basedir, "target/classes"); - mojos.assertBuildOutputs(classes, "basic/Basic.class"); - } - - @Test - public void testBasic_testCompile() throws Exception { - File basedir = compile("compile/basic"); - File testClasses = new File(basedir, "target/test-classes"); - - MavenProject project = mojos.readMavenProject(basedir); - MavenSession session = mojos.newMavenSession(project); - MojoExecution execution = mojos.newMojoExecution("testCompile"); - execution.getConfiguration().addChild(newParameter("compilerId", compilerId)); - mojos.executeMojo(session, project, execution); - - mojos.assertBuildOutputs(testClasses, "basic/BasicTest.class"); - } - - @Test - public void testBasic_verbose() throws Exception { - PrintStream origOut = System.out; - try { - ByteArrayOutputStream buf = new ByteArrayOutputStream(); - System.setOut(new PrintStream(buf, true)); - File basedir = compile("compile/basic", newParameter("verbose", "true")); - mojos.assertBuildOutputs(basedir, "target/classes/basic/Basic.class"); - String output = new String(buf.toByteArray()); - Assert.assertTrue(output.contains("parsing ")); - } finally { - System.setOut(origOut); + MavenProject project = mojos.readMavenProject(basedir); + MavenSession session = mojos.newMavenSession(project); + MojoExecution execution = mojos.newMojoExecution("testCompile"); + execution.getConfiguration().addChild(newParameter("compilerId", compilerId)); + mojos.executeMojo(session, project, execution); + + mojos.assertBuildOutputs(testClasses, "basic/BasicTest.class"); } - } - - @Test - public void testBasic_debugInfo() throws Exception { - File basedir; - - // all - basedir = compile("compile/basic"); - assertThat(new File(basedir, "target/classes/basic/Basic.class"), allOf(hasDebugSource(), hasDebugLines(), hasDebugVars())); - basedir = compile("compile/basic", newParameter("debug", "all")); - assertThat(new File(basedir, "target/classes/basic/Basic.class"), allOf(hasDebugSource(), hasDebugLines(), hasDebugVars())); - basedir = compile("compile/basic", newParameter("debug", "true")); - assertThat(new File(basedir, "target/classes/basic/Basic.class"), allOf(hasDebugSource(), hasDebugLines(), hasDebugVars())); - - // none - basedir = compile("compile/basic", newParameter("debug", "none")); - assertThat(new File(basedir, "target/classes/basic/Basic.class"), allOf(not(hasDebugSource()), not(hasDebugLines()), not(hasDebugVars()))); - basedir = compile("compile/basic", newParameter("debug", "false")); - assertThat(new File(basedir, "target/classes/basic/Basic.class"), allOf(not(hasDebugSource()), not(hasDebugLines()), not(hasDebugVars()))); - - // keywords - basedir = compile("compile/basic", newParameter("debug", "source")); - assertThat(new File(basedir, "target/classes/basic/Basic.class"), allOf(hasDebugSource(), not(hasDebugLines()), not(hasDebugVars()))); - basedir = compile("compile/basic", newParameter("debug", "source,lines")); - assertThat(new File(basedir, "target/classes/basic/Basic.class"), allOf(hasDebugSource(), hasDebugLines(), not(hasDebugVars()))); - basedir = compile("compile/basic", newParameter("debug", "source,lines,vars")); - assertThat(new File(basedir, "target/classes/basic/Basic.class"), allOf(hasDebugSource(), hasDebugLines(), hasDebugVars())); - } - - @Test - public void testBasic_skipMain() throws Exception { - File basedir = compile("compile/basic", newParameter("skipMain", "true")); - File classes = new File(basedir, "target/classes"); - mojos.assertBuildOutputs(classes, new String[0]); - - compile(basedir); - mojos.assertBuildOutputs(classes, "basic/Basic.class"); - - compile(basedir, newParameter("skipMain", "true")); - mojos.assertBuildOutputs(classes, new String[0]); - mojos.assertDeletedOutputs(classes, new String[0]); - } - - @Test - public void testBasic_skip() throws Exception { - File basedir = compile("compile/basic"); - File testClasses = new File(basedir, "target/test-classes"); - - MavenProject project = mojos.readMavenProject(basedir); - MavenSession session = mojos.newMavenSession(project); - MojoExecution execution = mojos.newMojoExecution("testCompile"); - execution.getConfiguration().addChild(newParameter("compilerId", compilerId)); - execution.getConfiguration().addChild(newParameter("skip", "true")); - mojos.executeMojo(session, project, execution); - mojos.assertBuildOutputs(testClasses, new String[0]); - - execution = mojos.newMojoExecution("testCompile"); - execution.getConfiguration().addChild(newParameter("compilerId", compilerId)); - mojos.executeMojo(session, project, execution); - mojos.assertBuildOutputs(testClasses, "basic/BasicTest.class"); - - execution = mojos.newMojoExecution("testCompile"); - execution.getConfiguration().addChild(newParameter("compilerId", compilerId)); - execution.getConfiguration().addChild(newParameter("skip", "true")); - mojos.executeMojo(session, project, execution); - mojos.assertBuildOutputs(testClasses, new String[0]); - mojos.assertDeletedOutputs(testClasses, new String[0]); - } - - @Test - @Ignore("Java 7 source/target is not supported on recent JDKs") - public void testBasic_java7() throws Exception { - File basedir = compile("compile/basic", newParameter("source", "1.7")); - assertThat(new File(basedir, "target/classes/basic/Basic.class"), isVersion(51)); - } - - @Test - public void testBasic_java8() throws Exception { - File basedir = compile("compile/basic", newParameter("source", "1.8")); - assertThat(new File(basedir, "target/classes/basic/Basic.class"), isVersion(52)); - } - - @Test - public void testBasic_java9() throws Exception { - assumeTrue(isJava9orBetter); - File basedir = compile("compile/basic", newParameter("source", "9")); - assertThat(new File(basedir, "target/classes/basic/Basic.class"), isVersion(53)); - } - - @Test - public void testBasic_java10() throws Exception { - assumeTrue(isJava10orBetter); - File basedir = compile("compile/basic", newParameter("source", "10")); - assertThat(new File(basedir, "target/classes/basic/Basic.class"), isVersion(54)); - } - - @Test - public void testBasic_java11() throws Exception { - assumeTrue(isJava10orBetter); - File basedir = compile("compile/basic", newParameter("source", "11")); - assertThat(new File(basedir, "target/classes/basic/Basic.class"), isVersion(55)); - } - - @Test - public void testIncludes() throws Exception { - Xpp3Dom includes = new Xpp3Dom("includes"); - includes.addChild(newParameter("include", "basic/Basic.java")); - File basedir = compile("compile/source-filtering", includes); - - mojos.assertBuildOutputs(new File(basedir, "target/classes"), "basic/Basic.class"); - } - - @Test - public void testExcludes() throws Exception { - Xpp3Dom excludes = new Xpp3Dom("excludes"); - excludes.addChild(newParameter("exclude", "basic/Garbage.java")); - File basedir = compile("compile/source-filtering", excludes); - - mojos.assertBuildOutputs(new File(basedir, "target/classes"), "basic/Basic.class"); - } - - @Test - public void testClasspath() throws Exception { - File dependency = new File(compile("compile/basic"), "target/classes"); - - File basedir = resources.getBasedir("compile/classpath"); - MavenProject project = mojos.readMavenProject(basedir); - MavenSession session = mojos.newMavenSession(project); - MojoExecution execution = mojos.newMojoExecution(); - - addDependency(project, "dependency", dependency); - - mojos.executeMojo(session, project, execution); - - mojos.assertBuildOutputs(new File(basedir, "target/classes"), "classpath/Classpath.class"); - } - - @Test - public void testClasspath_dependencySourceTypes_ignore() throws Exception { - // dependency has both .java and .class files, but .java file is corrupted - // assert the compiler uses .class file when dependencySourceTypes=ignore - - File dependency = compile("compile/basic"); - Files.write("corrupted", new File(dependency, "target/classes/basic/Basic.java"), Charsets.UTF_8); - touch(new File(dependency, "target/classes/basic/Basic.java")); // javac will pick newer file by default - - File basedir = resources.getBasedir("compile/classpath"); - MavenProject project = mojos.readMavenProject(basedir); - - addDependency(project, "dependency", new File(dependency, "target/classes")); - - mojos.compile(project, newParameter("dependencySourceTypes", "ignore")); - - mojos.assertBuildOutputs(new File(basedir, "target/classes"), "classpath/Classpath.class"); - } - - @Test - public void testSpace() throws Exception { - File basedir = compile("compile/spa ce"); - Assert.assertTrue(basedir.getAbsolutePath().contains(" ")); - mojos.assertBuildOutputs(new File(basedir, "target/classes"), "space/Space.class"); - } - - @Test - public void testError() throws Exception { - ErrorMessage expected = new ErrorMessage(compilerId); - expected.setSnippets("jdt", "ERROR Error.java [4:11] Foo cannot be resolved to a type"); - expected.setSnippets("javac", "ERROR Error.java [4:11]", "cannot find symbol", "class Foo", "location", "class basic.Error"); - - File basedir = resources.getBasedir("compile/error"); - try { - compile(basedir); - Assert.fail(); - } catch (MojoExecutionException e) { - // expected + + @Test + public void testBasic_verbose() throws Exception { + PrintStream origOut = System.out; + try { + ByteArrayOutputStream buf = new ByteArrayOutputStream(); + System.setOut(new PrintStream(buf, true)); + File basedir = compile("compile/basic", newParameter("verbose", "true")); + mojos.assertBuildOutputs(basedir, "target/classes/basic/Basic.class"); + String output = new String(buf.toByteArray()); + Assert.assertTrue(output.contains("parsing ")); + } finally { + System.setOut(origOut); + } } - mojos.assertBuildOutputs(basedir, new String[0]); - mojos.assertMessage(basedir, "src/main/java/error/Error.java", expected); - } - - @Test - public void testWarn() throws Exception { - File basedir = resources.getBasedir("compile/warn"); - compile(basedir); // no warnings by default - mojos.assertBuildOutputs(new File(basedir, "target/classes"), "warn/Warn.class"); - mojos.assertMessages(basedir, "src/main/java/warn/Warn.java", new String[0]); - - ErrorMessage expected = new ErrorMessage(compilerId); - expected.setSnippets("jdt", "WARNING Warn.java [5:3] List is a raw type. References to generic type List should be parameterized"); - expected.setSnippets("javac", "WARNING Warn.java [5:12] found raw type: java.util.List\n missing type arguments for generic class java.util.List"); - - compile(basedir, newParameter("showWarnings", "true")); - mojos.assertBuildOutputs(new File(basedir, "target/classes"), "warn/Warn.class"); - mojos.assertMessage(basedir, "src/main/java/warn/Warn.java", expected); - } - - @Test - public void testEncoding() throws Exception { - File basedir = resources.getBasedir("compile/encoding"); - try { - compile(basedir, newParameter("encoding", "ISO-8859-5")); - Assert.fail(); - } catch (MojoExecutionException e) { - // + + @Test + public void testBasic_debugInfo() throws Exception { + File basedir; + + // all + basedir = compile("compile/basic"); + assertThat( + new File(basedir, "target/classes/basic/Basic.class"), + allOf(hasDebugSource(), hasDebugLines(), hasDebugVars())); + basedir = compile("compile/basic", newParameter("debug", "all")); + assertThat( + new File(basedir, "target/classes/basic/Basic.class"), + allOf(hasDebugSource(), hasDebugLines(), hasDebugVars())); + basedir = compile("compile/basic", newParameter("debug", "true")); + assertThat( + new File(basedir, "target/classes/basic/Basic.class"), + allOf(hasDebugSource(), hasDebugLines(), hasDebugVars())); + + // none + basedir = compile("compile/basic", newParameter("debug", "none")); + assertThat( + new File(basedir, "target/classes/basic/Basic.class"), + allOf(not(hasDebugSource()), not(hasDebugLines()), not(hasDebugVars()))); + basedir = compile("compile/basic", newParameter("debug", "false")); + assertThat( + new File(basedir, "target/classes/basic/Basic.class"), + allOf(not(hasDebugSource()), not(hasDebugLines()), not(hasDebugVars()))); + + // keywords + basedir = compile("compile/basic", newParameter("debug", "source")); + assertThat( + new File(basedir, "target/classes/basic/Basic.class"), + allOf(hasDebugSource(), not(hasDebugLines()), not(hasDebugVars()))); + basedir = compile("compile/basic", newParameter("debug", "source,lines")); + assertThat( + new File(basedir, "target/classes/basic/Basic.class"), + allOf(hasDebugSource(), hasDebugLines(), not(hasDebugVars()))); + basedir = compile("compile/basic", newParameter("debug", "source,lines,vars")); + assertThat( + new File(basedir, "target/classes/basic/Basic.class"), + allOf(hasDebugSource(), hasDebugLines(), hasDebugVars())); } - mojos.assertMessage(new File(basedir, "src/main/java/encoding/ISO8859p5.java"), "\u043f\u043e\u0440\u0443\u0441\u0441\u043a\u0438"); // "inrussian" in UTF8 Russian - } - - @Test - public void testParameters() throws Exception { - File basedir = resources.getBasedir("compile/parameters"); - compile(basedir, newParameter("parameters", "true"), newParameter("source", "1.8")); - assertThat(new File(basedir, "target/classes/parameters/MethodParameter.class"), hasMethodParameterWithName("myNamedParameter")); - } - - @Test - public void testEmpty() throws Exception { - File basedir = compile("compile/empty"); - mojos.assertBuildOutputs(basedir, new String[0]); - Assert.assertFalse("outputDirectory was not created", new File(basedir, "target/classes").exists()); - } - - @Test - public void testIncludeNonJavaSources() throws Exception { - File basedir = resources.getBasedir("compile/unexpected-sources"); - try { - compile(basedir); - } catch (MojoExecutionException e) { - Assert.assertEquals(" patterns must end with .java. Illegal patterns: [**]", e.getMessage()); + + @Test + public void testBasic_skipMain() throws Exception { + File basedir = compile("compile/basic", newParameter("skipMain", "true")); + File classes = new File(basedir, "target/classes"); + mojos.assertBuildOutputs(classes, new String[0]); + + compile(basedir); + mojos.assertBuildOutputs(classes, "basic/Basic.class"); + + compile(basedir, newParameter("skipMain", "true")); + mojos.assertBuildOutputs(classes, new String[0]); + mojos.assertDeletedOutputs(classes, new String[0]); } - mojos.assertBuildOutputs(basedir, new String[0]); - } - - @Test - public void testMultipleExecutions() throws Exception { - File basedir = resources.getBasedir("compile/multiple-executions"); - MavenProject project = mojos.readMavenProject(basedir); - MavenSession session = mojos.newMavenSession(project); - - // compile "other" sources, execution id="other" - MojoExecution execution = mojos.newMojoExecution(); - Xpp3Dom configuration = execution.getConfiguration(); - Xpp3Dom otherIncludes = new Xpp3Dom("includes"); - otherIncludes.addChild(newParameter("include", "other/*.java")); - configuration.addChild(otherIncludes); - execution = new MojoExecution(execution.getMojoDescriptor(), "other", execution.getSource()); - execution.setConfiguration(configuration); - mojos.executeMojo(session, project, execution); - mojos.assertBuildOutputs(new File(basedir, "target/classes"), "other/Other.class"); - - // compile main sources - Xpp3Dom includes = new Xpp3Dom("includes"); - includes.addChild(newParameter("include", "main/*.java")); - compile(basedir, includes); - mojos.assertBuildOutputs(new File(basedir, "target/classes"), "main/Main.class"); - } - - @Test - public void testBinaryTypeMessage() throws Exception { - // javac (tested with 1.8.0_05 and 1.7.0_45) produce warning messages for dependency .class files in some cases - // the point of this test is to verify compile mojo tolerates this messages, i.e. does not fail - // in this particular test, the message is triggered by missing @annotation referenced from a dependency class - - File basedir = resources.getBasedir("compile/binary-class-message"); - - MavenProject project = mojos.readMavenProject(new File(basedir, "project")); - MavenSession session = mojos.newMavenSession(project); - MojoExecution execution = mojos.newMojoExecution(); - addDependency(project, "dependency", new File(basedir, "annotated.zip")); - mojos.executeMojo(session, project, execution); - mojos.assertBuildOutputs(new File(basedir, "project/target/classes"), "project/Project.class"); - } - - @Test - public void testImplicitClassfileGeneration() throws Exception { - // javac automatically generates class files from sources found on classpath in some cases - // the point of this test is to make sure this behaviour is disabled - - File dependency = compile("compile/basic"); - cp(dependency, "src/main/java/basic/Basic.java", "target/classes/basic/Basic.java"); - touch(dependency, "target/classes/basic/Basic.java"); // must be newer than .class file - - File basedir = resources.getBasedir("compile/implicit-classfile"); - MavenProject project = mojos.readMavenProject(basedir); - MavenSession session = mojos.newMavenSession(project); - MojoExecution execution = mojos.newMojoExecution(); - - addDependency(project, "dependency", new File(dependency, "target/classes")); - - mojos.executeMojo(session, project, execution); - - mojos.assertBuildOutputs(new File(basedir, "target/classes"), "implicit/Implicit.class"); - } - - @Test - public void testAnnotation() throws Exception { - File basedir = compile("compile/annotation"); - - assertThat(new File(basedir, "target/classes/annotation/AnnotatedClass.class"), hasAnnotation("annotation.Annotation")); - } - - @Test - @Ignore("The test is useful but needs to be reimplemented") - public void testInnerTypeDependency_sourceDependencies() throws Exception { - File basedir = resources.getBasedir("compile/inner-type-dependency"); - - MavenProject project = mojos.readMavenProject(basedir); - addDependency(project, "dependency", new File(basedir, "dependency/src/main/java")); - - mojos.compile(project, newParameter("dependencySourceTypes", "prefer")); - mojos.assertBuildOutputs(new File(basedir, "target/classes"), "innertyperef/InnerTypeRef.class"); - } - - @Test - public void testFailOnErrorTrue() throws Exception { - ErrorMessage expected = new ErrorMessage(compilerId); - String msg; - if (compilerId.equals(CompilerJdt.ID)) { - msg = "ERROR Error.java [5:13] Strin cannot be resolved to a type"; - expected.setSnippets(CompilerJdt.ID, msg); - } else { - // javac and forked-javac - msg = "ERROR Error.java [5:13] cannot find symbol\n" + // - " symbol: class Strin\n" + // - " location: class basic.Error"; - expected.setSnippets(CompilerJavac.ID, msg); + + @Test + public void testBasic_skip() throws Exception { + File basedir = compile("compile/basic"); + File testClasses = new File(basedir, "target/test-classes"); + + MavenProject project = mojos.readMavenProject(basedir); + MavenSession session = mojos.newMavenSession(project); + MojoExecution execution = mojos.newMojoExecution("testCompile"); + execution.getConfiguration().addChild(newParameter("compilerId", compilerId)); + execution.getConfiguration().addChild(newParameter("skip", "true")); + mojos.executeMojo(session, project, execution); + mojos.assertBuildOutputs(testClasses, new String[0]); + + execution = mojos.newMojoExecution("testCompile"); + execution.getConfiguration().addChild(newParameter("compilerId", compilerId)); + mojos.executeMojo(session, project, execution); + mojos.assertBuildOutputs(testClasses, "basic/BasicTest.class"); + + execution = mojos.newMojoExecution("testCompile"); + execution.getConfiguration().addChild(newParameter("compilerId", compilerId)); + execution.getConfiguration().addChild(newParameter("skip", "true")); + mojos.executeMojo(session, project, execution); + mojos.assertBuildOutputs(testClasses, new String[0]); + mojos.assertDeletedOutputs(testClasses, new String[0]); } - File basedir = resources.getBasedir("compile/failOnError"); - try { - compile("compile/failOnError"); - // Assert.fail(); - } catch (MojoExecutionException e) { - // + @Test + @Ignore("Java 7 source/target is not supported on recent JDKs") + public void testBasic_java7() throws Exception { + File basedir = compile("compile/basic", newParameter("source", "1.7")); + assertThat(new File(basedir, "target/classes/basic/Basic.class"), isVersion(51)); } - mojos.assertMessage(basedir, "src/main/java/basic/Error.java", expected); - } - - @Test - public void testFailOnErrorFalse() throws Exception { - try { - File basedir = resources.getBasedir("compile/failOnError"); - compile("compile/failOnError", newParameter("failOnError", "false")); - if (compilerId.equals(CompilerJdt.ID)) { + + @Test + public void testBasic_java8() throws Exception { + File basedir = compile("compile/basic", newParameter("source", "1.8")); + assertThat(new File(basedir, "target/classes/basic/Basic.class"), isVersion(52)); + } + + @Test + public void testBasic_java9() throws Exception { + assumeTrue(isJava9orBetter); + File basedir = compile("compile/basic", newParameter("source", "9")); + assertThat(new File(basedir, "target/classes/basic/Basic.class"), isVersion(53)); + } + + @Test + public void testBasic_java10() throws Exception { + assumeTrue(isJava10orBetter); + File basedir = compile("compile/basic", newParameter("source", "10")); + assertThat(new File(basedir, "target/classes/basic/Basic.class"), isVersion(54)); + } + + @Test + public void testBasic_java11() throws Exception { + assumeTrue(isJava10orBetter); + File basedir = compile("compile/basic", newParameter("source", "11")); + assertThat(new File(basedir, "target/classes/basic/Basic.class"), isVersion(55)); + } + + @Test + public void testIncludes() throws Exception { + Xpp3Dom includes = new Xpp3Dom("includes"); + includes.addChild(newParameter("include", "basic/Basic.java")); + File basedir = compile("compile/source-filtering", includes); + mojos.assertBuildOutputs(new File(basedir, "target/classes"), "basic/Basic.class"); - } - } catch (MojoExecutionException e) { - Assert.fail(); } - } + + @Test + public void testExcludes() throws Exception { + Xpp3Dom excludes = new Xpp3Dom("excludes"); + excludes.addChild(newParameter("exclude", "basic/Garbage.java")); + File basedir = compile("compile/source-filtering", excludes); + + mojos.assertBuildOutputs(new File(basedir, "target/classes"), "basic/Basic.class"); + } + + @Test + public void testClasspath() throws Exception { + File dependency = new File(compile("compile/basic"), "target/classes"); + + File basedir = resources.getBasedir("compile/classpath"); + MavenProject project = mojos.readMavenProject(basedir); + MavenSession session = mojos.newMavenSession(project); + MojoExecution execution = mojos.newMojoExecution(); + + addDependency(project, "dependency", dependency); + + mojos.executeMojo(session, project, execution); + + mojos.assertBuildOutputs(new File(basedir, "target/classes"), "classpath/Classpath.class"); + } + + @Test + public void testClasspath_dependencySourceTypes_ignore() throws Exception { + // dependency has both .java and .class files, but .java file is corrupted + // assert the compiler uses .class file when dependencySourceTypes=ignore + + File dependency = compile("compile/basic"); + Files.write("corrupted", new File(dependency, "target/classes/basic/Basic.java"), Charsets.UTF_8); + touch(new File(dependency, "target/classes/basic/Basic.java")); // javac will pick newer file by default + + File basedir = resources.getBasedir("compile/classpath"); + MavenProject project = mojos.readMavenProject(basedir); + + addDependency(project, "dependency", new File(dependency, "target/classes")); + + mojos.compile(project, newParameter("dependencySourceTypes", "ignore")); + + mojos.assertBuildOutputs(new File(basedir, "target/classes"), "classpath/Classpath.class"); + } + + @Test + public void testSpace() throws Exception { + File basedir = compile("compile/spa ce"); + Assert.assertTrue(basedir.getAbsolutePath().contains(" ")); + mojos.assertBuildOutputs(new File(basedir, "target/classes"), "space/Space.class"); + } + + @Test + public void testError() throws Exception { + ErrorMessage expected = new ErrorMessage(compilerId); + expected.setSnippets("jdt", "ERROR Error.java [4:11] Foo cannot be resolved to a type"); + expected.setSnippets( + "javac", "ERROR Error.java [4:11]", "cannot find symbol", "class Foo", "location", "class basic.Error"); + + File basedir = resources.getBasedir("compile/error"); + try { + compile(basedir); + Assert.fail(); + } catch (MojoExecutionException e) { + // expected + } + mojos.assertBuildOutputs(basedir, new String[0]); + mojos.assertMessage(basedir, "src/main/java/error/Error.java", expected); + } + + @Test + public void testWarn() throws Exception { + File basedir = resources.getBasedir("compile/warn"); + compile(basedir); // no warnings by default + mojos.assertBuildOutputs(new File(basedir, "target/classes"), "warn/Warn.class"); + mojos.assertMessages(basedir, "src/main/java/warn/Warn.java", new String[0]); + + ErrorMessage expected = new ErrorMessage(compilerId); + expected.setSnippets( + "jdt", + "WARNING Warn.java [5:3] List is a raw type. References to generic type List should be parameterized"); + expected.setSnippets( + "javac", + "WARNING Warn.java [5:12] found raw type: java.util.List\n missing type arguments for generic class java.util.List"); + + compile(basedir, newParameter("showWarnings", "true")); + mojos.assertBuildOutputs(new File(basedir, "target/classes"), "warn/Warn.class"); + mojos.assertMessage(basedir, "src/main/java/warn/Warn.java", expected); + } + + @Test + public void testEncoding() throws Exception { + File basedir = resources.getBasedir("compile/encoding"); + try { + compile(basedir, newParameter("encoding", "ISO-8859-5")); + Assert.fail(); + } catch (MojoExecutionException e) { + // + } + mojos.assertMessage( + new File(basedir, "src/main/java/encoding/ISO8859p5.java"), + "\u043f\u043e\u0440\u0443\u0441\u0441\u043a\u0438"); // "inrussian" in UTF8 Russian + } + + @Test + public void testParameters() throws Exception { + File basedir = resources.getBasedir("compile/parameters"); + compile(basedir, newParameter("parameters", "true"), newParameter("source", "1.8")); + assertThat( + new File(basedir, "target/classes/parameters/MethodParameter.class"), + hasMethodParameterWithName("myNamedParameter")); + } + + @Test + public void testEmpty() throws Exception { + File basedir = compile("compile/empty"); + mojos.assertBuildOutputs(basedir, new String[0]); + Assert.assertFalse("outputDirectory was not created", new File(basedir, "target/classes").exists()); + } + + @Test + public void testIncludeNonJavaSources() throws Exception { + File basedir = resources.getBasedir("compile/unexpected-sources"); + try { + compile(basedir); + } catch (MojoExecutionException e) { + Assert.assertEquals(" patterns must end with .java. Illegal patterns: [**]", e.getMessage()); + } + mojos.assertBuildOutputs(basedir, new String[0]); + } + + @Test + public void testMultipleExecutions() throws Exception { + File basedir = resources.getBasedir("compile/multiple-executions"); + MavenProject project = mojos.readMavenProject(basedir); + MavenSession session = mojos.newMavenSession(project); + + // compile "other" sources, execution id="other" + MojoExecution execution = mojos.newMojoExecution(); + Xpp3Dom configuration = execution.getConfiguration(); + Xpp3Dom otherIncludes = new Xpp3Dom("includes"); + otherIncludes.addChild(newParameter("include", "other/*.java")); + configuration.addChild(otherIncludes); + execution = new MojoExecution(execution.getMojoDescriptor(), "other", execution.getSource()); + execution.setConfiguration(configuration); + mojos.executeMojo(session, project, execution); + mojos.assertBuildOutputs(new File(basedir, "target/classes"), "other/Other.class"); + + // compile main sources + Xpp3Dom includes = new Xpp3Dom("includes"); + includes.addChild(newParameter("include", "main/*.java")); + compile(basedir, includes); + mojos.assertBuildOutputs(new File(basedir, "target/classes"), "main/Main.class"); + } + + @Test + public void testBinaryTypeMessage() throws Exception { + // javac (tested with 1.8.0_05 and 1.7.0_45) produce warning messages for dependency .class files in some cases + // the point of this test is to verify compile mojo tolerates this messages, i.e. does not fail + // in this particular test, the message is triggered by missing @annotation referenced from a dependency class + + File basedir = resources.getBasedir("compile/binary-class-message"); + + MavenProject project = mojos.readMavenProject(new File(basedir, "project")); + MavenSession session = mojos.newMavenSession(project); + MojoExecution execution = mojos.newMojoExecution(); + addDependency(project, "dependency", new File(basedir, "annotated.zip")); + mojos.executeMojo(session, project, execution); + mojos.assertBuildOutputs(new File(basedir, "project/target/classes"), "project/Project.class"); + } + + @Test + public void testImplicitClassfileGeneration() throws Exception { + // javac automatically generates class files from sources found on classpath in some cases + // the point of this test is to make sure this behaviour is disabled + + File dependency = compile("compile/basic"); + cp(dependency, "src/main/java/basic/Basic.java", "target/classes/basic/Basic.java"); + touch(dependency, "target/classes/basic/Basic.java"); // must be newer than .class file + + File basedir = resources.getBasedir("compile/implicit-classfile"); + MavenProject project = mojos.readMavenProject(basedir); + MavenSession session = mojos.newMavenSession(project); + MojoExecution execution = mojos.newMojoExecution(); + + addDependency(project, "dependency", new File(dependency, "target/classes")); + + mojos.executeMojo(session, project, execution); + + mojos.assertBuildOutputs(new File(basedir, "target/classes"), "implicit/Implicit.class"); + } + + @Test + public void testAnnotation() throws Exception { + File basedir = compile("compile/annotation"); + + assertThat( + new File(basedir, "target/classes/annotation/AnnotatedClass.class"), + hasAnnotation("annotation.Annotation")); + } + + @Test + @Ignore("The test is useful but needs to be reimplemented") + public void testInnerTypeDependency_sourceDependencies() throws Exception { + File basedir = resources.getBasedir("compile/inner-type-dependency"); + + MavenProject project = mojos.readMavenProject(basedir); + addDependency(project, "dependency", new File(basedir, "dependency/src/main/java")); + + mojos.compile(project, newParameter("dependencySourceTypes", "prefer")); + mojos.assertBuildOutputs(new File(basedir, "target/classes"), "innertyperef/InnerTypeRef.class"); + } + + @Test + public void testFailOnErrorTrue() throws Exception { + ErrorMessage expected = new ErrorMessage(compilerId); + String msg; + if (compilerId.equals(CompilerJdt.ID)) { + msg = "ERROR Error.java [5:13] Strin cannot be resolved to a type"; + expected.setSnippets(CompilerJdt.ID, msg); + } else { + // javac and forked-javac + msg = "ERROR Error.java [5:13] cannot find symbol\n" + // + " symbol: class Strin\n" + + // + " location: class basic.Error"; + expected.setSnippets(CompilerJavac.ID, msg); + } + + File basedir = resources.getBasedir("compile/failOnError"); + try { + compile("compile/failOnError"); + // Assert.fail(); + } catch (MojoExecutionException e) { + // + } + mojos.assertMessage(basedir, "src/main/java/basic/Error.java", expected); + } + + @Test + public void testFailOnErrorFalse() throws Exception { + try { + File basedir = resources.getBasedir("compile/failOnError"); + compile("compile/failOnError", newParameter("failOnError", "false")); + if (compilerId.equals(CompilerJdt.ID)) { + mojos.assertBuildOutputs(new File(basedir, "target/classes"), "basic/Basic.class"); + } + } catch (MojoExecutionException e) { + Assert.fail(); + } + } } diff --git a/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/compile/ErrorMessage.java b/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/compile/ErrorMessage.java index 0c81065a..dba0b5a1 100644 --- a/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/compile/ErrorMessage.java +++ b/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/compile/ErrorMessage.java @@ -5,46 +5,46 @@ public class ErrorMessage { - private final String compilerId; + private final String compilerId; - private final Map variants = new HashMap<>(); + private final Map variants = new HashMap<>(); - public ErrorMessage(String compilerId) { - this.compilerId = compilerId; - } + public ErrorMessage(String compilerId) { + this.compilerId = compilerId; + } - public void setSnippets(String compilerId, String... snippets) { - variants.put(normalizeCompilerId(compilerId), snippets); - } + public void setSnippets(String compilerId, String... snippets) { + variants.put(normalizeCompilerId(compilerId), snippets); + } - public boolean isMatch(String message) { - return isMatch(message, variants.get(normalizeCompilerId(compilerId))); - } + public boolean isMatch(String message) { + return isMatch(message, variants.get(normalizeCompilerId(compilerId))); + } - private String normalizeCompilerId(String compilerId) { - return "forked-javac".equals(compilerId) ? "javac" : compilerId; - } + private String normalizeCompilerId(String compilerId) { + return "forked-javac".equals(compilerId) ? "javac" : compilerId; + } - public static boolean isMatch(String message, String... snippets) { - int idx = 0; - for (String snippet : snippets) { - idx = message.indexOf(snippet, idx); - if (idx < 0) { - return false; - } + public static boolean isMatch(String message, String... snippets) { + int idx = 0; + for (String snippet : snippets) { + idx = message.indexOf(snippet, idx); + if (idx < 0) { + return false; + } + } + return true; } - return true; - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - for (String snippet : variants.get(compilerId)) { - if (sb.length() > 0) { - sb.append(" ... "); - } - sb.append(snippet); + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + for (String snippet : variants.get(compilerId)) { + if (sb.length() > 0) { + sb.append(" ... "); + } + sb.append(snippet); + } + return sb.toString(); } - return sb.toString(); - } } diff --git a/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/compile/ForkedCompileTest.java b/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/compile/ForkedCompileTest.java index e0d38fca..5a9be7f6 100644 --- a/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/compile/ForkedCompileTest.java +++ b/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/compile/ForkedCompileTest.java @@ -1,9 +1,7 @@ package io.takari.maven.plugins.compile; import io.takari.maven.testing.TestResources; - import java.io.File; - import org.apache.maven.plugin.MojoExecutionException; import org.codehaus.plexus.util.xml.Xpp3Dom; import org.junit.Assert; @@ -12,46 +10,46 @@ public class ForkedCompileTest { - @Rule - public final TestResources resources = new TestResources(); - - @Rule - public final CompileRule mojos = new CompileRule(); - - @Test - public void testJvmMemoryOptions() throws Exception { - File basedir = resources.getBasedir("compile/basic"); - - Xpp3Dom fork = new Xpp3Dom("compilerId"); - fork.setValue("forked-javac"); - - Xpp3Dom maxmem = new Xpp3Dom("maxmem"); - Xpp3Dom meminitial = new Xpp3Dom("meminitial"); - - maxmem.setValue("64M"); - meminitial.setValue("64M"); - mojos.compile(basedir, fork, meminitial, maxmem); - mojos.assertBuildOutputs(basedir, "target/classes/basic/Basic.class"); - - // this is an awkward way to assert parameters worked - // check if jvm startup fails with garbage -Xms/-Xmx parameters - - maxmem.setValue("garbage"); - meminitial.setValue("64M"); - try { - mojos.compile(basedir, fork, meminitial, maxmem); - Assert.fail(); - } catch (MojoExecutionException e) { - // TODO assert compilation failed for the right reason - } - - maxmem.setValue("64M"); - meminitial.setValue("garbage"); - try { - mojos.compile(basedir, fork, meminitial, maxmem); - Assert.fail(); - } catch (MojoExecutionException e) { - // TODO assert compilation failed for the right reason + @Rule + public final TestResources resources = new TestResources(); + + @Rule + public final CompileRule mojos = new CompileRule(); + + @Test + public void testJvmMemoryOptions() throws Exception { + File basedir = resources.getBasedir("compile/basic"); + + Xpp3Dom fork = new Xpp3Dom("compilerId"); + fork.setValue("forked-javac"); + + Xpp3Dom maxmem = new Xpp3Dom("maxmem"); + Xpp3Dom meminitial = new Xpp3Dom("meminitial"); + + maxmem.setValue("64M"); + meminitial.setValue("64M"); + mojos.compile(basedir, fork, meminitial, maxmem); + mojos.assertBuildOutputs(basedir, "target/classes/basic/Basic.class"); + + // this is an awkward way to assert parameters worked + // check if jvm startup fails with garbage -Xms/-Xmx parameters + + maxmem.setValue("garbage"); + meminitial.setValue("64M"); + try { + mojos.compile(basedir, fork, meminitial, maxmem); + Assert.fail(); + } catch (MojoExecutionException e) { + // TODO assert compilation failed for the right reason + } + + maxmem.setValue("64M"); + meminitial.setValue("garbage"); + try { + mojos.compile(basedir, fork, meminitial, maxmem); + Assert.fail(); + } catch (MojoExecutionException e) { + // TODO assert compilation failed for the right reason + } } - } } diff --git a/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/compile/MixedCompilerBackendTest.java b/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/compile/MixedCompilerBackendTest.java index 91967b93..fd01ad90 100644 --- a/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/compile/MixedCompilerBackendTest.java +++ b/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/compile/MixedCompilerBackendTest.java @@ -2,37 +2,35 @@ import static io.takari.maven.testing.TestMavenRuntime.newParameter; +import io.takari.maven.testing.TestResources; import java.io.File; - import org.apache.maven.project.MavenProject; import org.junit.Rule; import org.junit.Test; -import io.takari.maven.testing.TestResources; - public class MixedCompilerBackendTest { - @Rule - public final TestResources resources = new TestResources(); - - @Rule - public final CompileRule mojos = new CompileRule(); - - @Test - public void testClasspath() throws Exception { - // assert classpath caches are updated when project classes/test-classes changes - - File basedir = resources.getBasedir("compile-incremental/classpath"); - File moduleB = new File(basedir, "module-b"); - File moduleA = new File(basedir, "module-a"); - - mojos.compile(moduleB, newParameter("proc", "only"), newParameter("compilerId", "jdt")); - mojos.assertBuildOutputs(moduleB, new String[0]); - mojos.compile(moduleB, newParameter("compilerId", "javac")); - mojos.assertBuildOutputs(moduleB, "target/classes/moduleb/ModuleB.class"); - - MavenProject projectA = mojos.readMavenProject(moduleA); - mojos.newDependency(new File(moduleB, "target/classes")).addTo(projectA); - mojos.compile(projectA, newParameter("compilerId", "jdt")); - mojos.assertBuildOutputs(moduleA, "target/classes/modulea/ModuleA.class"); - } + @Rule + public final TestResources resources = new TestResources(); + + @Rule + public final CompileRule mojos = new CompileRule(); + + @Test + public void testClasspath() throws Exception { + // assert classpath caches are updated when project classes/test-classes changes + + File basedir = resources.getBasedir("compile-incremental/classpath"); + File moduleB = new File(basedir, "module-b"); + File moduleA = new File(basedir, "module-a"); + + mojos.compile(moduleB, newParameter("proc", "only"), newParameter("compilerId", "jdt")); + mojos.assertBuildOutputs(moduleB, new String[0]); + mojos.compile(moduleB, newParameter("compilerId", "javac")); + mojos.assertBuildOutputs(moduleB, "target/classes/moduleb/ModuleB.class"); + + MavenProject projectA = mojos.readMavenProject(moduleA); + mojos.newDependency(new File(moduleB, "target/classes")).addTo(projectA); + mojos.compile(projectA, newParameter("compilerId", "jdt")); + mojos.assertBuildOutputs(moduleA, "target/classes/modulea/ModuleA.class"); + } } diff --git a/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/compile/ProcessorpathResolverTest.java b/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/compile/ProcessorpathResolverTest.java index 97d598e9..f1c8a850 100644 --- a/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/compile/ProcessorpathResolverTest.java +++ b/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/compile/ProcessorpathResolverTest.java @@ -3,11 +3,12 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import io.takari.maven.testing.TestMavenRuntime; +import io.takari.maven.testing.TestResources; import java.io.File; import java.util.Collections; import java.util.List; import java.util.StringTokenizer; - import org.apache.maven.execution.MavenSession; import org.apache.maven.model.Dependency; import org.apache.maven.project.MavenProject; @@ -16,45 +17,45 @@ import org.junit.Test; import org.junit.rules.TemporaryFolder; -import io.takari.maven.testing.TestMavenRuntime; -import io.takari.maven.testing.TestResources; - public class ProcessorpathResolverTest { - @Rule - public final TemporaryFolder temp = new TemporaryFolder(); - - @Rule - public final TestResources resources = new TestResources(); - - @Rule - public final TestMavenRuntime maven = new TestMavenRuntime(); - - @Test - public void testVersionlessDependency() throws Exception { - File basedir = resources.getBasedir(); - MavenProject project = maven.readMavenProject(basedir); - maven.newDependency(temp.newFile()).setGroupId("g").setArtifactId("a").setVersion("1").addTo(project); - - MavenSession mavenSession = maven.newMavenSession(project); - RepositorySystemSession repoSession = mavenSession.getRepositorySession(); - SimpleReactorReader.builder() // - .addArtifact("g:a:1", temp.newFile()) // - .addArtifact("g:a:pom:1", temp.newFile()) // - .toSession(repoSession); - - ProcessorpathResolver resolver = maven.lookup(ProcessorpathResolver.class); - List processorpath = resolver.resolve(repoSession, project, dependencies("g:a")); - - assertEquals(1, processorpath.size()); - assertTrue(processorpath.get(0).isFile()); - } - - private List dependencies(String coords) { - StringTokenizer st = new StringTokenizer(coords, ":"); - Dependency dependency = new Dependency(); - dependency.setGroupId(st.nextToken()); - dependency.setArtifactId(st.nextToken()); - return Collections.singletonList(dependency); - } - + @Rule + public final TemporaryFolder temp = new TemporaryFolder(); + + @Rule + public final TestResources resources = new TestResources(); + + @Rule + public final TestMavenRuntime maven = new TestMavenRuntime(); + + @Test + public void testVersionlessDependency() throws Exception { + File basedir = resources.getBasedir(); + MavenProject project = maven.readMavenProject(basedir); + maven.newDependency(temp.newFile()) + .setGroupId("g") + .setArtifactId("a") + .setVersion("1") + .addTo(project); + + MavenSession mavenSession = maven.newMavenSession(project); + RepositorySystemSession repoSession = mavenSession.getRepositorySession(); + SimpleReactorReader.builder() // + .addArtifact("g:a:1", temp.newFile()) // + .addArtifact("g:a:pom:1", temp.newFile()) // + .toSession(repoSession); + + ProcessorpathResolver resolver = maven.lookup(ProcessorpathResolver.class); + List processorpath = resolver.resolve(repoSession, project, dependencies("g:a")); + + assertEquals(1, processorpath.size()); + assertTrue(processorpath.get(0).isFile()); + } + + private List dependencies(String coords) { + StringTokenizer st = new StringTokenizer(coords, ":"); + Dependency dependency = new Dependency(); + dependency.setGroupId(st.nextToken()); + dependency.setArtifactId(st.nextToken()); + return Collections.singletonList(dependency); + } } diff --git a/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/compile/SimpleReactorReader.java b/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/compile/SimpleReactorReader.java index 89740a3f..3f88df47 100644 --- a/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/compile/SimpleReactorReader.java +++ b/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/compile/SimpleReactorReader.java @@ -1,5 +1,6 @@ package io.takari.maven.plugins.compile; +import com.google.common.collect.ImmutableMap; import java.io.File; import java.util.ArrayList; import java.util.Collection; @@ -7,7 +8,6 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; - import org.apache.maven.artifact.ArtifactUtils; import org.apache.maven.model.Model; import org.apache.maven.project.MavenProject; @@ -19,138 +19,137 @@ import org.eclipse.aether.repository.WorkspaceRepository; import org.eclipse.aether.util.repository.ChainedWorkspaceReader; -import com.google.common.collect.ImmutableMap; - class SimpleReactorReader implements MavenWorkspaceReader { - private final WorkspaceRepository repository; - private final Map projectsByGAV; - private final Map artifactsByGAVCE; - - private SimpleReactorReader(Collection projects, Collection artifacts) { - repository = new WorkspaceRepository("reactor", new Object()); - - Map projectsByGAV = new LinkedHashMap<>(); - for (MavenProject project : projects) { - String projectKey = ArtifactUtils.key(project.getGroupId(), project.getArtifactId(), project.getVersion()); - projectsByGAV.put(projectKey, project); + private final WorkspaceRepository repository; + private final Map projectsByGAV; + private final Map artifactsByGAVCE; + + private SimpleReactorReader(Collection projects, Collection artifacts) { + repository = new WorkspaceRepository("reactor", new Object()); + + Map projectsByGAV = new LinkedHashMap<>(); + for (MavenProject project : projects) { + String projectKey = ArtifactUtils.key(project.getGroupId(), project.getArtifactId(), project.getVersion()); + projectsByGAV.put(projectKey, project); + } + this.projectsByGAV = ImmutableMap.copyOf(projectsByGAV); + + Map artifactsByGAVCE = new LinkedHashMap<>(); + for (Artifact artifact : artifacts) { + artifactsByGAVCE.put(keyGAVCE(artifact), artifact); + } + this.artifactsByGAVCE = ImmutableMap.copyOf(artifactsByGAVCE); } - this.projectsByGAV = ImmutableMap.copyOf(projectsByGAV); - Map artifactsByGAVCE = new LinkedHashMap<>(); - for (Artifact artifact : artifacts) { - artifactsByGAVCE.put(keyGAVCE(artifact), artifact); + @Override + public WorkspaceRepository getRepository() { + return repository; } - this.artifactsByGAVCE = ImmutableMap.copyOf(artifactsByGAVCE); - } - - @Override - public WorkspaceRepository getRepository() { - return repository; - } - - @Override - public File findArtifact(Artifact artifact) { - MavenProject project = getProject(artifact); - if (project != null) { - if ("pom".equals(artifact.getExtension())) { - return project.getFile(); - } else if ("jar".equals(artifact.getExtension()) && "".equals(artifact.getClassifier())) { - return new File(project.getBuild().getOutputDirectory()); - } + + @Override + public File findArtifact(Artifact artifact) { + MavenProject project = getProject(artifact); + if (project != null) { + if ("pom".equals(artifact.getExtension())) { + return project.getFile(); + } else if ("jar".equals(artifact.getExtension()) && "".equals(artifact.getClassifier())) { + return new File(project.getBuild().getOutputDirectory()); + } + } + Artifact _artifact = getArtifact(artifact); + if (_artifact != null) { + return _artifact.getFile(); + } + return null; } - Artifact _artifact = getArtifact(artifact); - if (_artifact != null) { - return _artifact.getFile(); + + private Artifact getArtifact(Artifact artifact) { + return artifactsByGAVCE.get(keyGAVCE(artifact)); } - return null; - } - - private Artifact getArtifact(Artifact artifact) { - return artifactsByGAVCE.get(keyGAVCE(artifact)); - } - - private static String keyGAVCE(Artifact artifact) { - StringBuilder key = new StringBuilder(); - key.append(artifact.getGroupId()) // - .append(":").append(artifact.getArtifactId()) // - .append(":").append(artifact.getVersion()) // - .append(":").append(artifact.getClassifier()) // - .append(":").append(artifact.getExtension()); - return key.toString(); - } - - private MavenProject getProject(Artifact artifact) { - String projectKey = ArtifactUtils.key(artifact.getGroupId(), artifact.getArtifactId(), artifact.getVersion()); - MavenProject project = projectsByGAV.get(projectKey); - return project; - } - - @Override - public List findVersions(Artifact artifact) { - MavenProject project = getProject(artifact); - if (project != null) { - return Collections.singletonList(project.getVersion()); + + private static String keyGAVCE(Artifact artifact) { + StringBuilder key = new StringBuilder(); + key.append(artifact.getGroupId()) // + .append(":") + .append(artifact.getArtifactId()) // + .append(":") + .append(artifact.getVersion()) // + .append(":") + .append(artifact.getClassifier()) // + .append(":") + .append(artifact.getExtension()); + return key.toString(); } - Artifact _artifact = getArtifact(artifact); - if (_artifact != null) { - return Collections.singletonList(_artifact.getVersion()); + + private MavenProject getProject(Artifact artifact) { + String projectKey = ArtifactUtils.key(artifact.getGroupId(), artifact.getArtifactId(), artifact.getVersion()); + MavenProject project = projectsByGAV.get(projectKey); + return project; } - return null; - } - - @Override - public Model findModel(Artifact artifact) { - MavenProject project = getProject(artifact); - if (project != null) { - return project.getModel(); + + @Override + public List findVersions(Artifact artifact) { + MavenProject project = getProject(artifact); + if (project != null) { + return Collections.singletonList(project.getVersion()); + } + Artifact _artifact = getArtifact(artifact); + if (_artifact != null) { + return Collections.singletonList(_artifact.getVersion()); + } + return null; } - return null; - } + @Override + public Model findModel(Artifact artifact) { + MavenProject project = getProject(artifact); + if (project != null) { + return project.getModel(); + } + return null; + } - // - // - // + // + // + // - public static class Builder { + public static class Builder { - private final List projects = new ArrayList<>(); - private final List artifacts = new ArrayList<>(); + private final List projects = new ArrayList<>(); + private final List artifacts = new ArrayList<>(); - public SimpleReactorReader build() { - return new SimpleReactorReader(projects, artifacts); - } + public SimpleReactorReader build() { + return new SimpleReactorReader(projects, artifacts); + } - public Builder addProject(MavenProject project) { - projects.add(project); - return this; - } + public Builder addProject(MavenProject project) { + projects.add(project); + return this; + } - /** :[:[:]]: */ - public Builder addArtifact(String coords, File file) { - artifacts.add(new DefaultArtifact(coords).setFile(file)); + /** :[:[:]]: */ + public Builder addArtifact(String coords, File file) { + artifacts.add(new DefaultArtifact(coords).setFile(file)); - return this; - } + return this; + } - public void toSession(RepositorySystemSession session) { - DefaultRepositorySystemSession _session = (DefaultRepositorySystemSession) session; - _session.setWorkspaceReader(ChainedWorkspaceReader.newInstance(build(), _session.getWorkspaceReader())); - } + public void toSession(RepositorySystemSession session) { + DefaultRepositorySystemSession _session = (DefaultRepositorySystemSession) session; + _session.setWorkspaceReader(ChainedWorkspaceReader.newInstance(build(), _session.getWorkspaceReader())); + } - public Builder addProjects(MavenProject... projects) { - for (MavenProject project : projects) { - addProject(project); - } + public Builder addProjects(MavenProject... projects) { + for (MavenProject project : projects) { + addProject(project); + } - return this; + return this; + } } - } - - public static Builder builder() { - return new Builder(); - } - + public static Builder builder() { + return new Builder(); + } } diff --git a/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/compile/jdt/AbstractCompileJdtTest.java b/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/compile/jdt/AbstractCompileJdtTest.java index eb03af16..34e02248 100644 --- a/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/compile/jdt/AbstractCompileJdtTest.java +++ b/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/compile/jdt/AbstractCompileJdtTest.java @@ -1,38 +1,36 @@ package io.takari.maven.plugins.compile.jdt; +import io.takari.maven.plugins.compile.CompileRule; +import io.takari.maven.testing.TestResources; import java.io.File; - import org.apache.maven.plugin.MojoExecution; import org.apache.maven.project.MavenProject; import org.codehaus.plexus.util.xml.Xpp3Dom; import org.junit.Rule; -import io.takari.maven.plugins.compile.CompileRule; -import io.takari.maven.testing.TestResources; - public abstract class AbstractCompileJdtTest { - @Rule - public final TestResources resources = new TestResources(); - - @Rule - public final CompileRule mojos = new CompileRule() { - @Override - public org.apache.maven.plugin.MojoExecution newMojoExecution() { - MojoExecution execution = super.newMojoExecution(); - Xpp3Dom compilerId = new Xpp3Dom("compilerId"); - compilerId.setValue("jdt"); - execution.getConfiguration().addChild(compilerId); - return execution; + @Rule + public final TestResources resources = new TestResources(); + + @Rule + public final CompileRule mojos = new CompileRule() { + @Override + public org.apache.maven.plugin.MojoExecution newMojoExecution() { + MojoExecution execution = super.newMojoExecution(); + Xpp3Dom compilerId = new Xpp3Dom("compilerId"); + compilerId.setValue("jdt"); + execution.getConfiguration().addChild(compilerId); + return execution; + } + ; }; - }; - - protected void addDependency(MavenProject project, String artifactId, File file) throws Exception { - addDependency(project, artifactId, file, true); - } - protected void addDependency(MavenProject project, String artifactId, File file, boolean direct) throws Exception { - mojos.newDependency(file).setArtifactId(artifactId).addTo(project, direct); - } + protected void addDependency(MavenProject project, String artifactId, File file) throws Exception { + addDependency(project, artifactId, file, true); + } + protected void addDependency(MavenProject project, String artifactId, File file, boolean direct) throws Exception { + mojos.newDependency(file).setArtifactId(artifactId).addTo(project, direct); + } } diff --git a/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/compile/jdt/CompileJdtClasspathTest.java b/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/compile/jdt/CompileJdtClasspathTest.java index 44c163aa..05c8da15 100644 --- a/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/compile/jdt/CompileJdtClasspathTest.java +++ b/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/compile/jdt/CompileJdtClasspathTest.java @@ -3,7 +3,6 @@ import static io.takari.maven.testing.TestResources.cp; import java.io.File; - import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.project.MavenProject; import org.junit.Assert; @@ -11,147 +10,166 @@ public class CompileJdtClasspathTest extends AbstractCompileJdtTest { - @Test - public void testReactor() throws Exception { - File parent = resources.getBasedir("compile-jdt-classpath/reactor-basic"); - - compileReactor(parent); - mojos.assertBuildOutputs(parent, "module-a/target/classes/reactor/modulea/ModuleA.class"); - - // no change rebuild - compileReactor(parent); - mojos.assertCarriedOverOutputs(parent, "module-a/target/classes/reactor/modulea/ModuleA.class"); - - // comment changes do NOT propagate - cp(new File(parent, "module-b/src/main/java/reactor/moduleb"), "ModuleB.java-comment", "ModuleB.java"); - compileReactor(parent); - mojos.assertCarriedOverOutputs(parent, "module-a/target/classes/reactor/modulea/ModuleA.class"); - - // API changes DO propagate - cp(new File(parent, "module-b/src/main/java/reactor/moduleb"), "ModuleB.java-method", "ModuleB.java"); - compileReactor(parent); - mojos.assertBuildOutputs(parent, "module-a/target/classes/reactor/modulea/ModuleA.class"); - } - - @Test - public void testReactor_missingType() throws Exception { - File parent = resources.getBasedir("compile-jdt-classpath/reactor-missing"); - - try { - compileReactor(parent); - Assert.fail(); - } catch (MojoExecutionException e) { - // expected + @Test + public void testReactor() throws Exception { + File parent = resources.getBasedir("compile-jdt-classpath/reactor-basic"); + + compileReactor(parent); + mojos.assertBuildOutputs(parent, "module-a/target/classes/reactor/modulea/ModuleA.class"); + + // no change rebuild + compileReactor(parent); + mojos.assertCarriedOverOutputs(parent, "module-a/target/classes/reactor/modulea/ModuleA.class"); + + // comment changes do NOT propagate + cp(new File(parent, "module-b/src/main/java/reactor/moduleb"), "ModuleB.java-comment", "ModuleB.java"); + compileReactor(parent); + mojos.assertCarriedOverOutputs(parent, "module-a/target/classes/reactor/modulea/ModuleA.class"); + + // API changes DO propagate + cp(new File(parent, "module-b/src/main/java/reactor/moduleb"), "ModuleB.java-method", "ModuleB.java"); + compileReactor(parent); + mojos.assertBuildOutputs(parent, "module-a/target/classes/reactor/modulea/ModuleA.class"); } - mojos.assertBuildOutputs(parent, new String[0]); - mojos.assertMessages(parent, "module-a/src/main/java/modulea/Error.java", "ERROR Error.java [3:8] The import moduleb cannot be resolved", - "ERROR Error.java [8:12] Missing cannot be resolved to a type", "ERROR Error.java [10:20] Missing cannot be resolved to a type"); - - // fix the problem and rebuild - cp(parent, "module-b/src/main/java/moduleb/Missing.java-missing", "module-b/src/main/java/moduleb/Missing.java"); - compileReactor(parent); - mojos.assertBuildOutputs(parent, "module-a/target/classes/modulea/Error.class"); - } - - @Test - public void testReactor_missingOnDemandImport() throws Exception { - File parent = resources.getBasedir("compile-jdt-classpath/reactor-missing-ondemand-import"); - - try { - compileReactor(parent); - Assert.fail(); - } catch (MojoExecutionException e) { - // expected + + @Test + public void testReactor_missingType() throws Exception { + File parent = resources.getBasedir("compile-jdt-classpath/reactor-missing"); + + try { + compileReactor(parent); + Assert.fail(); + } catch (MojoExecutionException e) { + // expected + } + mojos.assertBuildOutputs(parent, new String[0]); + mojos.assertMessages( + parent, + "module-a/src/main/java/modulea/Error.java", + "ERROR Error.java [3:8] The import moduleb cannot be resolved", + "ERROR Error.java [8:12] Missing cannot be resolved to a type", + "ERROR Error.java [10:20] Missing cannot be resolved to a type"); + + // fix the problem and rebuild + cp( + parent, + "module-b/src/main/java/moduleb/Missing.java-missing", + "module-b/src/main/java/moduleb/Missing.java"); + compileReactor(parent); + mojos.assertBuildOutputs(parent, "module-a/target/classes/modulea/Error.class"); + } + + @Test + public void testReactor_missingOnDemandImport() throws Exception { + File parent = resources.getBasedir("compile-jdt-classpath/reactor-missing-ondemand-import"); + + try { + compileReactor(parent); + Assert.fail(); + } catch (MojoExecutionException e) { + // expected + } + mojos.assertBuildOutputs(parent, new String[0]); + mojos.assertMessages( + parent, + "module-a/src/main/java/modulea/Error.java", + "ERROR Error.java [3:8] The import moduleb cannot be resolved"); + + // fix the problem and rebuild + cp( + parent, + "module-b/src/main/java/moduleb/Missing.java-missing", + "module-b/src/main/java/moduleb/Missing.java"); + compileReactor(parent); + mojos.assertBuildOutputs(parent, "module-a/target/classes/modulea/Error.class"); + } + + @Test + public void testReactor_missingType_splitpackage() throws Exception { + File parent = resources.getBasedir("compile-jdt-classpath/reactor-missing-splitpackage"); + + try { + compileReactor(parent); + Assert.fail(); + } catch (MojoExecutionException e) { + // expected + } + mojos.assertBuildOutputs(parent, new String[0]); + mojos.assertMessages( + parent, + "module-a/src/main/java/missing/Error.java", + "ERROR Error.java [6:12] Missing cannot be resolved to a type", + "ERROR Error.java [8:20] Missing cannot be resolved to a type"); + + // fix the problem and rebuild + cp( + parent, + "module-b/src/main/java/missing/Missing.java-missing", + "module-b/src/main/java/missing/Missing.java"); + compileReactor(parent); + mojos.assertBuildOutputs(parent, "module-a/target/classes/missing/Error.class"); } - mojos.assertBuildOutputs(parent, new String[0]); - mojos.assertMessages(parent, "module-a/src/main/java/modulea/Error.java", "ERROR Error.java [3:8] The import moduleb cannot be resolved"); - - // fix the problem and rebuild - cp(parent, "module-b/src/main/java/moduleb/Missing.java-missing", "module-b/src/main/java/moduleb/Missing.java"); - compileReactor(parent); - mojos.assertBuildOutputs(parent, "module-a/target/classes/modulea/Error.class"); - } - - @Test - public void testReactor_missingType_splitpackage() throws Exception { - File parent = resources.getBasedir("compile-jdt-classpath/reactor-missing-splitpackage"); - - try { - compileReactor(parent); - Assert.fail(); - } catch (MojoExecutionException e) { - // expected + + @Test + public void testRepository() throws Exception { + File parent = resources.getBasedir("compile-jdt-classpath/repo-basic"); + + MavenProject moduleA = mojos.readMavenProject(new File(parent, "module-a")); + addDependency(moduleA, "module-b", new File(parent, "module-b/module-b.jar")); + mojos.compile(moduleA); + mojos.assertBuildOutputs(parent, "module-a/target/classes/reactor/modulea/ModuleA.class"); + + // dependency changed non-structurally + moduleA = mojos.readMavenProject(new File(parent, "module-a")); + addDependency(moduleA, "module-b-2", new File(parent, "module-b/module-b-comment.jar")); + mojos.compile(moduleA); + mojos.assertBuildOutputs(parent, new String[0]); + + // dependency changed structurally + moduleA = mojos.readMavenProject(new File(parent, "module-a")); + addDependency(moduleA, "module-b-2", new File(parent, "module-b/module-b-method.jar")); + mojos.compile(moduleA); + mojos.assertBuildOutputs(parent, "module-a/target/classes/reactor/modulea/ModuleA.class"); + } + + @Test + public void testRepository_classpathOrder() throws Exception { + File parent = resources.getBasedir("compile-jdt-classpath/repo-basic"); + + MavenProject moduleA = mojos.readMavenProject(new File(parent, "module-a")); + addDependency(moduleA, "module-b", new File(parent, "module-b/module-b.jar")); + addDependency(moduleA, "module-b-comment", new File(parent, "module-b/module-b-comment.jar")); + addDependency(moduleA, "module-b-method", new File(parent, "module-b/module-b-method.jar")); + mojos.compile(moduleA); + mojos.assertBuildOutputs(parent, "module-a/target/classes/reactor/modulea/ModuleA.class"); + + // classpath order change did not result in structural type definition change + moduleA = mojos.readMavenProject(new File(parent, "module-a")); + addDependency(moduleA, "module-b-comment", new File(parent, "module-b/module-b-comment.jar")); + addDependency(moduleA, "module-b", new File(parent, "module-b/module-b.jar")); + addDependency(moduleA, "module-b-method", new File(parent, "module-b/module-b-method.jar")); + mojos.compile(moduleA); + mojos.assertBuildOutputs(parent, new String[0]); + + // classpath order change DID result in structural type definition change + moduleA = mojos.readMavenProject(new File(parent, "module-a")); + addDependency(moduleA, "module-b-method", new File(parent, "module-b/module-b-method.jar")); + addDependency(moduleA, "module-b", new File(parent, "module-b/module-b.jar")); + addDependency(moduleA, "module-b-comment", new File(parent, "module-b/module-b-comment.jar")); + mojos.compile(moduleA); + mojos.assertBuildOutputs(parent, "module-a/target/classes/reactor/modulea/ModuleA.class"); + } + + private void compileReactor(File parent) throws Exception { + mojos.flushClasspathCaches(); + + File moduleB = new File(parent, "module-b"); + + mojos.compile(moduleB); + + MavenProject moduleA = mojos.readMavenProject(new File(parent, "module-a")); + addDependency(moduleA, "module-b", new File(moduleB, "target/classes")); + + mojos.compile(moduleA); } - mojos.assertBuildOutputs(parent, new String[0]); - mojos.assertMessages(parent, "module-a/src/main/java/missing/Error.java", "ERROR Error.java [6:12] Missing cannot be resolved to a type", - "ERROR Error.java [8:20] Missing cannot be resolved to a type"); - - // fix the problem and rebuild - cp(parent, "module-b/src/main/java/missing/Missing.java-missing", "module-b/src/main/java/missing/Missing.java"); - compileReactor(parent); - mojos.assertBuildOutputs(parent, "module-a/target/classes/missing/Error.class"); - } - - @Test - public void testRepository() throws Exception { - File parent = resources.getBasedir("compile-jdt-classpath/repo-basic"); - - MavenProject moduleA = mojos.readMavenProject(new File(parent, "module-a")); - addDependency(moduleA, "module-b", new File(parent, "module-b/module-b.jar")); - mojos.compile(moduleA); - mojos.assertBuildOutputs(parent, "module-a/target/classes/reactor/modulea/ModuleA.class"); - - // dependency changed non-structurally - moduleA = mojos.readMavenProject(new File(parent, "module-a")); - addDependency(moduleA, "module-b-2", new File(parent, "module-b/module-b-comment.jar")); - mojos.compile(moduleA); - mojos.assertBuildOutputs(parent, new String[0]); - - // dependency changed structurally - moduleA = mojos.readMavenProject(new File(parent, "module-a")); - addDependency(moduleA, "module-b-2", new File(parent, "module-b/module-b-method.jar")); - mojos.compile(moduleA); - mojos.assertBuildOutputs(parent, "module-a/target/classes/reactor/modulea/ModuleA.class"); - } - - @Test - public void testRepository_classpathOrder() throws Exception { - File parent = resources.getBasedir("compile-jdt-classpath/repo-basic"); - - MavenProject moduleA = mojos.readMavenProject(new File(parent, "module-a")); - addDependency(moduleA, "module-b", new File(parent, "module-b/module-b.jar")); - addDependency(moduleA, "module-b-comment", new File(parent, "module-b/module-b-comment.jar")); - addDependency(moduleA, "module-b-method", new File(parent, "module-b/module-b-method.jar")); - mojos.compile(moduleA); - mojos.assertBuildOutputs(parent, "module-a/target/classes/reactor/modulea/ModuleA.class"); - - // classpath order change did not result in structural type definition change - moduleA = mojos.readMavenProject(new File(parent, "module-a")); - addDependency(moduleA, "module-b-comment", new File(parent, "module-b/module-b-comment.jar")); - addDependency(moduleA, "module-b", new File(parent, "module-b/module-b.jar")); - addDependency(moduleA, "module-b-method", new File(parent, "module-b/module-b-method.jar")); - mojos.compile(moduleA); - mojos.assertBuildOutputs(parent, new String[0]); - - // classpath order change DID result in structural type definition change - moduleA = mojos.readMavenProject(new File(parent, "module-a")); - addDependency(moduleA, "module-b-method", new File(parent, "module-b/module-b-method.jar")); - addDependency(moduleA, "module-b", new File(parent, "module-b/module-b.jar")); - addDependency(moduleA, "module-b-comment", new File(parent, "module-b/module-b-comment.jar")); - mojos.compile(moduleA); - mojos.assertBuildOutputs(parent, "module-a/target/classes/reactor/modulea/ModuleA.class"); - } - - private void compileReactor(File parent) throws Exception { - mojos.flushClasspathCaches(); - - File moduleB = new File(parent, "module-b"); - - mojos.compile(moduleB); - - MavenProject moduleA = mojos.readMavenProject(new File(parent, "module-a")); - addDependency(moduleA, "module-b", new File(moduleB, "target/classes")); - - mojos.compile(moduleA); - } } diff --git a/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/compile/jdt/CompileJdtClasspathVisibilityTest.java b/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/compile/jdt/CompileJdtClasspathVisibilityTest.java index 881fc912..71007e6c 100644 --- a/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/compile/jdt/CompileJdtClasspathVisibilityTest.java +++ b/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/compile/jdt/CompileJdtClasspathVisibilityTest.java @@ -1,10 +1,8 @@ package io.takari.maven.plugins.compile.jdt; import io.takari.maven.plugins.exportpackage.ExportPackageMojo; - import java.io.File; import java.io.FileOutputStream; - import org.apache.maven.execution.MavenSession; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.project.MavenProject; @@ -14,175 +12,203 @@ public class CompileJdtClasspathVisibilityTest extends AbstractCompileJdtTest { - private static final File DEPENDENCY = new File("src/test/projects/compile-jdt-classpath-visibility/test-dependency/test-dependency-0.1.jar"); - - @Test - public void testReference_directDependencyArtifact() throws Exception { - // sanity check, references to classes from direct dependencies are allowed - - File basedir = resources.getBasedir("compile-jdt-classpath-visibility/reference"); - - MavenProject project = mojos.readMavenProject(basedir); - addDependency(project, "dependency", DEPENDENCY); + private static final File DEPENDENCY = + new File("src/test/projects/compile-jdt-classpath-visibility/test-dependency/test-dependency-0.1.jar"); - compile(project, true); - } + @Test + public void testReference_directDependencyArtifact() throws Exception { + // sanity check, references to classes from direct dependencies are allowed - @Test - public void testReference_indirectDependencyArtifact() throws Exception { - // references to classes from indirect dependencies fail the build + File basedir = resources.getBasedir("compile-jdt-classpath-visibility/reference"); - File basedir = resources.getBasedir("compile-jdt-classpath-visibility/reference"); + MavenProject project = mojos.readMavenProject(basedir); + addDependency(project, "dependency", DEPENDENCY); - MavenProject project = mojos.readMavenProject(basedir); - addIndirectDependency(project, "dependency", DEPENDENCY); - - compile(project); - mojos.assertMessage(new File(basedir, "src/main/java/reference/Reference.java"), "The type 'DependencyClass' is not API", "test-dependency-0.1.jar"); - } - - @Test - public void testReference_accessRulesViolationIgnore() throws Exception { - File basedir = resources.getBasedir("compile-jdt-classpath-visibility/reference"); - - MavenProject project = mojos.readMavenProject(basedir); - addDependency(project, "dependency", DEPENDENCY); + compile(project, true); + } - MavenSession session = mojos.newMavenSession(project); + @Test + public void testReference_indirectDependencyArtifact() throws Exception { + // references to classes from indirect dependencies fail the build - mojos.executeMojo(session, project, "compile", // - param("compilerId", "jdt"), // - param("transitiveDependencyReference", "ignore"), // - param("privatePackageReference", "ignore")); - } + File basedir = resources.getBasedir("compile-jdt-classpath-visibility/reference"); - @Test - public void testReference_testCompile() throws Exception { - File basedir = resources.getBasedir("compile-jdt-classpath-visibility/reference"); + MavenProject project = mojos.readMavenProject(basedir); + addIndirectDependency(project, "dependency", DEPENDENCY); - MavenProject project = mojos.readMavenProject(basedir); - addDependency(project, "dependency", DEPENDENCY); + compile(project); + mojos.assertMessage( + new File(basedir, "src/main/java/reference/Reference.java"), + "The type 'DependencyClass' is not API", + "test-dependency-0.1.jar"); + } - MavenSession session = mojos.newMavenSession(project); + @Test + public void testReference_accessRulesViolationIgnore() throws Exception { + File basedir = resources.getBasedir("compile-jdt-classpath-visibility/reference"); - Xpp3Dom[] params = new Xpp3Dom[] {param("compilerId", "jdt"), // - param("transitiveDependencyReference", "error"), // - param("privatePackageReference", "error")}; + MavenProject project = mojos.readMavenProject(basedir); + addDependency(project, "dependency", DEPENDENCY); - mojos.executeMojo(session, project, "compile", params); + MavenSession session = mojos.newMavenSession(project); - mojos.executeMojo(session, project, "testCompile", params); - } + mojos.executeMojo( + session, + project, + "compile", // + param("compilerId", "jdt"), // + param("transitiveDependencyReference", "ignore"), // + param("privatePackageReference", "ignore")); + } - @Test - public void testReference_testCompile_internal() throws Exception { - File basedir = resources.getBasedir("compile-jdt-classpath-visibility/reference"); + @Test + public void testReference_testCompile() throws Exception { + File basedir = resources.getBasedir("compile-jdt-classpath-visibility/reference"); - MavenProject project = mojos.readMavenProject(basedir); - addDependency(project, "dependency", DEPENDENCY); + MavenProject project = mojos.readMavenProject(basedir); + addDependency(project, "dependency", DEPENDENCY); - MavenSession session = mojos.newMavenSession(project); + MavenSession session = mojos.newMavenSession(project); - Xpp3Dom[] params = new Xpp3Dom[] {param("compilerId", "jdt"), // - param("transitiveDependencyReference", "error"), // - param("privatePackageReference", "error")}; + Xpp3Dom[] params = new Xpp3Dom[] { + param("compilerId", "jdt"), // + param("transitiveDependencyReference", "error"), // + param("privatePackageReference", "error") + }; - mojos.executeMojo(session, project, "compile", params); + mojos.executeMojo(session, project, "compile", params); - // make all main classes internal - File exportsFile = new File(basedir, "target/classes/" + ExportPackageMojo.PATH_EXPORT_PACKAGE); - exportsFile.getParentFile().mkdirs(); - new FileOutputStream(exportsFile).close(); + mojos.executeMojo(session, project, "testCompile", params); + } - mojos.executeMojo(session, project, "testCompile", params); - } + @Test + public void testReference_testCompile_internal() throws Exception { + File basedir = resources.getBasedir("compile-jdt-classpath-visibility/reference"); + MavenProject project = mojos.readMavenProject(basedir); + addDependency(project, "dependency", DEPENDENCY); - @Test - public void testIndirectGrandparent() throws Exception { - // project -> ParentClass@direct-dependency -> DependencyClass@indirect-dependency + MavenSession session = mojos.newMavenSession(project); - File basedir = resources.getBasedir("compile-jdt-classpath-visibility/indirect-grandparent"); + Xpp3Dom[] params = new Xpp3Dom[] { + param("compilerId", "jdt"), // + param("transitiveDependencyReference", "error"), // + param("privatePackageReference", "error") + }; - MavenProject project = mojos.readMavenProject(basedir); - addDependency(project, "direct-dependency", new File(basedir, "test-parent/test-parent-0.1.jar")); - addIndirectDependency(project, "indirect-dependency", DEPENDENCY); + mojos.executeMojo(session, project, "compile", params); - compile(project, true); - } + // make all main classes internal + File exportsFile = new File(basedir, "target/classes/" + ExportPackageMojo.PATH_EXPORT_PACKAGE); + exportsFile.getParentFile().mkdirs(); + new FileOutputStream(exportsFile).close(); - @Test - public void testInternalReference() throws Exception { - // project references classes that are not exported by the dependency (takari export-package) + mojos.executeMojo(session, project, "testCompile", params); + } - File basedir = resources.getBasedir("compile-jdt-classpath-visibility/internal-reference"); + @Test + public void testIndirectGrandparent() throws Exception { + // project -> ParentClass@direct-dependency -> DependencyClass@indirect-dependency - MavenProject project = mojos.readMavenProject(basedir); - addDependency(project, "indirect-dependency", DEPENDENCY); + File basedir = resources.getBasedir("compile-jdt-classpath-visibility/indirect-grandparent"); - compile(project); - mojos.assertMessage(new File(basedir, "src/main/java/reference/Reference.java"), "The type 'DependencyInternalClass' is not API", "test-dependency-0.1.jar"); - } + MavenProject project = mojos.readMavenProject(basedir); + addDependency(project, "direct-dependency", new File(basedir, "test-parent/test-parent-0.1.jar")); + addIndirectDependency(project, "indirect-dependency", DEPENDENCY); - @Test - public void testInternalReference_testCompile() throws Exception { - // project references classes that are not exported by the dependency (takari export-package) + compile(project, true); + } - File basedir = resources.getBasedir("compile-jdt-classpath-visibility/internal-reference"); + @Test + public void testInternalReference() throws Exception { + // project references classes that are not exported by the dependency (takari export-package) - MavenProject project = mojos.readMavenProject(basedir); - addDependency(project, "indirect-dependency", DEPENDENCY); + File basedir = resources.getBasedir("compile-jdt-classpath-visibility/internal-reference"); - MavenSession session = mojos.newMavenSession(project); + MavenProject project = mojos.readMavenProject(basedir); + addDependency(project, "indirect-dependency", DEPENDENCY); - try { - mojos.executeMojo(session, project, "testCompile", // - param("compilerId", "jdt"), // - param("transitiveDependencyReference", "error"), // - param("privatePackageReference", "error")); - Assert.fail(); - } catch (MojoExecutionException expected) { - // expected + compile(project); + mojos.assertMessage( + new File(basedir, "src/main/java/reference/Reference.java"), + "The type 'DependencyInternalClass' is not API", + "test-dependency-0.1.jar"); } - mojos.assertMessage(new File(basedir, "src/test/java/reference/ReferenceTest.java"), "The type 'DependencyInternalClass' is not API", "test-dependency-0.1.jar"); - } - - @Test - public void testInternalReference_dependencyBundle() throws Exception { - // project references classes that are not exported by the dependency (bundle manifest) + @Test + public void testInternalReference_testCompile() throws Exception { + // project references classes that are not exported by the dependency (takari export-package) + + File basedir = resources.getBasedir("compile-jdt-classpath-visibility/internal-reference"); + + MavenProject project = mojos.readMavenProject(basedir); + addDependency(project, "indirect-dependency", DEPENDENCY); + + MavenSession session = mojos.newMavenSession(project); + + try { + mojos.executeMojo( + session, + project, + "testCompile", // + param("compilerId", "jdt"), // + param("transitiveDependencyReference", "error"), // + param("privatePackageReference", "error")); + Assert.fail(); + } catch (MojoExecutionException expected) { + // expected + } + + mojos.assertMessage( + new File(basedir, "src/test/java/reference/ReferenceTest.java"), + "The type 'DependencyInternalClass' is not API", + "test-dependency-0.1.jar"); + } - File basedir = resources.getBasedir("compile-jdt-classpath-visibility/internal-reference"); + @Test + public void testInternalReference_dependencyBundle() throws Exception { + // project references classes that are not exported by the dependency (bundle manifest) - MavenProject project = mojos.readMavenProject(basedir); - addDependency(project, "indirect-dependency", new File("src/test/projects/compile-jdt-classpath-visibility/test-dependency-bundle/test-dependency-bundle-0.1.jar")); + File basedir = resources.getBasedir("compile-jdt-classpath-visibility/internal-reference"); - compile(project); - mojos.assertMessage(new File(basedir, "src/main/java/reference/Reference.java"), "The type 'DependencyInternalClass' is not API", "test-dependency-bundle-0.1.jar"); - } + MavenProject project = mojos.readMavenProject(basedir); + addDependency( + project, + "indirect-dependency", + new File( + "src/test/projects/compile-jdt-classpath-visibility/test-dependency-bundle/test-dependency-bundle-0.1.jar")); - private void addIndirectDependency(MavenProject project, String string, File file) throws Exception { - addDependency(project, string, file, false); - } + compile(project); + mojos.assertMessage( + new File(basedir, "src/main/java/reference/Reference.java"), + "The type 'DependencyInternalClass' is not API", + "test-dependency-bundle-0.1.jar"); + } - private void compile(MavenProject project) throws Exception { - compile(project, false); - } + private void addIndirectDependency(MavenProject project, String string, File file) throws Exception { + addDependency(project, string, file, false); + } - private void compile(MavenProject project, boolean throwMojoExecutionException) throws Exception { - try { - mojos.compile(project, param("transitiveDependencyReference", "error"), param("privatePackageReference", "error")); - } catch (MojoExecutionException e) { - if (throwMojoExecutionException) { - throw e; - } + private void compile(MavenProject project) throws Exception { + compile(project, false); } - } - private static Xpp3Dom param(String name, String value) { - Xpp3Dom node = new Xpp3Dom(name); - node.setValue(value); - return node; - } + private void compile(MavenProject project, boolean throwMojoExecutionException) throws Exception { + try { + mojos.compile( + project, + param("transitiveDependencyReference", "error"), + param("privatePackageReference", "error")); + } catch (MojoExecutionException e) { + if (throwMojoExecutionException) { + throw e; + } + } + } + private static Xpp3Dom param(String name, String value) { + Xpp3Dom node = new Xpp3Dom(name); + node.setValue(value); + return node; + } } diff --git a/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/compile/jdt/CompileJdtTest.java b/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/compile/jdt/CompileJdtTest.java index cf574043..84a4998c 100644 --- a/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/compile/jdt/CompileJdtTest.java +++ b/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/compile/jdt/CompileJdtTest.java @@ -5,251 +5,299 @@ import static io.takari.maven.testing.TestResources.touch; import java.io.File; - import org.apache.maven.plugin.MojoExecutionException; import org.junit.Assert; import org.junit.Test; public class CompileJdtTest extends AbstractCompileJdtTest { - /** - * Asserts specified output exists and is not older than specified input - */ - protected static void assertBuildOutput(File basedir, String input, String output) { - File inputFile = new File(basedir, input); - File outputFile = new File(basedir, output); - Assert.assertTrue("output is older than input", outputFile.lastModified() >= inputFile.lastModified()); - } - - - @Test - public void testBasic() throws Exception { - File basedir = resources.getBasedir("compile-jdt/basic"); - - // initial build - mojos.compile(basedir); - mojos.assertBuildOutputs(basedir, "target/classes/basic/Basic1.class", "target/classes/basic/Basic2.class"); - assertBuildOutput(basedir, "src/main/java/basic/Basic1.java", "target/classes/basic/Basic1.class"); - assertBuildOutput(basedir, "src/main/java/basic/Basic2.java", "target/classes/basic/Basic2.class"); - - // no-change rebuild - mojos.compile(basedir); - mojos.assertBuildOutputs(basedir, new String[0]); - mojos.assertCarriedOverOutputs(basedir, "target/classes/basic/Basic1.class", "target/classes/basic/Basic2.class"); - - // one file changed - cp(basedir, "src/main/java/basic/Basic1.java-changed", "src/main/java/basic/Basic1.java"); - mojos.compile(basedir); - mojos.assertBuildOutputs(basedir, "target/classes/basic/Basic1.class"); - assertBuildOutput(basedir, "src/main/java/basic/Basic1.java", "target/classes/basic/Basic1.class"); - } - - @Test - public void testBasic_timestampChangeRebuild() throws Exception { - File basedir = resources.getBasedir("compile-jdt/basic"); - File classes = new File(basedir, "target/classes"); - - // initial build - mojos.compile(basedir); - mojos.assertBuildOutputs(classes, "basic/Basic1.class", "basic/Basic2.class"); - - // move back timestamp, round to 10s to accommodate filesystem timestamp rounding - long timestamp = System.currentTimeMillis() - 20000L; - timestamp = timestamp - (timestamp % 10000L); - new File(classes, "basic/Basic1.class").setLastModified(timestamp); - - touch(basedir, "src/main/java/basic/Basic1.java"); - mojos.compile(basedir); - mojos.assertBuildOutputs(classes, "basic/Basic1.class"); - // timestamp is the same if the file is the same - Assert.assertEquals(timestamp, new File(classes, "basic/Basic1.class").lastModified()); - } - - @Test - public void testSupertype() throws Exception { - File basedir = resources.getBasedir("compile-jdt/supertype"); - - // initial build - mojos.compile(basedir); - mojos.assertBuildOutputs(basedir, "target/classes/supertype/SubClass.class", "target/classes/supertype/SuperClass.class", "target/classes/supertype/SuperInterface.class"); - - // non-structural change - cp(basedir, "src/main/java/supertype/SuperClass.java-comment", "src/main/java/supertype/SuperClass.java"); - cp(basedir, "src/main/java/supertype/SuperInterface.java-comment", "src/main/java/supertype/SuperInterface.java"); - mojos.compile(basedir); - mojos.assertBuildOutputs(basedir, "target/classes/supertype/SuperClass.class", "target/classes/supertype/SuperInterface.class"); - - // superclass change - cp(basedir, "src/main/java/supertype/SuperClass.java-member", "src/main/java/supertype/SuperClass.java"); - mojos.compile(basedir); - mojos.assertBuildOutputs(basedir, "target/classes/supertype/SubClass.class", "target/classes/supertype/SuperClass.class"); - } - - @Test - public void testSupertype_superClassChangeDoesNotTriggerRebuildOfImplementedInterfaces() throws Exception { - File basedir = resources.getBasedir("compile-jdt/supertype"); - - // initial build - mojos.compile(basedir); - mojos.assertBuildOutputs(basedir, "target/classes/supertype/SubClass.class", "target/classes/supertype/SuperClass.class", "target/classes/supertype/SuperInterface.class"); - - // superclass insignificant change - cp(basedir, "src/main/java/supertype/SuperClass.java-methodBody", "src/main/java/supertype/SuperClass.java"); - mojos.compile(basedir); - mojos.assertBuildOutputs(basedir, "target/classes/supertype/SuperClass.class"); - - // superclass significant change - cp(basedir, "src/main/java/supertype/SuperClass.java-member", "src/main/java/supertype/SuperClass.java"); - mojos.compile(basedir); - mojos.assertBuildOutputs(basedir, "target/classes/supertype/SubClass.class", "target/classes/supertype/SuperClass.class"); - } - - @Test - public void testCircular() throws Exception { - File basedir = mojos.compile(resources.getBasedir("compile-jdt/circular")); - mojos.assertBuildOutputs(basedir, "target/classes/circular/ClassA.class", "target/classes/circular/ClassB.class"); - - cp(basedir, "src/main/java/circular/ClassA.java-changed", "src/main/java/circular/ClassA.java"); - mojos.compile(basedir); - mojos.assertBuildOutputs(basedir, "target/classes/circular/ClassA.class", "target/classes/circular/ClassB.class"); - } - - @Test - public void testReference() throws Exception { - File basedir = mojos.compile(resources.getBasedir("compile-jdt/reference")); - mojos.assertBuildOutputs(basedir, "target/classes/reference/Parameter.class", "target/classes/reference/Type.class"); - - // no change rebuild - mojos.compile(basedir); - mojos.assertBuildOutputs(basedir, new String[0]); - Assert.assertTrue(new File(basedir, "target/classes/reference/Parameter.class").canRead()); - Assert.assertTrue(new File(basedir, "target/classes/reference/Type.class").canRead()); - - // insignificant change - cp(basedir, "src/main/java/reference/Parameter.java-comment", "src/main/java/reference/Parameter.java"); - mojos.compile(basedir); - mojos.assertBuildOutputs(basedir, "target/classes/reference/Parameter.class"); - Assert.assertTrue(new File(basedir, "target/classes/reference/Type.class").canRead()); - - // significant change - cp(basedir, "src/main/java/reference/Parameter.java-method", "src/main/java/reference/Parameter.java"); - mojos.compile(basedir); - mojos.assertBuildOutputs(basedir, "target/classes/reference/Parameter.class", "target/classes/reference/Type.class"); - } - - @Test - public void testMissing() throws Exception { - final String[] messages = {"ERROR Error.java [6:12] Missing cannot be resolved to a type", "ERROR Error.java [8:20] Missing cannot be resolved to a type"}; - - File basedir = resources.getBasedir("compile-jdt/missing"); - try { - mojos.compile(basedir); - Assert.fail(); - } catch (MojoExecutionException expected) { - // expected + /** + * Asserts specified output exists and is not older than specified input + */ + protected static void assertBuildOutput(File basedir, String input, String output) { + File inputFile = new File(basedir, input); + File outputFile = new File(basedir, output); + Assert.assertTrue("output is older than input", outputFile.lastModified() >= inputFile.lastModified()); + } + + @Test + public void testBasic() throws Exception { + File basedir = resources.getBasedir("compile-jdt/basic"); + + // initial build + mojos.compile(basedir); + mojos.assertBuildOutputs(basedir, "target/classes/basic/Basic1.class", "target/classes/basic/Basic2.class"); + assertBuildOutput(basedir, "src/main/java/basic/Basic1.java", "target/classes/basic/Basic1.class"); + assertBuildOutput(basedir, "src/main/java/basic/Basic2.java", "target/classes/basic/Basic2.class"); + + // no-change rebuild + mojos.compile(basedir); + mojos.assertBuildOutputs(basedir, new String[0]); + mojos.assertCarriedOverOutputs( + basedir, "target/classes/basic/Basic1.class", "target/classes/basic/Basic2.class"); + + // one file changed + cp(basedir, "src/main/java/basic/Basic1.java-changed", "src/main/java/basic/Basic1.java"); + mojos.compile(basedir); + mojos.assertBuildOutputs(basedir, "target/classes/basic/Basic1.class"); + assertBuildOutput(basedir, "src/main/java/basic/Basic1.java", "target/classes/basic/Basic1.class"); + } + + @Test + public void testBasic_timestampChangeRebuild() throws Exception { + File basedir = resources.getBasedir("compile-jdt/basic"); + File classes = new File(basedir, "target/classes"); + + // initial build + mojos.compile(basedir); + mojos.assertBuildOutputs(classes, "basic/Basic1.class", "basic/Basic2.class"); + + // move back timestamp, round to 10s to accommodate filesystem timestamp rounding + long timestamp = System.currentTimeMillis() - 20000L; + timestamp = timestamp - (timestamp % 10000L); + new File(classes, "basic/Basic1.class").setLastModified(timestamp); + + touch(basedir, "src/main/java/basic/Basic1.java"); + mojos.compile(basedir); + mojos.assertBuildOutputs(classes, "basic/Basic1.class"); + // timestamp is the same if the file is the same + Assert.assertEquals(timestamp, new File(classes, "basic/Basic1.class").lastModified()); + } + + @Test + public void testSupertype() throws Exception { + File basedir = resources.getBasedir("compile-jdt/supertype"); + + // initial build + mojos.compile(basedir); + mojos.assertBuildOutputs( + basedir, + "target/classes/supertype/SubClass.class", + "target/classes/supertype/SuperClass.class", + "target/classes/supertype/SuperInterface.class"); + + // non-structural change + cp(basedir, "src/main/java/supertype/SuperClass.java-comment", "src/main/java/supertype/SuperClass.java"); + cp( + basedir, + "src/main/java/supertype/SuperInterface.java-comment", + "src/main/java/supertype/SuperInterface.java"); + mojos.compile(basedir); + mojos.assertBuildOutputs( + basedir, "target/classes/supertype/SuperClass.class", "target/classes/supertype/SuperInterface.class"); + + // superclass change + cp(basedir, "src/main/java/supertype/SuperClass.java-member", "src/main/java/supertype/SuperClass.java"); + mojos.compile(basedir); + mojos.assertBuildOutputs( + basedir, "target/classes/supertype/SubClass.class", "target/classes/supertype/SuperClass.class"); + } + + @Test + public void testSupertype_superClassChangeDoesNotTriggerRebuildOfImplementedInterfaces() throws Exception { + File basedir = resources.getBasedir("compile-jdt/supertype"); + + // initial build + mojos.compile(basedir); + mojos.assertBuildOutputs( + basedir, + "target/classes/supertype/SubClass.class", + "target/classes/supertype/SuperClass.class", + "target/classes/supertype/SuperInterface.class"); + + // superclass insignificant change + cp(basedir, "src/main/java/supertype/SuperClass.java-methodBody", "src/main/java/supertype/SuperClass.java"); + mojos.compile(basedir); + mojos.assertBuildOutputs(basedir, "target/classes/supertype/SuperClass.class"); + + // superclass significant change + cp(basedir, "src/main/java/supertype/SuperClass.java-member", "src/main/java/supertype/SuperClass.java"); + mojos.compile(basedir); + mojos.assertBuildOutputs( + basedir, "target/classes/supertype/SubClass.class", "target/classes/supertype/SuperClass.class"); } - mojos.assertBuildOutputs(basedir, "target/classes/missing/Other.class"); - Assert.assertFalse(new File(basedir, "target/classes/missing/Error.class").exists()); - mojos.assertMessages(basedir, "src/main/java/missing/Error.java", messages); + @Test + public void testCircular() throws Exception { + File basedir = mojos.compile(resources.getBasedir("compile-jdt/circular")); + mojos.assertBuildOutputs( + basedir, "target/classes/circular/ClassA.class", "target/classes/circular/ClassB.class"); - // no change rebuild - try { - mojos.compile(basedir); - Assert.fail(); - } catch (MojoExecutionException expected) { - // expected + cp(basedir, "src/main/java/circular/ClassA.java-changed", "src/main/java/circular/ClassA.java"); + mojos.compile(basedir); + mojos.assertBuildOutputs( + basedir, "target/classes/circular/ClassA.class", "target/classes/circular/ClassB.class"); } - mojos.assertBuildOutputs(basedir, new String[0]); - mojos.assertMessages(basedir, "src/main/java/missing/Error.java", messages); - - // fix the problem - cp(basedir, "src/main/java/missing/Missing.java-missing", "src/main/java/missing/Missing.java"); - mojos.compile(basedir); - mojos.assertBuildOutputs(basedir, "target/classes/missing/Error.class", "target/classes/missing/Missing.class"); - - // reintroduce the problem - rm(basedir, "src/main/java/missing/Missing.java"); - try { - mojos.compile(basedir); - Assert.fail(); - } catch (MojoExecutionException expected) { - // expected + + @Test + public void testReference() throws Exception { + File basedir = mojos.compile(resources.getBasedir("compile-jdt/reference")); + mojos.assertBuildOutputs( + basedir, "target/classes/reference/Parameter.class", "target/classes/reference/Type.class"); + + // no change rebuild + mojos.compile(basedir); + mojos.assertBuildOutputs(basedir, new String[0]); + Assert.assertTrue(new File(basedir, "target/classes/reference/Parameter.class").canRead()); + Assert.assertTrue(new File(basedir, "target/classes/reference/Type.class").canRead()); + + // insignificant change + cp(basedir, "src/main/java/reference/Parameter.java-comment", "src/main/java/reference/Parameter.java"); + mojos.compile(basedir); + mojos.assertBuildOutputs(basedir, "target/classes/reference/Parameter.class"); + Assert.assertTrue(new File(basedir, "target/classes/reference/Type.class").canRead()); + + // significant change + cp(basedir, "src/main/java/reference/Parameter.java-method", "src/main/java/reference/Parameter.java"); + mojos.compile(basedir); + mojos.assertBuildOutputs( + basedir, "target/classes/reference/Parameter.class", "target/classes/reference/Type.class"); } - mojos.assertDeletedOutputs(basedir, "target/classes/missing/Error.class", "target/classes/missing/Missing.class"); - } - - @Test - public void testMultifile() throws Exception { - File basedir = mojos.compile(resources.getBasedir("compile-jdt/multifile")); - mojos.assertBuildOutputs(basedir, "target/classes/multifile/ClassA.class", "target/classes/multifile/ClassB.class", "target/classes/multifile/ClassB$Nested.class"); - - touch(basedir, "src/main/java/multifile/ClassA.java"); - cp(basedir, "src/main/java/multifile/ClassB.java-changed", "src/main/java/multifile/ClassB.java"); - try { - mojos.compile(basedir); - Assert.fail(); - } catch (MojoExecutionException expected) { - // expected + + @Test + public void testMissing() throws Exception { + final String[] messages = { + "ERROR Error.java [6:12] Missing cannot be resolved to a type", + "ERROR Error.java [8:20] Missing cannot be resolved to a type" + }; + + File basedir = resources.getBasedir("compile-jdt/missing"); + try { + mojos.compile(basedir); + Assert.fail(); + } catch (MojoExecutionException expected) { + // expected + } + mojos.assertBuildOutputs(basedir, "target/classes/missing/Other.class"); + Assert.assertFalse(new File(basedir, "target/classes/missing/Error.class").exists()); + mojos.assertMessages(basedir, "src/main/java/missing/Error.java", messages); + + // no change rebuild + try { + mojos.compile(basedir); + Assert.fail(); + } catch (MojoExecutionException expected) { + // expected + } + mojos.assertBuildOutputs(basedir, new String[0]); + mojos.assertMessages(basedir, "src/main/java/missing/Error.java", messages); + + // fix the problem + cp(basedir, "src/main/java/missing/Missing.java-missing", "src/main/java/missing/Missing.java"); + mojos.compile(basedir); + mojos.assertBuildOutputs(basedir, "target/classes/missing/Error.class", "target/classes/missing/Missing.class"); + + // reintroduce the problem + rm(basedir, "src/main/java/missing/Missing.java"); + try { + mojos.compile(basedir); + Assert.fail(); + } catch (MojoExecutionException expected) { + // expected + } + mojos.assertDeletedOutputs( + basedir, "target/classes/missing/Error.class", "target/classes/missing/Missing.class"); } - // TODO assert expected error messages - mojos.assertBuildOutputs(basedir, "target/classes/multifile/ClassB.class"); - mojos.assertDeletedOutputs(basedir, "target/classes/multifile/ClassA.class", "target/classes/multifile/ClassB$Nested.class"); - } - - @Test - public void testSecondaryType() throws Exception { - File basedir = mojos.compile(resources.getBasedir("compile-jdt/secondary-type")); - File classes = new File(basedir, "target/classes"); - mojos.assertBuildOutputs(classes // - , "secondary/Primary.class" // - , "secondary/Secondary.class" // - , "secondary/SecondarySubclass.class" // - , "secondary/SecondarySubclassClient.class"); - - touch(basedir, "src/main/java/secondary/SecondarySubclassClient.java"); - mojos.compile(basedir); - mojos.assertBuildOutputs(classes // - , "secondary/SecondarySubclassClient.class"); - } - - @Test - public void testRemovedTypes() throws Exception { - File basedir = mojos.compile(resources.getBasedir("compile-jdt/removed-types")); - File classes = new File(basedir, "target/classes"); - mojos.assertBuildOutputs(classes // - , "removed/A.class" // - , "removed/B.class" // - , "removed/Dummy.class"); - - rm(basedir, "src/main/java/removed/A.java"); - rm(basedir, "src/main/java/removed/B.java"); - mojos.compile(basedir); - mojos.assertDeletedOutputs(classes // - , "removed/A.class" // - , "removed/B.class"); - } - - @Test - public void testRemoveSecondaryType() throws Exception { - File basedir = mojos.compile(resources.getBasedir("compile-jdt/remove-secondary-type")); - File classes = new File(basedir, "target/classes"); - mojos.assertBuildOutputs(classes // - , "secondary/A.class" // - , "secondary/B.class" // - , "secondary/ASecondary.class"); - - cp(basedir, "src/main/java/secondary/A.java-changed", "src/main/java/secondary/A.java"); - try { - mojos.compile(basedir); - Assert.fail(); - } catch (MojoExecutionException expected) { - // TODO assert error message + + @Test + public void testMultifile() throws Exception { + File basedir = mojos.compile(resources.getBasedir("compile-jdt/multifile")); + mojos.assertBuildOutputs( + basedir, + "target/classes/multifile/ClassA.class", + "target/classes/multifile/ClassB.class", + "target/classes/multifile/ClassB$Nested.class"); + + touch(basedir, "src/main/java/multifile/ClassA.java"); + cp(basedir, "src/main/java/multifile/ClassB.java-changed", "src/main/java/multifile/ClassB.java"); + try { + mojos.compile(basedir); + Assert.fail(); + } catch (MojoExecutionException expected) { + // expected + } + // TODO assert expected error messages + mojos.assertBuildOutputs(basedir, "target/classes/multifile/ClassB.class"); + mojos.assertDeletedOutputs( + basedir, "target/classes/multifile/ClassA.class", "target/classes/multifile/ClassB$Nested.class"); + } + + @Test + public void testSecondaryType() throws Exception { + File basedir = mojos.compile(resources.getBasedir("compile-jdt/secondary-type")); + File classes = new File(basedir, "target/classes"); + mojos.assertBuildOutputs( + classes // + , + "secondary/Primary.class" // + , + "secondary/Secondary.class" // + , + "secondary/SecondarySubclass.class" // + , + "secondary/SecondarySubclassClient.class"); + + touch(basedir, "src/main/java/secondary/SecondarySubclassClient.java"); + mojos.compile(basedir); + mojos.assertBuildOutputs( + classes // + , + "secondary/SecondarySubclassClient.class"); + } + + @Test + public void testRemovedTypes() throws Exception { + File basedir = mojos.compile(resources.getBasedir("compile-jdt/removed-types")); + File classes = new File(basedir, "target/classes"); + mojos.assertBuildOutputs( + classes // + , + "removed/A.class" // + , + "removed/B.class" // + , + "removed/Dummy.class"); + + rm(basedir, "src/main/java/removed/A.java"); + rm(basedir, "src/main/java/removed/B.java"); + mojos.compile(basedir); + mojos.assertDeletedOutputs( + classes // + , + "removed/A.class" // + , + "removed/B.class"); + } + + @Test + public void testRemoveSecondaryType() throws Exception { + File basedir = mojos.compile(resources.getBasedir("compile-jdt/remove-secondary-type")); + File classes = new File(basedir, "target/classes"); + mojos.assertBuildOutputs( + classes // + , + "secondary/A.class" // + , + "secondary/B.class" // + , + "secondary/ASecondary.class"); + + cp(basedir, "src/main/java/secondary/A.java-changed", "src/main/java/secondary/A.java"); + try { + mojos.compile(basedir); + Assert.fail(); + } catch (MojoExecutionException expected) { + // TODO assert error message + } + mojos.assertBuildOutputs( + classes // + , + "secondary/A.class"); + mojos.assertDeletedOutputs( + classes // + , + "secondary/B.class" // + , + "secondary/ASecondary.class"); } - mojos.assertBuildOutputs(classes // - , "secondary/A.class"); - mojos.assertDeletedOutputs(classes // - , "secondary/B.class" // - , "secondary/ASecondary.class"); - } } diff --git a/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/compile/jdt/EclipseFileManagerTest.java b/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/compile/jdt/EclipseFileManagerTest.java index 41b46960..3ff53c26 100644 --- a/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/compile/jdt/EclipseFileManagerTest.java +++ b/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/compile/jdt/EclipseFileManagerTest.java @@ -8,23 +8,21 @@ import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; - import javax.tools.StandardLocation; - import org.eclipse.jdt.internal.compiler.apt.util.EclipseFileManager; import org.junit.Test; public class EclipseFileManagerTest { - @Test - public void test514121_closeClassloaders() throws Exception { - EclipseFileManager fileManager = new EclipseFileManager(null, StandardCharsets.UTF_8); - List classpath = new ArrayList<>(); - classpath.add(new File("src/test/jars/commons-lang-2.0.jar")); - fileManager.setLocation(StandardLocation.ANNOTATION_PROCESSOR_PATH, classpath); - URLClassLoader loader = (URLClassLoader) fileManager.getClassLoader(StandardLocation.ANNOTATION_PROCESSOR_PATH); - assertNotNull(loader.findResource("META-INF/LICENSE.txt")); // sanity check - fileManager.close(); - assertNull(loader.findResource("META-INF/LICENSE.txt")); // assert the classloader is closed - } + @Test + public void test514121_closeClassloaders() throws Exception { + EclipseFileManager fileManager = new EclipseFileManager(null, StandardCharsets.UTF_8); + List classpath = new ArrayList<>(); + classpath.add(new File("src/test/jars/commons-lang-2.0.jar")); + fileManager.setLocation(StandardLocation.ANNOTATION_PROCESSOR_PATH, classpath); + URLClassLoader loader = (URLClassLoader) fileManager.getClassLoader(StandardLocation.ANNOTATION_PROCESSOR_PATH); + assertNotNull(loader.findResource("META-INF/LICENSE.txt")); // sanity check + fileManager.close(); + assertNull(loader.findResource("META-INF/LICENSE.txt")); // assert the classloader is closed + } } diff --git a/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/compile/jdt/FilerImplTest.java b/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/compile/jdt/FilerImplTest.java index d482a9ce..835fd20c 100644 --- a/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/compile/jdt/FilerImplTest.java +++ b/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/compile/jdt/FilerImplTest.java @@ -2,6 +2,14 @@ import static io.takari.maven.testing.TestResources.create; +import com.google.common.base.Charsets; +import com.google.common.io.CharStreams; +import io.takari.maven.plugins.compile.CompilerBuildContext; +import io.takari.maven.plugins.compile.jdt.classpath.Classpath; +import io.takari.maven.plugins.compile.jdt.classpath.ClasspathEntry; +import io.takari.maven.plugins.compile.jdt.classpath.ClasspathJar; +import io.takari.maven.plugins.compile.jdt.classpath.JavaInstallation; +import io.takari.maven.plugins.compile.jdt.classpath.MutableClasspathEntry; import java.io.File; import java.io.IOException; import java.io.InputStream; @@ -13,12 +21,10 @@ import java.util.List; import java.util.Locale; import java.util.Map; - import javax.annotation.processing.FilerException; import javax.lang.model.element.TypeElement; import javax.tools.FileObject; import javax.tools.StandardLocation; - import org.eclipse.jdt.internal.compiler.Compiler; import org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies; import org.eclipse.jdt.internal.compiler.ICompilerRequestor; @@ -32,167 +38,162 @@ import org.junit.Test; import org.junit.rules.TemporaryFolder; -import com.google.common.base.Charsets; -import com.google.common.io.CharStreams; - -import io.takari.maven.plugins.compile.CompilerBuildContext; -import io.takari.maven.plugins.compile.jdt.classpath.Classpath; -import io.takari.maven.plugins.compile.jdt.classpath.ClasspathEntry; -import io.takari.maven.plugins.compile.jdt.classpath.ClasspathJar; -import io.takari.maven.plugins.compile.jdt.classpath.JavaInstallation; -import io.takari.maven.plugins.compile.jdt.classpath.MutableClasspathEntry; - public class FilerImplTest { - @Rule - public TemporaryFolder temp = new TemporaryFolder(); + @Rule + public TemporaryFolder temp = new TemporaryFolder(); - @Test - public void testGetResource_unsupportedLocation() throws Exception { - EclipseFileManager fileManager = new EclipseFileManager(null, Charsets.UTF_8); + @Test + public void testGetResource_unsupportedLocation() throws Exception { + EclipseFileManager fileManager = new EclipseFileManager(null, Charsets.UTF_8); - FilerImpl filer = new FilerImpl(null /* context */, fileManager, null /* compiler */, null /* env */); + FilerImpl filer = new FilerImpl(null /* context */, fileManager, null /* compiler */, null /* env */); - try { - filer.getResource(StandardLocation.SOURCE_PATH, "", "test"); - Assert.fail(); - } catch (IllegalArgumentException expected) { - // TODO check exception message + try { + filer.getResource(StandardLocation.SOURCE_PATH, "", "test"); + Assert.fail(); + } catch (IllegalArgumentException expected) { + // TODO check exception message + } } - } - @Test - public void testGetResource_location_classpath() throws Exception { - EclipseFileManager fileManager = new EclipseFileManager(null, Charsets.UTF_8); + @Test + public void testGetResource_location_classpath() throws Exception { + EclipseFileManager fileManager = new EclipseFileManager(null, Charsets.UTF_8); - List classpath = new ArrayList<>(); - classpath.add(new File("src/test/projects/compile-jdt-proc/getresource-location-classpath/classes")); - classpath.add(new File("src/test/projects/compile-jdt-proc/getresource-location-classpath/dependency.zip")); - fileManager.setLocation(StandardLocation.CLASS_PATH, classpath); + List classpath = new ArrayList<>(); + classpath.add(new File("src/test/projects/compile-jdt-proc/getresource-location-classpath/classes")); + classpath.add(new File("src/test/projects/compile-jdt-proc/getresource-location-classpath/dependency.zip")); + fileManager.setLocation(StandardLocation.CLASS_PATH, classpath); - FilerImpl filer = new FilerImpl(null /* context */, fileManager, null /* compiler */, null /* env */); + FilerImpl filer = new FilerImpl(null /* context */, fileManager, null /* compiler */, null /* env */); - Assert.assertEquals("dir resource", toString(filer.getResource(StandardLocation.CLASS_PATH, "", "dirresource.txt"))); - // Assert.assertEquals("jar resource", toString(filer.getResource(StandardLocation.CLASS_PATH, "", "jarresource.txt"))); - Assert.assertEquals("pkg jar resource", toString(filer.getResource(StandardLocation.CLASS_PATH, "pkg", "jarresource.txt"))); - } - - private static String toString(FileObject file) throws IOException { - try (InputStream is = file.openInputStream()) { - return CharStreams.toString(new InputStreamReader(is, Charsets.UTF_8)); + Assert.assertEquals( + "dir resource", toString(filer.getResource(StandardLocation.CLASS_PATH, "", "dirresource.txt"))); + // Assert.assertEquals("jar resource", toString(filer.getResource(StandardLocation.CLASS_PATH, "", + // "jarresource.txt"))); + Assert.assertEquals( + "pkg jar resource", toString(filer.getResource(StandardLocation.CLASS_PATH, "pkg", "jarresource.txt"))); } - } - - @Test - public void testRecreateSourceFile() throws Exception { - EclipseFileManager fileManager = new EclipseFileManager(null, Charsets.UTF_8); - - File outputDir = temp.newFolder(); - fileManager.setLocation(StandardLocation.SOURCE_OUTPUT, Collections.singleton(outputDir)); - - FilerImpl filer = new FilerImpl(null /* context */, fileManager, null /* compiler */, null /* env */); - - filer.createSourceFile("test.Source"); - try { - filer.createSourceFile("test.Source"); - Assert.fail(); - } catch (FilerException expected) { - // From Filer javadoc: - // @throws FilerException if the same pathname has already been - // created, the same type has already been created, or the name is - // not valid for a type + + private static String toString(FileObject file) throws IOException { + try (InputStream is = file.openInputStream()) { + return CharStreams.toString(new InputStreamReader(is, Charsets.UTF_8)); + } } - } - @Test - public void testRecreateResource() throws Exception { - EclipseFileManager fileManager = new EclipseFileManager(null, Charsets.UTF_8); + @Test + public void testRecreateSourceFile() throws Exception { + EclipseFileManager fileManager = new EclipseFileManager(null, Charsets.UTF_8); - File outputDir = temp.newFolder(); - fileManager.setLocation(StandardLocation.SOURCE_OUTPUT, Collections.singleton(outputDir)); + File outputDir = temp.newFolder(); + fileManager.setLocation(StandardLocation.SOURCE_OUTPUT, Collections.singleton(outputDir)); - FilerImpl filer = new FilerImpl(null /* context */, fileManager, null /* compiler */, null /* env */); + FilerImpl filer = new FilerImpl(null /* context */, fileManager, null /* compiler */, null /* env */); - filer.createResource(StandardLocation.SOURCE_OUTPUT, "test", "resource.txt"); - try { - filer.createResource(StandardLocation.SOURCE_OUTPUT, "test", "resource.txt"); - Assert.fail(); - } catch (FilerException expected) { - // From Filer javadoc: - // @throws FilerException if the same pathname has already been - // created + filer.createSourceFile("test.Source"); + try { + filer.createSourceFile("test.Source"); + Assert.fail(); + } catch (FilerException expected) { + // From Filer javadoc: + // @throws FilerException if the same pathname has already been + // created, the same type has already been created, or the name is + // not valid for a type + } } - try { - create(outputDir, "test/resource.txt"); - filer.getResource(StandardLocation.SOURCE_OUTPUT, "test", "resource.txt"); - Assert.fail(); - } catch (FilerException expected) { - // From Filer javadoc: - // @throws FilerException if the same pathname has already been - // opened for writing - } - } + @Test + public void testRecreateResource() throws Exception { + EclipseFileManager fileManager = new EclipseFileManager(null, Charsets.UTF_8); - @Test - public void testBinaryOriginatingElements() throws Exception { - // the point of this test is to assert Filer#createSourceFile does not puke when originatingElements are not sources + File outputDir = temp.newFolder(); + fileManager.setLocation(StandardLocation.SOURCE_OUTPUT, Collections.singleton(outputDir)); - // originating source elements are used to cleanup generated outputs when corresponding sources change - // originating binary elements are not currently fully supported and are not tracked during incremental build + FilerImpl filer = new FilerImpl(null /* context */, fileManager, null /* compiler */, null /* env */); - Classpath namingEnvironment = createClasspath(); - IErrorHandlingPolicy errorHandlingPolicy = DefaultErrorHandlingPolicies.exitAfterAllProblems(); - IProblemFactory problemFactory = ProblemFactory.getProblemFactory(Locale.getDefault()); - CompilerOptions compilerOptions = new CompilerOptions(); - ICompilerRequestor requestor = null; - Compiler compiler = new Compiler(namingEnvironment, errorHandlingPolicy, compilerOptions, requestor, problemFactory); + filer.createResource(StandardLocation.SOURCE_OUTPUT, "test", "resource.txt"); + try { + filer.createResource(StandardLocation.SOURCE_OUTPUT, "test", "resource.txt"); + Assert.fail(); + } catch (FilerException expected) { + // From Filer javadoc: + // @throws FilerException if the same pathname has already been + // created + } - EclipseFileManager fileManager = new EclipseFileManager(null, Charsets.UTF_8); - File outputDir = temp.newFolder(); - fileManager.setLocation(StandardLocation.SOURCE_OUTPUT, Collections.singleton(outputDir)); + try { + create(outputDir, "test/resource.txt"); + filer.getResource(StandardLocation.SOURCE_OUTPUT, "test", "resource.txt"); + Assert.fail(); + } catch (FilerException expected) { + // From Filer javadoc: + // @throws FilerException if the same pathname has already been + // opened for writing + } + } - CompilerBuildContext context = null; - Map processorOptions = null; - CompilerJdt incrementalCompiler = null; - ProcessingEnvImpl env = new ProcessingEnvImpl(context, fileManager, processorOptions, compiler, incrementalCompiler); + @Test + public void testBinaryOriginatingElements() throws Exception { + // the point of this test is to assert Filer#createSourceFile does not puke when originatingElements are not + // sources - TypeElement typeElement = env.getElementUtils().getTypeElement("java.lang.Object"); + // originating source elements are used to cleanup generated outputs when corresponding sources change + // originating binary elements are not currently fully supported and are not tracked during incremental build - FilerImpl filer = new FilerImpl(null /* context */, fileManager, null /* compiler */, null /* env */); - filer.createSourceFile("test.Source", typeElement); - } + Classpath namingEnvironment = createClasspath(); + IErrorHandlingPolicy errorHandlingPolicy = DefaultErrorHandlingPolicies.exitAfterAllProblems(); + IProblemFactory problemFactory = ProblemFactory.getProblemFactory(Locale.getDefault()); + CompilerOptions compilerOptions = new CompilerOptions(); + ICompilerRequestor requestor = null; + Compiler compiler = + new Compiler(namingEnvironment, errorHandlingPolicy, compilerOptions, requestor, problemFactory); - @Test - public void testResourceDoesNotExist() throws Exception { - EclipseFileManager fileManager = new EclipseFileManager(null, Charsets.UTF_8); + EclipseFileManager fileManager = new EclipseFileManager(null, Charsets.UTF_8); + File outputDir = temp.newFolder(); + fileManager.setLocation(StandardLocation.SOURCE_OUTPUT, Collections.singleton(outputDir)); - File outputDir = temp.newFolder(); - fileManager.setLocation(StandardLocation.SOURCE_OUTPUT, Collections.singleton(outputDir)); + CompilerBuildContext context = null; + Map processorOptions = null; + CompilerJdt incrementalCompiler = null; + ProcessingEnvImpl env = + new ProcessingEnvImpl(context, fileManager, processorOptions, compiler, incrementalCompiler); - FilerImpl filer = new FilerImpl(null /* context */, fileManager, null /* compiler */, null /* env */); + TypeElement typeElement = env.getElementUtils().getTypeElement("java.lang.Object"); - try { - filer.getResource(StandardLocation.SOURCE_OUTPUT, "", "does-not-exist"); - Assert.fail(); - } catch (IOException expected) { - // from Filer javadoc: @throws IOException if the file cannot be opened + FilerImpl filer = new FilerImpl(null /* context */, fileManager, null /* compiler */, null /* env */); + filer.createSourceFile("test.Source", typeElement); } - } - private Classpath createClasspath() throws IOException { - final List entries = new ArrayList(); - final List mutableentries = new ArrayList(); - for (Path file : JavaInstallation.getDefault().getClasspath()) { - if (Files.isRegularFile(file)) { + @Test + public void testResourceDoesNotExist() throws Exception { + EclipseFileManager fileManager = new EclipseFileManager(null, Charsets.UTF_8); + + File outputDir = temp.newFolder(); + fileManager.setLocation(StandardLocation.SOURCE_OUTPUT, Collections.singleton(outputDir)); + + FilerImpl filer = new FilerImpl(null /* context */, fileManager, null /* compiler */, null /* env */); + try { - entries.add(ClasspathJar.create(file)); - } catch (IOException e) { - // ignore, not a valid zip/jar + filer.getResource(StandardLocation.SOURCE_OUTPUT, "", "does-not-exist"); + Assert.fail(); + } catch (IOException expected) { + // from Filer javadoc: @throws IOException if the file cannot be opened } - } } - return new Classpath(entries, mutableentries); - } + private Classpath createClasspath() throws IOException { + final List entries = new ArrayList(); + final List mutableentries = new ArrayList(); + for (Path file : JavaInstallation.getDefault().getClasspath()) { + if (Files.isRegularFile(file)) { + try { + entries.add(ClasspathJar.create(file)); + } catch (IOException e) { + // ignore, not a valid zip/jar + } + } + } + return new Classpath(entries, mutableentries); + } } diff --git a/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/compile/jdt/classpath/ClasspathTest.java b/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/compile/jdt/classpath/ClasspathTest.java index 8982a1cb..a5119e94 100644 --- a/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/compile/jdt/classpath/ClasspathTest.java +++ b/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/compile/jdt/classpath/ClasspathTest.java @@ -6,40 +6,39 @@ import java.nio.file.Path; import java.util.ArrayList; import java.util.List; - import org.eclipse.jdt.core.compiler.CharOperation; import org.junit.Assert; import org.junit.Test; public class ClasspathTest { - @Test - public void testEmptyJarPackage() throws Exception { - final List entries = new ArrayList(); - for (Path file : JavaInstallation.getDefault().getClasspath()) { - if (Files.isRegularFile(file)) { - try { - entries.add(ClasspathJar.create(file)); - } catch (IOException e) { - // ignore + @Test + public void testEmptyJarPackage() throws Exception { + final List entries = new ArrayList(); + for (Path file : JavaInstallation.getDefault().getClasspath()) { + if (Files.isRegularFile(file)) { + try { + entries.add(ClasspathJar.create(file)); + } catch (IOException e) { + // ignore + } + } else if (Files.isDirectory(file)) { + entries.add(ClasspathDirectory.create(file)); + } } - } else if (Files.isDirectory(file)) { - entries.add(ClasspathDirectory.create(file)); - } + Classpath classpath = new Classpath(entries, null); + Assert.assertTrue(classpath.isPackage(CharOperation.splitOn('.', "org".toCharArray()), "xml".toCharArray())); } - Classpath classpath = new Classpath(entries, null); - Assert.assertTrue(classpath.isPackage(CharOperation.splitOn('.', "org".toCharArray()), "xml".toCharArray())); - } - @Test - public void testCaseInsensitive() throws IOException { - // affects windows and osx, linux users should not apply - File sourceRoot = new File("target/test-classes").getCanonicalFile(); - ClasspathEntry cpe = ClasspathDirectory.create(sourceRoot.toPath()); - String pkg = getClass().getPackage().getName().replace('.', '/'); - String cls = getClass().getSimpleName(); - Assert.assertNotNull(cpe.findType(pkg, cls)); - Assert.assertNull(cpe.findType(pkg, cls.toLowerCase())); - Assert.assertNull(cpe.findType(pkg.toUpperCase(), cls)); - } + @Test + public void testCaseInsensitive() throws IOException { + // affects windows and osx, linux users should not apply + File sourceRoot = new File("target/test-classes").getCanonicalFile(); + ClasspathEntry cpe = ClasspathDirectory.create(sourceRoot.toPath()); + String pkg = getClass().getPackage().getName().replace('.', '/'); + String cls = getClass().getSimpleName(); + Assert.assertNotNull(cpe.findType(pkg, cls)); + Assert.assertNull(cpe.findType(pkg, cls.toLowerCase())); + Assert.assertNull(cpe.findType(pkg.toUpperCase(), cls)); + } } diff --git a/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/configurator/JarTest.java b/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/configurator/JarTest.java index 320556d4..0d1678b5 100644 --- a/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/configurator/JarTest.java +++ b/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/configurator/JarTest.java @@ -2,56 +2,54 @@ import io.takari.incrementalbuild.maven.testing.IncrementalBuildRule; import io.takari.maven.testing.TestResources; - import java.io.File; import java.util.Enumeration; import java.util.jar.JarEntry; import java.util.jar.JarFile; import java.util.jar.Manifest; - import org.junit.Assert; import org.junit.Rule; import org.junit.Test; public class JarTest { - @Rule - public final TestResources resources = new TestResources(); + @Rule + public final TestResources resources = new TestResources(); - @Rule - public final IncrementalBuildRule mojos = new IncrementalBuildRule(); + @Rule + public final IncrementalBuildRule mojos = new IncrementalBuildRule(); - @Test - public void testCustomManifest() throws Exception { - File basedir = resources.getBasedir("configurator/jar/project-with-manifest"); - new File(basedir, "target/classes").mkdirs(); // TODO this shouldn't be necessary - mojos.executeMojo(basedir, "jar"); - try (JarFile jar = new JarFile(new File(basedir, "target/test-1.0.jar"))) { - Manifest mf = jar.getManifest(); - Assert.assertEquals("custom-value", mf.getMainAttributes().getValue("Custom-Entry")); + @Test + public void testCustomManifest() throws Exception { + File basedir = resources.getBasedir("configurator/jar/project-with-manifest"); + new File(basedir, "target/classes").mkdirs(); // TODO this shouldn't be necessary + mojos.executeMojo(basedir, "jar"); + try (JarFile jar = new JarFile(new File(basedir, "target/test-1.0.jar"))) { + Manifest mf = jar.getManifest(); + Assert.assertEquals("custom-value", mf.getMainAttributes().getValue("Custom-Entry")); + } } - } - @Test - public void testDuplicateCustomManifest() throws Exception { - File basedir = resources.getBasedir("configurator/jar/project-with-manifest-under-target-classes"); - mojos.executeMojo(basedir, "jar"); - JarFile jar = new JarFile(new File(basedir, "target/test-1.0.jar")); - try { - // make sure there is only one manifest entry - int count = 0; - for (Enumeration entries = jar.entries(); entries.hasMoreElements();) { - JarEntry entry = entries.nextElement(); - if ("META-INF/MANIFEST.MF".equalsIgnoreCase(entry.getName())) { - count++; + @Test + public void testDuplicateCustomManifest() throws Exception { + File basedir = resources.getBasedir("configurator/jar/project-with-manifest-under-target-classes"); + mojos.executeMojo(basedir, "jar"); + JarFile jar = new JarFile(new File(basedir, "target/test-1.0.jar")); + try { + // make sure there is only one manifest entry + int count = 0; + for (Enumeration entries = jar.entries(); entries.hasMoreElements(); ) { + JarEntry entry = entries.nextElement(); + if ("META-INF/MANIFEST.MF".equalsIgnoreCase(entry.getName())) { + count++; + } + } + Assert.assertEquals(1, count); + // now check the manifest contents + Manifest mf = jar.getManifest(); + Assert.assertEquals("custom-value", mf.getMainAttributes().getValue("Custom-Entry")); + } finally { + jar.close(); } - } - Assert.assertEquals(1, count); - // now check the manifest contents - Manifest mf = jar.getManifest(); - Assert.assertEquals("custom-value", mf.getMainAttributes().getValue("Custom-Entry")); - } finally { - jar.close(); } - } } diff --git a/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/configurator/MojoConfigurationMergerTest.java b/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/configurator/MojoConfigurationMergerTest.java index 444d827a..828861e6 100644 --- a/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/configurator/MojoConfigurationMergerTest.java +++ b/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/configurator/MojoConfigurationMergerTest.java @@ -7,7 +7,6 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.util.Stack; - import org.apache.maven.plugin.descriptor.MojoDescriptor; import org.apache.maven.plugin.descriptor.PluginDescriptor; import org.apache.maven.plugin.descriptor.PluginDescriptorBuilder; @@ -18,132 +17,138 @@ public class MojoConfigurationMergerTest { - private static MojoConfigurationProcessor merger = new MojoConfigurationProcessor(); - private static PluginDescriptorBuilder pluginDescriptorBuilder = new PluginDescriptorBuilder(); - - - @Test - public void determineGoalFromMojoImplementation() throws Exception { - InputStream is = getClass().getResourceAsStream("/META-INF/maven/plugin.xml"); - assertNotNull(is); - PluginDescriptor pluginDescriptor = pluginDescriptorBuilder.build(new InputStreamReader(is, "UTF-8")); - String goal = merger.determineGoal("io.takari.maven.plugins.jar.Jar", pluginDescriptor); - assertEquals("We expect the goal name to be 'jar'", "jar", goal); - } - - @Test - public void extractionOfMojoSpecificConfigurationAndMergingwithDefaultMojoConfiguration() throws Exception { - InputStream is = getClass().getResourceAsStream("/META-INF/maven/plugin.xml"); - assertNotNull(is); - PluginDescriptor pluginDescriptor = pluginDescriptorBuilder.build(new InputStreamReader(is, "UTF-8")); - String goal = merger.determineGoal("io.takari.maven.plugins.jar.Jar", pluginDescriptor); - assertEquals("We expect the goal name to be 'jar'", "jar", goal); - MojoDescriptor mojoDescriptor = pluginDescriptor.getMojo(goal); - PlexusConfiguration defaultMojoConfiguration = mojoDescriptor.getMojoConfiguration(); - System.out.println(defaultMojoConfiguration); - - PlexusConfiguration configurationFromMaven = builder("configuration") // - .es("jar") // - .es("sourceJar").v("true").ee() // - .ee() // - .buildPlexusConfiguration(); - - PlexusConfiguration mojoConfiguration = merger.extractAndMerge(goal, configurationFromMaven, defaultMojoConfiguration); - - String xml = mojoConfiguration.toString(); - assertXpathEvaluatesTo("java.io.File", "/configuration/classesDirectory/@implementation", xml); - assertXpathEvaluatesTo("${project.build.outputDirectory}", "/configuration/classesDirectory/@default-value", xml); - assertXpathEvaluatesTo("java.util.List", "/configuration/reactorProjects/@implementation", xml); - assertXpathEvaluatesTo("${reactorProjects}", "/configuration/reactorProjects/@default-value", xml); - assertXpathEvaluatesTo("true", "/configuration/sourceJar", xml); - } - - - @Test - public void plexusConfigurationMerging() throws Exception { - - PlexusConfiguration mojoConfigurationFromPom = builder("configuration") // - .es("sourceJar").v("true").ee() // - .buildPlexusConfiguration(); - - PlexusConfiguration defaultMojoConfiguration = builder("configuration") // - .entry("classesDirectory", "java.io.File", "${project.build.outputDirectory}") // - .entry("reactorProjects", "java.util.List", "${reactorProjects}") // - .entry("souceJar", "boolean", "${sourceJar") // - .buildPlexusConfiguration(); - - PlexusConfiguration mojoConfiguration = merger.mergePlexusConfiguration(mojoConfigurationFromPom, defaultMojoConfiguration); - - String xml = mojoConfiguration.toString(); - assertXpathEvaluatesTo("java.io.File", "/configuration/classesDirectory/@implementation", xml); - assertXpathEvaluatesTo("${project.build.outputDirectory}", "/configuration/classesDirectory/@default-value", xml); - assertXpathEvaluatesTo("java.util.List", "/configuration/reactorProjects/@implementation", xml); - assertXpathEvaluatesTo("${reactorProjects}", "/configuration/reactorProjects/@default-value", xml); - assertXpathEvaluatesTo("true", "/configuration/sourceJar", xml); - } - - private Builder builder(String name) { - return new Builder(name); - } - - public class Builder { - private Stack stack; - private Xpp3Dom configuration; - - public Builder(String name) { - stack = new Stack(); - configuration = new Xpp3Dom(name); - } - - public Builder entry(String name, String implementation, String defaultValue) { - return es(name).i(implementation).dv(defaultValue).ee(); - } - - public Builder i(String implementation) { - a("implementation", implementation); - return this; - } - - public Builder dv(String value) { - a("default-value", value); - return this; - } - - public Builder es(String name) { - Xpp3Dom e = new Xpp3Dom(name); - configuration.addChild(e); - stack.push(configuration); - configuration = e; - return this; - } + private static MojoConfigurationProcessor merger = new MojoConfigurationProcessor(); + private static PluginDescriptorBuilder pluginDescriptorBuilder = new PluginDescriptorBuilder(); - public Builder ee() { - configuration = stack.pop(); - return this; + @Test + public void determineGoalFromMojoImplementation() throws Exception { + InputStream is = getClass().getResourceAsStream("/META-INF/maven/plugin.xml"); + assertNotNull(is); + PluginDescriptor pluginDescriptor = pluginDescriptorBuilder.build(new InputStreamReader(is, "UTF-8")); + String goal = merger.determineGoal("io.takari.maven.plugins.jar.Jar", pluginDescriptor); + assertEquals("We expect the goal name to be 'jar'", "jar", goal); } - public Builder v(String value) { - configuration.setValue(value); - return this; + @Test + public void extractionOfMojoSpecificConfigurationAndMergingwithDefaultMojoConfiguration() throws Exception { + InputStream is = getClass().getResourceAsStream("/META-INF/maven/plugin.xml"); + assertNotNull(is); + PluginDescriptor pluginDescriptor = pluginDescriptorBuilder.build(new InputStreamReader(is, "UTF-8")); + String goal = merger.determineGoal("io.takari.maven.plugins.jar.Jar", pluginDescriptor); + assertEquals("We expect the goal name to be 'jar'", "jar", goal); + MojoDescriptor mojoDescriptor = pluginDescriptor.getMojo(goal); + PlexusConfiguration defaultMojoConfiguration = mojoDescriptor.getMojoConfiguration(); + System.out.println(defaultMojoConfiguration); + + PlexusConfiguration configurationFromMaven = builder("configuration") // + .es("jar") // + .es("sourceJar") + .v("true") + .ee() // + .ee() // + .buildPlexusConfiguration(); + + PlexusConfiguration mojoConfiguration = + merger.extractAndMerge(goal, configurationFromMaven, defaultMojoConfiguration); + + String xml = mojoConfiguration.toString(); + assertXpathEvaluatesTo("java.io.File", "/configuration/classesDirectory/@implementation", xml); + assertXpathEvaluatesTo( + "${project.build.outputDirectory}", "/configuration/classesDirectory/@default-value", xml); + assertXpathEvaluatesTo("java.util.List", "/configuration/reactorProjects/@implementation", xml); + assertXpathEvaluatesTo("${reactorProjects}", "/configuration/reactorProjects/@default-value", xml); + assertXpathEvaluatesTo("true", "/configuration/sourceJar", xml); } - public Builder a(String name, String value) { - configuration.setAttribute(name, value); - return this; + @Test + public void plexusConfigurationMerging() throws Exception { + + PlexusConfiguration mojoConfigurationFromPom = builder("configuration") // + .es("sourceJar") + .v("true") + .ee() // + .buildPlexusConfiguration(); + + PlexusConfiguration defaultMojoConfiguration = builder("configuration") // + .entry("classesDirectory", "java.io.File", "${project.build.outputDirectory}") // + .entry("reactorProjects", "java.util.List", "${reactorProjects}") // + .entry("souceJar", "boolean", "${sourceJar") // + .buildPlexusConfiguration(); + + PlexusConfiguration mojoConfiguration = + merger.mergePlexusConfiguration(mojoConfigurationFromPom, defaultMojoConfiguration); + + String xml = mojoConfiguration.toString(); + assertXpathEvaluatesTo("java.io.File", "/configuration/classesDirectory/@implementation", xml); + assertXpathEvaluatesTo( + "${project.build.outputDirectory}", "/configuration/classesDirectory/@default-value", xml); + assertXpathEvaluatesTo("java.util.List", "/configuration/reactorProjects/@implementation", xml); + assertXpathEvaluatesTo("${reactorProjects}", "/configuration/reactorProjects/@default-value", xml); + assertXpathEvaluatesTo("true", "/configuration/sourceJar", xml); } - public Xpp3Dom buildXpp3Dom() { - if (!stack.empty()) { - throw new IllegalStateException("You have unclosed elements."); - } - return configuration; + private Builder builder(String name) { + return new Builder(name); } - public PlexusConfiguration buildPlexusConfiguration() { - if (!stack.empty()) { - throw new IllegalStateException("You have unclosed elements."); - } - return new XmlPlexusConfiguration(configuration); + public class Builder { + private Stack stack; + private Xpp3Dom configuration; + + public Builder(String name) { + stack = new Stack(); + configuration = new Xpp3Dom(name); + } + + public Builder entry(String name, String implementation, String defaultValue) { + return es(name).i(implementation).dv(defaultValue).ee(); + } + + public Builder i(String implementation) { + a("implementation", implementation); + return this; + } + + public Builder dv(String value) { + a("default-value", value); + return this; + } + + public Builder es(String name) { + Xpp3Dom e = new Xpp3Dom(name); + configuration.addChild(e); + stack.push(configuration); + configuration = e; + return this; + } + + public Builder ee() { + configuration = stack.pop(); + return this; + } + + public Builder v(String value) { + configuration.setValue(value); + return this; + } + + public Builder a(String name, String value) { + configuration.setAttribute(name, value); + return this; + } + + public Xpp3Dom buildXpp3Dom() { + if (!stack.empty()) { + throw new IllegalStateException("You have unclosed elements."); + } + return configuration; + } + + public PlexusConfiguration buildPlexusConfiguration() { + if (!stack.empty()) { + throw new IllegalStateException("You have unclosed elements."); + } + return new XmlPlexusConfiguration(configuration); + } } - } } diff --git a/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/exportpackage/ExportPackageMojoTest.java b/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/exportpackage/ExportPackageMojoTest.java index 0c57080b..9091ad71 100644 --- a/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/exportpackage/ExportPackageMojoTest.java +++ b/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/exportpackage/ExportPackageMojoTest.java @@ -4,122 +4,121 @@ import static io.takari.maven.testing.TestResources.rm; import static io.takari.maven.testing.TestResources.touch; +import com.google.common.base.Charsets; +import com.google.common.io.Files; +import io.takari.incrementalbuild.maven.testing.IncrementalBuildRule; +import io.takari.maven.testing.TestResources; import java.io.File; import java.io.IOException; import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.TreeSet; - import org.codehaus.plexus.util.Os; import org.junit.Assert; import org.junit.Assume; import org.junit.Rule; import org.junit.Test; -import com.google.common.base.Charsets; -import com.google.common.io.Files; +public class ExportPackageMojoTest { -import io.takari.incrementalbuild.maven.testing.IncrementalBuildRule; -import io.takari.maven.testing.TestResources; + @Rule + public final TestResources resources = new TestResources(); + + @Rule + public final IncrementalBuildRule mojos = new IncrementalBuildRule(); + + @Test + public void testBasic() throws Exception { + File basedir = resources.getBasedir("exportpackage/basic"); + + // initial build + mkfile(basedir, "target/classes/exported/Exported.class"); + mkfile(basedir, "target/classes/internal/Internal.class"); + mojos.executeMojo(basedir, "export-package"); + mojos.assertBuildOutputs(basedir, "target/classes/" + ExportPackageMojo.PATH_EXPORT_PACKAGE); + assertExportedPackages(basedir, "exported"); + + // no-change rebuild + mojos.executeMojo(basedir, "export-package"); + mojos.assertCarriedOverOutputs(basedir, "target/classes/" + ExportPackageMojo.PATH_EXPORT_PACKAGE); + assertExportedPackages(basedir, "exported"); + + // change public and private classes + touch(basedir, "target/classes/exported/Exported.class"); + touch(basedir, "target/classes/internal/Internal.class"); + mojos.executeMojo(basedir, "export-package"); + mojos.assertCarriedOverOutputs(basedir, "target/classes/" + ExportPackageMojo.PATH_EXPORT_PACKAGE); + assertExportedPackages(basedir, "exported"); + + // remove private class + rm(basedir, "target/classes/internal/Internal.class"); + mojos.executeMojo(basedir, "export-package"); + mojos.assertCarriedOverOutputs(basedir, "target/classes/" + ExportPackageMojo.PATH_EXPORT_PACKAGE); + assertExportedPackages(basedir, "exported"); + + // new public class + mkfile(basedir, "target/classes/exported/another/Exported.class"); + mojos.executeMojo(basedir, "export-package"); + mojos.assertBuildOutputs(basedir, "target/classes/" + ExportPackageMojo.PATH_EXPORT_PACKAGE); + assertExportedPackages(basedir, "exported", "exported.another"); + + // remove public class + rm(basedir, "target/classes/exported/another/Exported.class"); + mojos.executeMojo(basedir, "export-package"); + mojos.assertBuildOutputs(basedir, "target/classes/" + ExportPackageMojo.PATH_EXPORT_PACKAGE); + assertExportedPackages(basedir, "exported"); + + // remove last public class + rm(basedir, "target/classes/exported/Exported.class"); + mojos.executeMojo(basedir, "export-package"); + mojos.assertBuildOutputs(basedir, "target/classes/" + ExportPackageMojo.PATH_EXPORT_PACKAGE); + assertExportedPackages(basedir, new String[0]); + } -public class ExportPackageMojoTest { + @Test + public void testNoClassesDirectory() throws Exception { + File basedir = resources.getBasedir("exportpackage/basic"); + mojos.executeMojo(basedir, "export-package"); + mojos.assertBuildOutputs(basedir, "target/classes/" + ExportPackageMojo.PATH_EXPORT_PACKAGE); + assertExportedPackages(basedir, new String[0]); + } + + @Test + public void testBasic_symlinked() throws Exception { + Assume.assumeTrue(Os.isFamily(Os.FAMILY_UNIX)); + + File basedir = resources.getBasedir(); + + File orig = new File(basedir, "orig"); + create(orig, "target/classes/exported/Class.class"); + File symlink = java.nio.file.Files.createSymbolicLink(new File(basedir, "symlink").toPath(), orig.toPath()) + .toFile(); + + mojos.executeMojo(symlink, "export-package"); + assertExportedPackages(symlink, "exported"); + } + + private void assertExportedPackages(File basedir, String... exportedPackages) throws IOException { + List actual = Files.readLines( + new File(basedir, "target/classes/" + ExportPackageMojo.PATH_EXPORT_PACKAGE), Charsets.UTF_8); + Assert.assertEquals(toString(Arrays.asList(exportedPackages)), toString(actual)); + } + + private String toString(Collection strings) { + StringBuilder sb = new StringBuilder(); + for (String string : new TreeSet<>(strings)) { + if (sb.length() > 0) { + sb.append('\n'); + } + sb.append(string); + } + return sb.toString(); + } - @Rule - public final TestResources resources = new TestResources(); - - @Rule - public final IncrementalBuildRule mojos = new IncrementalBuildRule(); - - @Test - public void testBasic() throws Exception { - File basedir = resources.getBasedir("exportpackage/basic"); - - // initial build - mkfile(basedir, "target/classes/exported/Exported.class"); - mkfile(basedir, "target/classes/internal/Internal.class"); - mojos.executeMojo(basedir, "export-package"); - mojos.assertBuildOutputs(basedir, "target/classes/" + ExportPackageMojo.PATH_EXPORT_PACKAGE); - assertExportedPackages(basedir, "exported"); - - // no-change rebuild - mojos.executeMojo(basedir, "export-package"); - mojos.assertCarriedOverOutputs(basedir, "target/classes/" + ExportPackageMojo.PATH_EXPORT_PACKAGE); - assertExportedPackages(basedir, "exported"); - - // change public and private classes - touch(basedir, "target/classes/exported/Exported.class"); - touch(basedir, "target/classes/internal/Internal.class"); - mojos.executeMojo(basedir, "export-package"); - mojos.assertCarriedOverOutputs(basedir, "target/classes/" + ExportPackageMojo.PATH_EXPORT_PACKAGE); - assertExportedPackages(basedir, "exported"); - - // remove private class - rm(basedir, "target/classes/internal/Internal.class"); - mojos.executeMojo(basedir, "export-package"); - mojos.assertCarriedOverOutputs(basedir, "target/classes/" + ExportPackageMojo.PATH_EXPORT_PACKAGE); - assertExportedPackages(basedir, "exported"); - - // new public class - mkfile(basedir, "target/classes/exported/another/Exported.class"); - mojos.executeMojo(basedir, "export-package"); - mojos.assertBuildOutputs(basedir, "target/classes/" + ExportPackageMojo.PATH_EXPORT_PACKAGE); - assertExportedPackages(basedir, "exported", "exported.another"); - - // remove public class - rm(basedir, "target/classes/exported/another/Exported.class"); - mojos.executeMojo(basedir, "export-package"); - mojos.assertBuildOutputs(basedir, "target/classes/" + ExportPackageMojo.PATH_EXPORT_PACKAGE); - assertExportedPackages(basedir, "exported"); - - // remove last public class - rm(basedir, "target/classes/exported/Exported.class"); - mojos.executeMojo(basedir, "export-package"); - mojos.assertBuildOutputs(basedir, "target/classes/" + ExportPackageMojo.PATH_EXPORT_PACKAGE); - assertExportedPackages(basedir, new String[0]); - } - - @Test - public void testNoClassesDirectory() throws Exception { - File basedir = resources.getBasedir("exportpackage/basic"); - mojos.executeMojo(basedir, "export-package"); - mojos.assertBuildOutputs(basedir, "target/classes/" + ExportPackageMojo.PATH_EXPORT_PACKAGE); - assertExportedPackages(basedir, new String[0]); - } - - @Test - public void testBasic_symlinked() throws Exception { - Assume.assumeTrue(Os.isFamily(Os.FAMILY_UNIX)); - - File basedir = resources.getBasedir(); - - File orig = new File(basedir, "orig"); - create(orig, "target/classes/exported/Class.class"); - File symlink = java.nio.file.Files.createSymbolicLink(new File(basedir, "symlink").toPath(), orig.toPath()).toFile(); - - mojos.executeMojo(symlink, "export-package"); - assertExportedPackages(symlink, "exported"); - } - - private void assertExportedPackages(File basedir, String... exportedPackages) throws IOException { - List actual = Files.readLines(new File(basedir, "target/classes/" + ExportPackageMojo.PATH_EXPORT_PACKAGE), Charsets.UTF_8); - Assert.assertEquals(toString(Arrays.asList(exportedPackages)), toString(actual)); - } - - private String toString(Collection strings) { - StringBuilder sb = new StringBuilder(); - for (String string : new TreeSet<>(strings)) { - if (sb.length() > 0) { - sb.append('\n'); - } - sb.append(string); + private void mkfile(File basedir, String relpath) throws IOException { + File file = new File(basedir, relpath); + file.getParentFile().mkdirs(); + file.createNewFile(); } - return sb.toString(); - } - - private void mkfile(File basedir, String relpath) throws IOException { - File file = new File(basedir, relpath); - file.getParentFile().mkdirs(); - file.createNewFile(); - } } diff --git a/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/install_deploy/InstallDeployTest.java b/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/install_deploy/InstallDeployTest.java index 27ef842c..68afc36f 100644 --- a/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/install_deploy/InstallDeployTest.java +++ b/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/install_deploy/InstallDeployTest.java @@ -3,11 +3,12 @@ import static io.takari.maven.testing.TestMavenRuntime.newParameter; import static io.takari.maven.testing.TestResources.create; +import io.takari.incrementalbuild.maven.testing.IncrementalBuildRule; +import io.takari.maven.testing.TestResources; import java.io.File; import java.util.ArrayList; import java.util.List; import java.util.Properties; - import org.apache.maven.execution.DefaultMavenExecutionRequest; import org.apache.maven.execution.DefaultMavenExecutionResult; import org.apache.maven.execution.MavenExecutionRequest; @@ -24,150 +25,159 @@ import org.junit.Rule; import org.junit.Test; -import io.takari.incrementalbuild.maven.testing.IncrementalBuildRule; -import io.takari.maven.testing.TestResources; - public class InstallDeployTest { - @Rule - public final TestResources resources = new TestResources(); - - @Rule - public final IncrementalBuildRule mojos = new IncrementalBuildRule(); - - @Test - public void testBasic_release() throws Exception { - File basedir = resources.getBasedir("install-deploy/basic"); - create(basedir, "target/classes/resource.txt", "target/test-classes/resource.txt"); - - File localrepo = new File(basedir, "target/localrepo"); - Assert.assertTrue(localrepo.mkdirs()); - - File remoterepo = new File(basedir, "target/remoterepo"); - Assert.assertTrue(remoterepo.mkdirs()); - - Properties properties = new Properties(); - properties.put("version", "1.0"); - properties.put("repopath", remoterepo.getCanonicalPath()); - MavenProject project = readMavenProject(basedir, properties); - - MavenSession session = newSession(project, localrepo, null); - - mojos.executeMojo(session, project, "jar", newParameter("sourceJar", "true"), newParameter("testJar", "true")); - Assert.assertEquals(2, project.getAttachedArtifacts().size()); - - - mojos.executeMojo(session, project, "install"); - Assert.assertTrue(new File(localrepo, "io/takari/lifecycle/its/test/1.0/test-1.0.jar").canRead()); - Assert.assertTrue(new File(localrepo, "io/takari/lifecycle/its/test/1.0/test-1.0.pom").canRead()); - Assert.assertTrue(new File(localrepo, "io/takari/lifecycle/its/test/1.0/test-1.0-sources.jar").canRead()); - Assert.assertTrue(new File(localrepo, "io/takari/lifecycle/its/test/1.0/test-1.0-tests.jar").canRead()); - - mojos.executeMojo(session, project, "deploy"); - Assert.assertTrue(new File(remoterepo, "io/takari/lifecycle/its/test/1.0/test-1.0.jar").canRead()); - Assert.assertTrue(new File(remoterepo, "io/takari/lifecycle/its/test/1.0/test-1.0.pom").canRead()); - Assert.assertTrue(new File(remoterepo, "io/takari/lifecycle/its/test/1.0/test-1.0-sources.jar").canRead()); - Assert.assertTrue(new File(remoterepo, "io/takari/lifecycle/its/test/1.0/test-1.0-tests.jar").canRead()); - } - - private MavenSession newSession(MavenProject project, File localrepo, Properties properties) throws Exception { - MavenExecutionRequest request = new DefaultMavenExecutionRequest(); - MavenExecutionResult result = new DefaultMavenExecutionResult(); - DefaultRepositorySystemSession repoSession = MavenRepositorySystemUtils.newSession(); - LocalRepository localRepo = new LocalRepository(localrepo); - repoSession.setLocalRepositoryManager(mojos.getContainer().lookup(LocalRepositoryManagerFactory.class, "simple").newInstance(repoSession, localRepo)); - MavenSession session = new MavenSession(mojos.getContainer(), repoSession, request, result); - List projects = new ArrayList<>(); - projects.add(project); - for (String module : project.getModules()) { - MavenProject moduleProject = readMavenProject(new File(project.getBasedir(), module), properties); - moduleProject.setParent(project); - projects.add(moduleProject); - } + @Rule + public final TestResources resources = new TestResources(); - session.setProjects(projects); - return session; - } + @Rule + public final IncrementalBuildRule mojos = new IncrementalBuildRule(); - private MavenProject readMavenProject(File basedir, Properties properties) throws Exception { - File pom = new File(basedir, "pom.xml"); - MavenExecutionRequest request = new DefaultMavenExecutionRequest(); - request.setUserProperties(properties); - request.setBaseDirectory(basedir); - ProjectBuildingRequest configuration = request.getProjectBuildingRequest(); - configuration.setRepositorySession(new DefaultRepositorySystemSession()); - MavenProject project = mojos.lookup(ProjectBuilder.class).build(pom, configuration).getProject(); - Assert.assertNotNull(project); - return project; - } + @Test + public void testBasic_release() throws Exception { + File basedir = resources.getBasedir("install-deploy/basic"); + create(basedir, "target/classes/resource.txt", "target/test-classes/resource.txt"); - @Test - public void testAltDeployRepository() throws Exception { - File basedir = resources.getBasedir("install-deploy/basic"); - create(basedir, "target/classes/resource.txt", "target/test-classes/resource.txt"); + File localrepo = new File(basedir, "target/localrepo"); + Assert.assertTrue(localrepo.mkdirs()); - File localrepo = new File(basedir, "target/localrepo"); - Assert.assertTrue(localrepo.mkdirs()); + File remoterepo = new File(basedir, "target/remoterepo"); + Assert.assertTrue(remoterepo.mkdirs()); - File remoterepo = new File(basedir, "target/remoterepo"); - Assert.assertTrue(remoterepo.mkdirs()); + Properties properties = new Properties(); + properties.put("version", "1.0"); + properties.put("repopath", remoterepo.getCanonicalPath()); + MavenProject project = readMavenProject(basedir, properties); - Properties properties = new Properties(); - properties.put("version", "1.0"); - properties.put("repopath", remoterepo.getCanonicalPath()); - MavenProject project = readMavenProject(basedir, properties); + MavenSession session = newSession(project, localrepo, null); - MavenSession session = newSession(project, localrepo, null); + mojos.executeMojo(session, project, "jar", newParameter("sourceJar", "true"), newParameter("testJar", "true")); + Assert.assertEquals(2, project.getAttachedArtifacts().size()); - mojos.executeMojo(session, project, "jar", newParameter("sourceJar", "true"), newParameter("testJar", "true")); - Assert.assertEquals(2, project.getAttachedArtifacts().size()); + mojos.executeMojo(session, project, "install"); + Assert.assertTrue(new File(localrepo, "io/takari/lifecycle/its/test/1.0/test-1.0.jar").canRead()); + Assert.assertTrue(new File(localrepo, "io/takari/lifecycle/its/test/1.0/test-1.0.pom").canRead()); + Assert.assertTrue(new File(localrepo, "io/takari/lifecycle/its/test/1.0/test-1.0-sources.jar").canRead()); + Assert.assertTrue(new File(localrepo, "io/takari/lifecycle/its/test/1.0/test-1.0-tests.jar").canRead()); - File altDeploymentRepository = new File(basedir, "target/altremoterepo"); + mojos.executeMojo(session, project, "deploy"); + Assert.assertTrue(new File(remoterepo, "io/takari/lifecycle/its/test/1.0/test-1.0.jar").canRead()); + Assert.assertTrue(new File(remoterepo, "io/takari/lifecycle/its/test/1.0/test-1.0.pom").canRead()); + Assert.assertTrue(new File(remoterepo, "io/takari/lifecycle/its/test/1.0/test-1.0-sources.jar").canRead()); + Assert.assertTrue(new File(remoterepo, "io/takari/lifecycle/its/test/1.0/test-1.0-tests.jar").canRead()); + } - mojos.executeMojo(session, project, "deploy", newParameter("altDeploymentRepository", "default::default::file://" + altDeploymentRepository.getAbsolutePath())); - Assert.assertTrue(new File(altDeploymentRepository, "io/takari/lifecycle/its/test/1.0/test-1.0.jar").canRead()); - Assert.assertTrue(new File(altDeploymentRepository, "io/takari/lifecycle/its/test/1.0/test-1.0.pom").canRead()); - Assert.assertTrue(new File(altDeploymentRepository, "io/takari/lifecycle/its/test/1.0/test-1.0-sources.jar").canRead()); - Assert.assertTrue(new File(altDeploymentRepository, "io/takari/lifecycle/its/test/1.0/test-1.0-tests.jar").canRead()); + private MavenSession newSession(MavenProject project, File localrepo, Properties properties) throws Exception { + MavenExecutionRequest request = new DefaultMavenExecutionRequest(); + MavenExecutionResult result = new DefaultMavenExecutionResult(); + DefaultRepositorySystemSession repoSession = MavenRepositorySystemUtils.newSession(); + LocalRepository localRepo = new LocalRepository(localrepo); + repoSession.setLocalRepositoryManager(mojos.getContainer() + .lookup(LocalRepositoryManagerFactory.class, "simple") + .newInstance(repoSession, localRepo)); + MavenSession session = new MavenSession(mojos.getContainer(), repoSession, request, result); + List projects = new ArrayList<>(); + projects.add(project); + for (String module : project.getModules()) { + MavenProject moduleProject = readMavenProject(new File(project.getBasedir(), module), properties); + moduleProject.setParent(project); + projects.add(moduleProject); + } + + session.setProjects(projects); + return session; + } - } + private MavenProject readMavenProject(File basedir, Properties properties) throws Exception { + File pom = new File(basedir, "pom.xml"); + MavenExecutionRequest request = new DefaultMavenExecutionRequest(); + request.setUserProperties(properties); + request.setBaseDirectory(basedir); + ProjectBuildingRequest configuration = request.getProjectBuildingRequest(); + configuration.setRepositorySession(new DefaultRepositorySystemSession()); + MavenProject project = + mojos.lookup(ProjectBuilder.class).build(pom, configuration).getProject(); + Assert.assertNotNull(project); + return project; + } - @Test - public void testDeployAtEnd() throws Exception { - File basedir = resources.getBasedir("install-deploy/deploy-at-end"); + @Test + public void testAltDeployRepository() throws Exception { + File basedir = resources.getBasedir("install-deploy/basic"); + create(basedir, "target/classes/resource.txt", "target/test-classes/resource.txt"); + + File localrepo = new File(basedir, "target/localrepo"); + Assert.assertTrue(localrepo.mkdirs()); + + File remoterepo = new File(basedir, "target/remoterepo"); + Assert.assertTrue(remoterepo.mkdirs()); + + Properties properties = new Properties(); + properties.put("version", "1.0"); + properties.put("repopath", remoterepo.getCanonicalPath()); + MavenProject project = readMavenProject(basedir, properties); + + MavenSession session = newSession(project, localrepo, null); + + mojos.executeMojo(session, project, "jar", newParameter("sourceJar", "true"), newParameter("testJar", "true")); + Assert.assertEquals(2, project.getAttachedArtifacts().size()); + + File altDeploymentRepository = new File(basedir, "target/altremoterepo"); + + mojos.executeMojo( + session, + project, + "deploy", + newParameter( + "altDeploymentRepository", + "default::default::file://" + altDeploymentRepository.getAbsolutePath())); + Assert.assertTrue(new File(altDeploymentRepository, "io/takari/lifecycle/its/test/1.0/test-1.0.jar").canRead()); + Assert.assertTrue(new File(altDeploymentRepository, "io/takari/lifecycle/its/test/1.0/test-1.0.pom").canRead()); + Assert.assertTrue( + new File(altDeploymentRepository, "io/takari/lifecycle/its/test/1.0/test-1.0-sources.jar").canRead()); + Assert.assertTrue( + new File(altDeploymentRepository, "io/takari/lifecycle/its/test/1.0/test-1.0-tests.jar").canRead()); + } - File localrepo = new File(basedir, "target/localrepo"); - Assert.assertTrue(localrepo.mkdirs()); + @Test + public void testDeployAtEnd() throws Exception { + File basedir = resources.getBasedir("install-deploy/deploy-at-end"); - File remoterepo = new File(basedir, "target/remoterepo"); - Assert.assertTrue(remoterepo.mkdirs()); + File localrepo = new File(basedir, "target/localrepo"); + Assert.assertTrue(localrepo.mkdirs()); - Properties properties = new Properties(); - properties.put("version", "1.0"); - properties.put("repopath", remoterepo.getCanonicalPath()); - MavenProject project = readMavenProject(basedir, properties); + File remoterepo = new File(basedir, "target/remoterepo"); + Assert.assertTrue(remoterepo.mkdirs()); - MavenSession session = newSession(project, localrepo, properties); + Properties properties = new Properties(); + properties.put("version", "1.0"); + properties.put("repopath", remoterepo.getCanonicalPath()); + MavenProject project = readMavenProject(basedir, properties); - DeployParticipant deployParticipant = mojos.getContainer().lookup(DeployParticipant.class); + MavenSession session = newSession(project, localrepo, properties); - Assert.assertEquals(0, deployParticipant.getDeployAtEndRequests().size()); + DeployParticipant deployParticipant = mojos.getContainer().lookup(DeployParticipant.class); - for (MavenProject reactorProject : session.getProjects()) { - session.setCurrentProject(reactorProject); - if (!reactorProject.getPackaging().equals("pom")) { - mojos.executeMojo(session, reactorProject, "compile"); - mojos.executeMojo(session, reactorProject, "jar"); - } - mojos.executeMojo(session, reactorProject, "deploy"); - } + Assert.assertEquals(0, deployParticipant.getDeployAtEndRequests().size()); - Assert.assertFalse(new File(remoterepo, "io/takari/lifecycle/its/test/1.0/test-1.0.pom").canRead()); - Assert.assertFalse(new File(remoterepo, "io/takari/lifecycle/its/test-modulea/1.0/test-modulea-1.0.jar").canRead()); - Assert.assertFalse(new File(remoterepo, "io/takari/lifecycle/its/test-modulea/1.0/test-modulea-1.0.pom").canRead()); - Assert.assertFalse(new File(remoterepo, "io/takari/lifecycle/its/test-moduleb/1.0/test-moduleb-1.0.jar").canRead()); - Assert.assertFalse(new File(remoterepo, "io/takari/lifecycle/its/test-moduleb/1.0/test-moduleb-1.0.pom").canRead()); + for (MavenProject reactorProject : session.getProjects()) { + session.setCurrentProject(reactorProject); + if (!reactorProject.getPackaging().equals("pom")) { + mojos.executeMojo(session, reactorProject, "compile"); + mojos.executeMojo(session, reactorProject, "jar"); + } + mojos.executeMojo(session, reactorProject, "deploy"); + } - Assert.assertEquals(3, deployParticipant.getDeployAtEndRequests().size()); - } + Assert.assertFalse(new File(remoterepo, "io/takari/lifecycle/its/test/1.0/test-1.0.pom").canRead()); + Assert.assertFalse( + new File(remoterepo, "io/takari/lifecycle/its/test-modulea/1.0/test-modulea-1.0.jar").canRead()); + Assert.assertFalse( + new File(remoterepo, "io/takari/lifecycle/its/test-modulea/1.0/test-modulea-1.0.pom").canRead()); + Assert.assertFalse( + new File(remoterepo, "io/takari/lifecycle/its/test-moduleb/1.0/test-moduleb-1.0.jar").canRead()); + Assert.assertFalse( + new File(remoterepo, "io/takari/lifecycle/its/test-moduleb/1.0/test-moduleb-1.0.pom").canRead()); + Assert.assertEquals(3, deployParticipant.getDeployAtEndRequests().size()); + } } diff --git a/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/jar/JarTest.java b/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/jar/JarTest.java index 0429a831..072e2766 100644 --- a/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/jar/JarTest.java +++ b/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/jar/JarTest.java @@ -10,6 +10,10 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import com.google.common.io.Files; +import io.takari.hash.Sha1Fingerprint; +import io.takari.incrementalbuild.maven.testing.IncrementalBuildRule; +import io.takari.maven.testing.TestResources; import java.io.File; import java.io.IOException; import java.io.InputStream; @@ -29,7 +33,6 @@ import java.util.jar.Manifest; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; - import org.apache.maven.artifact.Artifact; import org.apache.maven.project.MavenProject; import org.codehaus.plexus.util.Os; @@ -39,295 +42,327 @@ import org.junit.Rule; import org.junit.Test; -import com.google.common.io.Files; - -import io.takari.hash.Sha1Fingerprint; -import io.takari.incrementalbuild.maven.testing.IncrementalBuildRule; -import io.takari.maven.testing.TestResources; - public class JarTest { - @Rule - public final TestResources resources = new TestResources(); - - @Rule - public final IncrementalBuildRule mojos = new IncrementalBuildRule(); - - @Test - public void jarCreation() throws Exception { - // - // Generate some resources to JAR - // - File basedir = resources.getBasedir("jar/project-with-resources"); - mojos.executeMojo(basedir, "process-resources"); - File resource = new File(basedir, "target/classes/resource.txt"); - assertTrue(resource.exists()); - String line = Files.readFirstLine(resource, Charset.defaultCharset()); - assertTrue(line.contains("resource.txt")); - // - // Generate the JAR a first time and capture the fingerprint - // - mojos.executeMojo(basedir, "jar"); - File jar0 = new File(basedir, "target/test-1.0.jar"); - assertTrue(jar0.exists()); - String fingerprint0 = new Sha1Fingerprint().fingerprint(jar0); - // - // Generate the JAR a second time and ensure that the fingerprint is still the same when - // the JAR content is the same. The outer SHA1 of a JAR built at two points in time will - // be different even though the content has not changed. - // - mojos.executeMojo(basedir, "jar"); - File jar1 = new File(basedir, "target/test-1.0.jar"); - Assert.assertTrue(jar1.exists()); - String fingerprint1 = new Sha1Fingerprint().fingerprint(jar1); - assertEquals("We expect the JAR to have the same fingerprint after repeated builds.", fingerprint0, fingerprint1); - - // Make sure our maven properties file is written correctly - try (ZipFile zip0 = new ZipFile(jar1)) { - String pomProperties = "META-INF/maven/io.takari.lifecycle.its/test/pom.properties"; - ZipEntry entry = zip0.getEntry(pomProperties); - if (entry != null) { - InputStream is = zip0.getInputStream(entry); - Properties p = new Properties(); - p.load(is); - assertEquals("io.takari.lifecycle.its", p.getProperty("groupId")); - assertEquals("test", p.getProperty("artifactId")); - assertEquals("1.0", p.getProperty("version")); - } else { - fail("We expected the standard pom.properties: " + pomProperties); - } - } + @Rule + public final TestResources resources = new TestResources(); + + @Rule + public final IncrementalBuildRule mojos = new IncrementalBuildRule(); + + @Test + public void jarCreation() throws Exception { + // + // Generate some resources to JAR + // + File basedir = resources.getBasedir("jar/project-with-resources"); + mojos.executeMojo(basedir, "process-resources"); + File resource = new File(basedir, "target/classes/resource.txt"); + assertTrue(resource.exists()); + String line = Files.readFirstLine(resource, Charset.defaultCharset()); + assertTrue(line.contains("resource.txt")); + // + // Generate the JAR a first time and capture the fingerprint + // + mojos.executeMojo(basedir, "jar"); + File jar0 = new File(basedir, "target/test-1.0.jar"); + assertTrue(jar0.exists()); + String fingerprint0 = new Sha1Fingerprint().fingerprint(jar0); + // + // Generate the JAR a second time and ensure that the fingerprint is still the same when + // the JAR content is the same. The outer SHA1 of a JAR built at two points in time will + // be different even though the content has not changed. + // + mojos.executeMojo(basedir, "jar"); + File jar1 = new File(basedir, "target/test-1.0.jar"); + Assert.assertTrue(jar1.exists()); + String fingerprint1 = new Sha1Fingerprint().fingerprint(jar1); + assertEquals( + "We expect the JAR to have the same fingerprint after repeated builds.", fingerprint0, fingerprint1); + + // Make sure our maven properties file is written correctly + try (ZipFile zip0 = new ZipFile(jar1)) { + String pomProperties = "META-INF/maven/io.takari.lifecycle.its/test/pom.properties"; + ZipEntry entry = zip0.getEntry(pomProperties); + if (entry != null) { + InputStream is = zip0.getInputStream(entry); + Properties p = new Properties(); + p.load(is); + assertEquals("io.takari.lifecycle.its", p.getProperty("groupId")); + assertEquals("test", p.getProperty("artifactId")); + assertEquals("1.0", p.getProperty("version")); + } else { + fail("We expected the standard pom.properties: " + pomProperties); + } + } - try (ZipFile zip1 = new ZipFile(jar1)) { - String manifestEntryName = "META-INF/MANIFEST.MF"; - ZipEntry manifestEntry = zip1.getEntry(manifestEntryName); - if (manifestEntry != null) { - InputStream is = zip1.getInputStream(manifestEntry); - Manifest p = new Manifest(is); - assertNotNull(p.getMainAttributes().getValue("Built-By")); - assertNotNull(p.getMainAttributes().getValue("Build-Jdk")); - assertEquals("1.0", p.getMainAttributes().getValue("Manifest-Version")); - assertEquals("test", p.getMainAttributes().getValue("Implementation-Title")); - assertEquals("1.0", p.getMainAttributes().getValue("Implementation-Version")); - assertEquals("io.takari.lifecycle.its", p.getMainAttributes().getValue("Implementation-Vendor-Id")); - } else { - fail("We expected the standard META-INF/MANIFEST.MF"); - } + try (ZipFile zip1 = new ZipFile(jar1)) { + String manifestEntryName = "META-INF/MANIFEST.MF"; + ZipEntry manifestEntry = zip1.getEntry(manifestEntryName); + if (manifestEntry != null) { + InputStream is = zip1.getInputStream(manifestEntry); + Manifest p = new Manifest(is); + assertNotNull(p.getMainAttributes().getValue("Built-By")); + assertNotNull(p.getMainAttributes().getValue("Build-Jdk")); + assertEquals("1.0", p.getMainAttributes().getValue("Manifest-Version")); + assertEquals("test", p.getMainAttributes().getValue("Implementation-Title")); + assertEquals("1.0", p.getMainAttributes().getValue("Implementation-Version")); + assertEquals("io.takari.lifecycle.its", p.getMainAttributes().getValue("Implementation-Vendor-Id")); + } else { + fail("We expected the standard META-INF/MANIFEST.MF"); + } + } } - } - @Test - public void testBasic_attachedArtifacts() throws Exception { - File basedir = resources.getBasedir("jar/basic"); - cp(basedir, "src/main/resources/resource.txt", "target/classes/resource.txt"); - cp(basedir, "src/test/resources/test-resource.txt", "target/test-classes/resource.txt"); + @Test + public void testBasic_attachedArtifacts() throws Exception { + File basedir = resources.getBasedir("jar/basic"); + cp(basedir, "src/main/resources/resource.txt", "target/classes/resource.txt"); + cp(basedir, "src/test/resources/test-resource.txt", "target/test-classes/resource.txt"); + + MavenProject project = mojos.readMavenProject(basedir); + mojos.executeMojo(project, "jar", newParameter("sourceJar", "true"), newParameter("testJar", "true")); + + Map attachedArtifacts = new HashMap(); + for (Artifact artifact : project.getAttachedArtifacts()) { + assertNull(attachedArtifacts.put(artifact.getClassifier(), artifact)); + } - MavenProject project = mojos.readMavenProject(basedir); - mojos.executeMojo(project, "jar", newParameter("sourceJar", "true"), newParameter("testJar", "true")); + // main artifact (test-1.0.jar) + File jar = new File(basedir, "target/test-1.0.jar"); + assertTrue(jar.exists()); + assertEquals(jar, project.getArtifact().getFile()); + assertEquals("jar", project.getArtifact().getType()); + + // sources (test-1.0-sources.jar) + File sourceJar = new File(basedir, "target/test-1.0-sources.jar"); + assertTrue(sourceJar.exists()); + assertEquals(sourceJar, attachedArtifacts.get("sources").getFile()); + assertEquals("jar", attachedArtifacts.get("sources").getType()); + + // tests (test-1.0-tests.jar) + File testJar = new File(basedir, "target/test-1.0-tests.jar"); + assertTrue(testJar.exists()); + assertEquals(testJar, attachedArtifacts.get("tests").getFile()); + assertEquals("jar", attachedArtifacts.get("tests").getType()); + } - Map attachedArtifacts = new HashMap(); - for (Artifact artifact : project.getAttachedArtifacts()) { - assertNull(attachedArtifacts.put(artifact.getClassifier(), artifact)); + @Test + public void testClassloader_getResources() throws Exception { + File basedir = resources.getBasedir("jar/project-with-resources"); + mojos.executeMojo(basedir, "process-resources"); + mojos.executeMojo(basedir, "jar"); + File jar = new File(basedir, "target/test-1.0.jar"); + try (URLClassLoader cl = new URLClassLoader(new URL[] {jar.toURI().toURL()}, null)) { + List list = toList(cl.getResources("subdir")); + Assert.assertEquals(1, list.size()); + Assert.assertTrue(list.get(0).toString(), list.get(0).toString().endsWith("test-1.0.jar!/subdir")); + } } - // main artifact (test-1.0.jar) - File jar = new File(basedir, "target/test-1.0.jar"); - assertTrue(jar.exists()); - assertEquals(jar, project.getArtifact().getFile()); - assertEquals("jar", project.getArtifact().getType()); - - // sources (test-1.0-sources.jar) - File sourceJar = new File(basedir, "target/test-1.0-sources.jar"); - assertTrue(sourceJar.exists()); - assertEquals(sourceJar, attachedArtifacts.get("sources").getFile()); - assertEquals("jar", attachedArtifacts.get("sources").getType()); - - // tests (test-1.0-tests.jar) - File testJar = new File(basedir, "target/test-1.0-tests.jar"); - assertTrue(testJar.exists()); - assertEquals(testJar, attachedArtifacts.get("tests").getFile()); - assertEquals("jar", attachedArtifacts.get("tests").getType()); - } - - @Test - public void testClassloader_getResources() throws Exception { - File basedir = resources.getBasedir("jar/project-with-resources"); - mojos.executeMojo(basedir, "process-resources"); - mojos.executeMojo(basedir, "jar"); - File jar = new File(basedir, "target/test-1.0.jar"); - try (URLClassLoader cl = new URLClassLoader(new URL[] {jar.toURI().toURL()}, null)) { - List list = toList(cl.getResources("subdir")); - Assert.assertEquals(1, list.size()); - Assert.assertTrue(list.get(0).toString(), list.get(0).toString().endsWith("test-1.0.jar!/subdir")); + @Test + public void testJarEntries() throws Exception { + File basedir = resources.getBasedir("jar/project-with-resources"); + mojos.executeMojo(basedir, "process-resources"); + mojos.executeMojo(basedir, "jar"); + File jar = new File(basedir, "target/test-1.0.jar"); + assertZipEntries( + jar // + , + "D META-INF/ 315561600000" // + , + "F META-INF/MANIFEST.MF 315561600000" // + , + "D META-INF/maven/ 315561600000" // + , + "D META-INF/maven/io.takari.lifecycle.its/ 315561600000" // + , + "D META-INF/maven/io.takari.lifecycle.its/test/ 315561600000" // + , + "F META-INF/maven/io.takari.lifecycle.its/test/pom.properties 315561600000" // + , + "F resource.txt 315561600000" // + , + "D subdir/ 315561600000" // + , + "F subdir/resource.txt 315561600000" // + ); } - } - - @Test - public void testJarEntries() throws Exception { - File basedir = resources.getBasedir("jar/project-with-resources"); - mojos.executeMojo(basedir, "process-resources"); - mojos.executeMojo(basedir, "jar"); - File jar = new File(basedir, "target/test-1.0.jar"); - assertZipEntries(jar // - , "D META-INF/ 315561600000" // - , "F META-INF/MANIFEST.MF 315561600000" // - , "D META-INF/maven/ 315561600000" // - , "D META-INF/maven/io.takari.lifecycle.its/ 315561600000" // - , "D META-INF/maven/io.takari.lifecycle.its/test/ 315561600000" // - , "F META-INF/maven/io.takari.lifecycle.its/test/pom.properties 315561600000" // - , "F resource.txt 315561600000" // - , "D subdir/ 315561600000" // - , "F subdir/resource.txt 315561600000" // - ); - } - - private static void assertZipEntries(File zipFile, String... expected) throws IOException { - try (ZipFile zip = new ZipFile(zipFile)) { - Map sorted = new LinkedHashMap<>(); - - Enumeration entries = zip.entries(); - while (entries.hasMoreElements()) { - ZipEntry entry = entries.nextElement(); - sorted.put(entry.getName(), entry); - } - - StringBuilder actualSb = new StringBuilder(); - for (ZipEntry entry : sorted.values()) { - actualSb.append(entry.isDirectory() ? "D " : "F ").append(entry.getName()).append(' ').append(entry.getTime()).append('\n'); - } - - StringBuilder expectedSb = new StringBuilder(); - for (String str : expected) { - expectedSb.append(str).append('\n'); - } - - Assert.assertEquals(expectedSb.toString(), actualSb.toString()); + + private static void assertZipEntries(File zipFile, String... expected) throws IOException { + try (ZipFile zip = new ZipFile(zipFile)) { + Map sorted = new LinkedHashMap<>(); + + Enumeration entries = zip.entries(); + while (entries.hasMoreElements()) { + ZipEntry entry = entries.nextElement(); + sorted.put(entry.getName(), entry); + } + + StringBuilder actualSb = new StringBuilder(); + for (ZipEntry entry : sorted.values()) { + actualSb.append(entry.isDirectory() ? "D " : "F ") + .append(entry.getName()) + .append(' ') + .append(entry.getTime()) + .append('\n'); + } + + StringBuilder expectedSb = new StringBuilder(); + for (String str : expected) { + expectedSb.append(str).append('\n'); + } + + Assert.assertEquals(expectedSb.toString(), actualSb.toString()); + } } - } - private static List toList(Enumeration e) { - ArrayList l = new ArrayList(); - while (e.hasMoreElements()) { - l.add(e.nextElement()); + private static List toList(Enumeration e) { + ArrayList l = new ArrayList(); + while (e.hasMoreElements()) { + l.add(e.nextElement()); + } + return l; } - return l; - } - - @Test - public void testCustomManifest() throws Exception { - File basedir = resources.getBasedir("jar/project-with-manifest"); - new File(basedir, "target/classes").mkdirs(); // TODO this shouldn't be necessary - mojos.executeMojo(basedir, "jar"); - try (JarFile jar = new JarFile(new File(basedir, "target/test-1.0.jar"))) { - Manifest mf = jar.getManifest(); - Assert.assertEquals("custom-value", mf.getMainAttributes().getValue("Custom-Entry")); + + @Test + public void testCustomManifest() throws Exception { + File basedir = resources.getBasedir("jar/project-with-manifest"); + new File(basedir, "target/classes").mkdirs(); // TODO this shouldn't be necessary + mojos.executeMojo(basedir, "jar"); + try (JarFile jar = new JarFile(new File(basedir, "target/test-1.0.jar"))) { + Manifest mf = jar.getManifest(); + Assert.assertEquals("custom-value", mf.getMainAttributes().getValue("Custom-Entry")); + } } - } - - @Test - @Ignore("this is currently broken, but the fix requires changes to incrementalbuild") - public void testCustomManifest_incremental() throws Exception { - File basedir = resources.getBasedir("jar/project-with-manifest"); - new File(basedir, "target/classes").mkdirs(); // TODO this shouldn't be necessary - mojos.executeMojo(basedir, "jar"); - try (JarFile jar = new JarFile(new File(basedir, "target/test-1.0.jar"))) { - Manifest mf = jar.getManifest(); - Assert.assertEquals("custom-value", mf.getMainAttributes().getValue("Custom-Entry")); + + @Test + @Ignore("this is currently broken, but the fix requires changes to incrementalbuild") + public void testCustomManifest_incremental() throws Exception { + File basedir = resources.getBasedir("jar/project-with-manifest"); + new File(basedir, "target/classes").mkdirs(); // TODO this shouldn't be necessary + mojos.executeMojo(basedir, "jar"); + try (JarFile jar = new JarFile(new File(basedir, "target/test-1.0.jar"))) { + Manifest mf = jar.getManifest(); + Assert.assertEquals("custom-value", mf.getMainAttributes().getValue("Custom-Entry")); + } + + cp(basedir, "src/META-INF/MANIFEST.MF-changed", "src/META-INF/MANIFEST.MF"); + mojos.executeMojo(basedir, "jar"); + try (JarFile jar = new JarFile(new File(basedir, "target/test-1.0.jar"))) { + Manifest mf = jar.getManifest(); + Assert.assertEquals("changed-custom-value", mf.getMainAttributes().getValue("Custom-Entry")); + } } - cp(basedir, "src/META-INF/MANIFEST.MF-changed", "src/META-INF/MANIFEST.MF"); - mojos.executeMojo(basedir, "jar"); - try (JarFile jar = new JarFile(new File(basedir, "target/test-1.0.jar"))) { - Manifest mf = jar.getManifest(); - Assert.assertEquals("changed-custom-value", mf.getMainAttributes().getValue("Custom-Entry")); + @Test + public void testDuplicateCustomManifest() throws Exception { + File basedir = resources.getBasedir("jar/project-with-manifest-under-target-classes"); + mojos.executeMojo(basedir, "jar"); + try (JarFile jar = new JarFile(new File(basedir, "target/test-1.0.jar"))) { + // make sure there is only one manifest entry + int count = 0; + for (Enumeration entries = jar.entries(); entries.hasMoreElements(); ) { + JarEntry entry = entries.nextElement(); + if ("META-INF/MANIFEST.MF".equalsIgnoreCase(entry.getName())) { + count++; + } + } + Assert.assertEquals(1, count); + // now check the manifest contents + Manifest mf = jar.getManifest(); + Assert.assertEquals("custom-value", mf.getMainAttributes().getValue("Custom-Entry")); + } } - } - - @Test - public void testDuplicateCustomManifest() throws Exception { - File basedir = resources.getBasedir("jar/project-with-manifest-under-target-classes"); - mojos.executeMojo(basedir, "jar"); - try (JarFile jar = new JarFile(new File(basedir, "target/test-1.0.jar"))) { - // make sure there is only one manifest entry - int count = 0; - for (Enumeration entries = jar.entries(); entries.hasMoreElements();) { - JarEntry entry = entries.nextElement(); - if ("META-INF/MANIFEST.MF".equalsIgnoreCase(entry.getName())) { - count++; + + @Test + public void testCustomManifestEntries() throws Exception { + File basedir = resources.getBasedir("jar/project-with-manifest-entries"); + new File(basedir, "target/classes").mkdirs(); // TODO this shouldn't be necessary + mojos.executeMojo(basedir, "jar"); + try (JarFile jar = new JarFile(new File(basedir, "target/test-1.0.jar"))) { + Manifest mf = jar.getManifest(); + Attributes main = mf.getMainAttributes(); + assertNotNull(main.getValue("Built-By")); + assertNotNull(main.getValue("Build-Jdk")); + assertEquals("1.0", main.getValue("Manifest-Version")); + assertEquals("test", main.getValue("Implementation-Title")); + assertEquals("1.0", main.getValue("Implementation-Version")); + assertEquals("io.takari.lifecycle.its", main.getValue("Implementation-Vendor-Id")); + assertEquals("custom-value", main.getValue("Custom-Entry")); } - } - Assert.assertEquals(1, count); - // now check the manifest contents - Manifest mf = jar.getManifest(); - Assert.assertEquals("custom-value", mf.getMainAttributes().getValue("Custom-Entry")); } - } - - @Test - public void testCustomManifestEntries() throws Exception { - File basedir = resources.getBasedir("jar/project-with-manifest-entries"); - new File(basedir, "target/classes").mkdirs(); // TODO this shouldn't be necessary - mojos.executeMojo(basedir, "jar"); - try (JarFile jar = new JarFile(new File(basedir, "target/test-1.0.jar"))) { - Manifest mf = jar.getManifest(); - Attributes main = mf.getMainAttributes(); - assertNotNull(main.getValue("Built-By")); - assertNotNull(main.getValue("Build-Jdk")); - assertEquals("1.0", main.getValue("Manifest-Version")); - assertEquals("test", main.getValue("Implementation-Title")); - assertEquals("1.0", main.getValue("Implementation-Version")); - assertEquals("io.takari.lifecycle.its", main.getValue("Implementation-Vendor-Id")); - assertEquals("custom-value", main.getValue("Custom-Entry")); + + @Test + public void testEmpty() throws Exception { + File basedir = resources.getBasedir("jar/empty"); + mojos.executeMojo(basedir, "jar"); + + assertTrue(new File(basedir, "target/test-1.0.jar").exists()); + assertTrue(new File(basedir, "target/test-1.0-sources.jar").exists()); + assertFalse(new File(basedir, "target/test-1.0-tests.jar").exists()); + } + + @Test + public void testSymlinkedDirectories() throws Exception { + Assume.assumeTrue(Os.isFamily(Os.FAMILY_UNIX)); + + File basedir = resources.getBasedir(); + + File orig = new File(basedir, "orig"); + create(orig, "src/main/java/pkg/Class.java"); + create(orig, "src/test/java/testpkg/Test.java"); + create(orig, "target/classes/resource.txt", "target/classes/subdir/resource.txt"); + java.nio.file.Files.createSymbolicLink( + new File(orig, "target/classes/symlinked-resource.txt").toPath(), + new File(orig, "target/classes/resource.txt").toPath()); + create(orig, "target/test-classes/test-resource.txt"); + + File symlink = java.nio.file.Files.createSymbolicLink(new File(basedir, "symlink").toPath(), orig.toPath()) + .toFile(); + mojos.executeMojo(symlink, "jar", newParameter("testJar", "true"), newParameter("sourceJar", "true")); + assertZipEntries( + new File(symlink, "target/test-1.jar") // + , + "D META-INF/ 315561600000" // + , + "F META-INF/MANIFEST.MF 315561600000" // + , + "D META-INF/maven/ 315561600000" // + , + "D META-INF/maven/test/ 315561600000" // + , + "D META-INF/maven/test/test/ 315561600000" // + , + "F META-INF/maven/test/test/pom.properties 315561600000" // + , + "F resource.txt 315561600000" // + , + "D subdir/ 315561600000" // + , + "F subdir/resource.txt 315561600000" // + , + "F symlinked-resource.txt 315561600000" // + ); + assertZipEntries( + new File(symlink, "target/test-1-tests.jar") // + , + "D META-INF/ 315561600000" // + , + "F META-INF/MANIFEST.MF 315561600000" // + , + "F test-resource.txt 315561600000" // + ); + assertZipEntries( + new File(symlink, "target/test-1-sources.jar") // + , + "D META-INF/ 315561600000" // + , + "F META-INF/MANIFEST.MF 315561600000" // + , + "D pkg/ 315561600000" // + , + "F pkg/Class.java 315561600000" // + ); } - } - - @Test - public void testEmpty() throws Exception { - File basedir = resources.getBasedir("jar/empty"); - mojos.executeMojo(basedir, "jar"); - - assertTrue(new File(basedir, "target/test-1.0.jar").exists()); - assertTrue(new File(basedir, "target/test-1.0-sources.jar").exists()); - assertFalse(new File(basedir, "target/test-1.0-tests.jar").exists()); - } - - @Test - public void testSymlinkedDirectories() throws Exception { - Assume.assumeTrue(Os.isFamily(Os.FAMILY_UNIX)); - - File basedir = resources.getBasedir(); - - File orig = new File(basedir, "orig"); - create(orig, "src/main/java/pkg/Class.java"); - create(orig, "src/test/java/testpkg/Test.java"); - create(orig, "target/classes/resource.txt", "target/classes/subdir/resource.txt"); - java.nio.file.Files.createSymbolicLink(new File(orig, "target/classes/symlinked-resource.txt").toPath(), new File(orig, "target/classes/resource.txt").toPath()); - create(orig, "target/test-classes/test-resource.txt"); - - File symlink = java.nio.file.Files.createSymbolicLink(new File(basedir, "symlink").toPath(), orig.toPath()).toFile(); - mojos.executeMojo(symlink, "jar", newParameter("testJar", "true"), newParameter("sourceJar", "true")); - assertZipEntries(new File(symlink, "target/test-1.jar") // - , "D META-INF/ 315561600000" // - , "F META-INF/MANIFEST.MF 315561600000" // - , "D META-INF/maven/ 315561600000" // - , "D META-INF/maven/test/ 315561600000" // - , "D META-INF/maven/test/test/ 315561600000" // - , "F META-INF/maven/test/test/pom.properties 315561600000" // - , "F resource.txt 315561600000" // - , "D subdir/ 315561600000" // - , "F subdir/resource.txt 315561600000" // - , "F symlinked-resource.txt 315561600000" // - ); - assertZipEntries(new File(symlink, "target/test-1-tests.jar") // - , "D META-INF/ 315561600000" // - , "F META-INF/MANIFEST.MF 315561600000" // - , "F test-resource.txt 315561600000" // - ); - assertZipEntries(new File(symlink, "target/test-1-sources.jar") // - , "D META-INF/ 315561600000" // - , "F META-INF/MANIFEST.MF 315561600000" // - , "D pkg/ 315561600000" // - , "F pkg/Class.java 315561600000" // - ); - } } diff --git a/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/jar/PomPropertiesTest.java b/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/jar/PomPropertiesTest.java index 14e98352..9fa79779 100644 --- a/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/jar/PomPropertiesTest.java +++ b/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/jar/PomPropertiesTest.java @@ -1,36 +1,36 @@ package io.takari.maven.plugins.jar; import static org.junit.Assert.assertEquals; + import io.takari.incrementalbuild.maven.testing.IncrementalBuildRule; import io.takari.maven.testing.TestResources; - import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import java.util.Properties; - import org.junit.Rule; import org.junit.Test; public class PomPropertiesTest { - @Rule - public final TestResources resources = new TestResources(); - - @Rule - public final IncrementalBuildRule mojos = new IncrementalBuildRule(); - - @Test - public void testBasic() throws Exception { - File basedir = resources.getBasedir("jar/basic"); - mojos.executeMojo(basedir, "pom-properties"); - - Properties properties = new Properties(); - try (InputStream is = new FileInputStream(new File(basedir, "target/classes/META-INF/maven/io.takari.lifecycle.its/test/pom.properties"))) { - properties.load(is); + @Rule + public final TestResources resources = new TestResources(); + + @Rule + public final IncrementalBuildRule mojos = new IncrementalBuildRule(); + + @Test + public void testBasic() throws Exception { + File basedir = resources.getBasedir("jar/basic"); + mojos.executeMojo(basedir, "pom-properties"); + + Properties properties = new Properties(); + try (InputStream is = new FileInputStream( + new File(basedir, "target/classes/META-INF/maven/io.takari.lifecycle.its/test/pom.properties"))) { + properties.load(is); + } + + assertEquals("io.takari.lifecycle.its", properties.getProperty("groupId")); + assertEquals("test", properties.getProperty("artifactId")); + assertEquals("1.0", properties.getProperty("version")); } - - assertEquals("io.takari.lifecycle.its", properties.getProperty("groupId")); - assertEquals("test", properties.getProperty("artifactId")); - assertEquals("1.0", properties.getProperty("version")); - } } diff --git a/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/plugin/MojoDescriptorGleanerTest.java b/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/plugin/MojoDescriptorGleanerTest.java index ce6b117f..7518f576 100644 --- a/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/plugin/MojoDescriptorGleanerTest.java +++ b/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/plugin/MojoDescriptorGleanerTest.java @@ -3,97 +3,96 @@ import static io.takari.maven.plugins.plugin.PluginDescriptorMojo.PATH_MOJOS_XML; import static io.takari.maven.testing.TestMavenRuntime.newParameter; +import io.takari.incrementalbuild.maven.testing.IncrementalBuildRule; +import io.takari.maven.plugins.plugin.model.MojoDescriptor; +import io.takari.maven.plugins.plugin.model.MojoParameter; +import io.takari.maven.plugins.plugin.model.MojoRequirement; +import io.takari.maven.plugins.plugin.model.PluginDescriptor; +import io.takari.maven.plugins.plugin.model.io.xpp3.PluginDescriptorXpp3Reader; +import io.takari.maven.testing.TestProperties; +import io.takari.maven.testing.TestResources; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; - import org.apache.maven.project.MavenProject; import org.codehaus.plexus.util.xml.pull.XmlPullParserException; import org.junit.Assert; import org.junit.Rule; import org.junit.Test; -import io.takari.incrementalbuild.maven.testing.IncrementalBuildRule; -import io.takari.maven.plugins.plugin.model.MojoDescriptor; -import io.takari.maven.plugins.plugin.model.MojoParameter; -import io.takari.maven.plugins.plugin.model.MojoRequirement; -import io.takari.maven.plugins.plugin.model.PluginDescriptor; -import io.takari.maven.plugins.plugin.model.io.xpp3.PluginDescriptorXpp3Reader; -import io.takari.maven.testing.TestProperties; -import io.takari.maven.testing.TestResources; - public class MojoDescriptorGleanerTest { - @Rule - public final TestResources resources = new TestResources(); - - @Rule - public final IncrementalBuildRule mojos = new IncrementalBuildRule(); - - public final TestProperties properties = new TestProperties(); - - @Test - public void testGleaner() throws Exception { - File basedir = resources.getBasedir("plugin-descriptor/gleaner"); - MavenProject project = mojos.readMavenProject(basedir); - addDependency(project, "apache-plugin-annotations-jar"); - mojos.executeMojo(project, "compile", newParameter("compilerId", "jdt")); - mojos.executeMojo(project, "mojo-annotation-processor"); - - MojoDescriptor d = readDescriptor(basedir, "glean_RequirementTypes"); - - Assert.assertEquals("java.util.Map", getRequirement(d, "mapRequirement").getRole()); - Assert.assertEquals("java.util.List", getRequirement(d, "listRequirement").getRole()); - Assert.assertEquals("java.util.List", getParameter(d, "listParameter").getType()); - Assert.assertEquals("boolean", getParameter(d, "booleanParameter").getType()); - Assert.assertEquals("java.lang.String[]", getParameter(d, "arrayParameter").getType()); - - Assert.assertFalse(d.isTakariBuilder()); - } - - @Test - public void testGleanerForBuilder() throws Exception { - File basedir = resources.getBasedir("plugin-descriptor/basic-builder"); - MavenProject project = mojos.readMavenProject(basedir); - addDependency(project, "apache-plugin-annotations-jar"); - addDependency(project, "maven-plugin-api-jar"); - addDependency(project, "takari-builder-jar"); - mojos.executeMojo(project, "compile", newParameter("compilerId", "jdt")); - mojos.executeMojo(project, "mojo-annotation-processor"); - - MojoDescriptor d = readDescriptor(basedir, "BasicBuilder"); - - Assert.assertTrue(d.isTakariBuilder()); - } - - private MojoParameter getParameter(MojoDescriptor descriptor, String fieldName) { - for (MojoParameter parameter : descriptor.getParameters()) { - if (fieldName.equals(parameter.getName())) { - return parameter; - } + @Rule + public final TestResources resources = new TestResources(); + + @Rule + public final IncrementalBuildRule mojos = new IncrementalBuildRule(); + + public final TestProperties properties = new TestProperties(); + + @Test + public void testGleaner() throws Exception { + File basedir = resources.getBasedir("plugin-descriptor/gleaner"); + MavenProject project = mojos.readMavenProject(basedir); + addDependency(project, "apache-plugin-annotations-jar"); + mojos.executeMojo(project, "compile", newParameter("compilerId", "jdt")); + mojos.executeMojo(project, "mojo-annotation-processor"); + + MojoDescriptor d = readDescriptor(basedir, "glean_RequirementTypes"); + + Assert.assertEquals("java.util.Map", getRequirement(d, "mapRequirement").getRole()); + Assert.assertEquals( + "java.util.List", getRequirement(d, "listRequirement").getRole()); + Assert.assertEquals("java.util.List", getParameter(d, "listParameter").getType()); + Assert.assertEquals("boolean", getParameter(d, "booleanParameter").getType()); + Assert.assertEquals( + "java.lang.String[]", getParameter(d, "arrayParameter").getType()); + + Assert.assertFalse(d.isTakariBuilder()); } - throw new AssertionError("No such parameter " + fieldName); - } - - private MojoRequirement getRequirement(MojoDescriptor descriptor, String fieldName) { - for (MojoRequirement requirement : descriptor.getRequirements()) { - if (fieldName.equals(requirement.getFieldName())) { - return requirement; - } + + @Test + public void testGleanerForBuilder() throws Exception { + File basedir = resources.getBasedir("plugin-descriptor/basic-builder"); + MavenProject project = mojos.readMavenProject(basedir); + addDependency(project, "apache-plugin-annotations-jar"); + addDependency(project, "maven-plugin-api-jar"); + addDependency(project, "takari-builder-jar"); + mojos.executeMojo(project, "compile", newParameter("compilerId", "jdt")); + mojos.executeMojo(project, "mojo-annotation-processor"); + + MojoDescriptor d = readDescriptor(basedir, "BasicBuilder"); + + Assert.assertTrue(d.isTakariBuilder()); + } + + private MojoParameter getParameter(MojoDescriptor descriptor, String fieldName) { + for (MojoParameter parameter : descriptor.getParameters()) { + if (fieldName.equals(parameter.getName())) { + return parameter; + } + } + throw new AssertionError("No such parameter " + fieldName); } - throw new AssertionError("No such requirement " + fieldName); - } - - private MojoDescriptor readDescriptor(File basedir, String classname) throws IOException, XmlPullParserException { - try (InputStream is = new FileInputStream(new File(basedir, "target/classes/" + PATH_MOJOS_XML))) { - PluginDescriptor descriptor = new PluginDescriptorXpp3Reader().read(is); - Assert.assertEquals(1, descriptor.getMojos().size()); - return descriptor.getMojos().get(0); + + private MojoRequirement getRequirement(MojoDescriptor descriptor, String fieldName) { + for (MojoRequirement requirement : descriptor.getRequirements()) { + if (fieldName.equals(requirement.getFieldName())) { + return requirement; + } + } + throw new AssertionError("No such requirement " + fieldName); } - } - private void addDependency(MavenProject project, String property) throws Exception { - mojos.newDependency(new File(properties.get(property))).addTo(project); - } + private MojoDescriptor readDescriptor(File basedir, String classname) throws IOException, XmlPullParserException { + try (InputStream is = new FileInputStream(new File(basedir, "target/classes/" + PATH_MOJOS_XML))) { + PluginDescriptor descriptor = new PluginDescriptorXpp3Reader().read(is); + Assert.assertEquals(1, descriptor.getMojos().size()); + return descriptor.getMojos().get(0); + } + } + private void addDependency(MavenProject project, String property) throws Exception { + mojos.newDependency(new File(properties.get(property))).addTo(project); + } } diff --git a/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/plugin/PluginDescriptorMojoTest.java b/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/plugin/PluginDescriptorMojoTest.java index 718efa28..fd02d291 100644 --- a/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/plugin/PluginDescriptorMojoTest.java +++ b/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/plugin/PluginDescriptorMojoTest.java @@ -6,9 +6,12 @@ import static io.takari.maven.testing.TestResources.rm; import static org.junit.Assert.fail; +import com.google.common.collect.ImmutableList; +import io.takari.incrementalbuild.maven.testing.IncrementalBuildRule; +import io.takari.maven.testing.TestProperties; +import io.takari.maven.testing.TestResources; import java.io.File; import java.io.FileOutputStream; - import org.apache.maven.artifact.Artifact; import org.apache.maven.execution.MavenSession; import org.apache.maven.plugin.MojoExecutionException; @@ -16,290 +19,364 @@ import org.junit.Rule; import org.junit.Test; -import com.google.common.collect.ImmutableList; +public class PluginDescriptorMojoTest { + @Rule + public final TestResources resources = new TestResources(); -import io.takari.incrementalbuild.maven.testing.IncrementalBuildRule; -import io.takari.maven.testing.TestProperties; -import io.takari.maven.testing.TestResources; + @Rule + public final IncrementalBuildRule mojos = new IncrementalBuildRule(); -public class PluginDescriptorMojoTest { - @Rule - public final TestResources resources = new TestResources(); + public final TestProperties properties = new TestProperties(); - @Rule - public final IncrementalBuildRule mojos = new IncrementalBuildRule(); + @Test + public void testBasic() throws Exception { + File basedir = resources.getBasedir("plugin-descriptor/basic"); - public final TestProperties properties = new TestProperties(); + MavenProject project = mojos.readMavenProject(basedir); + addDependencies(project, "apache-plugin-annotations-jar", "maven-plugin-api-jar"); - @Test - public void testBasic() throws Exception { - File basedir = resources.getBasedir("plugin-descriptor/basic"); + generatePluginDescriptor(project); - MavenProject project = mojos.readMavenProject(basedir); - addDependencies(project, "apache-plugin-annotations-jar", "maven-plugin-api-jar"); + mojos.assertBuildOutputs( + basedir, + "target/classes/META-INF/maven/plugin.xml", + "target/classes/META-INF/m2e/lifecycle-mapping-metadata.xml"); + assertFileContents(basedir, "expected/plugin.xml", "target/classes/META-INF/maven/plugin.xml"); + assertFileContents( + basedir, + "expected/lifecycle-mapping-metadata.xml", + "target/classes/META-INF/m2e/lifecycle-mapping-metadata.xml"); + } + + private void generatePluginDescriptor(MavenProject project) throws Exception { + mojos.executeMojo(project, "compile", newParameter("compilerId", "jdt")); + mojos.executeMojo(project, "mojo-annotation-processor"); + mojos.executeMojo(project, "plugin-descriptor"); + } - generatePluginDescriptor(project); + private void addDependencies(MavenProject project, String... keys) throws Exception { + File[] files = new File[keys.length]; + for (int i = 0; i < keys.length; i++) { + files[i] = new File(properties.get(keys[i])); + } + addDependencies(project, files); + } - mojos.assertBuildOutputs(basedir, "target/classes/META-INF/maven/plugin.xml", "target/classes/META-INF/m2e/lifecycle-mapping-metadata.xml"); - assertFileContents(basedir, "expected/plugin.xml", "target/classes/META-INF/maven/plugin.xml"); - assertFileContents(basedir, "expected/lifecycle-mapping-metadata.xml", "target/classes/META-INF/m2e/lifecycle-mapping-metadata.xml"); - } + private void addDependencies(MavenProject project, File... files) throws Exception { + for (File file : files) { + mojos.newDependency(file).addTo(project); + } + } - private void generatePluginDescriptor(MavenProject project) throws Exception { - mojos.executeMojo(project, "compile", newParameter("compilerId", "jdt")); - mojos.executeMojo(project, "mojo-annotation-processor"); - mojos.executeMojo(project, "plugin-descriptor"); - } + @Test + public void testLegacyInheritance() throws Exception { + File basedir = resources.getBasedir("plugin-descriptor/legacy-inheritance"); + File legacyBasedir = new File(basedir, "legacy"); + File pluginBasedir = new File(basedir, "plugin"); + + final MavenProject legacyProject = mojos.readMavenProject(legacyBasedir); + addDependencies(legacyProject, "apache-plugin-annotations-jar", "maven-plugin-api-jar"); + generatePluginDescriptor(legacyProject); + + mojos.assertBuildOutputs( + legacyBasedir, + "target/classes/META-INF/maven/plugin.xml", + "target/classes/META-INF/m2e/lifecycle-mapping-metadata.xml"); + rm( + legacyBasedir, + "target/classes/META-INF/takari/mojos.xml"); // make it look like plugin built with maven-plugin-plugin + mojos.executeMojo(legacyProject, "jar"); + + final MavenProject pluginProject = mojos.readMavenProject(pluginBasedir); + addDependencies(pluginProject, "apache-plugin-annotations-jar", "maven-plugin-api-jar"); + addDependencies(pluginProject, new File(legacyBasedir, "target/plugin-descriptor-legacy-0.1.jar")); + + generatePluginDescriptor(pluginProject); + mojos.assertBuildOutputs( + pluginBasedir, + "target/classes/META-INF/maven/plugin.xml", + "target/classes/META-INF/m2e/lifecycle-mapping-metadata.xml"); + assertFileContents(pluginBasedir, "expected/mojos.xml", "target/classes/META-INF/takari/mojos.xml"); + assertFileContents(pluginBasedir, "expected/plugin.xml", "target/classes/META-INF/maven/plugin.xml"); + } - private void addDependencies(MavenProject project, String... keys) throws Exception { - File[] files = new File[keys.length]; - for (int i = 0; i < keys.length; i++) { - files[i] = new File(properties.get(keys[i])); + @Test + public void testInheritance_incremental() throws Exception { + File basedir = resources.getBasedir("plugin-descriptor/incremental-inheritance"); + File abstractBasedir = new File(basedir, "abstract"); + File concreteBasedir = new File(basedir, "concrete"); + + final MavenProject abstractProject = mojos.readMavenProject(abstractBasedir); + addDependencies(abstractProject, "apache-plugin-annotations-jar", "maven-plugin-api-jar"); + final MavenProject concreteProject = mojos.readMavenProject(concreteBasedir); + addDependencies(concreteProject, "apache-plugin-annotations-jar", "maven-plugin-api-jar"); + addDependencies(concreteProject, new File(abstractBasedir, "target/classes")); + + // initial build + generatePluginDescriptor(abstractProject); + + mojos.assertBuildOutputs( + abstractBasedir, + "target/classes/META-INF/maven/plugin.xml", + "target/classes/META-INF/m2e/lifecycle-mapping-metadata.xml"); + assertFileContents(abstractBasedir, "expected/mojos.xml", "target/classes/META-INF/takari/mojos.xml"); + generatePluginDescriptor(concreteProject); + mojos.assertBuildOutputs( + concreteBasedir, + "target/classes/META-INF/maven/plugin.xml", + "target/classes/META-INF/m2e/lifecycle-mapping-metadata.xml"); + assertFileContents(concreteBasedir, "expected/mojos.xml", "target/classes/META-INF/takari/mojos.xml"); + assertFileContents(concreteBasedir, "expected/plugin.xml", "target/classes/META-INF/maven/plugin.xml"); + + // no change rebuild + mojos.executeMojo(abstractProject, "plugin-descriptor"); + assertFileContents(abstractBasedir, "expected/mojos.xml", "target/classes/META-INF/takari/mojos.xml"); + mojos.executeMojo(concreteProject, "plugin-descriptor"); + assertFileContents(concreteBasedir, "expected/mojos.xml", "target/classes/META-INF/takari/mojos.xml"); + assertFileContents(concreteBasedir, "expected/plugin.xml", "target/classes/META-INF/maven/plugin.xml"); + + // change external superclass + cp( + new File(abstractBasedir, "src/main/java/io/takari/lifecycle/uts/plugindescriptor"), + "AbstractExternalMojo.java-changed", + "AbstractExternalMojo.java"); + generatePluginDescriptor(abstractProject); + assertFileContents(abstractBasedir, "expected/mojos.xml-changed", "target/classes/META-INF/takari/mojos.xml"); + generatePluginDescriptor(concreteProject); + assertFileContents( + concreteBasedir, "expected/mojos.xml-external-changed", "target/classes/META-INF/takari/mojos.xml"); + assertFileContents( + concreteBasedir, "expected/plugin.xml-external-changed", "target/classes/META-INF/maven/plugin.xml"); + + // remove annotations from external superclass + cp( + new File(abstractBasedir, "src/main/java/io/takari/lifecycle/uts/plugindescriptor"), + "AbstractExternalMojo.java-removed", + "AbstractExternalMojo.java"); + generatePluginDescriptor(abstractProject); + generatePluginDescriptor(concreteProject); + assertFileContents( + concreteBasedir, "expected/mojos.xml-external-removed", "target/classes/META-INF/takari/mojos.xml"); + assertFileContents( + concreteBasedir, "expected/plugin.xml-external-removed", "target/classes/META-INF/maven/plugin.xml"); } - addDependencies(project, files); - } - private void addDependencies(MavenProject project, File... files) throws Exception { - for (File file : files) { - mojos.newDependency(file).addTo(project); + @Test + public void testIndirectReference_incremental() throws Exception { + File basedir = resources.getBasedir("plugin-descriptor/incremental-indirect-reference"); + + MavenProject project = mojos.readMavenProject(basedir); + addDependencies(project, "apache-plugin-annotations-jar", "maven-plugin-api-jar"); + + generatePluginDescriptor(project); + mojos.assertBuildOutputs( + basedir, + "target/classes/META-INF/maven/plugin.xml", + "target/classes/META-INF/m2e/lifecycle-mapping-metadata.xml"); + assertFileContents(basedir, "expected/plugin.xml", "target/classes/META-INF/maven/plugin.xml"); + + cp( + basedir, + "src/main/java/io/takari/lifecycle/uts/plugindescriptor/IndirectReference.java-changed", + "src/main/java/io/takari/lifecycle/uts/plugindescriptor/IndirectReference.java"); + generatePluginDescriptor(project); + mojos.assertBuildOutputs( + basedir, + "target/classes/META-INF/maven/plugin.xml", + "target/classes/META-INF/m2e/lifecycle-mapping-metadata.xml"); + assertFileContents(basedir, "expected/plugin.xml-changed", "target/classes/META-INF/maven/plugin.xml"); } - } - - @Test - public void testLegacyInheritance() throws Exception { - File basedir = resources.getBasedir("plugin-descriptor/legacy-inheritance"); - File legacyBasedir = new File(basedir, "legacy"); - File pluginBasedir = new File(basedir, "plugin"); - - final MavenProject legacyProject = mojos.readMavenProject(legacyBasedir); - addDependencies(legacyProject, "apache-plugin-annotations-jar", "maven-plugin-api-jar"); - generatePluginDescriptor(legacyProject); - - mojos.assertBuildOutputs(legacyBasedir, "target/classes/META-INF/maven/plugin.xml", "target/classes/META-INF/m2e/lifecycle-mapping-metadata.xml"); - rm(legacyBasedir, "target/classes/META-INF/takari/mojos.xml"); // make it look like plugin built with maven-plugin-plugin - mojos.executeMojo(legacyProject, "jar"); - - final MavenProject pluginProject = mojos.readMavenProject(pluginBasedir); - addDependencies(pluginProject, "apache-plugin-annotations-jar", "maven-plugin-api-jar"); - addDependencies(pluginProject, new File(legacyBasedir, "target/plugin-descriptor-legacy-0.1.jar")); - - generatePluginDescriptor(pluginProject); - mojos.assertBuildOutputs(pluginBasedir, "target/classes/META-INF/maven/plugin.xml", "target/classes/META-INF/m2e/lifecycle-mapping-metadata.xml"); - assertFileContents(pluginBasedir, "expected/mojos.xml", "target/classes/META-INF/takari/mojos.xml"); - assertFileContents(pluginBasedir, "expected/plugin.xml", "target/classes/META-INF/maven/plugin.xml"); - } - - @Test - public void testInheritance_incremental() throws Exception { - File basedir = resources.getBasedir("plugin-descriptor/incremental-inheritance"); - File abstractBasedir = new File(basedir, "abstract"); - File concreteBasedir = new File(basedir, "concrete"); - - final MavenProject abstractProject = mojos.readMavenProject(abstractBasedir); - addDependencies(abstractProject, "apache-plugin-annotations-jar", "maven-plugin-api-jar"); - final MavenProject concreteProject = mojos.readMavenProject(concreteBasedir); - addDependencies(concreteProject, "apache-plugin-annotations-jar", "maven-plugin-api-jar"); - addDependencies(concreteProject, new File(abstractBasedir, "target/classes")); - - // initial build - generatePluginDescriptor(abstractProject); - - mojos.assertBuildOutputs(abstractBasedir, "target/classes/META-INF/maven/plugin.xml", "target/classes/META-INF/m2e/lifecycle-mapping-metadata.xml"); - assertFileContents(abstractBasedir, "expected/mojos.xml", "target/classes/META-INF/takari/mojos.xml"); - generatePluginDescriptor(concreteProject); - mojos.assertBuildOutputs(concreteBasedir, "target/classes/META-INF/maven/plugin.xml", "target/classes/META-INF/m2e/lifecycle-mapping-metadata.xml"); - assertFileContents(concreteBasedir, "expected/mojos.xml", "target/classes/META-INF/takari/mojos.xml"); - assertFileContents(concreteBasedir, "expected/plugin.xml", "target/classes/META-INF/maven/plugin.xml"); - - // no change rebuild - mojos.executeMojo(abstractProject, "plugin-descriptor"); - assertFileContents(abstractBasedir, "expected/mojos.xml", "target/classes/META-INF/takari/mojos.xml"); - mojos.executeMojo(concreteProject, "plugin-descriptor"); - assertFileContents(concreteBasedir, "expected/mojos.xml", "target/classes/META-INF/takari/mojos.xml"); - assertFileContents(concreteBasedir, "expected/plugin.xml", "target/classes/META-INF/maven/plugin.xml"); - - // change external superclass - cp(new File(abstractBasedir, "src/main/java/io/takari/lifecycle/uts/plugindescriptor"), "AbstractExternalMojo.java-changed", "AbstractExternalMojo.java"); - generatePluginDescriptor(abstractProject); - assertFileContents(abstractBasedir, "expected/mojos.xml-changed", "target/classes/META-INF/takari/mojos.xml"); - generatePluginDescriptor(concreteProject); - assertFileContents(concreteBasedir, "expected/mojos.xml-external-changed", "target/classes/META-INF/takari/mojos.xml"); - assertFileContents(concreteBasedir, "expected/plugin.xml-external-changed", "target/classes/META-INF/maven/plugin.xml"); - - // remove annotations from external superclass - cp(new File(abstractBasedir, "src/main/java/io/takari/lifecycle/uts/plugindescriptor"), "AbstractExternalMojo.java-removed", "AbstractExternalMojo.java"); - generatePluginDescriptor(abstractProject); - generatePluginDescriptor(concreteProject); - assertFileContents(concreteBasedir, "expected/mojos.xml-external-removed", "target/classes/META-INF/takari/mojos.xml"); - assertFileContents(concreteBasedir, "expected/plugin.xml-external-removed", "target/classes/META-INF/maven/plugin.xml"); - } - - @Test - public void testIndirectReference_incremental() throws Exception { - File basedir = resources.getBasedir("plugin-descriptor/incremental-indirect-reference"); - - MavenProject project = mojos.readMavenProject(basedir); - addDependencies(project, "apache-plugin-annotations-jar", "maven-plugin-api-jar"); - - generatePluginDescriptor(project); - mojos.assertBuildOutputs(basedir, "target/classes/META-INF/maven/plugin.xml", "target/classes/META-INF/m2e/lifecycle-mapping-metadata.xml"); - assertFileContents(basedir, "expected/plugin.xml", "target/classes/META-INF/maven/plugin.xml"); - - cp(basedir, "src/main/java/io/takari/lifecycle/uts/plugindescriptor/IndirectReference.java-changed", "src/main/java/io/takari/lifecycle/uts/plugindescriptor/IndirectReference.java"); - generatePluginDescriptor(project); - mojos.assertBuildOutputs(basedir, "target/classes/META-INF/maven/plugin.xml", "target/classes/META-INF/m2e/lifecycle-mapping-metadata.xml"); - assertFileContents(basedir, "expected/plugin.xml-changed", "target/classes/META-INF/maven/plugin.xml"); - } - - @Test - public void testJavadocInheritance_incremental() throws Exception { - File basedir = resources.getBasedir("plugin-descriptor/incremental-javadoc-inheritance"); - - MavenProject project = mojos.readMavenProject(basedir); - addDependencies(project, "apache-plugin-annotations-jar", "maven-plugin-api-jar"); - - generatePluginDescriptor(project); - mojos.assertBuildOutputs(basedir, "target/classes/META-INF/maven/plugin.xml", "target/classes/META-INF/m2e/lifecycle-mapping-metadata.xml"); - assertFileContents(basedir, "expected/plugin.xml", "target/classes/META-INF/maven/plugin.xml"); - - cp(basedir, "src/main/java/io/takari/lifecycle/uts/plugindescriptor/AbstractBasicMojo.java-changed", "src/main/java/io/takari/lifecycle/uts/plugindescriptor/AbstractBasicMojo.java"); - generatePluginDescriptor(project); - mojos.assertBuildOutputs(basedir, "target/classes/META-INF/maven/plugin.xml", "target/classes/META-INF/m2e/lifecycle-mapping-metadata.xml"); - assertFileContents(basedir, "expected/plugin.xml-changed", "target/classes/META-INF/maven/plugin.xml"); - } - - @Test - public void testInheritance() throws Exception { - // the point of the test is to assert parameters/requirements inheritance - - // test classes are named such that parent mojo is merged before child mojo - // which causes duplicate parameters unless implementation handles this case - - File basedir = resources.getBasedir("plugin-descriptor/inheritance"); - MavenProject project = mojos.readMavenProject(basedir); - addDependencies(project, "apache-plugin-annotations-jar", "maven-plugin-api-jar"); - generatePluginDescriptor(project); - assertFileContents(basedir, "expected/plugin.xml", "target/classes/META-INF/maven/plugin.xml"); - } - - @Test - public void testUnreadableDependencyMojosXml() throws Exception { - // the point of this test is to assert the mojo does not throw exception when one of the dependencies cannot be read - // such dependencies are ignored by the compiler, so plugin.xml generation should ignore them too - - File basedir = resources.getBasedir("plugin-descriptor/basic"); - File bogusJar = new File(basedir, "bogus.jar"); - new FileOutputStream(bogusJar).close(); - - MavenProject project = mojos.readMavenProject(basedir); - addDependencies(project, "apache-plugin-annotations-jar", "maven-plugin-api-jar"); - addDependencies(project, bogusJar); - - generatePluginDescriptor(project); - } - - @Test - public void testIncrementalDependencyChange() throws Exception { - // the point of this test is to assert that non-structural dependency change does not force plugin.xml regeneration - - File basedir = resources.getBasedir("plugin-descriptor/incremental-dependency"); - File dependency = new File(basedir, "dependency"); - File plugin = new File(basedir, "plugin"); - - mojos.executeMojo(dependency, "compile"); - - MavenProject project = mojos.readMavenProject(plugin); - addDependencies(project, "apache-plugin-annotations-jar", "maven-plugin-api-jar"); - addDependencies(project, new File(dependency, "target/classes")); - generatePluginDescriptor(project); - mojos.assertBuildOutputs(plugin, "target/classes/META-INF/maven/plugin.xml", "target/classes/META-INF/m2e/lifecycle-mapping-metadata.xml"); - - cp(dependency, "src/main/java/io/takari/lifecycle/uts/plugindescriptor/ComponentClass.java-private-change", "src/main/java/io/takari/lifecycle/uts/plugindescriptor/ComponentClass.java"); - mojos.executeMojo(dependency, "compile"); - mojos.assertBuildOutputs(dependency, "target/classes/io/takari/lifecycle/uts/plugindescriptor/ComponentClass.class"); - - mojos.executeMojo(project, "compile", newParameter("compilerId", "jdt")); - mojos.assertCarriedOverOutputs(plugin, "target/classes/io/takari/lifecycle/uts/plugindescriptor/BasicMojo.class"); - - mojos.executeMojo(project, "mojo-annotation-processor"); - mojos.assertCarriedOverOutputs(plugin, "target/classes/META-INF/takari/mojos.xml"); - - mojos.executeMojo(project, "plugin-descriptor"); - mojos.assertCarriedOverOutputs(plugin, "target/classes/META-INF/maven/plugin.xml", "target/classes/META-INF/m2e/lifecycle-mapping-metadata.xml"); - } - - @Test - public void testSourcepathDependency() throws Exception { - // assert that MojoAnnotationProcessorMojo honours sourcepath=reactorDependencies - - File basedir = resources.getBasedir("plugin-descriptor/sourcepath-dependency"); - File dependency = new File(basedir, "dependency"); - File plugin = new File(basedir, "plugin"); - - MavenProject dependencyProject = mojos.readMavenProject(dependency); - MavenProject pluginProject = mojos.readMavenProject(plugin); - addDependencies(pluginProject, "apache-plugin-annotations-jar", "maven-plugin-api-jar"); - mojos.newDependency(new File(dependencyProject.getBuild().getOutputDirectory())) // - .setGroupId(dependencyProject.getGroupId()) // - .setArtifactId(dependencyProject.getArtifactId()) // - .setVersion(dependencyProject.getVersion()) // - .addTo(pluginProject); - Artifact dependencyArtifact = dependencyProject.getArtifact(); - dependencyArtifact.setScope(Artifact.SCOPE_COMPILE); - pluginProject.getArtifacts().add(dependencyArtifact); - MavenSession session = mojos.newMavenSession(pluginProject); - session.setProjects(ImmutableList.of(dependencyProject, pluginProject)); - session.setCurrentProject(pluginProject); - mojos.executeMojo(session, pluginProject, "mojo-annotation-processor", newParameter("sourcepath", "reactorDependencies")); - mojos.executeMojo(session, pluginProject, "plugin-descriptor"); - mojos.assertBuildOutputs(plugin, "target/classes/META-INF/maven/plugin.xml", "target/classes/META-INF/m2e/lifecycle-mapping-metadata.xml"); - } - - @Test - public void testBuilderM2eMetadataGeneration() throws Exception { - File basedir = resources.getBasedir("plugin-descriptor/basic-builder"); - - MavenProject project = mojos.readMavenProject(basedir); - addDependencies(project, "apache-plugin-annotations-jar", "maven-plugin-api-jar", "takari-builder-jar"); - - generatePluginDescriptor(project); - - mojos.assertBuildOutputs(basedir, "target/classes/META-INF/maven/plugin.xml", "target/classes/META-INF/m2e/lifecycle-mapping-metadata.xml"); - assertFileContents(basedir, "expected/plugin.xml", "target/classes/META-INF/maven/plugin.xml"); - assertFileContents(basedir, "expected/lifecycle-mapping-metadata.xml", "target/classes/META-INF/m2e/lifecycle-mapping-metadata.xml"); - } - - @Test - public void testPluginEclipseMatadata() throws Exception { - // assert plugin hand-written m2e metadata is not mangled during the build - - File basedir = resources.getBasedir("plugin-descriptor/m2e-metadata"); - MavenProject project = mojos.readMavenProject(basedir); - addDependencies(project, "apache-plugin-annotations-jar", "maven-plugin-api-jar"); - - generatePluginDescriptor(project); - - mojos.assertBuildOutputs(basedir, "target/classes/META-INF/maven/plugin.xml", "target/classes/META-INF/m2e/lifecycle-mapping-metadata.xml"); - assertFileContents(basedir, "src/main/m2e/lifecycle-mapping-metadata.xml", "target/classes/META-INF/m2e/lifecycle-mapping-metadata.xml"); - } - - @Test - public void testPluginEclipseMatadataResource() throws Exception { - // assert plugin build fails if m2e metadata is present in one of resources directories - - File basedir = resources.getBasedir("plugin-descriptor/m2e-metadata"); - cp(basedir, "src/main/m2e/lifecycle-mapping-metadata.xml", "src/main/resources/META-INF/m2e/lifecycle-mapping-metadata.xml"); - rm(basedir, "src/main/m2e/lifecycle-mapping-metadata.xml"); - - MavenProject project = mojos.readMavenProject(basedir); - addDependencies(project, "apache-plugin-annotations-jar", "maven-plugin-api-jar"); - - try { - generatePluginDescriptor(project); - fail(); - } catch (MojoExecutionException expected) { - // TODO assert - System.out.println(expected.getMessage()); + + @Test + public void testJavadocInheritance_incremental() throws Exception { + File basedir = resources.getBasedir("plugin-descriptor/incremental-javadoc-inheritance"); + + MavenProject project = mojos.readMavenProject(basedir); + addDependencies(project, "apache-plugin-annotations-jar", "maven-plugin-api-jar"); + + generatePluginDescriptor(project); + mojos.assertBuildOutputs( + basedir, + "target/classes/META-INF/maven/plugin.xml", + "target/classes/META-INF/m2e/lifecycle-mapping-metadata.xml"); + assertFileContents(basedir, "expected/plugin.xml", "target/classes/META-INF/maven/plugin.xml"); + + cp( + basedir, + "src/main/java/io/takari/lifecycle/uts/plugindescriptor/AbstractBasicMojo.java-changed", + "src/main/java/io/takari/lifecycle/uts/plugindescriptor/AbstractBasicMojo.java"); + generatePluginDescriptor(project); + mojos.assertBuildOutputs( + basedir, + "target/classes/META-INF/maven/plugin.xml", + "target/classes/META-INF/m2e/lifecycle-mapping-metadata.xml"); + assertFileContents(basedir, "expected/plugin.xml-changed", "target/classes/META-INF/maven/plugin.xml"); + } + + @Test + public void testInheritance() throws Exception { + // the point of the test is to assert parameters/requirements inheritance + + // test classes are named such that parent mojo is merged before child mojo + // which causes duplicate parameters unless implementation handles this case + + File basedir = resources.getBasedir("plugin-descriptor/inheritance"); + MavenProject project = mojos.readMavenProject(basedir); + addDependencies(project, "apache-plugin-annotations-jar", "maven-plugin-api-jar"); + generatePluginDescriptor(project); + assertFileContents(basedir, "expected/plugin.xml", "target/classes/META-INF/maven/plugin.xml"); + } + + @Test + public void testUnreadableDependencyMojosXml() throws Exception { + // the point of this test is to assert the mojo does not throw exception when one of the dependencies cannot be + // read + // such dependencies are ignored by the compiler, so plugin.xml generation should ignore them too + + File basedir = resources.getBasedir("plugin-descriptor/basic"); + File bogusJar = new File(basedir, "bogus.jar"); + new FileOutputStream(bogusJar).close(); + + MavenProject project = mojos.readMavenProject(basedir); + addDependencies(project, "apache-plugin-annotations-jar", "maven-plugin-api-jar"); + addDependencies(project, bogusJar); + + generatePluginDescriptor(project); + } + + @Test + public void testIncrementalDependencyChange() throws Exception { + // the point of this test is to assert that non-structural dependency change does not force plugin.xml + // regeneration + + File basedir = resources.getBasedir("plugin-descriptor/incremental-dependency"); + File dependency = new File(basedir, "dependency"); + File plugin = new File(basedir, "plugin"); + + mojos.executeMojo(dependency, "compile"); + + MavenProject project = mojos.readMavenProject(plugin); + addDependencies(project, "apache-plugin-annotations-jar", "maven-plugin-api-jar"); + addDependencies(project, new File(dependency, "target/classes")); + generatePluginDescriptor(project); + mojos.assertBuildOutputs( + plugin, + "target/classes/META-INF/maven/plugin.xml", + "target/classes/META-INF/m2e/lifecycle-mapping-metadata.xml"); + + cp( + dependency, + "src/main/java/io/takari/lifecycle/uts/plugindescriptor/ComponentClass.java-private-change", + "src/main/java/io/takari/lifecycle/uts/plugindescriptor/ComponentClass.java"); + mojos.executeMojo(dependency, "compile"); + mojos.assertBuildOutputs( + dependency, "target/classes/io/takari/lifecycle/uts/plugindescriptor/ComponentClass.class"); + + mojos.executeMojo(project, "compile", newParameter("compilerId", "jdt")); + mojos.assertCarriedOverOutputs( + plugin, "target/classes/io/takari/lifecycle/uts/plugindescriptor/BasicMojo.class"); + + mojos.executeMojo(project, "mojo-annotation-processor"); + mojos.assertCarriedOverOutputs(plugin, "target/classes/META-INF/takari/mojos.xml"); + + mojos.executeMojo(project, "plugin-descriptor"); + mojos.assertCarriedOverOutputs( + plugin, + "target/classes/META-INF/maven/plugin.xml", + "target/classes/META-INF/m2e/lifecycle-mapping-metadata.xml"); + } + + @Test + public void testSourcepathDependency() throws Exception { + // assert that MojoAnnotationProcessorMojo honours sourcepath=reactorDependencies + + File basedir = resources.getBasedir("plugin-descriptor/sourcepath-dependency"); + File dependency = new File(basedir, "dependency"); + File plugin = new File(basedir, "plugin"); + + MavenProject dependencyProject = mojos.readMavenProject(dependency); + MavenProject pluginProject = mojos.readMavenProject(plugin); + addDependencies(pluginProject, "apache-plugin-annotations-jar", "maven-plugin-api-jar"); + mojos.newDependency(new File(dependencyProject.getBuild().getOutputDirectory())) // + .setGroupId(dependencyProject.getGroupId()) // + .setArtifactId(dependencyProject.getArtifactId()) // + .setVersion(dependencyProject.getVersion()) // + .addTo(pluginProject); + Artifact dependencyArtifact = dependencyProject.getArtifact(); + dependencyArtifact.setScope(Artifact.SCOPE_COMPILE); + pluginProject.getArtifacts().add(dependencyArtifact); + MavenSession session = mojos.newMavenSession(pluginProject); + session.setProjects(ImmutableList.of(dependencyProject, pluginProject)); + session.setCurrentProject(pluginProject); + mojos.executeMojo( + session, pluginProject, "mojo-annotation-processor", newParameter("sourcepath", "reactorDependencies")); + mojos.executeMojo(session, pluginProject, "plugin-descriptor"); + mojos.assertBuildOutputs( + plugin, + "target/classes/META-INF/maven/plugin.xml", + "target/classes/META-INF/m2e/lifecycle-mapping-metadata.xml"); + } + + @Test + public void testBuilderM2eMetadataGeneration() throws Exception { + File basedir = resources.getBasedir("plugin-descriptor/basic-builder"); + + MavenProject project = mojos.readMavenProject(basedir); + addDependencies(project, "apache-plugin-annotations-jar", "maven-plugin-api-jar", "takari-builder-jar"); + + generatePluginDescriptor(project); + + mojos.assertBuildOutputs( + basedir, + "target/classes/META-INF/maven/plugin.xml", + "target/classes/META-INF/m2e/lifecycle-mapping-metadata.xml"); + assertFileContents(basedir, "expected/plugin.xml", "target/classes/META-INF/maven/plugin.xml"); + assertFileContents( + basedir, + "expected/lifecycle-mapping-metadata.xml", + "target/classes/META-INF/m2e/lifecycle-mapping-metadata.xml"); + } + + @Test + public void testPluginEclipseMatadata() throws Exception { + // assert plugin hand-written m2e metadata is not mangled during the build + + File basedir = resources.getBasedir("plugin-descriptor/m2e-metadata"); + MavenProject project = mojos.readMavenProject(basedir); + addDependencies(project, "apache-plugin-annotations-jar", "maven-plugin-api-jar"); + + generatePluginDescriptor(project); + + mojos.assertBuildOutputs( + basedir, + "target/classes/META-INF/maven/plugin.xml", + "target/classes/META-INF/m2e/lifecycle-mapping-metadata.xml"); + assertFileContents( + basedir, + "src/main/m2e/lifecycle-mapping-metadata.xml", + "target/classes/META-INF/m2e/lifecycle-mapping-metadata.xml"); + } + + @Test + public void testPluginEclipseMatadataResource() throws Exception { + // assert plugin build fails if m2e metadata is present in one of resources directories + + File basedir = resources.getBasedir("plugin-descriptor/m2e-metadata"); + cp( + basedir, + "src/main/m2e/lifecycle-mapping-metadata.xml", + "src/main/resources/META-INF/m2e/lifecycle-mapping-metadata.xml"); + rm(basedir, "src/main/m2e/lifecycle-mapping-metadata.xml"); + + MavenProject project = mojos.readMavenProject(basedir); + addDependencies(project, "apache-plugin-annotations-jar", "maven-plugin-api-jar"); + + try { + generatePluginDescriptor(project); + fail(); + } catch (MojoExecutionException expected) { + // TODO assert + System.out.println(expected.getMessage()); + } } - } } diff --git a/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/resources/ResourcesTest.java b/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/resources/ResourcesTest.java index 4fb59d93..64580026 100644 --- a/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/resources/ResourcesTest.java +++ b/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/resources/ResourcesTest.java @@ -5,11 +5,12 @@ import static io.takari.maven.testing.TestResources.cp; import static io.takari.maven.testing.TestResources.rm; import static org.hamcrest.CoreMatchers.containsString; -import static org.hamcrest.CoreMatchers.endsWith; +import com.google.common.io.Files; +import io.takari.incrementalbuild.maven.testing.IncrementalBuildRule; +import io.takari.maven.testing.TestResources; import java.io.File; import java.nio.charset.Charset; - import org.apache.maven.execution.MavenSession; import org.apache.maven.plugin.MojoExecution; import org.apache.maven.plugin.MojoExecutionException; @@ -18,181 +19,178 @@ import org.junit.Rule; import org.junit.Test; -import com.google.common.io.Files; +public class ResourcesTest { -import io.takari.incrementalbuild.maven.testing.IncrementalBuildRule; -import io.takari.maven.testing.TestResources; + @Rule + public final TestResources resources = new TestResources(); -public class ResourcesTest { + @Rule + public final IncrementalBuildRule mojos = new IncrementalBuildRule(); + + @Test + public void resources() throws Exception { + File basedir = resources.getBasedir("resources/project-with-resources"); + mojos.executeMojo(basedir, "process-resources"); + File resource = new File(basedir, "target/classes/resource.txt"); + Assert.assertTrue(resource.exists()); + String line = Files.readFirstLine(resource, Charset.defaultCharset()); + Assert.assertTrue(line.contains("resource.txt")); + } + + @Test + public void resources_skip() throws Exception { + File basedir = resources.getBasedir("resources/project-with-resources"); + File resource = new File(basedir, "target/classes/resource.txt"); + + MavenProject project = mojos.readMavenProject(basedir); + MavenSession session = mojos.newMavenSession(project); + + MojoExecution execution = mojos.newMojoExecution("process-resources"); + execution.getConfiguration().addChild(newParameter("skip", "true")); + mojos.executeMojo(session, project, execution); + Assert.assertFalse(resource.exists()); + + mojos.executeMojo(basedir, "process-resources"); + Assert.assertTrue(resource.exists()); + + execution = mojos.newMojoExecution("process-resources"); + execution.getConfiguration().addChild(newParameter("skip", "true")); + mojos.executeMojo(session, project, execution); + Assert.assertTrue(resource.exists()); + } + + @Test + public void resourcesWithTargetPath() throws Exception { + File basedir = resources.getBasedir("resources/project-with-resources-with-target-path"); + mojos.executeMojo(basedir, "process-resources"); + File resource = new File(basedir, "target/classes/resources/targetPath/resource.txt"); + Assert.assertTrue(resource.exists()); + String line = Files.readFirstLine(resource, Charset.defaultCharset()); + Assert.assertTrue(line.contains("resource.txt")); + } + + @Test + public void resourcesWithFiltering() throws Exception { + File basedir = resources.getBasedir("resources/project-with-resources-filtered"); + mojos.executeMojo(basedir, "process-resources"); + assertFileContents(basedir, "expected-resource-empty.txt", "target/classes/resource.txt"); + } + + @Test + public void resourcesWithFilteringEmpty() throws Exception { + File basedir = resources.getBasedir("resources/project-with-resources-filtered"); + mojos.executeMojo(basedir, "process-resources", newParameter("missingPropertyAction", "empty")); + assertFileContents(basedir, "expected-resource-empty.txt", "target/classes/resource.txt"); + } + + @Test + public void resourcesWithFilteringLeave() throws Exception { + File basedir = resources.getBasedir("resources/project-with-resources-filtered"); + mojos.executeMojo(basedir, "process-resources", newParameter("missingPropertyAction", "leave")); + assertFileContents(basedir, "expected-resource-leave.txt", "target/classes/resource.txt"); + } + + @Test + public void resourcesWithFilteringFail() throws Exception { + File basedir = resources.getBasedir("resources/project-with-resources-filtered"); + try { + mojos.executeMojo(basedir, "process-resources", newParameter("missingPropertyAction", "fail")); + Assert.fail("Should fail with missing property"); + } catch (MojoExecutionException e) { + Assert.assertThat(e.getMessage(), containsString("Filtering: property 'nonExistant' not found")); + } + } + + @Test + public void resourcesWithProjectFilters() throws Exception { + File basedir = resources.getBasedir("resources/project-with-resources-filters"); + mojos.executeMojo(basedir, "process-resources"); + assertFileContents(basedir, "expected-resource.txt", "target/classes/resource.txt"); + } + + @Test + public void testCustomResources() throws Exception { + File basedir = resources.getBasedir("resources/project-with-custom-resources"); + mojos.executeMojo(basedir, "process-resources"); + mojos.assertBuildOutputs(basedir, "target/custom/custom.txt"); + } + + @Test + public void testRelativeResourcesDirectory() throws Exception { + File basedir = resources.getBasedir("resources/project-with-relative-resources-directory"); + mojos.executeMojo(basedir, "process-resources"); + mojos.assertBuildOutputs(basedir, "target/custom/custom.txt"); + } + + @Test + public void testIncremental() throws Exception { + File basedir = resources.getBasedir("resources/resources-incremental"); + + mojos.executeMojo(basedir, "process-resources"); + mojos.assertBuildOutputs(basedir, "target/classes/resource.txt"); + + // no change rebuild + mojos.executeMojo(basedir, "process-resources"); + mojos.assertCarriedOverOutputs(basedir, "target/classes/resource.txt"); + + // pom.xml change, non-filtered resources are carried over as-is + cp(basedir, "pom.xml-description", "pom.xml"); + mojos.executeMojo(basedir, "process-resources"); + mojos.assertCarriedOverOutputs(basedir, "target/classes/resource.txt"); + + // resource change + cp(basedir, "resource.txt-changed", "src/main/resources/resource.txt"); + mojos.executeMojo(basedir, "process-resources"); + mojos.assertBuildOutputs(basedir, "target/classes/resource.txt"); + + // resource delete + rm(basedir, "src/main/resources/resource.txt"); + mojos.executeMojo(basedir, "process-resources"); + mojos.assertDeletedOutputs(basedir, "target/classes/resource.txt"); + } + + @Test + public void testIncrementalFiltering() throws Exception { + File basedir = resources.getBasedir("resources/resources-incremental-filtering"); + + mojos.executeMojo(basedir, "process-resources"); + mojos.assertBuildOutputs(basedir, "target/classes/filtered-resource.txt"); + assertFileContents(basedir, "expected/filtered-resource.txt", "target/classes/filtered-resource.txt"); + + // no change rebuild, note that filtered resources are always processed + mojos.executeMojo(basedir, "process-resources"); + mojos.assertBuildOutputs(basedir, "target/classes/filtered-resource.txt"); + assertFileContents(basedir, "expected/filtered-resource.txt", "target/classes/filtered-resource.txt"); + + // pom change + cp(basedir, "pom.xml-description", "pom.xml"); + mojos.executeMojo(basedir, "process-resources"); + mojos.assertBuildOutputs(basedir, "target/classes/filtered-resource.txt"); + assertFileContents( + basedir, "expected/filtered-resource.txt-pomChanged", "target/classes/filtered-resource.txt"); + + // resource change + cp(basedir, "filtered-resource.txt-changed", "src/main/resources/filtered-resource.txt"); + mojos.executeMojo(basedir, "process-resources"); + mojos.assertBuildOutputs(basedir, "target/classes/filtered-resource.txt"); + assertFileContents( + basedir, "expected/filtered-resource.txt-resourceChanged", "target/classes/filtered-resource.txt"); + + // resource delete + rm(basedir, "src/main/resources/filtered-resource.txt"); + mojos.executeMojo(basedir, "process-resources"); + mojos.assertDeletedOutputs(basedir, "target/classes/filtered-resource.txt"); + } + + @Test + public void testBinaryResource() throws Exception { + File basedir = resources.getBasedir("resources/project-with-binary-resources"); + + mojos.executeMojo(basedir, "process-resources"); + mojos.assertBuildOutputs(basedir, "target/classes/resource.data"); - @Rule - public final TestResources resources = new TestResources(); - - @Rule - public final IncrementalBuildRule mojos = new IncrementalBuildRule(); - - @Test - public void resources() throws Exception { - File basedir = resources.getBasedir("resources/project-with-resources"); - mojos.executeMojo(basedir, "process-resources"); - File resource = new File(basedir, "target/classes/resource.txt"); - Assert.assertTrue(resource.exists()); - String line = Files.readFirstLine(resource, Charset.defaultCharset()); - Assert.assertTrue(line.contains("resource.txt")); - } - - @Test - public void resources_skip() throws Exception { - File basedir = resources.getBasedir("resources/project-with-resources"); - File resource = new File(basedir, "target/classes/resource.txt"); - - MavenProject project = mojos.readMavenProject(basedir); - MavenSession session = mojos.newMavenSession(project); - - MojoExecution execution = mojos.newMojoExecution("process-resources"); - execution.getConfiguration().addChild(newParameter("skip", "true")); - mojos.executeMojo(session, project, execution); - Assert.assertFalse(resource.exists()); - - mojos.executeMojo(basedir, "process-resources"); - Assert.assertTrue(resource.exists()); - - execution = mojos.newMojoExecution("process-resources"); - execution.getConfiguration().addChild(newParameter("skip", "true")); - mojos.executeMojo(session, project, execution); - Assert.assertTrue(resource.exists()); - } - - @Test - public void resourcesWithTargetPath() throws Exception { - File basedir = resources.getBasedir("resources/project-with-resources-with-target-path"); - mojos.executeMojo(basedir, "process-resources"); - File resource = new File(basedir, "target/classes/resources/targetPath/resource.txt"); - Assert.assertTrue(resource.exists()); - String line = Files.readFirstLine(resource, Charset.defaultCharset()); - Assert.assertTrue(line.contains("resource.txt")); - } - - @Test - public void resourcesWithFiltering() throws Exception { - File basedir = resources.getBasedir("resources/project-with-resources-filtered"); - mojos.executeMojo(basedir, "process-resources"); - assertFileContents(basedir, "expected-resource-empty.txt", "target/classes/resource.txt"); - } - - @Test - public void resourcesWithFilteringEmpty() throws Exception { - File basedir = resources.getBasedir("resources/project-with-resources-filtered"); - mojos.executeMojo(basedir, "process-resources", newParameter("missingPropertyAction", "empty")); - assertFileContents(basedir, "expected-resource-empty.txt", "target/classes/resource.txt"); - } - - @Test - public void resourcesWithFilteringLeave() throws Exception { - File basedir = resources.getBasedir("resources/project-with-resources-filtered"); - mojos.executeMojo(basedir, "process-resources", newParameter("missingPropertyAction", "leave")); - assertFileContents(basedir, "expected-resource-leave.txt", "target/classes/resource.txt"); - } - - @Test - public void resourcesWithFilteringFail() throws Exception { - File basedir = resources.getBasedir("resources/project-with-resources-filtered"); - try { - mojos.executeMojo(basedir, "process-resources", newParameter("missingPropertyAction", "fail")); - Assert.fail("Should fail with missing property"); - } catch (MojoExecutionException e) { - Assert.assertThat(e.getMessage(), containsString("Filtering: property 'nonExistant' not found")); + byte[] expected = Files.toByteArray(new File(basedir, "src/main/resources/resource.data")); + byte[] actual = Files.toByteArray(new File(basedir, "target/classes/resource.data")); + Assert.assertArrayEquals(expected, actual); } - } - - @Test - public void resourcesWithProjectFilters() throws Exception { - File basedir = resources.getBasedir("resources/project-with-resources-filters"); - mojos.executeMojo(basedir, "process-resources"); - assertFileContents(basedir, "expected-resource.txt", "target/classes/resource.txt"); - } - - @Test - public void testCustomResources() throws Exception { - File basedir = resources.getBasedir("resources/project-with-custom-resources"); - mojos.executeMojo(basedir, "process-resources"); - mojos.assertBuildOutputs(basedir, "target/custom/custom.txt"); - } - - @Test - public void testRelativeResourcesDirectory() throws Exception { - File basedir = resources.getBasedir("resources/project-with-relative-resources-directory"); - mojos.executeMojo(basedir, "process-resources"); - mojos.assertBuildOutputs(basedir, "target/custom/custom.txt"); - } - - @Test - public void testIncremental() throws Exception { - File basedir = resources.getBasedir("resources/resources-incremental"); - - mojos.executeMojo(basedir, "process-resources"); - mojos.assertBuildOutputs(basedir, "target/classes/resource.txt"); - - // no change rebuild - mojos.executeMojo(basedir, "process-resources"); - mojos.assertCarriedOverOutputs(basedir, "target/classes/resource.txt"); - - // pom.xml change, non-filtered resources are carried over as-is - cp(basedir, "pom.xml-description", "pom.xml"); - mojos.executeMojo(basedir, "process-resources"); - mojos.assertCarriedOverOutputs(basedir, "target/classes/resource.txt"); - - // resource change - cp(basedir, "resource.txt-changed", "src/main/resources/resource.txt"); - mojos.executeMojo(basedir, "process-resources"); - mojos.assertBuildOutputs(basedir, "target/classes/resource.txt"); - - // resource delete - rm(basedir, "src/main/resources/resource.txt"); - mojos.executeMojo(basedir, "process-resources"); - mojos.assertDeletedOutputs(basedir, "target/classes/resource.txt"); - } - - @Test - public void testIncrementalFiltering() throws Exception { - File basedir = resources.getBasedir("resources/resources-incremental-filtering"); - - mojos.executeMojo(basedir, "process-resources"); - mojos.assertBuildOutputs(basedir, "target/classes/filtered-resource.txt"); - assertFileContents(basedir, "expected/filtered-resource.txt", "target/classes/filtered-resource.txt"); - - // no change rebuild, note that filtered resources are always processed - mojos.executeMojo(basedir, "process-resources"); - mojos.assertBuildOutputs(basedir, "target/classes/filtered-resource.txt"); - assertFileContents(basedir, "expected/filtered-resource.txt", "target/classes/filtered-resource.txt"); - - // pom change - cp(basedir, "pom.xml-description", "pom.xml"); - mojos.executeMojo(basedir, "process-resources"); - mojos.assertBuildOutputs(basedir, "target/classes/filtered-resource.txt"); - assertFileContents(basedir, "expected/filtered-resource.txt-pomChanged", "target/classes/filtered-resource.txt"); - - // resource change - cp(basedir, "filtered-resource.txt-changed", "src/main/resources/filtered-resource.txt"); - mojos.executeMojo(basedir, "process-resources"); - mojos.assertBuildOutputs(basedir, "target/classes/filtered-resource.txt"); - assertFileContents(basedir, "expected/filtered-resource.txt-resourceChanged", "target/classes/filtered-resource.txt"); - - // resource delete - rm(basedir, "src/main/resources/filtered-resource.txt"); - mojos.executeMojo(basedir, "process-resources"); - mojos.assertDeletedOutputs(basedir, "target/classes/filtered-resource.txt"); - } - - @Test - public void testBinaryResource() throws Exception { - File basedir = resources.getBasedir("resources/project-with-binary-resources"); - - mojos.executeMojo(basedir, "process-resources"); - mojos.assertBuildOutputs(basedir, "target/classes/resource.data"); - - byte[] expected = Files.toByteArray(new File(basedir, "src/main/resources/resource.data")); - byte[] actual = Files.toByteArray(new File(basedir, "target/classes/resource.data")); - Assert.assertArrayEquals(expected, actual); - } } diff --git a/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/resources/TestResourcesTest.java b/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/resources/TestResourcesTest.java index 703067b3..90e7e9b9 100644 --- a/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/resources/TestResourcesTest.java +++ b/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/resources/TestResourcesTest.java @@ -1,50 +1,48 @@ package io.takari.maven.plugins.resources; import static io.takari.maven.testing.TestResources.assertFileContents; + +import com.google.common.io.Files; import io.takari.incrementalbuild.maven.testing.IncrementalBuildRule; import io.takari.maven.testing.TestResources; - import java.io.File; import java.nio.charset.Charset; - import org.junit.Assert; import org.junit.Rule; import org.junit.Test; -import com.google.common.io.Files; - public class TestResourcesTest { - @Rule - public final TestResources resources = new TestResources(); - - @Rule - public final IncrementalBuildRule mojos = new IncrementalBuildRule(); - - @Test - public void testResources() throws Exception { - File basedir = resources.getBasedir("resources/project-with-test-resources"); - mojos.executeMojo(basedir, "process-test-resources"); - File resource = new File(basedir, "target/test-classes/resource.txt"); - Assert.assertTrue(resource.exists()); - String line = Files.readFirstLine(resource, Charset.defaultCharset()); - Assert.assertTrue(line.contains("resource.txt")); - } - - @Test - public void testResourcesWithTargetPath() throws Exception { - File basedir = resources.getBasedir("resources/project-with-test-resources-with-target-path"); - mojos.executeMojo(basedir, "process-test-resources"); - File resource = new File(basedir, "target/test-classes/resources/targetPath/resource.txt"); - Assert.assertTrue(resource.exists()); - String line = Files.readFirstLine(resource, Charset.defaultCharset()); - Assert.assertTrue(line.contains("resource.txt")); - } - - @Test - public void testResourcesWithFiltering() throws Exception { - File basedir = resources.getBasedir("resources/project-with-test-resources-filtered"); - mojos.executeMojo(basedir, "process-test-resources"); - assertFileContents(basedir, "expected-resource.txt", "target/test-classes/resource.txt"); - } + @Rule + public final TestResources resources = new TestResources(); + + @Rule + public final IncrementalBuildRule mojos = new IncrementalBuildRule(); + + @Test + public void testResources() throws Exception { + File basedir = resources.getBasedir("resources/project-with-test-resources"); + mojos.executeMojo(basedir, "process-test-resources"); + File resource = new File(basedir, "target/test-classes/resource.txt"); + Assert.assertTrue(resource.exists()); + String line = Files.readFirstLine(resource, Charset.defaultCharset()); + Assert.assertTrue(line.contains("resource.txt")); + } + + @Test + public void testResourcesWithTargetPath() throws Exception { + File basedir = resources.getBasedir("resources/project-with-test-resources-with-target-path"); + mojos.executeMojo(basedir, "process-test-resources"); + File resource = new File(basedir, "target/test-classes/resources/targetPath/resource.txt"); + Assert.assertTrue(resource.exists()); + String line = Files.readFirstLine(resource, Charset.defaultCharset()); + Assert.assertTrue(line.contains("resource.txt")); + } + + @Test + public void testResourcesWithFiltering() throws Exception { + File basedir = resources.getBasedir("resources/project-with-test-resources-filtered"); + mojos.executeMojo(basedir, "process-test-resources"); + assertFileContents(basedir, "expected-resource.txt", "target/test-classes/resource.txt"); + } } diff --git a/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/sisu/SisuIndexTest.java b/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/sisu/SisuIndexTest.java index ec0f632a..0c9284d0 100644 --- a/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/sisu/SisuIndexTest.java +++ b/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/sisu/SisuIndexTest.java @@ -3,79 +3,77 @@ import static io.takari.maven.testing.TestResources.assertFileContents; import static io.takari.maven.testing.TestResources.cp; +import io.takari.incrementalbuild.maven.testing.IncrementalBuildRule; +import io.takari.maven.testing.TestProperties; +import io.takari.maven.testing.TestResources; import java.io.File; import java.io.IOException; - import org.apache.maven.project.MavenProject; import org.junit.Rule; import org.junit.Test; -import io.takari.incrementalbuild.maven.testing.IncrementalBuildRule; -import io.takari.maven.testing.TestProperties; -import io.takari.maven.testing.TestResources; - public class SisuIndexTest { - @Rule - public final TestResources resources = new TestResources(); - - @Rule - public final IncrementalBuildRule mojos = new IncrementalBuildRule(); - - public final TestProperties properties = new TestProperties(); - - @Test - public void testBasic() throws Exception { - File basedir = resources.getBasedir("sisu-index"); - MavenProject project = mojos.readMavenProject(basedir); - addJavaxInjectDependency(project); - - mojos.executeMojo(project, "compile"); - mojos.executeMojo(project, "sisu-index"); - mojos.assertBuildOutputs(basedir, "target/classes/META-INF/sisu/javax.inject.Named"); - assertSisuIndex(basedir, "classes", "sisu.Basic"); - - // no-change rebuild - mojos.executeMojo(project, "compile"); - mojos.executeMojo(project, "sisu-index"); - mojos.assertCarriedOverOutputs(basedir, "target/classes/META-INF/sisu/javax.inject.Named"); - assertSisuIndex(basedir, "classes", "sisu.Basic"); - - // introduce new type - cp(basedir, "src/main/java/sisu/Another.java-new", "src/main/java/sisu/Another.java"); - mojos.executeMojo(project, "compile"); - mojos.executeMojo(project, "sisu-index"); - mojos.assertBuildOutputs(basedir, "target/classes/META-INF/sisu/javax.inject.Named"); - assertSisuIndex(basedir, "classes", "sisu.Another", "sisu.Basic"); // note alphabetical order - - // remove annotation from existing type - cp(basedir, "src/main/java/sisu/Basic.java-removed", "src/main/java/sisu/Basic.java"); - mojos.executeMojo(project, "compile"); - mojos.executeMojo(project, "sisu-index"); - mojos.assertBuildOutputs(basedir, "target/classes/META-INF/sisu/javax.inject.Named"); - assertSisuIndex(basedir, "classes", "sisu.Another"); - } + @Rule + public final TestResources resources = new TestResources(); + + @Rule + public final IncrementalBuildRule mojos = new IncrementalBuildRule(); + + public final TestProperties properties = new TestProperties(); + + @Test + public void testBasic() throws Exception { + File basedir = resources.getBasedir("sisu-index"); + MavenProject project = mojos.readMavenProject(basedir); + addJavaxInjectDependency(project); + + mojos.executeMojo(project, "compile"); + mojos.executeMojo(project, "sisu-index"); + mojos.assertBuildOutputs(basedir, "target/classes/META-INF/sisu/javax.inject.Named"); + assertSisuIndex(basedir, "classes", "sisu.Basic"); + + // no-change rebuild + mojos.executeMojo(project, "compile"); + mojos.executeMojo(project, "sisu-index"); + mojos.assertCarriedOverOutputs(basedir, "target/classes/META-INF/sisu/javax.inject.Named"); + assertSisuIndex(basedir, "classes", "sisu.Basic"); + + // introduce new type + cp(basedir, "src/main/java/sisu/Another.java-new", "src/main/java/sisu/Another.java"); + mojos.executeMojo(project, "compile"); + mojos.executeMojo(project, "sisu-index"); + mojos.assertBuildOutputs(basedir, "target/classes/META-INF/sisu/javax.inject.Named"); + assertSisuIndex(basedir, "classes", "sisu.Another", "sisu.Basic"); // note alphabetical order + + // remove annotation from existing type + cp(basedir, "src/main/java/sisu/Basic.java-removed", "src/main/java/sisu/Basic.java"); + mojos.executeMojo(project, "compile"); + mojos.executeMojo(project, "sisu-index"); + mojos.assertBuildOutputs(basedir, "target/classes/META-INF/sisu/javax.inject.Named"); + assertSisuIndex(basedir, "classes", "sisu.Another"); + } - @Test - public void testTestIndex() throws Exception { - File basedir = resources.getBasedir("sisu-index"); - MavenProject project = mojos.readMavenProject(basedir); - addJavaxInjectDependency(project); + @Test + public void testTestIndex() throws Exception { + File basedir = resources.getBasedir("sisu-index"); + MavenProject project = mojos.readMavenProject(basedir); + addJavaxInjectDependency(project); - mojos.executeMojo(project, "testCompile"); - mojos.executeMojo(project, "sisu-test-index"); - mojos.assertBuildOutputs(basedir, "target/test-classes/META-INF/sisu/javax.inject.Named"); - assertSisuIndex(basedir, "test-classes", "sisu.BasicTest"); - } + mojos.executeMojo(project, "testCompile"); + mojos.executeMojo(project, "sisu-test-index"); + mojos.assertBuildOutputs(basedir, "target/test-classes/META-INF/sisu/javax.inject.Named"); + assertSisuIndex(basedir, "test-classes", "sisu.BasicTest"); + } - private void addJavaxInjectDependency(MavenProject project) throws Exception { - mojos.newDependency(new File(properties.get("java-injext-jar"))).addTo(project); - } + private void addJavaxInjectDependency(MavenProject project) throws Exception { + mojos.newDependency(new File(properties.get("java-injext-jar"))).addTo(project); + } - private void assertSisuIndex(File basedir, String output, String... types) throws IOException { - StringBuilder expected = new StringBuilder(); - for (String type : types) { - expected.append(type).append('\n'); + private void assertSisuIndex(File basedir, String output, String... types) throws IOException { + StringBuilder expected = new StringBuilder(); + for (String type : types) { + expected.append(type).append('\n'); + } + assertFileContents(expected.toString(), basedir, "target/" + output + "/" + SisuIndexMojo.PATH_SISU_INDEX); } - assertFileContents(expected.toString(), basedir, "target/" + output + "/" + SisuIndexMojo.PATH_SISU_INDEX); - } } diff --git a/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/testproperties/TestPropertiesMojoTest.java b/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/testproperties/TestPropertiesMojoTest.java index fda542ef..518f983c 100644 --- a/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/testproperties/TestPropertiesMojoTest.java +++ b/takari-lifecycle-plugin/src/test/java/io/takari/maven/plugins/testproperties/TestPropertiesMojoTest.java @@ -1,5 +1,14 @@ package io.takari.maven.plugins.testproperties; +import static io.takari.maven.testing.TestMavenRuntime.newParameter; +import static org.hamcrest.CoreMatchers.containsString; + +import com.google.common.base.Charsets; +import com.google.common.hash.HashCode; +import com.google.common.hash.Hashing; +import com.google.common.io.Files; +import io.takari.incrementalbuild.maven.testing.IncrementalBuildRule; +import io.takari.maven.testing.TestResources; import java.io.BufferedWriter; import java.io.File; import java.io.FileOutputStream; @@ -10,7 +19,6 @@ import java.util.Collections; import java.util.List; import java.util.Map; - import org.apache.maven.artifact.Artifact; import org.apache.maven.artifact.DefaultArtifact; import org.apache.maven.artifact.handler.ArtifactHandler; @@ -27,248 +35,260 @@ import org.junit.Test; import org.junit.rules.TemporaryFolder; -import com.google.common.base.Charsets; -import com.google.common.hash.HashCode; -import com.google.common.hash.Hashing; -import com.google.common.io.Files; +public class TestPropertiesMojoTest { + @Rule + public final TestResources resources = new TestResources(); + + @Rule + public final IncrementalBuildRule mojos = new IncrementalBuildRule(); + + @Rule + public final TemporaryFolder temp = new TemporaryFolder(); + + private MojoExecution newMojoExecution(Xpp3Dom... parameters) throws IOException { + MojoExecution execution = mojos.newMojoExecution("testProperties", parameters); + PluginDescriptor pluginDescriptor = execution.getMojoDescriptor().getPluginDescriptor(); + + ArtifactHandler handler = new DefaultArtifactHandler("jar"); + DefaultArtifact workspaceResolver = new DefaultArtifact( + "io.takari.m2e.workspace", + "org.eclipse.m2e.workspace.cli", + "1", + Artifact.SCOPE_COMPILE, + ".jar", + null, + handler); + workspaceResolver.setFile(new File("target/workspaceResolver.jar").getCanonicalFile()); + + List pluginArtifacts = new ArrayList<>(pluginDescriptor.getArtifacts()); + pluginArtifacts.add(workspaceResolver); + pluginDescriptor.setArtifacts(pluginArtifacts); + + return execution; + } -import io.takari.incrementalbuild.maven.testing.IncrementalBuildRule; -import io.takari.maven.testing.TestResources; + @Test + public void testIncremental() throws Exception { + File basedir = resources.getBasedir("testproperties/basic"); + final MavenProject project = mojos.readMavenProject(basedir); + MavenSession session = mojos.newMavenSession(project); + session.setProjectDependencyGraph(new ProjectDependencyGraph() { + @Override + public List getUpstreamProjects(MavenProject project, boolean transitive) { + return Collections.emptyList(); + } + + @Override + public List getSortedProjects() { + return Collections.singletonList(project); + } + + @Override + public List getDownstreamProjects(MavenProject project, boolean transitive) { + return Collections.emptyList(); + } + + @Override + public List getAllProjects() { + return Collections.emptyList(); + } + }); + + mojos.executeMojo(session, project, newMojoExecution()); + mojos.assertBuildOutputs(basedir, "target/test-classes/test.properties", "target/workspacestate.properties"); + + File testProperties = new File(basedir, "target/test-classes/test.properties"); + File workspaceState = new File(basedir, "target/workspacestate.properties"); + + long testPropertiesLastmodified = testProperties.lastModified(); + long workspaceStateLastmodified = workspaceState.lastModified(); + + HashCode testPropertiesSha1 = Files.hash(testProperties, Hashing.sha1()); + HashCode workspaceStateSha1 = Files.hash(workspaceState, Hashing.sha1()); + + mojos.executeMojo(session, project, newMojoExecution()); + // mojos.assertCarriedOverOutputs(basedir, "target/test-classes/test.properties", + // "target/workspacestate.properties"); + + Assert.assertEquals(testPropertiesLastmodified, testProperties.lastModified()); + Assert.assertEquals(workspaceStateLastmodified, workspaceState.lastModified()); + + Assert.assertEquals(testPropertiesSha1, sha1(basedir, "target/test-classes/test.properties")); + Assert.assertEquals(workspaceStateSha1, sha1(basedir, "target/workspacestate.properties")); + } -import static io.takari.maven.testing.TestMavenRuntime.newParameter; -import static org.hamcrest.CoreMatchers.containsString; + @Test + public void testOffline() throws Exception { + File basedir = resources.getBasedir("testproperties/basic"); -public class TestPropertiesMojoTest { - @Rule - public final TestResources resources = new TestResources(); + MavenProject project = mojos.readMavenProject(basedir); + MavenSession session = mojos.newMavenSession(project); - @Rule - public final IncrementalBuildRule mojos = new IncrementalBuildRule(); + session.getRequest().setOffline(true); + mojos.executeMojo(session, project, newMojoExecution()); + Assert.assertEquals("true", readProperties(basedir).get("offline")); - @Rule - public final TemporaryFolder temp = new TemporaryFolder(); - - private MojoExecution newMojoExecution(Xpp3Dom... parameters) throws IOException { - MojoExecution execution = mojos.newMojoExecution("testProperties", parameters); - PluginDescriptor pluginDescriptor = execution.getMojoDescriptor().getPluginDescriptor(); - - ArtifactHandler handler = new DefaultArtifactHandler("jar"); - DefaultArtifact workspaceResolver = new DefaultArtifact("io.takari.m2e.workspace", "org.eclipse.m2e.workspace.cli", "1", Artifact.SCOPE_COMPILE, ".jar", null, handler); - workspaceResolver.setFile(new File("target/workspaceResolver.jar").getCanonicalFile()); - - List pluginArtifacts = new ArrayList<>(pluginDescriptor.getArtifacts()); - pluginArtifacts.add(workspaceResolver); - pluginDescriptor.setArtifacts(pluginArtifacts); - - return execution; - } - - @Test - public void testIncremental() throws Exception { - File basedir = resources.getBasedir("testproperties/basic"); - final MavenProject project = mojos.readMavenProject(basedir); - MavenSession session = mojos.newMavenSession(project); - session.setProjectDependencyGraph(new ProjectDependencyGraph() { - @Override - public List getUpstreamProjects(MavenProject project, boolean transitive) { - return Collections.emptyList(); - } - - @Override - public List getSortedProjects() { - return Collections.singletonList(project); - } - - @Override - public List getDownstreamProjects(MavenProject project, boolean transitive) { - return Collections.emptyList(); - } - - @Override - public List getAllProjects() { - return Collections.emptyList(); - } - }); - - mojos.executeMojo(session, project, newMojoExecution()); - mojos.assertBuildOutputs(basedir, "target/test-classes/test.properties", "target/workspacestate.properties"); - - File testProperties = new File(basedir, "target/test-classes/test.properties"); - File workspaceState = new File(basedir, "target/workspacestate.properties"); - - long testPropertiesLastmodified = testProperties.lastModified(); - long workspaceStateLastmodified = workspaceState.lastModified(); - - HashCode testPropertiesSha1 = Files.hash(testProperties, Hashing.sha1()); - HashCode workspaceStateSha1 = Files.hash(workspaceState, Hashing.sha1()); - - mojos.executeMojo(session, project, newMojoExecution()); - // mojos.assertCarriedOverOutputs(basedir, "target/test-classes/test.properties", "target/workspacestate.properties"); - - Assert.assertEquals(testPropertiesLastmodified, testProperties.lastModified()); - Assert.assertEquals(workspaceStateLastmodified, workspaceState.lastModified()); - - Assert.assertEquals(testPropertiesSha1, sha1(basedir, "target/test-classes/test.properties")); - Assert.assertEquals(workspaceStateSha1, sha1(basedir, "target/workspacestate.properties")); - } - - @Test - public void testOffline() throws Exception { - File basedir = resources.getBasedir("testproperties/basic"); - - MavenProject project = mojos.readMavenProject(basedir); - MavenSession session = mojos.newMavenSession(project); - - session.getRequest().setOffline(true); - mojos.executeMojo(session, project, newMojoExecution()); - Assert.assertEquals("true", readProperties(basedir).get("offline")); - - session.getRequest().setOffline(false); - mojos.executeMojo(session, project, newMojoExecution()); - Assert.assertEquals("false", readProperties(basedir).get("offline")); - } - - @Test - public void testUpdateSnapshots() throws Exception { - File basedir = resources.getBasedir("testproperties/basic"); - - MavenProject project = mojos.readMavenProject(basedir); - MavenSession session = mojos.newMavenSession(project); - - session.getRequest().setUpdateSnapshots(true); - mojos.executeMojo(session, project, newMojoExecution()); - Assert.assertEquals("true", readProperties(basedir).get("updateSnapshots")); - - session.getRequest().setUpdateSnapshots(false); - mojos.executeMojo(session, project, newMojoExecution()); - Assert.assertEquals("false", readProperties(basedir).get("updateSnapshots")); - } - - @Test - public void testCustomTestPropertiesFile() throws Exception { - File basedir = resources.getBasedir("testproperties/custom-test-properties-file"); - MavenProject project = mojos.readMavenProject(basedir); - MavenSession session = mojos.newMavenSession(project); - - mojos.executeMojo(session, project, newMojoExecution()); - Assert.assertEquals("value", readProperties(basedir).get("custom")); - - TestResources.cp(basedir, "src/test/modified-test.properties", "src/test/test.properties"); - mojos.executeMojo(session, project, newMojoExecution()); - Assert.assertEquals("modified-value", readProperties(basedir).get("custom")); - } - - @Test - public void testMissingTestPropertiesEmpty() throws Exception { - File basedir = resources.getBasedir("testproperties/missing-test-properties"); - MavenProject project = mojos.readMavenProject(basedir); - MavenSession session = mojos.newMavenSession(project); - - mojos.executeMojo(session, project, newMojoExecution(newParameter("missingPropertyAction", "empty"))); - Assert.assertEquals("", readProperties(basedir).get("custom")); - } - - @Test - public void testMissingTestPropertiesLeave() throws Exception { - File basedir = resources.getBasedir("testproperties/missing-test-properties"); - MavenProject project = mojos.readMavenProject(basedir); - MavenSession session = mojos.newMavenSession(project); - - mojos.executeMojo(session, project, newMojoExecution(newParameter("missingPropertyAction", "leave"))); - Assert.assertEquals("${missing}", readProperties(basedir).get("custom")); - } - - @Test - public void testMissingTestPropertiesFail() throws Exception { - File basedir = resources.getBasedir("testproperties/missing-test-properties"); - MavenProject project = mojos.readMavenProject(basedir); - MavenSession session = mojos.newMavenSession(project); - - try { - mojos.executeMojo(session, project, newMojoExecution(newParameter("missingPropertyAction", "fail"))); - Assert.fail("Should fail with missing property"); - } catch (MojoExecutionException e) { - Assert.assertThat(e.getMessage(), containsString("Filtering: property 'missing' not found")); + session.getRequest().setOffline(false); + mojos.executeMojo(session, project, newMojoExecution()); + Assert.assertEquals("false", readProperties(basedir).get("offline")); } - } - - @Test - public void testWorkspaceStateIncludesThisProjectJarArtifact() throws Exception { - File basedir = resources.getBasedir(); - MavenProject project = mojos.readMavenProject(basedir); - MavenSession session = mojos.newMavenSession(project); - - mojos.executeMojo(session, project, newMojoExecution()); - Map state = TestResources.readProperties(basedir, "target/workspacestate.properties"); - - Assert.assertEquals(new File(basedir, "pom.xml").getCanonicalPath(), state.get("test:test:pom::1")); - Assert.assertEquals(new File(basedir, "target/classes").getCanonicalPath(), state.get("test:test:jar::1")); - } - - private HashCode sha1(File basedir, String path) throws IOException { - return Files.hash(new File(basedir, path), Hashing.sha1()); - } - - private Map readProperties(File basedir) throws IOException { - return TestResources.readProperties(basedir, "target/test-classes/test.properties"); - } - - @Test - public void testWorkspaceResolver() throws Exception { - File basedir = resources.getBasedir(); - MavenProject project = mojos.readMavenProject(basedir); - MavenSession session = mojos.newMavenSession(project); - mojos.newDependency(basedir).setGroupId("io.takari.m2e.workspace").setArtifactId("org.eclipse.m2e.workspace.cli").addTo(project); - mojos.executeMojo(session, project, newMojoExecution()); - Map properties = readProperties(basedir); - Assert.assertEquals(basedir.getCanonicalPath(), properties.get("workspaceResolver")); - } - - @Test - public void testDependencyProperties() throws Exception { - File basedir = resources.getBasedir(); - MavenProject project = mojos.readMavenProject(basedir); - MavenSession session = mojos.newMavenSession(project); - - Assert.assertTrue(new File(basedir, "src/test").mkdirs()); - - try (OutputStream os = new FileOutputStream(new File(basedir, "src/test/test.properties"))) { - BufferedWriter w = new BufferedWriter(new OutputStreamWriter(os, Charsets.UTF_8)); - w.write("ga=${g:a}"); - w.newLine(); - w.write("ga_tests=${g:a:tests}"); - w.newLine(); - w.flush(); + + @Test + public void testUpdateSnapshots() throws Exception { + File basedir = resources.getBasedir("testproperties/basic"); + + MavenProject project = mojos.readMavenProject(basedir); + MavenSession session = mojos.newMavenSession(project); + + session.getRequest().setUpdateSnapshots(true); + mojos.executeMojo(session, project, newMojoExecution()); + Assert.assertEquals("true", readProperties(basedir).get("updateSnapshots")); + + session.getRequest().setUpdateSnapshots(false); + mojos.executeMojo(session, project, newMojoExecution()); + Assert.assertEquals("false", readProperties(basedir).get("updateSnapshots")); } - File ga = temp.newFile().getCanonicalFile(); - File ga_tests = temp.newFile().getCanonicalFile(); + @Test + public void testCustomTestPropertiesFile() throws Exception { + File basedir = resources.getBasedir("testproperties/custom-test-properties-file"); + MavenProject project = mojos.readMavenProject(basedir); + MavenSession session = mojos.newMavenSession(project); - mojos.newDependency(ga).setGroupId("g").setArtifactId("a").addTo(project); - mojos.newDependency(ga_tests).setGroupId("g").setArtifactId("a").setClassifier("tests").addTo(project); + mojos.executeMojo(session, project, newMojoExecution()); + Assert.assertEquals("value", readProperties(basedir).get("custom")); - mojos.executeMojo(session, project, "testProperties"); + TestResources.cp(basedir, "src/test/modified-test.properties", "src/test/test.properties"); + mojos.executeMojo(session, project, newMojoExecution()); + Assert.assertEquals("modified-value", readProperties(basedir).get("custom")); + } - Map properties = readProperties(basedir); - Assert.assertEquals(ga.getCanonicalPath().replace('\\', '/'), properties.get("ga")); - Assert.assertEquals(ga_tests.getCanonicalPath().replace('\\', '/'), properties.get("ga_tests")); - } + @Test + public void testMissingTestPropertiesEmpty() throws Exception { + File basedir = resources.getBasedir("testproperties/missing-test-properties"); + MavenProject project = mojos.readMavenProject(basedir); + MavenSession session = mojos.newMavenSession(project); - @Test - public void testClasspathScope() throws Exception { - File basedir = resources.getBasedir(); - MavenProject project = mojos.readMavenProject(basedir); - MavenSession session = mojos.newMavenSession(project); + mojos.executeMojo(session, project, newMojoExecution(newParameter("missingPropertyAction", "empty"))); + Assert.assertEquals("", readProperties(basedir).get("custom")); + } - File providedScoped = temp.newFile("provided.jar").getCanonicalFile(); - File testScoped = temp.newFile("test.jar").getCanonicalFile(); + @Test + public void testMissingTestPropertiesLeave() throws Exception { + File basedir = resources.getBasedir("testproperties/missing-test-properties"); + MavenProject project = mojos.readMavenProject(basedir); + MavenSession session = mojos.newMavenSession(project); - mojos.newDependency(providedScoped).setGroupId("g").setArtifactId("provided").setScope("provided").addTo(project); - mojos.newDependency(testScoped).setGroupId("g").setArtifactId("test").setScope("test").addTo(project); + mojos.executeMojo(session, project, newMojoExecution(newParameter("missingPropertyAction", "leave"))); + Assert.assertEquals("${missing}", readProperties(basedir).get("custom")); + } + + @Test + public void testMissingTestPropertiesFail() throws Exception { + File basedir = resources.getBasedir("testproperties/missing-test-properties"); + MavenProject project = mojos.readMavenProject(basedir); + MavenSession session = mojos.newMavenSession(project); + + try { + mojos.executeMojo(session, project, newMojoExecution(newParameter("missingPropertyAction", "fail"))); + Assert.fail("Should fail with missing property"); + } catch (MojoExecutionException e) { + Assert.assertThat(e.getMessage(), containsString("Filtering: property 'missing' not found")); + } + } - mojos.executeMojo(session, project, "testProperties"); + @Test + public void testWorkspaceStateIncludesThisProjectJarArtifact() throws Exception { + File basedir = resources.getBasedir(); + MavenProject project = mojos.readMavenProject(basedir); + MavenSession session = mojos.newMavenSession(project); - Map properties = readProperties(basedir); - Assert.assertEquals(new File(basedir, "target/classes").getCanonicalPath(), properties.get("classpath")); - } + mojos.executeMojo(session, project, newMojoExecution()); + Map state = TestResources.readProperties(basedir, "target/workspacestate.properties"); + + Assert.assertEquals(new File(basedir, "pom.xml").getCanonicalPath(), state.get("test:test:pom::1")); + Assert.assertEquals(new File(basedir, "target/classes").getCanonicalPath(), state.get("test:test:jar::1")); + } + + private HashCode sha1(File basedir, String path) throws IOException { + return Files.hash(new File(basedir, path), Hashing.sha1()); + } + + private Map readProperties(File basedir) throws IOException { + return TestResources.readProperties(basedir, "target/test-classes/test.properties"); + } + + @Test + public void testWorkspaceResolver() throws Exception { + File basedir = resources.getBasedir(); + MavenProject project = mojos.readMavenProject(basedir); + MavenSession session = mojos.newMavenSession(project); + mojos.newDependency(basedir) + .setGroupId("io.takari.m2e.workspace") + .setArtifactId("org.eclipse.m2e.workspace.cli") + .addTo(project); + mojos.executeMojo(session, project, newMojoExecution()); + Map properties = readProperties(basedir); + Assert.assertEquals(basedir.getCanonicalPath(), properties.get("workspaceResolver")); + } + + @Test + public void testDependencyProperties() throws Exception { + File basedir = resources.getBasedir(); + MavenProject project = mojos.readMavenProject(basedir); + MavenSession session = mojos.newMavenSession(project); + + Assert.assertTrue(new File(basedir, "src/test").mkdirs()); + + try (OutputStream os = new FileOutputStream(new File(basedir, "src/test/test.properties"))) { + BufferedWriter w = new BufferedWriter(new OutputStreamWriter(os, Charsets.UTF_8)); + w.write("ga=${g:a}"); + w.newLine(); + w.write("ga_tests=${g:a:tests}"); + w.newLine(); + w.flush(); + } + + File ga = temp.newFile().getCanonicalFile(); + File ga_tests = temp.newFile().getCanonicalFile(); + + mojos.newDependency(ga).setGroupId("g").setArtifactId("a").addTo(project); + mojos.newDependency(ga_tests) + .setGroupId("g") + .setArtifactId("a") + .setClassifier("tests") + .addTo(project); + + mojos.executeMojo(session, project, "testProperties"); + + Map properties = readProperties(basedir); + Assert.assertEquals(ga.getCanonicalPath().replace('\\', '/'), properties.get("ga")); + Assert.assertEquals(ga_tests.getCanonicalPath().replace('\\', '/'), properties.get("ga_tests")); + } + + @Test + public void testClasspathScope() throws Exception { + File basedir = resources.getBasedir(); + MavenProject project = mojos.readMavenProject(basedir); + MavenSession session = mojos.newMavenSession(project); + + File providedScoped = temp.newFile("provided.jar").getCanonicalFile(); + File testScoped = temp.newFile("test.jar").getCanonicalFile(); + + mojos.newDependency(providedScoped) + .setGroupId("g") + .setArtifactId("provided") + .setScope("provided") + .addTo(project); + mojos.newDependency(testScoped) + .setGroupId("g") + .setArtifactId("test") + .setScope("test") + .addTo(project); + + mojos.executeMojo(session, project, "testProperties"); + + Map properties = readProperties(basedir); + Assert.assertEquals(new File(basedir, "target/classes").getCanonicalPath(), properties.get("classpath")); + } }