1717import java .net .URL ;
1818import java .util .*;
1919import org .eclipse .core .runtime .*;
20+ import org .eclipse .equinox .internal .p2 .engine .*;
2021import org .eclipse .equinox .internal .provisional .frameworkadmin .BundleInfo ;
22+ import org .eclipse .equinox .internal .provisional .p2 .director .PlannerHelper ;
23+ import org .eclipse .equinox .internal .provisional .p2 .engine .*;
24+ import org .eclipse .equinox .internal .provisional .p2 .metadata .*;
25+ import org .eclipse .equinox .internal .provisional .p2 .metadata .VersionRange ;
26+ import org .eclipse .equinox .internal .provisional .p2 .metadata .MetadataFactory .InstallableUnitDescription ;
2127import org .eclipse .equinox .internal .provisional .simpleconfigurator .manipulator .SimpleConfiguratorManipulator ;
28+ import org .eclipse .osgi .service .resolver .*;
2229import org .eclipse .pde .core .plugin .IPluginBase ;
2330import org .eclipse .pde .core .plugin .IPluginModelBase ;
2431import org .eclipse .pde .internal .build .BundleHelper ;
2532import org .eclipse .pde .internal .build .IPDEBuildConstants ;
2633import org .eclipse .pde .internal .core .plugin .PluginBase ;
34+ import org .osgi .framework .Constants ;
2735
2836/**
29- * Utilities to read and write bundle and source information files.
37+ * Utilities to read and write p2 files
3038 *
3139 * @since 3.4
3240 */
@@ -39,6 +47,14 @@ public class P2Utils {
3947
4048 public static final String P2_FLAVOR_DEFAULT = "tooling" ; //$NON-NLS-1$
4149
50+ public static final ITouchpointType TOUCHPOINT_OSGI = MetadataFactory .createTouchpointType ("org.eclipse.equinox.p2.osgi" , Version .createOSGi (1 , 0 , 0 )); //$NON-NLS-1$
51+ private static final String CAPABILITY_NS_OSGI_BUNDLE = "osgi.bundle" ; //$NON-NLS-1$
52+ private static final String CAPABILITY_NS_OSGI_FRAGMENT = "osgi.fragment" ; //$NON-NLS-1$
53+ public static final String TYPE_ECLIPSE_BUNDLE = "bundle" ; //$NON-NLS-1$
54+ public static final String NAMESPACE_ECLIPSE_TYPE = "org.eclipse.equinox.p2.eclipse.type" ; //$NON-NLS-1$
55+ public static final IProvidedCapability BUNDLE_CAPABILITY = MetadataFactory .createProvidedCapability (NAMESPACE_ECLIPSE_TYPE , TYPE_ECLIPSE_BUNDLE , Version .createOSGi (1 , 0 , 0 ));
56+ public static final String CAPABILITY_NS_JAVA_PACKAGE = "java.package" ; //$NON-NLS-1$
57+
4258 /**
4359 * Returns bundles defined by the 'bundles.info' file in the
4460 * specified location, or <code>null</code> if none. The "bundles.info" file
@@ -296,4 +312,139 @@ public static URL writeBundlesTxt(Map bundles, int defaultStartLevel, boolean de
296312 }
297313 }
298314
315+ /**
316+ * Returns whether a profile with the given ID exists in a profile registry
317+ * stored in the give p2 data area.
318+ *
319+ * @param profileID id of the profile to check
320+ * @param p2DataArea data area where the profile registry is
321+ * @return whether the profile exists
322+ */
323+ public static boolean profileExists (String profileID , File p2DataArea ) {
324+ // Create a custom registry that checks the profile in the proper location
325+ File engineArea = new File (p2DataArea , EngineActivator .ID );
326+ File registryArea = new File (engineArea , SimpleProfileRegistry .DEFAULT_STORAGE_DIR );
327+ registryArea .mkdirs ();
328+ SimpleProfileRegistry customRegistry = new SimpleProfileRegistry (registryArea );
329+
330+ return customRegistry .containsProfile (profileID );
331+ }
332+
333+ /**
334+ * Generates a profile containing metadata for all of the bundles in the provided collection.
335+ * The profile will have the given profile ID and will be persisted in the profile registry
336+ * directory inside the given p2 data area.
337+ *
338+ * @param profileID the ID to be used when creating the profile, if a profile with the same name exists, it will be overwritten
339+ * @param p2DataArea the directory which contains p2 data including the profile registry, if the directory path doesn't exist it will be created
340+ * @param bundles the collection of bundles to create metadata for and add to the profile
341+ *
342+ * @throws CoreException if the profile cannot be generated
343+ */
344+ public static void createProfile (String profileID , File p2DataArea , Collection bundles ) throws CoreException {
345+ // 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)
346+
347+ // Create a custom registry that stores the profile in the proper location
348+ File engineArea = new File (p2DataArea , EngineActivator .ID );
349+ File registryArea = new File (engineArea , SimpleProfileRegistry .DEFAULT_STORAGE_DIR );
350+ registryArea .mkdirs ();
351+ SimpleProfileRegistry customRegistry = new SimpleProfileRegistry (registryArea );
352+
353+ // Delete any previous profiles with the same ID
354+ customRegistry .removeProfile (profileID );
355+
356+ // Create the profile
357+ IProfile profile = null ;
358+ Properties props = new Properties ();
359+ props .setProperty (IProfile .PROP_INSTALL_FOLDER , registryArea .getAbsolutePath ());
360+ profile = customRegistry .addProfile (profileID , props );
361+
362+ // Create metadata for the bundles
363+ Collection ius = new ArrayList (bundles .size ());
364+ for (Iterator iterator = bundles .iterator (); iterator .hasNext ();) {
365+ IPluginModelBase model = (IPluginModelBase ) iterator .next ();
366+ BundleDescription bundle = model .getBundleDescription ();
367+ ius .add (createBundleIU (bundle ));
368+ }
369+
370+ // Create operands to install the metadata
371+ Operand [] operands = new Operand [ius .size () * 2 ];
372+ int i = 0 ;
373+ for (Iterator iter = ius .iterator (); iter .hasNext ();) {
374+ IInstallableUnit iu = (IInstallableUnit ) iter .next ();
375+ operands [i ++] = new InstallableUnitOperand (null , iu );
376+ operands [i ++] = new InstallableUnitPropertyOperand (iu , "org.eclipse.equinox.p2.internal.inclusion.rules" , null , PlannerHelper .createOptionalInclusionRule (iu ));
377+ }
378+
379+ // Add the metadata to the profile
380+ ProvisioningContext context = new ProvisioningContext ();
381+ PhaseSet phaseSet = DefaultPhaseSet .createDefaultPhaseSet (DefaultPhaseSet .PHASE_CHECK_TRUST | DefaultPhaseSet .PHASE_COLLECT | DefaultPhaseSet .PHASE_CONFIGURE | DefaultPhaseSet .PHASE_UNCONFIGURE | DefaultPhaseSet .PHASE_UNINSTALL );
382+ File profileDataDirectory = customRegistry .getProfileDataDirectory (profile .getProfileId ());
383+ EngineSession session = new EngineSession (profile , profileDataDirectory , context );
384+ IStatus status = phaseSet .perform (new ActionManager (), session , profile , operands , context , new NullProgressMonitor ());
385+
386+ if (!status .isOK () && status .getSeverity () != IStatus .CANCEL ) {
387+ throw new CoreException (status );
388+ }
389+ }
390+
391+ /**
392+ * Creates an installable unit from a bundle description
393+ *
394+ * @param bd bundle description to create metadata for
395+ * @return an installable unit
396+ */
397+ private static IInstallableUnit createBundleIU (BundleDescription bd ) {
398+ InstallableUnitDescription iu = new MetadataFactory .InstallableUnitDescription ();
399+ iu .setSingleton (bd .isSingleton ());
400+ iu .setId (bd .getSymbolicName ());
401+ iu .setVersion (Version .fromOSGiVersion (bd .getVersion ()));
402+ iu .setFilter (bd .getPlatformFilter ());
403+ iu .setTouchpointType (TOUCHPOINT_OSGI );
404+
405+ boolean isFragment = bd .getHost () != null ;
406+
407+ //Process the required bundles
408+ BundleSpecification requiredBundles [] = bd .getRequiredBundles ();
409+ ArrayList reqsDeps = new ArrayList ();
410+ if (isFragment )
411+ reqsDeps .add (MetadataFactory .createRequiredCapability (CAPABILITY_NS_OSGI_BUNDLE , bd .getHost ().getName (), VersionRange .fromOSGiVersionRange (bd .getHost ().getVersionRange ()), null , false , false ));
412+ for (int j = 0 ; j < requiredBundles .length ; j ++)
413+ reqsDeps .add (MetadataFactory .createRequiredCapability (CAPABILITY_NS_OSGI_BUNDLE , requiredBundles [j ].getName (), VersionRange .fromOSGiVersionRange (requiredBundles [j ].getVersionRange ()), null , requiredBundles [j ].isOptional (), false ));
414+
415+ // Process the import packages
416+ ImportPackageSpecification osgiImports [] = bd .getImportPackages ();
417+ for (int i = 0 ; i < osgiImports .length ; i ++) {
418+ // TODO we need to sort out how we want to handle wild-carded dynamic imports - for now we ignore them
419+ ImportPackageSpecification importSpec = osgiImports [i ];
420+ String importPackageName = importSpec .getName ();
421+ if (importPackageName .indexOf ('*' ) != -1 )
422+ continue ;
423+ VersionRange versionRange = VersionRange .fromOSGiVersionRange (importSpec .getVersionRange ());
424+ //TODO this needs to be refined to take into account all the attribute handled by imports
425+ boolean isOptional = importSpec .getDirective (Constants .RESOLUTION_DIRECTIVE ).equals (ImportPackageSpecification .RESOLUTION_DYNAMIC ) || importSpec .getDirective (Constants .RESOLUTION_DIRECTIVE ).equals (ImportPackageSpecification .RESOLUTION_OPTIONAL );
426+ reqsDeps .add (MetadataFactory .createRequiredCapability (CAPABILITY_NS_JAVA_PACKAGE , importPackageName , versionRange , null , isOptional , false ));
427+ }
428+ iu .setRequiredCapabilities ((IRequiredCapability []) reqsDeps .toArray (new IRequiredCapability [reqsDeps .size ()]));
429+
430+ // Create set of provided capabilities
431+ ArrayList providedCapabilities = new ArrayList ();
432+ providedCapabilities .add (MetadataFactory .createProvidedCapability (IInstallableUnit .NAMESPACE_IU_ID , bd .getSymbolicName (), Version .fromOSGiVersion (bd .getVersion ())));
433+ providedCapabilities .add (MetadataFactory .createProvidedCapability (CAPABILITY_NS_OSGI_BUNDLE , bd .getSymbolicName (), Version .fromOSGiVersion (bd .getVersion ())));
434+
435+ // Process the export package
436+ ExportPackageDescription exports [] = bd .getExportPackages ();
437+ for (int i = 0 ; i < exports .length ; i ++) {
438+ //TODO make sure that we support all the refinement on the exports
439+ providedCapabilities .add (MetadataFactory .createProvidedCapability (CAPABILITY_NS_JAVA_PACKAGE , exports [i ].getName (), Version .fromOSGiVersion (exports [i ].getVersion ())));
440+ }
441+ // Here we add a bundle capability to identify bundles
442+ providedCapabilities .add (BUNDLE_CAPABILITY );
443+ if (isFragment )
444+ providedCapabilities .add (MetadataFactory .createProvidedCapability (CAPABILITY_NS_OSGI_FRAGMENT , bd .getHost ().getName (), Version .fromOSGiVersion (bd .getVersion ())));
445+
446+ iu .setCapabilities ((IProvidedCapability []) providedCapabilities .toArray (new IProvidedCapability [providedCapabilities .size ()]));
447+ return MetadataFactory .createInstallableUnit (iu );
448+ }
449+
299450}
0 commit comments