Bug 544838 - Option to automatically include requirements at launch
Change-Id: I3bf1acec1fb96d5bf6c14f4609ca08ac00f9e28f
Signed-off-by: Hannes Wellmann <wellmann.hannes1@gmx.net>
Reviewed-on: https://git.eclipse.org/r/c/pde/eclipse.pde.ui/+/186833
Reviewed-by: Julian Honnen <julian.honnen@vector.com>
Tested-by: PDE Bot <pde-bot@eclipse.org>
diff --git a/ui/org.eclipse.pde.launching/META-INF/MANIFEST.MF b/ui/org.eclipse.pde.launching/META-INF/MANIFEST.MF
index 76ae491..6b18bb1 100644
--- a/ui/org.eclipse.pde.launching/META-INF/MANIFEST.MF
+++ b/ui/org.eclipse.pde.launching/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@
Bundle-ManifestVersion: 2
Bundle-Name: %name
Bundle-SymbolicName: org.eclipse.pde.launching;singleton:=true
-Bundle-Version: 3.9.700.qualifier
+Bundle-Version: 3.10.0.qualifier
Bundle-RequiredExecutionEnvironment: JavaSE-11
Bundle-Vendor: %provider-name
Require-Bundle: org.eclipse.jdt.junit.core;bundle-version="[3.6.0,4.0.0)",
diff --git a/ui/org.eclipse.pde.launching/src/org/eclipse/pde/internal/launching/launcher/BundleLauncherHelper.java b/ui/org.eclipse.pde.launching/src/org/eclipse/pde/internal/launching/launcher/BundleLauncherHelper.java
index 35b302b..8af476d 100644
--- a/ui/org.eclipse.pde.launching/src/org/eclipse/pde/internal/launching/launcher/BundleLauncherHelper.java
+++ b/ui/org.eclipse.pde.launching/src/org/eclipse/pde/internal/launching/launcher/BundleLauncherHelper.java
@@ -17,6 +17,7 @@
* Hannes Wellmann - Bug 576887 - Handle multiple versions of features and plug-ins for feature-launches
* Hannes Wellmann - Bug 576888, Bug 576889 - Consider included child-features and required dependency-features for feature-launches
* Hannes Wellmann - Bug 576890 - Ignore included features/plug-ins not matching target-environment
+ * Hannes Wellmann - Bug 544838 - Option to automatically add requirements at launch
*******************************************************************************/
package org.eclipse.pde.internal.launching.launcher;
@@ -93,7 +94,12 @@
return getMergedBundleMapFeatureBased(wc);
}
- return getAllSelectedPluginBundles(wc);
+ Map<IPluginModelBase, String> selectedBundles = getAllSelectedPluginBundles(wc);
+ boolean autoAddRequirements = configuration.getAttribute(IPDELauncherConstants.AUTOMATIC_INCLUDE_REQUIREMENTS, false);
+ if (autoAddRequirements) {
+ addRequiredBundles(selectedBundles, configuration);
+ }
+ return selectedBundles;
}
public static Map<IPluginModelBase, String> getAllSelectedPluginBundles(ILaunchConfiguration config) throws CoreException {
@@ -103,14 +109,29 @@
return map;
}
+ private static void addRequiredBundles(Map<IPluginModelBase, String> bundle2startLevel, ILaunchConfiguration configuration) throws CoreException {
+
+ RequirementHelper.addApplicationLaunchRequirements(bundle2startLevel, configuration);
+
+ boolean includeOptional = configuration.getAttribute(IPDELauncherConstants.INCLUDE_OPTIONAL, true);
+ Set<BundleDescription> requiredDependencies = includeOptional //
+ ? DependencyManager.getDependencies(bundle2startLevel.keySet(), DependencyManager.Options.INCLUDE_OPTIONAL_DEPENDENCIES)
+ : DependencyManager.getDependencies(bundle2startLevel.keySet());
+
+ requiredDependencies.stream() //
+ .map(PluginRegistry::findModel).filter(Objects::nonNull) //
+ .forEach(p -> addDefaultStartingBundle(bundle2startLevel, p));
+ }
+
// --- feature based launches ---
private static Map<IPluginModelBase, String> getMergedBundleMapFeatureBased(ILaunchConfiguration configuration) throws CoreException {
String defaultPluginResolution = configuration.getAttribute(IPDELauncherConstants.FEATURE_PLUGIN_RESOLUTION, IPDELauncherConstants.LOCATION_WORKSPACE);
ITargetDefinition target = PDECore.getDefault().acquireService(ITargetPlatformService.class).getWorkspaceTargetDefinition();
+ boolean addRequirements = configuration.getAttribute(IPDELauncherConstants.AUTOMATIC_INCLUDE_REQUIREMENTS, true);
- Map<IFeature, String> feature2resolution = getSelectedFeatures(configuration, target);
+ Map<IFeature, String> feature2resolution = getSelectedFeatures(configuration, target, addRequirements);
// Get the feature model for each selected feature id and resolve its plugins
Set<IPluginModelBase> launchPlugins = new HashSet<>();
@@ -128,12 +149,14 @@
}
}
}
- IFeatureImport[] featureImports = feature.getImports();
- for (IFeatureImport featureImport : featureImports) {
- if (featureImport.getType() == IFeatureImport.PLUGIN) {
- IPluginModelBase plugin = getRequiredPlugin(featureImport.getId(), featureImport.getVersion(), featureImport.getMatch(), pluginResolution);
- if (plugin != null) {
- launchPlugins.add(plugin);
+ if (addRequirements) {
+ IFeatureImport[] featureImports = feature.getImports();
+ for (IFeatureImport featureImport : featureImports) {
+ if (featureImport.getType() == IFeatureImport.PLUGIN) {
+ IPluginModelBase plugin = getRequiredPlugin(featureImport.getId(), featureImport.getVersion(), featureImport.getMatch(), pluginResolution);
+ if (plugin != null) {
+ launchPlugins.add(plugin);
+ }
}
}
}
@@ -142,20 +165,17 @@
Map<IPluginModelBase, AdditionalPluginData> additionalPlugins = getAdditionalPlugins(configuration, true);
launchPlugins.addAll(additionalPlugins.keySet());
- // Get any plug-ins required by the application/product set on the config
- List<String> applicationIds = RequirementHelper.getApplicationLaunchRequirements(configuration);
- for (String applicationId : applicationIds) {
- IPluginModelBase plugin = getLatestPlugin(applicationId, defaultPluginResolution);
- if (plugin != null) {
- launchPlugins.add(plugin);
+ if (addRequirements) {
+ // Add all missing plug-ins required by the application/product set in the config
+ RequirementHelper.addApplicationLaunchRequirements(configuration, launchPlugins, launchPlugins::add);
+
+ // Get all required plugins
+ Set<BundleDescription> additionalBundles = DependencyManager.getDependencies(launchPlugins);
+ for (BundleDescription bundle : additionalBundles) {
+ IPluginModelBase plugin = getRequiredPlugin(bundle.getSymbolicName(), bundle.getVersion().toString(), IMatchRules.PERFECT, defaultPluginResolution);
+ launchPlugins.add(Objects.requireNonNull(plugin));// should never be null
}
}
- // Get all required plugins
- Set<BundleDescription> additionalBundles = DependencyManager.getDependencies(launchPlugins);
- for (BundleDescription bundle : additionalBundles) {
- IPluginModelBase plugin = getRequiredPlugin(bundle.getSymbolicName(), bundle.getVersion().toString(), IMatchRules.PERFECT, defaultPluginResolution);
- launchPlugins.add(Objects.requireNonNull(plugin));// should never be null
- }
// Create the start levels for the selected plugins and add them to the map
Map<IPluginModelBase, String> map = new LinkedHashMap<>();
@@ -167,7 +187,7 @@
return map;
}
- private static Map<IFeature, String> getSelectedFeatures(ILaunchConfiguration configuration, ITargetDefinition target) throws CoreException {
+ private static Map<IFeature, String> getSelectedFeatures(ILaunchConfiguration configuration, ITargetDefinition target, boolean addRequirements) throws CoreException {
String featureLocation = configuration.getAttribute(IPDELauncherConstants.FEATURE_DEFAULT_LOCATION, IPDELauncherConstants.LOCATION_WORKSPACE);
Predicate<IFeature> targetEnvironmentFilter = f -> f.matchesEnvironment(target);
@@ -201,11 +221,13 @@
}
}
- IFeatureImport[] featureImports = feature.getImports();
- for (IFeatureImport featureImport : featureImports) {
- if (featureImport.getType() == IFeatureImport.FEATURE) {
- IFeature dependency = getRequiredFeature(featureImport.getId(), featureImport.getVersion(), featureImport.getMatch(), targetEnvironmentFilter, featureMaps);
- addFeatureIfAbsent(dependency, pluginResolution, feature2pluginResolution, pendingFeatures);
+ if (addRequirements) {
+ IFeatureImport[] featureImports = feature.getImports();
+ for (IFeatureImport featureImport : featureImports) {
+ if (featureImport.getType() == IFeatureImport.FEATURE) {
+ IFeature dependency = getRequiredFeature(featureImport.getId(), featureImport.getVersion(), featureImport.getMatch(), targetEnvironmentFilter, featureMaps);
+ addFeatureIfAbsent(dependency, pluginResolution, feature2pluginResolution, pendingFeatures);
+ }
}
}
}
@@ -453,15 +475,17 @@
BundleDescription desc = bundle.getBundleDescription();
boolean defaultsl = startData == null || startData.equals(DEFAULT_START_LEVELS);
if (desc != null && defaultsl) {
- String runLevelText = resolveSystemRunLevelText(bundle);
- String autoText = resolveSystemAutoText(bundle);
- if (runLevelText != null && autoText != null) {
- startData = runLevelText + AUTO_START_SEPARATOR + autoText;
- }
+ startData = getStartData(desc, startData);
}
map.put(bundle, startData);
}
+ public static String getStartData(BundleDescription desc, String defaultStartData) {
+ String runLevel = resolveSystemRunLevelText(desc);
+ String auto = resolveSystemAutoText(desc);
+ return runLevel != null && auto != null ? (runLevel + AUTO_START_SEPARATOR + auto) : defaultStartData;
+ }
+
public static void addDefaultStartingBundle(Map<IPluginModelBase, String> map, IPluginModelBase bundle) {
addBundleToMap(map, bundle, DEFAULT_START_LEVELS);
}
@@ -474,13 +498,11 @@
Map.entry(IPDEBuildConstants.BUNDLE_CORE_RUNTIME, DEFAULT), //
Map.entry(IPDEBuildConstants.BUNDLE_FELIX_SCR, "1")); //$NON-NLS-1$
- public static String resolveSystemRunLevelText(IPluginModelBase model) {
- BundleDescription description = model.getBundleDescription();
+ public static String resolveSystemRunLevelText(BundleDescription description) {
return AUTO_STARTED_BUNDLE_LEVELS.get(description.getSymbolicName());
}
- public static String resolveSystemAutoText(IPluginModelBase model) {
- BundleDescription description = model.getBundleDescription();
+ public static String resolveSystemAutoText(BundleDescription description) {
return AUTO_STARTED_BUNDLE_LEVELS.containsKey(description.getSymbolicName()) ? "true" : null; //$NON-NLS-1$
}
diff --git a/ui/org.eclipse.pde.launching/src/org/eclipse/pde/internal/launching/launcher/RequirementHelper.java b/ui/org.eclipse.pde.launching/src/org/eclipse/pde/internal/launching/launcher/RequirementHelper.java
index 26d9ad7..b4050e2 100644
--- a/ui/org.eclipse.pde.launching/src/org/eclipse/pde/internal/launching/launcher/RequirementHelper.java
+++ b/ui/org.eclipse.pde.launching/src/org/eclipse/pde/internal/launching/launcher/RequirementHelper.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2010, 2018 IBM Corporation and others.
+ * Copyright (c) 2010, 2022 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
@@ -11,12 +11,14 @@
* Contributors:
* IBM Corporation - initial API and implementation
* Karsten Thoms (itemis) - Bug 530406
+ * Hannes Wellmann - Bug 576860 - Specify all launch-type requirements in RequirementHelper
*******************************************************************************/
package org.eclipse.pde.internal.launching.launcher;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
+import java.util.function.Consumer;
import java.util.stream.Stream;
import org.eclipse.core.runtime.*;
import org.eclipse.debug.core.*;
@@ -77,6 +79,11 @@
}
public static boolean addApplicationLaunchRequirements(Map<IPluginModelBase, String> bundle2startLevel, ILaunchConfiguration configuration) throws CoreException {
+ Consumer<IPluginModelBase> addPlugin = b -> BundleLauncherHelper.addDefaultStartingBundle(bundle2startLevel, b);
+ return addApplicationLaunchRequirements(configuration, bundle2startLevel.keySet(), addPlugin);
+ }
+
+ public static boolean addApplicationLaunchRequirements(ILaunchConfiguration configuration, Set<IPluginModelBase> containedPlugins, Consumer<IPluginModelBase> addPlugin) throws CoreException {
boolean isFeatureBasedLaunch = configuration.getAttribute(IPDELauncherConstants.USE_CUSTOM_FEATURES, false);
String pluginResolution = isFeatureBasedLaunch ? configuration.getAttribute(IPDELauncherConstants.FEATURE_PLUGIN_RESOLUTION, IPDELauncherConstants.LOCATION_WORKSPACE) : IPDELauncherConstants.LOCATION_WORKSPACE;
@@ -87,9 +94,9 @@
if (entry != null) {
// add required plug-in if not yet already included
var allPluginsWithId = Stream.of(entry.getWorkspaceModels(), entry.getExternalModels()).flatMap(Arrays::stream);
- if (allPluginsWithId.noneMatch(bundle2startLevel::containsKey)) {
+ if (allPluginsWithId.noneMatch(containedPlugins::contains)) {
IPluginModelBase plugin = BundleLauncherHelper.getLatestPlugin(requiredBundleId, pluginResolution);
- BundleLauncherHelper.addDefaultStartingBundle(bundle2startLevel, plugin);
+ addPlugin.accept(plugin);
}
} else {
missingRequirements = true;
diff --git a/ui/org.eclipse.pde.launching/src/org/eclipse/pde/launching/IPDELauncherConstants.java b/ui/org.eclipse.pde.launching/src/org/eclipse/pde/launching/IPDELauncherConstants.java
index 0ff5b1d..b9ae5c2 100644
--- a/ui/org.eclipse.pde.launching/src/org/eclipse/pde/launching/IPDELauncherConstants.java
+++ b/ui/org.eclipse.pde.launching/src/org/eclipse/pde/launching/IPDELauncherConstants.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2005, 2019 IBM Corporation and others.
+ * Copyright (c) 2005, 2022 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
@@ -219,6 +219,15 @@
String INCLUDE_OPTIONAL = "includeOptional"; //$NON-NLS-1$
/**
+ * Launch configuration attribute key. The value is a boolean specifying
+ * whether required plug-ins and/or features should be added automatically
+ * to the list of plug-ins to launch with.
+ *
+ * @since 3.10
+ */
+ String AUTOMATIC_INCLUDE_REQUIREMENTS = "automaticIncludeRequirements"; //$NON-NLS-1$
+
+ /**
* Launch configuration attribute key. The value is a boolean indicating
* whether tracing is enabled or disabled.
*/
diff --git a/ui/org.eclipse.pde.ui.tests/META-INF/MANIFEST.MF b/ui/org.eclipse.pde.ui.tests/META-INF/MANIFEST.MF
index fdcb898..ac06478 100644
--- a/ui/org.eclipse.pde.ui.tests/META-INF/MANIFEST.MF
+++ b/ui/org.eclipse.pde.ui.tests/META-INF/MANIFEST.MF
@@ -40,7 +40,9 @@
org.eclipse.ui.views.log,
org.eclipse.debug.core,
org.eclipse.pde.genericeditor.extension,
- org.eclipse.equinox.simpleconfigurator.manipulator;bundle-version="2.1.300"
+ org.eclipse.equinox.simpleconfigurator.manipulator;bundle-version="2.1.300",
+ org.eclipse.platform,
+ org.eclipse.ui.ide.application
Import-Package: org.assertj.core.api;version="3.14.0",
org.assertj.core.presentation;version="3.21.0",
org.junit.jupiter.api.function;version="5.8.1"
diff --git a/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/launcher/FeatureBasedLaunchTest.java b/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/launcher/FeatureBasedLaunchTest.java
index f16235f..da78771 100644
--- a/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/launcher/FeatureBasedLaunchTest.java
+++ b/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/launcher/FeatureBasedLaunchTest.java
@@ -17,11 +17,15 @@
package org.eclipse.pde.ui.tests.launcher;
import static java.util.Collections.emptySet;
+import static java.util.Map.entry;
import static java.util.Map.ofEntries;
import static org.assertj.core.api.Assertions.assertThat;
import static org.eclipse.pde.internal.core.ICoreConstants.DEFAULT_VERSION;
import static org.eclipse.pde.ui.tests.util.ProjectUtils.createPluginProject;
import static org.eclipse.pde.ui.tests.util.TargetPlatformUtil.bundle;
+import static org.eclipse.pde.ui.tests.util.TargetPlatformUtil.resolution;
+import static org.osgi.framework.Constants.REQUIRE_BUNDLE;
+import static org.osgi.framework.Constants.RESOLUTION_OPTIONAL;
import java.io.PrintWriter;
import java.nio.file.Files;
@@ -33,17 +37,17 @@
import org.eclipse.core.runtime.*;
import org.eclipse.debug.core.*;
import org.eclipse.jface.operation.IRunnableWithProgress;
-import org.eclipse.pde.core.plugin.IMatchRules;
-import org.eclipse.pde.core.plugin.IPluginModelBase;
+import org.eclipse.osgi.service.resolver.BundleDescription;
+import org.eclipse.pde.core.plugin.*;
import org.eclipse.pde.core.target.NameVersionDescriptor;
-import org.eclipse.pde.internal.core.FeatureModelManager;
-import org.eclipse.pde.internal.core.PDECore;
+import org.eclipse.pde.internal.core.*;
import org.eclipse.pde.internal.core.feature.FeatureChild;
import org.eclipse.pde.internal.core.feature.WorkspaceFeatureModel;
import org.eclipse.pde.internal.core.ifeature.*;
import org.eclipse.pde.internal.launching.launcher.BundleLauncherHelper;
import org.eclipse.pde.internal.ui.wizards.feature.AbstractCreateFeatureOperation;
import org.eclipse.pde.internal.ui.wizards.feature.FeatureData;
+import org.eclipse.pde.launching.EclipseApplicationLaunchConfiguration;
import org.eclipse.pde.launching.IPDELauncherConstants;
import org.eclipse.pde.ui.tests.util.TargetPlatformUtil;
import org.junit.*;
@@ -1302,6 +1306,84 @@
workspaceBundle("plugin.d", "1.0.0")));
}
+ @Test
+ public void testGetMergedBundleMap_automaticallyAddRequirements() throws Throwable {
+
+ var targetBundles = Map.ofEntries( //
+ bundle("plugin.b", "1.0.0"), //
+ bundle("plugin.c", "1.0.0"), //
+
+ bundle("plugin.z", "1.0.0", //
+ entry(REQUIRE_BUNDLE, "plugin.x,plugin.w" + resolution(RESOLUTION_OPTIONAL))),
+ bundle("plugin.y", "1.0.0"), //
+ bundle("plugin.x", "1.0.0"), //
+ bundle("plugin.w", "1.0.0"));
+
+ List<NameVersionDescriptor> targetFeatures = List.of( //
+ targetFeature("feature.a", "1.0.0", f -> {
+ addIncludedFeature(f, "feature.b", "1.0.0");
+ addRequiredFeature(f, "feature.c", "", IMatchRules.COMPATIBLE);
+ addIncludedPlugin(f, "plugin.z", "1.0.0");
+ addRequiredPlugin(f, "plugin.y", "", IMatchRules.COMPATIBLE);
+ }), //
+ targetFeature("feature.b", "1.0.0", f -> {
+ addIncludedPlugin(f, "plugin.b", "1.0.0");
+ }), //
+ targetFeature("feature.c", "1.0.0", f -> {
+ addIncludedPlugin(f, "plugin.c", "1.0.0");
+ }));
+
+ // Gather requirements of the product used below
+ Map<BundleLocationDescriptor, String> requiredRPBundles = getEclipseAppRequirementClosureForRunningPlatform();
+
+ TargetPlatformUtil.setRunningPlatformWithDummyBundlesAsTarget(null, targetBundles, targetFeatures,
+ tpJarDirectory);
+
+ ILaunchConfigurationWorkingCopy wc = createFeatureLaunchConfig();
+ wc.setAttribute(IPDELauncherConstants.SELECTED_FEATURES, Set.of("feature.a:external"));
+ wc.setAttribute(IPDELauncherConstants.USE_PRODUCT, true);
+ wc.setAttribute(IPDELauncherConstants.PRODUCT, "org.eclipse.platform.ide");
+
+ // test AUTOMATIC_ADD_REQUIREMENTS=true and its default (true)
+ for (Boolean autoAddRequirements : Arrays.asList(true, null)) {
+ wc.setAttribute(IPDELauncherConstants.AUTOMATIC_INCLUDE_REQUIREMENTS, autoAddRequirements);
+ assertGetMergedBundleMap(wc, concat(requiredRPBundles, toDefaultStartData(Set.of(//
+ targetBundle("plugin.b", "1.0.0"), //
+ targetBundle("plugin.c", "1.0.0"), //
+ targetBundle("plugin.z", "1.0.0"), //
+ targetBundle("plugin.y", "1.0.0"), //
+ targetBundle("plugin.x", "1.0.0")))));
+ }
+
+ // test AUTOMATIC_ADD_REQUIREMENTS=false
+ wc.setAttribute(IPDELauncherConstants.AUTOMATIC_INCLUDE_REQUIREMENTS, false);
+ assertGetMergedBundleMap(wc, Set.of( //
+ targetBundle("plugin.b", "1.0.0"), //
+ targetBundle("plugin.z", "1.0.0")));
+ }
+
+ static Map<BundleLocationDescriptor, String> getEclipseAppRequirementClosureForRunningPlatform(
+ DependencyManager.Options... closureOptions) throws Exception {
+ // ensure app requirements are registered (done at class initialization)
+ new EclipseApplicationLaunchConfiguration();
+ @SuppressWarnings("unused") // prevent bundle removal
+ org.eclipse.platform.internal.LaunchUpdateIntroAction a;
+ @SuppressWarnings("unused") // prevent bundle removal
+ org.eclipse.ui.internal.ide.application.IDEApplication app;
+
+ TargetPlatformUtil.setRunningPlatformAsTarget();
+
+ List<String> productPlugins = List.of("org.eclipse.platform", "org.eclipse.ui.ide.application");
+ Set<BundleDescription> appBundles = productPlugins.stream().map(PluginRegistry::findModel)
+ .map(IPluginModelBase::getBundleDescription).collect(Collectors.toSet());
+
+ Set<BundleDescription> appBundleClosure = DependencyManager.findRequirementsClosure(appBundles, closureOptions);
+ assertThat(appBundleClosure).hasSizeGreaterThanOrEqualTo(productPlugins.size());
+ return DependencyManager.findRequirementsClosure(appBundles, closureOptions).stream().collect(Collectors.toMap( //
+ d -> targetBundle(d.getSymbolicName(), d.getVersion().toString()),
+ d -> BundleLauncherHelper.getStartData(d, "default:default")));
+ }
+
// --- utility methods ---
private static interface CoreConsumer<E> {
@@ -1444,10 +1526,11 @@
private static void assertGetMergedBundleMap(String message, ILaunchConfiguration launchConfig,
Set<BundleLocationDescriptor> expectedBundles) throws Exception {
+ assertGetMergedBundleMap(message, launchConfig, toDefaultStartData(expectedBundles));
+ }
- Map<BundleLocationDescriptor, String> expectedBundleMap = expectedBundles.stream()
- .collect(Collectors.toMap(b -> b, b -> "default:default"));
- assertGetMergedBundleMap(message, launchConfig, expectedBundleMap);
+ static Map<BundleLocationDescriptor, String> toDefaultStartData(Collection<BundleLocationDescriptor> bundles) {
+ return bundles.stream().collect(Collectors.toMap(b -> b, b -> "default:default"));
}
private static void assertGetMergedBundleMap(ILaunchConfiguration launchConfig,
@@ -1467,4 +1550,11 @@
assertPluginMapsEquals(message, expectedPluginMap, bundleMap);
}
+
+ @SafeVarargs
+ static <K, V> Map<K, V> concat(Map<K, V>... maps) {
+ Map<K, V> map = new HashMap<>();
+ Arrays.stream(maps).forEach(map::putAll);
+ return map;
+ }
}
diff --git a/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/launcher/PluginBasedLaunchTest.java b/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/launcher/PluginBasedLaunchTest.java
index 8cc1837..dbf8237 100644
--- a/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/launcher/PluginBasedLaunchTest.java
+++ b/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/launcher/PluginBasedLaunchTest.java
@@ -13,9 +13,15 @@
*******************************************************************************/
package org.eclipse.pde.ui.tests.launcher;
+import static java.util.Map.entry;
import static java.util.Map.ofEntries;
+import static org.eclipse.pde.ui.tests.launcher.FeatureBasedLaunchTest.concat;
+import static org.eclipse.pde.ui.tests.launcher.FeatureBasedLaunchTest.toDefaultStartData;
import static org.eclipse.pde.ui.tests.util.TargetPlatformUtil.bundle;
+import static org.eclipse.pde.ui.tests.util.TargetPlatformUtil.resolution;
import static org.junit.Assert.assertEquals;
+import static org.osgi.framework.Constants.REQUIRE_BUNDLE;
+import static org.osgi.framework.Constants.RESOLUTION_OPTIONAL;
import java.nio.file.Path;
import java.util.*;
@@ -25,6 +31,8 @@
import org.eclipse.debug.core.*;
import org.eclipse.pde.core.plugin.IPluginModelBase;
import org.eclipse.pde.core.target.NameVersionDescriptor;
+import org.eclipse.pde.internal.core.DependencyManager;
+import org.eclipse.pde.internal.launching.IPDEConstants;
import org.eclipse.pde.internal.launching.launcher.BundleLauncherHelper;
import org.eclipse.pde.launching.IPDELauncherConstants;
import org.eclipse.pde.ui.tests.util.ProjectUtils;
@@ -731,6 +739,68 @@
assertGetMergedBundleMap(workspacePlugins, targetPlatformBundles, launchConfigSetup, expectedBundles);
}
+ // --- miscellaneous cases ---
+
+ @Test
+ public void testGetMergedBundleMap_automaticallyAddRequirements() throws Exception {
+
+ var targetPlatformBundles = Map.ofEntries( //
+ bundle("plugin.a", "1.0.0", //
+ entry(REQUIRE_BUNDLE, "plugin.b,plugin.c" + resolution(RESOLUTION_OPTIONAL))),
+ bundle("plugin.b", "1.0.0"), //
+ bundle("plugin.c", "1.0.0"));
+
+ Map<BundleLocationDescriptor, String> requiredRPBundlesWithoutOptional = FeatureBasedLaunchTest
+ .getEclipseAppRequirementClosureForRunningPlatform();
+
+ Map<BundleLocationDescriptor, String> requiredRPBundlesWithOptional = FeatureBasedLaunchTest
+ .getEclipseAppRequirementClosureForRunningPlatform(
+ DependencyManager.Options.INCLUDE_OPTIONAL_DEPENDENCIES);
+
+ TargetPlatformUtil.setRunningPlatformWithDummyBundlesAsTarget(null, targetPlatformBundles, List.of(),
+ tpJarDirectory);
+
+ Consumer<ILaunchConfigurationWorkingCopy> basicSetup = wc -> {
+ wc.setAttribute(IPDELauncherConstants.SELECTED_TARGET_BUNDLES, Set.of("plugin.a*1.0.0"));
+ wc.setAttribute(IPDELauncherConstants.USE_PRODUCT, true);
+ wc.setAttribute(IPDELauncherConstants.PRODUCT, "org.eclipse.platform.ide");
+ // prevent BundleLaunchHelper.migrateLaunchConfiguration() from
+ // adding more target plug-ins:
+ wc.setAttribute(IPDEConstants.LAUNCHER_PDE_VERSION, "3.3");
+ };
+
+ // test automatic-add-requirements disabled (which is the default)
+ for (Boolean autoAddRequirements : Arrays.asList(false, null)) {
+ assertGetMergedBundleMap(wc -> {
+ basicSetup.accept(wc);
+ wc.setAttribute(IPDELauncherConstants.AUTOMATIC_INCLUDE_REQUIREMENTS, autoAddRequirements);
+ }, toDefaultStartData(Set.of( //
+ targetBundle("plugin.a", "1.0.0"))));
+ }
+
+ // test enabled automatic-add-requirements
+ // with optional requirements enabled (which is the default)
+ for (Boolean includeOptional : Arrays.asList(true, null)) {
+ assertGetMergedBundleMap(wc -> {
+ basicSetup.accept(wc);
+ wc.setAttribute(IPDELauncherConstants.AUTOMATIC_INCLUDE_REQUIREMENTS, true);
+ wc.setAttribute(IPDELauncherConstants.INCLUDE_OPTIONAL, includeOptional);
+ }, concat(requiredRPBundlesWithOptional, toDefaultStartData(Set.of( //
+ targetBundle("plugin.a", "1.0.0"), //
+ targetBundle("plugin.b", "1.0.0"), //
+ targetBundle("plugin.c", "1.0.0")))));
+ }
+
+ // test automatic-add-requirements enabled without optional requirements
+ assertGetMergedBundleMap(wc -> {
+ basicSetup.accept(wc);
+ wc.setAttribute(IPDELauncherConstants.AUTOMATIC_INCLUDE_REQUIREMENTS, true);
+ wc.setAttribute(IPDELauncherConstants.INCLUDE_OPTIONAL, false);
+ }, concat(requiredRPBundlesWithoutOptional, toDefaultStartData(Set.of( //
+ targetBundle("plugin.a", "1.0.0"), //
+ targetBundle("plugin.b", "1.0.0")))));
+ }
+
// --- test cases for writeBundleEntry() ----
@Test
@@ -828,6 +898,11 @@
setUpWorkspace(workspacePlugins, targetPlugins);
+ assertGetMergedBundleMap(launchConfigPreparer, expectedBundleMap);
+ }
+
+ private static void assertGetMergedBundleMap(Consumer<ILaunchConfigurationWorkingCopy> launchConfigPreparer,
+ Map<BundleLocationDescriptor, String> expectedBundleMap) throws CoreException {
ILaunchConfigurationWorkingCopy wc = createPluginLaunchConfig("plugin-based-Eclipse-app");
launchConfigPreparer.accept(wc);
diff --git a/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/PDEUIMessages.java b/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/PDEUIMessages.java
index a34dce8..25516c7 100644
--- a/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/PDEUIMessages.java
+++ b/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/PDEUIMessages.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2014, 2021 IBM Corporation and others.
+ * Copyright (c) 2014, 2022 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
@@ -1055,6 +1055,10 @@
public static String AdvancedLauncherTab_subset;
public static String AdvancedLauncherTab_subset_plugins;
public static String AdvancedLauncherTab_subset_bundles;
+ public static String AdvancedLauncherTab_autoIncludeRequirements_bundles;
+ public static String AdvancedLauncherTab_autoIncludeRequirements_plugins;
+ public static String AdvancedLauncherTab_autoIncludeRequirements_features_withBundles;
+ public static String AdvancedLauncherTab_autoIncludeRequirements_features_withPlugins;
public static String AdvancedLauncherTab_addNew;
public static String AdvancedLauncherTab_addNew_plugins;
public static String AdvancedLauncherTab_addNew_bundles;
diff --git a/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/launcher/AbstractPluginBlock.java b/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/launcher/AbstractPluginBlock.java
index e79d6cf..9873f9e 100644
--- a/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/launcher/AbstractPluginBlock.java
+++ b/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/launcher/AbstractPluginBlock.java
@@ -54,8 +54,7 @@
import org.eclipse.swt.SWTException;
import org.eclipse.swt.custom.CCombo;
import org.eclipse.swt.custom.TreeEditor;
-import org.eclipse.swt.events.SelectionAdapter;
-import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.*;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.GridData;
@@ -78,6 +77,8 @@
protected int fNumExternalChecked;
protected int fNumWorkspaceChecked;
+ private Button fAutoIncludeRequirementsButton;
+ private boolean fAutoIncludeRequirementsButtonChanged;
private Button fIncludeOptionalButton;
protected Button fAddWorkspaceButton;
private Button fAutoValidate;
@@ -312,6 +313,15 @@
public void createControl(Composite parent, int span, int indent) {
createPluginViewer(parent, span - 1, indent);
createButtonContainer(parent);
+
+ if (fTab instanceof PluginsTab) {
+ fAutoIncludeRequirementsButton = createButton(parent, span, indent, PDEUIMessages.AdvancedLauncherTab_autoIncludeRequirements_plugins );
+ } else if (fTab instanceof BundlesTab) {
+ fAutoIncludeRequirementsButton = createButton(parent, span, indent, PDEUIMessages.AdvancedLauncherTab_autoIncludeRequirements_bundles);
+ }
+ fAutoIncludeRequirementsButton.addSelectionListener(
+ SelectionListener.widgetSelectedAdapter(e -> this.fAutoIncludeRequirementsButtonChanged = true));
+
if (fTab instanceof PluginsTab) {
fIncludeOptionalButton = createButton(parent, span, indent,PDEUIMessages.AdvancedLauncherTab_includeOptional_plugins);
}else if (fTab instanceof BundlesTab) {
@@ -652,10 +662,10 @@
autoText = autoText == null || autoText.length() == 0 ? "default" : autoText; //$NON-NLS-1$
// Replace run levels and auto start values for certain important system bundles
- String systemValue = BundleLauncherHelper.resolveSystemRunLevelText(model);
+ String systemValue = BundleLauncherHelper.resolveSystemRunLevelText(model.getBundleDescription());
levelText = systemValue != null ? systemValue : levelText;
- systemValue = BundleLauncherHelper.resolveSystemAutoText(model);
+ systemValue = BundleLauncherHelper.resolveSystemAutoText(model.getBundleDescription());
autoText = systemValue != null ? systemValue : autoText;
// Recache the values in case they changed. I believe the code to only recache
@@ -791,6 +801,8 @@
}
protected void initializeButtonsFrom(ILaunchConfiguration config) throws CoreException {
+ boolean autoIncludeRequired = config.getAttribute(IPDELauncherConstants.AUTOMATIC_INCLUDE_REQUIREMENTS, false);
+ fAutoIncludeRequirementsButton.setSelection(autoIncludeRequired);
fIncludeOptionalButton.setSelection(config.getAttribute(IPDELauncherConstants.INCLUDE_OPTIONAL, true));
fAddWorkspaceButton.setSelection(config.getAttribute(IPDELauncherConstants.AUTOMATIC_ADD, true));
fAutoValidate.setSelection(config.getAttribute(IPDELauncherConstants.AUTOMATIC_VALIDATE, true));
@@ -876,6 +888,11 @@
}
public void performApply(ILaunchConfigurationWorkingCopy config) {
+ if (fAutoIncludeRequirementsButtonChanged) {
+ boolean includeRequirements = fAutoIncludeRequirementsButton.getSelection();
+ config.setAttribute(IPDELauncherConstants.AUTOMATIC_INCLUDE_REQUIREMENTS, includeRequirements);
+ fAutoIncludeRequirementsButtonChanged = false;
+ }
config.setAttribute(IPDELauncherConstants.INCLUDE_OPTIONAL, fIncludeOptionalButton.getSelection());
config.setAttribute(IPDELauncherConstants.AUTOMATIC_ADD, fAddWorkspaceButton.getSelection());
config.setAttribute(IPDELauncherConstants.AUTOMATIC_VALIDATE, fAutoValidate.getSelection());
@@ -900,6 +917,7 @@
fWorkingSetButton.setEnabled(enable);
fSelectAllButton.setEnabled(enable);
fDeselectButton.setEnabled(enable);
+ fAutoIncludeRequirementsButton.setEnabled(enable);
fIncludeOptionalButton.setEnabled(enable);
fAddWorkspaceButton.setEnabled(enable);
fCounter.setEnabled(enable);
diff --git a/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/launcher/FeatureBlock.java b/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/launcher/FeatureBlock.java
index c41a9eb..fd0700d 100644
--- a/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/launcher/FeatureBlock.java
+++ b/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/launcher/FeatureBlock.java
@@ -798,6 +798,8 @@
private Button fSelectAllButton;
private Button fDeselectAllButton;
+ private Button fAutoIncludeRequirementsButton;
+ private boolean fAutoIncludeRequirementsButtonChanged;
private Button fWorkspacePluginButton;
private Button fExternalPluginButton;
private Button fFilterButton;
@@ -850,6 +852,15 @@
createCheckBoxTree(treeGroup);
createButtonContainer(treeGroup, 10);
+ if (fTab instanceof PluginsTab) {
+ fAutoIncludeRequirementsButton = SWTFactory.createCheckButton(treeGroup, PDEUIMessages.AdvancedLauncherTab_autoIncludeRequirements_features_withPlugins, null, false, 1);
+ } else if (fTab instanceof BundlesTab) {
+ fAutoIncludeRequirementsButton = SWTFactory.createCheckButton(treeGroup, PDEUIMessages.AdvancedLauncherTab_autoIncludeRequirements_features_withBundles, null, false, 1);
+ }
+ fAutoIncludeRequirementsButton.addSelectionListener(fListener);
+ fAutoIncludeRequirementsButton.addSelectionListener(
+ SelectionListener.widgetSelectedAdapter(e -> this.fAutoIncludeRequirementsButtonChanged = true));
+
fFeatureWorkspaceButton = SWTFactory.createCheckButton(treeGroup, PDEUIMessages.FeatureBlock_UseWorkspaceFeatures, null, true, 2);
fFeatureWorkspaceButton.addSelectionListener(fListener);
@@ -1114,6 +1125,8 @@
setInput(config, fTree);
// Setup other buttons
+ boolean autoIncludeRequired = config.getAttribute(IPDELauncherConstants.AUTOMATIC_INCLUDE_REQUIREMENTS, true);
+ fAutoIncludeRequirementsButton.setSelection(autoIncludeRequired);
String pluginResolution = config.getAttribute(IPDELauncherConstants.FEATURE_PLUGIN_RESOLUTION, IPDELauncherConstants.LOCATION_WORKSPACE);
if (pluginResolution.equalsIgnoreCase(IPDELauncherConstants.LOCATION_WORKSPACE)) {
fWorkspacePluginButton.setSelection(true);
@@ -1147,6 +1160,11 @@
}
public void performApply(ILaunchConfigurationWorkingCopy config) {
+ if (fAutoIncludeRequirementsButtonChanged) {
+ boolean includeRequirements = fAutoIncludeRequirementsButton.getSelection();
+ config.setAttribute(IPDELauncherConstants.AUTOMATIC_INCLUDE_REQUIREMENTS, includeRequirements);
+ fAutoIncludeRequirementsButtonChanged = false;
+ }
config.setAttribute(IPDELauncherConstants.SHOW_SELECTED_ONLY, fFilterButton.getSelection());
config.setAttribute(IPDELauncherConstants.FEATURE_DEFAULT_LOCATION, fFeatureWorkspaceButton.getSelection() ? IPDELauncherConstants.LOCATION_WORKSPACE : IPDELauncherConstants.LOCATION_EXTERNAL);
config.setAttribute(IPDELauncherConstants.FEATURE_PLUGIN_RESOLUTION, fWorkspacePluginButton.getSelection() ? IPDELauncherConstants.LOCATION_WORKSPACE : IPDELauncherConstants.LOCATION_EXTERNAL);
diff --git a/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/pderesources.properties b/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/pderesources.properties
index b197d49..7075fa7 100644
--- a/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/pderesources.properties
+++ b/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/pderesources.properties
@@ -569,6 +569,10 @@
AdvancedLauncherTab_subset=Add Re&quired {0}
AdvancedLauncherTab_subset_bundles=Select Re&quired
AdvancedLauncherTab_subset_plugins=Select Re&quired
+AdvancedLauncherTab_autoIncludeRequirements_bundles=Include required Bundles automatically while launching
+AdvancedLauncherTab_autoIncludeRequirements_plugins=Include required Plug-ins automatically while launching
+AdvancedLauncherTab_autoIncludeRequirements_features_withBundles=Include required Features and Bundles automatically while launching
+AdvancedLauncherTab_autoIncludeRequirements_features_withPlugins=Include required Features and Plug-ins automatically while launching
AdvancedLauncherTab_selectedBundles = Only s&how selected
AdvancedLauncherTab_addNew=&Add new workspace {0} to this launch configuration automatically
AdvancedLauncherTab_addNew_plugins=&Add new workspace Plug-ins to this launch configuration automatically