From 4c822cf2ff13f0559a80b3ba53b69a6a028d5211 Mon Sep 17 00:00:00 2001 From: Tim Ward Date: Tue, 30 Jan 2024 12:34:29 +0000 Subject: [PATCH 1/3] Ensure bnd-resolver-maven-plugin verify handles multi-release jars Multi-Release Jars are modelled in bnd using SupportingResource children. When verifying we only care about the *real* resources which end up in the run bundles so we must 1. Permit SupportingResource children to pass through the ResolveCallback 2. Remove SupportingResource children from the resolve result before comparing it Signed-off-by: Tim Ward --- .../it/verify-multirelease/invoker.properties | 7 +++ .../src/it/verify-multirelease/pom.xml | 48 +++++++++++++++++++ .../src/it/verify-multirelease/test.bndrun | 7 +++ .../maven/resolver/plugin/VerifierMojo.java | 26 ++++++++-- 4 files changed, 84 insertions(+), 4 deletions(-) create mode 100644 maven-plugins/bnd-resolver-maven-plugin/src/it/verify-multirelease/invoker.properties create mode 100644 maven-plugins/bnd-resolver-maven-plugin/src/it/verify-multirelease/pom.xml create mode 100644 maven-plugins/bnd-resolver-maven-plugin/src/it/verify-multirelease/test.bndrun diff --git a/maven-plugins/bnd-resolver-maven-plugin/src/it/verify-multirelease/invoker.properties b/maven-plugins/bnd-resolver-maven-plugin/src/it/verify-multirelease/invoker.properties new file mode 100644 index 0000000000..9c7a7746f7 --- /dev/null +++ b/maven-plugins/bnd-resolver-maven-plugin/src/it/verify-multirelease/invoker.properties @@ -0,0 +1,7 @@ +invoker.goals=--no-transfer-progress package + +# Run mvn with --debug for debug logging +#invoker.debug=true + +# Run mvn in debugging mode and wait for a debugger to attach +#invoker.environmentVariables.MAVEN_DEBUG_OPTS=-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=8000 diff --git a/maven-plugins/bnd-resolver-maven-plugin/src/it/verify-multirelease/pom.xml b/maven-plugins/bnd-resolver-maven-plugin/src/it/verify-multirelease/pom.xml new file mode 100644 index 0000000000..16a5c481d7 --- /dev/null +++ b/maven-plugins/bnd-resolver-maven-plugin/src/it/verify-multirelease/pom.xml @@ -0,0 +1,48 @@ + + 4.0.0 + + + biz.aQute.bnd-test + resolver-test + 0.0.1 + ../parent + + + verify-multirelease + 0.0.1 + pom + + + true + + + + + com.fasterxml.jackson.core + jackson-databind + 2.16.1 + + + + + + + biz.aQute.bnd + bnd-resolver-maven-plugin + + + package + + verify + + + false + + + + + + + diff --git a/maven-plugins/bnd-resolver-maven-plugin/src/it/verify-multirelease/test.bndrun b/maven-plugins/bnd-resolver-maven-plugin/src/it/verify-multirelease/test.bndrun new file mode 100644 index 0000000000..a98285c5af --- /dev/null +++ b/maven-plugins/bnd-resolver-maven-plugin/src/it/verify-multirelease/test.bndrun @@ -0,0 +1,7 @@ +-runfw: org.apache.felix.framework +-runrequires: osgi.identity;filter:='(osgi.identity=com.fasterxml.jackson.core.jackson-databind)' + +-runbundles: com.fasterxml.jackson.core.jackson-databind;version='[2.16.1,2.16.2)',\ + com.fasterxml.jackson.core.jackson-core;version='[2.16.1,2.16.2)',\ + com.fasterxml.jackson.core.jackson-annotations;version='[2.16.1,2.16.2)' + \ No newline at end of file diff --git a/maven-plugins/bnd-resolver-maven-plugin/src/main/java/aQute/bnd/maven/resolver/plugin/VerifierMojo.java b/maven-plugins/bnd-resolver-maven-plugin/src/main/java/aQute/bnd/maven/resolver/plugin/VerifierMojo.java index 29034a7f5d..a6d0cf4697 100644 --- a/maven-plugins/bnd-resolver-maven-plugin/src/main/java/aQute/bnd/maven/resolver/plugin/VerifierMojo.java +++ b/maven-plugins/bnd-resolver-maven-plugin/src/main/java/aQute/bnd/maven/resolver/plugin/VerifierMojo.java @@ -21,6 +21,7 @@ import aQute.bnd.osgi.Constants; import aQute.bnd.osgi.resource.CapReqBuilder; import aQute.bnd.osgi.resource.ResourceUtils; +import aQute.bnd.service.resource.SupportingResource; import aQute.bnd.unmodifiable.Sets; import aQute.bnd.version.VersionRange; import biz.aQute.resolve.ResolutionCallback; @@ -168,9 +169,19 @@ private Operation getOperation() { RunResolution result = run.resolve(new BundleFilter(runBundleReqs)); if (result.isOK()) { - List resolved = result.getContainers() + // We only care about the top level results and ignore + // child level supporting resources + List resolved = result.getOrderedResources() .stream() - .map(Container::getBundleId) + .filter(r -> { + if (r instanceof SupportingResource sr) { + return sr.getParent() + .isEmpty(); + } else { + return true; + } + }) + .map(ResourceUtils::getBundleId) .collect(toList()); List missing = expectedRunbundles.stream() @@ -240,8 +251,15 @@ public BundleFilter(List bundleRequirements) { public void processCandidates(Requirement requirement, Set wired, List candidates) { Iterator it = candidates.iterator(); while (it.hasNext()) { - Capability id = ResourceUtils.getIdentityCapability(it.next() - .getResource()); + Resource resource = it.next() + .getResource(); + // If this is a supporting resource we must check the parent + // against the run bundles, not the child supporting resources. + if (resource instanceof SupportingResource sr) { + resource = sr.getParent() + .orElse(sr); + } + Capability id = ResourceUtils.getIdentityCapability(resource); if (bundleRequirements.stream() .noneMatch(r -> ResourceUtils.matches(r, id))) { it.remove(); From e85642c338556629301844e5100ba33c828107a9 Mon Sep 17 00:00:00 2001 From: Tim Ward Date: Tue, 30 Jan 2024 15:50:22 +0000 Subject: [PATCH 2/3] Remove reference to SupportingResource from result processing By making a public method in RunResolution we can avoid filtering in the VerifierMojo and use the same rules that are defined for generating the -runbundles clause. This also prevents us from having to look for SupportingResource instances Signed-off-by: Tim Ward --- .../src/biz/aQute/resolve/RunResolution.java | 16 ++++++++++++++++ .../bnd/maven/resolver/plugin/VerifierMojo.java | 15 +-------------- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/biz.aQute.resolve/src/biz/aQute/resolve/RunResolution.java b/biz.aQute.resolve/src/biz/aQute/resolve/RunResolution.java index 6408b21094..9a24e7e31c 100644 --- a/biz.aQute.resolve/src/biz/aQute/resolve/RunResolution.java +++ b/biz.aQute.resolve/src/biz/aQute/resolve/RunResolution.java @@ -1,5 +1,7 @@ package biz.aQute.resolve; +import static java.util.stream.Collectors.toList; + import java.io.File; import java.lang.annotation.Annotation; import java.util.ArrayList; @@ -30,6 +32,7 @@ import aQute.bnd.help.instructions.ResolutionInstructions; import aQute.bnd.help.instructions.ResolutionInstructions.RunStartLevel; import aQute.bnd.help.instructions.ResolutionInstructions.Runorder; +import aQute.bnd.osgi.BundleId; import aQute.bnd.osgi.Constants; import aQute.bnd.osgi.Processor; import aQute.bnd.osgi.resource.ResourceUtils; @@ -280,6 +283,19 @@ public List getRunBundles() { return versionedClauses; } + /** + * Gets the resolution result as a list of bundle ids that represent the new + * -runbundles + * + * @return the BundleIds of the bundles in the resolution + */ + public List getResolvedRunBundles() { + return getOrderedResources().stream() + .filter(this::isBundle) + .map(ResourceUtils::getBundleId) + .collect(toList()); + } + /** * Return the current -runbundles. * diff --git a/maven-plugins/bnd-resolver-maven-plugin/src/main/java/aQute/bnd/maven/resolver/plugin/VerifierMojo.java b/maven-plugins/bnd-resolver-maven-plugin/src/main/java/aQute/bnd/maven/resolver/plugin/VerifierMojo.java index a6d0cf4697..599d7e1338 100644 --- a/maven-plugins/bnd-resolver-maven-plugin/src/main/java/aQute/bnd/maven/resolver/plugin/VerifierMojo.java +++ b/maven-plugins/bnd-resolver-maven-plugin/src/main/java/aQute/bnd/maven/resolver/plugin/VerifierMojo.java @@ -169,20 +169,7 @@ private Operation getOperation() { RunResolution result = run.resolve(new BundleFilter(runBundleReqs)); if (result.isOK()) { - // We only care about the top level results and ignore - // child level supporting resources - List resolved = result.getOrderedResources() - .stream() - .filter(r -> { - if (r instanceof SupportingResource sr) { - return sr.getParent() - .isEmpty(); - } else { - return true; - } - }) - .map(ResourceUtils::getBundleId) - .collect(toList()); + List resolved = result.getResolvedRunBundles(); List missing = expectedRunbundles.stream() .filter(c -> !resolved.contains(c)) From 09237baf032858d8b32c5f174149fdd9981f99b9 Mon Sep 17 00:00:00 2001 From: Tim Ward Date: Tue, 30 Jan 2024 17:01:10 +0000 Subject: [PATCH 3/3] Remove reference to SupportingResource from resolution callback By using a ResourcesRepository we can avoid the VerifierMojo having to use the SupportingResource. Instead when a resource is added to the repository any SupportingResources are added transparently. This commit adds a convenience method for quickly checking whether a resource is already in the repository. Signed-off-by: Tim Ward --- .../osgi/repository/ResourcesRepository.java | 10 +++++++ .../maven/resolver/plugin/VerifierMojo.java | 27 +++++++++++-------- 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/biz.aQute.bndlib/src/aQute/bnd/osgi/repository/ResourcesRepository.java b/biz.aQute.bndlib/src/aQute/bnd/osgi/repository/ResourcesRepository.java index dd41c10e89..f5c890b6bd 100644 --- a/biz.aQute.bndlib/src/aQute/bnd/osgi/repository/ResourcesRepository.java +++ b/biz.aQute.bndlib/src/aQute/bnd/osgi/repository/ResourcesRepository.java @@ -135,6 +135,16 @@ public List getResources() { return new ArrayList<>(resources); } + /** + * Tests whether the supplied resources is contained in this repository + * + * @param resource the resource to test + * @return true if this resource is already part of this ResourcesRepository + */ + public boolean contains(Resource resource) { + return resources.contains(resource); + } + /** * Returns a collector that accumulates capabilities into a list. * diff --git a/maven-plugins/bnd-resolver-maven-plugin/src/main/java/aQute/bnd/maven/resolver/plugin/VerifierMojo.java b/maven-plugins/bnd-resolver-maven-plugin/src/main/java/aQute/bnd/maven/resolver/plugin/VerifierMojo.java index 599d7e1338..49ec3b6bd8 100644 --- a/maven-plugins/bnd-resolver-maven-plugin/src/main/java/aQute/bnd/maven/resolver/plugin/VerifierMojo.java +++ b/maven-plugins/bnd-resolver-maven-plugin/src/main/java/aQute/bnd/maven/resolver/plugin/VerifierMojo.java @@ -19,9 +19,9 @@ import aQute.bnd.maven.lib.resolve.Scope; import aQute.bnd.osgi.BundleId; import aQute.bnd.osgi.Constants; +import aQute.bnd.osgi.repository.ResourcesRepository; import aQute.bnd.osgi.resource.CapReqBuilder; import aQute.bnd.osgi.resource.ResourceUtils; -import aQute.bnd.service.resource.SupportingResource; import aQute.bnd.unmodifiable.Sets; import aQute.bnd.version.VersionRange; import biz.aQute.resolve.ResolutionCallback; @@ -229,6 +229,12 @@ private Operation getOperation() { private static class BundleFilter implements ResolutionCallback { private final List bundleRequirements; + /** + * We slowly build up a repository of resources which we allow. This + * includes any SupportingResources without us having to introspect + * them. + */ + private final ResourcesRepository repo = new ResourcesRepository(); public BundleFilter(List bundleRequirements) { this.bundleRequirements = bundleRequirements; @@ -240,16 +246,15 @@ public void processCandidates(Requirement requirement, Set wired, Li while (it.hasNext()) { Resource resource = it.next() .getResource(); - // If this is a supporting resource we must check the parent - // against the run bundles, not the child supporting resources. - if (resource instanceof SupportingResource sr) { - resource = sr.getParent() - .orElse(sr); - } - Capability id = ResourceUtils.getIdentityCapability(resource); - if (bundleRequirements.stream() - .noneMatch(r -> ResourceUtils.matches(r, id))) { - it.remove(); + if (!repo.contains(resource)) { + Capability id = ResourceUtils.getIdentityCapability(resource); + if (bundleRequirements.stream() + .noneMatch(r -> ResourceUtils.matches(r, id))) { + // Not part of the repository and not in -runbundles + it.remove(); + } else { + repo.add(resource); + } } } }