Skip to content

Commit 93e5e98

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 5019aa1 commit 93e5e98

File tree

1 file changed

+40
-7
lines changed

1 file changed

+40
-7
lines changed

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

+40-7
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

@@ -35,10 +37,13 @@
3537
import org.eclipse.pde.core.target.NameVersionDescriptor;
3638
import org.osgi.framework.Constants;
3739
import org.osgi.framework.Version;
40+
import org.osgi.framework.wiring.BundleCapability;
3841
import org.osgi.framework.wiring.BundleRequirement;
3942
import org.osgi.framework.wiring.BundleRevision;
4043
import org.osgi.framework.wiring.BundleWire;
4144
import org.osgi.framework.wiring.BundleWiring;
45+
import org.osgi.resource.Capability;
46+
import org.osgi.resource.Namespace;
4247
import org.osgi.resource.Resource;
4348

4449
/**
@@ -172,12 +177,12 @@ public static Set<BundleDescription> findRequirementsClosure(Collection<BundleDe
172177

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

176182
// initialize with given bundles
177183
for (BundleDescription bundle : bundles) {
178-
addNewRequiredBundle(bundle, closure, pending);
184+
addNewRequiredBundle(bundle, closure, pending, provided);
179185
}
180-
181186
// perform exhaustive iterative bfs for required wires
182187
while (!pending.isEmpty()) {
183188
BundleDescription bundle = pending.remove();
@@ -191,14 +196,18 @@ public static Set<BundleDescription> findRequirementsClosure(Collection<BundleDe
191196
// A fragment's host is already required by a wire
192197
for (BundleDescription fragment : bundle.getFragments()) {
193198
if (includeAllFragments || !isTestWorkspaceProject(fragment)) {
194-
addNewRequiredBundle(fragment, closure, pending);
199+
addNewRequiredBundle(fragment, closure, pending, provided);
195200
}
196201
}
197202
}
198203

199204
List<BundleWire> requiredWires = wiring.getRequiredWires(null);
200205
for (BundleWire wire : requiredWires) {
201-
BundleRevision declaringBundle = wire.getRequirement().getRevision();
206+
BundleRequirement requirement = wire.getRequirement();
207+
if (isSingle(requirement) && isAlreadyProvided(requirement, provided)) {
208+
continue;
209+
}
210+
BundleRevision declaringBundle = requirement.getRevision();
202211
if (declaringBundle != bundle && !closure.contains(declaringBundle)) {
203212
// Requirement is declared by an attached fragment, which is
204213
// not included into the closure.
@@ -207,18 +216,42 @@ public static Set<BundleDescription> findRequirementsClosure(Collection<BundleDe
207216
BundleRevision provider = wire.getCapability().getRevision();
208217
// Use revision of required capability to support the case if
209218
// fragments contribute new packages to their host's API.
210-
if (provider instanceof BundleDescription requiredBundle && (includeOptional || !isOptional(wire.getRequirement()))) {
211-
addNewRequiredBundle(requiredBundle, closure, pending);
219+
if (provider instanceof BundleDescription requiredBundle && (includeOptional || !isOptional(requirement))) {
220+
addNewRequiredBundle(requiredBundle, closure, pending, provided);
212221
}
213222
}
214223
}
215224
return closure;
216225
}
217226

227+
private static boolean isSingle(BundleRequirement requirement) {
228+
return Namespace.CARDINALITY_SINGLE.equals(requirement.getDirectives()
229+
.getOrDefault(Namespace.REQUIREMENT_CARDINALITY_DIRECTIVE, Namespace.CARDINALITY_SINGLE));
230+
}
231+
232+
protected static boolean isAlreadyProvided(BundleRequirement requirement,
233+
Map<String, List<BundleCapability>> provided) {
234+
List<BundleCapability> list = provided.get(requirement.getNamespace());
235+
if (list != null && !list.isEmpty()) {
236+
for (BundleCapability bundleCapability : list) {
237+
if (requirement.matches(bundleCapability)) {
238+
return true;
239+
}
240+
}
241+
}
242+
return false;
243+
}
244+
218245
private static void addNewRequiredBundle(BundleDescription bundle, Set<BundleDescription> requiredBundles,
219-
Queue<BundleDescription> pending) {
246+
Queue<BundleDescription> pending, Map<String, List<BundleCapability>> provided) {
220247
if (bundle != null && bundle.isResolved() && !bundle.isRemovalPending() && requiredBundles.add(bundle)) {
221248
pending.add(bundle);
249+
List<Capability> capabilities = bundle.getCapabilities(null);
250+
for (Capability capability : capabilities) {
251+
if (capability instanceof BundleCapability bc) {
252+
provided.computeIfAbsent(capability.getNamespace(), nil -> new ArrayList<>()).add(bc);
253+
}
254+
}
222255
}
223256
}
224257

0 commit comments

Comments
 (0)