|
28 | 28 | import java.util.ArrayDeque; |
29 | 29 | import java.util.ArrayList; |
30 | 30 | import java.util.Arrays; |
| 31 | +import java.util.Collection; |
31 | 32 | import java.util.Collections; |
32 | 33 | import java.util.Comparator; |
| 34 | +import java.util.Dictionary; |
33 | 35 | import java.util.HashMap; |
34 | 36 | import java.util.HashSet; |
35 | 37 | import java.util.LinkedHashMap; |
|
51 | 53 | import org.eclipse.debug.core.ILaunchConfiguration; |
52 | 54 | import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; |
53 | 55 | import org.eclipse.osgi.service.resolver.BundleDescription; |
| 56 | +import org.eclipse.osgi.service.resolver.State; |
| 57 | +import org.eclipse.osgi.service.resolver.StateObjectFactory; |
54 | 58 | import org.eclipse.osgi.util.NLS; |
55 | 59 | import org.eclipse.pde.core.plugin.IMatchRules; |
56 | 60 | import org.eclipse.pde.core.plugin.IPluginBase; |
|
59 | 63 | import org.eclipse.pde.core.plugin.PluginRegistry; |
60 | 64 | import org.eclipse.pde.core.target.ITargetDefinition; |
61 | 65 | import org.eclipse.pde.core.target.ITargetPlatformService; |
| 66 | +import org.eclipse.pde.internal.build.BundleHelper; |
62 | 67 | import org.eclipse.pde.internal.build.IPDEBuildConstants; |
63 | 68 | import org.eclipse.pde.internal.core.DependencyManager; |
64 | 69 | import org.eclipse.pde.internal.core.FeatureModelManager; |
|
75 | 80 | import org.eclipse.pde.internal.launching.PDEMessages; |
76 | 81 | import org.eclipse.pde.launching.IPDELauncherConstants; |
77 | 82 | import org.osgi.framework.Version; |
78 | | -import org.osgi.resource.Resource; |
79 | 83 |
|
80 | 84 | public class BundleLauncherHelper { |
81 | 85 |
|
@@ -166,12 +170,7 @@ private static void addRequiredBundles(Map<IPluginModelBase, String> bundle2star |
166 | 170 | RequirementHelper.addApplicationLaunchRequirements(appRequirements, configuration, bundle2startLevel); |
167 | 171 |
|
168 | 172 | boolean includeOptional = configuration.getAttribute(IPDELauncherConstants.INCLUDE_OPTIONAL, true); |
169 | | - Set<BundleDescription> requiredDependencies = includeOptional // |
170 | | - ? DependencyManager.getDependencies(bundle2startLevel.keySet(), DependencyManager.Options.INCLUDE_OPTIONAL_DEPENDENCIES) |
171 | | - : DependencyManager.getDependencies(bundle2startLevel.keySet()); |
172 | | - |
173 | | - requiredDependencies.stream().map(Resource.class::cast) // |
174 | | - .map(PluginRegistry::findModel).filter(Objects::nonNull) // |
| 173 | + computeDependencyClosure0(bundle2startLevel.keySet(), includeOptional, IPDELauncherConstants.LOCATION_WORKSPACE) // |
175 | 174 | .forEach(p -> addDefaultStartingBundle(bundle2startLevel, p)); |
176 | 175 | } |
177 | 176 |
|
@@ -227,12 +226,8 @@ private static Map<IPluginModelBase, String> getMergedBundleMapFeatureBased(ILau |
227 | 226 | List<String> appRequirements = RequirementHelper.getApplicationLaunchRequirements(configuration); |
228 | 227 | RequirementHelper.addApplicationLaunchRequirements(appRequirements, configuration, launchPlugins, launchPlugins::add); |
229 | 228 |
|
230 | | - // Get all required plugins |
231 | | - Set<BundleDescription> additionalBundles = DependencyManager.getDependencies(launchPlugins); |
232 | | - for (BundleDescription bundle : additionalBundles) { |
233 | | - IPluginModelBase plugin = getRequiredPlugin(bundle.getSymbolicName(), bundle.getVersion().toString(), IMatchRules.PERFECT, defaultPluginResolution); |
234 | | - launchPlugins.add(Objects.requireNonNull(plugin));// should never be null |
235 | | - } |
| 229 | + computeDependencyClosure0(launchPlugins, false, defaultPluginResolution) // |
| 230 | + .map(Objects::requireNonNull).forEach(launchPlugins::add); |
236 | 231 | } |
237 | 232 |
|
238 | 233 | // Create the start levels for the selected plugins and add them to the map |
@@ -546,6 +541,83 @@ private static void addBundleToMap(Map<IPluginModelBase, String> map, IPluginMod |
546 | 541 | map.put(bundle, startData); |
547 | 542 | } |
548 | 543 |
|
| 544 | + // --- dependency resolution --- |
| 545 | + |
| 546 | + private static Stream<IPluginModelBase> computeDependencyClosure0(Set<IPluginModelBase> includedPlugins, boolean includeOptional, String defaultPluginResolution) { |
| 547 | + DependencyManager.Options[] options = includeOptional // |
| 548 | + ? new DependencyManager.Options[] {DependencyManager.Options.INCLUDE_OPTIONAL_DEPENDENCIES} |
| 549 | + : new DependencyManager.Options[] {}; |
| 550 | + if (includedPlugins.isEmpty()) { |
| 551 | + return Stream.empty(); |
| 552 | + } |
| 553 | + Set<BundleDescription> initialLaunchBundles = createNewState(includedPlugins, defaultPluginResolution).keySet(); |
| 554 | + State launchState = initialLaunchBundles.iterator().next().getContainingState(); |
| 555 | + Set<BundleDescription> bundles = new HashSet<>(initialLaunchBundles); |
| 556 | + DependencyManager.getImplicitDependencies().stream().map(descriptor -> { |
| 557 | + String versionStr = descriptor.getVersion(); |
| 558 | + Version version = versionStr != null ? Version.parseVersion(versionStr) : null; |
| 559 | + return launchState.getBundle(descriptor.getId(), version); |
| 560 | + }).forEach(bundles::add); |
| 561 | + |
| 562 | + Set<BundleDescription> closure = DependencyManager.findRequirementsClosure(bundles, options); |
| 563 | + return closure.stream() // |
| 564 | + .map(bundle -> { |
| 565 | + // Ensure that the preferred plugin-location is respected (therefore not just use PluginRegistry.findModel) |
| 566 | + //TODO: incooporate this when creating the new state?! |
| 567 | + return getRequiredPlugin(bundle.getSymbolicName(), bundle.getVersion().toString(), IMatchRules.PERFECT, defaultPluginResolution); |
| 568 | + }).map(Objects::requireNonNull) //TODO: check if this can ever be null?! |
| 569 | + .filter(p -> !includedPlugins.contains(p)); |
| 570 | + } |
| 571 | + |
| 572 | + private static Map<BundleDescription, IPluginModelBase> createNewState(Collection<IPluginModelBase> initialPlugins, String defaultPluginResolution) { |
| 573 | + StateObjectFactory factory = BundleHelper.getPlatformAdmin().getFactory(); |
| 574 | + IPluginModelBase any = initialPlugins.iterator().next(); |
| 575 | + // The state is the same as TargetPlatformHelper.getState() |
| 576 | + State tpState = any.getBundleDescription().getContainingState(); |
| 577 | + Set<BundleDescription> initialBundles = new HashSet<>(); |
| 578 | + State launchState = factory.createState(true); |
| 579 | + Map<BundleDescription, IPluginModelBase> launchBundle2plugin = new HashMap<>(); |
| 580 | + for (IPluginModelBase plugin : initialPlugins) { |
| 581 | + BundleDescription bundle = plugin.getBundleDescription(); |
| 582 | + if (bundle != null) { |
| 583 | + if (bundle.getContainingState() != tpState) { |
| 584 | + throw new IllegalStateException("Plugins have different TP state"); //$NON-NLS-1$ |
| 585 | + } |
| 586 | + initialBundles.add(bundle); |
| 587 | + BundleDescription launchBundle = factory.createBundleDescription(bundle); |
| 588 | + if (!launchState.addBundle(launchBundle)) { |
| 589 | + throw new IllegalStateException("Failed to add bundle to launch state: " + launchBundle); //$NON-NLS-1$ |
| 590 | + } |
| 591 | + if (launchBundle2plugin.put(launchBundle, plugin) != null) { |
| 592 | + throw new IllegalStateException("Duplicated launch bundle for plugin: " + plugin); //$NON-NLS-1$ |
| 593 | + } |
| 594 | + } |
| 595 | + } |
| 596 | + // Add all other bundles from tpState later to ensure that the initial plugins are preferd. |
| 597 | + //TODO: check how this is ensured?! Maybe resolve inbeteen, which is probably incomplete? |
| 598 | + BundleDescription[] bundles = tpState.getBundles(); |
| 599 | + //TODO: or use PluginRegistry.getAllModels(); and check compare against the initialPlugins. But this has different semantic |
| 600 | + for (BundleDescription bundle : bundles) { |
| 601 | + if (!initialBundles.contains(bundle)) { |
| 602 | + BundleDescription launchBundle = factory.createBundleDescription(bundle); |
| 603 | + if (!launchState.addBundle(launchBundle)) { |
| 604 | + throw new IllegalStateException("Failed to add bundle to launch state: " + launchBundle); //$NON-NLS-1$ |
| 605 | + } |
| 606 | +// IPluginModelBase plugin = getRequiredPlugin(bundle.getSymbolicName(), bundle.getVersion().toString(), IMatchRules.PERFECT, defaultPluginResolution); |
| 607 | +// if (launchBundle2plugin.put(launchBundle, plugin) != null) { |
| 608 | +// throw new IllegalStateException("Duplicated launch bundle for plugin: " + plugin); //$NON-NLS-1$ |
| 609 | +// } |
| 610 | + } |
| 611 | + } |
| 612 | + //TODO: ensure this is correct?! |
| 613 | + Dictionary<?, ?>[] platformProperties = tpState.getPlatformProperties(); |
| 614 | + launchState.setPlatformProperties(platformProperties); |
| 615 | + launchState.resolve(false); |
| 616 | + return launchBundle2plugin; |
| 617 | + } |
| 618 | + |
| 619 | + // -- start data --- |
| 620 | + |
549 | 621 | public static String getStartData(BundleDescription desc, String defaultStartData) { |
550 | 622 | String runLevel = resolveSystemRunLevelText(desc); |
551 | 623 | String auto = resolveSystemAutoText(desc); |
|
0 commit comments