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/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/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..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 @@ -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. @@ -132,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 @@ -174,7 +172,7 @@ public abstract class AbstractBndMavenPlugin extends AbstractMojo { MavenProjectHelper projectHelper; @Component - private ArtifactHandlerManager artifactHandlerManager; + ArtifactHandlerManager artifactHandlerManager; File propertiesFile; @@ -198,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 @@ -235,7 +237,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))) { @@ -269,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'"); @@ -539,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 @@ -548,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 { @@ -659,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("") @@ -836,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; + } }