Skip to content

Commit

Permalink
gradle: Avoid setting a manifest object
Browse files Browse the repository at this point in the history
Rather than setting a manifest object in the task so that we can
set the effective manifest after building, we instead merge the
generated manifest into the existing manifest object.

Fixes #5275

Signed-off-by: BJ Hargrave <bj@hargrave.dev>
  • Loading branch information
bjhargrave committed Jun 4, 2022
1 parent 03d29ef commit ec20b95
Showing 1 changed file with 26 additions and 94 deletions.
Expand Up @@ -37,9 +37,6 @@
import org.gradle.api.file.FileCollection;
import org.gradle.api.file.ProjectLayout;
import org.gradle.api.file.RegularFileProperty;
import org.gradle.api.java.archives.Attributes;
import org.gradle.api.java.archives.ManifestException;
import org.gradle.api.java.archives.ManifestMergeSpec;
import org.gradle.api.java.archives.internal.DefaultManifest;
import org.gradle.api.model.ObjectFactory;
import org.gradle.api.provider.ListProperty;
Expand All @@ -66,7 +63,6 @@
import aQute.lib.io.IO;
import aQute.lib.strings.Strings;
import aQute.lib.utf8properties.UTF8Properties;
import groovy.lang.Closure;

/**
* BundleTaskExtension for Gradle.
Expand Down Expand Up @@ -100,7 +96,6 @@ public class BundleTaskExtension {
private final ConfigurableFileCollection classpath;
private final Provider<String> bnd;
private final MapProperty<String, Object> properties;
private final EffectiveManifest effectiveManifest;

/**
* The bndfile property.
Expand Down Expand Up @@ -216,12 +211,6 @@ public BundleTaskExtension(org.gradle.api.tasks.bundling.Jar task) {
classpath(mainSourceSet.getCompileClasspath());
properties = objects.mapProperty(String.class, Object.class)
.convention(Maps.of("project", "__convention__"));
// Wrap manifest
org.gradle.api.java.archives.Manifest manifest = task.getManifest();
effectiveManifest = new EffectiveManifest(manifest);
if (manifest != null) {
task.setManifest(effectiveManifest);
}
// need to programmatically add to inputs since @InputFiles in a
// extension is not processed
task.getInputs()
Expand Down Expand Up @@ -367,6 +356,8 @@ public void execute(Task t) {
File buildDir = unwrapFile(getLayout().getBuildDirectory());
File buildFile = getBuildFile();
FileCollection sourcepath = getAllSource().filter(file -> file.exists());
Optional<org.gradle.api.java.archives.Manifest> taskManifest = Optional
.ofNullable(getTask().getManifest());
// create Builder
Properties gradleProperties = new BeanProperties();
gradleProperties.putAll(unwrap(getProperties()));
Expand All @@ -379,14 +370,14 @@ public void execute(Task t) {
try (Writer writer = IO.writer(temporaryBndFile)) {
// write any task manifest entries into the tmp bnd
// file
Optional<UTF8Properties> properties = Optional.ofNullable(getTask().getManifest())
.map(manifest -> MapStream.ofNullable(manifest.getEffectiveManifest()
Optional<UTF8Properties> properties = taskManifest.map(manifest -> MapStream
.ofNullable(manifest.getEffectiveManifest()
.getAttributes())
.filterKey(key -> !Objects.equals(key, "Manifest-Version"))
.mapValue(Object::toString)
.collect(MapStream.toMap((k1, k2) -> {
throw new IllegalStateException("Duplicate key " + k1);
}, UTF8Properties::new)));
.filterKey(key -> !Objects.equals(key, "Manifest-Version"))
.mapValue(Object::toString)
.collect(MapStream.toMap((k1, k2) -> {
throw new IllegalStateException("Duplicate key " + k1);
}, UTF8Properties::new)));
if (properties.isPresent()) {
properties.get()
.replaceHere(projectDir)
Expand Down Expand Up @@ -514,8 +505,15 @@ public void execute(Task t) {
builtJar.write(archiveFile);
long now = System.currentTimeMillis();
archiveFile.setLastModified(now);
// Set effective manifest to generated manifest
effectiveManifest.setEffectiveManifest(builtJar.getManifest());
// Set effective manifest from generated manifest
Manifest builtManifest = builtJar.getManifest();
taskManifest.ifPresent(
manifest -> manifest.from(mergeManifest(builtManifest), merge -> merge.eachEntry(details -> {
if (details.getMergeValue() == null) {
// exclude if entry not in merge manifest
details.exclude();
}
})));
logReport(builder, getTask().getLogger());
if (!builder.isOk()) {
failTask("Bundle " + archiveFileName + " has errors", archiveFile);
Expand All @@ -526,6 +524,14 @@ public void execute(Task t) {
}
}

private org.gradle.api.java.archives.Manifest mergeManifest(Manifest builtManifest) {
org.gradle.api.java.archives.Manifest mergeManifest = new DefaultManifest(null);
mergeManifest.attributes(new AttributesMap(builtManifest.getMainAttributes()));
builtManifest.getEntries()
.forEach((section, attrs) -> mergeManifest.attributes(new AttributesMap(attrs), section));
return mergeManifest;
}

private void failTask(String msg, File archiveFile) {
IO.delete(archiveFile);
throw new GradleException(msg);
Expand All @@ -537,80 +543,6 @@ private boolean isEmpty(String header) {
}
}

static final class EffectiveManifest implements org.gradle.api.java.archives.Manifest {
final org.gradle.api.java.archives.Manifest delegate;
Manifest effectiveManifest;

EffectiveManifest(org.gradle.api.java.archives.Manifest delegate) {
this.delegate = delegate;
this.effectiveManifest = null;
}

void setEffectiveManifest(Manifest effectiveManifest) {
this.effectiveManifest = effectiveManifest;
}

@Override
public org.gradle.api.java.archives.Manifest attributes(Map<String, ?> attributes) throws ManifestException {
delegate.attributes(attributes);
return this;
}

@Override
public org.gradle.api.java.archives.Manifest attributes(Map<String, ?> attributes, String sectionName)
throws ManifestException {
delegate.attributes(attributes, sectionName);
return this;
}

@Override
public org.gradle.api.java.archives.Manifest from(Object... mergePath) {
delegate.from(mergePath);
return this;
}

@Override
public org.gradle.api.java.archives.Manifest from(Object mergePath, Closure<?> closure) {
delegate.from(mergePath, closure);
return this;
}

@Override
public org.gradle.api.java.archives.Manifest from(Object mergePath, Action<ManifestMergeSpec> action) {
delegate.from(mergePath, action);
return this;
}

@Override
public Attributes getAttributes() {
return delegate.getAttributes();
}

@Override
public org.gradle.api.java.archives.Manifest getEffectiveManifest() {
Manifest effectiveManifest = this.effectiveManifest;
if (effectiveManifest == null) {
return delegate.getEffectiveManifest();
}
org.gradle.api.java.archives.Manifest result = new DefaultManifest(null);
result.attributes(new AttributesMap(effectiveManifest.getMainAttributes()));
effectiveManifest.getEntries()
.forEach((section, attrs) -> result.attributes(new AttributesMap(attrs), section));
return result;
}

@Override
public Map<String, Attributes> getSections() {
return delegate.getSections();
}

@Override
public org.gradle.api.java.archives.Manifest writeTo(Object path) {
getEffectiveManifest().writeTo(path);
return this;
}
}

static final class AttributesMap extends AbstractMap<String, Object> {
final java.util.jar.Attributes source;

Expand Down

0 comments on commit ec20b95

Please sign in to comment.