diff --git a/tycho-bundles/org.eclipse.tycho.p2.resolver.impl/src/main/java/org/eclipse/tycho/p2/util/resolution/AbstractSlicerResolutionStrategy.java b/tycho-bundles/org.eclipse.tycho.p2.resolver.impl/src/main/java/org/eclipse/tycho/p2/util/resolution/AbstractSlicerResolutionStrategy.java index db73d03923..56cf987d17 100644 --- a/tycho-bundles/org.eclipse.tycho.p2.resolver.impl/src/main/java/org/eclipse/tycho/p2/util/resolution/AbstractSlicerResolutionStrategy.java +++ b/tycho-bundles/org.eclipse.tycho.p2.resolver.impl/src/main/java/org/eclipse/tycho/p2/util/resolution/AbstractSlicerResolutionStrategy.java @@ -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 @@ -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; @@ -16,19 +17,25 @@ 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; @@ -43,6 +50,11 @@ protected AbstractSlicerResolutionStrategy(MavenLogger logger) { protected final IQueryable slice(Map properties, IProgressMonitor monitor) throws ResolverException { + return slice(properties, Collections.emptyList(), monitor); + } + + protected final IQueryable slice(Map properties, + List additionalUnits, IProgressMonitor monitor) throws ResolverException { if (logger.isExtendedDebugEnabled()) { logger.debug("Properties: " + properties.toString()); @@ -62,6 +74,7 @@ protected final IQueryable slice(Map propertie Set availableIUs = new LinkedHashSet<>(data.getAvailableIUs()); availableIUs.addAll(data.getEEResolutionHints().getTemporaryAdditions()); availableIUs.addAll(data.getEEResolutionHints().getMandatoryUnits()); + availableIUs.addAll(additionalUnits); Set seedIUs = new LinkedHashSet<>(data.getRootIUs()); if (data.getAdditionalRequirements() != null && !data.getAdditionalRequirements().isEmpty()) { @@ -115,6 +128,31 @@ protected static IInstallableUnit createUnitRequiring(String name, Collection 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 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; diff --git a/tycho-bundles/org.eclipse.tycho.p2.resolver.impl/src/main/java/org/eclipse/tycho/p2/util/resolution/ProjectorResolutionStrategy.java b/tycho-bundles/org.eclipse.tycho.p2.resolver.impl/src/main/java/org/eclipse/tycho/p2/util/resolution/ProjectorResolutionStrategy.java index 71b26c97e0..77810c1bf2 100644 --- a/tycho-bundles/org.eclipse.tycho.p2.resolver.impl/src/main/java/org/eclipse/tycho/p2/util/resolution/ProjectorResolutionStrategy.java +++ b/tycho-bundles/org.eclipse.tycho.p2.resolver.impl/src/main/java/org/eclipse/tycho/p2/util/resolution/ProjectorResolutionStrategy.java @@ -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 @@ -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; @@ -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; @@ -63,10 +65,17 @@ protected boolean isSlicerError(MultiStatus slicerStatus) { @Override public Collection resolve(Map properties, IProgressMonitor monitor) throws ResolverException { + List additionalUnits = new ArrayList<>(); + Collection newState = resolveInternal(properties, additionalUnits, monitor); + newState.removeAll(additionalUnits); //remove the tycho generated IUs if any + return newState; + } + protected Collection resolveInternal(Map properties, + List additionalUnits, IProgressMonitor monitor) throws ResolverException { Map newSelectionContext = SimplePlanner.createSelectionContext(properties); - IQueryable slice = slice(properties, monitor); + IQueryable slice = slice(properties, additionalUnits, monitor); Set seedUnits = new LinkedHashSet<>(data.getRootIUs()); List seedRequires = new ArrayList<>(); @@ -80,14 +89,40 @@ public Collection resolve(Map properties, IPro Projector projector = new Projector(slice, newSelectionContext, new HashSet(), 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 = projector.getExplanation(new NullProgressMonitor()); // suppress "Cannot complete the request. Generating details." + if (!data.failOnMissingRequirements()) { + List 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 = 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)); } @@ -101,7 +136,6 @@ public Collection resolve(Map properties, IPro if (logger.isExtendedDebugEnabled()) { logger.debug("Resolved IUs:\n" + ResolverDebugUtils.toDebugString(newState, false)); } - return newState; } @@ -136,13 +170,14 @@ void fixSWT(Collection availableIUs, Collection iter = new QueryableCollection(availableIUs).query( - QueryUtil.ALL_UNITS, monitor).iterator(); iter.hasNext();) { + all_ius: for (Iterator 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; } @@ -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); diff --git a/tycho-bundles/org.eclipse.tycho.p2.resolver.impl/src/main/java/org/eclipse/tycho/p2/util/resolution/ResolutionData.java b/tycho-bundles/org.eclipse.tycho.p2.resolver.impl/src/main/java/org/eclipse/tycho/p2/util/resolution/ResolutionData.java index 1615b528fc..6da03451eb 100644 --- a/tycho-bundles/org.eclipse.tycho.p2.resolver.impl/src/main/java/org/eclipse/tycho/p2/util/resolution/ResolutionData.java +++ b/tycho-bundles/org.eclipse.tycho.p2.resolver.impl/src/main/java/org/eclipse/tycho/p2/util/resolution/ResolutionData.java @@ -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 @@ -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; @@ -30,4 +31,14 @@ public interface ResolutionData { ExecutionEnvironmentResolutionHints getEEResolutionHints(); Map getAdditionalFilterProperties(); + + /** + * @return true if the resolve operation should fail if there are missing + * requirements + */ + boolean failOnMissingRequirements(); + + void addMissingRequirement(IRequirement requirement); + + Collection getMissingRequirements(); } diff --git a/tycho-bundles/org.eclipse.tycho.p2.resolver.impl/src/main/java/org/eclipse/tycho/p2/util/resolution/ResolutionDataImpl.java b/tycho-bundles/org.eclipse.tycho.p2.resolver.impl/src/main/java/org/eclipse/tycho/p2/util/resolution/ResolutionDataImpl.java index bb05ae2d7d..43e8e05e81 100644 --- a/tycho-bundles/org.eclipse.tycho.p2.resolver.impl/src/main/java/org/eclipse/tycho/p2/util/resolution/ResolutionDataImpl.java +++ b/tycho-bundles/org.eclipse.tycho.p2.resolver.impl/src/main/java/org/eclipse/tycho/p2/util/resolution/ResolutionDataImpl.java @@ -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 @@ -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; @@ -34,6 +36,8 @@ public class ResolutionDataImpl implements ResolutionData { private Collection rootIUs; private List additionalRequirements; private Map additionalFilterProperties; + private Collection missing = new ArrayList<>(); + private boolean failOnMissing = true; public ResolutionDataImpl(ExecutionEnvironmentResolutionHints eeResolutionHints) { this.eeResolutionHints = eeResolutionHints; @@ -114,4 +118,27 @@ public void setAdditionalFilterProperties(Map 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 getMissingRequirements() { + return Collections.unmodifiableCollection(missing); + } + + public void clearMissingRequirements() { + missing.clear(); + } + }