### Eclipse Workspace Patch 1.0 #P org.eclipse.pde.core Index: src/org/eclipse/pde/internal/core/target/AbstractBundleContainer.java =================================================================== RCS file: /cvsroot/eclipse/pde/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/target/AbstractBundleContainer.java,v retrieving revision 1.9 diff -u -r1.9 AbstractBundleContainer.java --- src/org/eclipse/pde/internal/core/target/AbstractBundleContainer.java 30 Aug 2010 21:30:07 -0000 1.9 +++ src/org/eclipse/pde/internal/core/target/AbstractBundleContainer.java 30 Nov 2010 21:03:55 -0000 @@ -41,12 +41,12 @@ /** * Resolved bundles or null if unresolved */ - private IResolvedBundle[] fBundles; + protected IResolvedBundle[] fBundles; /** * List of features contained in this bundle container or null if unresolved */ - private IFeatureModel[] fFeatures; + protected IFeatureModel[] fFeatures; /** * Status generated when this container was resolved, possibly null @@ -551,4 +551,14 @@ } return fVMArgs; } + + /** + * Associate this bundle container with the given target. This allows for the container and + * the target to share configuration information etc. + * + * @param target the target to which this container is being added. + */ + protected void associateWithTarget(ITargetDefinition target) { + // Do nothing by default + } } Index: src/org/eclipse/pde/internal/core/target/IUBundleContainer.java =================================================================== RCS file: /cvsroot/eclipse/pde/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/target/IUBundleContainer.java,v retrieving revision 1.33 diff -u -r1.33 IUBundleContainer.java --- src/org/eclipse/pde/internal/core/target/IUBundleContainer.java 17 Nov 2010 20:00:09 -0000 1.33 +++ src/org/eclipse/pde/internal/core/target/IUBundleContainer.java 30 Nov 2010 21:03:55 -0000 @@ -8,31 +8,19 @@ * Contributors: * IBM Corporation - initial API and implementation * Sonatype, Inc. - ongoing development + * EclipseSource, Inc. - ongoing development *******************************************************************************/ package org.eclipse.pde.internal.core.target; import java.io.File; import java.net.URI; -import java.net.URISyntaxException; import java.util.*; import org.eclipse.core.runtime.*; -import org.eclipse.core.runtime.preferences.IPreferencesService; import org.eclipse.equinox.internal.p2.director.PermissiveSlicer; -import org.eclipse.equinox.internal.p2.engine.ProfileMetadataRepository; -import org.eclipse.equinox.p2.core.IAgentLocation; -import org.eclipse.equinox.p2.core.ProvisionException; -import org.eclipse.equinox.p2.engine.*; -import org.eclipse.equinox.p2.engine.query.IUProfilePropertyQuery; +import org.eclipse.equinox.p2.engine.IProfile; import org.eclipse.equinox.p2.metadata.*; -import org.eclipse.equinox.p2.metadata.MetadataFactory.InstallableUnitDescription; -import org.eclipse.equinox.p2.planner.IPlanner; -import org.eclipse.equinox.p2.planner.IProfileChangeRequest; import org.eclipse.equinox.p2.query.*; -import org.eclipse.equinox.p2.repository.*; -import org.eclipse.equinox.p2.repository.artifact.IArtifactRepositoryManager; import org.eclipse.equinox.p2.repository.artifact.IFileArtifactRepository; -import org.eclipse.equinox.p2.repository.metadata.IMetadataRepository; -import org.eclipse.equinox.p2.repository.metadata.IMetadataRepositoryManager; import org.eclipse.equinox.p2.touchpoint.eclipse.query.OSGiBundleQuery; import org.eclipse.osgi.util.NLS; import org.eclipse.pde.internal.core.PDECore; @@ -57,64 +45,56 @@ private static final String FEATURE_ID_SUFFIX = ".feature.group"; //$NON-NLS-1$ /** - * IU identifiers. + * Whether this container must have all required IUs of the selected IUs available and included + * in the target to resolve successfully. If this option is true, the planner will be used to resolve + * otherwise the slicer is used. The planner can describe any missing requirements as errors. */ - private String[] fIds; + public static final int INCLUDE_REQUIRED = 1 << 0; /** - * IU versions + * Whether this container should download and include environment (platform) specific units for all + * available platforms (vs only the current target definition's environment settings). Only supported + * by the slicer so {@link fIncludeAllRequired} must be turned off for this setting to be used. */ - private Version[] fVersions; + public static final int INCLUDE_ALL_ENVIRONMENTS = 1 << 1; /** - * Cached IU's referenced by this bundle container, or null if not - * resolved. + * Whether this container should download and include source bundles for the selected units if the associated + * source is available in the repository. */ - private IInstallableUnit[] fUnits; + public static final int INCLUDE_SOURCE = 1 << 2; /** - * Cached id/version pairs listing the features that were downloaded to the bundle pool during resolution. null if not resolved. + * IU identifiers. */ - private NameVersionDescriptor[] fFeatures; + private String[] fIds; /** - * Repositories to consider, or null if default. + * IU versions */ - private URI[] fRepos; + private Version[] fVersions; /** - * Whether this container must have all required IUs of the selected IUs available and included - * in the target to resolve successfully. If this option is true, the planner will be used to resolve - * otherwise the slicer is used. The planner can describe any missing requirements as errors. - *

- * true by default - *

+ * Cached IU's referenced by this bundle container, or null if not + * resolved. */ - private boolean fIncludeAllRequired = true; + private IInstallableUnit[] fUnits; /** - * Whether this container should download and include environment (platform) specific units for all - * available platforms (vs only the current target definition's environment settings). Only supported - * by the slicer so {@link fIncludeAllRequired} must be turned off for this setting to be used. - *

- * false by default - *

+ * Repositories to consider, or null if default. */ - private boolean fIncludeMultipleEnvironments = false; + private URI[] fRepos; /** - * Whether this container should download and include source bundles for the selected units if the associated - * source is available in the repository. - *

- * falseby default + * A set of bitmask flags that indicate how this container gets elements from its + * associated p2 repository. */ - private boolean fIncludeSource = false; + private int fFlags; /** - * Constant ID for a root installable unit that is installed into the profile if {@link #fIncludeSource} is set - * to true. The source units found in the repository will be set as required IUs on the root unit. + * The p2 synchronizer to use in managing this container. */ - private static final String SOURCE_IU_ID = "org.eclipse.pde.core.target.source.bundles"; //$NON-NLS-1$ + private P2TargetUtils fSynchronizer; private static final boolean DEBUG_PROFILE; @@ -127,11 +107,12 @@ * * @param ids IU identifiers * @param versions IU versions - * @param repositories metadata repositories used to search for IU's or null if - * default set + * @param repositories metadata repositories used to search for IU's or null for default set + * @param resolutionFlags bitmask of flags to control IU resolution, possible flags are {@link IUBundleContainer#INCLUDE_ALL_ENVIRONMENTS}, {@link IUBundleContainer#INCLUDE_REQUIRED}, {@link IUBundleContainer#INCLUDE_SOURCE} */ - IUBundleContainer(String[] ids, String[] versions, URI[] repositories) { + IUBundleContainer(String[] ids, String[] versions, URI[] repositories, int resolutionFlags) { fIds = ids; + fFlags = resolutionFlags; fVersions = new Version[versions.length]; for (int i = 0; i < versions.length; i++) { fVersions[i] = Version.create(versions[i]); @@ -148,12 +129,12 @@ * Constructs a installable unit bundle container for the specified units. * * @param units IU's - * @param repositories metadata repositories used to search for IU's or null if - * default set + * @param repositories metadata repositories used to search for IU's or null for default set + * @param resolutionFlags bitmask of flags to control IU resolution, possible flags are {@link IUBundleContainer#INCLUDE_ALL_ENVIRONMENTS}, {@link IUBundleContainer#INCLUDE_REQUIRED}, {@link IUBundleContainer#INCLUDE_SOURCE} */ - IUBundleContainer(IInstallableUnit[] units, URI[] repositories) { - fUnits = units; + IUBundleContainer(IInstallableUnit[] units, URI[] repositories, int resolutionFlags) { fIds = new String[units.length]; + fFlags = resolutionFlags; fVersions = new Version[units.length]; for (int i = 0; i < units.length; i++) { fIds[i] = units[i].getId(); @@ -184,609 +165,131 @@ * @see org.eclipse.pde.internal.core.target.AbstractBundleContainer#resolveFeatures(org.eclipse.pde.internal.core.target.provisional.ITargetDefinition, org.eclipse.core.runtime.IProgressMonitor) */ protected IFeatureModel[] resolveFeatures(ITargetDefinition definition, IProgressMonitor monitor) throws CoreException { - if (fFeatures == null || fFeatures.length == 0 || !(definition instanceof TargetDefinition)) { + fSynchronizer.synchronize(monitor); + return fFeatures; + } + + /** + * Update this container's cache of feature objects based on the given profile. + * NOTE: this method expects the synchronizer to be synchronized and is called + * as a result of a synchronization operation. + */ + IFeatureModel[] cacheFeatures() throws CoreException { + Set features = new HashSet(); + for (int i = 0; i < fUnits.length; i++) { + IInstallableUnit unit = fUnits[i]; + String id = unit.getId(); + // if theIU was explicitly added and the naming convention says it is a feature, then add it. + // This is less than optimal but there is no clear way of identifying an IU as a feature. + if (isRoot(id, unit.getVersion()) && id.endsWith(FEATURE_ID_SUFFIX)) { + id = id.substring(0, id.length() - FEATURE_ID_SUFFIX.length()); + String version = unit.getVersion().toString(); + features.add(new NameVersionDescriptor(id, version, NameVersionDescriptor.TYPE_FEATURE)); + } + } + if (features.isEmpty()) { return new IFeatureModel[0]; } - // Note: By creating a map of the container features, we are limiting the user to only one version of a feature in this container + // Now get feature models for all known features + TargetDefinition definition = (TargetDefinition) fSynchronizer.getTargetDefinition(); + IFeatureModel[] allFeatures = definition.getFeatureModels(getLocation(false), new NullProgressMonitor()); - // Get all the features in the bundle pool - IFeatureModel[] allFeatures = ((TargetDefinition) definition).getFeatureModels(getLocation(false), monitor); - - // Create a map of the container features for quick lookups - HashMap containerFeatures = new HashMap(); - for (int i = 0; i < fFeatures.length; i++) { - containerFeatures.put(fFeatures[i].getId(), fFeatures[i]); - } - - List includedFeatures = new ArrayList(); + // Build a final set of the models for the features in the profile. + List result = new ArrayList(); for (int i = 0; i < allFeatures.length; i++) { - NameVersionDescriptor candidate = (NameVersionDescriptor) containerFeatures.get(allFeatures[i].getFeature().getId()); - if (candidate != null) { - if (candidate.getVersion().equals(allFeatures[i].getFeature().getVersion())) { - includedFeatures.add(allFeatures[i]); - } + NameVersionDescriptor candidate = new NameVersionDescriptor(allFeatures[i].getFeature().getId(), allFeatures[i].getFeature().getVersion(), NameVersionDescriptor.TYPE_FEATURE); + if (features.contains(candidate)) { + result.add(allFeatures[i]); } } - return (IFeatureModel[]) includedFeatures.toArray(new IFeatureModel[includedFeatures.size()]); + fFeatures = (IFeatureModel[]) result.toArray(new IFeatureModel[result.size()]); + return fFeatures; + } + + private boolean isRoot(String id, Version version) { + for (int i = 0; i < fIds.length; i++) { + String fid = fIds[i]; + if (fid.equals(id) && fVersions[i].equals(version)) + return true; + } + return false; } /* (non-Javadoc) * @see org.eclipse.pde.internal.core.target.impl.AbstractBundleContainer#resolveBundles(org.eclipse.pde.internal.core.target.provisional.ITargetDefinition, org.eclipse.core.runtime.IProgressMonitor) */ protected IResolvedBundle[] resolveBundles(ITargetDefinition definition, IProgressMonitor monitor) throws CoreException { - // Resolving may change the included features, clear the cached values - fFeatures = null; - - SubMonitor subMon = SubMonitor.convert(monitor, 100); - - // Attempt to restore from the profile first, as it is local and faster - IResolvedBundle[] result = resolveWithProfile(definition, subMon.newChild(25)); - if (result != null) { - subMon.done(); - return result; - } - - // Unable to load from profile, resolve normally - try { - if (fIncludeAllRequired) { - result = resolveWithPlanner(definition, subMon.newChild(75)); - } else { - result = resolveWithSlicer(definition, subMon.newChild(75)); - } - // If there is a problem generating the profile, delete it so it doesn't get used by #resolveWithProfile() - if (result == null || result.length == 0 || subMon.isCanceled()) { - AbstractTargetHandle handle = ((AbstractTargetHandle) definition.getHandle()); - P2TargetUtils.deleteProfile(handle); - } - return result; - } catch (CoreException e) { - AbstractTargetHandle handle = ((AbstractTargetHandle) definition.getHandle()); - P2TargetUtils.deleteProfile(handle); - throw e; - } - + fSynchronizer.synchronize(monitor); + return fBundles; } /** - * Used to resolve the contents of this container if the container has been resolved and saved to a profile file. If the - * profile contains the correct bundles, there is no need to do a full resolve. If this method has a problem (missing - * file, unable to compute all dependent bundles), this method will return null and the caller should - * use {@link #resolveWithPlanner(ITargetDefinition, IProgressMonitor)} or {@link #resolveWithSlicer(ITargetDefinition, IProgressMonitor)} - * to do a full resolve. - * - * @param definition definition being resolved - * @param monitor for reporting progress - * @return set of bundles included in this container or null if the profile is out of date - * @throws CoreException if an unexpected problem occurs trying to read from the profile - */ - private IResolvedBundle[] resolveWithProfile(ITargetDefinition definition, IProgressMonitor monitor) throws CoreException { - if (DEBUG_PROFILE) { - System.out.println("Target resolution using profile (" + definition.getName() + ")"); //$NON-NLS-1$//$NON-NLS-2$ - } - - IProfile profile = P2TargetUtils.getProfile(definition); - if (profile == null) { - if (DEBUG_PROFILE) { - System.out.println("No profile found"); //$NON-NLS-1$ - } - return null; - } - - SubMonitor subMonitor = SubMonitor.convert(monitor, Messages.IUBundleContainer_LoadingFromProfileJob, 20); - - // Always create our own units because the slicer will return existing units even though the profile is empty - if (DEBUG_PROFILE) { - System.out.print("Required Units: "); //$NON-NLS-1$ - for (int i = 0; i < fIds.length; i++) { - System.out.print(fIds[i] + ", "); //$NON-NLS-1$ - } - System.out.println(); - } - - fUnits = new IInstallableUnit[fIds.length]; + * Update this container's cache of top level IUs based on the given profile. + * NOTE: this method expects the synchronizer to be synchronized and is called + * as a result of a synchronization operation. + */ + IInstallableUnit[] cacheIUs() throws CoreException { + IProfile profile = fSynchronizer.getProfile(); + ArrayList result = new ArrayList(); for (int i = 0; i < fIds.length; i++) { IQuery query = QueryUtil.createIUQuery(fIds[i], fVersions[i]); IQueryResult queryResult = profile.query(query, null); - if (queryResult.isEmpty()) { - if (DEBUG_PROFILE) { - System.out.println("Required unit not found in profile: " + fIds[i]); //$NON-NLS-1$ - } - fUnits = null; - return null; - } - fUnits[i] = (IInstallableUnit) queryResult.iterator().next(); - } - // check that the include source flag matches what the profile represents - if (fIncludeSource != (getCurrentSourceIU(profile) != null)) - return null; - - // OK. Everything looks good. Now gather the features and bundles and be done. - ResolvedBundle[] resolvedBundles = updateAfterResolve(profile, definition); - - subMonitor.worked(10); - subMonitor.done(); - if (DEBUG_PROFILE) { - if (resolvedBundles == null || resolvedBundles.length == 0) - System.out.println("No bundles loaded from profile"); //$NON-NLS-1$ - else - System.out.println("Loading from profile successful. " + resolvedBundles.length + " bundles found"); //$NON-NLS-1$ //$NON-NLS-2$ - System.out.println(); - } - return resolvedBundles; - } - - /** - * Used to resolve the contents of this container if the user is including all required software. The p2 planner is used - * to determine the complete set of IUs required to run the selected software. If all requirements are met, the bundles - * are downloaded from the repository into the bundle pool and added to the target definition. - * - * @param definition definition being resolved - * @param monitor for reporting progress - * @return set of bundles included in this container - * @throws CoreException if there is a problem with the requirements or there is a problem downloading - */ - private IResolvedBundle[] resolveWithPlanner(ITargetDefinition definition, IProgressMonitor monitor) throws CoreException { - SubProgressMonitor subMonitor = new SubProgressMonitor(monitor, 10); - subMonitor.beginTask(Messages.IUBundleContainer_0, 200); - - // retrieve profile - IProfile profile = P2TargetUtils.getProfile(definition); - profile.getTimestamp(); - subMonitor.worked(10); - - if (subMonitor.isCanceled()) { - return new IResolvedBundle[0]; - } - - // resolve IUs - IInstallableUnit[] units = getInstallableUnits(profile); - - if (subMonitor.isCanceled()) { - return new IResolvedBundle[0]; - } - - // create the provisioning plan - IPlanner planner = P2TargetUtils.getPlanner(); - IProfileChangeRequest request = planner.createChangeRequest(profile); - // first remove everything that was explicitly installed. Then add it back. This has the net effect of - // removing everything that is no longer needed. - computeRemovals(profile, request, units); - request.addAll(Arrays.asList(units)); - for (int i = 0; i < units.length; i++) { - IInstallableUnit unit = units[i]; - request.setInstallableUnitProfileProperty(unit, P2TargetUtils.PROP_INSTALLED_IU, Boolean.toString(true)); - } - - ProvisioningContext context = new ProvisioningContext(P2TargetUtils.getAgent()); - context.setMetadataRepositories(resolveRepositories()); - context.setArtifactRepositories(resolveArtifactRepositories()); - - if (subMonitor.isCanceled()) { - return new IResolvedBundle[0]; - } - - IProvisioningPlan plan = planner.getProvisioningPlan(request, context, new SubProgressMonitor(subMonitor, 20)); - IStatus status = plan.getStatus(); - if (!status.isOK()) { - throw new CoreException(status); - } - IProvisioningPlan installerPlan = plan.getInstallerPlan(); - if (installerPlan != null) { - // this plan requires an update to the installer first, log the fact and attempt - // to continue, we don't want to update the running SDK while provisioning a target - PDECore.log(new Status(IStatus.INFO, PDECore.PLUGIN_ID, Messages.IUBundleContainer_6)); - } - subMonitor.worked(10); - - if (subMonitor.isCanceled()) { - return new IResolvedBundle[0]; - } - - // execute the provisioning plan - IPhaseSet phases = PhaseSetFactory.createDefaultPhaseSetExcluding(new String[] {PhaseSetFactory.PHASE_CHECK_TRUST, PhaseSetFactory.PHASE_CONFIGURE, PhaseSetFactory.PHASE_UNCONFIGURE}); - IEngine engine = P2TargetUtils.getEngine(); - plan.setProfileProperty(P2TargetUtils.PROP_PROVISION_MODE, TargetDefinitionPersistenceHelper.MODE_PLANNER); - plan.setProfileProperty(P2TargetUtils.PROP_ALL_ENVIRONMENTS, Boolean.toString(false)); - IStatus result = engine.perform(plan, phases, new SubProgressMonitor(subMonitor, 140)); - - if (subMonitor.isCanceled()) { - return new IResolvedBundle[0]; - } - if (!result.isOK()) { - throw new CoreException(result); - } - - // Now that we have a plan with all the binary and explicit bundles, do a second pass and add - // in all the source. - try { - planInSourceBundles(profile, context, subMonitor); - } catch (CoreException e) { - // XXX Review required: is adding in the source critical or optional? - // We failed adding in the source so remove the intermediate profile and rethrow - P2TargetUtils.getProfileRegistry().removeProfile(profile.getProfileId(), profile.getTimestamp()); - throw e; - } - - ResolvedBundle[] resolvedBundles = updateAfterResolve(profile, definition); - subMonitor.worked(10); - subMonitor.done(); - return resolvedBundles; - } - - /** - * Update the given change request to remove anything that was explicitly installed - * including the internal source IU. - */ - private void computeRemovals(IProfile profile, IProfileChangeRequest request, IInstallableUnit[] units) { - // if include source is off then ensure that the source IU is removed. - if (!fIncludeSource) { - IInstallableUnit sourceIU = getCurrentSourceIU(profile); - if (sourceIU != null) - request.remove(sourceIU); - } - // remove everything that is marked as roots. The plan will have the new roots added in anyway. - IQuery query = new IUProfilePropertyQuery(P2TargetUtils.PROP_INSTALLED_IU, Boolean.toString(true)); - IQueryResult installedIUs = profile.query(query, null); - request.removeAll(installedIUs.toSet()); - } - - // run a second pass of the planner to add in the source bundles for everything that's - // in the current profile. - private void planInSourceBundles(IProfile profile, ProvisioningContext context, IProgressMonitor monitor) throws CoreException { - if (!fIncludeSource) - return; - - SubProgressMonitor subMonitor = new SubProgressMonitor(monitor, 10); - subMonitor.beginTask(Messages.IUBundleContainer_ProvisioningSourceBundles, 200); - - // create an IU that optionally and greedily requires the related source bundles. - // Completely replace any source IU that may already be in place - IInstallableUnit currentSourceIU = getCurrentSourceIU(profile); - - // determine the new version number. start at 1 - Version sourceVersion = Version.createOSGi(1, 0, 0); - if (currentSourceIU != null) { - Integer major = (Integer) currentSourceIU.getVersion().getSegment(0); - sourceVersion = Version.createOSGi(major.intValue() + 1, 0, 0); - } - IInstallableUnit sourceIU = createSourceIU(profile, sourceVersion); - - // call the planner again to add in the new source IU and all available source bundles - IPlanner planner = P2TargetUtils.getPlanner(); - IProfileChangeRequest request = planner.createChangeRequest(profile); - if (currentSourceIU != null) - request.remove(currentSourceIU); - request.add(sourceIU); - IProvisioningPlan plan = planner.getProvisioningPlan(request, context, new SubProgressMonitor(subMonitor, 20)); - IStatus status = plan.getStatus(); - if (!status.isOK()) { - throw new CoreException(status); - } - if (subMonitor.isCanceled()) { - return; - } - - long oldTimestamp = profile.getTimestamp(); - - // execute the provisioning plan - IPhaseSet phases = PhaseSetFactory.createDefaultPhaseSetExcluding(new String[] {PhaseSetFactory.PHASE_CHECK_TRUST, PhaseSetFactory.PHASE_CONFIGURE, PhaseSetFactory.PHASE_UNCONFIGURE, PhaseSetFactory.PHASE_UNINSTALL}); - IEngine engine = P2TargetUtils.getEngine(); - plan.setProfileProperty(P2TargetUtils.PROP_PROVISION_MODE, TargetDefinitionPersistenceHelper.MODE_PLANNER); - plan.setProfileProperty(P2TargetUtils.PROP_ALL_ENVIRONMENTS, Boolean.toString(false)); - IStatus result = engine.perform(plan, phases, new SubProgressMonitor(subMonitor, 140)); - - if (subMonitor.isCanceled()) { - return; - } - if (!result.isOK()) { - throw new CoreException(result); - } - - // remove the old (intermediate) profile version now we have a new one with source. - P2TargetUtils.getProfileRegistry().removeProfile(profile.getProfileId(), oldTimestamp); - subMonitor.worked(10); - subMonitor.done(); - } - - // Create and return an IU that has optional and greedy requirements on all source bundles - // related to bundle IUs in the given queryable. - /** - * Creates and returns an IU that has optional and greedy requirements on all source bundles - * related to bundle IUs in the given queryable. - * @param queryable location to search for source bundle IUs - * @param iuVersion version to set on the returned installable unit - * @return a new installable unit with requirements on the available source IUs - */ - private IInstallableUnit createSourceIU(IQueryable queryable, Version iuVersion) { - // compute the set of source bundles we could possibly need for the bundles in the profile - IRequirement bundleRequirement = MetadataFactory.createRequirement("org.eclipse.equinox.p2.eclipse.type", "bundle", null, null, false, false, false); //$NON-NLS-1$ //$NON-NLS-2$ - IQueryResult profileIUs = queryable.query(QueryUtil.createIUAnyQuery(), null); - ArrayList requirements = new ArrayList(); - for (Iterator i = profileIUs.iterator(); i.hasNext();) { - IInstallableUnit profileIU = (IInstallableUnit) i.next(); - if (profileIU.satisfies(bundleRequirement)) { - String id = profileIU.getId() + ".source"; //$NON-NLS-1$ - Version version = profileIU.getVersion(); - VersionRange range = new VersionRange(version, true, version, true); - IRequirement sourceRequirement = MetadataFactory.createRequirement("osgi.bundle", id, range, null, true, false, true); //$NON-NLS-1$ - requirements.add(sourceRequirement); - } + if (queryResult.isEmpty()) + throw new CoreException(new Status(IStatus.ERROR, PDECore.PLUGIN_ID, NLS.bind(Messages.IUBundleContainer_1, fIds[i]))); + result.add(queryResult.iterator().next()); } - - InstallableUnitDescription sourceDescription = new MetadataFactory.InstallableUnitDescription(); - sourceDescription.setSingleton(true); - sourceDescription.setId(SOURCE_IU_ID); - sourceDescription.setVersion(iuVersion); - sourceDescription.addRequirements(requirements); - IProvidedCapability capability = MetadataFactory.createProvidedCapability(IInstallableUnit.NAMESPACE_IU_ID, SOURCE_IU_ID, iuVersion); - sourceDescription.setCapabilities(new IProvidedCapability[] {capability}); - return MetadataFactory.createInstallableUnit(sourceDescription); - } - - /** - * Lookup and return the source IU in the given queryable or null if not found. - * @param queryable location to look for source IUs - * @return the source IU or null - */ - private IInstallableUnit getCurrentSourceIU(IQueryable queryable) { - IQuery query = QueryUtil.createIUQuery(SOURCE_IU_ID); - IQueryResult list = queryable.query(query, null); - IInstallableUnit currentSourceIU = null; - if (!list.isEmpty()) - currentSourceIU = (IInstallableUnit) list.iterator().next(); - return currentSourceIU; + fUnits = (IInstallableUnit[]) result.toArray(new IInstallableUnit[result.size()]); + return fUnits; } /** - * Used to resolve the contents of this container when the user has chosen to manage the dependencies in the target - * themselves. The selected IUs and any required software that can be found will be retrieved from the repositories - * and added to the target. Any missing required software will be ignored. - * - * @param definition definition being resolved - * @param monitor for reporting progress - * @return set of resolved bundles included in this container - * @throws CoreException if there is a problem interacting with the repositories - */ - private IResolvedBundle[] resolveWithSlicer(ITargetDefinition definition, IProgressMonitor monitor) throws CoreException { - SubProgressMonitor subMonitor = new SubProgressMonitor(monitor, 10); - subMonitor.beginTask(Messages.IUBundleContainer_0, 180); - - // retrieve profile - IProfile profile = P2TargetUtils.getProfile(definition); - subMonitor.worked(10); - - if (subMonitor.isCanceled()) { - return new IResolvedBundle[0]; - } - - // resolve IUs - IInstallableUnit[] units = getInstallableUnits(profile); - - if (subMonitor.isCanceled()) { - return new IResolvedBundle[0]; - } - - URI[] repositories = resolveRepositories(); - int repoCount = repositories.length; - if (repoCount == 0) { - return new IResolvedBundle[0]; - } - - IProgressMonitor loadMonitor = new SubProgressMonitor(subMonitor, 10); - loadMonitor.beginTask(null, repoCount * 10); - List metadataRepos = new ArrayList(repoCount); - MultiStatus repoStatus = new MultiStatus(PDECore.PLUGIN_ID, 0, Messages.IUBundleContainer_ProblemsLoadingRepositories, null); - IMetadataRepositoryManager manager = P2TargetUtils.getRepoManager(); - for (int i = 0; i < repoCount; ++i) { - try { - IMetadataRepository repo = manager.loadRepository(repositories[i], new SubProgressMonitor(loadMonitor, 10)); - metadataRepos.add(repo); - } catch (ProvisionException e) { - repoStatus.add(e.getStatus()); - } - } - loadMonitor.done(); - - IQueryable allMetadata; - if (metadataRepos.size() == 0) { - throw new CoreException(repoStatus); - } else if (metadataRepos.size() == 1) { - allMetadata = (IQueryable) metadataRepos.get(0); - } else { - allMetadata = QueryUtil.compoundQueryable(metadataRepos); - } - - // do an initial slice to add everything the user requested - IQueryResult queryResult = slice(units, allMetadata, definition, subMonitor); - if (subMonitor.isCanceled() || queryResult == null || queryResult.isEmpty()) { - return new IResolvedBundle[0]; - } - - // If we are including source then create a source IU to bring in the relevant source - // bundles and run the slicer again. - if (fIncludeSource) { - // Build an IU that represents all the source bundles and slice again to add them in if available - IInstallableUnit sourceIU = createSourceIU(queryResult, Version.createOSGi(1, 0, 0)); - IInstallableUnit[] units2 = new IInstallableUnit[units.length + 1]; - System.arraycopy(units, 0, units2, 0, units.length); - units2[units.length] = sourceIU; - - queryResult = slice(units2, allMetadata, definition, subMonitor); - if (subMonitor.isCanceled() || queryResult == null || queryResult.isEmpty()) { - return new IResolvedBundle[0]; - } - } - - IEngine engine = P2TargetUtils.getEngine(); - ProvisioningContext context = new ProvisioningContext(P2TargetUtils.getAgent()); - context.setMetadataRepositories(repositories); - context.setArtifactRepositories(resolveArtifactRepositories()); - IProvisioningPlan plan = engine.createPlan(profile, context); - - Set newSet = queryResult.toSet(); - Iterator itor = newSet.iterator(); - while (itor.hasNext()) { - plan.addInstallableUnit((IInstallableUnit) itor.next()); - } - for (int i = 0; i < units.length; i++) { - IInstallableUnit unit = units[i]; - plan.setInstallableUnitProfileProperty(unit, P2TargetUtils.PROP_INSTALLED_IU, Boolean.toString(true)); - } - - // remove all units that are in the current profile but not in the new slice - Set toRemove = profile.query(QueryUtil.ALL_UNITS, null).toSet(); - toRemove.removeAll(newSet); - for (Iterator i = toRemove.iterator(); i.hasNext();) { - plan.removeInstallableUnit((IInstallableUnit) i.next()); - } - - plan.setProfileProperty(P2TargetUtils.PROP_PROVISION_MODE, TargetDefinitionPersistenceHelper.MODE_SLICER); - plan.setProfileProperty(P2TargetUtils.PROP_ALL_ENVIRONMENTS, Boolean.toString(getIncludeAllEnvironments())); - - // execute the provisioning plan - IPhaseSet phases = PhaseSetFactory.createDefaultPhaseSetExcluding(new String[] {PhaseSetFactory.PHASE_CHECK_TRUST, PhaseSetFactory.PHASE_CONFIGURE, PhaseSetFactory.PHASE_UNCONFIGURE}); - IStatus result = engine.perform(plan, phases, new SubProgressMonitor(subMonitor, 140)); - - if (subMonitor.isCanceled()) { - return new IResolvedBundle[0]; - } - if (!result.isOK()) { - throw new CoreException(result); - } - - ResolvedBundle[] resolvedBundles = updateAfterResolve(profile, definition); - - subMonitor.worked(10); - subMonitor.done(); - return resolvedBundles; - } - - private ResolvedBundle[] updateAfterResolve(IProfile profile, ITargetDefinition definition) throws CoreException { - // Cache the feature list - queryForFeatures(profile); + * Update this container's cache of bundle objects based on the given profile. + * NOTE: this method expects the synchronizer to be synchronized and is called + * as a result of a synchronization operation. + */ + IResolvedBundle[] cacheBundles() throws CoreException { + // slice the profile to find the bundles attributed to this container. + // Look only for strict dependencies if we are using the slicer. + // We can always consider all platforms since the profile wouldn't contain it if it was not interesting + boolean onlyStrict = !fSynchronizer.getIncludeAllRequired(); + IProfile metadata = fSynchronizer.getProfile(); + PermissiveSlicer slicer = new PermissiveSlicer(metadata, new HashMap(), true, false, true, onlyStrict, false); + IQueryable slice = slicer.slice(fUnits, new NullProgressMonitor()); // query for bundles - IFileArtifactRepository repository = null; + IFileArtifactRepository artifacts = null; try { - repository = P2TargetUtils.getBundlePool(profile); + artifacts = P2TargetUtils.getBundlePool(); } catch (CoreException e) { if (DEBUG_PROFILE) { System.out.println("Bundle pool repository could not be loaded"); //$NON-NLS-1$ } - return null; + return fBundles = null; } - Map bundles = generateResolvedBundles(profile, repository, true); - if (bundles == null || bundles.isEmpty()) { + Map bundles = generateResolvedBundles(slice, metadata, artifacts); + if (bundles.isEmpty()) { if (DEBUG_PROFILE) { System.out.println("Profile does not contain any bundles or artifacts were missing"); //$NON-NLS-1$ } - return null; - } - - removeDuplicateBundles(definition, bundles); - if (bundles.isEmpty()) { - return null; + return fBundles = null; } - return (ResolvedBundle[]) bundles.values().toArray(new ResolvedBundle[bundles.size()]); - } - - private IQueryResult slice(IInstallableUnit[] units, IQueryable allMetadata, ITargetDefinition definition, SubProgressMonitor subMonitor) throws CoreException { - // slice IUs and all prerequisites - PermissiveSlicer slicer = null; - if (getIncludeAllEnvironments()) { - slicer = new PermissiveSlicer(allMetadata, new HashMap(), true, false, true, true, false); - } else { - Map props = new HashMap(); - props.put("osgi.os", definition.getOS() != null ? definition.getOS() : Platform.getOS()); //$NON-NLS-1$ - props.put("osgi.ws", definition.getWS() != null ? definition.getWS() : Platform.getWS()); //$NON-NLS-1$ - props.put("osgi.arch", definition.getArch() != null ? definition.getArch() : Platform.getOSArch()); //$NON-NLS-1$ - props.put("osgi.nl", definition.getNL() != null ? definition.getNL() : Platform.getNL()); //$NON-NLS-1$ - props.put(IProfile.PROP_INSTALL_FEATURES, Boolean.TRUE.toString()); - slicer = new PermissiveSlicer(allMetadata, props, true, false, false, true, false); - } - IQueryable slice = slicer.slice(units, new SubProgressMonitor(subMonitor, 10)); - if (!slicer.getStatus().isOK()) { - throw new CoreException(slicer.getStatus()); - } - IQueryResult queryResult = null; - if (slice != null) - queryResult = slice.query(QueryUtil.createIUAnyQuery(), new SubProgressMonitor(subMonitor, 10)); - return queryResult; - } - - /** - * Queries the given given queryable and finds all feature group IUs. The feature id/versions of the features - * are cached in {@link #fFeatures}. - * - * @param queryable profile/slicer/etc. to query for features - */ - private void queryForFeatures(IQueryable queryable) { - // Query for features, cache the result for calls to resolveFeatures() - // Get any IU with the group property, this will return any feature groups - IQuery featureQuery = QueryUtil.createMatchQuery("properties[$0] == $1", new Object[] {MetadataFactory.InstallableUnitDescription.PROP_TYPE_GROUP, Boolean.TRUE.toString()}); //$NON-NLS-1$ - IQueryResult featureResult = queryable.query(featureQuery, null); - List features = new ArrayList(); - for (Iterator iterator = featureResult.iterator(); iterator.hasNext();) { - IInstallableUnit unit = (IInstallableUnit) iterator.next(); - String id = unit.getId(); - if (id.endsWith(FEATURE_ID_SUFFIX)) { - id = id.substring(0, id.length() - FEATURE_ID_SUFFIX.length()); - } - String version = unit.getVersion().toString(); - features.add(new NameVersionDescriptor(id, version, NameVersionDescriptor.TYPE_FEATURE)); - } - fFeatures = (NameVersionDescriptor[]) features.toArray(new NameVersionDescriptor[features.size()]); + fBundles = (ResolvedBundle[]) bundles.values().toArray(new ResolvedBundle[bundles.size()]); + return fBundles; } - /** - * Returns the IU's this container references. Checks in the profile first to avoid - * going out to repositories. - * - * @param profile profile to check first - * @return IU's - * @exception CoreException if unable to retrieve IU's + /* + * Respond to the notification that the synchronizer associated with this container has changed + * This is a callback method used by the synchronizer. + * It should NOT be called any other time. */ - public synchronized IInstallableUnit[] getInstallableUnits(IProfile profile) throws CoreException { - if (fUnits == null) { - fUnits = new IInstallableUnit[fIds.length]; - for (int i = 0; i < fIds.length; i++) { - IQuery query = QueryUtil.createIUQuery(fIds[i], fVersions[i]); - IQueryResult queryResult = profile.query(query, null); - if (queryResult.isEmpty()) { - // try repositories - URI[] repositories = resolveRepositories(); - for (int j = 0; j < repositories.length; j++) { - try { - IMetadataRepository repository = P2TargetUtils.getRepository(repositories[j]); - queryResult = repository.query(query, null); - if (!queryResult.isEmpty()) { - break; - } - } catch (ProvisionException e) { - // Ignore and move on to the next site - } - } - } - if (queryResult.isEmpty()) { - // not found - fUnits = null; - throw new CoreException(new Status(IStatus.ERROR, PDECore.PLUGIN_ID, NLS.bind(Messages.IUBundleContainer_1, fIds[i]))); - } - fUnits[i] = (IInstallableUnit) queryResult.iterator().next(); - } - } - return fUnits; - } - - private IMetadataRepository[] getRepos() throws CoreException { - URI[] repos = resolveRepositories(); - IMetadataRepository[] result = new IMetadataRepository[repos.length]; - for (int i = 0; i < repos.length; i++) - result[i] = P2TargetUtils.getRepository(repos[i]); - return result; + void synchronizerChanged() throws CoreException { + // cache the IUs first as they are used to slice the profile for the other caches. + cacheIUs(); + cacheBundles(); + cacheFeatures(); } /** @@ -794,11 +297,11 @@ * * @param toUpdate the set of IU ids in this container to consider updating. If null * then update everything - * @return a bitmasked int indicating how/if this container changed. See {@link UpdateTargetJob#DIRTY} and {@link UpdateTargetJob#UPDATED}. + * @return a bitmasked int indicating how/if this container changed. See DIRTY and UPDATED. * @exception CoreException if unable to retrieve IU's */ public synchronized int update(Set toUpdate) throws CoreException { - IQueryable source = new CompoundQueryable(getRepos()); + IQueryable source = fSynchronizer.getQueryableMetadata(fRepos, null); int dirty = 0; int updated = 0; for (int i = 0; i < fIds.length; i++) { @@ -811,7 +314,6 @@ if (!it.hasNext()) throw new CoreException(new Status(IStatus.ERROR, PDECore.PLUGIN_ID, NLS.bind(Messages.IUBundleContainer_1, fIds[i]))); IInstallableUnit iu = (IInstallableUnit) it.next(); - fUnits[i] = iu; // if the version is different from the spec (up or down), record the change. if (!iu.getVersion().equals(fVersions[i])) { updated = UpdateTargetJob.UPDATED; @@ -826,87 +328,64 @@ } /** - * Checks all other bundle containers in the given target and removes any bundles provided by them from - * the map. This prevents targets containing more than one IUBundleContainer from having duplicate bundles. - * - * @param definition target definition to look for other containers in - * @param bundles collection of bundles arranged by mapping BundleInfo to IResolvedBundle - */ - private void removeDuplicateBundles(ITargetDefinition definition, Map bundles) { - // remove all bundles from previous IU containers (so we don't get duplicates from multi-locations - IBundleContainer[] containers = definition.getBundleContainers(); - for (int i = 0; i < containers.length; i++) { - IBundleContainer container = containers[i]; - if (container == this) { - break; - } - if (container instanceof IUBundleContainer) { - IUBundleContainer bc = (IUBundleContainer) container; - IResolvedBundle[] included = bc.getBundles(); - if (included != null) { - for (int j = 0; j < included.length; j++) { - bundles.remove(included[j].getBundleInfo()); - } - } - } - } - } - - /** * Collects all available installable units from the given source that represent OSGI * bundles. A IResolvedBundle is created for each and a map containing all results * mapping BundleInfo to IResolvedBundle is returned. *

- * If there is an artifact missing for a unit it will either be ignored (not added to the returned map), - * or null will be returned depending on the ignoreMissingFiles parameter. + * If there is an artifact missing for a unit it will be ignored (not added to the returned map). + * If this container is setup to automatically include source, an corresponding source bundles + * found in the given profile will also be added as resolved bundles. *

- * @param source A queryable profile or slice that the bundle units will be obtained from - * @param ignoreMissingFiles if true ius that have missing artifacts will be ignored and not added to the map, if false, null will be returned - * @return map of BundleInfo to IResolvedBundle or null if a missing file is found and not ignored + * @param source the bundle units to be converted + * @param metadata the metadata backing the conversion + * @param artifacts the underlying artifact repo against which the bundles are validated + * @return map of BundleInfo to IResolvedBundle * @throws CoreException */ - private Map generateResolvedBundles(IQueryable source, IFileArtifactRepository repo, boolean ignoreMissingFiles) throws CoreException { + private Map generateResolvedBundles(IQueryable source, IQueryable metadata, IFileArtifactRepository artifacts) throws CoreException { OSGiBundleQuery query = new OSGiBundleQuery(); IQueryResult queryResult = source.query(query, null); Map bundles = new LinkedHashMap(); - for (Iterator iterator = queryResult.iterator(); iterator.hasNext();) { - IInstallableUnit unit = (IInstallableUnit) iterator.next(); - Collection artifacts = unit.getArtifacts(); - for (Iterator iterator2 = artifacts.iterator(); iterator2.hasNext();) { - File file = repo.getArtifactFile((IArtifactKey) iterator2.next()); - if (file == null) { - // Missing file - if (!ignoreMissingFiles) { - if (DEBUG_PROFILE) { - System.out.println("Backing file missing for: " + unit.getId()); //$NON-NLS-1$ - } - return null; - } - } else { - IResolvedBundle bundle = generateBundle(file); - if (bundle != null) { - bundles.put(bundle.getBundleInfo(), bundle); - } + for (Iterator i = queryResult.iterator(); i.hasNext();) { + IInstallableUnit unit = (IInstallableUnit) i.next(); + generateBundle(unit, artifacts, bundles); + if (getIncludeSource()) { + // bit of a hack using the bundle naming convention for finding source bundles + // but this matches what we do when adding source to the profile so... + IQuery sourceQuery = QueryUtil.createIUQuery(unit.getId() + ".source", unit.getVersion()); //$NON-NLS-1$ + IQueryResult result = metadata.query(sourceQuery, null); + if (!result.isEmpty()) { + generateBundle((IInstallableUnit) result.iterator().next(), artifacts, bundles); } } } return bundles; } + private void generateBundle(IInstallableUnit unit, IFileArtifactRepository repo, Map bundles) throws CoreException { + Collection artifacts = unit.getArtifacts(); + for (Iterator iterator2 = artifacts.iterator(); iterator2.hasNext();) { + File file = repo.getArtifactFile((IArtifactKey) iterator2.next()); + if (file != null) { + IResolvedBundle bundle = generateBundle(file); + if (bundle != null) { + bundles.put(bundle.getBundleInfo(), bundle); + } + } + } + } + /* (non-Javadoc) * @see org.eclipse.pde.internal.core.target.impl.AbstractBundleContainer#isContentEqual(org.eclipse.pde.internal.core.target.impl.AbstractBundleContainer) */ public boolean isContentEqual(AbstractBundleContainer container) { if (container instanceof IUBundleContainer) { IUBundleContainer iuContainer = (IUBundleContainer) container; - if (iuContainer.getIncludeAllRequired() == getIncludeAllRequired()) { - // include all targets only matters if include all required is turned off - if (getIncludeAllRequired() || iuContainer.getIncludeAllEnvironments() == getIncludeAllEnvironments()) { - return isEqualOrNull(fIds, iuContainer.fIds) && isEqualOrNull(fVersions, iuContainer.fVersions) && isEqualOrNull(fRepos, iuContainer.fRepos); - } - } - if (fIncludeSource != iuContainer.getIncludeSource()) - return false; + boolean result = true; + result &= iuContainer.getIncludeAllRequired() == getIncludeAllRequired(); + result &= iuContainer.getIncludeAllEnvironments() == getIncludeAllEnvironments(); + result &= iuContainer.getIncludeSource() == getIncludeSource(); + return result && isEqualOrNull(fIds, iuContainer.fIds) && isEqualOrNull(fVersions, iuContainer.fVersions) && isEqualOrNull(fRepos, iuContainer.fRepos); } return false; } @@ -947,141 +426,24 @@ } /** - * Returns the repositories to consider when resolving IU's (will return default set of - * repositories if current repository settings are null). - * - * @return URI's of repositories to use when resolving bundles - * @exception CoreException - */ - private URI[] resolveRepositories() throws CoreException { - if (fRepos == null) { - IMetadataRepositoryManager manager = P2TargetUtils.getRepoManager(); - return manager.getKnownRepositories(IRepositoryManager.REPOSITORIES_ALL); - } - return fRepos; - } - - /** - * Returns the artifact repositories to consider when getting artifacts. Returns a default set of - * repositories if current repository settings are null). + * Removes an installable unit from this container. The container will no longer be resolved. * - * @return URI's of repositories to use when getting artifacts - * @exception CoreException - */ - private URI[] resolveArtifactRepositories() throws CoreException { - URI[] repositories = fRepos; - if (fRepos == null) { - IArtifactRepositoryManager manager = P2TargetUtils.getArtifactRepositoryManager(); - repositories = manager.getKnownRepositories(IRepositoryManager.REPOSITORIES_ALL); - } - if (!useAdditionalLocalArtifacts()) - return repositories; - Set additionalRepos = new HashSet(Arrays.asList(repositories)); - findProfileRepos(additionalRepos); - findWorkspaceRepos(additionalRepos); - return (URI[]) additionalRepos.toArray(new URI[additionalRepos.size()]); - } - - /** - * @return whether to use local artifact repositories when provisioning the target - */ - private boolean useAdditionalLocalArtifacts() { - // TODO consider using a preference here or another strategy if users are able to spec - // what local repos are to be considered. - return true; - } - - /** - * Add the artifact repos from the PDE target bundle pools from all known repos. For example, the list - * of "recent workspaces" maintained by the IDE is a good source. - * - * @param additionalRepos the set to which additional repos are added. - */ - private void findWorkspaceRepos(Set additionalRepos) { - IPreferencesService prefs = P2TargetUtils.getPreferences(); - if (prefs == null) - return; - String recent = prefs.getString("org.eclipse.ui.ide", "RECENT_WORKSPACES", null, null); //$NON-NLS-1$ //$NON-NLS-2$ - if (recent == null) - return; - String[] recents = recent.split("\n"); //$NON-NLS-1$ - for (int i = 0; i < recents.length; i++) { - String bundlePool = recents[i] + "/.metadata/.plugins/org.eclipse.pde.core/.bundle_pool"; //$NON-NLS-1$ - if (new File(bundlePool).exists()) { - URI uri; - try { - uri = new URI("file", bundlePool, null); //$NON-NLS-1$ - additionalRepos.add(uri); - } catch (URISyntaxException e) { - // should never happen - } - } - } - } - - /** - * Look through the current p2 profile (_SELF_) and add the artifact repos that make up its - * bundle pool, dropins location, ... This helps in the cases that you are targeting stuff that - * makes up your current IDE. - * - * @param additionalRepos the set to which additional repos are added. + * @param unit unit to remove from the list of root IUs */ - private void findProfileRepos(Set additionalRepos) { - try { - // NOTE: be sure to use the global p2 agent here as we are looking for SELF. - IProfileRegistry profileRegistry = (IProfileRegistry) P2TargetUtils.getGlobalAgent().getService(IProfileRegistry.SERVICE_NAME); - if (profileRegistry == null) - return; - IProfile self = profileRegistry.getProfile(IProfileRegistry.SELF); - if (self == null) - return; - - IAgentLocation location = (IAgentLocation) P2TargetUtils.getGlobalAgent().getService(IAgentLocation.SERVICE_NAME); - URI dataArea = location.getDataArea("org.eclipse.equinox.p2.engine"); //$NON-NLS-1$ - dataArea = URIUtil.append(dataArea, "profileRegistry/" + self.getProfileId() + ".profile"); //$NON-NLS-1$//$NON-NLS-2$ - ProfileMetadataRepository profileRepo = new ProfileMetadataRepository(P2TargetUtils.getGlobalAgent(), dataArea, null); - Collection repos = profileRepo.getReferences(); - for (Iterator i = repos.iterator(); i.hasNext();) { - Object element = i.next(); - if (element instanceof IRepositoryReference) { - IRepositoryReference reference = (IRepositoryReference) element; - if (reference.getType() == IRepository.TYPE_ARTIFACT && reference.getLocation() != null) - additionalRepos.add(reference.getLocation()); - } + public synchronized void removeInstallableUnit(IInstallableUnit unit) { + List newIds = new ArrayList(fIds.length); + List newVersions = new ArrayList(fIds.length); + for (int i = 0; i < fIds.length; i++) { + if (fIds[i].equals(unit.getId()) && fVersions[i].equals(unit.getVersion())) { + newIds.add(fIds[i]); + newVersions.add(fVersions[i]); } - } catch (CoreException e) { - // if there is a problem, move on. Could log something here - return; } - } + fIds = (String[]) newIds.toArray(new String[newIds.size()]); + fVersions = (Version[]) newVersions.toArray(new Version[newVersions.size()]); - /** - * Sets whether all required units must be available to resolve this container. When true - * the resolve operation will use the planner to determine the complete set of IUs required to - * make the selected IUs runnable. If any dependencies are missing, the resolve operation will return an - * error explaining what problems exist. When false the resolve operation will use the slicer - * to determine what units to include. Any required units that are not available in the repositories will - * be ignored. - *

- * Since there is only one profile per target and the planner and slicer resolve methods are incompatible - * it is highly recommended that the parent target be passed to this method so all other IUBundleContainers - * in the target can be updated with the new setting. - *

- * @param include whether all required units must be available to resolve this container - * @param definition parent target, used to update other IUBundleContainers with this setting, can be null - */ - public void setIncludeAllRequired(boolean include, ITargetDefinition definition) { - fIncludeAllRequired = include; - if (definition != null) { - IBundleContainer[] containers = definition.getBundleContainers(); - if (containers != null) { - for (int i = 0; i < containers.length; i++) { - if (containers[i] instanceof IUBundleContainer && containers[i] != this) { - ((IUBundleContainer) containers[i]).setIncludeAllRequired(include, null); - } - } - } - } + // Need to mark the container as unresolved + clearResolutionStatus(); } /** @@ -1095,35 +457,10 @@ * @return whether all required units must be available to resolve this container */ public boolean getIncludeAllRequired() { - return fIncludeAllRequired; - } - - /** - * Sets whether all environment (platform) specific installable units should - * be included in this container when it is resolved. This feature is not supported - * by the planner so will only have an effect if the include all required setting - * is turned off ({@link #getIncludeAllRequired()}). - *

- * There is only one profile per target and this setting can only be set for the - * entire target definition. It is highly recommended that the parent target be passed - * to this method so all other IUBundleContainers in the target can be updated with the - * new setting. - *

- * @param include whether environment specific units should be included - * @param definition parent target, used to update other IUBundleContainers with this setting, can be null - */ - public void setIncludeAllEnvironments(boolean include, ITargetDefinition definition) { - fIncludeMultipleEnvironments = include; - if (definition != null) { - IBundleContainer[] containers = definition.getBundleContainers(); - if (containers != null) { - for (int i = 0; i < containers.length; i++) { - if (containers[i] instanceof IUBundleContainer && containers[i] != this) { - ((IUBundleContainer) containers[i]).setIncludeAllEnvironments(include, null); - } - } - } - } + // if this container has not been associated with a container, return its own value + if (fSynchronizer == null) + return (fFlags & INCLUDE_REQUIRED) == INCLUDE_REQUIRED; + return fSynchronizer.getIncludeAllRequired(); } /** @@ -1135,17 +472,10 @@ * @return whether environment specific units should be included */ public boolean getIncludeAllEnvironments() { - return fIncludeMultipleEnvironments; - } - - /** - * Set whether or not the source bundles corresponding to any binary bundles should - * be automatically included in the target. - * - * @param value whether or not to include source - */ - public void setIncludeSource(boolean value) { - fIncludeSource = value; + // if this container has not been associated with a container, return its own value + if (fSynchronizer == null) + return (fFlags & INCLUDE_ALL_ENVIRONMENTS) == INCLUDE_ALL_ENVIRONMENTS; + return fSynchronizer.getIncludeAllEnvironments(); } /** @@ -1155,30 +485,22 @@ * @return whether or not source is included automatically */ public boolean getIncludeSource() { - return fIncludeSource; + // if this container has not been associated with a container, return its own value + if (fSynchronizer == null) + return (fFlags & INCLUDE_SOURCE) == INCLUDE_SOURCE; + return fSynchronizer.getIncludeSource(); } /** - * Removes an installable unit from this container. The container will no longer be resolved. - * - * @param unit unit to remove from the list of root IUs + * Returns the installable units defined by this container + * + * @return the discovered IUs + * @exception CoreException if unable to retrieve IU's */ - public void removeInstallableUnit(IInstallableUnit unit) { - List newUnits = new ArrayList(fUnits.length); - for (int i = 0; i < fUnits.length; i++) { - if (!fUnits[i].equals(unit)) { - newUnits.add(fUnits[i]); - } - } - fUnits = (IInstallableUnit[]) newUnits.toArray(new IInstallableUnit[newUnits.size()]); - fIds = new String[fUnits.length]; - fVersions = new Version[fUnits.length]; - for (int i = 0; i < fUnits.length; i++) { - fIds[i] = fUnits[i].getId(); - fVersions[i] = fUnits[i].getVersion(); - } - // Need to mark the container as unresolved - clearResolutionStatus(); + public IInstallableUnit[] getInstallableUnits() throws CoreException { + if (fUnits == null) + return new IInstallableUnit[0]; + return fUnits; } /** @@ -1199,4 +521,36 @@ return fVersions; } + /** + * Return the synchronizer for this container. If there isn't one and a target definition is + * supplied, then get/create the one used by the target and the other containers. + */ + P2TargetUtils getSynchronizer(ITargetDefinition definition) { + if (fSynchronizer != null) { + return fSynchronizer; + } + if (definition == null) + return null; + return fSynchronizer = P2TargetUtils.getSynchronizer(definition); + } + + /** + * Callback method used by the synchronizer to associate containers with + * synchronizers. + */ + void setSynchronizer(P2TargetUtils value) { + fSynchronizer = value; + } + + /** + * Associate this container with the given target. The include settings for this container + * override the settings for all other IU containers in the target. Last one wins. + */ + protected void associateWithTarget(ITargetDefinition target) { + super.associateWithTarget(target); + fSynchronizer = getSynchronizer(target); + fSynchronizer.setIncludeAllRequired((fFlags & INCLUDE_REQUIRED) == INCLUDE_REQUIRED); + fSynchronizer.setIncludeAllEnvironments((fFlags & INCLUDE_ALL_ENVIRONMENTS) == INCLUDE_ALL_ENVIRONMENTS); + fSynchronizer.setIncludeSource((fFlags & INCLUDE_SOURCE) == INCLUDE_SOURCE); + } } Index: src/org/eclipse/pde/internal/core/target/Messages.java =================================================================== RCS file: /cvsroot/eclipse/pde/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/target/Messages.java,v retrieving revision 1.10 diff -u -r1.10 Messages.java --- src/org/eclipse/pde/internal/core/target/Messages.java 5 Nov 2010 15:56:16 -0000 1.10 +++ src/org/eclipse/pde/internal/core/target/Messages.java 30 Nov 2010 21:03:55 -0000 @@ -34,6 +34,7 @@ public static String IUBundleContainer_0; public static String IUBundleContainer_1; public static String IUBundleContainer_10; + public static String IUBundleContainer_11; public static String IUBundleContainer_2; public static String IUBundleContainer_3; public static String IUBundleContainer_4; Index: src/org/eclipse/pde/internal/core/target/Messages.properties =================================================================== RCS file: /cvsroot/eclipse/pde/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/target/Messages.properties,v retrieving revision 1.10 diff -u -r1.10 Messages.properties --- src/org/eclipse/pde/internal/core/target/Messages.properties 5 Nov 2010 15:56:16 -0000 1.10 +++ src/org/eclipse/pde/internal/core/target/Messages.properties 30 Nov 2010 21:03:55 -0000 @@ -25,14 +25,15 @@ FeatureBundleContainer_5=Plug-ins directory does not exist for feature {0} IUBundleContainer_0=Provisioning target IUBundleContainer_1=Unable to locate installable unit {0} -IUBundleContainer_10=Provisioning Agent service not found +IUBundleContainer_10=Provisioning Agent Location service not found +IUBundleContainer_11=Global Provisioning Agent service not found IUBundleContainer_2=Metadata repository service not found IUBundleContainer_3=Artifact respository service not found IUBundleContainer_4=Provisioning engine not found IUBundleContainer_5=Provisioning planner not found IUBundleContainer_6=Target provisioning skipped install plan IUBundleContainer_7=Provisioning agent not found -IUBundleContainer_8=Profile registry service not found +IUBundleContainer_8=Profile Registry service not found IUBundleContainer_9=Garbage Collector service not found IUBundleContainer_LoadingFromProfileJob=Loading target information from profile IUBundleContainer_NoBundlePool=No location for downloaded bundles could be found. Index: src/org/eclipse/pde/internal/core/target/P2TargetUtils.java =================================================================== RCS file: /cvsroot/eclipse/pde/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/target/P2TargetUtils.java,v retrieving revision 1.1 diff -u -r1.1 P2TargetUtils.java --- src/org/eclipse/pde/internal/core/target/P2TargetUtils.java 5 Nov 2010 15:56:16 -0000 1.1 +++ src/org/eclipse/pde/internal/core/target/P2TargetUtils.java 30 Nov 2010 21:03:55 -0000 @@ -12,27 +12,36 @@ import java.io.File; import java.net.URI; +import java.net.URISyntaxException; import java.util.*; import org.eclipse.core.runtime.*; import org.eclipse.core.runtime.preferences.IPreferencesService; +import org.eclipse.equinox.internal.p2.director.PermissiveSlicer; +import org.eclipse.equinox.internal.p2.engine.*; +import org.eclipse.equinox.internal.p2.engine.phases.*; import org.eclipse.equinox.internal.p2.garbagecollector.GarbageCollector; import org.eclipse.equinox.p2.core.*; import org.eclipse.equinox.p2.engine.*; import org.eclipse.equinox.p2.engine.query.IUProfilePropertyQuery; -import org.eclipse.equinox.p2.metadata.IInstallableUnit; +import org.eclipse.equinox.p2.engine.spi.ProvisioningAction; +import org.eclipse.equinox.p2.metadata.*; +import org.eclipse.equinox.p2.metadata.MetadataFactory.InstallableUnitDescription; import org.eclipse.equinox.p2.metadata.Version; import org.eclipse.equinox.p2.planner.IPlanner; -import org.eclipse.equinox.p2.query.IQueryResult; -import org.eclipse.equinox.p2.repository.artifact.IArtifactRepositoryManager; -import org.eclipse.equinox.p2.repository.artifact.IFileArtifactRepository; -import org.eclipse.equinox.p2.repository.metadata.IMetadataRepository; +import org.eclipse.equinox.p2.planner.IProfileChangeRequest; +import org.eclipse.equinox.p2.query.*; +import org.eclipse.equinox.p2.repository.*; +import org.eclipse.equinox.p2.repository.artifact.*; import org.eclipse.equinox.p2.repository.metadata.IMetadataRepositoryManager; +import org.eclipse.osgi.util.NLS; import org.eclipse.pde.internal.core.PDECore; import org.eclipse.pde.internal.core.target.provisional.*; import org.osgi.framework.*; public class P2TargetUtils { + private static final String SOURCE_IU_ID = "org.eclipse.pde.core.target.source.bundles"; //$NON-NLS-1$ + /** * URI to the local directory where the p2 agent keeps its information. */ @@ -81,6 +90,58 @@ static final String PROP_ALL_ENVIRONMENTS = PDECore.PLUGIN_ID + ".all_environments"; //$NON-NLS-1$ /** + * Profile property that keeps track of the target sequence number + */ + static final String PROP_SEQUENCE_NUMBER = PDECore.PLUGIN_ID + ".sequence"; //$NON-NLS-1$ + + /** + * Profile property that tracks whether or not source to be auto-included + */ + static final String PROP_AUTO_INCLUDE_SOURCE = PDECore.PLUGIN_ID + ".autoIncludeSource"; //$NON-NLS-1$ + + /** + * The profile to be synchronized + */ + private IProfile fProfile; + + /** + * The target to be synchronized. + */ + private ITargetDefinition fTarget; + + /** + * Whether this container must have all required IUs of the selected IUs available and included + * in the target to resolve successfully. If this option is true, the planner will be used to resolve + * otherwise the slicer is used. The planner can describe any missing requirements as errors. + *

+ * true by default + *

+ */ + private boolean fIncludeAllRequired = true; + + /** + * Whether this container should download and include environment (platform) specific units for all + * available platforms (vs only the current target definition's environment settings). Only supported + * by the slicer so {@link fIncludeAllRequired} must be turned off for this setting to be used. + *

+ * false by default + *

+ */ + private boolean fIncludeMultipleEnvironments = false; + + /** + * Whether this container should download and include source bundles for the selected units if the associated + * source is available in the repository. + *

+ * falseby default + */ + private boolean fIncludeSource = false; + + public P2TargetUtils(ITargetDefinition target) { + fTarget = target; + } + + /** * Deletes any profiles associated with target definitions that no longer exist * and returns a list of profile identifiers that were deleted. */ @@ -93,8 +154,8 @@ for (int i = 0; i < profiles.length; i++) { IProfile profile = profiles[i]; String id = profile.getProfileId(); - if (id.startsWith(P2TargetUtils.PROFILE_ID_PREFIX)) { - String memento = id.substring(P2TargetUtils.PROFILE_ID_PREFIX.length()); + if (id.startsWith(PROFILE_ID_PREFIX)) { + String memento = id.substring(PROFILE_ID_PREFIX.length()); ITargetHandle handle = tps.getTarget(memento); if (!handle.exists()) { deleteProfile(handle); @@ -154,7 +215,7 @@ try { IProfile[] profiles = getProfileRegistry().getProfiles(); for (int i = 0; i < profiles.length; i++) { - if (profiles[i].getProfileId().startsWith(P2TargetUtils.PROFILE_ID_PREFIX)) { + if (profiles[i].getProfileId().startsWith(PROFILE_ID_PREFIX)) { getGarbageCollector().runGC(profiles[i]); } } @@ -169,7 +230,7 @@ * * @return environment properties */ - private static String generateEnvironmentProperties(ITargetDefinition target) { + private String generateEnvironmentProperties(ITargetDefinition target) { // TODO: are there constants for these keys? StringBuffer env = new StringBuffer(); String ws = target.getWS(); @@ -200,7 +261,7 @@ * * @return NL profile property */ - private static String generateNLProperty(ITargetDefinition target) { + private String generateNLProperty(ITargetDefinition target) { String nl = target.getNL(); if (nl == null) { nl = Platform.getNL(); @@ -246,7 +307,7 @@ public static IProvisioningAgent getGlobalAgent() throws CoreException { IProvisioningAgent agent = (IProvisioningAgent) PDECore.getDefault().acquireService(IProvisioningAgent.SERVICE_NAME); if (agent == null) - throw new CoreException(new Status(IStatus.ERROR, PDECore.PLUGIN_ID, Messages.IUBundleContainer_10)); + throw new CoreException(new Status(IStatus.ERROR, PDECore.PLUGIN_ID, Messages.IUBundleContainer_11)); return agent; } @@ -278,22 +339,23 @@ } /** - * Returns the local bundle pool (repository) where bundles are stored for the - * given profile. + * Returns the local bundle pool (repository) where bundles are stored * - * @param profile profile bundles are stored * @return local file artifact repository * @throws CoreException */ - public static IFileArtifactRepository getBundlePool(IProfile profile) throws CoreException { - String path = profile.getProperty(IProfile.PROP_CACHE); - if (path == null) { - // We should always be setting the bundle pool, so if the bundle pool location is missing there isn't much we can do - throw new CoreException(new Status(IStatus.ERROR, PDECore.PLUGIN_ID, Messages.IUBundleContainer_NoBundlePool)); - } - URI uri = new File(path).toURI(); + public static IFileArtifactRepository getBundlePool() throws CoreException { + URI uri = BUNDLE_POOL.toFile().toURI(); IArtifactRepositoryManager manager = getArtifactRepositoryManager(); - return (IFileArtifactRepository) manager.loadRepository(uri, null); + try { + if (manager.contains(uri)) + return (IFileArtifactRepository) manager.loadRepository(uri, null); + } catch (CoreException e) { + // could not load or there wasn't one, fall through to create + } + String repoName = "PDE Target Bundle Pool"; //$NON-NLS-1$ + IArtifactRepository result = manager.createRepository(uri, repoName, IArtifactRepositoryManager.TYPE_SIMPLE_REPOSITORY, null); + return (IFileArtifactRepository) result; } /** @@ -331,7 +393,7 @@ * @throws CoreException if none */ public static IPlanner getPlanner() throws CoreException { - IPlanner planner = (IPlanner) P2TargetUtils.getAgent().getService(IPlanner.class.getName()); + IPlanner planner = (IPlanner) getAgent().getService(IPlanner.class.getName()); if (planner == null) { throw new CoreException(new Status(IStatus.ERROR, PDECore.PLUGIN_ID, Messages.IUBundleContainer_5)); } @@ -348,107 +410,328 @@ } /** - * Returns the profile for the this target handle, creating one if required. + * Returns whether the contents of the profile matches the expected contents of the target definition * - * @return profile + * @return whether or not the profile and target definitions match * @throws CoreException in unable to retrieve profile */ - public static IProfile getProfile(ITargetDefinition target) throws CoreException { - IProfileRegistry registry = getProfileRegistry(); - if (registry == null) { - throw new CoreException(new Status(IStatus.ERROR, PDECore.PLUGIN_ID, Messages.AbstractTargetHandle_0)); + private boolean checkProfile() throws CoreException { + // make sure we have a profile to validate + if (fProfile == null) { + return false; + } + + // check that the target and profiles are in sync. If they are then life is good. + // If they are not equal, there is still a chance that everything is ok. + String profileNumber = fProfile.getProperty(PROP_SEQUENCE_NUMBER); + if (Integer.toString(fTarget.currentSequenceNumber()).equals(profileNumber)) { + return true; + } + + // check if all environments setting is the same + boolean all = false; + String value = fProfile.getProperty(PROP_ALL_ENVIRONMENTS); + if (value != null) { + all = Boolean.valueOf(value).booleanValue(); + if (!Boolean.toString(getIncludeAllEnvironments()).equals(value)) { + return false; + } } - AbstractTargetHandle handle = ((AbstractTargetHandle) target.getHandle()); - String id = P2TargetUtils.getProfileId(handle); - IProfile profile = registry.getProfile(id); - if (profile != null) { - boolean recreate = false; - // check if all environments setting is the same - boolean all = false; - String value = profile.getProperty(P2TargetUtils.PROP_ALL_ENVIRONMENTS); - if (value != null) { - all = Boolean.valueOf(value).booleanValue(); - if (!Boolean.toString(isAllEnvironments(target)).equals(value)) { - recreate = true; - } - } - // ensure environment & NL settings are still the same (else we need a new profile) - String property = null; - if (!recreate && !all) { - property = generateEnvironmentProperties(target); - value = profile.getProperty(IProfile.PROP_ENVIRONMENTS); - if (!property.equals(value)) { - recreate = true; - } - } - // check provisioning mode: slice versus plan - String mode = getProvisionMode(target); - if (mode != null) { - value = profile.getProperty(P2TargetUtils.PROP_PROVISION_MODE); - if (!mode.equals(value)) { - recreate = true; + + // ensure environment & NL settings are still the same (else we need a new profile) + String property = null; + if (!all) { + property = generateEnvironmentProperties(fTarget); + value = fProfile.getProperty(IProfile.PROP_ENVIRONMENTS); + if (!property.equals(value)) { + return false; + } + } + property = generateNLProperty(fTarget); + value = fProfile.getProperty(IProfile.PROP_NL); + if (!property.equals(value)) { + return false; + } + + // check provisioning mode: slice versus plan + if (!getProvisionMode(fTarget).equals(fProfile.getProperty(PROP_PROVISION_MODE))) { + return false; + } + + // check that the include source flag matches what the profile represents + if (getIncludeSource() != Boolean.valueOf(fProfile.getProperty(PROP_AUTO_INCLUDE_SOURCE)).booleanValue()) { + return false; + } + + // check top level IU's. If any have been removed from the containers that are + // still in the profile, we need to recreate (rather than uninstall) + IUProfilePropertyQuery propertyQuery = new IUProfilePropertyQuery(PROP_INSTALLED_IU, Boolean.toString(true)); + IQueryResult queryResult = fProfile.query(propertyQuery, null); + Iterator iterator = queryResult.iterator(); + Set installedIUs = new HashSet(); + while (iterator.hasNext()) { + IInstallableUnit unit = (IInstallableUnit) iterator.next(); + installedIUs.add(new NameVersionDescriptor(unit.getId(), unit.getVersion().toString())); + } + IBundleContainer[] containers = fTarget.getBundleContainers(); + if (containers == null) { + return installedIUs.isEmpty(); + } + for (int i = 0; i < containers.length; i++) { + if (containers[i] instanceof IUBundleContainer) { + IUBundleContainer bc = (IUBundleContainer) containers[i]; + String[] ids = bc.getIds(); + Version[] versions = bc.getVersions(); + for (int j = 0; j < versions.length; j++) { + // if there is something in a container but not in the profile, recreate + if (!installedIUs.remove(new NameVersionDescriptor(ids[j], versions[j].toString()))) { + return false; + } } } + } + if (!installedIUs.isEmpty()) { + return false; + } - if (!recreate) { - property = generateNLProperty(target); - value = profile.getProperty(IProfile.PROP_NL); - if (!property.equals(value)) { - recreate = true; - } - } - if (!recreate) { - // check top level IU's. If any have been removed from the containers that are - // still in the profile, we need to recreate (rather than uninstall) - IUProfilePropertyQuery propertyQuery = new IUProfilePropertyQuery(P2TargetUtils.PROP_INSTALLED_IU, Boolean.toString(true)); - IQueryResult queryResult = profile.query(propertyQuery, null); - Iterator iterator = queryResult.iterator(); - if (iterator.hasNext()) { - Set installedIUs = new HashSet(); - while (iterator.hasNext()) { - IInstallableUnit unit = (IInstallableUnit) iterator.next(); - installedIUs.add(new NameVersionDescriptor(unit.getId(), unit.getVersion().toString())); - } - IBundleContainer[] containers = target.getBundleContainers(); - if (containers != null) { - for (int i = 0; i < containers.length; i++) { - if (containers[i] instanceof IUBundleContainer) { - IUBundleContainer bc = (IUBundleContainer) containers[i]; - String[] ids = bc.getIds(); - Version[] versions = bc.getVersions(); - for (int j = 0; j < versions.length; j++) { - installedIUs.remove(new NameVersionDescriptor(ids[j], versions[j].toString())); - } - } - } - } - if (!installedIUs.isEmpty()) { - recreate = true; - } + // Phew! seems like the profile checks out. + return true; + } + + /** + * Sets whether all required units must be available to resolve this container. When true + * the resolve operation will use the planner to determine the complete set of IUs required to + * make the selected IUs runnable. If any dependencies are missing, the resolve operation will return an + * error explaining what problems exist. When false the resolve operation will use the slicer + * to determine what units to include. Any required units that are not available in the repositories will + * be ignored. + *

+ * Since there is only one profile per target and the planner and slicer resolve methods are incompatible. + *

+ * @param value whether all required units must be available to resolve this container + */ + public void setIncludeAllRequired(boolean value) { + fIncludeAllRequired = value; + } + + /** + * Returns whether all required units must be available to resolve this container. When true + * the resolve operation will use the planner to determine the complete set of IUs required to + * make the selected IUs runnable. If any dependencies are missing, the resolve operation will return an + * error explaining what problems exist. When false the resolve operation will use the slicer + * to determine what units to include. Any required units that are not available in the repositories will + * be ignored. + * + * @return whether all required units must be available to resolve this container + */ + public boolean getIncludeAllRequired() { + return fIncludeAllRequired; + } + + /** + * Sets whether all environment (platform) specific installable units should + * be included in this container when it is resolved. This feature is not supported + * by the planner so will only have an effect if the include all required setting + * is turned off ({@link #getIncludeAllRequired()}). + *

+ * There is only one profile per target and this setting can only be set for the + * entire target definition. + *

+ * @param value whether environment specific units should be included + */ + public void setIncludeAllEnvironments(boolean value) { + fIncludeMultipleEnvironments = value; + } + + /** + * Returns whether all environment (platform) specific installable units should + * be included in this container when it is resolved. This feature is not supported + * by the planner so will only have an effect if the include all required setting + * is turned off ({@link #getIncludeAllRequired()}). + * + * @return whether environment specific units should be included + */ + public boolean getIncludeAllEnvironments() { + return fIncludeMultipleEnvironments; + } + + /** + * Set whether or not the source bundles corresponding to any binary bundles should + * be automatically included in the target. + * + * @param value whether or not to include source + */ + public void setIncludeSource(boolean value) { + fIncludeSource = value; + } + + /** + * Returns whether or not source bundles corresponding to selected binary bundles + * are automatically included in the target. + * + * @return whether or not source is included automatically + */ + public boolean getIncludeSource() { + return fIncludeSource; + } + + /** + * Return whether or not the given target has a matching profile that is in sync + * @param target the target to check + * @return whether or not the target has been resolved at the p2 level + */ + public static boolean isResolved(ITargetDefinition target) { + P2TargetUtils synchronizer = getSynchronizer(target); + if (synchronizer == null) + return false; + try { + return synchronizer.checkProfile(); + } catch (CoreException e) { + return false; + } + } + + /** + * Get the synchronizer to use for the given target. If there is already one on a + * container in the target, use that one. Otherwise, create a new one. Either way, + * ensure that all other IU containers in the target are using the same synchronizer. + *

+ * The synchronizer is an instance of {@link P2TargetUtils} that has access to the + * profile and other p2 bits for the target. + *

+ * + * @param target the target for which we are getting the synchronizer + * @return the discovered or created synchronizer + */ + static synchronized P2TargetUtils getSynchronizer(ITargetDefinition target) { + IBundleContainer[] containers = target.getBundleContainers(); + P2TargetUtils result = null; + // if there are no containers then just create/return the synchronizer + if (containers == null) { + return new P2TargetUtils(target); + } + + // Otherwise, look for a pre-existing synchronizer + for (int i = 0; i < containers.length; i++) { + if (containers[i] instanceof IUBundleContainer) { + result = ((IUBundleContainer) containers[i]).getSynchronizer(null); + if (result != null) { + break; } } - if (recreate) { - P2TargetUtils.deleteProfile(handle); - profile = null; - } - } - if (profile == null) { - // create profile - Map properties = new HashMap(); - properties.put(IProfile.PROP_INSTALL_FOLDER, P2TargetUtils.INSTALL_FOLDERS.append(Long.toString(LocalTargetHandle.nextTimeStamp())).toOSString()); - properties.put(IProfile.PROP_CACHE, P2TargetUtils.BUNDLE_POOL.toOSString()); - properties.put(IProfile.PROP_INSTALL_FEATURES, Boolean.TRUE.toString()); - // set up environment & NL properly so OS specific fragments are down loaded/installed - properties.put(IProfile.PROP_ENVIRONMENTS, generateEnvironmentProperties(target)); - properties.put(IProfile.PROP_NL, generateNLProperty(target)); - String mode = getProvisionMode(target); - if (mode != null) { - properties.put(P2TargetUtils.PROP_PROVISION_MODE, mode); - properties.put(P2TargetUtils.PROP_ALL_ENVIRONMENTS, Boolean.toString(isAllEnvironments(target))); + } + + // still no luck? create a new one + if (result == null) { + result = new P2TargetUtils(target); + } + + // finally set all the other IU containers to use the same synchronizer + for (int i = 0; i < containers.length; i++) { + if (containers[i] instanceof IUBundleContainer) { + ((IUBundleContainer) containers[i]).setSynchronizer(result); + } + } + return result; + } + + /** + * Return the set of IUs in all IU containers associated with this synchronizer. + * This is a helper method so we don't have to expose the profile itself. + * + * @param target the target definition to query + * @param monitor the progress monitor to use + * @return the set of associated IUs + * @throws CoreException if there is a problem discovering the IUs + */ + public static IQueryResult getIUs(ITargetDefinition target, IProgressMonitor monitor) throws CoreException { + P2TargetUtils synchronizer = getSynchronizer(target); + if (synchronizer == null) + return null; + synchronizer.synchronize(monitor); + return synchronizer.getProfile().query(QueryUtil.createIUAnyQuery(), null); + } + + /** + * Synchronize the profile and the target definition managed by this synchronizer. On return the profile will + * be resolved and correctly match the given target. The IUBundleContainers associated with + * the target will be notified of any changes in the underlying p2 profile and given an + * opportunity to update themselves accordingly. + * + * NOTE: this is a potentially *very* heavyweight operation. + * + * NOTE: this method is synchronized as it is effectively a "test and set" caching method. Two + * threads getting the profile at the same time should not execute concurrently or the profiles + * will get out of sync. + * + * @throws CoreException if there was a problem synchronizing + */ + public synchronized void synchronize(IProgressMonitor monitor) throws CoreException { + // Happiness if we have a profile and it checks out or if we can load one and it checks out. + if (fProfile == null) { + fProfile = getProfileRegistry().getProfile(getProfileId(fTarget)); + if (fProfile != null && checkProfile()) { + // if we just loaded the profile for the first time, refresh the container caches + notify(monitor); + return; + } + } else if (checkProfile()) { + return; + } + + long timestamp = -1; + // If we could not find a profile, create one. + if (fProfile == null) + createProfile(); + else + timestamp = fProfile.getTimestamp(); + + // Now resolve the profile and refresh the relate IU containers + if (getIncludeAllRequired()) + resolveWithPlanner(monitor); + else + resolveWithSlicer(monitor); + + // If we are updating a profile then delete the old snapshot on success. + if (timestamp != -1) + getProfileRegistry().removeProfile(getProfileId(fTarget), timestamp); + notify(monitor); + } + + private void createProfile() throws CoreException, ProvisionException { + // create a new profile + IProfileRegistry registry = getProfileRegistry(); + if (registry == null) { + throw new CoreException(new Status(IStatus.ERROR, PDECore.PLUGIN_ID, Messages.AbstractTargetHandle_0)); + } + Map properties = new HashMap(); + properties.put(IProfile.PROP_INSTALL_FOLDER, INSTALL_FOLDERS.append(Long.toString(LocalTargetHandle.nextTimeStamp())).toOSString()); + properties.put(IProfile.PROP_CACHE, BUNDLE_POOL.toOSString()); + properties.put(IProfile.PROP_INSTALL_FEATURES, Boolean.TRUE.toString()); + properties.put(IProfile.PROP_ENVIRONMENTS, generateEnvironmentProperties(fTarget)); + properties.put(IProfile.PROP_NL, generateNLProperty(fTarget)); + properties.put(PROP_SEQUENCE_NUMBER, Integer.toString(fTarget.currentSequenceNumber())); + properties.put(PROP_PROVISION_MODE, getProvisionMode(fTarget)); + properties.put(PROP_ALL_ENVIRONMENTS, Boolean.toString(getIncludeAllEnvironments())); + properties.put(PROP_AUTO_INCLUDE_SOURCE, Boolean.toString(getIncludeSource())); + fProfile = registry.addProfile(getProfileId(fTarget), properties); + } + + /** + * Signal the relevant bundle containers that the given profile has changed. + */ + private void notify(IProgressMonitor monitor) throws CoreException { + // flush the target caches first since some of them are used in rebuilding + // the container caches (e.g., featureModels) + ((TargetDefinition) fTarget).flushCaches(P2TargetUtils.BUNDLE_POOL.toOSString()); + // Now proactively recompute all the related container caches. + IBundleContainer[] containers = fTarget.getBundleContainers(); + for (int i = 0; i < containers.length; i++) { + IBundleContainer container = containers[i]; + if (container instanceof IUBundleContainer) { + ((IUBundleContainer) container).synchronizerChanged(); } - profile = registry.addProfile(id, properties); } - return profile; } /** @@ -466,6 +749,22 @@ } /** + * Returns the profile identifier for this target handle. There is one profile + * per target definition. + * + * @return definition the target to lookup + * @throws CoreException in unable to generate identifier + */ + public static String getProfileId(ITargetDefinition definition) { + try { + return getProfileId(definition.getHandle()); + } catch (CoreException e) { + // gotta make sure that this never happens. all we're doing here is computing a string. + return null; + } + } + + /** * Returns the profile registry or null * * @return profile registry or null @@ -485,20 +784,8 @@ * * @return provisioning mode or null */ - private static String getProvisionMode(ITargetDefinition target) { - IBundleContainer[] containers = target.getBundleContainers(); - if (containers != null) { - for (int i = 0; i < containers.length; i++) { - if (containers[i] instanceof IUBundleContainer) { - IUBundleContainer iu = (IUBundleContainer) containers[i]; - if (iu.getIncludeAllRequired()) { - return TargetDefinitionPersistenceHelper.MODE_PLANNER; - } - return TargetDefinitionPersistenceHelper.MODE_SLICER; - } - } - } - return null; + private String getProvisionMode(ITargetDefinition target) { + return getIncludeAllRequired() ? TargetDefinitionPersistenceHelper.MODE_PLANNER : TargetDefinitionPersistenceHelper.MODE_SLICER; } /** @@ -516,37 +803,591 @@ } /** - * Returns the metadata repository with the given URI. + * Return a queryable on the metadata defined in the given repo locations * - * @param uri location - * @return repository - * @throws CoreException + * @param repos the repos to lookup + * @param monitor the progress monitor + * @return the set of metadata repositories found + * @throws CoreException if there is a problem getting the repositories */ - public static IMetadataRepository getRepository(URI uri) throws CoreException { + static IQueryable getQueryableMetadata(URI[] repos, IProgressMonitor monitor) throws CoreException { IMetadataRepositoryManager manager = getRepoManager(); - IMetadataRepository repo = manager.loadRepository(uri, null); - return repo; + if (repos == null) { + repos = manager.getKnownRepositories(IRepositoryManager.REPOSITORIES_ALL); + } + + IProgressMonitor loadMonitor = new SubProgressMonitor(monitor, 10); + int repoCount = repos.length; + loadMonitor.beginTask(null, repoCount * 10); + List result = new ArrayList(repoCount); + MultiStatus repoStatus = new MultiStatus(PDECore.PLUGIN_ID, 0, Messages.IUBundleContainer_ProblemsLoadingRepositories, null); + for (int i = 0; i < repoCount; ++i) { + try { + result.add(manager.loadRepository(repos[i], new SubProgressMonitor(loadMonitor, 10))); + } catch (ProvisionException e) { + repoStatus.add(e.getStatus()); + } + } + loadMonitor.done(); + + if (result.size() != repos.length) { + throw new CoreException(repoStatus); + } + if (result.size() == 1) { + return (IQueryable) result.get(0); + } + return QueryUtil.compoundQueryable(result); } /** - * Returns whether software site containers are configured to provision for all environments - * versus a single environment. + * Used to resolve the contents of this container if the user is including all required software. The p2 planner is used + * to determine the complete set of IUs required to run the selected software. If all requirements are met, the bundles + * are downloaded from the repository into the bundle pool and added to the target definition. * - * @return whether all environments will be provisioned + * @param monitor for reporting progress + * @throws CoreException if there is a problem with the requirements or there is a problem downloading */ - private static boolean isAllEnvironments(ITargetDefinition target) { + private void resolveWithPlanner(IProgressMonitor monitor) throws CoreException { + SubProgressMonitor subMonitor = new SubProgressMonitor(monitor, 10); + subMonitor.beginTask(Messages.IUBundleContainer_0, 200); + + // Get the root IUs for every relevant container in the target definition + IInstallableUnit[] units = getRootIUs(fTarget); + if (subMonitor.isCanceled()) { + return; + } + + // create the provisioning plan + IPlanner planner = getPlanner(); + IProfileChangeRequest request = planner.createChangeRequest(fProfile); + // first remove everything that was explicitly installed. Then add it back. This has the net effect of + // removing everything that is no longer needed. + computeRemovals(fProfile, request, getIncludeSource()); + request.addAll(Arrays.asList(units)); + for (int i = 0; i < units.length; i++) { + IInstallableUnit unit = units[i]; + request.setInstallableUnitProfileProperty(unit, PROP_INSTALLED_IU, Boolean.toString(true)); + } + + ProvisioningContext context = new ProvisioningContext(getAgent()); + context.setMetadataRepositories(getMetadataRepositories(fTarget)); + context.setArtifactRepositories(getArtifactRepositories(fTarget)); + + if (subMonitor.isCanceled()) { + return; + } + + IProvisioningPlan plan = planner.getProvisioningPlan(request, context, new SubProgressMonitor(subMonitor, 20)); + IStatus status = plan.getStatus(); + if (!status.isOK()) { + throw new CoreException(status); + } + setPlanProperties(plan, fTarget, TargetDefinitionPersistenceHelper.MODE_PLANNER); + IProvisioningPlan installerPlan = plan.getInstallerPlan(); + if (installerPlan != null) { + // this plan requires an update to the installer first, log the fact and attempt + // to continue, we don't want to update the running SDK while provisioning a target + PDECore.log(new Status(IStatus.INFO, PDECore.PLUGIN_ID, Messages.IUBundleContainer_6)); + } + subMonitor.worked(10); + if (subMonitor.isCanceled()) { + return; + } + + // execute the provisioning plan + IPhaseSet phases = createPhaseSet(); + IEngine engine = getEngine(); + IStatus result = engine.perform(plan, phases, new SubProgressMonitor(subMonitor, 140)); + if (subMonitor.isCanceled()) { + return; + } + if (!result.isOK()) { + throw new CoreException(result); + } + + // Now that we have a plan with all the binary and explicit bundles, do a second pass and add + // in all the source. + try { + planInSourceBundles(fProfile, context, subMonitor); + } catch (CoreException e) { + // XXX Review required: is adding in the source critical or optional? + // We failed adding in the source so remove the intermediate profile and rethrow + getProfileRegistry().removeProfile(fProfile.getProfileId(), fProfile.getTimestamp()); + throw e; + } + subMonitor.worked(10); + subMonitor.done(); + } + + private void setPlanProperties(IProvisioningPlan plan, ITargetDefinition definition, String mode) { + plan.setProfileProperty(PROP_PROVISION_MODE, mode); + plan.setProfileProperty(PROP_ALL_ENVIRONMENTS, Boolean.toString(getIncludeSource())); + plan.setProfileProperty(PROP_AUTO_INCLUDE_SOURCE, Boolean.toString(getIncludeSource())); + plan.setProfileProperty(PROP_SEQUENCE_NUMBER, Integer.toString(definition.currentSequenceNumber())); + } + + private IPhaseSet createPhaseSet() { + ArrayList phases = new ArrayList(4); + phases.add(new Collect(100)); + phases.add(new Property(1)); + phases.add(new Uninstall(50, true)); + phases.add(new Install(50)); + phases.add(new CollectNativesPhase(100)); + return new PhaseSet((Phase[]) phases.toArray(new Phase[phases.size()])); + } + + /** + * Update the given change request to remove anything that was explicitly installed + * including the internal source IU. + */ + private void computeRemovals(IProfile profile, IProfileChangeRequest request, boolean includeSource) { + // if include source is off then ensure that the source IU is removed. + if (!includeSource) { + IInstallableUnit sourceIU = getCurrentSourceIU(profile); + if (sourceIU != null) + request.remove(sourceIU); + } + // remove everything that is marked as roots. The plan will have the new roots added in anyway. + IQuery query = new IUProfilePropertyQuery(PROP_INSTALLED_IU, Boolean.toString(true)); + IQueryResult installedIUs = profile.query(query, null); + request.removeAll(installedIUs.toSet()); + } + + // run a second pass of the planner to add in the source bundles for everything that's + // in the current profile. + private void planInSourceBundles(IProfile fProfile, ProvisioningContext context, IProgressMonitor monitor) throws CoreException { + SubProgressMonitor subMonitor = new SubProgressMonitor(monitor, 10); + subMonitor.beginTask("Provisioning source bundles", 200); + + // create an IU that optionally and greedily requires the related source bundles. + // Completely replace any source IU that may already be in place + IInstallableUnit currentSourceIU = getCurrentSourceIU(fProfile); + + // determine the new version number. start at 1 + Version sourceVersion = Version.createOSGi(1, 0, 0); + if (currentSourceIU != null) { + Integer major = (Integer) currentSourceIU.getVersion().getSegment(0); + sourceVersion = Version.createOSGi(major.intValue() + 1, 0, 0); + } + IInstallableUnit sourceIU = createSourceIU(fProfile, sourceVersion); + + // call the planner again to add in the new source IU and all available source bundles + IPlanner planner = getPlanner(); + IProfileChangeRequest request = planner.createChangeRequest(fProfile); + if (currentSourceIU != null) + request.remove(currentSourceIU); + request.add(sourceIU); + IProvisioningPlan plan = planner.getProvisioningPlan(request, context, new SubProgressMonitor(subMonitor, 20)); + IStatus status = plan.getStatus(); + if (!status.isOK()) { + throw new CoreException(status); + } + if (subMonitor.isCanceled()) { + return; + } + + // execute the provisioning plan + long oldTimestamp = fProfile.getTimestamp(); + IPhaseSet phases = PhaseSetFactory.createDefaultPhaseSetExcluding(new String[] {PhaseSetFactory.PHASE_CHECK_TRUST, PhaseSetFactory.PHASE_CONFIGURE, PhaseSetFactory.PHASE_UNCONFIGURE, PhaseSetFactory.PHASE_UNINSTALL}); + IEngine engine = getEngine(); + plan.setProfileProperty(PROP_PROVISION_MODE, TargetDefinitionPersistenceHelper.MODE_PLANNER); + plan.setProfileProperty(PROP_ALL_ENVIRONMENTS, Boolean.toString(false)); + IStatus result = engine.perform(plan, phases, new SubProgressMonitor(subMonitor, 140)); + + if (subMonitor.isCanceled()) { + return; + } + if (!result.isOK()) { + throw new CoreException(result); + } + + // remove the old (intermediate) profile version now we have a new one with source. + getProfileRegistry().removeProfile(fProfile.getProfileId(), oldTimestamp); + subMonitor.worked(10); + subMonitor.done(); + } + + // Create and return an IU that has optional and greedy requirements on all source bundles + // related to bundle IUs in the given queryable. + private IInstallableUnit createSourceIU(IQueryable queryable, Version iuVersion) { + // compute the set of source bundles we could possibly need for the bundles in the profile + IRequirement bundleRequirement = MetadataFactory.createRequirement("org.eclipse.equinox.p2.eclipse.type", "bundle", null, null, false, false, false); //$NON-NLS-1$ //$NON-NLS-2$ + IQueryResult profileIUs = queryable.query(QueryUtil.createIUAnyQuery(), null); + ArrayList requirements = new ArrayList(); + for (Iterator i = profileIUs.iterator(); i.hasNext();) { + IInstallableUnit profileIU = (IInstallableUnit) i.next(); + if (profileIU.satisfies(bundleRequirement)) { + String id = profileIU.getId() + ".source"; //$NON-NLS-1$ + Version version = profileIU.getVersion(); + VersionRange range = new VersionRange(version, true, version, true); + IRequirement sourceRequirement = MetadataFactory.createRequirement("osgi.bundle", id, range, null, true, false, true); //$NON-NLS-1$ + requirements.add(sourceRequirement); + } + } + + InstallableUnitDescription sourceDescription = new MetadataFactory.InstallableUnitDescription(); + sourceDescription.setSingleton(true); + sourceDescription.setId(SOURCE_IU_ID); + sourceDescription.setVersion(iuVersion); + sourceDescription.addRequirements(requirements); + IProvidedCapability capability = MetadataFactory.createProvidedCapability(IInstallableUnit.NAMESPACE_IU_ID, SOURCE_IU_ID, iuVersion); + sourceDescription.setCapabilities(new IProvidedCapability[] {capability}); + return MetadataFactory.createInstallableUnit(sourceDescription); + } + + // Lookup and return (if any) the source IU in the given queryable. + private IInstallableUnit getCurrentSourceIU(IQueryable queryable) { + IQuery query = QueryUtil.createIUQuery(SOURCE_IU_ID); + IQueryResult list = queryable.query(query, null); + IInstallableUnit currentSourceIU = null; + if (!list.isEmpty()) + currentSourceIU = (IInstallableUnit) list.iterator().next(); + return currentSourceIU; + } + + /** + * Used to resolve the contents of this container when the user has chosen to manage the dependencies in the target + * themselves. The selected IUs and any required software that can be found will be retrieved from the repositories + * and added to the target. Any missing required software will be ignored. + * + * @param monitor for reporting progress + * @throws CoreException if there is a problem interacting with the repositories + */ + private void resolveWithSlicer(IProgressMonitor monitor) throws CoreException { + SubProgressMonitor subMonitor = new SubProgressMonitor(monitor, 10); + subMonitor.beginTask(Messages.IUBundleContainer_0, 180); + + // resolve IUs + IInstallableUnit[] units = getRootIUs(fTarget); + if (subMonitor.isCanceled()) { + return; + } + + URI[] repositories = getMetadataRepositories(fTarget); + int repoCount = repositories.length; + if (repoCount == 0) { + return; + } + IQueryable allMetadata = getQueryableMetadata(repositories, subMonitor); + + // do an initial slice to add everything the user requested + IQueryResult queryResult = slice(units, allMetadata, fTarget, subMonitor); + if (subMonitor.isCanceled() || queryResult == null || queryResult.isEmpty()) { + return; + } + + // If we are including source then create a source IU to bring in the relevant source + // bundles and run the slicer again. + if (getIncludeSource()) { + // Build an IU that represents all the source bundles and slice again to add them in if available + IInstallableUnit sourceIU = createSourceIU(queryResult, Version.createOSGi(1, 0, 0)); + IInstallableUnit[] units2 = new IInstallableUnit[units.length + 1]; + System.arraycopy(units, 0, units2, 0, units.length); + units2[units.length] = sourceIU; + + queryResult = slice(units2, allMetadata, fTarget, subMonitor); + if (subMonitor.isCanceled() || queryResult == null || queryResult.isEmpty()) { + return; + } + } + + IEngine engine = getEngine(); + ProvisioningContext context = new ProvisioningContext(getAgent()); + context.setMetadataRepositories(repositories); + context.setArtifactRepositories(getArtifactRepositories(fTarget)); + IProvisioningPlan plan = engine.createPlan(fProfile, context); + setPlanProperties(plan, fTarget, TargetDefinitionPersistenceHelper.MODE_SLICER); + + Set newSet = queryResult.toSet(); + Iterator itor = newSet.iterator(); + while (itor.hasNext()) { + plan.addInstallableUnit((IInstallableUnit) itor.next()); + } + for (int i = 0; i < units.length; i++) { + IInstallableUnit unit = units[i]; + plan.setInstallableUnitProfileProperty(unit, PROP_INSTALLED_IU, Boolean.toString(true)); + } + + // remove all units that are in the current profile but not in the new slice + Set toRemove = fProfile.query(QueryUtil.ALL_UNITS, null).toSet(); + toRemove.removeAll(newSet); + for (Iterator i = toRemove.iterator(); i.hasNext();) { + plan.removeInstallableUnit((IInstallableUnit) i.next()); + } + + // execute the provisioning plan + IPhaseSet phases = createPhaseSet(); + IStatus result = engine.perform(plan, phases, new SubProgressMonitor(subMonitor, 140)); + if (!result.isOK()) { + throw new CoreException(result); + } + + subMonitor.worked(10); + subMonitor.done(); + } + + private IQueryResult slice(IInstallableUnit[] units, IQueryable allMetadata, ITargetDefinition definition, SubProgressMonitor subMonitor) throws CoreException { + // slice IUs and all prerequisites + PermissiveSlicer slicer = null; + if (getIncludeAllEnvironments()) { + slicer = new PermissiveSlicer(allMetadata, new HashMap(), true, false, true, true, false); + } else { + Map props = new HashMap(); + props.put("osgi.os", definition.getOS() != null ? definition.getOS() : Platform.getOS()); //$NON-NLS-1$ + props.put("osgi.ws", definition.getWS() != null ? definition.getWS() : Platform.getWS()); //$NON-NLS-1$ + props.put("osgi.arch", definition.getArch() != null ? definition.getArch() : Platform.getOSArch()); //$NON-NLS-1$ + props.put("osgi.nl", definition.getNL() != null ? definition.getNL() : Platform.getNL()); //$NON-NLS-1$ + props.put(IProfile.PROP_INSTALL_FEATURES, Boolean.TRUE.toString()); + slicer = new PermissiveSlicer(allMetadata, props, true, false, false, true, false); + } + IQueryable slice = slicer.slice(units, new SubProgressMonitor(subMonitor, 10)); + if (!slicer.getStatus().isOK()) { + throw new CoreException(slicer.getStatus()); + } + IQueryResult queryResult = null; + if (slice != null) + queryResult = slice.query(QueryUtil.createIUAnyQuery(), new SubProgressMonitor(subMonitor, 10)); + return queryResult; + } + + /** + * Returns the artifact repositories to consider when getting artifacts. Returns a default set of + * repositories if current repository settings are null). + * + * @return URI's of repositories to use when getting artifacts + * @exception CoreException + */ + private URI[] getArtifactRepositories(ITargetDefinition target) throws CoreException { + Set result = new HashSet(); IBundleContainer[] containers = target.getBundleContainers(); - if (containers != null) { - for (int i = 0; i < containers.length; i++) { - if (containers[i] instanceof IUBundleContainer) { - IUBundleContainer iu = (IUBundleContainer) containers[i]; - if (iu.getIncludeAllEnvironments()) { - return true; - } + IArtifactRepositoryManager manager = getArtifactRepositoryManager(); + for (int i = 0; i < containers.length; i++) { + IBundleContainer container = containers[i]; + if (container instanceof IUBundleContainer) { + URI[] repos = ((IUBundleContainer) container).getRepositories(); + if (repos == null) { + repos = manager.getKnownRepositories(IRepositoryManager.REPOSITORIES_ALL); + } + result.addAll(Arrays.asList(repos)); + } + } + if (useAdditionalLocalArtifacts()) { + // get all the artifact repos we know in the manager currently + result.addAll(Arrays.asList(manager.getKnownRepositories(IRepositoryManager.REPOSITORIES_ALL))); + + // Add in the IDE profile bundle pool and all known workspaces + findProfileRepos(result); + findWorkspaceRepos(result); + } + return (URI[]) result.toArray(new URI[result.size()]); + } + + /** + * return whether or not to use local artifact repositories when provisioning the target + */ + private boolean useAdditionalLocalArtifacts() { + // XXX consider using a preference here or another strategy if users are able to spec + // what local repos are to be considered. + return true; + } + + /** + * Add the artifact repos from the PDE target bundle pools from all known repos. For example, the list + * of "recent workspaces" maintained by the IDE is a good source. + * + * @param additionalRepos the set to which additional repos are added. + */ + private void findWorkspaceRepos(Set additionalRepos) { + IPreferencesService prefs = getPreferences(); + if (prefs == null) + return; + String recent = prefs.getString("org.eclipse.ui.ide", "RECENT_WORKSPACES", null, null); //$NON-NLS-1$ //$NON-NLS-2$ + if (recent == null) + return; + String[] recents = recent.split("\n"); //$NON-NLS-1$ + for (int i = 0; i < recents.length; i++) { + String bundlePool = recents[i] + "/.metadata/.plugins/org.eclipse.pde.core/.bundle_pool"; //$NON-NLS-1$ + if (new File(bundlePool).exists()) { + URI uri; + try { + uri = new URI("file", bundlePool, null); //$NON-NLS-1$ + additionalRepos.add(uri); + } catch (URISyntaxException e) { + // should never happen + } + } + } + } + + /** + * Look through the current p2 profile (_SELF_) and add the artifact repos that make up its + * bundle pool, dropins location, ... This helps in the cases that you are targeting stuff that + * makes up your current IDE. + * + * @param additionalRepos the set to which additional repos are added. + */ + private void findProfileRepos(Set additionalRepos) { + try { + // NOTE: be sure to use the global p2 agent here as we are looking for SELF. + IProfileRegistry profileRegistry = (IProfileRegistry) getGlobalAgent().getService(IProfileRegistry.SERVICE_NAME); + if (profileRegistry == null) + return; + IProfile self = profileRegistry.getProfile(IProfileRegistry.SELF); + if (self == null) + return; + + IAgentLocation location = (IAgentLocation) getGlobalAgent().getService(IAgentLocation.SERVICE_NAME); + URI dataArea = location.getDataArea("org.eclipse.equinox.p2.engine"); //$NON-NLS-1$ + dataArea = URIUtil.append(dataArea, "profileRegistry/" + self.getProfileId() + ".profile"); //$NON-NLS-1$//$NON-NLS-2$ + ProfileMetadataRepository profileRepo = new ProfileMetadataRepository(getGlobalAgent(), dataArea, null); + Collection repos = profileRepo.getReferences(); + for (Iterator i = repos.iterator(); i.hasNext();) { + Object element = i.next(); + if (element instanceof IRepositoryReference) { + IRepositoryReference reference = (IRepositoryReference) element; + if (reference.getType() == IRepository.TYPE_ARTIFACT && reference.getLocation() != null) + additionalRepos.add(reference.getLocation()); + } + } + } catch (CoreException e) { + // if there is a problem, move on. Could log something here + return; + } + } + + /** + * Returns the IU's for the given target related to the given containers + * + * @param containers the bundle containers to filter with + * @return the discovered IUs + * @exception CoreException if unable to retrieve IU's + */ + private IInstallableUnit[] getRootIUs(ITargetDefinition definition) throws CoreException { + HashSet result = new HashSet(); + IBundleContainer[] containers = definition.getBundleContainers(); + for (int i = 0; i < containers.length; i++) { + IBundleContainer container = containers[i]; + if (container instanceof IUBundleContainer) { + IUBundleContainer iuContainer = (IUBundleContainer) container; + IQueryable repos = getQueryableMetadata(iuContainer.getRepositories(), new NullProgressMonitor()); + String[] ids = iuContainer.getIds(); + Version[] versions = iuContainer.getVersions(); + for (int j = 0; j < ids.length; j++) { + IQuery query = QueryUtil.createIUQuery(ids[j], versions[j]); + IQueryResult queryResult = repos.query(query, null); + if (queryResult.isEmpty()) + throw new CoreException(new Status(IStatus.ERROR, PDECore.PLUGIN_ID, NLS.bind(Messages.IUBundleContainer_1, ids[j]))); + result.add(queryResult.iterator().next()); } } } - return false; + return (IInstallableUnit[]) result.toArray(new IInstallableUnit[result.size()]); + } + + /** + * Returns the repositories to consider when resolving IU's (will return default set of + * repositories if current repository settings are null). + * + * @return URI's of repositories to use when resolving bundles + * @exception CoreException + */ + private URI[] getMetadataRepositories(ITargetDefinition target) throws CoreException { + Set result = new HashSet(); + IBundleContainer[] containers = target.getBundleContainers(); + IMetadataRepositoryManager manager = getRepoManager(); + for (int i = 0; i < containers.length; i++) { + IBundleContainer container = containers[i]; + if (container instanceof IUBundleContainer) { + URI[] repos = ((IUBundleContainer) container).getRepositories(); + if (repos == null) { + repos = manager.getKnownRepositories(IRepositoryManager.REPOSITORIES_ALL); + } + result.addAll(Arrays.asList(repos)); + } + } + return (URI[]) result.toArray(new URI[result.size()]); + } + + private static final String NATIVE_ARTIFACTS = "nativeArtifacts"; //$NON-NLS-1$ + private static final String NATIVE_TYPE = "org.eclipse.equinox.p2.native"; //$NON-NLS-1$ + private static final String PARM_OPERAND = "operand"; //$NON-NLS-1$ + + protected static class CollectNativesAction extends ProvisioningAction { + public IStatus execute(Map parameters) { + InstallableUnitOperand operand = (InstallableUnitOperand) parameters.get(PARM_OPERAND); + IInstallableUnit installableUnit = operand.second(); + if (installableUnit == null) + return Status.OK_STATUS; + + IArtifactRepositoryManager manager; + try { + Collection toDownload = installableUnit.getArtifacts(); + if (toDownload == null) + return Status.OK_STATUS; + + List artifactRequests = (List) parameters.get(NATIVE_ARTIFACTS); + IArtifactRepository destinationArtifactRepository = getBundlePool(); + manager = getArtifactRepositoryManager(); + for (Iterator i = toDownload.iterator(); i.hasNext();) { + IArtifactKey keyToDownload = (IArtifactKey) i.next(); + IArtifactRequest request = manager.createMirrorRequest(keyToDownload, destinationArtifactRepository, null, null); + artifactRequests.add(request); + } + } catch (CoreException e) { + return e.getStatus(); + } + return Status.OK_STATUS; + } + + public IStatus undo(Map parameters) { + // nothing to do for now + return Status.OK_STATUS; + } + } + + protected static class CollectNativesPhase extends InstallableUnitPhase { + public CollectNativesPhase(int weight) { + super(NATIVE_ARTIFACTS, weight); + } + + protected List getActions(InstallableUnitOperand operand) { + IInstallableUnit unit = operand.second(); + if (unit != null && unit.getTouchpointType().getId().equals(NATIVE_TYPE)) { + return Collections.singletonList(new CollectNativesAction()); + } + return null; + } + + protected IStatus initializePhase(IProgressMonitor monitor, IProfile profile, Map parameters) { + parameters.put(NATIVE_ARTIFACTS, new ArrayList()); + parameters.put(PARM_PROFILE, profile); + return null; + } + + protected IStatus completePhase(IProgressMonitor monitor, IProfile profile, Map parameters) { + List artifactRequests = (List) parameters.get(NATIVE_ARTIFACTS); + ProvisioningContext context = (ProvisioningContext) parameters.get(PARM_CONTEXT); + IProvisioningAgent agent = (IProvisioningAgent) parameters.get(PARM_AGENT); + DownloadManager dm = new DownloadManager(context, agent); + for (Iterator i = artifactRequests.iterator(); i.hasNext();) { + dm.add((IArtifactRequest) i.next()); + } + return dm.start(monitor); + } + } + + /** + * @return the profile associated with this synchronizer + */ + IProfile getProfile() { + return fProfile; + } + + /** + * @return the target definition associated with this synchronizer + */ + ITargetDefinition getTargetDefinition() { + return fTarget; } } Index: src/org/eclipse/pde/internal/core/target/TargetDefinition.java =================================================================== RCS file: /cvsroot/eclipse/pde/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/target/TargetDefinition.java,v retrieving revision 1.18 diff -u -r1.18 TargetDefinition.java --- src/org/eclipse/pde/internal/core/target/TargetDefinition.java 5 Nov 2010 15:56:16 -0000 1.18 +++ src/org/eclipse/pde/internal/core/target/TargetDefinition.java 30 Nov 2010 21:03:55 -0000 @@ -75,6 +75,8 @@ private IFeatureModel[] fFeatureModels; private IResolvedBundle[] fOtherBundles; + private int fSequenceNumber = -1; + /** * Constructs a target definition based on the given handle. */ @@ -142,6 +144,7 @@ * @see org.eclipse.pde.internal.core.target.provisional.ITargetDefinition#setArch(java.lang.String) */ public void setArch(String arch) { + incrementSequenceNumber(); fArch = arch; } @@ -149,6 +152,7 @@ * @see org.eclipse.pde.internal.core.target.provisional.ITargetDefinition#setNL(java.lang.String) */ public void setNL(String nl) { + incrementSequenceNumber(); fNL = nl; } @@ -163,6 +167,7 @@ * @see org.eclipse.pde.internal.core.target.provisional.ITargetDefinition#setOS(java.lang.String) */ public void setOS(String os) { + incrementSequenceNumber(); fOS = os; } @@ -190,6 +195,7 @@ * @see org.eclipse.pde.internal.core.target.provisional.ITargetDefinition#setWS(java.lang.String) */ public void setWS(String ws) { + incrementSequenceNumber(); fWS = ws; } @@ -197,6 +203,7 @@ * @see org.eclipse.pde.internal.core.target.provisional.ITargetDefinition#setBundleContainers(org.eclipse.pde.internal.core.target.provisional.IBundleContainer[]) */ public void setBundleContainers(IBundleContainer[] containers) { + incrementSequenceNumber(); // Clear the feature model cache as it is based on the bundle container locations fFeatureModels = null; fOtherBundles = null; @@ -210,6 +217,30 @@ if (containers == null) { fIncluded = null; fOptional = null; + } else { + for (int i = 0; i < containers.length; i++) { + ((AbstractBundleContainer) containers[i]).associateWithTarget(this); + } + } + } + + /** + * Clears the any models that are cached for the given container location. + * + * @param location location to clear cache for or null to clear all cached models + */ + public void flushCaches(String location) { + // Clear the feature model cache as it is based on the bundle container locations + fFeatureModels = null; + fOtherBundles = null; + if (location == null) { + fFeaturesInLocation.clear(); + } else { + fFeaturesInLocation.remove(location); + } + if (fContainers == null) { + fIncluded = null; + fOptional = null; } } @@ -623,6 +654,7 @@ fProgramArgs = null; fVMArgs = null; fWS = null; + fSequenceNumber = 0; TargetDefinitionPersistenceHelper.initFromXML(this, stream); } catch (ParserConfigurationException e) { abort(Messages.TargetDefinition_0, e); @@ -994,11 +1026,42 @@ return result; } + /** + * @return the current UI style one of {@link #MODE_FEATURE} or {@link #MODE_PLUGIN} + */ public int getUIMode() { return fUIMode; } + /** + * @param mode new UI style to use, one of {@link #MODE_FEATURE} or {@link #MODE_PLUGIN} + */ public void setUIMode(int mode) { fUIMode = mode; } + + /* (non-Javadoc) + * @see org.eclipse.pde.internal.core.target.provisional.ITargetDefinition#currentSequenceNumber() + */ + public int currentSequenceNumber() { + return fSequenceNumber; + } + + /** + * Increases the current sequence number. + * @see TargetDefinition#currentSequenceNumber() + * @return the current sequence number after it has been increased + */ + public int incrementSequenceNumber() { + return ++fSequenceNumber; + } + + /** + * Convenience method to set the sequence number to a specific + * value. Used when loading a target from a persisted file. + * @param value value to set the sequence number to + */ + void setSequenceNumber(int value) { + fSequenceNumber = value; + } } Index: src/org/eclipse/pde/internal/core/target/TargetDefinitionPersistenceHelper.java =================================================================== RCS file: /cvsroot/eclipse/pde/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/target/TargetDefinitionPersistenceHelper.java,v retrieving revision 1.9 diff -u -r1.9 TargetDefinitionPersistenceHelper.java --- src/org/eclipse/pde/internal/core/target/TargetDefinitionPersistenceHelper.java 5 Nov 2010 15:56:16 -0000 1.9 +++ src/org/eclipse/pde/internal/core/target/TargetDefinitionPersistenceHelper.java 30 Nov 2010 21:03:55 -0000 @@ -72,6 +72,7 @@ static final String ATTR_OPTIONAL = "optional"; //$NON-NLS-1$ static final String ATTR_VERSION = "version"; //$NON-NLS-1$ static final String ATTR_CONFIGURATION = "configuration"; //$NON-NLS-1$ + static final String ATTR_SEQUENCE_NUMBER = "sequenceNumber"; //$NON-NLS-1$ static final String CONTENT = "content"; //$NON-NLS-1$ static final String ATTR_USE_ALL = "useAllPlugins"; //$NON-NLS-1$ static final String PLUGINS = "plugins"; //$NON-NLS-1$ @@ -107,6 +108,8 @@ rootElement.setAttribute(ATTR_INCLUDE_MODE, FEATURE); } + rootElement.setAttribute(ATTR_SEQUENCE_NUMBER, Integer.toString(definition.currentSequenceNumber())); + IBundleContainer[] containers = definition.getBundleContainers(); if (containers != null && containers.length > 0) { Element containersElement = doc.createElement(LOCATIONS); Index: src/org/eclipse/pde/internal/core/target/TargetPersistence35Helper.java =================================================================== RCS file: /cvsroot/eclipse/pde/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/target/TargetPersistence35Helper.java,v retrieving revision 1.2 diff -u -r1.2 TargetPersistence35Helper.java --- src/org/eclipse/pde/internal/core/target/TargetPersistence35Helper.java 1 Mar 2010 21:41:05 -0000 1.2 +++ src/org/eclipse/pde/internal/core/target/TargetPersistence35Helper.java 30 Nov 2010 21:03:55 -0000 @@ -224,18 +224,14 @@ String[] iuIDs = (String[]) ids.toArray(new String[ids.size()]); String[] iuVer = (String[]) versions.toArray(new String[versions.size()]); URI[] uris = (URI[]) repos.toArray(new URI[repos.size()]); - container = new IUBundleContainer(iuIDs, iuVer, uris); + int flags = IUBundleContainer.INCLUDE_REQUIRED; if (includeMode != null && includeMode.trim().length() > 0) { - if (includeMode.equals(TargetDefinitionPersistenceHelper.MODE_PLANNER)) { - ((IUBundleContainer) container).setIncludeAllRequired(true, null); - } else if (includeMode.equals(TargetDefinitionPersistenceHelper.MODE_SLICER)) { - ((IUBundleContainer) container).setIncludeAllRequired(false, null); + if (includeMode.equals(TargetDefinitionPersistenceHelper.MODE_SLICER)) { + flags = 0; } } - if (includeAllPlatforms != null && includeAllPlatforms.trim().length() > 0) { - ((IUBundleContainer) container).setIncludeAllEnvironments(Boolean.valueOf(includeAllPlatforms).booleanValue(), null); - } - + flags |= Boolean.valueOf(includeAllPlatforms).booleanValue() ? IUBundleContainer.INCLUDE_ALL_ENVIRONMENTS : 0; + container = new IUBundleContainer(iuIDs, iuVer, uris, flags); } NodeList list = location.getChildNodes(); Index: src/org/eclipse/pde/internal/core/target/TargetPersistence36Helper.java =================================================================== RCS file: /cvsroot/eclipse/pde/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/target/TargetPersistence36Helper.java,v retrieving revision 1.2 diff -u -r1.2 TargetPersistence36Helper.java --- src/org/eclipse/pde/internal/core/target/TargetPersistence36Helper.java 5 Nov 2010 15:56:16 -0000 1.2 +++ src/org/eclipse/pde/internal/core/target/TargetPersistence36Helper.java 30 Nov 2010 21:03:55 -0000 @@ -148,6 +148,14 @@ } } } + + // Set the sequence number at the very end + String sequenceNumber = root.getAttribute(TargetDefinitionPersistenceHelper.ATTR_SEQUENCE_NUMBER); + try { + ((TargetDefinition) definition).setSequenceNumber(Integer.parseInt(sequenceNumber)); + } catch (NumberFormatException e) { + ((TargetDefinition) definition).setSequenceNumber(0); + } } /** @@ -215,19 +223,16 @@ String[] iuIDs = (String[]) ids.toArray(new String[ids.size()]); String[] iuVer = (String[]) versions.toArray(new String[versions.size()]); URI[] uris = (URI[]) repos.toArray(new URI[repos.size()]); - container = new IUBundleContainer(iuIDs, iuVer, uris); + + int flags = IUBundleContainer.INCLUDE_REQUIRED; if (includeMode != null && includeMode.trim().length() > 0) { - if (includeMode.equals(TargetDefinitionPersistenceHelper.MODE_PLANNER)) { - ((IUBundleContainer) container).setIncludeAllRequired(true, null); - } else if (includeMode.equals(TargetDefinitionPersistenceHelper.MODE_SLICER)) { - ((IUBundleContainer) container).setIncludeAllRequired(false, null); + if (includeMode.equals(TargetDefinitionPersistenceHelper.MODE_SLICER)) { + flags = 0; } } - if (includeAllPlatforms != null && includeAllPlatforms.trim().length() > 0) { - ((IUBundleContainer) container).setIncludeAllEnvironments(Boolean.valueOf(includeAllPlatforms).booleanValue(), null); - } - ((IUBundleContainer) container).setIncludeSource(Boolean.valueOf(includeSource).booleanValue()); - + flags |= Boolean.valueOf(includeAllPlatforms).booleanValue() ? IUBundleContainer.INCLUDE_ALL_ENVIRONMENTS : 0; + flags |= Boolean.valueOf(includeSource).booleanValue() ? IUBundleContainer.INCLUDE_SOURCE : 0; + container = new IUBundleContainer(iuIDs, iuVer, uris, flags); } return container; } Index: src/org/eclipse/pde/internal/core/target/TargetPlatformService.java =================================================================== RCS file: /cvsroot/eclipse/pde/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/target/TargetPlatformService.java,v retrieving revision 1.12 diff -u -r1.12 TargetPlatformService.java --- src/org/eclipse/pde/internal/core/target/TargetPlatformService.java 5 Nov 2010 15:56:16 -0000 1.12 +++ src/org/eclipse/pde/internal/core/target/TargetPlatformService.java 30 Nov 2010 21:03:55 -0000 @@ -591,16 +591,16 @@ } /* (non-Javadoc) - * @see org.eclipse.pde.internal.core.target.provisional.ITargetPlatformService#newIUContainer(org.eclipse.equinox.internal.provisional.p2.metadata.IInstallableUnit[], java.net.URI[]) + * @see org.eclipse.pde.internal.core.target.provisional.ITargetPlatformService#newIUContainer(org.eclipse.equinox.p2.metadata.IInstallableUnit[], java.net.URI[], int) */ - public IBundleContainer newIUContainer(IInstallableUnit[] units, URI[] repositories) { - return new IUBundleContainer(units, repositories); + public IBundleContainer newIUContainer(IInstallableUnit[] units, URI[] repositories, int resolutionFlags) { + return new IUBundleContainer(units, repositories, resolutionFlags); } /* (non-Javadoc) - * @see org.eclipse.pde.internal.core.target.provisional.ITargetPlatformService#newIUContainer(java.lang.String[], java.lang.String[], java.net.URI[]) + * @see org.eclipse.pde.internal.core.target.provisional.ITargetPlatformService#newIUContainer(java.lang.String[], java.lang.String[], java.net.URI[], int) */ - public IBundleContainer newIUContainer(String[] unitIds, String[] versions, URI[] repositories) { - return new IUBundleContainer(unitIds, versions, repositories); + public IBundleContainer newIUContainer(String[] unitIds, String[] versions, URI[] repositories, int resolutionFlags) { + return new IUBundleContainer(unitIds, versions, repositories, resolutionFlags); } } Index: src/org/eclipse/pde/internal/core/target/provisional/ITargetDefinition.java =================================================================== RCS file: /cvsroot/eclipse/pde/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/target/provisional/ITargetDefinition.java,v retrieving revision 1.10 diff -u -r1.10 ITargetDefinition.java --- src/org/eclipse/pde/internal/core/target/provisional/ITargetDefinition.java 8 Apr 2010 20:57:50 -0000 1.10 +++ src/org/eclipse/pde/internal/core/target/provisional/ITargetDefinition.java 30 Nov 2010 21:03:55 -0000 @@ -320,4 +320,13 @@ * @return implicit dependencies or null */ public NameVersionDescriptor[] getImplicitDependencies(); + + /** + * Returns the current sequence number of this target. Sequence numbers change + * whenever something in the target that affects the set of features and bundles that + * would be resolved. + * + * @return the current sequence number + */ + public int currentSequenceNumber(); } Index: src/org/eclipse/pde/internal/core/target/provisional/ITargetPlatformService.java =================================================================== RCS file: /cvsroot/eclipse/pde/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/target/provisional/ITargetPlatformService.java,v retrieving revision 1.13 diff -u -r1.13 ITargetPlatformService.java --- src/org/eclipse/pde/internal/core/target/provisional/ITargetPlatformService.java 28 May 2010 19:40:04 -0000 1.13 +++ src/org/eclipse/pde/internal/core/target/provisional/ITargetPlatformService.java 30 Nov 2010 21:03:55 -0000 @@ -10,11 +10,11 @@ *******************************************************************************/ package org.eclipse.pde.internal.core.target.provisional; -import org.eclipse.equinox.p2.metadata.IInstallableUnit; - import java.net.URI; import org.eclipse.core.resources.IFile; import org.eclipse.core.runtime.*; +import org.eclipse.equinox.p2.metadata.IInstallableUnit; +import org.eclipse.pde.internal.core.target.IUBundleContainer; /** * A service to manage target platform definitions available to the workspace. @@ -139,9 +139,10 @@ * @param units installable units * @param repositories URI's describing repository locations or null to use * default repositories + * @param resolutionFlags bitmask of flags to control IU resolution, possible flags are {@link IUBundleContainer#INCLUDE_ALL_ENVIRONMENTS}, {@link IUBundleContainer#INCLUDE_REQUIRED}, {@link IUBundleContainer#INCLUDE_SOURCE} * @return bundle container */ - public IBundleContainer newIUContainer(IInstallableUnit[] units, URI[] repositories); + public IBundleContainer newIUContainer(IInstallableUnit[] units, URI[] repositories, int resolutionFlags); /** * Creates and returns a bundle container that contains all bundles contained in @@ -152,9 +153,10 @@ * @param versions version identifiers * @param repositories URI's describing repository locations or null to use * default repositories + * @param resolutionFlags bitmask of flags to control IU resolution, possible flags are {@link IUBundleContainer#INCLUDE_ALL_ENVIRONMENTS}, {@link IUBundleContainer#INCLUDE_REQUIRED}, {@link IUBundleContainer#INCLUDE_SOURCE} * @return bundle container */ - public IBundleContainer newIUContainer(String[] unitIds, String[] versions, URI[] repositories); + public IBundleContainer newIUContainer(String[] unitIds, String[] versions, URI[] repositories, int resolutionFlags); /** * Creates and returns a bundle container that contains all bundles referenced by #P org.eclipse.pde.ui Index: META-INF/MANIFEST.MF =================================================================== RCS file: /cvsroot/eclipse/pde/ui/org.eclipse.pde.ui/META-INF/MANIFEST.MF,v retrieving revision 1.88 diff -u -r1.88 MANIFEST.MF --- META-INF/MANIFEST.MF 23 Nov 2010 18:56:29 -0000 1.88 +++ META-INF/MANIFEST.MF 30 Nov 2010 21:03:58 -0000 @@ -108,7 +108,7 @@ org.eclipse.pde.launching;bundle-version="[3.6.0,4.0.0)";visibility:=reexport, org.eclipse.ui.console;bundle-version="[3.5.0,4.0.0)", org.eclipse.equinox.simpleconfigurator;bundle-version="[1.0.200,2.0.0)", - org.eclipse.equinox.p2.repository.tools + org.eclipse.equinox.p2.repository.tools;bundle-version="[2.0.100,3.0.0)" Eclipse-LazyStart: true Import-Package: com.ibm.icu.text, org.eclipse.jdt.debug.core Index: src/org/eclipse/pde/internal/ui/search/dialogs/FilteredIUSelectionDialog.java =================================================================== RCS file: /cvsroot/eclipse/pde/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/search/dialogs/FilteredIUSelectionDialog.java,v retrieving revision 1.3 diff -u -r1.3 FilteredIUSelectionDialog.java --- src/org/eclipse/pde/internal/ui/search/dialogs/FilteredIUSelectionDialog.java 2 Mar 2010 20:57:09 -0000 1.3 +++ src/org/eclipse/pde/internal/ui/search/dialogs/FilteredIUSelectionDialog.java 30 Nov 2010 21:03:58 -0000 @@ -13,7 +13,6 @@ import java.util.Comparator; import java.util.Iterator; import org.eclipse.core.runtime.*; -import org.eclipse.equinox.p2.core.IProvisioningAgent; import org.eclipse.equinox.p2.metadata.IInstallableUnit; import org.eclipse.equinox.p2.metadata.IProvidedCapability; import org.eclipse.equinox.p2.query.IQuery; @@ -24,6 +23,7 @@ import org.eclipse.jface.viewers.*; import org.eclipse.pde.internal.core.PDECore; import org.eclipse.pde.internal.core.target.Messages; +import org.eclipse.pde.internal.core.target.P2TargetUtils; import org.eclipse.pde.internal.ui.*; import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionAdapter; @@ -67,6 +67,13 @@ styledString.append("(", StyledString.QUALIFIER_STYLER); //$NON-NLS-1$ styledString.append(iuPackage.getVersion().toString(), StyledString.QUALIFIER_STYLER); styledString.append(")", StyledString.QUALIFIER_STYLER); //$NON-NLS-1$ + IInstallableUnit iu = iuPackage.getIU(); + styledString.append(" from ", StyledString.QUALIFIER_STYLER); //$NON-NLS-1$ + styledString.append(iu.getId(), StyledString.QUALIFIER_STYLER); + styledString.append(' '); + styledString.append("(", StyledString.QUALIFIER_STYLER); //$NON-NLS-1$ + styledString.append(iu.getVersion().toString(), StyledString.QUALIFIER_STYLER); + styledString.append(")", StyledString.QUALIFIER_STYLER); //$NON-NLS-1$ } else if (element instanceof IInstallableUnit) { IInstallableUnit iu = (IInstallableUnit) element; String name = iu.getProperty(IInstallableUnit.PROP_NAME, null); @@ -190,10 +197,9 @@ */ protected void fillContentProvider(AbstractContentProvider contentProvider, ItemsFilter itemsFilter, IProgressMonitor progressMonitor) throws CoreException { // TODO clean up this code a bit... - IProvisioningAgent agent = (IProvisioningAgent) PDECore.getDefault().acquireService(IProvisioningAgent.SERVICE_NAME); - if (agent == null) - throw new CoreException(new Status(IStatus.ERROR, PDECore.PLUGIN_ID, Messages.IUBundleContainer_7)); - IMetadataRepositoryManager manager = (IMetadataRepositoryManager) agent.getService(IMetadataRepositoryManager.SERVICE_NAME); + IMetadataRepositoryManager manager = P2TargetUtils.getRepoManager(); + if (manager == null) + throw new CoreException(new Status(IStatus.ERROR, PDECore.PLUGIN_ID, Messages.IUBundleContainer_2)); //URI[] knownRepositories = metadataManager.getKnownRepositories(IRepositoryManager.REPOSITORIES_ALL); IQuery pipedQuery; Index: src/org/eclipse/pde/internal/ui/search/dialogs/TargetRepositorySearchHandler.java =================================================================== RCS file: /cvsroot/eclipse/pde/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/search/dialogs/TargetRepositorySearchHandler.java,v retrieving revision 1.7 diff -u -r1.7 TargetRepositorySearchHandler.java --- src/org/eclipse/pde/internal/ui/search/dialogs/TargetRepositorySearchHandler.java 9 Aug 2010 21:18:08 -0000 1.7 +++ src/org/eclipse/pde/internal/ui/search/dialogs/TargetRepositorySearchHandler.java 30 Nov 2010 21:03:58 -0000 @@ -78,10 +78,9 @@ ITargetPlatformService service = (ITargetPlatformService) PDECore.getDefault().acquireService(ITargetPlatformService.class.getName()); ITargetHandle currentTarget = service.getWorkspaceTargetHandle(); ITargetDefinition definition = currentTarget.getTargetDefinition(); - IUBundleContainer container = (IUBundleContainer) service.newIUContainer(units, repositories); // Force the target into slicer mode as all requirements may not be available - container.setIncludeAllRequired(false, definition); - container.setIncludeAllEnvironments(true, definition); + int flags = IUBundleContainer.INCLUDE_ALL_ENVIRONMENTS | IUBundleContainer.INCLUDE_SOURCE; + IUBundleContainer container = (IUBundleContainer) service.newIUContainer(units, repositories, flags); IBundleContainer[] oldContainers = definition.getBundleContainers(); if (oldContainers == null) { definition.setBundleContainers(new IBundleContainer[] {container}); Index: src/org/eclipse/pde/internal/ui/shared/target/AddBundleContainerSelectionPage.java =================================================================== RCS file: /cvsroot/eclipse/pde/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/shared/target/AddBundleContainerSelectionPage.java,v retrieving revision 1.21 diff -u -r1.21 AddBundleContainerSelectionPage.java --- src/org/eclipse/pde/internal/ui/shared/target/AddBundleContainerSelectionPage.java 5 Nov 2010 15:56:16 -0000 1.21 +++ src/org/eclipse/pde/internal/ui/shared/target/AddBundleContainerSelectionPage.java 30 Nov 2010 21:03:58 -0000 @@ -14,12 +14,10 @@ import java.util.ArrayList; import java.util.List; import org.eclipse.core.runtime.*; -import org.eclipse.equinox.p2.engine.IProfile; import org.eclipse.jface.dialogs.*; import org.eclipse.jface.viewers.*; import org.eclipse.jface.wizard.*; import org.eclipse.pde.internal.core.PDECore; -import org.eclipse.pde.internal.core.target.P2TargetUtils; import org.eclipse.pde.internal.core.target.provisional.*; import org.eclipse.pde.internal.ui.*; import org.eclipse.pde.internal.ui.wizards.WizardElement; @@ -291,14 +289,7 @@ settings = PDEPlugin.getDefault().getDialogSettings().addNewSection(SETTINGS_SECTION); } setDialogSettings(settings); - // TODO Use proper API to get the profile - IProfile profile = null; - try { - profile = P2TargetUtils.getProfile(fTarget); - } catch (CoreException e) { - PDEPlugin.log(e); - } - addPage(new EditIUContainerPage(fTarget, profile)); + addPage(new EditIUContainerPage(fTarget)); } public boolean performFinish() { Index: src/org/eclipse/pde/internal/ui/shared/target/EditBundleContainerWizard.java =================================================================== RCS file: /cvsroot/eclipse/pde/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/shared/target/EditBundleContainerWizard.java,v retrieving revision 1.6 diff -u -r1.6 EditBundleContainerWizard.java --- src/org/eclipse/pde/internal/ui/shared/target/EditBundleContainerWizard.java 5 Nov 2010 15:56:16 -0000 1.6 +++ src/org/eclipse/pde/internal/ui/shared/target/EditBundleContainerWizard.java 30 Nov 2010 21:03:58 -0000 @@ -10,7 +10,6 @@ *******************************************************************************/ package org.eclipse.pde.internal.ui.shared.target; -import org.eclipse.core.runtime.CoreException; import org.eclipse.jface.dialogs.IDialogSettings; import org.eclipse.jface.wizard.Wizard; import org.eclipse.pde.internal.core.target.*; @@ -50,11 +49,7 @@ } else if (fContainer instanceof FeatureBundleContainer) { fPage = new EditFeatureContainerPage(fContainer); } else if (fContainer instanceof IUBundleContainer) { - try { - fPage = new EditIUContainerPage((IUBundleContainer) fContainer, fTarget, P2TargetUtils.getProfile(fTarget)); - } catch (CoreException e) { - PDEPlugin.log(e); - } + fPage = new EditIUContainerPage((IUBundleContainer) fContainer, fTarget); } if (fPage != null) { addPage(fPage); Index: src/org/eclipse/pde/internal/ui/shared/target/EditIUContainerPage.java =================================================================== RCS file: /cvsroot/eclipse/pde/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/shared/target/EditIUContainerPage.java,v retrieving revision 1.18 diff -u -r1.18 EditIUContainerPage.java --- src/org/eclipse/pde/internal/ui/shared/target/EditIUContainerPage.java 5 Nov 2010 15:56:16 -0000 1.18 +++ src/org/eclipse/pde/internal/ui/shared/target/EditIUContainerPage.java 30 Nov 2010 21:03:58 -0000 @@ -18,7 +18,6 @@ import org.eclipse.equinox.internal.p2.ui.actions.PropertyDialogAction; import org.eclipse.equinox.internal.p2.ui.dialogs.*; import org.eclipse.equinox.internal.p2.ui.query.IUViewQueryContext; -import org.eclipse.equinox.p2.engine.IProfile; import org.eclipse.equinox.p2.metadata.IInstallableUnit; import org.eclipse.equinox.p2.ui.Policy; import org.eclipse.equinox.p2.ui.ProvisioningUI; @@ -30,6 +29,7 @@ import org.eclipse.osgi.util.NLS; import org.eclipse.pde.internal.core.PDECore; import org.eclipse.pde.internal.core.target.IUBundleContainer; +import org.eclipse.pde.internal.core.target.P2TargetUtils; import org.eclipse.pde.internal.core.target.provisional.*; import org.eclipse.pde.internal.ui.*; import org.eclipse.swt.SWT; @@ -68,11 +68,6 @@ private IUBundleContainer fEditContainer; /** - * Profile from the target - */ - private IProfile fProfile; - - /** * Used to provide special attributes/filtering to the available iu group */ private IUViewQueryContext fQueryContext; @@ -97,19 +92,18 @@ /** * Constructor for creating a new container - * @param profile profile from the parent target, used to setup the p2 UI + * @param definition the target definintion we are editing */ - protected EditIUContainerPage(ITargetDefinition definition, IProfile profile) { + protected EditIUContainerPage(ITargetDefinition definition) { super("AddP2Container"); //$NON-NLS-1$ setTitle(Messages.EditIUContainerPage_5); setMessage(Messages.EditIUContainerPage_6); fTarget = definition; - fProfile = profile; ProvisioningUI selfProvisioningUI = ProvisioningUI.getDefaultUI(); // TODO we use the service session from the self profile. In the future we may want // to set up our own services for the profile (separate repo managers, etc). // We use our own new policy so we don't bash the SDK's settings. - profileUI = new ProvisioningUI(selfProvisioningUI.getSession(), profile.getProfileId(), new Policy()); + profileUI = new ProvisioningUI(selfProvisioningUI.getSession(), P2TargetUtils.getProfileId(definition), new Policy()); } /** @@ -117,8 +111,8 @@ * @param container the container to edit * @param profile profile from the parent target, used to setup the p2 UI */ - protected EditIUContainerPage(IUBundleContainer container, ITargetDefinition definition, IProfile profile) { - this(definition, profile); + protected EditIUContainerPage(IUBundleContainer container, ITargetDefinition definition) { + this(definition); setTitle(Messages.EditIUContainerPage_7); setMessage(Messages.EditIUContainerPage_6); fEditContainer = container; @@ -132,10 +126,10 @@ if (service == null) { PDEPlugin.log(new Status(IStatus.ERROR, PDEPlugin.getPluginId(), Messages.EditIUContainerPage_9)); } - IUBundleContainer container = (IUBundleContainer) service.newIUContainer(fAvailableIUGroup.getCheckedLeafIUs(), fRepoLocation != null ? new URI[] {fRepoLocation} : null); - container.setIncludeAllRequired(fIncludeRequiredButton.getSelection(), fTarget); - container.setIncludeAllEnvironments(fAllPlatformsButton.getSelection(), fTarget); - container.setIncludeSource(fIncludeSourceButton.getSelection()); + int flags = fIncludeRequiredButton.getSelection() ? IUBundleContainer.INCLUDE_REQUIRED : 0; + flags |= fAllPlatformsButton.getSelection() ? IUBundleContainer.INCLUDE_ALL_ENVIRONMENTS : 0; + flags |= fIncludeSourceButton.getSelection() ? IUBundleContainer.INCLUDE_SOURCE : 0; + IUBundleContainer container = (IUBundleContainer) service.newIUContainer(fAvailableIUGroup.getCheckedLeafIUs(), fRepoLocation != null ? new URI[] {fRepoLocation} : null, flags); return container; } @@ -299,32 +293,37 @@ }); ((GridData) fAllPlatformsButton.getLayoutData()).horizontalIndent = 10; fIncludeSourceButton = SWTFactory.createCheckButton(slicerGroup, Messages.EditIUContainerPage_16, null, true, 1); + fIncludeSourceButton.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + warnIfGlobalSettingChanged(); + } + }); } private void warnIfGlobalSettingChanged() { - boolean warn = false; - if (fTarget != null) { - IBundleContainer[] containers = fTarget.getBundleContainers(); - if (containers != null) { - for (int i = 0; i < containers.length; i++) { - if (containers[i] instanceof IUBundleContainer && containers[i] != fEditContainer) { - IUBundleContainer container = (IUBundleContainer) containers[i]; - if (container.getIncludeAllRequired() != fIncludeRequiredButton.getSelection()) { - warn = true; - break; - } - if (!fIncludeRequiredButton.getSelection() && container.getIncludeAllEnvironments() != fAllPlatformsButton.getSelection()) { - warn = true; - break; - } - } + boolean noChange = true; + IUBundleContainer iuContainer = null; + IBundleContainer[] containers = fTarget.getBundleContainers(); + if (containers != null) { + // Look for a IUBundleContainer to compare against. + for (int i = 0; i < containers.length; i++) { + if (containers[i] instanceof IUBundleContainer && containers[i] != fEditContainer) { + iuContainer = (IUBundleContainer) containers[i]; + break; } } + // If there is another IU container then compare against it. No need to check them all + // as they will all be set the same within one target. + if (iuContainer != null) { + noChange &= fIncludeRequiredButton.getSelection() == iuContainer.getIncludeAllRequired(); + noChange &= fAllPlatformsButton.getSelection() == iuContainer.getIncludeAllEnvironments(); + noChange &= fIncludeSourceButton.getSelection() == iuContainer.getIncludeSource(); + } } - if (warn) { - setMessage(Messages.EditIUContainerPage_4, IStatus.WARNING); - } else { + if (noChange) { setMessage(Messages.EditIUContainerPage_6); + } else { + setMessage(Messages.EditIUContainerPage_4, IStatus.WARNING); } } @@ -333,7 +332,7 @@ */ private void createQueryContext() { fQueryContext = ProvUI.getQueryContext(ProvisioningUI.getDefaultUI().getPolicy()); - fQueryContext.setInstalledProfileId(fProfile.getProfileId()); + fQueryContext.setInstalledProfileId(P2TargetUtils.getProfileId(fTarget)); fQueryContext.showAlreadyInstalled(); } @@ -498,7 +497,7 @@ // Only able to check items if we don't have categories fQueryContext.setViewType(IUViewQueryContext.AVAILABLE_VIEW_FLAT); fAvailableIUGroup.updateAvailableViewState(); - fAvailableIUGroup.setChecked(fEditContainer.getInstallableUnits(fProfile)); + fAvailableIUGroup.setChecked(fEditContainer.getInstallableUnits()); // Make sure view is back in proper state updateViewContext(); IInstallableUnit[] units = fAvailableIUGroup.getCheckedLeafIUs(); @@ -519,5 +518,4 @@ } } } - } Index: src/org/eclipse/pde/internal/ui/shared/target/TargetContentsGroup.java =================================================================== RCS file: /cvsroot/eclipse/pde/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/shared/target/TargetContentsGroup.java,v retrieving revision 1.22 diff -u -r1.22 TargetContentsGroup.java --- src/org/eclipse/pde/internal/ui/shared/target/TargetContentsGroup.java 1 Oct 2010 19:23:59 -0000 1.22 +++ src/org/eclipse/pde/internal/ui/shared/target/TargetContentsGroup.java 30 Nov 2010 21:03:58 -0000 @@ -1028,10 +1028,10 @@ if (parent == null) { result = fAllBundles.toArray(); } else if (fFeaureModeButton.getSelection() && parent == OTHER_CATEGORY) { - return ((TargetDefinition) fTargetDefinition).getOtherBundles(); + result = ((TargetDefinition) fTargetDefinition).getOtherBundles(); } else if (fGrouping == GROUP_BY_CONTAINER && parent instanceof IBundleContainer) { IBundleContainer container = (IBundleContainer) parent; - return container.getBundles(); + result = container.getBundles(); } else if (fGrouping == GROUP_BY_FILE_LOC && parent instanceof IPath) { List bundles = (List) getFileBundleMapping().get(parent); if (bundles != null && bundles.size() > 0) { Index: src/org/eclipse/pde/internal/ui/shared/target/TargetLocationsGroup.java =================================================================== RCS file: /cvsroot/eclipse/pde/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/shared/target/TargetLocationsGroup.java,v retrieving revision 1.17 diff -u -r1.17 TargetLocationsGroup.java --- src/org/eclipse/pde/internal/ui/shared/target/TargetLocationsGroup.java 5 Nov 2010 15:56:16 -0000 1.17 +++ src/org/eclipse/pde/internal/ui/shared/target/TargetLocationsGroup.java 30 Nov 2010 21:03:58 -0000 @@ -10,14 +10,11 @@ *******************************************************************************/ package org.eclipse.pde.internal.ui.shared.target; -import org.eclipse.pde.internal.core.target.UpdateTargetJob; - import java.util.*; import java.util.List; import org.eclipse.core.runtime.*; import org.eclipse.core.runtime.jobs.IJobChangeEvent; import org.eclipse.core.runtime.jobs.JobChangeAdapter; -import org.eclipse.equinox.p2.engine.IProfile; import org.eclipse.equinox.p2.metadata.IInstallableUnit; import org.eclipse.jface.viewers.*; import org.eclipse.jface.window.Window; @@ -440,7 +437,7 @@ boolean updateAllowed = false; Iterator iter = selection.iterator(); while (iter.hasNext()) { - if (removeAllowed && updateAllowed){ + if (removeAllowed && updateAllowed) { break; } Object current = iter.next(); @@ -495,10 +492,13 @@ } } else if (parentElement instanceof IUBundleContainer) { // Show the IUs as children - // TODO See if we can get the profile using API try { - IProfile profile = P2TargetUtils.getProfile(fTarget); - IInstallableUnit[] units = ((IUBundleContainer) parentElement).getInstallableUnits(profile); + // if this is a bundle container then we must be sure that all bundle containers are + // happy since they all share the same profile. + if (!P2TargetUtils.isResolved(fTarget)) { + return new Object[0]; + } + IInstallableUnit[] units = ((IUBundleContainer) parentElement).getInstallableUnits(); // Wrap the units so that they remember their parent container List wrappedUnits = new ArrayList(units.length); for (int i = 0; i < units.length; i++) { Index: src/org/eclipse/pde/internal/ui/wizards/exports/ExportTargetJob.java =================================================================== RCS file: /cvsroot/eclipse/pde/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/wizards/exports/ExportTargetJob.java,v retrieving revision 1.1 diff -u -r1.1 ExportTargetJob.java --- src/org/eclipse/pde/internal/ui/wizards/exports/ExportTargetJob.java 23 Nov 2010 18:56:29 -0000 1.1 +++ src/org/eclipse/pde/internal/ui/wizards/exports/ExportTargetJob.java 30 Nov 2010 21:03:58 -0000 @@ -15,13 +15,11 @@ import org.eclipse.core.filesystem.*; import org.eclipse.core.runtime.*; import org.eclipse.core.runtime.jobs.Job; -import org.eclipse.equinox.p2.engine.IProfile; import org.eclipse.equinox.p2.internal.repository.tools.Repo2Runnable; import org.eclipse.equinox.p2.internal.repository.tools.RepositoryDescriptor; import org.eclipse.equinox.p2.metadata.IInstallableUnit; import org.eclipse.equinox.p2.metadata.IProvidedCapability; import org.eclipse.equinox.p2.query.IQueryResult; -import org.eclipse.equinox.p2.query.QueryUtil; import org.eclipse.pde.internal.core.feature.ExternalFeatureModel; import org.eclipse.pde.internal.core.ifeature.IFeatureModel; import org.eclipse.pde.internal.core.target.IUBundleContainer; @@ -219,13 +217,12 @@ } private void exportProfile(ITargetDefinition target, URI destination, IProgressMonitor monitor) throws CoreException { - IProfile profile = P2TargetUtils.getProfile(target); Repo2Runnable exporter = new Repo2Runnable(); - exporter.addDestination(createRepoDescriptor(destination, profile.getProfileId(), RepositoryDescriptor.KIND_METADATA)); - exporter.addDestination(createRepoDescriptor(destination, profile.getProfileId(), RepositoryDescriptor.KIND_ARTIFACT)); - exporter.addSource(createRepoDescriptor(P2TargetUtils.getBundlePool(profile).getLocation(), null, RepositoryDescriptor.KIND_ARTIFACT)); + exporter.addDestination(createRepoDescriptor(destination, P2TargetUtils.getProfileId(target), RepositoryDescriptor.KIND_METADATA)); + exporter.addDestination(createRepoDescriptor(destination, P2TargetUtils.getProfileId(target), RepositoryDescriptor.KIND_ARTIFACT)); + exporter.addSource(createRepoDescriptor(P2TargetUtils.getBundlePool().getLocation(), null, RepositoryDescriptor.KIND_ARTIFACT)); - IQueryResult ius = profile.query(QueryUtil.createIUAnyQuery(), null); + IQueryResult ius = P2TargetUtils.getIUs(target, monitor); ArrayList toExport = new ArrayList(); for (Iterator i = ius.iterator(); i.hasNext();) { IInstallableUnit iu = (IInstallableUnit) i.next(); #P org.eclipse.pde.ui.tests Index: src/org/eclipse/pde/ui/tests/target/IUBundleContainerTests.java =================================================================== RCS file: /cvsroot/eclipse/pde/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/target/IUBundleContainerTests.java,v retrieving revision 1.15 diff -u -r1.15 IUBundleContainerTests.java --- src/org/eclipse/pde/ui/tests/target/IUBundleContainerTests.java 5 Nov 2010 19:53:46 -0000 1.15 +++ src/org/eclipse/pde/ui/tests/target/IUBundleContainerTests.java 30 Nov 2010 21:03:59 -0000 @@ -10,10 +10,6 @@ *******************************************************************************/ package org.eclipse.pde.ui.tests.target; -import org.eclipse.pde.internal.core.target.P2TargetUtils; - -import java.util.Iterator; - import java.io.*; import java.net.URI; import java.net.URL; @@ -23,8 +19,6 @@ import org.eclipse.core.filesystem.URIUtil; import org.eclipse.core.runtime.*; import org.eclipse.equinox.internal.p2.core.helpers.URLUtil; -import org.eclipse.equinox.p2.core.IProvisioningAgent; -import org.eclipse.equinox.p2.engine.*; import org.eclipse.equinox.p2.metadata.IInstallableUnit; import org.eclipse.equinox.p2.query.IQueryResult; import org.eclipse.equinox.p2.query.QueryUtil; @@ -89,16 +83,16 @@ } public void testResolveUsingProfile() throws Exception { - String[] bundleIDs = new String[]{"feature.b.feature.group"}; + String[] features1 = new String[]{"feature.b.feature.group"}; + String[] features2 = new String[]{"feature.a.feature.group"}; String[] expectedBundles = new String[]{"bundle.a1", "bundle.a2", "bundle.a3", "bundle.b1", "bundle.b2", "bundle.b3"}; - String[] expectedBundles2 = new String[]{"bundle.b1", "bundle.b2", "bundle.b3"}; + String[] expectedBundles2 = new String[]{"bundle.a1", "bundle.a2", "bundle.a3"}; try { - - IUBundleContainer container = createContainer(bundleIDs); + // create a target that references just a high level root + IUBundleContainer container = createContainer(features1); ITargetDefinition target = getTargetService().newTarget(); target.setBundleContainers(new IBundleContainer[]{container}); - List infos = getAllBundleInfos(target); Set names = collectAllSymbolicNames(infos); assertEquals(expectedBundles.length, infos.size()); @@ -106,24 +100,9 @@ assertTrue("Missing: " + expectedBundles[i], names.contains(expectedBundles[i])); } - IProfile profile = P2TargetUtils.getProfile(target); - - IProvisioningAgent agent = P2TargetUtils.getAgent(); - IEngine engine = P2TargetUtils.getEngine(); - IProvisioningPlan plan = engine.createPlan(profile, new ProvisioningContext(agent)); - IQueryResult units = profile.query(QueryUtil.ALL_UNITS, null); - for (Iterator iterator = units.iterator(); iterator.hasNext();) { - IInstallableUnit unit = (IInstallableUnit) iterator.next(); - if (unit.getId().startsWith("bundle.a")){ - plan.removeInstallableUnit(unit); - } - } - IPhaseSet phases = PhaseSetFactory.createDefaultPhaseSetExcluding(new String[] {PhaseSetFactory.PHASE_CHECK_TRUST, PhaseSetFactory.PHASE_CONFIGURE, PhaseSetFactory.PHASE_UNCONFIGURE}); - IStatus result = engine.perform(plan, phases, null); - - assertTrue("Problem while provisioning: " + result.getMessage(), result.isOK()); - - target.resolve(null); // Force the target to reresolve (hopefully using the modified profile) + // Now modify the target to have just a lower level root. The extra higher level stuff should get removed. + container = createContainer(features2); + target.setBundleContainers(new IBundleContainer[]{container}); infos = getAllBundleInfos(target); names = collectAllSymbolicNames(infos); assertEquals(expectedBundles2.length, infos.size()); @@ -211,8 +190,8 @@ */ public void testContentEqualNull() throws Exception { ITargetPlatformService service = getTargetService(); - IUBundleContainer c3 = (IUBundleContainer) service.newIUContainer(new String[]{"bundle.a1", "bundle.a2"}, new String[]{"1.0.0", "1.0.0"}, null); - IUBundleContainer c4 = (IUBundleContainer) service.newIUContainer(new String[]{"bundle.a1", "bundle.a2"}, new String[]{"1.0.0", "1.0.0"}, null); + IUBundleContainer c3 = (IUBundleContainer) service.newIUContainer(new String[]{"bundle.a1", "bundle.a2"}, new String[]{"1.0.0", "1.0.0"}, null, 0); + IUBundleContainer c4 = (IUBundleContainer) service.newIUContainer(new String[]{"bundle.a1", "bundle.a2"}, new String[]{"1.0.0", "1.0.0"}, null, 0); assertTrue("Contents should be equivalent", c3.isContentEqual(c4)); } @@ -223,8 +202,8 @@ */ public void testContentNotEqualNull() throws Exception { ITargetPlatformService service = getTargetService(); - IUBundleContainer c3 = (IUBundleContainer) service.newIUContainer(new String[]{"bundle.a1", "bundle.a2"}, new String[]{"1.0.0", "1.0.0"}, null); - IUBundleContainer c4 = (IUBundleContainer) service.newIUContainer(new String[]{"bundle.b1", "bundle.b2"}, new String[]{"1.0.0", "1.0.0"}, null); + IUBundleContainer c3 = (IUBundleContainer) service.newIUContainer(new String[]{"bundle.a1", "bundle.a2"}, new String[]{"1.0.0", "1.0.0"}, null, 1); + IUBundleContainer c4 = (IUBundleContainer) service.newIUContainer(new String[]{"bundle.b1", "bundle.b2"}, new String[]{"1.0.0", "1.0.0"}, null, 0); assertFalse("Contents should not be equivalent", c3.isContentEqual(c4)); } @@ -356,7 +335,7 @@ * @throws Exception */ protected IUBundleContainer createContainer(IInstallableUnit[] units, URI[] repositories) throws Exception { - return (IUBundleContainer) getTargetService().newIUContainer(units, repositories); + return (IUBundleContainer) getTargetService().newIUContainer(units, repositories, IUBundleContainer.INCLUDE_REQUIRED); } /** @@ -473,7 +452,7 @@ infos = getBundleInfos(c2); names = collectAllSymbolicNames(infos); - bundleIds = new String[]{"bundle.b1", "bundle.b2", "bundle.b3"}; + bundleIds = new String[]{"bundle.a1", "bundle.a2", "bundle.a3", "bundle.b1", "bundle.b2", "bundle.b3"}; assertEquals(bundleIds.length, infos.size()); for (int i = 0; i < bundleIds.length; i++) { Index: src/org/eclipse/pde/ui/tests/target/TargetDefinitionPersistenceTests.java =================================================================== RCS file: /cvsroot/eclipse/pde/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/target/TargetDefinitionPersistenceTests.java,v retrieving revision 1.13 diff -u -r1.13 TargetDefinitionPersistenceTests.java --- src/org/eclipse/pde/ui/tests/target/TargetDefinitionPersistenceTests.java 25 Feb 2010 19:44:40 -0000 1.13 +++ src/org/eclipse/pde/ui/tests/target/TargetDefinitionPersistenceTests.java 30 Nov 2010 21:03:59 -0000 @@ -236,12 +236,8 @@ IBundleContainer restrictedProfileContainer = getTargetService().newProfileContainer(TargetPlatform.getDefaultLocation(), null); // Site bundle containers with different settings - IUBundleContainer siteContainer = (IUBundleContainer)getTargetService().newIUContainer(new IInstallableUnit[]{}, new URI[]{new URI("TESTURI"), new URI("TESTURI2")}); - siteContainer.setIncludeAllRequired(false, null); - siteContainer.setIncludeAllEnvironments(true, null); - IUBundleContainer siteContainer2 = (IUBundleContainer)getTargetService().newIUContainer(new String[]{"unit1","unit2"},new String[]{"1.0", "2.0"}, new URI[]{new URI("TESTURI"), new URI("TESTURI2")}); - siteContainer2.setIncludeAllRequired(true, null); - siteContainer2.setIncludeAllEnvironments(false, null); + IUBundleContainer siteContainer = (IUBundleContainer)getTargetService().newIUContainer(new IInstallableUnit[]{}, new URI[]{new URI("TESTURI"), new URI("TESTURI2")}, IUBundleContainer.INCLUDE_ALL_ENVIRONMENTS); + IUBundleContainer siteContainer2 = (IUBundleContainer)getTargetService().newIUContainer(new String[]{"unit1","unit2"},new String[]{"1.0", "2.0"}, new URI[]{new URI("TESTURI"), new URI("TESTURI2")}, IUBundleContainer.INCLUDE_REQUIRED); NameVersionDescriptor[] restrictions = new NameVersionDescriptor[]{ new NameVersionDescriptor("org.eclipse.jdt.launching", null), Index: src/org/eclipse/pde/ui/tests/target/TargetDefinitionResolutionTests.java =================================================================== RCS file: /cvsroot/eclipse/pde/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/target/TargetDefinitionResolutionTests.java,v retrieving revision 1.16 diff -u -r1.16 TargetDefinitionResolutionTests.java --- src/org/eclipse/pde/ui/tests/target/TargetDefinitionResolutionTests.java 9 Nov 2010 15:40:15 -0000 1.16 +++ src/org/eclipse/pde/ui/tests/target/TargetDefinitionResolutionTests.java 30 Nov 2010 21:03:59 -0000 @@ -594,47 +594,49 @@ */ public void testSiteContainerIncludeSettings() throws Exception{ ITargetDefinition target = getNewTarget(); - IUBundleContainer containerA = (IUBundleContainer)getTargetService().newIUContainer(new IInstallableUnit[0], null); - IUBundleContainer containerB = (IUBundleContainer)getTargetService().newIUContainer(new String[]{"unit1", "unit2"}, new String[]{"1.0","2.0"}, null); + IUBundleContainer containerA = (IUBundleContainer)getTargetService().newIUContainer(new IInstallableUnit[0], null, IUBundleContainer.INCLUDE_REQUIRED); + IUBundleContainer containerB = (IUBundleContainer)getTargetService().newIUContainer(new String[]{"unit1", "unit2"}, new String[]{"1.0","2.0"}, null, IUBundleContainer.INCLUDE_REQUIRED); target.setBundleContainers(new IBundleContainer[]{containerA, containerB}); // Check default settings assertTrue(containerA.getIncludeAllRequired()); assertFalse(containerA.getIncludeAllEnvironments()); + assertFalse(containerA.getIncludeSource()); assertTrue(containerB.getIncludeAllRequired()); assertFalse(containerB.getIncludeAllEnvironments()); + assertFalse(containerB.getIncludeSource()); // Check basic changes - containerA.setIncludeAllRequired(false, null); - containerA.setIncludeAllEnvironments(true, null); + int flags = IUBundleContainer.INCLUDE_ALL_ENVIRONMENTS | IUBundleContainer.INCLUDE_SOURCE; + containerA = (IUBundleContainer)getTargetService().newIUContainer(new IInstallableUnit[0], null, flags); + containerB = (IUBundleContainer)getTargetService().newIUContainer(new String[]{"unit1", "unit2"}, new String[]{"1.0","2.0"}, null, flags); + target.setBundleContainers(new IBundleContainer[]{containerA, containerB}); assertFalse(containerA.getIncludeAllRequired()); assertTrue(containerA.getIncludeAllEnvironments()); - containerA.setIncludeAllEnvironments(false, null); - containerA.setIncludeAllRequired(true, null); - assertTrue(containerA.getIncludeAllRequired()); - assertFalse(containerA.getIncludeAllEnvironments()); + assertTrue(containerA.getIncludeSource()); // Check that all containers are updated in the target if target is passed as argument - containerA.setIncludeAllRequired(false, target); - assertFalse(containerA.getIncludeAllRequired()); - assertFalse(containerA.getIncludeAllEnvironments()); - assertFalse(containerB.getIncludeAllRequired()); - assertFalse(containerB.getIncludeAllEnvironments()); - containerB.setIncludeAllRequired(true, target); + flags = IUBundleContainer.INCLUDE_ALL_ENVIRONMENTS | IUBundleContainer.INCLUDE_SOURCE; + containerA = (IUBundleContainer)getTargetService().newIUContainer(new IInstallableUnit[0], null, flags); + flags = IUBundleContainer.INCLUDE_REQUIRED; + containerB = (IUBundleContainer)getTargetService().newIUContainer(new String[]{"unit1", "unit2"}, new String[]{"1.0","2.0"}, null, flags); + + target.setBundleContainers(new IBundleContainer[]{containerA, containerB}); assertTrue(containerA.getIncludeAllRequired()); assertFalse(containerA.getIncludeAllEnvironments()); + assertFalse(containerA.getIncludeSource()); assertTrue(containerB.getIncludeAllRequired()); assertFalse(containerB.getIncludeAllEnvironments()); - containerA.setIncludeAllEnvironments(true, target); - assertTrue(containerA.getIncludeAllRequired()); + assertFalse(containerB.getIncludeSource()); + + // now switch the order of A and B + target.setBundleContainers(new IBundleContainer[]{containerB, containerA}); + assertFalse(containerA.getIncludeAllRequired()); assertTrue(containerA.getIncludeAllEnvironments()); - assertTrue(containerB.getIncludeAllRequired()); + assertTrue(containerA.getIncludeSource()); + assertFalse(containerB.getIncludeAllRequired()); assertTrue(containerB.getIncludeAllEnvironments()); - containerB.setIncludeAllEnvironments(false, target); - assertTrue(containerA.getIncludeAllRequired()); - assertFalse(containerA.getIncludeAllEnvironments()); - assertTrue(containerB.getIncludeAllRequired()); - assertFalse(containerB.getIncludeAllEnvironments()); + assertTrue(containerB.getIncludeSource()); } public void testNameVersionDescriptor() {