From 31425bf7863eac138db063062d19395b64349044 Mon Sep 17 00:00:00 2001 From: BJ Hargrave Date: Wed, 6 Jul 2022 19:00:50 -0400 Subject: [PATCH 1/2] maven/gradle: Fix project.output Builder property Both maven and gradle are updated to set the Builder's project.output to refer to the compiler's output directory. AKA the bin folder in Bnd workspace model builds. Signed-off-by: BJ Hargrave --- .../aQute/bnd/gradle/BundleTaskExtension.java | 19 ++++++++++++++++--- .../aQute/bnd/gradle/TestBundlePlugin.groovy | 12 ++++++------ .../it/jar-test-api-bundle/postbuild.groovy | 2 +- .../jar-test-wrapper-bundle/postbuild.groovy | 2 +- .../src/it/test-api-bundle/postbuild.groovy | 2 +- .../src/it/test-impl-bundle/postbuild.groovy | 2 +- .../it/test-wrapper-bundle/postbuild.groovy | 2 +- .../maven/plugin/AbstractBndMavenPlugin.java | 7 ++----- 8 files changed, 29 insertions(+), 19 deletions(-) diff --git a/gradle-plugins/biz.aQute.bnd.gradle/src/main/java/aQute/bnd/gradle/BundleTaskExtension.java b/gradle-plugins/biz.aQute.bnd.gradle/src/main/java/aQute/bnd/gradle/BundleTaskExtension.java index df09d6121c..d31f65b775 100644 --- a/gradle-plugins/biz.aQute.bnd.gradle/src/main/java/aQute/bnd/gradle/BundleTaskExtension.java +++ b/gradle-plugins/biz.aQute.bnd.gradle/src/main/java/aQute/bnd/gradle/BundleTaskExtension.java @@ -44,6 +44,7 @@ import org.gradle.api.Project; import org.gradle.api.Task; import org.gradle.api.file.ConfigurableFileCollection; +import org.gradle.api.file.DirectoryProperty; import org.gradle.api.file.FileCollection; import org.gradle.api.file.ProjectLayout; import org.gradle.api.file.RegularFileProperty; @@ -60,6 +61,7 @@ import org.gradle.api.tasks.PathSensitive; import org.gradle.api.tasks.SourceSet; import org.gradle.api.tasks.TaskInputFilePropertyBuilder; +import org.gradle.api.tasks.compile.AbstractCompile; import org.gradle.work.NormalizeLineEndings; /** @@ -185,6 +187,7 @@ public MapProperty getProperties() { private final ProjectLayout layout; private final File buildFile; private final ListProperty instructions; + private final DirectoryProperty outputDirectory; /** * Create a BundleTaskExtension for the specified Jar task. @@ -206,6 +209,7 @@ public BundleTaskExtension(org.gradle.api.tasks.bundling.Jar task) { bnd = instructions.map(list -> Strings.join("\n", list)); classpath = objects.fileCollection(); allSource = objects.fileCollection(); + outputDirectory = objects.directoryProperty(); SourceSet mainSourceSet = sourceSets(project).getByName(SourceSet.MAIN_SOURCE_SET_NAME); setSourceSet(mainSourceSet); classpath(mainSourceSet.getCompileClasspath()); @@ -331,6 +335,11 @@ public void setClasspath(Object path) { public void setSourceSet(SourceSet sourceSet) { getAllSource().setFrom(sourceSet.getAllSource() .getSourceDirectories()); + getOutputDirectory().value(getTask().getProject() + .getTasks() + .named(sourceSet.getCompileJavaTaskName(), AbstractCompile.class) + .flatMap(AbstractCompile::getDestinationDirectory)); + jarLibraryElements(getTask(), sourceSet.getCompileClasspathConfigurationName()); } @@ -342,6 +351,10 @@ File getBuildFile() { return buildFile; } + DirectoryProperty getOutputDirectory() { + return outputDirectory; + } + /** * The default value for the Bundle-SymbolicName manifest header. *

@@ -388,9 +401,9 @@ private class BuildAction implements Action { public void execute(Task t) { try { File projectDir = unwrapFile(getLayout().getProjectDirectory()); - File buildDir = unwrapFile(getLayout().getBuildDirectory()); + File outputDir = unwrapFile(getOutputDirectory()); File buildFile = getBuildFile(); - FileCollection sourcepath = getAllSource().filter(file -> file.exists()); + FileCollection sourcepath = getAllSource().filter(File::exists); Optional taskManifest = Optional .ofNullable(getTask().getManifest()); // create Builder @@ -436,7 +449,7 @@ public void execute(Task t) { } // this will cause project.dir property to be set builder.setProperties(temporaryBndFile, projectDir); - builder.setProperty("project.output", buildDir.getCanonicalPath()); + builder.setProperty("project.output", outputDir.getCanonicalPath()); // If no bundle to be built, we have nothing to do if (builder.is(Constants.NOBUNDLES)) { return; diff --git a/gradle-plugins/biz.aQute.bnd.gradle/src/test/groovy/aQute/bnd/gradle/TestBundlePlugin.groovy b/gradle-plugins/biz.aQute.bnd.gradle/src/test/groovy/aQute/bnd/gradle/TestBundlePlugin.groovy index ab81e4faf2..cbfefa5dd8 100644 --- a/gradle-plugins/biz.aQute.bnd.gradle/src/test/groovy/aQute/bnd/gradle/TestBundlePlugin.groovy +++ b/gradle-plugins/biz.aQute.bnd.gradle/src/test/groovy/aQute/bnd/gradle/TestBundlePlugin.groovy @@ -57,7 +57,7 @@ class TestBundlePlugin extends Specification { jartask_manifest.getValue("Bundle-Name") == "test.bnd.gradle:${testProject}" jartask_manifest.getValue("Project-Name") == "${testProject}" new File(jartask_manifest.getValue("Project-Dir")).canonicalFile == testProjectDir - new File(jartask_manifest.getValue("Project-Output")).canonicalFile == testProjectBuildDir + new File(jartask_manifest.getValue("Project-Output")).canonicalFile == new File(testProjectBuildDir, "classes/java/main").canonicalFile jartask_manifest.getValue("Project-Sourcepath") jartask_manifest.getValue("Project-Buildpath") jartask_manifest.getValue("Bundle-ClassPath") =~ /commons-lang-2\.6\.jar/ @@ -95,7 +95,7 @@ class TestBundlePlugin extends Specification { bundletask_manifest.getValue("Bundle-Name") == "test.bnd.gradle:${testProject}-bundle" bundletask_manifest.getValue("Project-Name") == "${testProject}" new File(bundletask_manifest.getValue("Project-Dir")).canonicalFile == testProjectDir - new File(bundletask_manifest.getValue("Project-Output")).canonicalFile == testProjectBuildDir + new File(bundletask_manifest.getValue("Project-Output")).canonicalFile == new File(testProjectBuildDir, "classes/java/test").canonicalFile bundletask_manifest.getValue("Project-Sourcepath") bundletask_manifest.getValue("Project-Buildpath") bundletask_manifest.getValue("Bundle-ClassPath") =~ /commons-lang-2\.6\.jar/ @@ -207,7 +207,7 @@ class TestBundlePlugin extends Specification { jartask_manifest.getValue("Bundle-Name") == "test.bnd.gradle:${testProject}" jartask_manifest.getValue("Project-Name") == "${testProject}" new File(jartask_manifest.getValue("Project-Dir")).canonicalFile == testProjectDir - new File(jartask_manifest.getValue("Project-Output")).canonicalFile == testProjectBuildDir + new File(jartask_manifest.getValue("Project-Output")).canonicalFile == new File(testProjectBuildDir, "classes/java/main").canonicalFile jartask_manifest.getValue("Project-Sourcepath") jartask_manifest.getValue("Project-Buildpath") jartask_manifest.getValue("Bundle-ClassPath") =~ /commons-lang-2\.6\.jar/ @@ -244,7 +244,7 @@ class TestBundlePlugin extends Specification { bundletask_manifest.getValue("Bundle-Name") == "test.bnd.gradle:${testProject}-bundle" bundletask_manifest.getValue("Project-Name") == "${testProject}" new File(bundletask_manifest.getValue("Project-Dir")).canonicalFile == testProjectDir - new File(bundletask_manifest.getValue("Project-Output")).canonicalFile == testProjectBuildDir + new File(bundletask_manifest.getValue("Project-Output")).canonicalFile == new File(testProjectBuildDir, "classes/java/test").canonicalFile bundletask_manifest.getValue("Project-Sourcepath") bundletask_manifest.getValue("Project-Buildpath") bundletask_manifest.getValue("Bundle-ClassPath") =~ /commons-lang-2\.6\.jar/ @@ -316,7 +316,7 @@ class TestBundlePlugin extends Specification { jartask_manifest.getValue("Bundle-Name") == "test.bnd.gradle:${testProject}" jartask_manifest.getValue("Project-Name") == "${testProject}" new File(jartask_manifest.getValue("Project-Dir")).canonicalFile == testProjectDir - new File(jartask_manifest.getValue("Project-Output")).canonicalFile == testProjectBuildDir + new File(jartask_manifest.getValue("Project-Output")).canonicalFile == new File(testProjectBuildDir, "classes/java/main").canonicalFile jartask_manifest.getValue("Project-Sourcepath") jartask_manifest.getValue("Project-Buildpath") jartask_manifest.getValue("Gradle-Project-Prop") == "prop.project" @@ -353,7 +353,7 @@ class TestBundlePlugin extends Specification { bundletask_manifest.getValue("Bundle-Name") == "test.bnd.gradle:${testProject}-overridden" bundletask_manifest.getValue("Project-Name") == "${testProject}" new File(bundletask_manifest.getValue("Project-Dir")).canonicalFile == testProjectDir - new File(bundletask_manifest.getValue("Project-Output")).canonicalFile == testProjectBuildDir + new File(bundletask_manifest.getValue("Project-Output")).canonicalFile == new File(testProjectBuildDir, "classes/java/test").canonicalFile bundletask_manifest.getValue("Project-Sourcepath") bundletask_manifest.getValue("Project-Buildpath") bundletask_manifest.getValue("Here") == testProjectDir.absolutePath.replace(File.separatorChar, (char)'/') diff --git a/maven/bnd-maven-plugin/src/it/jar-test-api-bundle/postbuild.groovy b/maven/bnd-maven-plugin/src/it/jar-test-api-bundle/postbuild.groovy index 0e9c081dde..63bef0fb27 100644 --- a/maven/bnd-maven-plugin/src/it/jar-test-api-bundle/postbuild.groovy +++ b/maven/bnd-maven-plugin/src/it/jar-test-api-bundle/postbuild.groovy @@ -29,7 +29,7 @@ assert manifest.getValue('X-IncludedParentProjectProperty') == 'Included via -in // Check bnd properties assert manifest.getValue('Project-Name') == 'Test API Bundle' assert manifest.getValue('Project-Dir') == basedir.absolutePath.replace(File.separatorChar, '/' as char) -assert manifest.getValue('Project-Output') == new File(basedir, "target").absolutePath +assert manifest.getValue('Project-Output') == new File(basedir, "target/classes").absolutePath assert manifest.getValue('Project-Buildpath') assert manifest.getValue('Project-Sourcepath') assert manifest.getValue('Here') == basedir.absolutePath.replace(File.separatorChar, '/' as char) diff --git a/maven/bnd-maven-plugin/src/it/jar-test-wrapper-bundle/postbuild.groovy b/maven/bnd-maven-plugin/src/it/jar-test-wrapper-bundle/postbuild.groovy index 6e439bed13..91860c5086 100644 --- a/maven/bnd-maven-plugin/src/it/jar-test-wrapper-bundle/postbuild.groovy +++ b/maven/bnd-maven-plugin/src/it/jar-test-wrapper-bundle/postbuild.groovy @@ -37,7 +37,7 @@ assert manifest.getValue('X-IncludedProperty') == 'Included via -include in proj // Check bnd properties assert manifest.getValue('Project-Name') == moduleDir assert manifest.getValue('Project-Dir') == basedir.absolutePath.replace(File.separatorChar, '/' as char) -assert manifest.getValue('Project-Output') == new File(basedir, "target").absolutePath +assert manifest.getValue('Project-Output') == new File(basedir, "target/classes").absolutePath assert manifest.getValue('Project-Buildpath') assert !manifest.getValue('Project-Sourcepath') assert manifest.getValue('Parent-Here') == new File(basedir, '../jar-parent').canonicalPath.replace(File.separatorChar, '/' as char) diff --git a/maven/bnd-maven-plugin/src/it/test-api-bundle/postbuild.groovy b/maven/bnd-maven-plugin/src/it/test-api-bundle/postbuild.groovy index 69f694d0a0..8d6ecc82ad 100644 --- a/maven/bnd-maven-plugin/src/it/test-api-bundle/postbuild.groovy +++ b/maven/bnd-maven-plugin/src/it/test-api-bundle/postbuild.groovy @@ -24,7 +24,7 @@ assert api_manifest.getValue('X-IncludedParentProjectProperty') == 'Included via // Check bnd properties assert api_manifest.getValue('Project-Name') == 'Test API Bundle' assert api_manifest.getValue('Project-Dir') == basedir.absolutePath.replace(File.separatorChar, '/' as char) -assert api_manifest.getValue('Project-Output') == new File(basedir, 'target').absolutePath +assert api_manifest.getValue('Project-Output') == new File(basedir, 'target/classes').absolutePath assert api_manifest.getValue('Project-Buildpath') assert api_manifest.getValue('Project-Sourcepath') assert api_manifest.getValue('Here') == basedir.absolutePath.replace(File.separatorChar, '/' as char) diff --git a/maven/bnd-maven-plugin/src/it/test-impl-bundle/postbuild.groovy b/maven/bnd-maven-plugin/src/it/test-impl-bundle/postbuild.groovy index 261cb4983a..cf9352d422 100644 --- a/maven/bnd-maven-plugin/src/it/test-impl-bundle/postbuild.groovy +++ b/maven/bnd-maven-plugin/src/it/test-impl-bundle/postbuild.groovy @@ -35,7 +35,7 @@ assert impl_manifest.getValue('SomeParentVar') == 'parentValue' // Check bnd properties assert impl_manifest.getValue('Project-Name') == 'test-impl-bundle' assert impl_manifest.getValue('Project-Dir') == basedir.absolutePath.replace(File.separatorChar, '/' as char) -assert impl_manifest.getValue('Project-Output') == new File(basedir, 'target').absolutePath +assert impl_manifest.getValue('Project-Output') == new File(basedir, 'target/classes').absolutePath assert impl_manifest.getValue('Project-Buildpath') assert impl_manifest.getValue('Project-Sourcepath') assert impl_manifest.getValue('Parent-Here') == new File(basedir, "../process-parent").canonicalPath.replace(File.separatorChar, '/' as char) diff --git a/maven/bnd-maven-plugin/src/it/test-wrapper-bundle/postbuild.groovy b/maven/bnd-maven-plugin/src/it/test-wrapper-bundle/postbuild.groovy index c68adef719..c28f1aefb5 100644 --- a/maven/bnd-maven-plugin/src/it/test-wrapper-bundle/postbuild.groovy +++ b/maven/bnd-maven-plugin/src/it/test-wrapper-bundle/postbuild.groovy @@ -26,7 +26,7 @@ assert wrapper_manifest.getValue('X-IncludedProperty') == 'Included via -include /// Check bnd properties assert wrapper_manifest.getValue('Project-Name') == 'test-wrapper-bundle' assert wrapper_manifest.getValue('Project-Dir') == basedir.absolutePath.replace(File.separatorChar, '/' as char) -assert wrapper_manifest.getValue('Project-Output') == new File(basedir, 'target').absolutePath +assert wrapper_manifest.getValue('Project-Output') == new File(basedir, 'target/classes').absolutePath assert wrapper_manifest.getValue('Project-Buildpath') assert !wrapper_manifest.getValue('Project-Sourcepath') assert wrapper_manifest.getValue('Parent-Here') == new File(basedir, "../process-parent").canonicalPath.replace(File.separatorChar, '/' as char) diff --git a/maven/bnd-maven-plugin/src/main/java/aQute/bnd/maven/plugin/AbstractBndMavenPlugin.java b/maven/bnd-maven-plugin/src/main/java/aQute/bnd/maven/plugin/AbstractBndMavenPlugin.java index a82151f583..2ef5e12a1f 100644 --- a/maven/bnd-maven-plugin/src/main/java/aQute/bnd/maven/plugin/AbstractBndMavenPlugin.java +++ b/maven/bnd-maven-plugin/src/main/java/aQute/bnd/maven/plugin/AbstractBndMavenPlugin.java @@ -93,9 +93,6 @@ public abstract class AbstractBndMavenPlugin extends AbstractMojo { static final String TSTAMP = "${tstamp}"; static final String SNAPSHOT = "SNAPSHOT"; - @Parameter(defaultValue = "${project.build.directory}", readonly = true) - File buildDir; - /** * Whether to include the contents of the {@code classesDir} directory * in the generated bundle. @@ -174,7 +171,7 @@ public abstract class AbstractBndMavenPlugin extends AbstractMojo { MavenProjectHelper projectHelper; @Component - private ArtifactHandlerManager artifactHandlerManager; + ArtifactHandlerManager artifactHandlerManager; File propertiesFile; @@ -235,7 +232,7 @@ public void execute() throws MojoExecutionException, MojoFailureException { builder.setBase(project.getBasedir()); propertiesFile = loadProperties(builder); - builder.setProperty("project.output", buildDir.getCanonicalPath()); + builder.setProperty("project.output", getClassesDir().getCanonicalPath()); // If no bundle to be built, we have nothing to do if (Processor.isTrue(builder.getProperty(Constants.NOBUNDLES))) { From d5f4b987c3b3df2ab54a9396303fcc4ad5273cff Mon Sep 17 00:00:00 2001 From: BJ Hargrave Date: Wed, 6 Jul 2022 19:23:31 -0400 Subject: [PATCH 2/2] maven: Fix packaging goals to put artifact in outputDir Allow the user to configure the outputDir like maven-jar/war-plugins. The default outputDir for the packaging goals is project.build.directory (aka. `target`). The README is also updated. Signed-off-by: BJ Hargrave --- maven/bnd-maven-plugin/README.md | 56 +++++++++++-------- .../maven/plugin/AbstractBndMavenPlugin.java | 26 +++++---- .../maven/plugin/BndMavenPackagingPlugin.java | 13 ++++- .../plugin/BndMavenPackagingTestsPlugin.java | 13 ++++- 4 files changed, 73 insertions(+), 35 deletions(-) diff --git a/maven/bnd-maven-plugin/README.md b/maven/bnd-maven-plugin/README.md index 0ff2be0814..88cd512d7d 100644 --- a/maven/bnd-maven-plugin/README.md +++ b/maven/bnd-maven-plugin/README.md @@ -47,13 +47,15 @@ The `jar` goal is not executed by default, therefore at least one explicit execu |-------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | `bndfile` | File path to a bnd file containing bnd instructions for this project. The file path can be either absolute or relative to the project directory. _Defaults to `bnd.bnd`_. | | `bnd` | Bnd instructions for this project specified directly in the pom file. This is generally be done using a `` section. If the projects has a `bndfile` configuration property or a file in the default location `bnd.bnd`, then this configuration element is ignored. | -| `classifier` | A string added to the artifact indicating a supplemental artifact produced by the project. If no value is provided it indicates the main artifact produced by the project. _Defaults to no value_. ||`manifestPath` | Specify the path to a manifest file to use. _Defaults to `${project.build.outputDirectory}/META-INF/MANIFEST.MF`._| +| `classifier` | A string added to the artifact indicating a supplemental artifact produced by the project. If no value is provided it indicates the main artifact produced by the project. _Defaults to no value_. | | `classesDir` | The directory where the `maven-compiler-plugin` places its output. _Defaults to `${project.build.outputDirectory}`._ | | `includeClassesDir` | Include the entire contents of `classesDir` in the bundle. *Defaults to `true`*. | -| `outputDir` | The directory where the `bnd-maven-plugin` will extract it's contents. _Defaults to `${project.build.outputDirectory}`._ | +| `outputDir` | The directory where this goal will store the generated artifact. _Defaults to `${project.build.directory}`._ | +| `webappDirectory` | The directory where the webapp is built when packaging is `war`. _Defaults to `${project.build.directory}/${project.build.finalName}`._ | | `packagingTypes` | The list of maven packaging types for which the plugin will execute. *Defaults to `jar,war`*. Override with property `bnd.packagingTypes`. | | `skip` | Skip the project. _Defaults to `false`._ Override with property `bnd.skip`. | -| `skipIfEmpty` | Skip processing if `includeClassesDir` is `true` and the `${project.build.outputDirectory}` is empty. _Defaults to `false`._ Override with property `bnd.skipIfEmpty`. | +| `skipIfEmpty` | Skip processing if `includeClassesDir` is `true` and `classesDir` is empty. _Defaults to `false`._ Override with property `bnd.skipIfEmpty`. | +| `outputTimestamp` | Timestamp for [reproducible][1] output archive entries, either formatted as ISO 8601 `yyyy-MM-dd'T'HH:mm:ssXXX` or as an int representing seconds since the epoch. _Defaults to `${project.build.outputTimestamp}`_. | **No additional packaging plugins are necessary when using the `jar` goal.** @@ -96,14 +98,15 @@ The `bnd-process` is not executed by default, therefore at least one explicit ex |-------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | `bndfile` | File path to a bnd file containing bnd instructions for this project. The file path can be either absolute or relative to the project directory. _Defaults to `bnd.bnd`_. | | `bnd` | Bnd instructions for this project specified directly in the pom file. This is generally be done using a `` section. If the projects has a `bndfile` configuration property or a file in the default location `bnd.bnd`, then this configuration element is ignored. | -| `manifestPath` | Specify the path to a manifest file to use. _Defaults to `${project.build.outputDirectory}/META-INF/MANIFEST.MF`._ | +| `manifestPath` | Specify the path to store the generated manifest file. _Defaults to `${project.build.outputDirectory}/META-INF/MANIFEST.MF`._ | | `classesDir` | The directory where the `maven-compiler-plugin` places its output. _Defaults to `${project.build.outputDirectory}`._ | | `includeClassesDir` | Include the entire contents of `classesDir` in the bundle. *Defaults to `true`*. | -| `outputDir` | The directory where the `bnd-maven-plugin` will extract it's contents. _Defaults to `${project.build.outputDirectory}`._ | +| `outputDir` | The directory where this goal will store its output. _Defaults to `${project.build.outputDirectory}`._ | | `webappDirectory` | The directory where the webapp is built when packaging is `war`. _Defaults to `${project.build.directory}/${project.build.finalName}`._ | | `packagingTypes` | The list of maven packaging types for which the plugin will execute. *Defaults to `jar,war`*. Override with property `bnd.packagingTypes`. | | `skip` | Skip the project. _Defaults to `false`._ Override with property `bnd.skip`. | -| `skipIfEmpty` | Skip processing if `includeClassesDir` is `true` and the `${project.build.outputDirectory}` is empty. _Defaults to `false`._ Override with property `bnd.skipIfEmpty`. | +| `skipIfEmpty` | Skip processing if `includeClassesDir` is `true` and the `classesDir` is empty. _Defaults to `false`._ Override with property `bnd.skipIfEmpty`. | +| `outputTimestamp` | Timestamp for [reproducible][1] output archive entries, either formatted as ISO 8601 `yyyy-MM-dd'T'HH:mm:ssXXX` or as an int representing seconds since the epoch. _Defaults to `${project.build.outputTimestamp}`_. | ### IMPORTANT NOTE about Maven JAR|WAR Plugin @@ -154,16 +157,16 @@ It is also supported to specify the Bnd instructions embedded in the pom file. T **Note**: Deep indentation of the `` content to match the xml indentation functions perfectly well. -The contents of `${project.build.outputDirectory}` is always included as input to the plugin (*i.e. placed in the bnd builder's classpath*). +The contents of `classesDir` is made available as input to the plugin (*i.e. placed in the bnd builder's classpath*). -Optionally, the plugin adds the entire content of `${project.build.outputDirectory}` to the bundle content (but no other packages from the build path). This behavior is **enabled** by default. (*See `includeClassesDir` configuration parameter*). +Optionally, the plugin adds the entire content of `classesDir` to the bundle content (but no other packages from the build path). This behavior is **enabled** by default. (*See `includeClassesDir` configuration parameter*). For further usage information, see the integration test projects under the included `src/it` directory. ### Default Bundle Headers -The plugin will by default set some OSGi bundle headers derived from [pom elements](https://maven.apache.org/pom.html) (if not overwritten with explicit bnd instructions). +The plugin will by default set some OSGi bundle headers derived from [pom elements][2] (if not overwritten with explicit bnd instructions). | OSGi Header | Derived from POM Element | |-----------------------|-----------------------------------------------------------------| @@ -171,7 +174,7 @@ The plugin will by default set some OSGi bundle headers derived from [pom elemen | `Bundle-Name` | `name` | | `Bundle-Version` | `version` | | `Bundle-Description` | `description` | -| `Bundle-Vendor` | `organisation.name` | +| `Bundle-Vendor` | `organization.name` | | `Bundle-License` | `licenses` | | `Bundle-SCM` | `scm` | | `Bundle-Developers` | `developers` (child element `id` must be set on each developer) | @@ -179,9 +182,9 @@ The plugin will by default set some OSGi bundle headers derived from [pom elemen ### Reproducible Builds -If the Maven project property `project.build.outputTimestamp` is set, indicating [reproducible builds](https://maven.apache.org/guides/mini/guide-reproducible-builds.html), this plugin will automatically use the following Bnd instructions, if not otherwise configured. +If the configuration parameter `outputTimestamp` is set, indicating [reproducible][1] output, this plugin will automatically use the following Bnd instructions, if not otherwise configured. -To support reproducible builds, the following Bnd instructions need to be configured: +To support reproducible output, the following Bnd instructions need to be configured: ```properties -noextraheaders: true @@ -202,7 +205,7 @@ The plugin has 6 distinct usage scenarios broken into two groups. Given executions using the `jar` goal we have the following 3 cases: -1. The common case where very little configuration is required; inputs and outputs are based on defaults. Bnd performs its analysis and enhances the jar with OSGi metadata obtained through introspection of classes, resources, dependencies, and [OSGi bundle annotations](https://osgi.org/specification/osgi.core/7.0.0/framework.api.html#org.osgi.annotation.bundle): +1. The common case where very little configuration is required; inputs and outputs are based on defaults. Bnd performs its analysis and enhances the jar with OSGi metadata obtained through introspection of classes, resources, dependencies, and [OSGi bundle annotations][3]: ```xml @@ -246,7 +249,7 @@ Given executions using the `jar` goal we have the following 3 cases: Given executions using the `bnd-process` goal we have the following 3 cases: -1. The common case is that very little configuration is required; inputs and outputs are based on defaults. Bnd performs its analysis and enhances the jar with OSGi metadata obtained through introspection of classes, resources, dependencies, and [OSGi bundle annotations](https://osgi.org/specification/osgi.core/7.0.0/framework.api.html#org.osgi.annotation.bundle): +1. The common case is that very little configuration is required; inputs and outputs are based on defaults. Bnd performs its analysis and enhances the jar with OSGi metadata obtained through introspection of classes, resources, dependencies, and [OSGi bundle annotations][3]: ```xml @@ -354,17 +357,19 @@ The `test-jar` goal is not executed by default, therefore at least one explicit | `bndfile` | File path to a bnd file containing bnd instructions for this project. The file path can be either absolute or relative to the project directory. _Defaults to `bnd.bnd`_. | | `bnd` | Bnd instructions for this project specified directly in the pom file. This is generally be done using a `` section. If the projects has a `bndfile` configuration property or a file in the default location `bnd.bnd`, then this configuration element is ignored. | | `classifier` | A string added to the artifact indicating a supplemental artifact produced by the project. _Defaults to `tests`_. | +| `classesDir` | The directory where the `maven-compiler-plugin` places its output. _Defaults to `${project.build.testOutputDirectory}`._ | | `includeClassesDir` | Include the entire contents of `classesDir` in the bundle. *Defaults to `true`*. | -| `skip` | Skip the goal. _Defaults to `false`._ Override with property `bnd-tests.skip` or `maven.test.skip`. | | `artifactFragment` | If true, make the tests artifact a fragment using `${project.artifactId}` as the `Fragment-Host` header and setting the `Bundle-SymbolicName` of the tests artifact to `${project.artifactId}-tests`. *Defaults to `false`*. | | `testCases` | Specify the filter that will determine which classes to identify as test cases. *Defaults to `junit5`*. See [Test Cases](#test-cases). | -| `skipIfEmpty` | Skip processing if `includeClassesDir` is `true` and the `${project.build.testOutputDirectory}` is empty. _Defaults to `false`._ Override with property `bnd.skipIfEmpty`. | +| `skip` | Skip the goal. _Defaults to `false`._ Override with property `bnd-tests.skip` or `maven.test.skip`. | +| `skipIfEmpty` | Skip processing if `includeClassesDir` is `true` and the `classesDir` is empty. _Defaults to `false`._ Override with property `bnd.skipIfEmpty`. | +| `outputDir` | The directory where this goal will store the generated artifact. _Defaults to `${project.build.directory}`._ | +| `packagingTypes` | The list of maven packaging types for which the plugin will execute. *Defaults to `jar,war`*. Override with property `bnd.packagingTypes`. | +| `outputTimestamp` | Timestamp for [reproducible][1] output archive entries, either formatted as ISO 8601 `yyyy-MM-dd'T'HH:mm:ssXXX` or as an int representing seconds since the epoch. _Defaults to `${project.build.outputTimestamp}`_. | Some details are predefined for simplicity: - `${project.build.testSourceDirectory}` is used as the source directory - `${project.build.testResources}` is used as the resources directory -- `${project.build.testOutputDirectory}` is used as the source of input for bnd to analyse -- `${project.build.testOutputDirectory}/META-INF/MANIFEST.MF` is used as the manifest path **No additional packaging plugins are necessary when using the `test-jar` goal.** @@ -395,17 +400,20 @@ The `bnd-process-tests` is not executed by default, therefore at least one expli |-------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | `bndfile` | File path to a bnd file containing bnd instructions for this project. The file path can be either absolute or relative to the project directory. _Defaults to `bnd.bnd`_. | | `bnd` | Bnd instructions for this project specified directly in the pom file. This is generally be done using a `` section. If the projects has a `bndfile` configuration property or a file in the default location `bnd.bnd`, then this configuration element is ignored. | +| `classesDir` | The directory where the `maven-compiler-plugin` places its output. _Defaults to `${project.build.testOutputDirectory}`._ | | `includeClassesDir` | Include the entire contents of `classesDir` in the bundle. *Defaults to `true`*. | -| `skip` | Skip the goal. _Defaults to `false`._ Override with property `bnd-tests.skip` or `maven.test.skip`. | | `artifactFragment` | If true, make the tests artifact a fragment using `${project.artifactId}` as the `Fragment-Host` header and setting the `Bundle-SymbolicName` of the tests artifact to `${project.artifactId}-tests`. *Defaults to `false`*. | | `testCases` | Specify the filter that will determine which classes to identify as test cases. *Defaults to `junit5`*. See [Test Cases](#test-cases). | -| `skipIfEmpty` | Skip processing if `includeClassesDir` is `true` and the `${project.build.testOutputDirectory}` is empty. _Defaults to `false`._ Override with property `bnd.skipIfEmpty`. | +| `skip` | Skip the goal. _Defaults to `false`._ Override with property `bnd-tests.skip` or `maven.test.skip`. | +| `skipIfEmpty` | Skip processing if `includeClassesDir` is `true` and the `classesDir` is empty. _Defaults to `false`._ Override with property `bnd.skipIfEmpty`. | +| `manifestPath` | Specify the path to store the generated manifest file. _Defaults to `${project.build.testOutputDirectory}/META-INF/MANIFEST.MF`._ | +| `outputDir` | The directory where this goal will store its output. _Defaults to `${project.build.testOutputDirectory}`._ | +| `packagingTypes` | The list of maven packaging types for which the plugin will execute. *Defaults to `jar,war`*. Override with property `bnd.packagingTypes`. | +| `outputTimestamp` | Timestamp for [reproducible][1] output archive entries, either formatted as ISO 8601 `yyyy-MM-dd'T'HH:mm:ssXXX` or as an int representing seconds since the epoch. _Defaults to `${project.build.outputTimestamp}`_. | Some details are predefined for simplicity: - `${project.build.testSourceDirectory}` is used as the source directory - `${project.build.testResources}` is used as the resources directory -- `${project.build.testOutputDirectory}` is used as the source of input for bnd to analyse -- `${project.build.testOutputDirectory}/META-INF/MANIFEST.MF` is used as the manifest path ### IMPORTANT NOTE about Maven JAR Plugin @@ -442,3 +450,7 @@ Bnd's integration testing uses the manifest header `Test-Cases` to identify clas - **`all`** - represents all the JUnit filters: `junit3`, `junit4`, and `junit5`. - **`testng`** - represents the filter `${classes;HIERARCHY_ANNOTATED;org.testng.annotations.Test;CONCRETE}`. Note: A JUnit Platform engine for TestNG, or other means to run TestNG tests, must be in the test execution runtime. - **`useTestCasesHeader`** - indicates that the `Test-Cases` header in the bnd configuration should be used instead. The build will fail if this value is set and there is no `Test-Cases` header in the bnd configuration. + +[1]: https://maven.apache.org/guides/mini/guide-reproducible-builds.html +[2]: https://maven.apache.org/pom.html +[3]: https://osgi.org/specification/osgi.core/7.0.0/framework.api.html#org.osgi.annotation.bundle diff --git a/maven/bnd-maven-plugin/src/main/java/aQute/bnd/maven/plugin/AbstractBndMavenPlugin.java b/maven/bnd-maven-plugin/src/main/java/aQute/bnd/maven/plugin/AbstractBndMavenPlugin.java index 2ef5e12a1f..dc64de77ef 100644 --- a/maven/bnd-maven-plugin/src/main/java/aQute/bnd/maven/plugin/AbstractBndMavenPlugin.java +++ b/maven/bnd-maven-plugin/src/main/java/aQute/bnd/maven/plugin/AbstractBndMavenPlugin.java @@ -129,7 +129,8 @@ public abstract class AbstractBndMavenPlugin extends AbstractMojo { boolean skipIfEmpty; /** - * If set, the generated output will be reproducible. + * Timestamp for reproducible output archive entries, either formatted as ISO 8601 + * {@code yyyy-MM-dd'T'HH:mm:ssXXX} or as an int representing seconds since the epoch. * * @see Configuring * for Reproducible Builds @@ -195,6 +196,10 @@ public Optional getType() { return Optional.empty(); } + File getWebappDirectory() { + return webappDirectory; + } + @Override public void execute() throws MojoExecutionException, MojoFailureException { // Exit without generating anything if the project packaging is not a @@ -266,16 +271,13 @@ public void execute() throws MojoExecutionException, MojoFailureException { boolean hasWablibs = builder.getProperty(Constants.WABLIB) != null; String wabProperty = builder.getProperty(Constants.WAB); - File outputDir = getOutputDir(); - if (isWab) { if (wabProperty == null) { builder.setProperty(Constants.WAB, ""); } - outputDir = webappDirectory; logger .info("WAB mode enabled. Bnd output will be expanded into the 'maven-war-plugin' :" - + outputDir); + + getWebappDirectory()); } else if ((wabProperty != null) || hasWablibs) { throw new MojoFailureException( Constants.WAB + " & " + Constants.WABLIB + " are not supported with packaging 'jar'"); @@ -536,8 +538,9 @@ public void execute() throws MojoExecutionException, MojoFailureException { } if (isWab) { // Write Jar into webappDirectory - writeFolder(bndJar, webappDirectory); - File manifestPath = new File(webappDirectory, bndJar.getManifestName()); + File outputDirectory = getWebappDirectory(); + writeContent(bndJar, outputDirectory); + File manifestPath = new File(outputDirectory, bndJar.getManifestName()); writeManifest(bndJar, manifestPath); } // Add META-INF/maven metadata to jar @@ -545,8 +548,9 @@ public void execute() throws MojoExecutionException, MojoFailureException { // Write the jar directly and attach it to the project attachArtifactToProject(bndJar); } else { - // Write Jar into outputDir - writeFolder(bndJar, outputDir); + File outputDirectory = isWab ? getWebappDirectory() : getOutputDir(); + // Write Jar content into outputDirectory + writeContent(bndJar, outputDirectory); writeManifest(bndJar, getManifestPath()); } } else { @@ -656,7 +660,7 @@ private void addMavenMetadataToJar(Jar bndJar) throws IOException { } private File getArtifactFile() { - return new File(buildDir, project.getBuild() + return new File(getOutputDir(), project.getBuild() .getFinalName() + getClassifier().map("-"::concat) .orElse("") @@ -833,7 +837,7 @@ protected boolean isEmpty(File directory) { } } - private void writeFolder(Jar jar, File directory) throws Exception { + private void writeContent(Jar jar, File directory) throws Exception { final long lastModified = jar.lastModified(); if (logger.isDebugEnabled()) { logger.debug(String.format("Bundle lastModified: %tF % getClassifier() { @@ -34,4 +41,8 @@ public Optional getType() { return Optional.of("jar"); } + @Override + public File getOutputDir() { + return outputDir; + } } diff --git a/maven/bnd-maven-plugin/src/main/java/aQute/bnd/maven/plugin/BndMavenPackagingTestsPlugin.java b/maven/bnd-maven-plugin/src/main/java/aQute/bnd/maven/plugin/BndMavenPackagingTestsPlugin.java index a4a65c39a6..3d8fab2cad 100644 --- a/maven/bnd-maven-plugin/src/main/java/aQute/bnd/maven/plugin/BndMavenPackagingTestsPlugin.java +++ b/maven/bnd-maven-plugin/src/main/java/aQute/bnd/maven/plugin/BndMavenPackagingTestsPlugin.java @@ -1,5 +1,6 @@ package aQute.bnd.maven.plugin; +import java.io.File; import java.util.Optional; import org.apache.maven.plugins.annotations.LifecyclePhase; @@ -20,7 +21,13 @@ public class BndMavenPackagingTestsPlugin extends BndMavenTestsPlugin { * The classifier to use for the generated artifact. */ @Parameter(defaultValue = "tests") - private String classifier; + String classifier; + + /** + * The directory where this plugin will store the generated artifact. + */ + @Parameter(defaultValue = "${project.build.directory}") + File outputDir; @Override public Optional getClassifier() { @@ -34,4 +41,8 @@ public Optional getType() { return Optional.of("test-jar"); } + @Override + public File getOutputDir() { + return outputDir; + } }