### Eclipse Workspace Patch 1.0 #P org.eclipse.pde.core Index: src/org/eclipse/pde/internal/core/P2Utils.java =================================================================== RCS file: /cvsroot/eclipse/pde/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/P2Utils.java,v retrieving revision 1.20 diff -u -r1.20 P2Utils.java --- src/org/eclipse/pde/internal/core/P2Utils.java 13 Apr 2009 14:10:31 -0000 1.20 +++ src/org/eclipse/pde/internal/core/P2Utils.java 22 Oct 2009 20:34:56 -0000 @@ -17,16 +17,24 @@ import java.net.URL; import java.util.*; import org.eclipse.core.runtime.*; +import org.eclipse.equinox.internal.p2.engine.*; import org.eclipse.equinox.internal.provisional.frameworkadmin.BundleInfo; +import org.eclipse.equinox.internal.provisional.p2.director.PlannerHelper; +import org.eclipse.equinox.internal.provisional.p2.engine.*; +import org.eclipse.equinox.internal.provisional.p2.metadata.*; +import org.eclipse.equinox.internal.provisional.p2.metadata.VersionRange; +import org.eclipse.equinox.internal.provisional.p2.metadata.MetadataFactory.InstallableUnitDescription; import org.eclipse.equinox.internal.provisional.simpleconfigurator.manipulator.SimpleConfiguratorManipulator; +import org.eclipse.osgi.service.resolver.*; import org.eclipse.pde.core.plugin.IPluginBase; import org.eclipse.pde.core.plugin.IPluginModelBase; import org.eclipse.pde.internal.build.BundleHelper; import org.eclipse.pde.internal.build.IPDEBuildConstants; import org.eclipse.pde.internal.core.plugin.PluginBase; +import org.osgi.framework.Constants; /** - * Utilities to read and write bundle and source information files. + * Utilities to read and write p2 files * * @since 3.4 */ @@ -39,6 +47,14 @@ public static final String P2_FLAVOR_DEFAULT = "tooling"; //$NON-NLS-1$ + public static final ITouchpointType TOUCHPOINT_OSGI = MetadataFactory.createTouchpointType("org.eclipse.equinox.p2.osgi", Version.createOSGi(1, 0, 0)); //$NON-NLS-1$ + private static final String CAPABILITY_NS_OSGI_BUNDLE = "osgi.bundle"; //$NON-NLS-1$ + private static final String CAPABILITY_NS_OSGI_FRAGMENT = "osgi.fragment"; //$NON-NLS-1$ + public static final String TYPE_ECLIPSE_BUNDLE = "bundle"; //$NON-NLS-1$ + public static final String NAMESPACE_ECLIPSE_TYPE = "org.eclipse.equinox.p2.eclipse.type"; //$NON-NLS-1$ + public static final IProvidedCapability BUNDLE_CAPABILITY = MetadataFactory.createProvidedCapability(NAMESPACE_ECLIPSE_TYPE, TYPE_ECLIPSE_BUNDLE, Version.createOSGi(1, 0, 0)); + public static final String CAPABILITY_NS_JAVA_PACKAGE = "java.package"; //$NON-NLS-1$ + /** * Returns bundles defined by the 'bundles.info' file in the * specified location, or null if none. The "bundles.info" file @@ -296,4 +312,148 @@ } } + /** + * Returns whether a profile with the given ID exists in a profile registry + * stored in the give p2 data area. + * + * @param profileID id of the profile to check + * @param p2DataArea data area where the profile registry is + * @return whether the profile exists + */ + public static boolean profileExists(String profileID, File p2DataArea) { + // Create a custom registry that checks the profile in the proper location + File engineArea = new File(p2DataArea, EngineActivator.ID); + File registryArea = new File(engineArea, SimpleProfileRegistry.DEFAULT_STORAGE_DIR); + registryArea.mkdirs(); + SimpleProfileRegistry customRegistry = new SimpleProfileRegistry(registryArea); + + return customRegistry.containsProfile(profileID); + } + + /** + * Generates a profile containing metadata for all of the bundles in the provided collection. + * The profile will have the given profile ID and will be persisted in the profile registry + * directory inside the given p2 data area. + * + * @param profileID the ID to be used when creating the profile, if a profile with the same name exists, it will be overwritten + * @param p2DataArea the directory which contains p2 data including the profile registry, if the directory path doesn't exist it will be created + * @param bundles the collection of bundles to create metadata for and add to the profile + * + * @throws CoreException if the profile cannot be generated + */ + public static void createProfile(String profileID, File p2DataArea, Collection bundles) throws CoreException { + // TODO Could avoid using internal p2 code if multiple instances of the p2 servers could be run on the same vm (being looked at in 3.6) + + // Create a custom registry that stores the profile in the proper location + File engineArea = new File(p2DataArea, EngineActivator.ID); + File registryArea = new File(engineArea, SimpleProfileRegistry.DEFAULT_STORAGE_DIR); + registryArea.mkdirs(); + SimpleProfileRegistry customRegistry = new SimpleProfileRegistry(registryArea); + + // Delete any previous profiles with the same ID + customRegistry.removeProfile(profileID); + + // Create the profile + IProfile profile = null; + Properties props = new Properties(); + props.setProperty(IProfile.PROP_INSTALL_FOLDER, registryArea.getAbsolutePath()); + profile = customRegistry.addProfile(profileID, props); + + // Create metadata for the bundles + Collection ius = new ArrayList(bundles.size()); + for (Iterator iterator = bundles.iterator(); iterator.hasNext();) { + IPluginModelBase model = (IPluginModelBase) iterator.next(); + BundleDescription bundle = model.getBundleDescription(); + ius.add(createBundleIU(bundle)); + } + + // Create operands to install the metadata + Operand[] operands = new Operand[ius.size() * 2]; + int i = 0; + for (Iterator iter = ius.iterator(); iter.hasNext();) { + IInstallableUnit iu = (IInstallableUnit) iter.next(); + operands[i++] = new InstallableUnitOperand(null, iu); + operands[i++] = new InstallableUnitPropertyOperand(iu, "org.eclipse.equinox.p2.internal.inclusion.rules", null, PlannerHelper.createOptionalInclusionRule(iu)); + } + + // Add the metadata to the profile + ProvisioningContext context = new ProvisioningContext(); + PhaseSet phaseSet = DefaultPhaseSet.createDefaultPhaseSet(DefaultPhaseSet.PHASE_CHECK_TRUST | DefaultPhaseSet.PHASE_COLLECT | DefaultPhaseSet.PHASE_CONFIGURE | DefaultPhaseSet.PHASE_UNCONFIGURE | DefaultPhaseSet.PHASE_UNINSTALL); + File profileDataDirectory = customRegistry.getProfileDataDirectory(profile.getProfileId()); + EngineSession session = new EngineSession(profile, profileDataDirectory, context); + IStatus status = phaseSet.perform(new ActionManager(), session, profile, operands, context, new NullProgressMonitor()); + + if (!status.isOK() && status.getSeverity() != IStatus.CANCEL) { + throw new CoreException(status); + } + } + + /** + * Creates an installable unit from a bundle description + * + * @param bd bundle description to create metadata for + * @return an installable unit + */ + private static IInstallableUnit createBundleIU(BundleDescription bd) { + InstallableUnitDescription iu = new MetadataFactory.InstallableUnitDescription(); + iu.setSingleton(bd.isSingleton()); + iu.setId(bd.getSymbolicName()); + iu.setVersion(Version.fromOSGiVersion(bd.getVersion())); + iu.setFilter(bd.getPlatformFilter()); + iu.setTouchpointType(TOUCHPOINT_OSGI); + + boolean isFragment = bd.getHost() != null; + + //Process the required bundles + BundleSpecification requiredBundles[] = bd.getRequiredBundles(); + ArrayList reqsDeps = new ArrayList(); + if (isFragment) + reqsDeps.add(MetadataFactory.createRequiredCapability(CAPABILITY_NS_OSGI_BUNDLE, bd.getHost().getName(), VersionRange.fromOSGiVersionRange(bd.getHost().getVersionRange()), null, false, false)); + for (int j = 0; j < requiredBundles.length; j++) + reqsDeps.add(MetadataFactory.createRequiredCapability(CAPABILITY_NS_OSGI_BUNDLE, requiredBundles[j].getName(), VersionRange.fromOSGiVersionRange(requiredBundles[j].getVersionRange()), null, requiredBundles[j].isOptional(), false)); + + // Process the import packages + ImportPackageSpecification osgiImports[] = bd.getImportPackages(); + for (int i = 0; i < osgiImports.length; i++) { + // TODO we need to sort out how we want to handle wild-carded dynamic imports - for now we ignore them + ImportPackageSpecification importSpec = osgiImports[i]; + String importPackageName = importSpec.getName(); + if (importPackageName.indexOf('*') != -1) + continue; + VersionRange versionRange = VersionRange.fromOSGiVersionRange(importSpec.getVersionRange()); + //TODO this needs to be refined to take into account all the attribute handled by imports + reqsDeps.add(MetadataFactory.createRequiredCapability(CAPABILITY_NS_JAVA_PACKAGE, importPackageName, versionRange, null, isOptional(importSpec), false)); + } + iu.setRequiredCapabilities((IRequiredCapability[]) reqsDeps.toArray(new IRequiredCapability[reqsDeps.size()])); + + // Create set of provided capabilities + ArrayList providedCapabilities = new ArrayList(); + providedCapabilities.add(createSelfCapability(bd.getSymbolicName(), Version.fromOSGiVersion(bd.getVersion()))); + providedCapabilities.add(MetadataFactory.createProvidedCapability(CAPABILITY_NS_OSGI_BUNDLE, bd.getSymbolicName(), Version.fromOSGiVersion(bd.getVersion()))); + + // Process the export package + ExportPackageDescription exports[] = bd.getExportPackages(); + for (int i = 0; i < exports.length; i++) { + //TODO make sure that we support all the refinement on the exports + providedCapabilities.add(MetadataFactory.createProvidedCapability(CAPABILITY_NS_JAVA_PACKAGE, exports[i].getName(), Version.fromOSGiVersion(exports[i].getVersion()))); + } + // Here we add a bundle capability to identify bundles + providedCapabilities.add(BUNDLE_CAPABILITY); + if (isFragment) + providedCapabilities.add(MetadataFactory.createProvidedCapability(CAPABILITY_NS_OSGI_FRAGMENT, bd.getHost().getName(), Version.fromOSGiVersion(bd.getVersion()))); + + iu.setCapabilities((IProvidedCapability[]) providedCapabilities.toArray(new IProvidedCapability[providedCapabilities.size()])); + return MetadataFactory.createInstallableUnit(iu); + } + + private static IProvidedCapability createSelfCapability(String installableUnitId, Version installableUnitVersion) { + return MetadataFactory.createProvidedCapability(IInstallableUnit.NAMESPACE_IU_ID, installableUnitId, installableUnitVersion); + } + + private static boolean isOptional(ImportPackageSpecification importedPackage) { + if (importedPackage.getDirective(Constants.RESOLUTION_DIRECTIVE).equals(ImportPackageSpecification.RESOLUTION_DYNAMIC) || importedPackage.getDirective(Constants.RESOLUTION_DIRECTIVE).equals(ImportPackageSpecification.RESOLUTION_OPTIONAL)) + return true; + return false; + } + } #P org.eclipse.pde.launching Index: src/org/eclipse/pde/internal/launching/launcher/LaunchConfigurationHelper.java =================================================================== RCS file: /cvsroot/eclipse/pde/ui/org.eclipse.pde.launching/src/org/eclipse/pde/internal/launching/launcher/LaunchConfigurationHelper.java,v retrieving revision 1.2 diff -u -r1.2 LaunchConfigurationHelper.java --- src/org/eclipse/pde/internal/launching/launcher/LaunchConfigurationHelper.java 21 Sep 2009 18:53:53 -0000 1.2 +++ src/org/eclipse/pde/internal/launching/launcher/LaunchConfigurationHelper.java 22 Oct 2009 20:34:57 -0000 @@ -10,11 +10,6 @@ *******************************************************************************/ package org.eclipse.pde.internal.launching.launcher; -import org.eclipse.pde.launching.IPDELauncherConstants; - -import org.eclipse.pde.internal.launching.PDELaunchingPlugin; - - import java.io.*; import java.net.URL; import java.util.*; @@ -28,6 +23,9 @@ import org.eclipse.pde.core.plugin.TargetPlatform; import org.eclipse.pde.internal.build.IPDEBuildConstants; import org.eclipse.pde.internal.core.*; +import org.eclipse.pde.internal.launching.IPDEConstants; +import org.eclipse.pde.internal.launching.PDELaunchingPlugin; +import org.eclipse.pde.launching.IPDELauncherConstants; /** * Contains helper methods for launching an Eclipse Runtime Workbench @@ -37,6 +35,12 @@ private static final String PROP_OSGI_FRAMEWORK = "osgi.framework"; //$NON-NLS-1$ private static final String PROP_OSGI_BUNDLES = "osgi.bundles"; //$NON-NLS-1$ private static final String PROP_P2_DATA_AREA = "eclipse.p2.data.area"; //$NON-NLS-1$ + private static final String DEFAULT_PROFILE_NAME = "SelfHostingProfile"; //$NON-NLS-1$ + + /** + * The p2 data area will be set to a directory with this name inside the configuration folder + */ + private static final String DEFAULT_P2_DIRECTORY = ".p2"; //$NON-NLS-1$ public static void synchronizeManifests(ILaunchConfiguration config, File configDir) { try { @@ -83,7 +87,7 @@ return mgr.performStringSubstitution(text); } - public static Properties createConfigIniFile(ILaunchConfiguration configuration, String productID, Map bundles, Map bundlesWithStartLevels, File directory) throws CoreException { + public static Properties createConfigIniFile(ILaunchConfiguration configuration, String productID, Map bundles, Map bundlesWithStartLevels, File configurationDirectory) throws CoreException { Properties properties = null; // if we are to generate a config.ini, start with the values in the target platform's config.ini - bug 141918 if (configuration.getAttribute(IPDELauncherConstants.CONFIG_GENERATE_DEFAULT, true)) { @@ -98,12 +102,6 @@ String bundleList = properties.getProperty(PROP_OSGI_BUNDLES); if (bundleList != null) properties.setProperty(PROP_OSGI_BUNDLES, computeOSGiBundles(TargetPlatformHelper.stripPathInformation(bundleList), bundles, bundlesWithStartLevels)); - String dataArea = properties.getProperty(PROP_P2_DATA_AREA); - if (dataArea != null) { - // Make the p2 data area in the configuration area itself, rather than a sibling of the configuration - // area (which is a the root pde.core shared metadata area) @see bug 272810 - properties.setProperty(PROP_P2_DATA_AREA, "@config.dir/.p2"); //$NON-NLS-1$ - } } else { String templateLoc = configuration.getAttribute(IPDELauncherConstants.CONFIG_TEMPLATE_LOCATION, (String) null); if (templateLoc != null) { @@ -120,25 +118,28 @@ } else { properties = new Properties(); } - if (!directory.exists()) { - directory.mkdirs(); + if (!configurationDirectory.exists()) { + configurationDirectory.mkdirs(); } String osgiBundles = properties.getProperty(PROP_OSGI_BUNDLES); int start = configuration.getAttribute(IPDELauncherConstants.DEFAULT_START_LEVEL, 4); properties.put("osgi.bundles.defaultStartLevel", Integer.toString(start)); //$NON-NLS-1$ boolean autostart = configuration.getAttribute(IPDELauncherConstants.DEFAULT_AUTO_START, false); - // if we are launching using P2, write out P2 files (bundles.txt) and add P2 property to config.ini + // Special processing for launching with p2 if (osgiBundles != null && osgiBundles.indexOf(IPDEBuildConstants.BUNDLE_SIMPLE_CONFIGURATOR) != -1 && bundles.containsKey(IPDEBuildConstants.BUNDLE_SIMPLE_CONFIGURATOR)) { + + // Write out P2 files (bundles.txt) URL bundlesTxt = null; boolean usedefault = configuration.getAttribute(IPDELauncherConstants.USE_DEFAULT, true); boolean useFeatures = configuration.getAttribute(IPDELauncherConstants.USEFEATURES, false); if (usedefault || useFeatures) { - bundlesTxt = P2Utils.writeBundlesTxt(bundlesWithStartLevels, 4, false, directory, osgiBundles); + bundlesTxt = P2Utils.writeBundlesTxt(bundlesWithStartLevels, 4, false, configurationDirectory, osgiBundles); } else { - bundlesTxt = P2Utils.writeBundlesTxt(bundlesWithStartLevels, start, autostart, directory, null); + bundlesTxt = P2Utils.writeBundlesTxt(bundlesWithStartLevels, start, autostart, configurationDirectory, null); } + // Add bundles.txt as p2 config data if (bundlesTxt != null) { properties.setProperty("org.eclipse.equinox.simpleconfigurator.configUrl", bundlesTxt.toString()); //$NON-NLS-1$ // if we have simple configurator and update configurator together, ensure update doesn't reconcile @@ -146,11 +147,27 @@ properties.setProperty("org.eclipse.update.reconcile", "false"); //$NON-NLS-1$ //$NON-NLS-2$ } } + + // Make the p2 data area in the configuration area itself, rather than a sibling of the configuration + // area (which is a the root pde.core shared metadata area) @see bug 272810 + properties.setProperty(PROP_P2_DATA_AREA, "@config.dir/".concat(DEFAULT_P2_DIRECTORY)); //$NON-NLS-1$ + + // Generate a profile to launch with, set the profile id as the default + if (configuration.getAttribute(IPDELauncherConstants.GENERATE_PROFILE, false)) { + String profileID = DEFAULT_PROFILE_NAME; + File p2DataArea = new File(configurationDirectory, DEFAULT_P2_DIRECTORY); + + // Unless we are restarting an existing profile, generate/overwrite the profile + if (!configuration.getAttribute(IPDEConstants.RESTART, false) || !P2Utils.profileExists(profileID, p2DataArea)) { + P2Utils.createProfile(profileID, p2DataArea, bundles.values()); + } + properties.setProperty("eclipse.p2.profile", profileID); //$NON-NLS-1$ + } } setBundleLocations(bundles, properties, autostart); - save(new File(directory, "config.ini"), properties); //$NON-NLS-1$ + save(new File(configurationDirectory, "config.ini"), properties); //$NON-NLS-1$ return properties; } #P org.eclipse.pde.ui Index: src/org/eclipse/pde/internal/ui/PDEUIMessages.java =================================================================== RCS file: /cvsroot/eclipse/pde/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/PDEUIMessages.java,v retrieving revision 1.446 diff -u -r1.446 PDEUIMessages.java --- src/org/eclipse/pde/internal/ui/PDEUIMessages.java 5 Oct 2009 22:43:14 -0000 1.446 +++ src/org/eclipse/pde/internal/ui/PDEUIMessages.java 22 Oct 2009 20:34:58 -0000 @@ -2677,6 +2677,10 @@ public static String ProductInfoSection_features; + public static String ProfileBlock_0; + + public static String ProfileBlock_1; + public static String ImportPackageSection_goToPackage; public static String ExportPackageSection_findReferences;