blob: f55018586f66099cb147c0d7c8b848f9715f7e68 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2007 IBM Corporation and others. All rights reserved. This
* program and the accompanying materials are made available under the terms of
* the Eclipse Public License v1.0 which accompanies this distribution, and is
* available at http://www.eclipse.org/legal/epl-v10.html
*
* Contributors: IBM Corporation - initial API and implementation
******************************************************************************/
package org.eclipse.equinox.p2.director;
import java.util.*;
import org.eclipse.core.runtime.*;
import org.eclipse.equinox.internal.p2.director.*;
import org.eclipse.equinox.p2.core.helpers.ServiceHelper;
import org.eclipse.equinox.p2.engine.Operand;
import org.eclipse.equinox.p2.engine.Profile;
import org.eclipse.equinox.p2.metadata.IInstallableUnit;
import org.eclipse.equinox.p2.metadata.IInstallableUnitConstants;
import org.eclipse.equinox.p2.metadata.repository.IMetadataRepository;
import org.eclipse.equinox.p2.metadata.repository.IMetadataRepositoryManager;
import org.eclipse.equinox.p2.resolution.ResolutionHelper;
import org.eclipse.osgi.service.resolver.VersionRange;
import org.eclipse.osgi.util.NLS;
public class SimplePlanner implements IPlanner {
static final int ExpandWork = 10;
public ProvisioningPlan getInstallPlan(IInstallableUnit[] installRoots, Profile profile, IProgressMonitor monitor) {
SubMonitor sub = SubMonitor.convert(monitor, ExpandWork);
sub.setTaskName(Messages.Director_Task_Resolving_Dependencies);
try {
MultiStatus result = new MultiStatus(DirectorActivator.PI_DIRECTOR, 1, Messages.Director_Install_Problems, null);
// Get the list of ius installed in the profile we are installing into
IInstallableUnit[] alreadyInstalled = toArray(profile.getInstallableUnits());
// If any of these are already installed, return a warning status
// specifying that they are already installed.
for (int i = 0; i < installRoots.length; i++)
for (int j = 0; j < alreadyInstalled.length; j++)
if (installRoots[i].equals(alreadyInstalled[j]))
result.merge(new Status(IStatus.WARNING, DirectorActivator.PI_DIRECTOR, NLS.bind(Messages.Director_Already_Installed, installRoots[i].getId())));
if (!result.isOK()) {
return new ProvisioningPlan(result);
}
//Compute the complete closure of things to install to successfully install the installRoots.
NewDependencyExpander expander = new NewDependencyExpander(installRoots, alreadyInstalled, gatherAvailableInstallableUnits(installRoots), profile, true);
// NewDependencyExpander expander = new NewDependencyExpander(installRoots, alreadyInstalled, gatherAvailableInstallableUnits(), profile, true);
IStatus expanderResult = expander.expand(sub.newChild(ExpandWork));
if (!expanderResult.isOK()) {
result.merge(expanderResult);
return new ProvisioningPlan(result);
}
ResolutionHelper oldStateHelper = new ResolutionHelper(profile.getSelectionContext(), null);
Collection oldState = oldStateHelper.attachCUs(Arrays.asList(alreadyInstalled));
List oldStateOrder = oldStateHelper.getSorted();
ResolutionHelper newStateHelper = new ResolutionHelper(profile.getSelectionContext(), expander.getRecommendations());
Collection newState = newStateHelper.attachCUs(expander.getAllInstallableUnits());
List newStateOrder = newStateHelper.getSorted();
return new ProvisioningPlan(Status.OK_STATUS, generateOperations(oldState, newState, oldStateOrder, newStateOrder));
} finally {
sub.done();
}
}
private Operand[] generateOperations(Collection fromState, Collection toState, List fromStateOrder, List newStateOrder) {
return sortOperations(new OperationGenerator().generateOperation(fromState, toState), newStateOrder, fromStateOrder);
}
private Operand[] sortOperations(Operand[] toSort, List installOrder, List uninstallOrder) {
List updateOp = new ArrayList();
for (int i = 0; i < toSort.length; i++) {
Operand op = toSort[i];
if (op.first() == null && op.second() != null) {
installOrder.set(installOrder.indexOf(op.second()), op);
continue;
}
if (op.first() != null && op.second() == null) {
uninstallOrder.set(uninstallOrder.indexOf(op.first()), op);
continue;
}
if (op.first() != null && op.second() != null) {
updateOp.add(op);
continue;
}
}
int i = 0;
for (Iterator iterator = installOrder.iterator(); iterator.hasNext();) {
Object elt = iterator.next();
if (elt instanceof Operand) {
toSort[i++] = (Operand) elt;
}
}
for (Iterator iterator = uninstallOrder.iterator(); iterator.hasNext();) {
Object elt = iterator.next();
if (elt instanceof Operand) {
toSort[i++] = (Operand) elt;
}
}
for (Iterator iterator = updateOp.iterator(); iterator.hasNext();) {
Object elt = iterator.next();
if (elt instanceof Operand) {
toSort[i++] = (Operand) elt;
}
}
return toSort;
}
public ProvisioningPlan getBecomePlan(IInstallableUnit target, Profile profile, IProgressMonitor monitor) {
SubMonitor sub = SubMonitor.convert(monitor, ExpandWork);
sub.setTaskName(Messages.Director_Task_Resolving_Dependencies);
try {
MultiStatus result = new MultiStatus(DirectorActivator.PI_DIRECTOR, 1, Messages.Director_Become_Problems, null);
if (!Boolean.valueOf(target.getProperty(IInstallableUnitConstants.PROFILE_IU_KEY)).booleanValue()) {
result.add(new Status(IStatus.ERROR, DirectorActivator.PI_DIRECTOR, NLS.bind(Messages.Director_Unexpected_IU, target.getId())));
return new ProvisioningPlan(result);
}
//TODO Here we need to deal with the change of properties between the two profiles
//Also if the profile changes (locations are being modified, etc), should not we do a full uninstall then an install?
//Maybe it depends on the kind of changes in a profile
//We need to get all the ius that were part of the profile and give that to be what to become
NewDependencyExpander toExpander = new NewDependencyExpander(new IInstallableUnit[] {target}, null, gatherAvailableInstallableUnits(new IInstallableUnit[] {target}), profile, true);
toExpander.expand(sub.newChild(ExpandWork));
ResolutionHelper newStateHelper = new ResolutionHelper(profile.getSelectionContext(), toExpander.getRecommendations());
Collection newState = newStateHelper.attachCUs(toExpander.getAllInstallableUnits());
newState.remove(target);
Iterator it = profile.getInstallableUnits();
Collection oldIUs = new HashSet();
for (; it.hasNext();) {
oldIUs.add(it.next());
}
ResolutionHelper oldStateHelper = new ResolutionHelper(profile.getSelectionContext(), null);
Collection oldState = oldStateHelper.attachCUs(oldIUs);
return new ProvisioningPlan(Status.OK_STATUS, generateOperations(oldState, newState, oldStateHelper.getSorted(), newStateHelper.getSorted()));
} finally {
sub.done();
}
}
private IInstallableUnit[] inProfile(IInstallableUnit[] toFind, Profile profile, boolean found, IProgressMonitor monitor) {
ArrayList result = new ArrayList(toFind.length);
for (int i = 0; i < toFind.length; i++) {
if (profile.query(toFind[i].getId(), new VersionRange(toFind[i].getVersion(), true, toFind[i].getVersion(), true), null, false, monitor).length > 0) {
if (found)
result.add(toFind[i]);
} else {
if (!found)
result.add(toFind[i]);
}
}
return (IInstallableUnit[]) result.toArray(new IInstallableUnit[result.size()]);
}
public ProvisioningPlan getUninstallPlan(IInstallableUnit[] uninstallRoots, Profile profile, IProgressMonitor monitor) {
SubMonitor sub = SubMonitor.convert(monitor, ExpandWork);
sub.setTaskName(Messages.Director_Task_Resolving_Dependencies);
try {
IInstallableUnit[] toReallyUninstall = inProfile(uninstallRoots, profile, true, sub.newChild(0));
if (toReallyUninstall.length == 0) {
return new ProvisioningPlan(new Status(IStatus.OK, DirectorActivator.PI_DIRECTOR, Messages.Director_Nothing_To_Uninstall));
} else if (toReallyUninstall.length != uninstallRoots.length) {
uninstallRoots = toReallyUninstall;
}
MultiStatus result = new MultiStatus(DirectorActivator.PI_DIRECTOR, 1, Messages.Director_Uninstall_Problems, null);
IInstallableUnit[] alreadyInstalled = toArray(profile.getInstallableUnits());
ResolutionHelper oldStateHelper = new ResolutionHelper(profile.getSelectionContext(), null);
Collection oldState = oldStateHelper.attachCUs(Arrays.asList(alreadyInstalled));
NewDependencyExpander expander = new NewDependencyExpander(uninstallRoots, new IInstallableUnit[0], alreadyInstalled, profile, true);
expander.expand(sub.newChild(ExpandWork / 2));
Collection toUninstallClosure = new ResolutionHelper(profile.getSelectionContext(), null).attachCUs(expander.getAllInstallableUnits());
Collection remainingIUs = new HashSet(oldState);
remainingIUs.removeAll(toUninstallClosure);
NewDependencyExpander finalExpander = new NewDependencyExpander(null, (IInstallableUnit[]) remainingIUs.toArray(new IInstallableUnit[remainingIUs.size()]), gatherAvailableInstallableUnits(uninstallRoots), profile, true);
finalExpander.expand(sub.newChild(ExpandWork / 2));
ResolutionHelper newStateHelper = new ResolutionHelper(profile.getSelectionContext(), null);
Collection newState = newStateHelper.attachCUs(finalExpander.getAllInstallableUnits());
for (int i = 0; i < uninstallRoots.length; i++) {
if (newState.contains(uninstallRoots[i]))
result.add(new Status(IStatus.ERROR, DirectorActivator.PI_DIRECTOR, NLS.bind(Messages.Director_Cannot_Uninstall, uninstallRoots[i])));
}
if (!result.isOK())
return new ProvisioningPlan(result);
return new ProvisioningPlan(Status.OK_STATUS, generateOperations(oldState, newState, oldStateHelper.getSorted(), newStateHelper.getSorted()));
} finally {
sub.done();
}
}
protected IInstallableUnit[] gatherAvailableInstallableUnits(IInstallableUnit[] additionalSource) {
IMetadataRepositoryManager repoMgr = (IMetadataRepositoryManager) ServiceHelper.getService(DirectorActivator.context, IMetadataRepositoryManager.class.getName());
IMetadataRepository[] repos = repoMgr.getKnownRepositories();
List results = new ArrayList();
if (additionalSource != null) {
for (int i = 0; i < additionalSource.length; i++) {
results.add(additionalSource[i]);
}
}
for (int i = 0; i < repos.length; i++) {
results.addAll(Arrays.asList(repos[i].getInstallableUnits(null)));
}
return (IInstallableUnit[]) results.toArray(new IInstallableUnit[results.size()]);
}
public ProvisioningPlan getReplacePlan(IInstallableUnit[] toUninstall, IInstallableUnit[] toInstall, Profile profile, IProgressMonitor monitor) {
SubMonitor sub = SubMonitor.convert(monitor, ExpandWork);
sub.setTaskName(Messages.Director_Task_Resolving_Dependencies);
try {
//find the things being updated in the profile
IInstallableUnit[] alreadyInstalled = toArray(profile.getInstallableUnits());
IInstallableUnit[] uninstallRoots = toUninstall;
//compute the transitive closure and remove them.
ResolutionHelper oldStateHelper = new ResolutionHelper(profile.getSelectionContext(), null);
Collection oldState = oldStateHelper.attachCUs(Arrays.asList(alreadyInstalled));
NewDependencyExpander expander = new NewDependencyExpander(uninstallRoots, new IInstallableUnit[0], alreadyInstalled, profile, true);
expander.expand(sub.newChild(ExpandWork / 2));
Collection toUninstallClosure = new ResolutionHelper(profile.getSelectionContext(), null).attachCUs(expander.getAllInstallableUnits());
//add the new set.
Collection remainingIUs = new HashSet(oldState);
remainingIUs.removeAll(toUninstallClosure);
// for (int i = 0; i < updateRoots.length; i++) {
// remainingIUs.add(updateRoots[i]);
// }
NewDependencyExpander finalExpander = new NewDependencyExpander(toInstall, (IInstallableUnit[]) remainingIUs.toArray(new IInstallableUnit[remainingIUs.size()]), gatherAvailableInstallableUnits(null), profile, true);
finalExpander.expand(sub.newChild(ExpandWork / 2));
ResolutionHelper newStateHelper = new ResolutionHelper(profile.getSelectionContext(), null);
Collection newState = newStateHelper.attachCUs(finalExpander.getAllInstallableUnits());
return new ProvisioningPlan(Status.OK_STATUS, generateOperations(oldState, newState, oldStateHelper.getSorted(), newStateHelper.getSorted()));
} finally {
sub.done();
}
}
public IInstallableUnit[] updatesFor(IInstallableUnit toUpdate) {
IInstallableUnit[] allius = gatherAvailableInstallableUnits(null);
Set updates = new HashSet();
for (int i = 0; i < allius.length; i++) {
if (toUpdate.getId().equals(allius[i].getProperty(IInstallableUnitConstants.UPDATE_FROM))) {
if (toUpdate.getVersion().compareTo(allius[i].getVersion()) < 0 && new VersionRange(allius[i].getProperty(IInstallableUnitConstants.UPDATE_RANGE)).isIncluded(toUpdate.getVersion()))
updates.add(allius[i]);
}
}
return (IInstallableUnit[]) updates.toArray(new IInstallableUnit[updates.size()]);
}
//TODO This is really gross!!!!! We need to make things uniform
private IInstallableUnit[] toArray(Iterator it) {
ArrayList result = new ArrayList();
while (it.hasNext()) {
result.add(it.next());
}
return (IInstallableUnit[]) result.toArray(new IInstallableUnit[result.size()]);
}
public ProvisioningPlan getRevertPlan(IInstallableUnit previous, Profile profile, IProgressMonitor monitor) {
return getBecomePlan(previous, profile, monitor);
}
}