Skip to content

Commit 4a39b83

Browse files
committed
Don't include more bundles if the requirement is already fulfilled
Currently PDE includes everything wired in the target platform even though a requirement might already be fulfilled and only has single cardinality. This now tracks all capabilities provided and check if a single cardinality is already fulfilled by some of the bundles chosen.
1 parent ea1089d commit 4a39b83

1 file changed

Lines changed: 40 additions & 7 deletions

File tree

ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/DependencyManager.java

Lines changed: 40 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,10 @@
2020
import java.util.Arrays;
2121
import java.util.Collection;
2222
import java.util.Collections;
23+
import java.util.HashMap;
2324
import java.util.HashSet;
2425
import java.util.List;
26+
import java.util.Map;
2527
import java.util.Queue;
2628
import java.util.Set;
2729

@@ -36,10 +38,13 @@
3638
import org.osgi.framework.Constants;
3739
import org.osgi.framework.Version;
3840
import org.osgi.framework.namespace.HostNamespace;
41+
import org.osgi.framework.wiring.BundleCapability;
3942
import org.osgi.framework.wiring.BundleRequirement;
4043
import org.osgi.framework.wiring.BundleRevision;
4144
import org.osgi.framework.wiring.BundleWire;
4245
import org.osgi.framework.wiring.BundleWiring;
46+
import org.osgi.resource.Capability;
47+
import org.osgi.resource.Namespace;
4348
import org.osgi.resource.Resource;
4449

4550
/**
@@ -173,12 +178,12 @@ public static Set<BundleDescription> findRequirementsClosure(Collection<BundleDe
173178

174179
Set<BundleDescription> closure = new HashSet<>(bundles.size() * 4 / 3 + 1);
175180
Queue<BundleDescription> pending = new ArrayDeque<>(bundles.size());
181+
Map<String, List<BundleCapability>> provided = new HashMap<>();
176182

177183
// initialize with given bundles
178184
for (BundleDescription bundle : bundles) {
179-
addNewRequiredBundle(bundle, closure, pending);
185+
addNewRequiredBundle(bundle, closure, pending, provided);
180186
}
181-
182187
// perform exhaustive iterative bfs for required wires
183188
while (!pending.isEmpty()) {
184189
BundleDescription bundle = pending.remove();
@@ -192,7 +197,7 @@ public static Set<BundleDescription> findRequirementsClosure(Collection<BundleDe
192197
// A fragment's host is already required by a wire
193198
for (BundleDescription fragment : bundle.getFragments()) {
194199
if (includeAllFragments || !isTestWorkspaceProject(fragment)) {
195-
addNewRequiredBundle(fragment, closure, pending);
200+
addNewRequiredBundle(fragment, closure, pending, provided);
196201
}
197202
}
198203
}
@@ -212,7 +217,11 @@ public static Set<BundleDescription> findRequirementsClosure(Collection<BundleDe
212217

213218
List<BundleWire> requiredWires = wiring.getRequiredWires(null);
214219
for (BundleWire wire : requiredWires) {
215-
BundleRevision declaringBundle = wire.getRequirement().getRevision();
220+
BundleRequirement requirement = wire.getRequirement();
221+
if (isSingle(requirement) && isAlreadyProvided(requirement, provided)) {
222+
continue;
223+
}
224+
BundleRevision declaringBundle = requirement.getRevision();
216225
if (declaringBundle != bundle && !closure.contains(declaringBundle)) {
217226
// Requirement is declared by an attached fragment, which is
218227
// not included into the closure.
@@ -221,18 +230,42 @@ public static Set<BundleDescription> findRequirementsClosure(Collection<BundleDe
221230
BundleRevision provider = wire.getCapability().getRevision();
222231
// Use revision of required capability to support the case if
223232
// fragments contribute new packages to their host's API.
224-
if (provider instanceof BundleDescription requiredBundle && (includeOptional || !isOptional(wire.getRequirement()))) {
225-
addNewRequiredBundle(requiredBundle, closure, pending);
233+
if (provider instanceof BundleDescription requiredBundle && (includeOptional || !isOptional(requirement))) {
234+
addNewRequiredBundle(requiredBundle, closure, pending, provided);
226235
}
227236
}
228237
}
229238
return closure;
230239
}
231240

241+
private static boolean isSingle(BundleRequirement requirement) {
242+
return Namespace.CARDINALITY_SINGLE.equals(requirement.getDirectives()
243+
.getOrDefault(Namespace.REQUIREMENT_CARDINALITY_DIRECTIVE, Namespace.CARDINALITY_SINGLE));
244+
}
245+
246+
protected static boolean isAlreadyProvided(BundleRequirement requirement,
247+
Map<String, List<BundleCapability>> provided) {
248+
List<BundleCapability> list = provided.get(requirement.getNamespace());
249+
if (list != null && !list.isEmpty()) {
250+
for (BundleCapability bundleCapability : list) {
251+
if (requirement.matches(bundleCapability)) {
252+
return true;
253+
}
254+
}
255+
}
256+
return false;
257+
}
258+
232259
private static void addNewRequiredBundle(BundleDescription bundle, Set<BundleDescription> requiredBundles,
233-
Queue<BundleDescription> pending) {
260+
Queue<BundleDescription> pending, Map<String, List<BundleCapability>> provided) {
234261
if (bundle != null && bundle.isResolved() && !bundle.isRemovalPending() && requiredBundles.add(bundle)) {
235262
pending.add(bundle);
263+
List<Capability> capabilities = bundle.getCapabilities(null);
264+
for (Capability capability : capabilities) {
265+
if (capability instanceof BundleCapability bc) {
266+
provided.computeIfAbsent(capability.getNamespace(), nil -> new ArrayList<>()).add(bc);
267+
}
268+
}
236269
}
237270
}
238271

0 commit comments

Comments
 (0)