diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md
index 377fe8d7ab..ec262bbd13 100644
--- a/RELEASE_NOTES.md
+++ b/RELEASE_NOTES.md
@@ -6,6 +6,7 @@ This page describes the noteworthy improvements provided by each release of Ecli
### backports:
+- new `mirror-target-platform` mojo
- new director mojo
- support for PDE Api Tools Annotations
- api tools fixes
diff --git a/pom.xml b/pom.xml
index 270ee8c1e7..5bd8d9ea5a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -390,6 +390,8 @@
${min.jdk.version}
+
+ false
diff --git a/target-platform-configuration/src/main/java/org/eclipse/tycho/target/MirrorTargetPlatformMojo.java b/target-platform-configuration/src/main/java/org/eclipse/tycho/target/MirrorTargetPlatformMojo.java
new file mode 100644
index 0000000000..bc7c9c61e3
--- /dev/null
+++ b/target-platform-configuration/src/main/java/org/eclipse/tycho/target/MirrorTargetPlatformMojo.java
@@ -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());
+ }
+ }
+
+}
diff --git a/tycho-core/src/main/java/org/eclipse/tycho/p2/tools/mirroring/facade/MirrorApplicationService.java b/tycho-core/src/main/java/org/eclipse/tycho/p2/tools/mirroring/facade/MirrorApplicationService.java
index 2362e74a4b..2cd396d248 100644
--- a/tycho-core/src/main/java/org/eclipse/tycho/p2/tools/mirroring/facade/MirrorApplicationService.java
+++ b/tycho-core/src/main/java/org/eclipse/tycho/p2/tools/mirroring/facade/MirrorApplicationService.java
@@ -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;
@@ -107,6 +109,22 @@ void mirrorStandalone(RepositoryReferences sources, DestinationRepositoryDescrip
Collection 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).
diff --git a/tycho-core/src/main/java/org/eclipse/tycho/p2resolver/InstallableUnitResolver.java b/tycho-core/src/main/java/org/eclipse/tycho/p2resolver/InstallableUnitResolver.java
index 6194935b5d..c6524a233d 100644
--- a/tycho-core/src/main/java/org/eclipse/tycho/p2resolver/InstallableUnitResolver.java
+++ b/tycho-core/src/main/java/org/eclipse/tycho/p2resolver/InstallableUnitResolver.java
@@ -75,7 +75,8 @@ public InstallableUnitResolver(List environments,
this.logger = logger;
}
- public void addLocation(InstallableUnitLocation iuLocationDefinition, IQueryable localUnits) {
+ public Collection addLocation(InstallableUnitLocation iuLocationDefinition,
+ IQueryable localUnits) {
//update (and validate) desired global state
setIncludeMode(iuLocationDefinition.getIncludeMode());
setIncludeAllEnvironments(iuLocationDefinition.includeAllEnvironments());
@@ -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 rootIUs = getRootIUs(iuLocationDefinition.getUnits(), localUnits);
+ rootUnits.add(new RootUnits(rootIUs, localUnits));
+ return rootIUs;
}
private void setIncludeMode(IncludeMode newValue) throws TargetDefinitionResolutionException {
diff --git a/tycho-core/src/main/java/org/eclipse/tycho/p2resolver/PreliminaryTargetPlatformImpl.java b/tycho-core/src/main/java/org/eclipse/tycho/p2resolver/PreliminaryTargetPlatformImpl.java
index 089b5f6627..258121013d 100644
--- a/tycho-core/src/main/java/org/eclipse/tycho/p2resolver/PreliminaryTargetPlatformImpl.java
+++ b/tycho-core/src/main/java/org/eclipse/tycho/p2resolver/PreliminaryTargetPlatformImpl.java
@@ -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;
@@ -61,7 +62,8 @@ public PreliminaryTargetPlatformImpl(Map externalIUs, ExecutionEnvironmentResolutionHints executionEnvironment,
TargetPlatformFilterEvaluator filter, LocalMetadataRepository localMetadataRepository,
IRawArtifactFileProvider externalArtifacts, LocalArtifactRepository localArtifactRepository,
- boolean includeLocalRepo, MavenLogger logger, Set shadowed) {
+ boolean includeLocalRepo, MavenLogger logger, Set shadowed,
+ IProvisioningAgent remoteAgent) {
super(collectAllInstallableUnits(reactorProjectIUs, externalIUs, executionEnvironment), executionEnvironment,
externalArtifacts, localArtifactRepository, reactorProjectIUs, new HashMap<>(), shadowed);
this.externalIUs = externalIUs;
@@ -69,7 +71,8 @@ public PreliminaryTargetPlatformImpl(Map collectAllInstallableUnits(
diff --git a/tycho-core/src/main/java/org/eclipse/tycho/p2resolver/TargetDefinitionResolver.java b/tycho-core/src/main/java/org/eclipse/tycho/p2resolver/TargetDefinitionResolver.java
index bc54520f63..9347563cc5 100644
--- a/tycho-core/src/main/java/org/eclipse/tycho/p2resolver/TargetDefinitionResolver.java
+++ b/tycho-core/src/main/java/org/eclipse/tycho/p2resolver/TargetDefinitionResolver.java
@@ -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;
@@ -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 environments;
@@ -148,7 +157,11 @@ public TargetDefinitionContent resolveContentWithExceptions(TargetDefinition def
location, repository.getId(), referencedRepositoryMode)));
}
IQueryable locationUnits = QueryUtil.compoundQueryable(locations);
- installableUnitResolver.addLocation((InstallableUnitLocation) locationDefinition, locationUnits);
+ Collection 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;
@@ -161,32 +174,38 @@ public TargetDefinitionContent resolveContentWithExceptions(TargetDefinition def
FileTargetDefinitionContent fileRepositoryRolver = fileRepositories.computeIfAbsent(
fileLocation.getAbsolutePath(),
key -> new FileTargetDefinitionContent(provisioningAgent, fileLocation));
+ IQueryResult 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 result = targetDefinitionContent.query(QueryUtil.ALL_UNITS,
new LoggingProgressMonitor(logger));
unitResultSet.addAll(result);
+ Set 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);
@@ -219,6 +238,7 @@ public TargetDefinitionContent resolveContentWithExceptions(TargetDefinition def
IQueryResult 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");
}
@@ -294,6 +314,14 @@ public IArtifactRepository getArtifactRepository() {
};
}
+ private static IInstallableUnit createCategory(String label, IQueryResult 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
diff --git a/tycho-core/src/main/java/org/eclipse/tycho/p2resolver/TargetPlatformFactoryImpl.java b/tycho-core/src/main/java/org/eclipse/tycho/p2resolver/TargetPlatformFactoryImpl.java
index 960c32992d..6f069e6b6a 100644
--- a/tycho-core/src/main/java/org/eclipse/tycho/p2resolver/TargetPlatformFactoryImpl.java
+++ b/tycho-core/src/main/java/org/eclipse/tycho/p2resolver/TargetPlatformFactoryImpl.java
@@ -294,7 +294,7 @@ public P2TargetPlatform createTargetPlatform(TargetPlatformConfigurationStub tpC
externalArtifactFileProvider, //
localArtifactRepository, //
includeLocalMavenRepo, //
- logger, shadowed);
+ logger, shadowed, remoteAgent);
eeResolutionHandler.readFullSpecification(targetPlatform.getInstallableUnits());
return targetPlatform;
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 68ea32319b..3225af8565 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
@@ -14,28 +14,45 @@
package org.eclipse.tycho.p2tools;
import java.io.File;
+import java.io.FileOutputStream;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URLConnection;
+import java.nio.file.Files;
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.Properties;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.jar.JarEntry;
+import java.util.jar.JarOutputStream;
+
+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;
@@ -44,9 +61,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;
@@ -66,6 +85,8 @@
@Component(role = MirrorApplicationService.class)
public class MirrorApplicationServiceImpl implements MirrorApplicationService {
+ private static final String P2_INDEX_FILE = "p2.index";
+
private static final String MIRROR_FAILURE_MESSAGE = "Mirroring failed";
@Requirement
@@ -436,4 +457,86 @@ 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 toMirror = new TreeSet<>(Comparator.comparing(IArtifactKey::getId).thenComparing(
+ Comparator.comparing(IArtifactKey::getVersion).thenComparing(IArtifactKey::getClassifier)));
+ multiStatus.add(destinationMetadataRepository.executeBatch(monitor -> {
+ IQueryResult result = sourceMetadataRepository.query(QueryUtil.ALL_UNITS, monitor);
+ Set 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));
+ }
+ writeP2Index(repositoryDestination);
+ compressXml(repositoryDestination, "artifacts");
+ compressXml(repositoryDestination, "content");
+ try {
+ XZCompressor xzCompressor = new XZCompressor();
+ xzCompressor.setPreserveOriginalFile(true);
+ xzCompressor.setRepoFolder(repositoryDestination.getAbsolutePath());
+ xzCompressor.compressRepo();
+ } catch (IOException e) {
+ throw new FacadeException("XZ compression failed", e);
+ }
+ }
+
+ private void writeP2Index(File repositoryDestination) throws FacadeException {
+ Properties properties = new Properties();
+ properties.setProperty("version", "1");
+ properties.setProperty("artifact.repository.factory.order", "artifacts.xml,!");
+ properties.setProperty("metadata.repository.factory.order", "content.xml,!");
+ try (FileOutputStream stream = new FileOutputStream(new File(repositoryDestination, P2_INDEX_FILE))) {
+ properties.store(stream, null);
+ } catch (IOException e) {
+ throw new FacadeException("writing index file failed", e);
+ }
+ }
+
+ private void compressXml(File repositoryDestination, String name) throws FacadeException {
+ File jarFile = new File(repositoryDestination, name + ".jar");
+ File xmlFile = new File(repositoryDestination, name + ".xml");
+ try (JarOutputStream jarOutputStream = new JarOutputStream(new FileOutputStream(jarFile))) {
+ jarOutputStream.putNextEntry(new JarEntry(xmlFile.getName()));
+ Files.copy(xmlFile.toPath(), jarOutputStream);
+ } catch (IOException e) {
+ throw new FacadeException("compression failed", e);
+ }
+ }
}
diff --git a/tycho-core/src/test/java/org/eclipse/tycho/p2resolver/TargetDefinitionResolverIncludeSourceTest.java b/tycho-core/src/test/java/org/eclipse/tycho/p2resolver/TargetDefinitionResolverIncludeSourceTest.java
index efa0a88ec7..b84971653e 100644
--- a/tycho-core/src/test/java/org/eclipse/tycho/p2resolver/TargetDefinitionResolverIncludeSourceTest.java
+++ b/tycho-core/src/test/java/org/eclipse/tycho/p2resolver/TargetDefinitionResolverIncludeSourceTest.java
@@ -21,7 +21,11 @@
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
+import java.util.Set;
+import java.util.stream.Collectors;
+
import org.eclipse.equinox.p2.core.IProvisioningAgent;
+import org.eclipse.equinox.p2.metadata.IInstallableUnit;
import org.eclipse.equinox.p2.metadata.IVersionedId;
import org.eclipse.equinox.p2.metadata.VersionedId;
import org.eclipse.equinox.p2.query.QueryUtil;
@@ -83,7 +87,7 @@ public void testIncludeSourceWithSlicerMode() throws Exception {
assertThat(versionedIdsOf(content), hasItem(BUNDLE_WITH_SOURCES));
assertThat(versionedIdsOf(content), hasItem(SOURCE_BUNDLE));
- assertEquals(2, content.query(QueryUtil.ALL_UNITS, null).toUnmodifiableSet().size());
+ assertEquals(2, getResultSet(content).size());
}
@Test
@@ -96,7 +100,12 @@ public void testIncludeSourceWithPlannerMode() throws Exception {
assertThat(versionedIdsOf(content), hasItem(BUNDLE_WITH_SOURCES));
assertThat(versionedIdsOf(content), hasItem(SOURCE_BUNDLE));
- assertEquals(2, content.query(QueryUtil.ALL_UNITS, null).toUnmodifiableSet().size());
+ assertEquals(2, getResultSet(content).size());
+ }
+
+ private Set getResultSet(TargetDefinitionContent content) {
+ return content.query(QueryUtil.ALL_UNITS, null).stream()
+ .filter(iu -> !iu.getId().startsWith("generated.target.category.")).collect(Collectors.toSet());
}
@Test
@@ -108,7 +117,7 @@ public void testNoSourceIncludeWhenIncludeSourceIsFalseWithSlicerMode() throws E
lookup(IProvisioningAgent.class));
assertThat(versionedIdsOf(content), not(hasItem(SOURCE_BUNDLE)));
- assertEquals(1, content.query(QueryUtil.ALL_UNITS, null).toUnmodifiableSet().size());
+ assertEquals(1, getResultSet(content).size());
}
@Test
@@ -120,7 +129,7 @@ public void testNoSourceIncludeWhenIncludeSourceIsFalseWithPlannerMode() throws
lookup(IProvisioningAgent.class));
assertThat(versionedIdsOf(content), not(hasItem(SOURCE_BUNDLE)));
- assertEquals(1, content.query(QueryUtil.ALL_UNITS, null).toUnmodifiableSet().size());
+ assertEquals(1, getResultSet(content).size());
}
@Test
@@ -134,7 +143,7 @@ public void testCanResolveBundlesWithoutSourcesWithSlicerMode() throws Exception
assertThat(versionedIdsOf(content), hasItem(NOSOURCE_BUNDLE));
assertThat(versionedIdsOf(content), hasItem(BUNDLE_WITH_SOURCES));
assertThat(versionedIdsOf(content), hasItem(SOURCE_BUNDLE));
- assertEquals(3, content.query(QueryUtil.ALL_UNITS, null).toUnmodifiableSet().size());
+ assertEquals(3, getResultSet(content).size());
}
@Test
@@ -148,7 +157,7 @@ public void testCanResolveBundlesWithoutSourcesWithPlannerMode() throws Exceptio
assertThat(versionedIdsOf(content), hasItem(NOSOURCE_BUNDLE));
assertThat(versionedIdsOf(content), hasItem(BUNDLE_WITH_SOURCES));
assertThat(versionedIdsOf(content), hasItem(SOURCE_BUNDLE));
- assertEquals(3, content.query(QueryUtil.ALL_UNITS, null).toUnmodifiableSet().size());
+ assertEquals(3, getResultSet(content).size());
}
static class WithSourceLocationStub extends LocationStub {
diff --git a/tycho-core/src/test/java/org/eclipse/tycho/p2resolver/TargetDefinitionResolverTest.java b/tycho-core/src/test/java/org/eclipse/tycho/p2resolver/TargetDefinitionResolverTest.java
index 78f765f169..f05aeb264c 100644
--- a/tycho-core/src/test/java/org/eclipse/tycho/p2resolver/TargetDefinitionResolverTest.java
+++ b/tycho-core/src/test/java/org/eclipse/tycho/p2resolver/TargetDefinitionResolverTest.java
@@ -253,7 +253,11 @@ public boolean matchesSafely(Collection item) {
static Collection versionedIdsOf(TargetDefinitionContent content) {
Collection result = new ArrayList<>();
for (IInstallableUnit unit : content.query(QueryUtil.ALL_UNITS, null).toUnmodifiableSet()) {
- result.add(new VersionedId(unit.getId(), unit.getVersion()));
+ String id = unit.getId();
+ if (id.startsWith("generated.target.category.")) {
+ continue;
+ }
+ result.add(new VersionedId(id, unit.getVersion()));
}
return result;
}
diff --git a/tycho-targetplatform/src/main/java/org/eclipse/tycho/targetplatform/TargetDefinition.java b/tycho-targetplatform/src/main/java/org/eclipse/tycho/targetplatform/TargetDefinition.java
index ca591b0b7b..e700d90ce2 100644
--- a/tycho-targetplatform/src/main/java/org/eclipse/tycho/targetplatform/TargetDefinition.java
+++ b/tycho-targetplatform/src/main/java/org/eclipse/tycho/targetplatform/TargetDefinition.java
@@ -115,6 +115,8 @@ enum DependencyDepth {
Element getFeatureTemplate();
+ String getLabel();
+
@Override
public default String getTypeDescription() {
return TYPE;
diff --git a/tycho-targetplatform/src/main/java/org/eclipse/tycho/targetplatform/TargetDefinitionFile.java b/tycho-targetplatform/src/main/java/org/eclipse/tycho/targetplatform/TargetDefinitionFile.java
index f64418c913..0cda363213 100644
--- a/tycho-targetplatform/src/main/java/org/eclipse/tycho/targetplatform/TargetDefinitionFile.java
+++ b/tycho-targetplatform/src/main/java/org/eclipse/tycho/targetplatform/TargetDefinitionFile.java
@@ -27,6 +27,7 @@
import java.io.OutputStream;
import java.io.StringReader;
import java.net.URI;
+import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -197,11 +198,13 @@ private static class MavenLocation implements TargetDefinition.MavenGAVLocation
private final DependencyDepth dependencyDepth;
private final Collection repositoryReferences;
private final Element featureTemplate;
+ private String label;
public MavenLocation(Collection roots, Collection includeDependencyScopes,
MissingManifestStrategy manifestStrategy, boolean includeSource,
Collection instructions, DependencyDepth dependencyDepth,
- Collection repositoryReferences, Element featureTemplate) {
+ Collection repositoryReferences, Element featureTemplate,
+ String label) {
this.roots = roots;
this.includeDependencyScopes = includeDependencyScopes;
this.manifestStrategy = manifestStrategy;
@@ -209,6 +212,7 @@ public MavenLocation(Collection roots, Collection inclu
this.instructions = instructions;
this.dependencyDepth = dependencyDepth;
this.repositoryReferences = repositoryReferences;
+ this.label = label;
this.featureTemplate = featureTemplate == null ? null : (Element) featureTemplate.cloneNode(true);
}
@@ -265,6 +269,30 @@ public DependencyDepth getIncludeDependencyDepth() {
return dependencyDepth;
}
+ @Override
+ public String getLabel() {
+ if (label != null && !label.isBlank()) {
+ return label;
+ }
+ if (featureTemplate != null) {
+ String featureLabel = featureTemplate.getAttribute("label");
+ if (featureLabel != null && !featureLabel.isBlank()) {
+ return featureLabel;
+ }
+ String featureId = featureTemplate.getAttribute("id");
+ if (featureId != null && !featureId.isBlank()) {
+ return featureId;
+ }
+ }
+ if (roots.size() == 1) {
+ MavenDependency dependency = roots.iterator().next();
+ return MessageFormat.format("{0}:{1} ({2})", dependency.getGroupId(), dependency.getArtifactId(),
+ dependency.getVersion());
+ } else {
+ return MessageFormat.format("{0} Maven Dependencies", roots.size());
+ }
+ }
+
}
private static final class MavenDependencyRoot implements MavenDependency {
@@ -668,7 +696,8 @@ private static MavenLocation parseMavenLocation(Element dom) {
Element featureTemplate = getChild(dom, "feature");
return new MavenLocation(parseRoots(dom, globalExcludes), scopes, parseManifestStrategy(dom),
Boolean.parseBoolean(dom.getAttribute("includeSource")), parseInstructions(dom),
- parseDependencyDepth(dom, scope), parseRepositoryReferences(dom), featureTemplate);
+ parseDependencyDepth(dom, scope), parseRepositoryReferences(dom), featureTemplate,
+ dom.getAttribute("label"));
}
private static IULocation parseIULocation(Element dom) {