From 22c01cd466248946114256fbd22d14ceb45e5969 Mon Sep 17 00:00:00 2001 From: Hannes Wellmann Date: Sun, 24 Sep 2023 00:08:26 +0200 Subject: [PATCH] Assemble repository for all environments in one pass --- .../p2tools/MirrorApplicationServiceImpl.java | 41 +++++++--------- .../tycho/p2tools/TychoMirrorApplication.java | 48 +++++++++++++++--- .../copiedfromp2/MirrorApplication.java | 49 +++++++++++++------ 3 files changed, 93 insertions(+), 45 deletions(-) diff --git a/tycho-core/src/main/java/org/eclipse/tycho/p2tools/MirrorApplicationServiceImpl.java b/tycho-core/src/main/java/org/eclipse/tycho/p2tools/MirrorApplicationServiceImpl.java index cc249ffaf9..f54ca5fae2 100644 --- a/tycho-core/src/main/java/org/eclipse/tycho/p2tools/MirrorApplicationServiceImpl.java +++ b/tycho-core/src/main/java/org/eclipse/tycho/p2tools/MirrorApplicationServiceImpl.java @@ -51,7 +51,6 @@ import org.eclipse.equinox.p2.repository.metadata.IMetadataRepository; import org.eclipse.tycho.ArtifactType; import org.eclipse.tycho.BuildDirectory; -import org.eclipse.tycho.TargetEnvironment; import org.eclipse.tycho.core.resolver.shared.DependencySeed; import org.eclipse.tycho.core.shared.StatusTool; import org.eclipse.tycho.p2.repository.GAV; @@ -164,28 +163,24 @@ public void mirrorReactor(RepositoryReferences sources, DestinationRepositoryDes mirrorApp.setIncludeRequiredFeatures(includeRequiredFeatures); mirrorApp.setIncludePacked(false); // no way, Tycho do no longer support packed artifacts anyways mirrorApp.setFilterProvided(filterProvided); - // TODO the p2 mirror tool should support mirroring multiple environments at once - for (TargetEnvironment environment : context.getEnvironments()) { - SlicingOptions options = new SlicingOptions(); - options.considerStrictDependencyOnly(!includeAllDependencies); - Map filter = options.getFilter(); - addFilterForFeatureJARs(filter); - if (filterProperties != null) { - filter.putAll(filterProperties); - } - filter.putAll(environment.toFilterProperties()); - mirrorApp.setSlicingOptions(options); - - try { - LogListener logListener = new LogListener(logger); - mirrorApp.setLog(logListener); - - IStatus returnStatus = mirrorApp.run(null); - checkStatus(returnStatus, false); - logListener.showHelpForLoggedMessages(); - } catch (ProvisionException e) { - throw new FacadeException(MIRROR_FAILURE_MESSAGE + ": " + StatusTool.collectProblems(e.getStatus()), e); - } + mirrorApp.setEnvironments(context.getEnvironments()); + SlicingOptions options = new SlicingOptions(); + options.considerStrictDependencyOnly(!includeAllDependencies); + Map filter = options.getFilter(); + addFilterForFeatureJARs(filter); + if (filterProperties != null) { + filter.putAll(filterProperties); + } + mirrorApp.setSlicingOptions(options); + try { + LogListener logListener = new LogListener(logger); + mirrorApp.setLog(logListener); + + IStatus returnStatus = mirrorApp.run(null); + checkStatus(returnStatus, false); + logListener.showHelpForLoggedMessages(); + } catch (ProvisionException e) { + throw new FacadeException(MIRROR_FAILURE_MESSAGE + ": " + StatusTool.collectProblems(e.getStatus()), e); } recreateArtifactRepository(destination); } diff --git a/tycho-core/src/main/java/org/eclipse/tycho/p2tools/TychoMirrorApplication.java b/tycho-core/src/main/java/org/eclipse/tycho/p2tools/TychoMirrorApplication.java index 78e8d2a996..f03a9a2430 100644 --- a/tycho-core/src/main/java/org/eclipse/tycho/p2tools/TychoMirrorApplication.java +++ b/tycho-core/src/main/java/org/eclipse/tycho/p2tools/TychoMirrorApplication.java @@ -9,6 +9,7 @@ * * Contributors: * SAP SE - initial API and implementation + * Hannes Wellmann - Assemble repository for all environments in one pass *******************************************************************************/ package org.eclipse.tycho.p2tools; @@ -29,6 +30,8 @@ import org.eclipse.equinox.internal.p2.director.PermissiveSlicer; import org.eclipse.equinox.internal.p2.director.Slicer; import org.eclipse.equinox.internal.p2.metadata.IRequiredCapability; +import org.eclipse.equinox.internal.p2.metadata.InstallableUnit; +import org.eclipse.equinox.internal.p2.metadata.RequiredCapability; import org.eclipse.equinox.p2.core.IProvisioningAgent; import org.eclipse.equinox.p2.core.ProvisionException; import org.eclipse.equinox.p2.internal.repository.tools.RepositoryDescriptor; @@ -82,13 +85,16 @@ protected IArtifactRepository initializeDestination(RepositoryDescriptor toInit, @Override protected Slicer createSlicer(SlicingOptions options) { - Map context = options.getFilter(); + List> filters = getContextFilters(); + List selectionContexts = filters.stream().map(InstallableUnit::contextIU).toList(); boolean includeOptionalDependencies = options.includeOptionalDependencies(); boolean onlyFilteredRequirements = options.followOnlyFilteredRequirements(); - boolean considerFilter = context != null && context.size() > 1; + boolean considerFilter = filters.stream().anyMatch(f -> f.size() > 1); + boolean evalFilterTo = options.forceFilterTo(); IMetadataRepository repository = getCompositeMetadataRepository(); - return new PermissiveSlicer(repository, context, includeOptionalDependencies, options.isEverythingGreedy(), - options.forceFilterTo(), options.considerStrictDependencyOnly(), onlyFilteredRequirements) { + boolean considerOnlyStrictDependency = options.considerStrictDependencyOnly(); + return new PermissiveSlicer(repository, filters.get(0), includeOptionalDependencies, + options.isEverythingGreedy(), evalFilterTo, considerOnlyStrictDependency, onlyFilteredRequirements) { @Override protected boolean isApplicable(IInstallableUnit iu, IRequirement req) { if ((includeRequiredBundles || includeRequiredFeatures) && QueryUtil.isGroup(iu) @@ -103,15 +109,43 @@ protected boolean isApplicable(IInstallableUnit iu, IRequirement req) { if (onlyFilteredRequirements && filter == null) { return false; } - return !considerFilter || filter == null || filter.isMatch(selectionContext); + return !considerFilter || filter == null || matchesSelectionContext(filter); } } - return super.isApplicable(req); + return isApplicable(req); } @Override protected boolean isApplicable(IRequirement req) { - throw new UnsupportedOperationException("should never be called!"); + //Every filter in this method needs to continue except when the filter does not pass + if (!includeOptionalDependencies && req.getMin() == 0) { + return false; + } + if (considerOnlyStrictDependency && !RequiredCapability.isStrictVersionRequirement(req.getMatches())) { + return false; + } + //deal with filters + IMatchExpression filter = req.getFilter(); + if (considerFilter) { + if (onlyFilteredRequirements && filter == null) { + return false; + } + return filter == null || matchesSelectionContext(filter); + } + return filter == null ? !onlyFilteredRequirements : evalFilterTo; + } + + @Override + protected boolean isApplicable(IInstallableUnit iu) { + if (considerFilter) { + IMatchExpression filter = iu.getFilter(); + return filter == null || matchesSelectionContext(filter); + } + return iu.getFilter() == null || evalFilterTo; + } + + private boolean matchesSelectionContext(IMatchExpression filter) { + return selectionContexts.stream().anyMatch(filter::isMatch); } @Override diff --git a/tycho-core/src/main/java/org/eclipse/tycho/p2tools/copiedfromp2/MirrorApplication.java b/tycho-core/src/main/java/org/eclipse/tycho/p2tools/copiedfromp2/MirrorApplication.java index 25a7e45579..23dcb4ff6f 100644 --- a/tycho-core/src/main/java/org/eclipse/tycho/p2tools/copiedfromp2/MirrorApplication.java +++ b/tycho-core/src/main/java/org/eclipse/tycho/p2tools/copiedfromp2/MirrorApplication.java @@ -5,6 +5,7 @@ import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Collection; +import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -43,7 +44,6 @@ import org.eclipse.equinox.p2.metadata.VersionRange; import org.eclipse.equinox.p2.planner.IPlanner; import org.eclipse.equinox.p2.planner.IProfileChangeRequest; -import org.eclipse.equinox.p2.query.CompoundQueryable; import org.eclipse.equinox.p2.query.IQuery; import org.eclipse.equinox.p2.query.IQueryResult; import org.eclipse.equinox.p2.query.IQueryable; @@ -52,6 +52,7 @@ import org.eclipse.equinox.p2.repository.artifact.IArtifactRepository; import org.eclipse.equinox.p2.repository.metadata.IMetadataRepository; import org.eclipse.osgi.util.NLS; +import org.eclipse.tycho.TargetEnvironment; public class MirrorApplication extends AbstractApplication implements IApplication, IExecutableExtension { private static final String DEFAULT_COMPARATOR = ArtifactChecksumComparator.COMPARATOR_ID + ".sha-256"; //$NON-NLS-1$ @@ -59,6 +60,7 @@ public class MirrorApplication extends AbstractApplication implements IApplicati private static final String MIRROR_MODE = "metadataOrArtifacts"; //$NON-NLS-1$ protected SlicingOptions slicingOptions = new SlicingOptions(); + protected List environments = new ArrayList<>(); private URI baseline; private String comparatorID; @@ -397,22 +399,35 @@ private IArtifactMirrorLog getLog(File location, String root) { } private IQueryable performResolution(IProgressMonitor monitor) throws ProvisionException { + List> filters = getContextFilters(); IProfileRegistry registry = getProfileRegistry(); String profileId = "MirrorApplication-" + System.currentTimeMillis(); //$NON-NLS-1$ - IProfile profile = registry.addProfile(profileId, slicingOptions.getFilter()); - IPlanner planner = agent.getService(IPlanner.class); - if (planner == null) - throw new IllegalStateException(); - IProfileChangeRequest pcr = planner.createChangeRequest(profile); - pcr.addAll(sourceIUs); - IProvisioningPlan plan = planner.getProvisioningPlan(pcr, null, monitor); - registry.removeProfile(profileId); - @SuppressWarnings("unchecked") - IQueryable[] arr = new IQueryable[plan.getInstallerPlan() == null ? 1 : 2]; - arr[0] = plan.getAdditions(); - if (plan.getInstallerPlan() != null) - arr[1] = plan.getInstallerPlan().getAdditions(); - return new CompoundQueryable<>(arr); + List> queryables = new ArrayList<>(); + for (Map filter : filters) { + IProfile profile = registry.addProfile(profileId, filter); + IPlanner planner = agent.getService(IPlanner.class); + if (planner == null) { + throw new IllegalStateException(); + } + IProfileChangeRequest pcr = planner.createChangeRequest(profile); + pcr.addAll(sourceIUs); + IProvisioningPlan plan = planner.getProvisioningPlan(pcr, null, monitor); + registry.removeProfile(profileId); + queryables.add(plan.getAdditions()); + IProvisioningPlan installerPlan = plan.getInstallerPlan(); + if (installerPlan != null) { + queryables.add(installerPlan.getAdditions()); + } + } + return QueryUtil.compoundQueryable(queryables); + } + + protected List> getContextFilters() { + return environments.isEmpty() ? List.of(slicingOptions.getFilter()) : environments.stream().map(environment -> { + Map filter = new HashMap<>(slicingOptions.getFilter()); + filter.putAll(environment.toFilterProperties()); + return filter; + }).toList(); } private IProfileRegistry getProfileRegistry() throws ProvisionException { @@ -452,6 +467,10 @@ protected Slicer createSlicer(SlicingOptions options) { return slicer; } + public void setEnvironments(List environments) { + this.environments = environments; + } + public void setSlicingOptions(SlicingOptions options) { slicingOptions = options; }