Skip to content

Commit 041a144

Browse files
committed
Consider already selected bundles and allow optional to be wiped out
Currently we only filter bundles by our own closure, but if the closure transitively pull in more than junit we can still get things from the target state as there is no alternative. This now adds all selected bundles to the state to make sure we do not miss anything that is already selected. Also we allow optional to be wiped out completely if not from target state.
1 parent 5878cb4 commit 041a144

File tree

1 file changed

+22
-5
lines changed

1 file changed

+22
-5
lines changed

ui/org.eclipse.pde.launching/src/org/eclipse/pde/internal/launching/JUnitLaunchRequirements.java

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@
4646
import org.osgi.framework.wiring.BundleCapability;
4747
import org.osgi.framework.wiring.BundleRequirement;
4848
import org.osgi.framework.wiring.BundleRevision;
49+
import org.osgi.resource.Namespace;
50+
import org.osgi.resource.Requirement;
4951

5052
public class JUnitLaunchRequirements {
5153

@@ -56,16 +58,16 @@ public class JUnitLaunchRequirements {
5658

5759
public static void addRequiredJunitRuntimePlugins(ILaunchConfiguration configuration, Map<String, List<IPluginModelBase>> collectedModels, Map<IPluginModelBase, String> startLevelMap) throws CoreException {
5860
Collection<IPluginModelBase> runtimeBundles = getEclipseJunitRuntimePlugins(configuration, collectedModels, startLevelMap);
59-
List<BundleDescription> roots = runtimeBundles.stream().map(p -> p.getBundleDescription()).filter(Objects::nonNull).toList();
60-
Set<BundleDescription> closure = DependencyManager.findRequirementsClosure(roots);
61-
Collection<BundleDescription> runtimeRequirements = filterRequirementsByState(closure, runtimeBundles, configuration);
61+
List<BundleDescription> roots = modelsAsDescriptions(runtimeBundles).toList();
62+
List<BundleDescription> bundles = Stream.concat(DependencyManager.findRequirementsClosure(roots).stream(), collectedModels.values().stream().flatMap(pl -> modelsAsDescriptions(pl))).distinct().toList();
63+
Collection<BundleDescription> runtimeRequirements = filterRequirementsByState(bundles, runtimeBundles, configuration);
6264
addAbsentRequirements(runtimeRequirements, collectedModels, startLevelMap);
6365
}
6466

6567
private static Collection<BundleDescription> filterRequirementsByState(Collection<BundleDescription> bundles, Collection<IPluginModelBase> rootBundles, ILaunchConfiguration configuration) throws CoreException {
6668
//lookup that maps a copy to the original description from the bundles parameter
6769
Map<BundleRevision, BundleDescription> descriptionnMap = new IdentityHashMap<>();
68-
Set<BundleRevision> rootSet = rootBundles.stream().map(p -> p.getBundleDescription()).filter(Objects::nonNull).collect(Collectors.toSet());
70+
Set<BundleRevision> rootSet = modelsAsDescriptions(rootBundles).collect(Collectors.toSet());
6971
State state = FACTORY.createState(true);
7072
State targetState = PDECore.getDefault().getModelManager().getState().getState();
7173
List<BundleDescription> resolveRoots = new ArrayList<>();
@@ -95,13 +97,18 @@ public void filterResolvable(Collection<BundleRevision> candidates) {
9597

9698
@Override
9799
public void filterMatches(BundleRequirement requirement, Collection<BundleCapability> candidates) {
100+
boolean optional = isOptional(requirement);
101+
if (candidates.size() == 1 && !optional) {
102+
//We only have one candidate and requirement is not optional, so keep it or we get an error!
103+
return;
104+
}
98105
List<BundleCapability> list = candidates.stream().filter(cp -> isFromDifferentState(cp)).toList();
99106
if (list.isEmpty()) {
100107
//nothing to do here...
101108
return;
102109
}
103110
//iterate in reverse order so we remove lower ranked candidates first ...
104-
for (int i = list.size() - 1; i >= 0 && candidates.size() > 1; i--) {
111+
for (int i = list.size() - 1; i >= 0 && (optional || candidates.size() > 1); i--) {
105112
BundleCapability capability = list.get(i);
106113
candidates.remove(capability);
107114
}
@@ -129,6 +136,7 @@ public void end() {
129136
throw new CoreException(Status.error(String.format("%s can not be resolved: %s", rootBundle, Arrays.toString(errors)))); //$NON-NLS-1$
130137
}
131138
}
139+
132140
Collection<BundleDescription> closure = DependencyManager.findRequirementsClosure(resolveRoots);
133141
// map back to the originals!
134142
return closure.stream().map(bd -> descriptionnMap.get(bd)).filter(Objects::nonNull).toList();
@@ -195,4 +203,13 @@ private static IPluginModelBase findRequiredPluginInTargetOrHost(IPluginModelBas
195203
return model;
196204
}
197205

206+
private static Stream<BundleDescription> modelsAsDescriptions(Collection<IPluginModelBase> runtimeBundles) {
207+
return runtimeBundles.stream().map(p -> p.getBundleDescription()).filter(Objects::nonNull);
208+
}
209+
210+
private static boolean isOptional(Requirement req) {
211+
String resolution = req.getDirectives().get(Namespace.REQUIREMENT_RESOLUTION_DIRECTIVE);
212+
return Namespace.RESOLUTION_OPTIONAL.equalsIgnoreCase(resolution);
213+
}
214+
198215
}

0 commit comments

Comments
 (0)