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 index bc7c9c61e3..0818a39ae5 100644 --- 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 @@ -13,7 +13,11 @@ package org.eclipse.tycho.target; import java.io.File; +import java.net.URI; import java.util.List; +import java.util.Set; +import java.util.UUID; +import java.util.stream.Collectors; import org.apache.maven.plugin.AbstractMojo; import org.apache.maven.plugin.MojoExecutionException; @@ -24,9 +28,18 @@ import org.apache.maven.plugins.annotations.Parameter; import org.apache.maven.plugins.annotations.ResolutionScope; import org.apache.maven.project.MavenProject; +import org.eclipse.core.runtime.CoreException; +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.IInstallableUnit; +import org.eclipse.equinox.p2.query.CollectionResult; +import org.eclipse.equinox.p2.query.IQueryResult; +import org.eclipse.equinox.p2.query.IQueryable; +import org.eclipse.equinox.p2.query.QueryUtil; import org.eclipse.equinox.p2.repository.artifact.IArtifactRepository; import org.eclipse.equinox.p2.repository.metadata.IMetadataRepository; +import org.eclipse.tycho.PackagingType; import org.eclipse.tycho.ReactorProject; import org.eclipse.tycho.TargetPlatform; import org.eclipse.tycho.TargetPlatformService; @@ -35,6 +48,7 @@ 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.InstallableUnitSlicer; import org.eclipse.tycho.p2maven.ListCompositeArtifactRepository; import org.eclipse.tycho.repository.registry.facade.ReactorRepositoryManager; @@ -43,9 +57,11 @@ * 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) +@Mojo(name = "mirror-target-platform", threadSafe = true, requiresDependencyResolution = ResolutionScope.COMPILE, defaultPhase = LifecyclePhase.PACKAGE) public class MirrorTargetPlatformMojo extends AbstractMojo { + private static final SiteXMLAction CATEGORY_FACTORY = new SiteXMLAction((URI) null, (String) null); + @Parameter(property = "project", readonly = true) private MavenProject project; @@ -55,6 +71,9 @@ public class MirrorTargetPlatformMojo extends AbstractMojo { @Parameter(defaultValue = "${project.id}") private String name; + @Parameter(defaultValue = "true") + private boolean includeCategories = true; + @Component private TargetPlatformService platformService; @@ -67,6 +86,9 @@ public class MirrorTargetPlatformMojo extends AbstractMojo { @Component private IProvisioningAgent agent; + @Component + private InstallableUnitSlicer installableUnitSlicer; + @Override public void execute() throws MojoExecutionException, MojoFailureException { ReactorProject reactorProject = DefaultReactorProject.adapt(project); @@ -78,16 +100,54 @@ public void execute() throws MojoExecutionException, MojoFailureException { IArtifactRepository sourceArtifactRepository = targetPlatform.getArtifactRepository(); IMetadataRepository sourceMetadataRepository = targetPlatform.getMetadataRepository(); PublishingRepository publishingRepository = repositoryManager.getPublishingRepository(reactorProject); - getLog().info("Mirroring target platform, this can take a while ..."); try { + IMetadataRepository projectRepository = publishingRepository.getMetadataRepository(); 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); + List.of(sourceMetadataRepository, projectRepository), agent); + IQueryable mirrorUnits; + if (PackagingType.TYPE_ECLIPSE_TARGET_DEFINITION.equals(project.getPackaging())) { + //for a target platform we like to mirror everything... + mirrorUnits = metadataRepository; + } else { + //for everything else we want to mirror only items that are required by the project + try { + IQueryResult query = projectRepository.query(QueryUtil.ALL_UNITS, null); + Set rootIus = query.toSet(); + String label; + String projectName = project.getName(); + if (projectName != null && !projectName.isBlank()) { + label = projectName; + } else { + label = project.getId(); + } + rootIus.add(createCategory(label, query)); + mirrorUnits = installableUnitSlicer.computeDependencies(rootIus, metadataRepository); + } catch (CoreException e) { + throw new MojoFailureException("Failed to compute dependencies to mirror", e); + } + } + Set toMirror = mirrorUnits.query(QueryUtil.ALL_UNITS, null).toSet(); + if (!includeCategories) { + //remove any categories from the result + toMirror.removeIf(QueryUtil::isCategory); + } + getLog().info( + "Mirroring " + toMirror.size() + " unit(s) from the target platform, this can take a while ..."); + mirrorService.mirrorDirect(artifactRepository, new CollectionResult(toMirror), + destination, name); } catch (FacadeException e) { throw new MojoFailureException(e.getMessage(), e.getCause()); } } + private static IInstallableUnit createCategory(String label, IQueryResult result) { + SiteCategory category = new SiteCategory(); + category.setLabel(label); + category.setName("generated.project.category." + UUID.randomUUID()); + return CATEGORY_FACTORY.createCategoryIU(category, + result.stream().filter(iu -> !iu.getId().endsWith(".feature.jar")).collect(Collectors.toSet())); + } + } 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 2cd396d248..6c9f772622 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,8 +17,9 @@ import java.util.Collection; import java.util.Map; +import org.eclipse.equinox.p2.metadata.IInstallableUnit; +import org.eclipse.equinox.p2.query.IQueryable; 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; @@ -121,9 +122,11 @@ void mirrorStandalone(RepositoryReferences sources, DestinationRepositoryDescrip * the destination * @param repositoryName * the name of the new repository + * @throws FacadeException */ - void mirrorDirect(IArtifactRepository sourceArtifactRepository, IMetadataRepository sourceMetadataRepository, - File repositoryDestination, String repositoryName) throws FacadeException; + void mirrorDirect(IArtifactRepository sourceArtifactRepository, + IQueryable sourceMetadataRepository, File repositoryDestination, String repositoryName) + throws FacadeException; /** * Modifies the artifact repository to add mapping rules to download Maven released artifacts 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 3225af8565..4709107cdb 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 @@ -62,6 +62,7 @@ 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.IQueryable; import org.eclipse.equinox.p2.query.QueryUtil; import org.eclipse.equinox.p2.repository.IRepositoryManager; import org.eclipse.equinox.p2.repository.artifact.IArtifactDescriptor; @@ -459,8 +460,9 @@ public void addMavenMappingRules(File repository, URI[] mavenRepositories) throw } @Override - public void mirrorDirect(IArtifactRepository sourceArtifactRepository, IMetadataRepository sourceMetadataRepository, - File repositoryDestination, String repositoryName) throws FacadeException { + public void mirrorDirect(IArtifactRepository sourceArtifactRepository, + IQueryable sourceMetadataRepository, File repositoryDestination, String repositoryName) + throws FacadeException { if (repositoryDestination.exists()) { FileUtils.deleteQuietly(repositoryDestination); } diff --git a/tycho-its/projects/TYCHO0383dotQualifierMatching/featureDotQualifier/pom.xml b/tycho-its/projects/TYCHO0383dotQualifierMatching/featureDotQualifier/pom.xml index cbe79ed013..c62a0f93c7 100644 --- a/tycho-its/projects/TYCHO0383dotQualifierMatching/featureDotQualifier/pom.xml +++ b/tycho-its/projects/TYCHO0383dotQualifierMatching/featureDotQualifier/pom.xml @@ -32,11 +32,20 @@ org.eclipse.tycho - tycho-packaging-plugin + target-platform-configuration ${tycho-version} - - true - + + + inject + + mirror-target-platform + + + + + ${project.build.directory}/site + false + diff --git a/tycho-its/projects/TYCHO0439repositoryCategories/pom.xml b/tycho-its/projects/TYCHO0439repositoryCategories/pom.xml index 033073b31c..6a1f543414 100644 --- a/tycho-its/projects/TYCHO0439repositoryCategories/pom.xml +++ b/tycho-its/projects/TYCHO0439repositoryCategories/pom.xml @@ -31,11 +31,20 @@ org.eclipse.tycho - tycho-packaging-plugin + target-platform-configuration ${tycho-version} - - true - + + + inject + + mirror-target-platform + + + + + ${project.build.directory}/site + false + org.eclipse.tycho diff --git a/tycho-its/projects/brokenp2data/pom.xml b/tycho-its/projects/brokenp2data/pom.xml index 41de980146..384f934f90 100644 --- a/tycho-its/projects/brokenp2data/pom.xml +++ b/tycho-its/projects/brokenp2data/pom.xml @@ -25,9 +25,6 @@ org.eclipse.tycho tycho-packaging-plugin ${tycho-version} - - true - diff --git a/tycho-its/projects/custom-bundle-plugin/custom-bundle-parent/custom.bundle.feature/pom.xml b/tycho-its/projects/custom-bundle-plugin/custom-bundle-parent/custom.bundle.feature/pom.xml index 4401d0e80e..3c6ebbeb4f 100644 --- a/tycho-its/projects/custom-bundle-plugin/custom-bundle-parent/custom.bundle.feature/pom.xml +++ b/tycho-its/projects/custom-bundle-plugin/custom-bundle-parent/custom.bundle.feature/pom.xml @@ -15,11 +15,20 @@ org.eclipse.tycho - tycho-packaging-plugin + target-platform-configuration ${tycho-version} - - true - + + + inject + + mirror-target-platform + + + + + ${project.build.directory}/site + false + diff --git a/tycho-its/src/test/java/org/eclipse/tycho/test/TYCHO0439repositoryCategories/RepositoryCategoriesTest.java b/tycho-its/src/test/java/org/eclipse/tycho/test/TYCHO0439repositoryCategories/RepositoryCategoriesTest.java index 5fcc59a91f..790943ebfd 100644 --- a/tycho-its/src/test/java/org/eclipse/tycho/test/TYCHO0439repositoryCategories/RepositoryCategoriesTest.java +++ b/tycho-its/src/test/java/org/eclipse/tycho/test/TYCHO0439repositoryCategories/RepositoryCategoriesTest.java @@ -28,41 +28,41 @@ public class RepositoryCategoriesTest extends AbstractTychoIntegrationTest { - @Test - public void testDeployableFeature() throws Exception { - Verifier v01 = getVerifier("TYCHO0439repositoryCategories"); - v01.executeGoal("install"); - v01.verifyErrorFreeLog(); + @Test + public void testDeployableFeature() throws Exception { + Verifier v01 = getVerifier("TYCHO0439repositoryCategories"); + v01.executeGoal("install"); + v01.verifyErrorFreeLog(); - File site = new File(v01.getBasedir(), "target/site"); - Assert.assertTrue(site.isDirectory()); + File site = new File(v01.getBasedir(), "target/site"); + Assert.assertTrue(site.isDirectory()); - File content = new File(site, "content.jar"); - Assert.assertTrue(content.isFile()); + File content = new File(site, "content.jar"); + Assert.assertTrue(content.getAbsolutePath() + " is not a file!", content.isFile()); - boolean found = false; + boolean found = false; - XMLParser parser = new XMLParser(); - Document document = null; - ZipFile contentJar = new ZipFile(content); - try { - ZipEntry contentXmlEntry = contentJar.getEntry("content.xml"); - document = parser.parse(new XMLIOSource(contentJar.getInputStream(contentXmlEntry))); - } finally { - contentJar.close(); - } - Element repository = document.getRootElement(); - all_units: for (Element unit : repository.getChild("units").getChildren("unit")) { - for (Element property : unit.getChild("properties").getChildren("property")) { - if ("org.eclipse.equinox.p2.type.category".equals(property.getAttributeValue("name")) - && Boolean.parseBoolean(property.getAttributeValue("value"))) { - found = true; - break all_units; - } - } - } + XMLParser parser = new XMLParser(); + Document document = null; + ZipFile contentJar = new ZipFile(content); + try { + ZipEntry contentXmlEntry = contentJar.getEntry("content.xml"); + document = parser.parse(new XMLIOSource(contentJar.getInputStream(contentXmlEntry))); + } finally { + contentJar.close(); + } + Element repository = document.getRootElement(); + all_units: for (Element unit : repository.getChild("units").getChildren("unit")) { + for (Element property : unit.getChild("properties").getChildren("property")) { + if ("org.eclipse.equinox.p2.type.category".equals(property.getAttributeValue("name")) + && Boolean.parseBoolean(property.getAttributeValue("value"))) { + found = true; + break all_units; + } + } + } - Assert.assertTrue("Custom category", found); - } + Assert.assertTrue("Custom category is missing: " + content.getAbsolutePath(), found); + } } diff --git a/tycho-p2-plugin/src/main/java/org/eclipse/tycho/plugins/p2/CategoryP2MetadataMojo.java b/tycho-p2-plugin/src/main/java/org/eclipse/tycho/plugins/p2/CategoryP2MetadataMojo.java index c149fd6df3..dc130d6aac 100644 --- a/tycho-p2-plugin/src/main/java/org/eclipse/tycho/plugins/p2/CategoryP2MetadataMojo.java +++ b/tycho-p2-plugin/src/main/java/org/eclipse/tycho/plugins/p2/CategoryP2MetadataMojo.java @@ -13,15 +13,20 @@ package org.eclipse.tycho.plugins.p2; import java.io.File; +import java.io.FileOutputStream; import java.io.IOException; import java.net.MalformedURLException; +import java.nio.file.Files; import java.util.List; +import java.util.jar.JarEntry; +import java.util.jar.JarOutputStream; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; import org.apache.maven.plugins.annotations.Mojo; import org.apache.maven.plugins.annotations.Parameter; import org.eclipse.equinox.internal.p2.updatesite.CategoryPublisherApplication; +import org.eclipse.equinox.p2.internal.repository.tools.XZCompressor; /** * Adds category IUs to existing metadata repository. @@ -42,16 +47,49 @@ protected CategoryPublisherApplication getPublisherApplication() { @Override protected void addArguments(List arguments) throws IOException, MalformedURLException { + File location = getUpdateSiteLocation(); arguments.add("-metadataRepository"); - arguments.add(getUpdateSiteLocation().toURL().toExternalForm()); + arguments.add(location.toURI().toURL().toExternalForm()); arguments.add("-categoryDefinition"); - arguments.add(categoryDefinition.toURL().toExternalForm()); + arguments.add(categoryDefinition.toURI().toURL().toExternalForm()); } @Override public void execute() throws MojoExecutionException, MojoFailureException { synchronized (LOCK) { + File location = getUpdateSiteLocation(); + File xmlFile = new File(location, "content.xml"); + File jarFile = new File(location, "content.jar"); + File xzFile = new File(location, "content.xml.xz"); + boolean jar = jarFile.isFile(); + boolean xz = xzFile.isFile(); + if (xmlFile.isFile()) { + if (jar) { + jarFile.delete(); + } + } + if (xz) { + xzFile.delete(); + } super.execute(); + try { + if (jar && xmlFile.exists()) { + //need to recreate the jar + try (JarOutputStream jarOutputStream = new JarOutputStream(new FileOutputStream(jarFile))) { + jarOutputStream.putNextEntry(new JarEntry(xmlFile.getName())); + Files.copy(xmlFile.toPath(), jarOutputStream); + } + } + if (xz) { + //need to recreate the xz + XZCompressor xzCompressor = new XZCompressor(); + xzCompressor.setPreserveOriginalFile(true); + xzCompressor.setRepoFolder(location.getAbsolutePath()); + xzCompressor.compressRepo(); + } + } catch (IOException e) { + throw new MojoFailureException("compress content failed", e); + } } } } diff --git a/tycho-packaging-plugin/src/main/java/org/eclipse/tycho/packaging/PackageFeatureMojo.java b/tycho-packaging-plugin/src/main/java/org/eclipse/tycho/packaging/PackageFeatureMojo.java index c4c393f64c..74319d9c3d 100644 --- a/tycho-packaging-plugin/src/main/java/org/eclipse/tycho/packaging/PackageFeatureMojo.java +++ b/tycho-packaging-plugin/src/main/java/org/eclipse/tycho/packaging/PackageFeatureMojo.java @@ -103,10 +103,13 @@ public class PackageFeatureMojo extends AbstractTychoPackagingMojo { private String finalName; /** - * If set to true, standard eclipse update site directory with feature content will - * be created under target folder. - */ + * If set to true, standard eclipse update site directory with + * feature content will be created under target folder. + * + * @deprecated use the new mirror-target-platform instead. + */ @Parameter(defaultValue = "false") + @Deprecated private boolean deployableFeature = false; @Parameter(defaultValue = "${project.build.directory}/site")