blob: f5cd7da1d60f790fc5a2f3c34cb5287ca85ff573 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009, 2020 Daniel Le Berre and others.
*
* This
* program and the accompanying materials are made available under the terms of
* the Eclipse Public License 2.0 which accompanies this distribution, and is
* available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Daniel Le Berre - initial API and implementation
* Red Hat, Inc. - support for remediation page
******************************************************************************/
package org.eclipse.equinox.internal.p2.director;
import java.math.BigInteger;
import java.util.*;
import org.eclipse.equinox.internal.p2.director.Projector.AbstractVariable;
import org.eclipse.equinox.p2.metadata.*;
import org.eclipse.equinox.p2.query.*;
import org.sat4j.pb.tools.*;
import org.sat4j.specs.ContradictionException;
public class UserDefinedOptimizationFunction extends OptimizationFunction {
private Collection<IInstallableUnit> alreadyExistingRoots;
private SteppedTimeoutLexicoHelper<Object, Explanation> dependencyHelper;
private IQueryable<IInstallableUnit> picker;
public UserDefinedOptimizationFunction(IQueryable<IInstallableUnit> lastState, List<AbstractVariable> abstractVariables, List<AbstractVariable> optionalVariables, IQueryable<IInstallableUnit> picker, IInstallableUnit selectionContext, Map<String, Map<Version, IInstallableUnit>> slice, DependencyHelper<Object, Explanation> dependencyHelper, Collection<IInstallableUnit> alreadyInstalledIUs) {
super(lastState, abstractVariables, optionalVariables, picker, selectionContext, slice);
this.picker = picker;
this.slice = slice;
this.dependencyHelper = (SteppedTimeoutLexicoHelper<Object, Explanation>) dependencyHelper;
this.alreadyExistingRoots = alreadyInstalledIUs;
}
@Override
public List<WeightedObject<? extends Object>> createOptimizationFunction(IInstallableUnit metaIu, Collection<IInstallableUnit> newRoots) {
List<WeightedObject<?>> weightedObjects = new ArrayList<>();
List<Object> objects = new ArrayList<>();
BigInteger weight = BigInteger.valueOf(slice.size() + 1);
String[] criterias = new String[] {"+new", "-notuptodate", "-changed", "-removed"}; //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$//$NON-NLS-4$
BigInteger currentWeight = weight.pow(criterias.length - 1);
boolean maximizes;
Object thing;
for (String criteria : criterias) {
if (criteria.endsWith("new")) { //$NON-NLS-1$
weightedObjects.clear();
newRoots(weightedObjects, criteria.startsWith("+") ? currentWeight.negate() : currentWeight, metaIu); //$NON-NLS-1$
currentWeight = currentWeight.divide(weight);
} else if (criteria.endsWith("removed")) { //$NON-NLS-1$
weightedObjects.clear();
removedRoots(weightedObjects, criteria.startsWith("+") ? currentWeight.negate() : currentWeight, metaIu); //$NON-NLS-1$
currentWeight = currentWeight.divide(weight);
} else if (criteria.endsWith("notuptodate")) { //$NON-NLS-1$
weightedObjects.clear();
notuptodate(weightedObjects, criteria.startsWith("+") ? currentWeight.negate() : currentWeight, metaIu); //$NON-NLS-1$
currentWeight = currentWeight.divide(weight);
} else if (criteria.endsWith("changed")) { //$NON-NLS-1$
weightedObjects.clear();
changedRoots(weightedObjects, criteria.startsWith("+") ? currentWeight.negate() : currentWeight, metaIu); //$NON-NLS-1$
currentWeight = currentWeight.divide(weight);
}
objects.clear();
maximizes = criteria.startsWith("+"); //$NON-NLS-1$
for (WeightedObject<?> weightedObject : weightedObjects) {
thing = weightedObject.thing;
if (maximizes) {
thing = dependencyHelper.not(thing);
}
objects.add(thing);
}
dependencyHelper.addCriterion(objects);
}
weightedObjects.clear();
return null;
}
protected void changedRoots(List<WeightedObject<?>> weightedObjects, BigInteger weight, IInstallableUnit entryPointIU) {
Collection<IRequirement> requirements = entryPointIU.getRequirements();
for (IRequirement req : requirements) {
IQuery<IInstallableUnit> query = QueryUtil.createMatchQuery(req.getMatches());
IQueryResult<IInstallableUnit> matches = picker.query(query, null);
Object[] changed = new Object[matches.toUnmodifiableSet().size()];
int i = 0;
for (IInstallableUnit match : matches) {
changed[i++] = isInstalledAsRoot(match) ? dependencyHelper.not(match) : match;
}
try {
Projector.AbstractVariable abs = new Projector.AbstractVariable("CHANGED"); //$NON-NLS-1$
dependencyHelper.or(FakeExplanation.getInstance(), abs, changed);
weightedObjects.add(WeightedObject.newWO(abs, weight));
} catch (ContradictionException e) {
// TODO Auto-generated catch block TODO
e.printStackTrace();
}
}
}
protected void newRoots(List<WeightedObject<?>> weightedObjects, BigInteger weight, IInstallableUnit entryPointIU) {
Collection<IRequirement> requirements = entryPointIU.getRequirements();
for (IRequirement req : requirements) {
IQuery<IInstallableUnit> query = QueryUtil.createMatchQuery(req.getMatches());
IQueryResult<IInstallableUnit> matches = picker.query(query, null);
boolean oneInstalled = false;
for (IInstallableUnit match : matches) {
oneInstalled = oneInstalled || isInstalledAsRoot(match);
}
if (!oneInstalled) {
try {
Projector.AbstractVariable abs = new Projector.AbstractVariable("NEW"); //$NON-NLS-1$
dependencyHelper.or(FakeExplanation.getInstance(), abs, (Object[]) matches.toArray(IInstallableUnit.class));
weightedObjects.add(WeightedObject.newWO(abs, weight));
} catch (ContradictionException e) {
// should not happen
e.printStackTrace();
}
}
}
}
protected void removedRoots(List<WeightedObject<?>> weightedObjects, BigInteger weight, IInstallableUnit entryPointIU) {
Collection<IRequirement> requirements = entryPointIU.getRequirements();
for (IRequirement req : requirements) {
IQuery<IInstallableUnit> query = QueryUtil.createMatchQuery(req.getMatches());
IQueryResult<IInstallableUnit> matches = picker.query(query, null);
boolean installed = false;
Object[] literals = new Object[matches.toUnmodifiableSet().size()];
int i = 0;
for (IInstallableUnit match : matches) {
installed = installed || isInstalledAsRoot(match);
literals[i++] = dependencyHelper.not(match);
}
if (installed) {
try {
Projector.AbstractVariable abs = new Projector.AbstractVariable("REMOVED"); //$NON-NLS-1$
dependencyHelper.and(FakeExplanation.getInstance(), abs, literals);
weightedObjects.add(WeightedObject.newWO(abs, weight));
} catch (ContradictionException e) {
// should not happen TODO
e.printStackTrace();
}
}
}
}
protected void notuptodate(List<WeightedObject<?>> weightedObjects, BigInteger weight, IInstallableUnit entryPointIU) {
Collection<IRequirement> requirements = entryPointIU.getRequirements();
for (IRequirement req : requirements) {
IQuery<IInstallableUnit> query = QueryUtil.createMatchQuery(req.getMatches());
IQueryResult<IInstallableUnit> matches = picker.query(query, null);
List<IInstallableUnit> toSort = new ArrayList<>(matches.toUnmodifiableSet());
toSort.sort(Collections.reverseOrder());
if (toSort.isEmpty())
continue;
Projector.AbstractVariable abs = new Projector.AbstractVariable();
Object notlatest = dependencyHelper.not(toSort.get(0));
try {
// notuptodate <=> not iuvn and (iuv1 or iuv2 or ... iuvn-1)
dependencyHelper.implication(new Object[] {abs}).implies(notlatest).named(FakeExplanation.getInstance());
Object[] clause = new Object[toSort.size()];
toSort.toArray(clause);
clause[0] = dependencyHelper.not(abs);
dependencyHelper.clause(FakeExplanation.getInstance(), clause);
for (int i = 1; i < toSort.size(); i++) {
dependencyHelper.implication(new Object[] {notlatest, toSort.get(i)}).implies(abs).named(FakeExplanation.getInstance());
}
} catch (ContradictionException e) {
// should never happen
e.printStackTrace();
}
weightedObjects.add(WeightedObject.newWO(abs, weight));
}
}
private static class FakeExplanation extends Explanation {
private static Explanation singleton = new FakeExplanation();
public static Explanation getInstance() {
return singleton;
}
@Override
protected int orderValue() {
return Explanation.OTHER_REASON;
}
@Override
public int shortAnswer() {
return 0;
}
}
private boolean isInstalledAsRoot(IInstallableUnit isInstalled) {
for (IInstallableUnit installed : alreadyExistingRoots) {
if (isInstalled.equals(installed))
return true;
}
return false;
}
}