diff --git a/maven/bnd-maven-plugin/README.md b/maven/bnd-maven-plugin/README.md index 014d2104d8..0ff2be0814 100644 --- a/maven/bnd-maven-plugin/README.md +++ b/maven/bnd-maven-plugin/README.md @@ -43,24 +43,23 @@ The `jar` goal is not executed by default, therefore at least one explicit execu ### Configuration Parameters -|Configuration Parameter | Description | -| --- | --- | -|`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`._| -|`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}`._| -|`warOutputDir` | The directory where the `bnd-maven-plugin` will extract it's contents 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`.| +| Configuration Parameter | Description | +|-------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `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`._| +| `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}`._ | +| `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`. | **No additional packaging plugins are necessary when using the `jar` goal.** #### Matching executions -The `bnd-maven-plugin` does not blindly remove all `maven-(jar|war)-plugin` found in the project, only those whose executions match by `goal`, `packaging` and `classifier`. Therefore it is possible to have both plugins operating within the same project provided they do not overlap. (And remember that no `classifier` means the main artifact.) +The `bnd-maven-plugin` does not blindly remove all `maven-(jar|war)-plugin` found in the project, only those whose executions match by `goal`, `packaging` and `classifier`. Therefore, it is possible to have both plugins operating within the same project provided they do not overlap. (And remember that no `classifier` means the main artifact.) ## `bnd-process` goal @@ -93,18 +92,18 @@ The `bnd-process` is not executed by default, therefore at least one explicit ex ### Configuration Parameters -|Configuration Parameter | Description | -| --- | --- | -|`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`._| -|`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}`._| -|`warOutputDir` | The directory where the `bnd-maven-plugin` will extract it's contents 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`.| +| Configuration Parameter | Description | +|-------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `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`._ | +| `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}`._ | +| `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`. | ### IMPORTANT NOTE about Maven JAR|WAR Plugin @@ -166,17 +165,17 @@ For further usage information, see the integration test projects under the inclu 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). -|OSGi Header | Derived from POM Element | -| --- | --- | -| `Bundle-SymbolicName` | `artifactId` | -| `Bundle-Name` | `name` | -| `Bundle-Version` | `version` | -| `Bundle-Description` | `description` | -| `Bundle-Vendor` | `organisation.name` | -| `Bundle-License` | `licenses` | -| `Bundle-SCM` | `scm` | -| `Bundle-Developers` | `developers` (child element `id` must be set on each developer) | -| `Bundle-DocURL` | `url` | +| OSGi Header | Derived from POM Element | +|-----------------------|-----------------------------------------------------------------| +| `Bundle-SymbolicName` | `artifactId` | +| `Bundle-Name` | `name` | +| `Bundle-Version` | `version` | +| `Bundle-Description` | `description` | +| `Bundle-Vendor` | `organisation.name` | +| `Bundle-License` | `licenses` | +| `Bundle-SCM` | `scm` | +| `Bundle-Developers` | `developers` (child element `id` must be set on each developer) | +| `Bundle-DocURL` | `url` | ### Reproducible Builds @@ -203,7 +202,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 it's 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](https://osgi.org/specification/osgi.core/7.0.0/framework.api.html#org.osgi.annotation.bundle): ```xml @@ -247,7 +246,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 it's 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](https://osgi.org/specification/osgi.core/7.0.0/framework.api.html#org.osgi.annotation.bundle): ```xml @@ -350,19 +349,19 @@ The `test-jar` goal is not executed by default, therefore at least one explicit ### Configuration Parameters -| Configuration Parameter | Description | -| ----------------------- | ------------------------------------------------------------ | -| `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`_. | +| Configuration Parameter | Description | +|-------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `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`_.| -| `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`.| +| `classifier` | A string added to the artifact indicating a supplemental artifact produced by the project. _Defaults to `tests`_. | +| `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`. | Some details are predefined for simplicity: -- `${project.build.testSourceDirectory}` is used as a the source directory +- `${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 @@ -392,25 +391,25 @@ The `bnd-process-tests` is not executed by default, therefore at least one expli ### Configuration Parameters -| Configuration Parameter | Description | -| ----------------------- | ------------------------------------------------------------ | -| `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`_. | +| Configuration Parameter | Description | +|-------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `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. | -| `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`.| +| `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`. | Some details are predefined for simplicity: -- `${project.build.testSourceDirectory}` is used as a the source directory +- `${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 -When using the `bnd-process-tests` goal it is important to take the following into consideration. The `maven-jar-plugin` provides the goal `test-jar` for building a jar from a project's test classes. It is bound to the `package` phase but has no default execution and so one must be configured. Like the `jar` goal it will NOT currently use the data from the generated `MANIFEST.MF` file when using its default configuration so it is necessary to configure it as follows: +When using the `bnd-process-tests` goal it is important to take the following into consideration. The `maven-jar-plugin` provides the goal `test-jar` for building a jar from a project's test classes. It is bound to the `package` phase but has no default execution, so one must be configured. Like the `jar` goal it will NOT currently use the data from the generated `MANIFEST.MF` file when using its default configuration, so it is necessary to configure it as follows: ```xml @@ -442,4 +441,4 @@ Bnd's integration testing uses the manifest header `Test-Cases` to identify clas - **`junit5`** - represents the filter `${classes;HIERARCHY_INDIRECTLY_ANNOTATED;org.junit.platform.commons.annotation.Testable;CONCRETE}`. - **`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 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. +- **`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. diff --git a/maven/bnd-maven-plugin/src/it/jar-test-war-bundle/pom.xml b/maven/bnd-maven-plugin/src/it/jar-test-war-bundle/pom.xml index 98009cdb15..e2f0cfded5 100644 --- a/maven/bnd-maven-plugin/src/it/jar-test-war-bundle/pom.xml +++ b/maven/bnd-maven-plugin/src/it/jar-test-war-bundle/pom.xml @@ -52,6 +52,7 @@ + ${project.build.directory}/${project.build.finalName} diff --git a/maven/bnd-maven-plugin/src/it/jar-test-war-bundle/postbuild.groovy b/maven/bnd-maven-plugin/src/it/jar-test-war-bundle/postbuild.groovy index fb91ff4847..479f745fe3 100644 --- a/maven/bnd-maven-plugin/src/it/jar-test-war-bundle/postbuild.groovy +++ b/maven/bnd-maven-plugin/src/it/jar-test-war-bundle/postbuild.groovy @@ -3,12 +3,16 @@ import groovy.xml.XmlSlurper import java.util.jar.Attributes import java.util.jar.JarFile +import static org.assertj.core.api.Assertions.assertThat + def bsn = 'jar-test-war-bundle' def version = '0.0.1-SNAPSHOT' -// Check the bundles exist! +// Check the output exists! File wab = new File(basedir, "target/${bsn}-${version}.war") -assert wab.isFile() +File webapp_directory = new File(basedir, "target/${bsn}-${version}") +assertThat(wab).isFile() +assertThat(webapp_directory).isDirectory() // Load manifests JarFile war = new JarFile(wab) @@ -26,12 +30,18 @@ assert war.getEntry('WEB-INF/classes/org/example/impl/') != null assert war.getEntry('WEB-INF/lib/jar-test-api-bundle-0.0.1.jar') != null assert war.getEntry('WEB-INF/lib/osgi.cmpn-6.0.0.jar') == null assert war.getEntry('WEB-INF/lib/osgi.annotation-6.0.1.jar') == null - -assert war.getEntry("META-INF/maven/biz.aQute.bnd-test/${bsn}/pom.xml") != null -assert war.getEntry("META-INF/maven/biz.aQute.bnd-test/${bsn}/pom.properties") != null +assertThat(new File(webapp_directory, 'META-INF/MANIFEST.MF')).isFile() +assertThat(new File(webapp_directory, 'WEB-INF')).isDirectory() +assertThat(new File(webapp_directory, 'WEB-INF/classes/org/example/impl')).isDirectory() +assertThat(new File(webapp_directory, 'WEB-INF/lib/jar-test-api-bundle-0.0.1.jar')).isFile() +assertThat(new File(webapp_directory, 'WEB-INF/lib/osgi.cmpn-6.0.0.jar')).doesNotExist() +assertThat(new File(webapp_directory, 'WEB-INF/lib/osgi.annotation-6.0.1.jar')).doesNotExist() def groupId = 'biz.aQute.bnd-test' +assert war.getEntry("META-INF/maven/${groupId}/${bsn}/pom.xml") != null +assert war.getEntry("META-INF/maven/${groupId}/${bsn}/pom.properties") != null + def checkMavenPom(JarFile jar, String entry, String groupId, String artifactId, String version) { def pom = new XmlSlurper().parse(jar.getInputStream(jar.getEntry(entry))) assert pom.groupId == groupId || pom.parent.groupId == groupId diff --git a/maven/bnd-maven-plugin/src/it/test-war-bundle/pom.xml b/maven/bnd-maven-plugin/src/it/test-war-bundle/pom.xml index 36eea80074..9bca9bc69c 100644 --- a/maven/bnd-maven-plugin/src/it/test-war-bundle/pom.xml +++ b/maven/bnd-maven-plugin/src/it/test-war-bundle/pom.xml @@ -52,6 +52,8 @@ + + ${project.build.directory}/${project.build.finalName} diff --git a/maven/bnd-maven-plugin/src/it/test-war-bundle/postbuild.groovy b/maven/bnd-maven-plugin/src/it/test-war-bundle/postbuild.groovy index eac3303a6b..bd5bd7405e 100644 --- a/maven/bnd-maven-plugin/src/it/test-war-bundle/postbuild.groovy +++ b/maven/bnd-maven-plugin/src/it/test-war-bundle/postbuild.groovy @@ -1,9 +1,13 @@ import java.util.jar.Attributes -import java.util.jar.JarFile; +import java.util.jar.JarFile -// Check the bundles exist! +import static org.assertj.core.api.Assertions.assertThat + +// Check the output exists! File war_bundle = new File(basedir, 'target/test-war-bundle-0.0.1-SNAPSHOT.war') -assert war_bundle.isFile() +File webapp_directory = new File(basedir, 'target/test-war-bundle-0.0.1-SNAPSHOT') +assertThat(war_bundle).isFile() +assertThat(webapp_directory).isDirectory() // Load manifests JarFile war_jar = new JarFile(war_bundle) @@ -21,3 +25,12 @@ assert war_jar.getEntry('WEB-INF/classes/org/example/impl/') != null assert war_jar.getEntry('WEB-INF/lib/test-api-bundle-0.0.1.jar') != null assert war_jar.getEntry('WEB-INF/lib/osgi.cmpn-6.0.0.jar') == null assert war_jar.getEntry('WEB-INF/lib/osgi.annotation-6.0.1.jar') == null + +assertThat(new File(webapp_directory, 'META-INF/MANIFEST.MF')).isFile() +assertThat(new File(webapp_directory, 'WEB-INF')).isDirectory() +assertThat(new File(webapp_directory, 'WEB-INF/classes/org/example/impl')).isDirectory() +assertThat(new File(webapp_directory, 'WEB-INF/lib/test-api-bundle-0.0.1.jar')).isFile() +assertThat(new File(webapp_directory, 'WEB-INF/lib/osgi.cmpn-6.0.0.jar')).doesNotExist() +assertThat(new File(webapp_directory, 'WEB-INF/lib/osgi.annotation-6.0.1.jar')).doesNotExist() + +true // success 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 54e61e929d..a82151f583 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 @@ -23,6 +23,7 @@ import java.io.OutputStream; import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.Collection; import java.util.Enumeration; @@ -34,11 +35,27 @@ import java.util.Properties; import java.util.Set; import java.util.jar.Manifest; -import java.util.stream.Collectors; import java.util.stream.Stream; import java.util.zip.ZipException; import java.util.zip.ZipFile; +import aQute.bnd.build.Project; +import aQute.bnd.exceptions.Exceptions; +import aQute.bnd.header.OSGiHeader; +import aQute.bnd.maven.PomPropertiesResource; +import aQute.bnd.maven.lib.configuration.BeanProperties; +import aQute.bnd.osgi.Builder; +import aQute.bnd.osgi.Constants; +import aQute.bnd.osgi.FileResource; +import aQute.bnd.osgi.Jar; +import aQute.bnd.osgi.Processor; +import aQute.bnd.osgi.Resource; +import aQute.bnd.version.MavenVersion; +import aQute.bnd.version.Version; +import aQute.lib.io.IO; +import aQute.lib.strings.Strings; +import aQute.lib.utf8properties.UTF8Properties; +import aQute.service.reporter.Report.Location; import org.apache.maven.artifact.Artifact; import org.apache.maven.artifact.handler.ArtifactHandler; import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager; @@ -64,30 +81,12 @@ import org.slf4j.LoggerFactory; import org.sonatype.plexus.build.incremental.BuildContext; -import aQute.bnd.build.Project; -import aQute.bnd.exceptions.Exceptions; -import aQute.bnd.header.OSGiHeader; -import aQute.bnd.maven.PomPropertiesResource; -import aQute.bnd.maven.lib.configuration.BeanProperties; -import aQute.bnd.osgi.Builder; -import aQute.bnd.osgi.Constants; -import aQute.bnd.osgi.FileResource; -import aQute.bnd.osgi.Jar; -import aQute.bnd.osgi.Processor; -import aQute.bnd.osgi.Resource; -import aQute.bnd.version.MavenVersion; -import aQute.bnd.version.Version; -import aQute.lib.io.IO; -import aQute.lib.strings.Strings; -import aQute.lib.utf8properties.UTF8Properties; -import aQute.service.reporter.Report.Location; - /** * Abstract base class for all bnd-maven-plugin mojos. */ public abstract class AbstractBndMavenPlugin extends AbstractMojo { protected final Logger logger = LoggerFactory.getLogger(getClass()); - static final String MANIFEST_LAST_MODIFIED = "aQute.bnd.maven.plugin.BndMavenPlugin.manifestLastModified"; + static final String LAST_MODIFIED = "aQute.bnd.maven.plugin.BndMavenPlugin.lastModified"; static final String MARKED_FILES = "aQute.bnd.maven.plugin.BndMavenPlugin.markedFiles"; static final String PACKAGING_JAR = "jar"; static final String PACKAGING_WAR = "war"; @@ -105,10 +104,10 @@ public abstract class AbstractBndMavenPlugin extends AbstractMojo { boolean includeClassesDir; /** - * The directory where this plugin will store its output when packaging is {@code war}. + * The directory where the webapp is built when packaging is {@code war}. */ - @Parameter(defaultValue = "${project.build.directory}/${project.build.finalName}") - File warOutputDir; + @Parameter(alias = "warOutputDir", defaultValue = "${project.build.directory}/${project.build.finalName}") + File webappDirectory; @Parameter(defaultValue = "${project}", required = true, readonly = true) MavenProject project; @@ -201,8 +200,8 @@ public Optional getType() { @Override public void execute() throws MojoExecutionException, MojoFailureException { - // Exit without generating anything if this is neither a jar or war - // project. Probably it's just a parent project. + // Exit without generating anything if the project packaging is not a + // packaging type. Probably it's just a parent project. if (!packagingTypes.contains(project.getPackaging())) { logger.debug("skip project with packaging=" + project.getPackaging()); return; @@ -276,7 +275,7 @@ public void execute() throws MojoExecutionException, MojoFailureException { if (wabProperty == null) { builder.setProperty(Constants.WAB, ""); } - outputDir = warOutputDir; + outputDir = webappDirectory; logger .info("WAB mode enabled. Bnd output will be expanded into the 'maven-war-plugin' :" + outputDir); @@ -330,8 +329,7 @@ public void execute() throws MojoExecutionException, MojoFailureException { } if (!wablibs.isEmpty()) { - String wablib = wablibs.stream() - .collect(Collectors.joining(",")); + String wablib = String.join(",", wablibs); builder.setProperty(Constants.WABLIB, wablib); } @@ -341,7 +339,7 @@ public void execute() throws MojoExecutionException, MojoFailureException { logger.debug("builder classpath: {}", builder.getProperty("project.buildpath")); // Compute bnd sourcepath - boolean delta = !buildContext.isIncremental() || manifestOutOfDate(); + boolean delta = !buildContext.isIncremental() || outOfDate(); List sourcepath = new ArrayList<>(); if (getSourceDir().exists()) { sourcepath.add(getSourceDir().getCanonicalFile()); @@ -524,30 +522,35 @@ public void execute() throws MojoExecutionException, MojoFailureException { // Build bnd Jar (in memory) Jar bndJar = builder.build(); - String goal = mojoExecution.getMojoDescriptor() - .getGoal(); - // If a bnd-maven-plugin packaging goal is used it means // this execution is responsible for creating and attaching the // target artifact to the project + String goal = mojoExecution.getMojoDescriptor() + .getGoal(); if (isPackagingGoal(goal)) { // However, if extensions for this plugin are not enabled - // the maven-(j|w)wa-plugin will also execute, resulting in + // the maven-(jar|war)-plugin will also execute, resulting in // conflicting results - if (mojoExecution.getPlugin() + if (!mojoExecution.getPlugin() .isExtensions()) { - // Add META-INF/maven metadata to jar - addMavenMetadataToJar(bndJar); - // Write the jar directly and attach it to the project - attachArtifactToProject(bndJar); - } else { throw new MojoExecutionException(String.format( "In order to use the bnd-maven-plugin packaging goal %s, true must be set on the plugin", goal)); } + if (isWab) { + // Write Jar into webappDirectory + writeFolder(bndJar, webappDirectory); + File manifestPath = new File(webappDirectory, bndJar.getManifestName()); + writeManifest(bndJar, manifestPath); + } + // Add META-INF/maven metadata to jar + addMavenMetadataToJar(bndJar); + // Write the jar directly and attach it to the project + attachArtifactToProject(bndJar); } else { - // Expand Jar into target/classes - expandJar(bndJar, outputDir); + // Write Jar into outputDir + writeFolder(bndJar, outputDir); + writeManifest(bndJar, getManifestPath()); } } else { logger.debug("No build"); @@ -601,15 +604,22 @@ private static StringBuilder addHeaderAttribute(StringBuilder builder, String ke } private void attachArtifactToProject(Jar bndJar) throws Exception { - File artifactFile = createArtifactFile(); - File parent = artifactFile.getParentFile(); - - if (!parent.exists()) { - IO.mkdirs(parent); - } + File artifactFile = getArtifactFile(); + if (outOfDate(artifactFile) || artifactFile.lastModified() < bndJar.lastModified()) { + if (logger.isDebugEnabled()) { + if (artifactFile.exists()) + logger.debug(String.format("Updating lastModified: %tF % entries = Files.walk(path)) { - return !entries.filter(p -> !Files.isDirectory(p)) - .filter(p -> !path.relativize(p) - .startsWith("META-INF/")) - .findFirst() - .isPresent(); + return entries.allMatch(p -> Files.isDirectory(p) || path.relativize(p) + .startsWith(meta_inf)); } catch (IOException ioe) { throw Exceptions.duck(ioe); } } - private void expandJar(Jar jar, File dir) throws Exception { + private void writeFolder(Jar jar, File directory) throws Exception { final long lastModified = jar.lastModified(); if (logger.isDebugEnabled()) { logger.debug(String.format("Bundle lastModified: %tF % entry : jar.getResources() .entrySet()) { - File outFile = IO.getBasedFile(dir, entry.getKey()); + File outFile = IO.getBasedFile(directory, entry.getKey()); Resource resource = entry.getValue(); // Skip the copy if the source and target are the same file if (resource instanceof FileResource) { @@ -863,33 +871,42 @@ private void expandJar(Jar jar, File dir) throws Exception { } } } + } - if (manifestOutOfDate() || getManifestPath().lastModified() < lastModified) { + private void writeManifest(Jar jar, File manifestPath) throws Exception { + final long lastModified = jar.lastModified(); + if (outOfDate(manifestPath) || manifestPath.lastModified() < lastModified) { if (logger.isDebugEnabled()) { - if (!manifestOutOfDate()) + if (!outOfDate(manifestPath)) logger.debug(String.format("Updating lastModified: %tF %biz.aQute.bnd bnd-plugin-parent Parent POM for the Bnd Maven plugins. - ${project.groupId}:${project.artifactId} + Bnd Maven Plugins Parent pom ${revision} @@ -207,6 +207,16 @@ org.osgi osgi.annotation + + + org.junit.jupiter + junit-jupiter + test + + + org.assertj + assertj-core + diff --git a/maven/bnd-reporter-maven-plugin/pom.xml b/maven/bnd-reporter-maven-plugin/pom.xml index a043b1dfd3..dc07de8e8f 100644 --- a/maven/bnd-reporter-maven-plugin/pom.xml +++ b/maven/bnd-reporter-maven-plugin/pom.xml @@ -61,11 +61,6 @@ biz.aQute.bnd.reporter - - org.junit.jupiter - junit-jupiter - test - org.slf4j slf4j-simple diff --git a/maven/pom.xml b/maven/pom.xml index 813955e442..785755f971 100644 --- a/maven/pom.xml +++ b/maven/pom.xml @@ -8,7 +8,7 @@ maven 1.0.0 Reactor to build the Bnd Maven plugins. - Bnd Maven plugins reactor + Bnd Maven Plugins Reactor pom