Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gradle: Make default Bundle-SymbolicName and Bundle-Version inputs #5280

Merged
merged 2 commits into from Jun 14, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -8,7 +8,6 @@
import static aQute.bnd.gradle.BndUtils.unwrap;
import static aQute.bnd.gradle.BndUtils.unwrapFile;
import static aQute.bnd.gradle.BndUtils.unwrapFileOptional;
import static aQute.bnd.gradle.BndUtils.unwrapOptional;
import static java.util.Collections.singletonList;
import static java.util.Objects.requireNonNull;
import static java.util.stream.Collectors.toList;
Expand All @@ -29,6 +28,17 @@
import java.util.jar.Manifest;
import java.util.zip.ZipFile;

import aQute.bnd.exceptions.Exceptions;
import aQute.bnd.osgi.Builder;
import aQute.bnd.osgi.Constants;
import aQute.bnd.osgi.Jar;
import aQute.bnd.osgi.Processor;
import aQute.bnd.stream.MapStream;
import aQute.bnd.unmodifiable.Maps;
import aQute.bnd.version.MavenVersion;
import aQute.lib.io.IO;
import aQute.lib.strings.Strings;
import aQute.lib.utf8properties.UTF8Properties;
import org.gradle.api.Action;
import org.gradle.api.GradleException;
import org.gradle.api.Project;
Expand All @@ -52,18 +62,6 @@
import org.gradle.api.tasks.TaskInputFilePropertyBuilder;
import org.gradle.work.NormalizeLineEndings;

import aQute.bnd.exceptions.Exceptions;
import aQute.bnd.osgi.Builder;
import aQute.bnd.osgi.Constants;
import aQute.bnd.osgi.Jar;
import aQute.bnd.osgi.Processor;
import aQute.bnd.stream.MapStream;
import aQute.bnd.unmodifiable.Maps;
import aQute.bnd.version.MavenVersion;
import aQute.lib.io.IO;
import aQute.lib.strings.Strings;
import aQute.lib.utf8properties.UTF8Properties;

/**
* BundleTaskExtension for Gradle.
* <p>
Expand Down Expand Up @@ -96,6 +94,8 @@ public class BundleTaskExtension {
private final ConfigurableFileCollection classpath;
private final Provider<String> bnd;
private final MapProperty<String, Object> properties;
private final Provider<String> defaultBundleSymbolicName;
private final Provider<String> defaultBundleVersion;

/**
* The bndfile property.
Expand Down Expand Up @@ -131,7 +131,7 @@ public ConfigurableFileCollection getClasspath() {
* If the bndfile property points an existing file, this property is
* ignored. Otherwise, the bnd instructions in this property will be used.
*
* @return The property for the bnd instructions.
* @return The provider for the bnd instructions.
*/
@Input
@org.gradle.api.tasks.Optional
Expand Down Expand Up @@ -211,6 +211,13 @@ public BundleTaskExtension(org.gradle.api.tasks.bundling.Jar task) {
classpath(mainSourceSet.getCompileClasspath());
properties = objects.mapProperty(String.class, Object.class)
.convention(Maps.of("project", "__convention__"));
defaultBundleSymbolicName = task.getArchiveBaseName()
.zip(task.getArchiveClassifier(), (baseName, classifier) -> classifier.isEmpty() ? baseName : baseName + "-" + classifier);
defaultBundleVersion = task.getArchiveVersion()
.orElse("0")
.map(version -> MavenVersion.parseMavenString(version)
.getOSGiVersion()
.toString());
// need to programmatically add to inputs since @InputFiles in a
// extension is not processed
task.getInputs()
Expand All @@ -229,6 +236,10 @@ public BundleTaskExtension(org.gradle.api.tasks.bundling.Jar task) {
.property("bnd", getBnd());
task.getInputs()
.property("properties", getProperties());
task.getInputs()
.property("default Bundle-SymbolicName", getDefaultBundleSymbolicName());
task.getInputs()
.property("default Bundle-Version", getDefaultBundleVersion());
}

/**
Expand Down Expand Up @@ -331,6 +342,30 @@ File getBuildFile() {
return buildFile;
}

/**
* The default value for the Bundle-SymbolicName manifest header.
* <p>
* If the Bundle-SymbolicName manifest header is not set in the bnd instructions,
* the value of this provider will be used.
*
* @return The provider for the default Bundle-SymbolicName manifest header.
*/
Provider<String> getDefaultBundleSymbolicName() {
return defaultBundleSymbolicName;
}

/**
* The default value for the Bundle-Version manifest header.
* <p>
* If the Bundle-Version manifest header is not set in the bnd instructions,
* the value of this provider will be used.
*
* @return The provider for the default Bundle-Version manifest header.
*/
Provider<String> getDefaultBundleVersion() {
return defaultBundleVersion;
}

ProjectLayout getLayout() {
return layout;
}
Expand Down Expand Up @@ -374,7 +409,7 @@ public void execute(Task t) {
.ofNullable(manifest.getEffectiveManifest()
.getAttributes())
.filterKey(key -> !Objects.equals(key, "Manifest-Version"))
.mapValue(Object::toString)
.mapValue(this::unwrapAttributeValue)
.collect(MapStream.toMap((k1, k2) -> {
throw new IllegalStateException("Duplicate key " + k1);
}, UTF8Properties::new)));
Expand Down Expand Up @@ -412,9 +447,6 @@ public void execute(Task t) {
}
File archiveFile = unwrapFile(getTask().getArchiveFile());
String archiveFileName = unwrap(getTask().getArchiveFileName());
String archiveBaseName = unwrap(getTask().getArchiveBaseName());
String archiveClassifier = unwrap(getTask().getArchiveClassifier());
String archiveVersion = unwrapOptional(getTask().getArchiveVersion()).orElse(null);

// Include entire contents of Jar task generated jar
// (except the manifest)
Expand Down Expand Up @@ -472,22 +504,18 @@ public void execute(Task t) {
.toArray(new File[0]));
getTask().getLogger()
.debug("builder sourcepath: {}", builder.getSourcePath());
// set bundle symbolic name from tasks's archiveBaseName
// property if necessary
// set bundle symbolic name if necessary
String bundleSymbolicName = builder.getProperty(Constants.BUNDLE_SYMBOLICNAME);
if (isEmpty(bundleSymbolicName)) {
bundleSymbolicName = archiveClassifier.isEmpty() ? archiveBaseName
: archiveBaseName + "-" + archiveClassifier;
bundleSymbolicName = unwrap(getDefaultBundleSymbolicName());
builder.setProperty(Constants.BUNDLE_SYMBOLICNAME, bundleSymbolicName);
}

// set bundle version from task's archiveVersion if
// necessary
// set bundle version if necessary
String bundleVersion = builder.getProperty(Constants.BUNDLE_VERSION);
if (isEmpty(bundleVersion)) {
builder.setProperty(Constants.BUNDLE_VERSION, MavenVersion.parseMavenString(archiveVersion)
.getOSGiVersion()
.toString());
bundleVersion = unwrap(getDefaultBundleVersion());
builder.setProperty(Constants.BUNDLE_VERSION, bundleVersion);
}

getTask().getLogger()
Expand Down Expand Up @@ -532,6 +560,16 @@ private org.gradle.api.java.archives.Manifest mergeManifest(Manifest builtManife
return mergeManifest;
}

private String unwrapAttributeValue(Object value) {
while (value instanceof Provider) {
value = ((Provider<?>) value).getOrNull();
}
if (value == null) {
return null;
}
return value.toString();
}

private void failTask(String msg, File archiveFile) {
IO.delete(archiveFile);
throw new GradleException(msg);
Expand Down
Expand Up @@ -147,17 +147,19 @@ class TestBundlePlugin extends Specification {
result.task(":bundle").outcome == SUCCESS
result.task(":jar").outcome == SUCCESS

File jartask_result = new File(testProjectBuildDir, "libs/${testProject}-1.0.0.jar")
File jartask_result = new File(testProjectBuildDir, "libs/${testProject}.jar")
jartask_result.isFile()
JarFile jartask_jar = new JarFile(jartask_result)
Attributes jartask_manifest = jartask_jar.getManifest().getMainAttributes()

File bundletask_bundle = new File(testProjectBuildDir, "libs/${testProject}-1.0.0-bundle.jar")
File bundletask_bundle = new File(testProjectBuildDir, "libs/${testProject}-bundle.jar")
bundletask_bundle.isFile()
JarFile bundletask_jar = new JarFile(bundletask_bundle)
Attributes bundletask_manifest = bundletask_jar.getManifest().getMainAttributes()

jartask_manifest.getValue("XX-Signed") == "true"
bundletask_manifest.getValue("Bundle-SymbolicName") == "${testProject}-bundle"
bundletask_manifest.getValue("Bundle-Version") == "0.0.0"
bundletask_manifest.getValue("XX-Signed") == "true"
bundletask_manifest.getValue("YY-Sealed") == "true"
bundletask_manifest.getValue("ZZ-Delivered") == "true"
Expand Down
Expand Up @@ -25,7 +25,7 @@ dependencies {
jar {
ext.taskprop = 'prop.task'
manifest {
attributes('Implementation-Title': project.archivesBaseName,
attributes('Implementation-Title': providers.provider({ -> project.archivesBaseName}),
'Implementation-Version': project.version,
'-includeresource': '{${.}/bar.txt}',
'-include': '${.}/other.bnd',
Expand Down
Expand Up @@ -10,7 +10,6 @@ plugins {
}

group = 'test.bnd.gradle'
version = '1.0.0'

repositories {
mavenCentral()
Expand All @@ -19,7 +18,6 @@ repositories {
ext {
extraInstructions = provider {
'''\
YY-Sealed: true
ZZ-Delivered: true
'''
}
Expand All @@ -28,7 +26,7 @@ ZZ-Delivered: true
// Not a bundle.
def jarTask = tasks.named('jar', Jar) {
manifest {
attributes('XX-Signed': true)
attributes('XX-Signed': provider({true}))
}
}

Expand All @@ -37,16 +35,19 @@ task bundle(type: Bundle) {
group = 'build'
from jarTask.map { zipTree(it.archiveFile) }
archiveClassifier = 'bundle'
manifest {
attributes('YY-Sealed': provider({true}))
}

bundle {
bnd = jarTask.flatMap { jar ->
jar.archiveFile.map { file ->
"-include: jar:${file.asFile.toURI()}!/META-INF/MANIFEST.MF"
}
}

bnd extraInstructions

bnd '''
Bundle-Name: ${project.group}:${task.archiveBaseName}-${task.archiveClassifier}
'''
Expand Down