Skip to content

Commit

Permalink
eclipse-tycho#462 - Allow to resolve with missing requirements and re…
Browse files Browse the repository at this point in the history
…cord those

Signed-off-by: Christoph Läubrich <laeubi@laeubi-soft.de>
  • Loading branch information
laeubi committed Jan 2, 2022
1 parent 8712fe5 commit d474649
Show file tree
Hide file tree
Showing 4 changed files with 125 additions and 14 deletions.
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2008, 2011 Sonatype Inc. and others.
* Copyright (c) 2008, 2022 Sonatype Inc. 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
Expand All @@ -9,26 +9,33 @@
*
* Contributors:
* Sonatype Inc. - initial API and implementation
* Christoph Läubrich - #462 - Delay Pom considered items to the final Target Platform calculation
*******************************************************************************/
package org.eclipse.tycho.p2.util.resolution;

import static org.eclipse.tycho.p2.util.resolution.ResolverDebugUtils.toDebugString;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.MultiStatus;
import org.eclipse.equinox.internal.p2.director.Slicer;
import org.eclipse.equinox.internal.p2.metadata.IRequiredCapability;
import org.eclipse.equinox.internal.p2.metadata.RequiredCapability;
import org.eclipse.equinox.p2.metadata.IInstallableUnit;
import org.eclipse.equinox.p2.metadata.IProvidedCapability;
import org.eclipse.equinox.p2.metadata.IRequirement;
import org.eclipse.equinox.p2.metadata.MetadataFactory;
import org.eclipse.equinox.p2.metadata.MetadataFactory.InstallableUnitDescription;
import org.eclipse.equinox.p2.metadata.Version;
import org.eclipse.equinox.p2.metadata.VersionRange;
import org.eclipse.equinox.p2.metadata.expression.IMatchExpression;
import org.eclipse.equinox.p2.query.IQueryable;
import org.eclipse.tycho.core.shared.MavenLogger;
import org.eclipse.tycho.repository.p2base.metadata.QueryableCollection;
Expand All @@ -43,6 +50,11 @@ protected AbstractSlicerResolutionStrategy(MavenLogger logger) {

protected final IQueryable<IInstallableUnit> slice(Map<String, String> properties, IProgressMonitor monitor)
throws ResolverException {
return slice(properties, Collections.emptyList(), monitor);
}

protected final IQueryable<IInstallableUnit> slice(Map<String, String> properties,
List<IInstallableUnit> additionalUnits, IProgressMonitor monitor) throws ResolverException {

if (logger.isExtendedDebugEnabled()) {
logger.debug("Properties: " + properties.toString());
Expand All @@ -62,6 +74,7 @@ protected final IQueryable<IInstallableUnit> slice(Map<String, String> propertie
Set<IInstallableUnit> availableIUs = new LinkedHashSet<>(data.getAvailableIUs());
availableIUs.addAll(data.getEEResolutionHints().getTemporaryAdditions());
availableIUs.addAll(data.getEEResolutionHints().getMandatoryUnits());
availableIUs.addAll(additionalUnits);

Set<IInstallableUnit> seedIUs = new LinkedHashSet<>(data.getRootIUs());
if (data.getAdditionalRequirements() != null && !data.getAdditionalRequirements().isEmpty()) {
Expand Down Expand Up @@ -115,6 +128,31 @@ protected static IInstallableUnit createUnitRequiring(String name, Collection<II
return MetadataFactory.createInstallableUnit(result);
}

protected IInstallableUnit createUnitProviding(String name, Collection<IRequirement> requirements) {

InstallableUnitDescription result = new MetadataFactory.InstallableUnitDescription();
String time = Long.toString(System.currentTimeMillis());
result.setId(name + "-" + time);
result.setVersion(Version.createOSGi(0, 0, 0, time));
for (IRequirement requirement : requirements) {
if (requirement instanceof IRequiredCapability) {
try {
IRequiredCapability capability = (IRequiredCapability) requirement;
String namespace = capability.getNamespace();
IMatchExpression<IInstallableUnit> matches = capability.getMatches();
String extractName = RequiredCapability.extractName(matches);
Version version = RequiredCapability.extractRange(matches).getMinimum();
IProvidedCapability providedCapability = MetadataFactory.createProvidedCapability(namespace,
extractName, version);
result.addProvidedCapabilities(Collections.singleton(providedCapability));
} catch (RuntimeException e) {
logger.debug("can't convert requirement " + requirement + " to capability: " + e.toString(), e);
}
}
}
return MetadataFactory.createInstallableUnit(result);
}

private static IRequirement createStrictRequirementTo(IInstallableUnit unit) {
VersionRange strictRange = new VersionRange(unit.getVersion(), true, unit.getVersion(), true);
int min = 1;
Expand Down
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2008, 2011 Sonatype Inc. and others.
* Copyright (c) 2008, 2022 Sonatype Inc. 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
Expand All @@ -9,6 +9,7 @@
*
* Contributors:
* Sonatype Inc. - initial API and implementation
* Christoph Läubrich - #462 - Delay Pom considered items to the final Target Platform calculation
*******************************************************************************/
package org.eclipse.tycho.p2.util.resolution;

Expand All @@ -27,6 +28,7 @@
import org.eclipse.core.runtime.MultiStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.equinox.internal.p2.director.Explanation;
import org.eclipse.equinox.internal.p2.director.Explanation.MissingIU;
import org.eclipse.equinox.internal.p2.director.Projector;
import org.eclipse.equinox.internal.p2.director.QueryableArray;
import org.eclipse.equinox.internal.p2.director.SimplePlanner;
Expand Down Expand Up @@ -63,10 +65,17 @@ protected boolean isSlicerError(MultiStatus slicerStatus) {
@Override
public Collection<IInstallableUnit> resolve(Map<String, String> properties, IProgressMonitor monitor)
throws ResolverException {
List<IInstallableUnit> additionalUnits = new ArrayList<>();
Collection<IInstallableUnit> newState = resolveInternal(properties, additionalUnits, monitor);
newState.removeAll(additionalUnits); //remove the tycho generated IUs if any
return newState;
}

protected Collection<IInstallableUnit> resolveInternal(Map<String, String> properties,
List<IInstallableUnit> additionalUnits, IProgressMonitor monitor) throws ResolverException {
Map<String, String> newSelectionContext = SimplePlanner.createSelectionContext(properties);

IQueryable<IInstallableUnit> slice = slice(properties, monitor);
IQueryable<IInstallableUnit> slice = slice(properties, additionalUnits, monitor);

Set<IInstallableUnit> seedUnits = new LinkedHashSet<>(data.getRootIUs());
List<IRequirement> seedRequires = new ArrayList<>();
Expand All @@ -80,14 +89,40 @@ public Collection<IInstallableUnit> resolve(Map<String, String> properties, IPro

Projector projector = new Projector(slice, newSelectionContext, new HashSet<IInstallableUnit>(), false);
projector.encode(createUnitRequiring("tycho", seedUnits, seedRequires),
EMPTY_IU_ARRAY /* alreadyExistingRoots */, new QueryableArray(EMPTY_IU_ARRAY) /* installedIUs */,
seedUnits /* newRoots */, monitor);
EMPTY_IU_ARRAY /* alreadyExistingRoots */,
new QueryableArray(EMPTY_IU_ARRAY) /* installedIUs */, seedUnits /* newRoots */, monitor);
IStatus s = projector.invokeSolver(monitor);
if (s.getSeverity() == IStatus.ERROR) {
Set<Explanation> explanation = projector.getExplanation(new NullProgressMonitor()); // suppress "Cannot complete the request. Generating details."
if (!data.failOnMissingRequirements()) {
List<IRequirement> missingRequirements = new ArrayList<>();
for (Explanation exp : explanation) {
if (exp instanceof MissingIU) {
MissingIU missingIU = (MissingIU) exp;
logger.debug("Recording missing requirement for IU " + missingIU.iu + ": " + missingIU.req);
data.addMissingRequirement(missingIU.req);
missingRequirements.add(missingIU.req);
} else {
if (logger.isExtendedDebugEnabled()) {
logger.debug("Ignoring Explanation of type " + exp.getClass()
+ " in computation of missing requirements: " + exp);
}
}
}
if (missingRequirements.size() > 0) {
//only start a new resolve if we have collected additional requirements...
IInstallableUnit providing = createUnitProviding("tycho.unresolved.requirements",
missingRequirements);
if (providing.getProvidedCapabilities().size() > 0) {
//... and we could provide additional capabilities
additionalUnits.add(providing);
return resolveInternal(properties, additionalUnits, monitor);
}
}
}
// log all transitive requirements which cannot be satisfied; this doesn't print the dependency chain from the seed to the units with missing requirements, so this is less useful than the "explanation"
logger.debug(StatusTool.collectProblems(s));

Set<Explanation> explanation = projector.getExplanation(new NullProgressMonitor()); // suppress "Cannot complete the request. Generating details."
throw new ResolverException(explanation.stream().map(Object::toString).collect(Collectors.joining("\n")),
newSelectionContext.toString(), StatusTool.findException(s));
}
Expand All @@ -101,7 +136,6 @@ public Collection<IInstallableUnit> resolve(Map<String, String> properties, IPro
if (logger.isExtendedDebugEnabled()) {
logger.debug("Resolved IUs:\n" + ResolverDebugUtils.toDebugString(newState, false));
}

return newState;
}

Expand Down Expand Up @@ -136,13 +170,14 @@ void fixSWT(Collection<IInstallableUnit> availableIUs, Collection<IInstallableUn

IInstallableUnit swtFragment = null;

all_ius: for (Iterator<IInstallableUnit> iter = new QueryableCollection(availableIUs).query(
QueryUtil.ALL_UNITS, monitor).iterator(); iter.hasNext();) {
all_ius: for (Iterator<IInstallableUnit> iter = new QueryableCollection(availableIUs)
.query(QueryUtil.ALL_UNITS, monitor).iterator(); iter.hasNext();) {
IInstallableUnit iu = iter.next();
if (iu.getId().startsWith("org.eclipse.swt") && isApplicable(newSelectionContext, iu.getFilter())
&& providesJavaPackages(iu)) {
for (IProvidedCapability provided : iu.getProvidedCapabilities()) {
if ("osgi.fragment".equals(provided.getNamespace()) && "org.eclipse.swt".equals(provided.getName())) {
if ("osgi.fragment".equals(provided.getNamespace())
&& "org.eclipse.swt".equals(provided.getName())) {
if (swtFragment == null || swtFragment.getVersion().compareTo(iu.getVersion()) < 0) {
swtFragment = iu;
}
Expand All @@ -153,8 +188,8 @@ && providesJavaPackages(iu)) {
}

if (swtFragment == null) {
throw new RuntimeException("Could not determine SWT implementation fragment bundle for environment "
+ newSelectionContext);
throw new RuntimeException(
"Could not determine SWT implementation fragment bundle for environment " + newSelectionContext);
}

resolutionResult.add(swtFragment);
Expand Down
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2012 SAP AG and others.
* Copyright (c) 2012, 2022 SAP AG 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
Expand All @@ -9,6 +9,7 @@
*
* Contributors:
* SAP AG - initial API and implementation
* Christoph Läubrich - #462 - Delay Pom considered items to the final Target Platform calculation
*******************************************************************************/
package org.eclipse.tycho.p2.util.resolution;

Expand All @@ -30,4 +31,14 @@ public interface ResolutionData {
ExecutionEnvironmentResolutionHints getEEResolutionHints();

Map<String, String> getAdditionalFilterProperties();

/**
* @return <code>true</code> if the resolve operation should fail if there are missing
* requirements
*/
boolean failOnMissingRequirements();

void addMissingRequirement(IRequirement requirement);

Collection<IRequirement> getMissingRequirements();
}
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2012, 2014 SAP SE and others.
* Copyright (c) 2012, 2022 SAP SE 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
Expand All @@ -9,9 +9,11 @@
*
* Contributors:
* SAP SE - initial API and implementation
* Christoph Läubrich - #462 - Delay Pom considered items to the final Target Platform calculation
*******************************************************************************/
package org.eclipse.tycho.p2.util.resolution;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
Expand All @@ -34,6 +36,8 @@ public class ResolutionDataImpl implements ResolutionData {
private Collection<IInstallableUnit> rootIUs;
private List<IRequirement> additionalRequirements;
private Map<String, String> additionalFilterProperties;
private Collection<IRequirement> missing = new ArrayList<>();
private boolean failOnMissing = true;

public ResolutionDataImpl(ExecutionEnvironmentResolutionHints eeResolutionHints) {
this.eeResolutionHints = eeResolutionHints;
Expand Down Expand Up @@ -114,4 +118,27 @@ public void setAdditionalFilterProperties(Map<String, String> additionalFilterPr
this.additionalFilterProperties = additionalFilterProperties;
}

@Override
public boolean failOnMissingRequirements() {
return failOnMissing;
}

public void setFailOnMissing(boolean failOnMissing) {
this.failOnMissing = failOnMissing;
}

@Override
public void addMissingRequirement(IRequirement requirement) {
missing.add(requirement);
}

@Override
public Collection<IRequirement> getMissingRequirements() {
return Collections.unmodifiableCollection(missing);
}

public void clearMissingRequirements() {
missing.clear();
}

}

0 comments on commit d474649

Please sign in to comment.