Skip to content

Commit 425ffa6

Browse files
laeubimerks
authored andcommitted
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 b2b12f1 commit 425ffa6

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

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

@@ -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)