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 25, 2023
1 parent d64b98f commit 3cb6136
Show file tree
Hide file tree
Showing 13 changed files with 339 additions and 24 deletions.
21 changes: 21 additions & 0 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,27 @@ If you are reading this in the browser, then you can quickly jump to specific ve

## 5.0.0 (under development)

### new `mirror-target-platform`

There is a new `mirror-target-platform` that allows to mirror the current target platform of a project into a P2 update site, this can b enabled for a project like this:

```xml
<plugin>
<groupId>org.eclipse.tycho</groupId>
<artifactId>target-platform-configuration</artifactId>
<executions>
<execution>
<id>inject</id>
<goals>
<goal>mirror-target-platform</goal>
</goals>
</execution>
</executions>
</plugin>
```

the most usual use-case for this is to transform an existing target-file into a standalone repository.

### new `director` mojo

This mojo can be used in two ways:
Expand Down
2 changes: 2 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,8 @@
<configuration>
<source>${min.jdk.version}</source>
<target>${min.jdk.version}</target>
<!-- Workaround for https://issues.apache.org/jira/browse/MCOMPILER-567 -->
<useIncrementalCompilation>false</useIncrementalCompilation>
</configuration>
</plugin>
<plugin>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/*******************************************************************************
* 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 java.util.List;

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.core.IProvisioningAgent;
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.repository.ListCompositeMetadataRepository;
import org.eclipse.tycho.p2.repository.PublishingRepository;
import org.eclipse.tycho.p2.tools.FacadeException;
import org.eclipse.tycho.p2.tools.mirroring.facade.MirrorApplicationService;
import org.eclipse.tycho.p2maven.ListCompositeArtifactRepository;
import org.eclipse.tycho.repository.registry.facade.ReactorRepositoryManager;

/**
* 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;

@Component
private ReactorRepositoryManager repositoryManager;

@Component
private IProvisioningAgent agent;

@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();
PublishingRepository publishingRepository = repositoryManager.getPublishingRepository(reactorProject);
getLog().info("Mirroring target platform, this can take a while ...");
try {
IArtifactRepository artifactRepository = new ListCompositeArtifactRepository(
List.of(sourceArtifactRepository, publishingRepository.getArtifactRepository()), agent);
IMetadataRepository metadataRepository = new ListCompositeMetadataRepository(
List.of(sourceMetadataRepository, publishingRepository.getMetadataRepository()), agent);
mirrorService.mirrorDirect(artifactRepository, metadataRepository, 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 @@ -75,7 +75,8 @@ public InstallableUnitResolver(List<TargetEnvironment> environments,
this.logger = logger;
}

public void addLocation(InstallableUnitLocation iuLocationDefinition, IQueryable<IInstallableUnit> localUnits) {
public Collection<IInstallableUnit> addLocation(InstallableUnitLocation iuLocationDefinition,
IQueryable<IInstallableUnit> localUnits) {
//update (and validate) desired global state
setIncludeMode(iuLocationDefinition.getIncludeMode());
setIncludeAllEnvironments(iuLocationDefinition.includeAllEnvironments());
Expand All @@ -85,7 +86,9 @@ public void addLocation(InstallableUnitLocation iuLocationDefinition, IQueryable
default -> iuLocationDefinition.includeSource();
});
//resolve root units and add them
rootUnits.add(new RootUnits(getRootIUs(iuLocationDefinition.getUnits(), localUnits), localUnits));
Collection<IInstallableUnit> rootIUs = getRootIUs(iuLocationDefinition.getUnits(), localUnits);
rootUnits.add(new RootUnits(rootIUs, localUnits));
return rootIUs;
}

private void setIncludeMode(IncludeMode newValue) throws TargetDefinitionResolutionException {
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 @@ -23,14 +23,21 @@
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.equinox.internal.p2.updatesite.SiteCategory;
import org.eclipse.equinox.internal.p2.updatesite.SiteXMLAction;
import org.eclipse.equinox.p2.core.IProvisioningAgent;
import org.eclipse.equinox.p2.metadata.IArtifactKey;
import org.eclipse.equinox.p2.metadata.IInstallableUnit;
import org.eclipse.equinox.p2.query.CollectionResult;
import org.eclipse.equinox.p2.query.Collector;
import org.eclipse.equinox.p2.query.IQuery;
import org.eclipse.equinox.p2.query.IQueryResult;
Expand Down Expand Up @@ -77,6 +84,8 @@
*/
public final class TargetDefinitionResolver {

private static final SiteXMLAction CATEGORY_FACTORY = new SiteXMLAction((URI) null, (String) null);

private final MavenLogger logger;

private final List<TargetEnvironment> environments;
Expand Down Expand Up @@ -148,7 +157,11 @@ public TargetDefinitionContent resolveContentWithExceptions(TargetDefinition def
location, repository.getId(), referencedRepositoryMode)));
}
IQueryable<IInstallableUnit> locationUnits = QueryUtil.compoundQueryable(locations);
installableUnitResolver.addLocation((InstallableUnitLocation) locationDefinition, locationUnits);
Collection<IInstallableUnit> rootUnits = installableUnitResolver
.addLocation((InstallableUnitLocation) locationDefinition, locationUnits);
unitResultSet.accept(
createCategory(installableUnitLocation.getRepositories().stream().map(r -> r.getLocation())
.collect(Collectors.joining(", ")), new CollectionResult<>(rootUnits)));
} else if (locationDefinition instanceof PathLocation pathLocation) {
String resolvePath = resolvePath(pathLocation.getPath(), definition);
File fileLocation;
Expand All @@ -161,32 +174,38 @@ public TargetDefinitionContent resolveContentWithExceptions(TargetDefinition def
FileTargetDefinitionContent fileRepositoryRolver = fileRepositories.computeIfAbsent(
fileLocation.getAbsolutePath(),
key -> new FileTargetDefinitionContent(provisioningAgent, fileLocation));
IQueryResult<IInstallableUnit> result;
if (pathLocation instanceof DirectoryLocation || pathLocation instanceof ProfileLocation) {
unitResultSet.addAll(
fileRepositoryRolver.query(QueryUtil.ALL_UNITS, new LoggingProgressMonitor(logger)));
result = fileRepositoryRolver.query(QueryUtil.ALL_UNITS, new LoggingProgressMonitor(logger));
} else if (pathLocation instanceof FeaturesLocation featuresLocation) {
IArtifactKey key = org.eclipse.equinox.p2.publisher.eclipse.FeaturesAction
.createFeatureArtifactKey(featuresLocation.getId(), featuresLocation.getVersion());
unitResultSet.addAll(fileRepositoryRolver.query(QueryUtil.createIUQuery(key),
new LoggingProgressMonitor(logger)));
result = fileRepositoryRolver.query(QueryUtil.createIUQuery(key),
new LoggingProgressMonitor(logger));
} else {
continue;
}
unitResultSet.addAll(result);
unitResultSet.accept(createCategory(resolvePath, result));
} else {
logger.warn("Target location path '" + fileLocation.getAbsolutePath()
+ "' does not exist, target resolution might be incomplete.");
}
} else if (locationDefinition instanceof MavenGAVLocation location) {
} else if (locationDefinition instanceof MavenGAVLocation mavenLocation) {
TargetDefinitionContent targetDefinitionContent = mavenDependenciesResolver
.resolveTargetDefinitionContent(location, includeSourceMode);
.resolveTargetDefinitionContent(mavenLocation, includeSourceMode);
mavenLocations.add(targetDefinitionContent);
IQueryResult<IInstallableUnit> result = targetDefinitionContent.query(QueryUtil.ALL_UNITS,
new LoggingProgressMonitor(logger));
unitResultSet.addAll(result);
Set<IInstallableUnit> locationUnits = result.toUnmodifiableSet();
if (logger.isDebugEnabled()) {
logger.debug("The following artifacts were resolved from location " + location);
for (IInstallableUnit iu : result.toUnmodifiableSet()) {
logger.debug("The following artifacts were resolved from location " + mavenLocation);
for (IInstallableUnit iu : locationUnits) {
logger.debug("\t" + iu);
}
}
unitResultSet.accept(createCategory(mavenLocation.getLabel(), result));
} else if (locationDefinition instanceof TargetReferenceLocation referenceLocation) {
logger.info("Resolving " + referenceLocation.getUri());
String resolvePath = resolvePath(referenceLocation.getUri(), definition);
Expand Down Expand Up @@ -219,6 +238,7 @@ public TargetDefinitionContent resolveContentWithExceptions(TargetDefinition def
IQueryResult<IInstallableUnit> result = content.query(QueryUtil.ALL_UNITS,
new LoggingProgressMonitor(logger));
unitResultSet.addAll(result);
unitResultSet.accept(createCategory(uri, result));
} else {
logger.warn("Target location type '" + locationDefinition.getTypeDescription() + "' is not supported");
}
Expand Down Expand Up @@ -294,6 +314,14 @@ public IArtifactRepository getArtifactRepository() {
};
}

private static IInstallableUnit createCategory(String label, IQueryResult<IInstallableUnit> result) {
SiteCategory category = new SiteCategory();
category.setLabel(label);
category.setName("generated.target.category." + UUID.randomUUID());
return CATEGORY_FACTORY.createCategoryIU(category,
result.stream().filter(iu -> !iu.getId().endsWith(".feature.jar")).collect(Collectors.toSet()));
}

/**
* Converts a "raw" URI string into one that can be used to parse it as an {@link URI}. The
* conversion is especially for converting file URIs constructed using maven properties that
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
Loading

0 comments on commit 3cb6136

Please sign in to comment.