Skip to content

Commit

Permalink
Add support for mirroring the projects target platform
Browse files Browse the repository at this point in the history
This adds support for converting the projects computed target platform
into a deployable p2 repository. This can be used to create a mirror of
a target-file, or to have a repository that can be used to install one
specific bundle or feature with all its dependencies.
  • Loading branch information
laeubi committed Dec 19, 2023
1 parent 8a05c36 commit 78c899f
Show file tree
Hide file tree
Showing 5 changed files with 162 additions and 3 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*******************************************************************************
* Copyright (c) 2023 Christoph Läubrich 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:
* Christoph Läubrich - initial API and implementation
*******************************************************************************/
package org.eclipse.tycho.target;

import java.io.File;

import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.Component;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.plugins.annotations.ResolutionScope;
import org.apache.maven.project.MavenProject;
import org.eclipse.equinox.p2.repository.artifact.IArtifactRepository;
import org.eclipse.equinox.p2.repository.metadata.IMetadataRepository;
import org.eclipse.tycho.ReactorProject;
import org.eclipse.tycho.TargetPlatform;
import org.eclipse.tycho.TargetPlatformService;
import org.eclipse.tycho.core.osgitools.DefaultReactorProject;
import org.eclipse.tycho.p2.tools.FacadeException;
import org.eclipse.tycho.p2.tools.mirroring.facade.MirrorApplicationService;

/**
* Supports mirroring the computed target platform of the current project, this behaves similar to
* what PDE offers with its export deployable feature / plug-in and assembles an update site that
* contains everything this particular project depends on.
*/
@Mojo(name = "mirror-target-platform", threadSafe = true, requiresDependencyResolution = ResolutionScope.COMPILE, defaultPhase = LifecyclePhase.PREPARE_PACKAGE)
public class MirrorTargetPlatformMojo extends AbstractMojo {

@Parameter(property = "project", readonly = true)
private MavenProject project;

@Parameter(defaultValue = "${project.build.directory}/target-platform-repository")
private File destination;

@Parameter(defaultValue = "${project.id}")
private String name;

@Component
private TargetPlatformService platformService;

@Component
private MirrorApplicationService mirrorService;

@Override
public void execute() throws MojoExecutionException, MojoFailureException {
ReactorProject reactorProject = DefaultReactorProject.adapt(project);
TargetPlatform targetPlatform = platformService.getTargetPlatform(reactorProject).orElse(null);
if (targetPlatform == null) {
getLog().info("Project has no target platform, skip execution.");
return;
}
IArtifactRepository sourceArtifactRepository = targetPlatform.getArtifactRepository();
IMetadataRepository sourceMetadataRepository = targetPlatform.getMetadataRepository();
getLog().info("Mirroring target platform, this can take a while ...");
try {
mirrorService.mirrorDirect(sourceArtifactRepository, sourceMetadataRepository, destination, name);
} catch (FacadeException e) {
throw new MojoFailureException(e.getMessage(), e.getCause());
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
import java.util.Collection;
import java.util.Map;

import org.eclipse.equinox.p2.repository.artifact.IArtifactRepository;
import org.eclipse.equinox.p2.repository.metadata.IMetadataRepository;
import org.eclipse.tycho.BuildDirectory;
import org.eclipse.tycho.DependencySeed;
import org.eclipse.tycho.p2.tools.BuildContext;
Expand Down Expand Up @@ -107,6 +109,22 @@ void mirrorStandalone(RepositoryReferences sources, DestinationRepositoryDescrip
Collection<IUDescription> seedUnits, MirrorOptions mirrorOptions, BuildDirectory tempDirectory)
throws FacadeException;

/**
* Mirrors the given sources to the destination, if the destination exits it will be delete
* beforehand.
*
* @param sourceArtifactRepository
* the source artifact repository
* @param sourceMetadataRepository
* the source metadata repository
* @param repositoryDestination
* the destination
* @param repositoryName
* the name of the new repository
*/
void mirrorDirect(IArtifactRepository sourceArtifactRepository, IMetadataRepository sourceMetadataRepository,
File repositoryDestination, String repositoryName) throws FacadeException;

/**
* Modifies the artifact repository to add mapping rules to download Maven released artifacts
* from one of the specified maven repositories (when it's found).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import java.util.Map;
import java.util.Set;

import org.eclipse.equinox.p2.core.IProvisioningAgent;
import org.eclipse.equinox.p2.metadata.IInstallableUnit;
import org.eclipse.equinox.p2.query.QueryUtil;
import org.eclipse.equinox.p2.repository.artifact.IArtifactRepository;
Expand Down Expand Up @@ -61,15 +62,17 @@ public PreliminaryTargetPlatformImpl(Map<IInstallableUnit, ReactorProjectIdentit
Collection<IInstallableUnit> externalIUs, ExecutionEnvironmentResolutionHints executionEnvironment,
TargetPlatformFilterEvaluator filter, LocalMetadataRepository localMetadataRepository,
IRawArtifactFileProvider externalArtifacts, LocalArtifactRepository localArtifactRepository,
boolean includeLocalRepo, MavenLogger logger, Set<IInstallableUnit> shadowed) {
boolean includeLocalRepo, MavenLogger logger, Set<IInstallableUnit> shadowed,
IProvisioningAgent remoteAgent) {
super(collectAllInstallableUnits(reactorProjectIUs, externalIUs, executionEnvironment), executionEnvironment,
externalArtifacts, localArtifactRepository, reactorProjectIUs, new HashMap<>(), shadowed);
this.externalIUs = externalIUs;
this.filter = filter;
this.localMetadataRepository = localMetadataRepository;
this.includeLocalRepo = includeLocalRepo;
this.logger = logger;
this.artifactRepository = new ProviderOnlyArtifactRepository(artifacts, null, URI.create("preliminary:/"));
this.artifactRepository = new ProviderOnlyArtifactRepository(artifacts, remoteAgent,
URI.create("preliminary:/"));
}

public static LinkedHashSet<IInstallableUnit> collectAllInstallableUnits(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,7 @@ public P2TargetPlatform createTargetPlatform(TargetPlatformConfigurationStub tpC
externalArtifactFileProvider, //
localArtifactRepository, //
includeLocalMavenRepo, //
logger, shadowed);
logger, shadowed, remoteAgent);
eeResolutionHandler.readFullSpecification(targetPlatform.getInstallableUnits());

return targetPlatform;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,21 +21,33 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.TreeSet;

import org.apache.commons.io.FileUtils;
import org.codehaus.plexus.component.annotations.Component;
import org.codehaus.plexus.component.annotations.Requirement;
import org.codehaus.plexus.logging.Logger;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.MultiStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.equinox.internal.p2.artifact.repository.simple.SimpleArtifactRepository;
import org.eclipse.equinox.internal.p2.artifact.repository.simple.SimpleArtifactRepositoryFactory;
import org.eclipse.equinox.internal.p2.metadata.repository.SimpleMetadataRepositoryFactory;
import org.eclipse.equinox.internal.p2.repository.Transport;
import org.eclipse.equinox.p2.core.IProvisioningAgent;
import org.eclipse.equinox.p2.core.ProvisionException;
import org.eclipse.equinox.p2.internal.repository.mirroring.IArtifactMirrorLog;
import org.eclipse.equinox.p2.internal.repository.mirroring.Mirroring;
import org.eclipse.equinox.p2.internal.repository.tools.Activator;
import org.eclipse.equinox.p2.internal.repository.tools.Messages;
import org.eclipse.equinox.p2.internal.repository.tools.RecreateRepositoryApplication;
import org.eclipse.equinox.p2.internal.repository.tools.RepositoryDescriptor;
import org.eclipse.equinox.p2.internal.repository.tools.SlicingOptions;
Expand All @@ -44,9 +56,11 @@
import org.eclipse.equinox.p2.metadata.IInstallableUnit;
import org.eclipse.equinox.p2.metadata.Version;
import org.eclipse.equinox.p2.query.IQuery;
import org.eclipse.equinox.p2.query.IQueryResult;
import org.eclipse.equinox.p2.query.QueryUtil;
import org.eclipse.equinox.p2.repository.IRepositoryManager;
import org.eclipse.equinox.p2.repository.artifact.IArtifactDescriptor;
import org.eclipse.equinox.p2.repository.artifact.IArtifactRepository;
import org.eclipse.equinox.p2.repository.artifact.IArtifactRepositoryManager;
import org.eclipse.equinox.p2.repository.metadata.IMetadataRepository;
import org.eclipse.tycho.ArtifactType;
Expand Down Expand Up @@ -436,4 +450,52 @@ public void addMavenMappingRules(File repository, URI[] mavenRepositories) throw
true, false, false);
xzCompress(desc);
}

@Override
public void mirrorDirect(IArtifactRepository sourceArtifactRepository, IMetadataRepository sourceMetadataRepository,
File repositoryDestination, String repositoryName) throws FacadeException {
if (repositoryDestination.exists()) {
FileUtils.deleteQuietly(repositoryDestination);
}
//See https://github.com/eclipse-equinox/p2/pull/418
Objects.requireNonNull(sourceArtifactRepository.getProvisioningAgent(),
"Source repository needs to have an agent");
SimpleMetadataRepositoryFactory metadataRepositoryFactory = new SimpleMetadataRepositoryFactory();
metadataRepositoryFactory.setAgent(agent);
SimpleArtifactRepositoryFactory artifactRepositoryFactory = new SimpleArtifactRepositoryFactory();
artifactRepositoryFactory.setAgent(agent);
IArtifactRepository destinationArtifactRepository = artifactRepositoryFactory
.create(repositoryDestination.toURI(), repositoryName, null, Map.of());
IMetadataRepository destinationMetadataRepository = metadataRepositoryFactory
.create(repositoryDestination.toURI(), repositoryName, null, Map.of());
MultiStatus multiStatus = new MultiStatus(Activator.ID, IStatus.OK, Messages.message_mirroringStatus, null);
Set<IArtifactKey> toMirror = new TreeSet<>(Comparator.comparing(IArtifactKey::getId).thenComparing(
Comparator.comparing(IArtifactKey::getVersion).thenComparing(IArtifactKey::getClassifier)));
multiStatus.add(destinationMetadataRepository.executeBatch(monitor -> {
IQueryResult<IInstallableUnit> result = sourceMetadataRepository.query(QueryUtil.ALL_UNITS, monitor);
Set<IInstallableUnit> units = result.toUnmodifiableSet();
destinationMetadataRepository.addInstallableUnits(units);
for (IInstallableUnit unit : units) {
toMirror.addAll(unit.getArtifacts());
}
}, null));
multiStatus.add(destinationArtifactRepository.executeBatch(monitor -> {
Mirroring mirroring = new Mirroring(sourceArtifactRepository, destinationArtifactRepository, true);
mirroring.setCompare(false);
mirroring.setValidate(false);
mirroring.setTransport(agent.getService(Transport.class));
IArtifactKey[] keys = toMirror.toArray(IArtifactKey[]::new);
mirroring.setArtifactKeys(keys);
multiStatus.addAll(mirroring.run(false, false));
}, null));
if (!multiStatus.isOK()) {
String logMessage = StatusTool.toLogMessage(multiStatus);
if (multiStatus.getSeverity() == IStatus.INFO) {
logger.info(logMessage, StatusTool.findException(multiStatus));
} else if (multiStatus.getSeverity() == IStatus.WARNING) {
logger.warn(logMessage, StatusTool.findException(multiStatus));
}
throw new FacadeException(logMessage, new CoreException(multiStatus));
}
}
}

0 comments on commit 78c899f

Please sign in to comment.