Bnd includes Gradle plugins for Gradle users to build
Bnd projects in Bnd Workspace builds as well as in
non-Bnd Workspace builds. A typical Gradle build is a
non-Bnd workspace build. A Bnd Workspace build uses the information
specified in the Bnd Workspace's cnf/build.bnd
file and each project's
bnd.bnd
file to configure the Gradle projects and tasks.
The biz.aQute.bnd.gradle
jar contains the Bnd Gradle Plugins.
These plugins requires at least Gradle 5.1 for Java 8 to Java 12,
at least Gradle 6.0 for Java 13,
and at least Gradle 6.3 for Java 14.
This README represents the capabilities and features of the Bnd Gradle Plugins in
the branch containing this README. So for the master
branch, this will be
the latest development SNAPSHOT build. See the appropriate Git tag for the README for the
Bnd Gradle Plugin version you are using.
Bnd offers Gradle support for building bundles in
typical Gradle build environments. There are two ways this support can
be used. You can apply the biz.aQute.bnd.builder
plugin to your
project and/or you can use the new task types:
Bundle
Baseline
Resolve
Export
TestOSGi
Index
Bndrun
To make the Bnd Builder Gradle Plugin available to your build, use the following in settings.gradle
:
pluginManagement {
plugins {
id 'biz.aQute.bnd.builder' version '5.1.0'
}
}
The Gradle marker plugins for the Bnd Gradle plugins are also in Maven Central and JCenter. So you may use either of them as a pluginManagement
repository.
To apply the biz.aQute.bnd.builder
plugin to your project, use the following in build.gradle
:
plugins {
id 'biz.aQute.bnd.builder'
}
This plugin extends the normal java
plugin by:
- Extending the
jar
task by adding theBundleTaskConvention
. This adds new properties are to thejar
task and the task actions are extended to use Bnd to generate a bundle. The bundle will contain all the content configured into thejar
task plus whatever additional content is included via the Bnd instructions. Thebndfile
property of the task'sBundleTaskConvention
is set to'bnd.bnd'
if a'bnd.bnd'
file exists in the project folder. - Adds a
baseline
configuration. - Adds a
baseline
task of typeBaseline
which baselines the bundle generated by thejar
task against the prior version of that bundle in the repositories.
If you don't want to apply the plugin to the project but just need to use the task types, you can access the types with:
plugins {
id 'biz.aQute.bnd.builder' apply false
}
The Bundle
task type is
an extension of the Jar
task type that adds the BundleTaskConvention
which adds new properties and
uses Bnd to generate a bundle. The bundle will contain all the content
configured into the task plus whatever additional content is included
via the Bnd instructions. For example:
import aQute.bnd.gradle.Bundle
tasks.register('bundle', Bundle) {
from sourceSets.main.output
}
In either usage mode, there are four properties, in addition to the
Jar
task properties, which can be configured.
The bnd file to use to create the bundle. If this property is not set or
the bnd file does not exist, then the bnd
property will be used.
The bnd instructions to use to create the
bundle. This property is ignored if the bndfile
property refers
to a file that exists. If the bndfile
property is not set or does not
refer to a file that exists, or this property is not set, this is OK.
But without some instructions to Bnd, your bundle will not be very
interesting.
The SourceSet object to use for the Bnd builder. The default value is ${project.sourceSets.main}. You will only need to specify this property if you want to use a different SourceSet or the default SourceSet does not exist.
The FileCollection object to use as the classpath for the Bnd builder. The default value is ${sourceSet.compileClasspath}. You will only need to specify this property if you want to specify additional classpath elements or replace the classpath.
import aQute.bnd.gradle.Bundle
configurations {
bundleCompile
}
sourceSets {
bundle
}
tasks.register('bundle', Bundle) {
from sourceSets.bundle.output
bndfile = 'bundle.bnd'
sourceSet = sourceSets.bundle
}
The normal way to instruct Bnd on how to build the bundle is to use a
bnd file. This file will specify the Bnd instructions like
-exportcontents
, etc. You can also use the bnd
property of the
BundleTaskConvention
. It can be used in several different ways. You can configure
the bnd
property with a multiline string:
jar {
bnd '''
-exportcontents: com.acme.api.*
-sources: true
-include: other.bnd
'''
}
You can also configure the bnd
property with map notation:
jar {
bnd('-exportcontents': 'com.acme.api.*',
'-sources': 'true',
'-include': 'other.bnd')
}
Finally, you can also use the manifest
property
to instruct Bnd. For example:
jar {
manifest {
attributes('-exportcontents': 'com.acme.api.*',
'-sources': 'true',
'-include': 'other.bnd')
}
}
You can even use a combination of the manifest
property and a
BundleTaskConvention
property. But the BundleTaskConvention
property
takes priority over the manifest
property. So
if the same instruction is in both places, the one in the
BundleTaskConvention
property will be
used and the one in the manifest
property will be ignored.
In Gradle 5.0, the OSGi Plugin was deprecated. If you used
the OSGi Plugin and want to switch to the Bnd Gradle Plugin, you
will need to modify your build scripts. In addition to applying the
biz.aQute.bnd.builder
plugin to replace the OSGi Plugin, you will need
to change usage of the OSGiManifest
's instruction
property to use
the bnd
property.
For example:
jar {
manifest { // the manifest of the default jar is of type OsgiManifest
name = 'overwrittenSpecialOsgiName'
instruction 'Bundle-Vendor', 'MyCompany'
instruction 'Bundle-Description', 'Platform2: Metrics 2 Measures Framework'
instruction 'Bundle-DocURL', 'https://www.mycompany.com'
}
}
becomes:
jar {
bnd ('Bundle-Name': 'overwrittenSpecialOsgiName',
'Bundle-Vendor': 'MyCompany',
'Bundle-Description': 'Platform2: Metrics 2 Measures Framework',
'Bundle-DocURL': 'https://www.mycompany.com')
}
Use the sourceSet
property to replace use of the classesDir
property.
Use of the convenience properties on OSGiManifest
must be replaced with
the specifying the actual OSGi manifest header name in the Bnd
instructions. For example, name = 'overwrittenSpecialOsgiName'
is replaced
with bnd 'Bundle-Name: overwrittenSpecialOsgiName'
.
The Baseline
task type
will baseline a bundle against a different version of the bundle. For
example:
import aQute.bnd.gradle.Baseline
configurations {
baseline
}
dependencies {
baseline('group': group, 'name': jar.archiveBaseName) {
version {
strictly "(0,${jar.archiveVersion.get()}["
}
transitive = false
}
}
tasks.register('baseline', Baseline) {
bundle jar
baseline configurations.baseline
}
There are six properties which can be configured for a Baseline task:
If true
the build will not fail due to baseline problems; instead an
error message will be logged. Otherwise, the build will fail. The
default is false
.
The name of the baseline reports directory. Can be a name or a
path relative to the project's reporting.baseDirectory
. The default name is
baseline
.
The bundle to be baselined. It can be anything that Project.files(Object...)
can accept to result in a single file. This property must be set.
The baseline bundle. It can be anything that Project.files(Object...)
can accept to result in a single file. This property must be set.
The names of the exported packages in the bundle to baseline. The default is all the exported packages but this property can be used to specify which exported packages are baselined.
The manifest header names and resource paths to ignore when baseline comparing. This property can be used to exclude items from baseline comparison.
For example, to exclude bundle versions from baseline comparison, add Bundle-Version
to diffignore
.
The Resolve
task type
will resolve a standalone bndrun file and set the -runbundles
property
in the file. For example:
import aQute.bnd.gradle.Resolve
tasks.register('resolve', Resolve) {
bndrun 'my.bndrun'
}
There are six properties which can be configured for a Resolve task:
If true
the task will not fail due to resolution failures; instead an
error message will be logged. Otherwise, the task will fail. The
default is false
.
If true
the build will fail if the resolve process changes the value of the
-runbundles
property. The default is false
.
If true
the build will write changes to the value of the -runbundles
property back to the bndrun file. The default is true
.
The bndrun to be resolved. It can be anything that Project.file(Object)
can accept. This property must be set.
The directory for the resolve process. The default is ${temporaryDir}.
The collection of files to use for locating bundles during the resolve process. The default is ${project.sourceSets.main.runtimeClasspath} plus ${project.configurations.archives.artifacts.files}.
If true
failure reports will include optional requirements. The default is
true
.
The Export
task type
will export a standalone bndrun file. For example:
import aQute.bnd.gradle.Export
tasks.register('export', Export) {
bndrun 'my.bndrun'
}
There are five properties which can be configured for an Export task:
If true
the task will not fail due to export failures; instead an
error message will be logged. Otherwise, the task will fail. The
default is false
.
Bnd has two built-in exporter plugins. bnd.executablejar
exports an
executable jar and bnd.runbundles
exports the -runbundles
files.
The exporter plugin with the specified name must be an installed exporter
plugin. The default is bnd.executablejar
.
The bndrun to be exported. It can be anything that Project.file(Object)
can accept. This property must be set.
The directory for the output. The default for destinationDirectory is
${project.distsDirectory}/executable if the exporter is bnd.executablejar
,
${project.distsDirectory}/runbundles/${bndrun.name - '.bndrun'} if
the exporter is bnd.runbundles
, and ${project.distsDirectory}/${task.name}
for all other exporters.
The directory for the export operation. The default is ${temporaryDir}.
The collection of files to use for locating bundles during the bndrun export. The default is ${project.sourceSets.main.runtimeClasspath} plus ${project.configurations.archives.artifacts.files}.
The TestOSGi
task type
will execute tests in a standalone bndrun file. For example:
import aQute.bnd.gradle.TestOSGi
tasks.register('testOSGi', TestOSGi) {
bndrun 'my.bndrun'
}
There are five properties which can be configured for a TestOSGi task:
If true
the task will not fail due to test case failures; instead an
error message will be logged. Otherwise, the task will fail. The
default is false
.
The bndrun to be tested. It can be anything that Project.file(Object)
can accept. This property must be set.
The directory for the test execution. The default is ${temporaryDir}.
The collection of files to use for locating bundles during the bndrun execution. The default is ${project.sourceSets.main.runtimeClasspath} plus ${project.configurations.archives.artifacts.files}.
The list of fully qualified names of test classes to run. If not set, or empty,
Then all the test classes listed in the Test-Classes
manifest header are
run. The --tests
command line option can be used
to set the fully qualified name of a test class to run. This can be repeated
multiple times to specify multiple test classes to run.
Use a colon (:
) to specify a test method to run on the specified test class.
The Index
task type
will generate an index for a set of bundles. For
example:
import aQute.bnd.gradle.Index
tasks.register('index', Index) {
destinationDirectory = file('bundles')
gzip = true
bundles = fileTree(destinationDirectory) {
include '**/*.jar'
exclude '**/*-sources.jar'
exclude '**/*-javadoc.jar'
}
}
There are five properties which can be configured for an Index task:
If true
, then a gzip'd copy of the index will be made with a .gz
extension.
Otherwise, only the uncompressed index will be made. The default is
false
.
The name of the index file. The file is created in the destinationDirectory.
The default isindex.xml
.
The name attribute in the generated index. The default is the name of the task.
The destination directory for the index. The default value is ${project.buildDir}.
The URI base for the generated index. The default value is ${project.uri(destinationDirectory)}.
This is the bundles to be indexed. It can be anything that Project.files(Object...)
can accept. This property must be set.
The Bndrun
task type will execute a bndrun file. For example:
import aQute.bnd.gradle.Bndrun
tasks.register('run', Bndrun) {
bndrun 'my.bndrun'
}
There are four properties which can be configured for a Bndrun task:
If true
the task will not fail due to execution failures; instead an
error message will be logged. Otherwise, the task will fail. The
default is false
.
The bndrun to be executed. It can be anything that Project.file(Object)
can accept. This property must be set.
The directory for the execution. The default is ${temporaryDir}.
The collection of files to use for locating bundles during the bndrun execution. The default is ${project.sourceSets.main.runtimeClasspath} plus ${project.configurations.archives.artifacts.files}.
The Bnd Gradle Plugins for Bnd Workspace builds uses the information
specified in the Bnd Workspace's cnf/build.bnd
file and each project's
bnd.bnd
file to build the projects.
The Bnd Gradle Plugins for Bnd Workspace builds consists of two plugins:
- The
biz.aQute.bnd.workspace
Gradle plugin can be applied in thesettings.gradle
file or the Bnd Workspace folder'sbuild.gradle
file. - The
biz.aQute.bnd
Gradle plugin is applied to each subproject that is a Bnd project. Thebiz.aQute.bnd.workspace
Gradle plugin will automatically apply thebiz.aQute.bnd
Gradle plugin to the Gradle projects for all the identified Bnd Workspace projects.
A Bnd Workspace is a folder containing a cnf
project as well as a
number of peer folders each holding a Bnd project. So the Bnd Workspace
folder is the main project of the Gradle build for the Bnd Workspace.
The following files are in the root project:
gradle.properties
- Some initial properties to configure the Gradle build for the workspace.settings.gradle
- Initializes the projects to be included in the Gradle build for the workspace.build.gradle
- Configures the Gradle build for the workspace.
When creating a new Bnd Workspace with Bndtools, it will put these files on the root folder of the workspace.
These files can be modified to customize the overall Gradle build for
the Bnd Workspace. If special Gradle build behavior for a project is needed,
beyond changes to the project's bnd.bnd
file, then you should place a
build.gradle
file in the project folder and place your
customizations in there.
If you are using the Gradle build added by Bndtools when creating the the Bnd Workspace, you don't need to do anything else.
If you want to use the Bnd Gradle Plugins in your existing Gradle build,
there are two approaches you can take. The main
approach is to edit settings.gradle
as follows:
plugins {
id 'biz.aQute.bnd.workspace' version '5.1.0'
}
The Gradle marker plugins for the Bnd Gradle plugins are also in Maven Central and JCenter. So you may use either of them as a pluginManagement
repository.
When you apply the biz.aQute.bnd.workspace
Gradle plugin in the
settings.gradle
file, the plugin will determine the Bnd project folders
in the Bnd Workspace, include them in the Gradle build, and apply itself
to the root project. This will result in the biz.aQute.bnd
Gradle plugin
being applied to each project which is a Bnd project. With this approach, you
don't even need a build.gradle
file for the root project. But you can
use a build.gradle
file in the root project to apply common configuration
across all your Bnd projects:
subprojects {
if (plugins.hasPlugin('biz.aQute.bnd')) {
// additional configuration for Bnd projects
}
}
The second approach, for when you already have a settings.gradle
file which
includes the desired projects and you don't want the set of projects to
include to be computed, is to put the plugins
block in the root project's build.gradle
file:
plugins {
id 'biz.aQute.bnd.workspace' version '5.1.0'
}
While this is the same as the previous settings.gradle
example, since it
is the root project's build.gradle
file, it requires that your settings.gradle
file has already included the necessary projects in the Gradle build. The plugin
will apply the biz.aQute.bnd
Gradle plugin to each Gradle project which is a
Bnd project.
In general, your Gradle scripts will not apply the biz.aQute.bnd
Gradle plugin
directly to a project since this is handled by using the biz.aQute.bnd.workspace
Gradle
plugin in the settings.gradle
file or the build.gradle
file in the root project.
The biz.aQute.bnd
Gradle Plugin extends the standard Gradle Java plugin. It
modifies some of the standard Java plugin tasks as necessary and also
adds some additional tasks. Running gradle tasks --all
in a project
will provide a complete list of the tasks available within the project.
The dependencies for the project are configured from the path
information specified in the bnd.bnd
file such as -buildpath
and -testpath
. These paths are then used by various tasks such as
compileJava
and compileTestJava
.
The jar
task uses Bnd to build the project's bundles.
The test
task runs any plain JUnit tests in the project.
The check
task runs all verification tasks in the project,
including test
and testOSGi
.
The jarDependencies
task jars all projects the project
depends on.
The buildDependencies
task assembles and tests all projects
the project depends on.
The release
task releases the project's bundles to the
-releaserepo
, if one is configured for the project.
The releaseDependencies
task releases all projects the project
depends on.
The releaseNeeded
task releases the project and all projects it
depends on.
The testOSGi
task runs any OSGi JUnit tests in the project's bnd.bnd
file by launching a framework and running the tests in the launched
framework. This means the bnd.bnd
file must have the necessary
-runfw
and -runbundles
to support the test bundles built by
the project. The check
task depends on the testOSGi
task.
The checkDependencies
task runs the check
task on all
projects the project depends on.
The checkNeeded
task runs the check
task on the project and all
projects it depends on.
The cleanDependencies
task cleans all projects the project depends
on.
The cleanNeeded
task cleans the project and all projects it depends
on.
The export.
name tasks, one per bndrun file in the project, exports
the name.bndrun
file to an executable jar.
The export
task will export all the bndrun files to executable jars.
The runbundles.
name tasks, one per bndrun file in the project,
creates a distribution of the -runbundles of the name.bndrun
file.
The runbundles
task will create distributions of the runbundles for
all the bndrun files.
The resolve.
name tasks, one per bndrun file in the project, resolves
the name.bndrun
file and updates the -runbundles
instruction in the
file.
The resolve
task resolves all the bndrun files and updates the -runbundles
instruction in each bndrun file.
The run.
name tasks, one per bndrun file in the project, runs
the name.bndrun
file.
The testrun.
name tasks, one per bndrun file in the project, runs
the OSGi JUnit tests in the name.bndrun
file.
The echo
task will display some help information on the dependencies,
paths and configuration of the project.
The bndproperties
task will display the Bnd properties of the project.
If you do need to write a build.gradle
file for a Bnd project, there
are some properties of the Bnd Gradle Plugins you will find useful.
- The
bndWorkspace
property of the project for the Bnd Workspace contains the Workspace object. - The
bnd.project
property of the project contains the Project object.
Bnd properties for a project can be accessed in several ways. Given the
example property name foo
, you can use the bnd
function,
bnd('foo', 'defaultValue')
, or directly from the bnd extension,
bnd.foo
. To access Bnd properties without any macro processing you can
use the bndUnprocessed
function, bndUnprocessed('foo', 'defaultValue')
.
You can also use the Index
task type described above to generate an
index.
When you use the Gradle plugin for another JVM language like Groovy, Scala, or Kotlin
with your Bnd Workspace build, the Bnd Gradle Plugin will configure the language's
srcDirs
for the main
and test
source sets to use the Bnd source and test source
folders.
If you want to try the latest development SNAPSHOT build of the
Bnd Gradle Plugins, you will need to refer to the snapshot repository
and select the latest version (+
) of the plugin.
For example, replace the pluginManagement
block (in
settings.gradle
) with a buildscript
script block, to configure the repository and
version of the plugin jar:
buildscript {
repositories {
maven {
url 'https://bndtools.jfrog.io/bndtools/libs-snapshot'
}
}
dependencies {
classpath 'biz.aQute.bnd:biz.aQute.bnd.gradle:+'
}
}
Then replace the plugins
block to use the apply plugin:
syntax to apply the plugin. For example:
apply plugin: 'biz.aQute.bnd.workspace'
If you want to use the latest development SNAPSHOT version on a regular basis, you
will need to also need to add the following to the buildscript
block to ensure
Gradle checks more frequently for updates:
buildscript {
...
/* Since the files in the repository change with each build, we need to recheck for changes */
configurations.classpath {
resolutionStrategy {
cacheChangingModulesFor 30, 'minutes'
cacheDynamicVersionsFor 30, 'minutes'
}
}
dependencies {
components {
all { ComponentMetadataDetails details ->
details.changing = true
}
}
}
}
Remember, if you are using the Gradle daemon, you will need to stop it after making the change to use the development SNAPSHOT versions to ensure Gradle stops using the prior version of the plugin.
For full details on what the Bnd Gradle Plugins do, check out the source code.