From e90800415e455e505015978304e82193542dadb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20L=C3=A4ubrich?= Date: Sun, 19 Jun 2022 19:34:01 +0200 Subject: [PATCH] Support site/product in TychoGraphBuilder requests Currently only bundle and feature projects are supported for -pl/-am/-amd options when using the TychoGraphBuilder, this should be enhanced to also support sites and products --- p2-maven-plugin/pom.xml | 15 ++ .../p2maven/InstallableUnitGenerator.java | 163 ++++++++++++++++++ .../actions/AbstractDependenciesAction.java | 159 +++++++++++++++++ .../AbstractSiteDependenciesAction.java | 121 +++++++++++++ .../actions/CategoryDependenciesAction.java | 31 ++++ .../actions/ProductDependenciesAction.java | 100 +++++++++++ .../tycho/p2maven/actions/ProductFile2.java | 67 +++++++ .../tycho/build/TychoGraphBuilder.java | 75 ++------ .../feature3/build.properties | 1 + .../feature3/feature.xml | 5 + .../reactor.makeBehaviour/feature3/pom.xml | 14 ++ .../projects/reactor.makeBehaviour/pom.xml | 58 ++++--- .../reactor.makeBehaviour/product/pom.xml | 14 ++ .../product/test.product | 22 +++ .../reactor.makeBehaviour/site/category.xml | 4 + .../reactor.makeBehaviour/site/pom.xml | 14 ++ .../MavenReactorMakeOptionsTest.java | 16 ++ 17 files changed, 791 insertions(+), 88 deletions(-) create mode 100644 p2-maven-plugin/src/main/java/org/eclipse/tycho/p2maven/InstallableUnitGenerator.java create mode 100644 p2-maven-plugin/src/main/java/org/eclipse/tycho/p2maven/actions/AbstractDependenciesAction.java create mode 100644 p2-maven-plugin/src/main/java/org/eclipse/tycho/p2maven/actions/AbstractSiteDependenciesAction.java create mode 100644 p2-maven-plugin/src/main/java/org/eclipse/tycho/p2maven/actions/CategoryDependenciesAction.java create mode 100644 p2-maven-plugin/src/main/java/org/eclipse/tycho/p2maven/actions/ProductDependenciesAction.java create mode 100644 p2-maven-plugin/src/main/java/org/eclipse/tycho/p2maven/actions/ProductFile2.java create mode 100644 tycho-its/projects/reactor.makeBehaviour/feature3/build.properties create mode 100644 tycho-its/projects/reactor.makeBehaviour/feature3/feature.xml create mode 100644 tycho-its/projects/reactor.makeBehaviour/feature3/pom.xml create mode 100644 tycho-its/projects/reactor.makeBehaviour/product/pom.xml create mode 100644 tycho-its/projects/reactor.makeBehaviour/product/test.product create mode 100644 tycho-its/projects/reactor.makeBehaviour/site/category.xml create mode 100644 tycho-its/projects/reactor.makeBehaviour/site/pom.xml diff --git a/p2-maven-plugin/pom.xml b/p2-maven-plugin/pom.xml index 77f5cddadf..7c2518e33f 100644 --- a/p2-maven-plugin/pom.xml +++ b/p2-maven-plugin/pom.xml @@ -71,6 +71,11 @@ org.eclipse.equinox.p2.publisher.eclipse 1.4.100 + + org.eclipse.platform + org.eclipse.equinox.frameworkadmin + 2.2.0 + org.apache.maven maven-model @@ -92,6 +97,16 @@ org.eclipse.equinox.p2.metadata.repository 1.4.100 + + org.eclipse.platform + org.eclipse.equinox.p2.updatesite + 1.2.300 + + + org.eclipse.tycho + tycho-embedder-api + ${project.version} + diff --git a/p2-maven-plugin/src/main/java/org/eclipse/tycho/p2maven/InstallableUnitGenerator.java b/p2-maven-plugin/src/main/java/org/eclipse/tycho/p2maven/InstallableUnitGenerator.java new file mode 100644 index 0000000000..3ae42c0db6 --- /dev/null +++ b/p2-maven-plugin/src/main/java/org/eclipse/tycho/p2maven/InstallableUnitGenerator.java @@ -0,0 +1,163 @@ +/******************************************************************************* + * Copyright (c) 2022 Christoph Läubrich and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Christoph Läubrich - initial API and implementation + *******************************************************************************/ +package org.eclipse.tycho.p2maven; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.maven.project.MavenProject; +import org.codehaus.plexus.component.annotations.Component; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.core.runtime.Status; +import org.eclipse.equinox.internal.p2.publisher.eclipse.FeatureParser; +import org.eclipse.equinox.internal.p2.publisher.eclipse.IProductDescriptor; +import org.eclipse.equinox.internal.p2.updatesite.CategoryParser; +import org.eclipse.equinox.internal.p2.updatesite.SiteModel; +import org.eclipse.equinox.p2.metadata.IInstallableUnit; +import org.eclipse.equinox.p2.publisher.IPublisherAction; +import org.eclipse.equinox.p2.publisher.IPublisherInfo; +import org.eclipse.equinox.p2.publisher.PublisherInfo; +import org.eclipse.equinox.p2.publisher.PublisherResult; +import org.eclipse.equinox.p2.publisher.eclipse.BundlesAction; +import org.eclipse.equinox.p2.publisher.eclipse.Feature; +import org.eclipse.equinox.p2.publisher.eclipse.FeaturesAction; +import org.eclipse.equinox.p2.query.QueryUtil; +import org.eclipse.tycho.PackagingType; +import org.eclipse.tycho.p2maven.actions.CategoryDependenciesAction; +import org.eclipse.tycho.p2maven.actions.ProductDependenciesAction; +import org.eclipse.tycho.p2maven.actions.ProductFile2; +import org.xml.sax.SAXException; + +/** + * Component used to generate {@link IInstallableUnit}s from other artifacts + * + */ +@Component(role = InstallableUnitGenerator.class) +public class InstallableUnitGenerator { + + private static final String KEY_UNITS = "InstallableUnitGenerator.units"; + + /** + * Computes the {@link IInstallableUnit}s for the given project, the computation + * is cached unless forceUpdate is true meaning data is always + * regenerated from scratch. + * + * @param project the project to examine + * @param forceUpdate if cached data is fine + * @return a (possibly empty) collection of {@link IInstallableUnit}s for the + * given {@link MavenProject} + * @throws CoreException if anything goes wrong + */ + @SuppressWarnings("unchecked") + public Collection getInstallableUnits(MavenProject project, boolean forceUpdate) + throws CoreException { + synchronized (project) { + if (!forceUpdate) { + Object contextValue = project.getContextValue(KEY_UNITS); + if (contextValue instanceof Collection) { + return (Collection) contextValue; + } + } + List actions = new ArrayList<>(); + + File basedir = project.getBasedir(); + if (basedir == null || !basedir.isDirectory()) { + return Collections.emptyList(); + } + switch (project.getPackaging()) { + case PackagingType.TYPE_ECLIPSE_TEST_PLUGIN: + case PackagingType.TYPE_ECLIPSE_PLUGIN: { + actions.add(new BundlesAction(new File[] { basedir })); + break; + } + case PackagingType.TYPE_ECLIPSE_FEATURE: { + FeatureParser parser = new FeatureParser(); + Feature feature = parser.parse(basedir); + Map featureMap = new HashMap<>(); + FeaturesAction action = new FeaturesAction(new Feature[] { feature }) { + @Override + protected void publishFeatureArtifacts(Feature feature, IInstallableUnit featureIU, + IPublisherInfo publisherInfo) { + // so not call super as we don't wan't to copy anything --> Bug in P2 with + // IPublisherInfo.A_INDEX option + // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=578380 + } + + @Override + protected IInstallableUnit generateFeatureJarIU(Feature feature, IPublisherInfo publisherInfo) { + IInstallableUnit iu = super.generateFeatureJarIU(feature, publisherInfo); + featureMap.put(iu, feature); + return iu; + } + }; + actions.add(action); + break; + } + case PackagingType.TYPE_ECLIPSE_REPOSITORY: { + File categoryFile = new File(basedir, "category.xml"); + if (categoryFile.exists()) { + try (InputStream stream = new FileInputStream(categoryFile)) { + SiteModel siteModel = new CategoryParser(null).parse(stream); + actions.add(new CategoryDependenciesAction(siteModel, project.getArtifactId(), + project.getVersion())); + } catch (IOException | SAXException e) { + throw new CoreException(Status.error("Error reading " + categoryFile.getAbsolutePath())); + } + } + for (File f : basedir.listFiles(File::isFile)) { + if (f.getName().endsWith(".product") && !f.getName().startsWith(".polyglot")) { + try { + IProductDescriptor productDescriptor = new ProductFile2(f.getAbsolutePath()); + actions.add(new ProductDependenciesAction(productDescriptor)); + } catch (Exception e) { + throw new CoreException(Status.error("Error reading " + f.getAbsolutePath())); + } + } + } + break; + } + default: + return Collections.emptyList(); + } + if (actions.isEmpty()) { + List list = Collections.emptyList(); + project.setContextValue(KEY_UNITS, list); + return list; + } + PublisherInfo publisherInfo = new PublisherInfo(); + publisherInfo.setArtifactOptions(IPublisherInfo.A_INDEX); + PublisherResult results = new PublisherResult(); + for (IPublisherAction action : actions) { + IStatus status = action.perform(publisherInfo, results, new NullProgressMonitor()); + if (status.matches(IStatus.ERROR)) { + throw new CoreException(status); + } + } + Set result = Collections + .unmodifiableSet(results.query(QueryUtil.ALL_UNITS, null).toSet()); + project.setContextValue(KEY_UNITS, result); + return result; + + } + } + +} diff --git a/p2-maven-plugin/src/main/java/org/eclipse/tycho/p2maven/actions/AbstractDependenciesAction.java b/p2-maven-plugin/src/main/java/org/eclipse/tycho/p2maven/actions/AbstractDependenciesAction.java new file mode 100644 index 0000000000..50f678e280 --- /dev/null +++ b/p2-maven-plugin/src/main/java/org/eclipse/tycho/p2maven/actions/AbstractDependenciesAction.java @@ -0,0 +1,159 @@ +/******************************************************************************* + * Copyright (c) 2008, 2011 Sonatype Inc. 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: + * Sonatype Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.tycho.p2maven.actions; + +import java.util.LinkedHashSet; +import java.util.Set; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.equinox.internal.p2.metadata.InstallableUnit; +import org.eclipse.equinox.p2.metadata.IInstallableUnit; +import org.eclipse.equinox.p2.metadata.IProvidedCapability; +import org.eclipse.equinox.p2.metadata.IRequirement; +import org.eclipse.equinox.p2.metadata.MetadataFactory; +import org.eclipse.equinox.p2.metadata.MetadataFactory.InstallableUnitDescription; +import org.eclipse.equinox.p2.metadata.Version; +import org.eclipse.equinox.p2.metadata.VersionRange; +import org.eclipse.equinox.p2.publisher.AbstractPublisherAction; +import org.eclipse.equinox.p2.publisher.IPublisherInfo; +import org.eclipse.equinox.p2.publisher.IPublisherResult; +import org.eclipse.equinox.p2.publisher.PublisherResult; +import org.eclipse.equinox.spi.p2.publisher.PublisherHelper; + +public abstract class AbstractDependenciesAction extends AbstractPublisherAction { + + protected static final Version OSGi_versionMin = Version.createOSGi(0, 0, 0); + + /** + * Conventional qualifier used to denote "ANY QUALIFIER" in feature.xml and .product files. See + * TYCHO-383. + */ + protected static final String ANY_QUALIFIER = "qualifier"; + + /** + * copy&paste from e3.5.1 org.eclipse.osgi.internal.resolver.StateImpl + */ + protected static final String OSGI_OS = "osgi.os"; + + /** + * copy&paste from e3.5.1 org.eclipse.osgi.internal.resolver.StateImpl + */ + protected static final String OSGI_WS = "osgi.ws"; + + /** + * copy&paste from e3.5.1 org.eclipse.osgi.internal.resolver.StateImpl + */ + protected static final String OSGI_ARCH = "osgi.arch"; + + /** + * copy&paste from e3.5.1 org.eclipse.osgi.internal.resolver.StateImpl + */ + protected static final String OSGI_NL = "osgi.nl"; + + protected static final String FEATURE_GROUP_IU_SUFFIX = ".feature.group"; + + protected void addRequiredCapability(Set required, String id, Version version, String filter, + boolean optional) { + VersionRange range = getVersionRange(version); + + required.add(MetadataFactory.createRequirement(IInstallableUnit.NAMESPACE_IU_ID, id, range, + InstallableUnit.parseFilter(filter), optional, false)); + } + + @Override + public IStatus perform(IPublisherInfo publisherInfo, IPublisherResult results, IProgressMonitor monitor) { + InstallableUnitDescription iud = new MetadataFactory.InstallableUnitDescription(); + iud.setId(getId()); + iud.setVersion(getVersion()); + + Set provided = new LinkedHashSet<>(); + addProvidedCapabilities(provided); + provided.add(MetadataFactory.createProvidedCapability(IInstallableUnit.NAMESPACE_IU_ID, iud.getId(), + iud.getVersion())); + iud.addProvidedCapabilities(provided); + + iud.addRequirements(getRequiredCapabilities()); + + addProperties(iud); + addPublisherAdvice(publisherInfo); + + processCapabilityAdvice(iud, publisherInfo); + processInstallableUnitPropertiesAdvice(iud, publisherInfo); + + IInstallableUnit iu = MetadataFactory.createInstallableUnit(iud); + results.addIU(iu, PublisherResult.ROOT); + + InstallableUnitDescription[] others = processAdditionalInstallableUnitsAdvice(iu, publisherInfo); + if (others != null) { + for (InstallableUnitDescription other : others) { + // using PublisherResult.NON_ROOT results in these IUs appear after the primary + // see org.eclipse.equinox.p2.publisher.PublisherResult.getIUs(String, String) + // see org.eclipse.tycho.p2.metadata.IReactorArtifactFacade.getDependencyMetadata() + results.addIU(MetadataFactory.createInstallableUnit(other), PublisherResult.NON_ROOT); + } + } + + return Status.OK_STATUS; + } + + protected void addPublisherAdvice(IPublisherInfo publisherInfo) { + // do nothing by default + } + + protected void addProperties(InstallableUnitDescription iud) { + // do nothing by default + } + + protected abstract Set getRequiredCapabilities(); + + protected void addProvidedCapabilities(Set provided) { + + } + + protected abstract Version getVersion(); + + protected abstract String getId(); + + protected VersionRange getVersionRange(String version) { + if (version == null) { + return VersionRange.emptyRange; + } + + return getVersionRange(Version.create(version)); + } + + protected VersionRange getVersionRange(Version version) { + if (version == null || OSGi_versionMin.equals(version)) { + return VersionRange.emptyRange; + } + + org.osgi.framework.Version osgiVersion = PublisherHelper.toOSGiVersion(version); + + String qualifier = osgiVersion.getQualifier(); + + if (qualifier == null || "".equals(qualifier) || ANY_QUALIFIER.equals(qualifier)) { + Version from = Version.createOSGi(osgiVersion.getMajor(), osgiVersion.getMinor(), osgiVersion.getMicro()); + Version to = Version.createOSGi(osgiVersion.getMajor(), osgiVersion.getMinor(), osgiVersion.getMicro() + 1); + return new VersionRange(from, true, to, false); + } + + return new VersionRange(version, true, version, true); + } + + protected Version createVersion(String version) { + return Version.create(version); + } + +} diff --git a/p2-maven-plugin/src/main/java/org/eclipse/tycho/p2maven/actions/AbstractSiteDependenciesAction.java b/p2-maven-plugin/src/main/java/org/eclipse/tycho/p2maven/actions/AbstractSiteDependenciesAction.java new file mode 100644 index 0000000000..278c781902 --- /dev/null +++ b/p2-maven-plugin/src/main/java/org/eclipse/tycho/p2maven/actions/AbstractSiteDependenciesAction.java @@ -0,0 +1,121 @@ +/******************************************************************************* + * Copyright (c) 2008, 2018 Sonatype Inc. 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: + * Sonatype Inc. - initial API and implementation + * Rapicorp, Inc. - add support for IU type (428310) + *******************************************************************************/ +package org.eclipse.tycho.p2maven.actions; + +import java.util.LinkedHashSet; +import java.util.Set; + +import org.eclipse.equinox.internal.p2.metadata.InstallableUnit; +import org.eclipse.equinox.internal.p2.updatesite.SiteBundle; +import org.eclipse.equinox.internal.p2.updatesite.SiteFeature; +import org.eclipse.equinox.internal.p2.updatesite.SiteIU; +import org.eclipse.equinox.internal.p2.updatesite.SiteModel; +import org.eclipse.equinox.p2.metadata.IInstallableUnit; +import org.eclipse.equinox.p2.metadata.IRequirement; +import org.eclipse.equinox.p2.metadata.MetadataFactory; +import org.eclipse.equinox.p2.metadata.Version; +import org.eclipse.equinox.p2.metadata.VersionRange; +import org.eclipse.equinox.p2.metadata.expression.ExpressionUtil; +import org.eclipse.equinox.p2.metadata.expression.IMatchExpression; +import org.eclipse.tycho.TargetEnvironment; + +@SuppressWarnings("restriction") +public abstract class AbstractSiteDependenciesAction extends AbstractDependenciesAction { + + private final String id; + + private final String version; + + public AbstractSiteDependenciesAction(String id, String version) { + this.id = id; + this.version = version; + } + + abstract SiteModel getSiteModel(); + + @Override + protected Set getRequiredCapabilities() { + Set required = new LinkedHashSet<>(); + + for (SiteFeature feature : getSiteModel().getFeatures()) { + String id = feature.getFeatureIdentifier() + FEATURE_GROUP_IU_SUFFIX; //$NON-NLS-1$ + + VersionRange range = getVersionRange(createVersion(feature.getFeatureVersion())); + String filter = new TargetEnvironment(feature.getOS(), feature.getWS(), feature.getOSArch()) + .toFilterExpression(); + // boolean optional = feature.isOptional(); + required.add(MetadataFactory.createRequirement(IInstallableUnit.NAMESPACE_IU_ID, id, range, + InstallableUnit.parseFilter(filter), false, false)); + } + + for (SiteBundle bundle : getSiteModel().getBundles()) { + String id = bundle.getBundleIdentifier(); + VersionRange range = getVersionRange(createVersion(bundle.getBundleVersion())); + String filter = new TargetEnvironment(bundle.getOS(), bundle.getWS(), bundle.getOSArch()) + .toFilterExpression(); + // boolean optional = feature.isOptional(); + required.add(MetadataFactory.createRequirement(IInstallableUnit.NAMESPACE_IU_ID, id, range, + InstallableUnit.parseFilter(filter), false, false)); + } + + for (SiteIU iu : getSiteModel().getIUs()) { + IRequirement requirement = getRequirement(iu); + if (requirement != null) + required.add(requirement); + } + + return required; + } + + //This is roughly inspired from org.eclipse.equinox.internal.p2.updatesite.SiteXMLAction + private IRequirement getRequirement(SiteIU iu) { + String id = iu.getID(); + String range = iu.getRange(); + String type = iu.getQueryType(); + String expression = iu.getQueryExpression(); + Object[] params = iu.getQueryParams(); + if (id != null) { + VersionRange vRange = new VersionRange(range); + return MetadataFactory.createRequirement(IInstallableUnit.NAMESPACE_IU_ID, id, vRange, null, false, false); + } else if ("match".equals(type)) { + IMatchExpression iuMatcher = ExpressionUtil.getFactory() + . matchExpression(ExpressionUtil.parse(expression), params); + return MetadataFactory.createRequirement(iuMatcher, null, 0, 1, true); + } else if ("context".equals(type)) { + throw new IllegalStateException( + "Context iu queries are not supported in Tycho. Faulty expression is " + expression); + } + return null; + } + + @Override + protected String getId() { + return id; + } + + @Override + protected Version getVersion() { + return createSiteVersion(version); + } + + public static Version createSiteVersion(String version) { + try { + // try default (OSGi?) format first + return Version.create(version); + } catch (IllegalArgumentException e) { + // treat as raw otherwise + return Version.create("format(n[.n=0;[.n=0;['-'S]]]):" + version); + } + } +} diff --git a/p2-maven-plugin/src/main/java/org/eclipse/tycho/p2maven/actions/CategoryDependenciesAction.java b/p2-maven-plugin/src/main/java/org/eclipse/tycho/p2maven/actions/CategoryDependenciesAction.java new file mode 100644 index 0000000000..a30203f327 --- /dev/null +++ b/p2-maven-plugin/src/main/java/org/eclipse/tycho/p2maven/actions/CategoryDependenciesAction.java @@ -0,0 +1,31 @@ +/******************************************************************************* + * Copyright (c) 2010, 2011 SAP AG 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: + * SAP AG - initial API and implementation + *******************************************************************************/ +package org.eclipse.tycho.p2maven.actions; + +import org.eclipse.equinox.internal.p2.updatesite.SiteModel; + +@SuppressWarnings("restriction") +public class CategoryDependenciesAction extends AbstractSiteDependenciesAction { + private final SiteModel siteModel; + + public CategoryDependenciesAction(SiteModel siteModel, String id, String version) { + super(id, version); + this.siteModel = siteModel; + } + + @Override + SiteModel getSiteModel() { + return this.siteModel; + } + +} diff --git a/p2-maven-plugin/src/main/java/org/eclipse/tycho/p2maven/actions/ProductDependenciesAction.java b/p2-maven-plugin/src/main/java/org/eclipse/tycho/p2maven/actions/ProductDependenciesAction.java new file mode 100644 index 0000000000..4e19ce9353 --- /dev/null +++ b/p2-maven-plugin/src/main/java/org/eclipse/tycho/p2maven/actions/ProductDependenciesAction.java @@ -0,0 +1,100 @@ +/******************************************************************************* + * Copyright (c) 2008, 2014 Sonatype Inc. 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: + * Sonatype Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.tycho.p2maven.actions; + +import java.io.File; +import java.util.LinkedHashSet; +import java.util.Set; + +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.Path; +import org.eclipse.equinox.internal.p2.publisher.eclipse.IProductDescriptor; +import org.eclipse.equinox.internal.p2.publisher.eclipse.ProductFile; +import org.eclipse.equinox.p2.metadata.IRequirement; +import org.eclipse.equinox.p2.metadata.IVersionedId; +import org.eclipse.equinox.p2.metadata.MetadataFactory.InstallableUnitDescription; +import org.eclipse.equinox.p2.metadata.Version; +import org.eclipse.equinox.p2.publisher.AdviceFileAdvice; +import org.eclipse.equinox.p2.publisher.IPublisherInfo; +import org.eclipse.equinox.p2.publisher.eclipse.FeatureEntry; + +@SuppressWarnings("restriction") +public class ProductDependenciesAction extends AbstractDependenciesAction { + private final IProductDescriptor product; + + public ProductDependenciesAction(IProductDescriptor product) { + this.product = product; + } + + @Override + protected Version getVersion() { + return Version.create(product.getVersion()); + } + + @Override + protected String getId() { + return product.getId(); + } + + @Override + protected Set getRequiredCapabilities() { + Set required = new LinkedHashSet<>(); + + if (product.useFeatures()) { + for (IVersionedId feature : product.getFeatures()) { + String id = feature.getId() + FEATURE_GROUP_IU_SUFFIX; //$NON-NLS-1$ + Version version = feature.getVersion(); + + addRequiredCapability(required, id, version, null, false); + } + } else { + for (FeatureEntry plugin : ((ProductFile) product).getProductEntries()) { + addRequiredCapability(required, plugin.getId(), Version.parseVersion(plugin.getVersion()), null, true); + } + } + + if (product.includeLaunchers()) { + addRequiredCapability(required, "org.eclipse.equinox.executable.feature.group", null, null, false); + } + return required; + } + + @Override + protected void addPublisherAdvice(IPublisherInfo publisherInfo) { + // see org.eclipse.equinox.p2.publisher.eclipse.ProductAction.createAdviceFileAdvice() + + File productFileLocation = product.getLocation(); + if (productFileLocation == null) { + return; + } + + String id = product.getId(); + Version parseVersion = Version.parseVersion(product.getVersion()); + IPath basePath = new Path(productFileLocation.getParent()); + + // must match org.eclipse.tycho.plugins.p2.publisher.PublishProductMojo.getSourceP2InfFile(File) + final String productFileName = productFileLocation.getName(); + final String p2infFilename = productFileName.substring(0, productFileName.length() - ".product".length()) + + ".p2.inf"; + + AdviceFileAdvice advice = new AdviceFileAdvice(id, parseVersion, basePath, new Path(p2infFilename)); + if (advice.containsAdvice()) { + publisherInfo.addAdvice(advice); + } + } + + @Override + protected void addProperties(InstallableUnitDescription iud) { + iud.setProperty(InstallableUnitDescription.PROP_TYPE_PRODUCT, Boolean.toString(true)); + } +} diff --git a/p2-maven-plugin/src/main/java/org/eclipse/tycho/p2maven/actions/ProductFile2.java b/p2-maven-plugin/src/main/java/org/eclipse/tycho/p2maven/actions/ProductFile2.java new file mode 100644 index 0000000000..1d595328e5 --- /dev/null +++ b/p2-maven-plugin/src/main/java/org/eclipse/tycho/p2maven/actions/ProductFile2.java @@ -0,0 +1,67 @@ +/******************************************************************************* + * Copyright (c) 2008, 2015 Sonatype Inc. 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: + * Sonatype Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.tycho.p2maven.actions; + +import java.util.List; + +import org.eclipse.equinox.internal.p2.publisher.eclipse.ProductFile; +import org.eclipse.equinox.p2.metadata.IVersionedId; +import org.eclipse.equinox.p2.publisher.eclipse.FeatureEntry; +import org.xml.sax.Attributes; + +@SuppressWarnings({ "restriction" }) +public class ProductFile2 extends ProductFile { + protected static final String ATTRIBUTE_OS = "os"; + + protected static final String ATTRIBUTE_WS = "ws"; + + protected static final String ATTRIBUTE_ARCH = "arch"; + + public ProductFile2(String location) throws Exception { + super(location); + } + + @Override + protected void processPlugin(Attributes attributes) { + String fragment = attributes.getValue(ATTRIBUTE_FRAGMENT); + String pluginId = attributes.getValue(ATTRIBUTE_ID); + String pluginVersion = attributes.getValue(ATTRIBUTE_VERSION); + boolean isFragment = Boolean.valueOf(fragment); + FeatureEntry entry = new FeatureEntry(pluginId, pluginVersion != null ? pluginVersion : GENERIC_VERSION_NUMBER, + true); + entry.setFragment(isFragment); + + String os = attributes.getValue(ATTRIBUTE_OS); + String ws = attributes.getValue(ATTRIBUTE_WS); + String arch = attributes.getValue(ATTRIBUTE_ARCH); + if (os != null || ws != null || arch != null) { + entry.setEnvironment(os, ws, arch, null); + } + + if (isFragment) { + fragments.add(entry); + } else { + plugins.add(entry); + } + } + + @Override + public List getFeatures() { + /* + * Unlike the final IU, the dependency-only IU shall depend on root features so that the + * dependency resolver correctly discovers dependencies to root features from the reactor. + */ + return getFeatures(INCLUDED_FEATURES | ROOT_FEATURES); + } + +} diff --git a/tycho-build/src/main/java/org/eclipse/tycho/build/TychoGraphBuilder.java b/tycho-build/src/main/java/org/eclipse/tycho/build/TychoGraphBuilder.java index 84d479e45e..1795473792 100644 --- a/tycho-build/src/main/java/org/eclipse/tycho/build/TychoGraphBuilder.java +++ b/tycho-build/src/main/java/org/eclipse/tycho/build/TychoGraphBuilder.java @@ -12,8 +12,6 @@ *******************************************************************************/ package org.eclipse.tycho.build; -import java.io.File; -import java.io.IOException; import java.util.Collection; import java.util.Collections; import java.util.HashMap; @@ -55,35 +53,20 @@ import org.codehaus.plexus.logging.Logger; import org.codehaus.plexus.util.dag.CycleDetectedException; import org.eclipse.core.runtime.CoreException; -import org.eclipse.equinox.internal.p2.publisher.eclipse.FeatureParser; -import org.eclipse.equinox.p2.metadata.IArtifactKey; import org.eclipse.equinox.p2.metadata.IInstallableUnit; -import org.eclipse.equinox.p2.publisher.IPublisherInfo; -import org.eclipse.equinox.p2.publisher.PublisherInfo; -import org.eclipse.equinox.p2.publisher.PublisherResult; -import org.eclipse.equinox.p2.publisher.eclipse.BundlesAction; -import org.eclipse.equinox.p2.publisher.eclipse.Feature; -import org.eclipse.equinox.p2.publisher.eclipse.FeaturesAction; import org.eclipse.equinox.p2.query.CollectionResult; import org.eclipse.equinox.p2.query.IQueryResult; -import org.eclipse.equinox.p2.query.QueryUtil; -import org.eclipse.osgi.service.resolver.BundleDescription; +import org.eclipse.tycho.PackagingType; import org.eclipse.tycho.core.shared.MavenLogger; +import org.eclipse.tycho.p2maven.InstallableUnitGenerator; import org.eclipse.tycho.p2maven.InstallableUnitSlicer; import org.eclipse.tycho.pomless.AbstractTychoMapping; import org.osgi.framework.BundleContext; -import org.osgi.framework.BundleException; import org.sonatype.maven.polyglot.mapping.Mapping; @Component(role = GraphBuilder.class, hint = GraphBuilder.HINT) public class TychoGraphBuilder extends DefaultGraphBuilder { - public static final String TYPE_ECLIPSE_PLUGIN = "eclipse-plugin"; - public static final String TYPE_ECLIPSE_TEST_PLUGIN = "eclipse-test-plugin"; - public static final String TYPE_ECLIPSE_FEATURE = "eclipse-feature"; - public static final String TYPE_ECLIPSE_REPOSITORY = "eclipse-repository"; - public static final String TYPE_ECLIPSE_TARGET_DEFINITION = "eclipse-target-definition"; - @Requirement private Logger log; @@ -96,6 +79,9 @@ public class TychoGraphBuilder extends DefaultGraphBuilder { @Requirement private InstallableUnitSlicer slicer; + @Requirement + private InstallableUnitGenerator generator; + @Override public Result build(MavenSession session) { // Tell the polyglot mappings that we are in extension mode @@ -246,7 +232,7 @@ public Result build(MavenSession session) { // needed if referenced inside projects we might be more selective and choose // target projects depending on project configuration for (MavenProject mavenProject : projects) { - if (TYPE_ECLIPSE_TARGET_DEFINITION.equals(mavenProject.getPackaging())) { + if (PackagingType.TYPE_ECLIPSE_TARGET_DEFINITION.equals(mavenProject.getPackaging())) { selectedProjects.add(mavenProject); } @@ -265,49 +251,14 @@ public Result build(MavenSession session) { private Function> computeProjectUnits(List problems) { return project -> { - PublisherInfo publisherInfo = new PublisherInfo(); - publisherInfo.setArtifactOptions(IPublisherInfo.A_INDEX); - if (TYPE_ECLIPSE_PLUGIN.equals(project.getPackaging()) - || TYPE_ECLIPSE_TEST_PLUGIN.equals(project.getPackaging())) { - try { - BundleDescription bundleDescription = BundlesAction.createBundleDescription(project.getBasedir()); - IArtifactKey descriptor = BundlesAction.createBundleArtifactKey(bundleDescription.getSymbolicName(), - bundleDescription.getVersion().toString()); - IInstallableUnit iu = BundlesAction.createBundleIU(bundleDescription, descriptor, publisherInfo); - return Collections.singletonList(iu); - } catch (IOException | BundleException e) { - problems.add(new DefaultModelProblem( - "can't read " + project.getPackaging() + " project @ " + project.getBasedir(), - Severity.ERROR, null, null, 0, 0, e)); - } - } else if (TYPE_ECLIPSE_FEATURE.equals(project.getPackaging())) { - FeatureParser parser = new FeatureParser(); - File basedir = project.getBasedir(); - Feature feature = parser.parse(basedir); - Map featureMap = new HashMap<>(); - FeaturesAction action = new FeaturesAction(new Feature[] { feature }) { - @Override - protected void publishFeatureArtifacts(Feature feature, IInstallableUnit featureIU, - IPublisherInfo publisherInfo) { - // so not call super as we don't wan't to copy anything --> Bug in P2 with - // IPublisherInfo.A_INDEX option - // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=578380 - } - - @Override - protected IInstallableUnit generateFeatureJarIU(Feature feature, IPublisherInfo publisherInfo) { - IInstallableUnit iu = super.generateFeatureJarIU(feature, publisherInfo); - featureMap.put(iu, feature); - return iu; - } - }; - PublisherResult results = new PublisherResult(); - action.perform(publisherInfo, results, null); - Set result = results.query(QueryUtil.ALL_UNITS, null).toSet(); - return result; - + try { + return generator.getInstallableUnits(project, true); + } catch (CoreException e) { + problems.add(new DefaultModelProblem( + "can't read " + project.getPackaging() + " project @ " + project.getBasedir(), Severity.ERROR, + null, null, 0, 0, e)); + return Collections.emptyList(); } - return Collections.emptyList(); }; } diff --git a/tycho-its/projects/reactor.makeBehaviour/feature3/build.properties b/tycho-its/projects/reactor.makeBehaviour/feature3/build.properties new file mode 100644 index 0000000000..4fb4ed1a18 --- /dev/null +++ b/tycho-its/projects/reactor.makeBehaviour/feature3/build.properties @@ -0,0 +1 @@ +bin.includes=feature.xml \ No newline at end of file diff --git a/tycho-its/projects/reactor.makeBehaviour/feature3/feature.xml b/tycho-its/projects/reactor.makeBehaviour/feature3/feature.xml new file mode 100644 index 0000000000..422fa34a70 --- /dev/null +++ b/tycho-its/projects/reactor.makeBehaviour/feature3/feature.xml @@ -0,0 +1,5 @@ + + + diff --git a/tycho-its/projects/reactor.makeBehaviour/feature3/pom.xml b/tycho-its/projects/reactor.makeBehaviour/feature3/pom.xml new file mode 100644 index 0000000000..41fb4b8209 --- /dev/null +++ b/tycho-its/projects/reactor.makeBehaviour/feature3/pom.xml @@ -0,0 +1,14 @@ + + + 4.0.0 + + + tycho-its-project.reactor.makeBehaviour + parent + 1.0.0-SNAPSHOT + + + feature3 + eclipse-feature + diff --git a/tycho-its/projects/reactor.makeBehaviour/pom.xml b/tycho-its/projects/reactor.makeBehaviour/pom.xml index 0e07411e47..d04674824a 100644 --- a/tycho-its/projects/reactor.makeBehaviour/pom.xml +++ b/tycho-its/projects/reactor.makeBehaviour/pom.xml @@ -1,30 +1,36 @@ - - 4.0.0 + + 4.0.0 - tycho-its-project.reactor.makeBehaviour - parent - 1.0.0-SNAPSHOT - pom + tycho-its-project.reactor.makeBehaviour + parent + 1.0.0-SNAPSHOT + pom - - feature1 - feature2 - bundle1 - bundle1a - bundle1b - bundle2 - + + 3.0.0-SNAPSHOT + - - - - org.eclipse.tycho - tycho-maven-plugin - ${tycho-version} - true - - - + + feature1 + feature2 + feature3 + bundle1 + bundle1a + bundle1b + bundle2 + site + product + - + + + + org.eclipse.tycho + tycho-maven-plugin + ${tycho-version} + true + + + + + \ No newline at end of file diff --git a/tycho-its/projects/reactor.makeBehaviour/product/pom.xml b/tycho-its/projects/reactor.makeBehaviour/product/pom.xml new file mode 100644 index 0000000000..ad8dec5aed --- /dev/null +++ b/tycho-its/projects/reactor.makeBehaviour/product/pom.xml @@ -0,0 +1,14 @@ + + + 4.0.0 + + + tycho-its-project.reactor.makeBehaviour + parent + 1.0.0-SNAPSHOT + + + product + eclipse-repository + diff --git a/tycho-its/projects/reactor.makeBehaviour/product/test.product b/tycho-its/projects/reactor.makeBehaviour/product/test.product new file mode 100644 index 0000000000..4e4b171ddb --- /dev/null +++ b/tycho-its/projects/reactor.makeBehaviour/product/test.product @@ -0,0 +1,22 @@ + + + + + + + + + + -XstartOnFirstThread -Dorg.eclipse.swt.internal.carbon.smallFonts + + + + + + + + + + + + diff --git a/tycho-its/projects/reactor.makeBehaviour/site/category.xml b/tycho-its/projects/reactor.makeBehaviour/site/category.xml new file mode 100644 index 0000000000..a351caed8c --- /dev/null +++ b/tycho-its/projects/reactor.makeBehaviour/site/category.xml @@ -0,0 +1,4 @@ + + + + diff --git a/tycho-its/projects/reactor.makeBehaviour/site/pom.xml b/tycho-its/projects/reactor.makeBehaviour/site/pom.xml new file mode 100644 index 0000000000..e9df3cda77 --- /dev/null +++ b/tycho-its/projects/reactor.makeBehaviour/site/pom.xml @@ -0,0 +1,14 @@ + + + 4.0.0 + + + tycho-its-project.reactor.makeBehaviour + parent + 1.0.0-SNAPSHOT + + + site + eclipse-repository + diff --git a/tycho-its/src/test/java/org/eclipse/tycho/test/reactor/makeBehaviour/MavenReactorMakeOptionsTest.java b/tycho-its/src/test/java/org/eclipse/tycho/test/reactor/makeBehaviour/MavenReactorMakeOptionsTest.java index 6fd4211a62..df87d7ceb9 100644 --- a/tycho-its/src/test/java/org/eclipse/tycho/test/reactor/makeBehaviour/MavenReactorMakeOptionsTest.java +++ b/tycho-its/src/test/java/org/eclipse/tycho/test/reactor/makeBehaviour/MavenReactorMakeOptionsTest.java @@ -74,6 +74,22 @@ public void testAlsoMake() throws Exception { verifier.assertFileNotPresent("feature2/target/feature2-1.0.0-SNAPSHOT.jar"); } + @Test + public void testAlsoMakeSite() throws Exception { + verifier.addCliOption("-am"); + verifier.addCliOption("-pl site"); + verifier.executeGoals(List.of("clean", "verify")); + verifier.verifyErrorFreeLog(); + } + + @Test + public void testAlsoMakeProduct() throws Exception { + verifier.addCliOption("-am"); + verifier.addCliOption("-pl product"); + verifier.executeGoals(List.of("clean", "verify")); + verifier.verifyErrorFreeLog(); + } + @Test public void testAlsoMakeWithIndirectDependencies() throws Exception { // REACTOR_MAKE_UPSTREAM