Skip to content

Commit 27f380f

Browse files
committed
Filter bundles with preference for the target state
Currently it can happen that one bundle (in this particular case org.eclipse.pde.junit.runtime) is not part of the target platform and therefore selected from the running host. This then pull in even more from the host through the DependencyManager collection leading to duplicates all over the place. As long as target and host are equal enough it does not cause any problem as id+version are the same and so are canceled out but if not this leads to multiple version unnecessary included and this is especially a problem for singletons. This now: - collects all items as before - put everything into a new state and performs a resolve operation - during the resolve make sure we filter out providers whenever there is an alternative from the target platform. Fix #2082
1 parent 262249d commit 27f380f

File tree

2 files changed

+108
-22
lines changed

2 files changed

+108
-22
lines changed

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

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@
4747
import org.eclipse.pde.core.project.IBundleProjectService;
4848
import org.eclipse.pde.core.target.ITargetDefinition;
4949
import org.eclipse.pde.core.target.ITargetPlatformService;
50-
import org.eclipse.pde.internal.build.IPDEBuildConstants;
5150
import org.eclipse.pde.internal.core.bnd.BndResourceChangeListener;
5251
import org.eclipse.pde.internal.core.bnd.BndWorkspaceServiceFactory;
5352
import org.eclipse.pde.internal.core.builders.FeatureRebuilder;
@@ -245,11 +244,6 @@ public PDECore() {
245244
* {@link #VERSION} comparator.
246245
*/
247246
public Stream<IPluginModelBase> findPluginsInHost(String id) {
248-
if (IPDEBuildConstants.BUNDLE_OSGI.equals(id)) {
249-
// Do not expose the OSGi framework from the host see
250-
// https://github.com/eclipse-pde/eclipse.pde/issues/2082
251-
return Stream.empty();
252-
}
253247
Map<String, List<IPluginModelBase>> hostPlugins = getHostPlugins();
254248
if (hostPlugins == null) {
255249
return null;

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

Lines changed: 108 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -14,40 +14,126 @@
1414
package org.eclipse.pde.internal.launching;
1515

1616
import java.util.ArrayList;
17+
import java.util.Arrays;
1718
import java.util.Collection;
19+
import java.util.IdentityHashMap;
1820
import java.util.LinkedHashSet;
1921
import java.util.List;
2022
import java.util.Map;
23+
import java.util.Objects;
2124
import java.util.Optional;
2225
import java.util.Set;
2326
import java.util.function.Function;
27+
import java.util.stream.Collectors;
2428
import java.util.stream.Stream;
2529

2630
import org.eclipse.core.runtime.CoreException;
2731
import org.eclipse.core.runtime.Status;
2832
import org.eclipse.debug.core.ILaunchConfiguration;
2933
import org.eclipse.osgi.service.resolver.BundleDescription;
34+
import org.eclipse.osgi.service.resolver.ResolverError;
35+
import org.eclipse.osgi.service.resolver.State;
36+
import org.eclipse.osgi.service.resolver.StateObjectFactory;
3037
import org.eclipse.osgi.util.NLS;
3138
import org.eclipse.pde.core.plugin.IPluginModelBase;
3239
import org.eclipse.pde.core.plugin.PluginRegistry;
40+
import org.eclipse.pde.internal.build.BundleHelper;
3341
import org.eclipse.pde.internal.core.DependencyManager;
3442
import org.eclipse.pde.internal.core.PDECore;
3543
import org.eclipse.pde.internal.launching.launcher.BundleLauncherHelper;
44+
import org.osgi.framework.hooks.resolver.ResolverHook;
45+
import org.osgi.framework.hooks.resolver.ResolverHookFactory;
46+
import org.osgi.framework.wiring.BundleCapability;
47+
import org.osgi.framework.wiring.BundleRequirement;
3648
import org.osgi.framework.wiring.BundleRevision;
3749

3850
public class JUnitLaunchRequirements {
3951

52+
private static final StateObjectFactory FACTORY = BundleHelper.getPlatformAdmin().getFactory();
4053
private static final String PDE_JUNIT_RUNTIME = "org.eclipse.pde.junit.runtime"; //$NON-NLS-1$
4154
private static final String JUNIT4_JDT_RUNTIME_PLUGIN = "org.eclipse.jdt.junit4.runtime"; //$NON-NLS-1$
4255
private static final String JUNIT5_JDT_RUNTIME_PLUGIN = "org.eclipse.jdt.junit5.runtime"; //$NON-NLS-1$
4356

4457
public static void addRequiredJunitRuntimePlugins(ILaunchConfiguration configuration, Map<String, List<IPluginModelBase>> collectedModels, Map<IPluginModelBase, String> startLevelMap) throws CoreException {
45-
Collection<String> runtimePlugins = getRequiredJunitRuntimeEclipsePlugins(configuration);
46-
Set<BundleDescription> addedRuntimeBundles = addAbsentRequirements(runtimePlugins, collectedModels, startLevelMap);
47-
Set<BundleDescription> runtimeRequirements = DependencyManager.findRequirementsClosure(addedRuntimeBundles);
58+
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);
4862
addAbsentRequirements(runtimeRequirements, collectedModels, startLevelMap);
4963
}
5064

65+
private static Collection<BundleDescription> filterRequirementsByState(Collection<BundleDescription> bundles, Collection<IPluginModelBase> rootBundles, ILaunchConfiguration configuration) throws CoreException {
66+
//lookup that maps a copy to the original description from the bundles parameter
67+
Map<BundleRevision, BundleDescription> descriptionnMap = new IdentityHashMap<>();
68+
Set<BundleRevision> rootSet = rootBundles.stream().map(p -> p.getBundleDescription()).filter(Objects::nonNull).collect(Collectors.toSet());
69+
State state = FACTORY.createState(true);
70+
State targetState = PDECore.getDefault().getModelManager().getState().getState();
71+
List<BundleDescription> resolveRoots = new ArrayList<>();
72+
long id = 1;
73+
for (BundleDescription bundle : bundles) {
74+
BundleDescription copy = FACTORY.createBundleDescription(id++, bundle);
75+
descriptionnMap.put(copy, bundle);
76+
state.addBundle(copy);
77+
if (rootSet.contains(bundle)) {
78+
resolveRoots.add(copy);
79+
}
80+
}
81+
state.setPlatformProperties(targetState.getPlatformProperties());
82+
state.setResolverHookFactory(new ResolverHookFactory() {
83+
84+
@Override
85+
public ResolverHook begin(Collection<BundleRevision> triggers) {
86+
return new ResolverHook() {
87+
88+
@Override
89+
public void filterSingletonCollisions(BundleCapability singleton, Collection<BundleCapability> collisionCandidates) {
90+
}
91+
92+
@Override
93+
public void filterResolvable(Collection<BundleRevision> candidates) {
94+
}
95+
96+
@Override
97+
public void filterMatches(BundleRequirement requirement, Collection<BundleCapability> candidates) {
98+
List<BundleCapability> list = candidates.stream().filter(cp -> isFromDifferentState(cp)).toList();
99+
if (list.isEmpty()) {
100+
//nothing to do here...
101+
return;
102+
}
103+
//iterate in reverse order so we remove lower ranked candidates first ...
104+
for (int i = list.size() - 1; i >= 0 && candidates.size() > 1; i--) {
105+
BundleCapability capability = list.get(i);
106+
candidates.remove(capability);
107+
}
108+
}
109+
110+
private boolean isFromDifferentState(BundleCapability capability) {
111+
BundleRevision resource = capability.getResource();
112+
BundleDescription original = descriptionnMap.get(resource);
113+
if (original != null) {
114+
return original.getContainingState() != targetState;
115+
}
116+
return false;
117+
}
118+
119+
@Override
120+
public void end() {
121+
}
122+
};
123+
}
124+
});
125+
state.resolve(false);
126+
for (BundleDescription rootBundle : resolveRoots) {
127+
ResolverError[] errors = state.getResolverErrors(rootBundle);
128+
if (errors.length > 0) {
129+
throw new CoreException(Status.error(String.format("%s can not be resolved: %s", rootBundle, Arrays.toString(errors)))); //$NON-NLS-1$
130+
}
131+
}
132+
Collection<BundleDescription> closure = DependencyManager.findRequirementsClosure(resolveRoots);
133+
// map back to the originals!
134+
return closure.stream().map(bd -> descriptionnMap.get(bd)).filter(Objects::nonNull).toList();
135+
}
136+
51137
@SuppressWarnings("restriction")
52138
public static Collection<String> getRequiredJunitRuntimeEclipsePlugins(ILaunchConfiguration configuration) {
53139
org.eclipse.jdt.internal.junit.launcher.ITestKind testKind = org.eclipse.jdt.internal.junit.launcher.JUnitLaunchConfigurationConstants.getTestRunnerKind(configuration);
@@ -59,7 +145,7 @@ public static Collection<String> getRequiredJunitRuntimeEclipsePlugins(ILaunchCo
59145
return List.of(PDE_JUNIT_RUNTIME);
60146
} // Nothing to add for JUnit-3
61147
case org.eclipse.jdt.internal.junit.launcher.TestKindRegistry.JUNIT4_TEST_KIND_ID -> {
62-
return List.of(PDE_JUNIT_RUNTIME,JUNIT4_JDT_RUNTIME_PLUGIN);
148+
return List.of(PDE_JUNIT_RUNTIME, JUNIT4_JDT_RUNTIME_PLUGIN);
63149
}
64150
case org.eclipse.jdt.internal.junit.launcher.TestKindRegistry.JUNIT5_TEST_KIND_ID -> {
65151
return List.of(PDE_JUNIT_RUNTIME, JUNIT5_JDT_RUNTIME_PLUGIN);
@@ -68,21 +154,27 @@ public static Collection<String> getRequiredJunitRuntimeEclipsePlugins(ILaunchCo
68154
}
69155
}
70156

71-
private static Set<BundleDescription> addAbsentRequirements(Collection<String> requirements, Map<String, List<IPluginModelBase>> collectedModels, Map<IPluginModelBase, String> startLevelMap) throws CoreException {
72-
Set<BundleDescription> addedRequirements = new LinkedHashSet<>();
73-
for (String id : requirements) {
74-
List<IPluginModelBase> models = collectedModels.computeIfAbsent(id, k -> new ArrayList<>());
75-
if (models.stream().noneMatch(p -> p.getBundleDescription().isResolved())) {
76-
IPluginModelBase model = findRequiredPluginInTargetOrHost(PluginRegistry.findModel(id), plugins -> plugins.max(PDECore.VERSION), id);
77-
models.add(model);
78-
BundleLauncherHelper.addDefaultStartingBundle(startLevelMap, model);
79-
addedRequirements.add(model.getBundleDescription());
80-
}
157+
private static Collection<IPluginModelBase> getEclipseJunitRuntimePlugins(ILaunchConfiguration configuration, Map<String, List<IPluginModelBase>> collectedModels, Map<IPluginModelBase, String> startLevelMap) throws CoreException {
158+
Set<IPluginModelBase> descriptions = new LinkedHashSet<>();
159+
for (String id : getRequiredJunitRuntimeEclipsePlugins(configuration)) {
160+
addIfAbsent(id, collectedModels, startLevelMap).ifPresent(descriptions::add);
81161
}
82-
return addedRequirements;
162+
return descriptions;
163+
}
164+
165+
private static Optional<IPluginModelBase> addIfAbsent(String id, Map<String, List<IPluginModelBase>> collectedModels, Map<IPluginModelBase, String> startLevelMap) throws CoreException {
166+
List<IPluginModelBase> models = collectedModels.computeIfAbsent(id, k -> new ArrayList<>());
167+
if (models.stream().noneMatch(m -> m.getBundleDescription().isResolved())) {
168+
IPluginModelBase model = findRequiredPluginInTargetOrHost(PluginRegistry.findModel(id), plugins -> plugins.max(PDECore.VERSION), id);
169+
models.add(model);
170+
BundleLauncherHelper.addDefaultStartingBundle(startLevelMap, model);
171+
return Optional.of(model);
172+
}
173+
174+
return models.stream().filter(m -> m.getBundleDescription().isResolved()).findFirst();
83175
}
84176

85-
private static void addAbsentRequirements(Set<BundleDescription> requirements, Map<String, List<IPluginModelBase>> collectedModels, Map<IPluginModelBase, String> startLevelMap) throws CoreException {
177+
private static void addAbsentRequirements(Collection<BundleDescription> requirements, Map<String, List<IPluginModelBase>> collectedModels, Map<IPluginModelBase, String> startLevelMap) throws CoreException {
86178
for (BundleRevision bundle : requirements) {
87179
String id = bundle.getSymbolicName();
88180
List<IPluginModelBase> models = collectedModels.computeIfAbsent(id, k -> new ArrayList<>());

0 commit comments

Comments
 (0)