blob: 375d6b032e555aba2ad2126dd516ff755bb6d166 [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.internal.p2.director;
import java.util.*;
import org.eclipse.core.runtime.*;
import org.eclipse.equinox.internal.p2.core.helpers.LogHelper;
import org.eclipse.equinox.internal.provisional.p2.metadata.*;
import org.eclipse.equinox.internal.provisional.p2.metadata.query.CapabilityQuery;
import org.eclipse.equinox.internal.provisional.p2.query.Collector;
import org.eclipse.equinox.internal.provisional.p2.query.IQueryable;
import org.eclipse.osgi.util.NLS;
import org.osgi.framework.InvalidSyntaxException;
public class Slicer {
private static boolean DEBUG = false;
private IQueryable possibilites;
private LinkedList toProcess;
private Set considered; //IUs to add to the slice
private TwoTierMap slice; //The IUs that have been considered to be part of the problem
private Dictionary selectionContext;
private MultiStatus result;
public Slicer(IQueryable input, Dictionary context) {
possibilites = input;
slice = new TwoTierMap();
selectionContext = context;
result = new MultiStatus(DirectorActivator.PI_DIRECTOR, IStatus.OK, Messages.Planner_Problems_resolving_plan, null);
}
public Slicer(IInstallableUnit[] installRoots, IInstallableUnit[] gatherAvailableInstallableUnits, Dictionary selectionContext) {
this(new QueryableArray(gatherAvailableInstallableUnits), selectionContext);
}
public IQueryable slice(IInstallableUnit[] ius, IProgressMonitor monitor) {
try {
long start = 0;
if (DEBUG) {
start = System.currentTimeMillis();
System.out.println("Start slicing: " + start); //$NON-NLS-1$
}
validateInput(ius);
considered = new HashSet(Arrays.asList(ius));
toProcess = new LinkedList(considered);
while (!toProcess.isEmpty())
processIU((IInstallableUnit) toProcess.removeFirst());
if (DEBUG) {
long stop = System.currentTimeMillis();
System.out.println("Slicing complete: " + (stop - start)); //$NON-NLS-1$
}
} catch (IllegalStateException e) {
result.add(new Status(IStatus.ERROR, DirectorActivator.PI_DIRECTOR, e.getMessage(), e));
}
if (!result.isOK())
LogHelper.log(result);
if (result.getSeverity() == IStatus.ERROR)
return null;
return new QueryableArray((IInstallableUnit[]) considered.toArray(new IInstallableUnit[considered.size()]));
}
public MultiStatus getStatus() {
return result;
}
//This is a shortcut to simplify the error reporting when the filter of the ius we are being asked to install does not pass
private void validateInput(IInstallableUnit[] ius) {
for (int i = 0; i < ius.length; i++) {
if (!isApplicable(ius[i]))
throw new IllegalStateException("The IU " + ius[i] + " can't be installed in this environment because its filter does not match."); //$NON-NLS-1$//$NON-NLS-2$
}
}
// Check whether the requirement is applicable
private boolean isApplicable(RequiredCapability req) {
String filter = req.getFilter();
if (filter == null)
return true;
try {
return DirectorActivator.context.createFilter(filter).match(selectionContext);
} catch (InvalidSyntaxException e) {
return false;
}
}
private boolean isApplicable(IInstallableUnit iu) {
String enablementFilter = iu.getFilter();
if (enablementFilter == null)
return true;
try {
return DirectorActivator.context.createFilter(enablementFilter).match(selectionContext);
} catch (InvalidSyntaxException e) {
return false;
}
}
private void processIU(IInstallableUnit iu) {
iu = iu.unresolved();
slice.put(iu.getId(), iu.getVersion(), iu);
if (!isApplicable(iu)) {
return;
}
RequiredCapability[] reqs = getRequiredCapabilities(iu);
if (reqs.length == 0) {
return;
}
for (int i = 0; i < reqs.length; i++) {
if (!isApplicable(reqs[i]))
continue;
if (!reqs[i].isGreedy()) {
continue;
}
expandRequirement(iu, reqs[i]);
}
}
private RequiredCapability[] getRequiredCapabilities(IInstallableUnit iu) {
if (!(iu instanceof IInstallableUnitPatch)) {
return iu.getRequiredCapabilities();
}
RequiredCapability[] aggregatedCapabilities;
IInstallableUnitPatch patchIU = (IInstallableUnitPatch) iu;
RequirementChange[] changes = patchIU.getRequirementsChange();
int initialRequirementCount = iu.getRequiredCapabilities().length;
aggregatedCapabilities = new RequiredCapability[initialRequirementCount + changes.length];
System.arraycopy(iu.getRequiredCapabilities(), 0, aggregatedCapabilities, 0, initialRequirementCount);
for (int i = 0; i < changes.length; i++) {
aggregatedCapabilities[initialRequirementCount++] = changes[i].newValue();
}
return aggregatedCapabilities;
}
private void expandRequirement(IInstallableUnit iu, RequiredCapability req) {
Collector matches = possibilites.query(new CapabilityQuery(req), new Collector(), null);
int validMatches = 0;
for (Iterator iterator = matches.iterator(); iterator.hasNext();) {
IInstallableUnit match = (IInstallableUnit) iterator.next();
if (!isApplicable(match))
continue;
validMatches++;
if (!slice.containsKey(match.getId(), match.getVersion()))
consider(match);
}
if (validMatches == 0) {
if (req.isOptional()) {
if (DEBUG)
System.out.println("No IU found to satisfy optional dependency of " + iu + " on req " + req); //$NON-NLS-1$//$NON-NLS-2$
} else {
result.add(new Status(IStatus.WARNING, DirectorActivator.PI_DIRECTOR, NLS.bind(Messages.Planner_Unsatisfied_dependency, iu, req)));
}
}
}
private void consider(IInstallableUnit match) {
if (considered.add(match))
toProcess.addLast(match);
}
}