From ac896028a4cc69551aa137135fce3c06642016d5 Mon Sep 17 00:00:00 2001 From: Tobias Oberlies Date: Wed, 11 Feb 2015 18:32:16 +0100 Subject: 428889 Don't include installMode="root" features in the product IU - Ignore features marked with installMode="root" when publishing products. This attribute is currently only supported by Tycho (cf. bug 427563 for adding p2 support for this) and entails that the feature must *not* be referenced from the product IU. This is achieved with the changed implementation of getFeatures(). - This change allows to get rid of separate product file pre-processing steps in Tycho. Bug: 428889 Change-Id: Ib7aa666c6746fbf417fa7437a7fa7b6a95ebd51f --- .../p2/publisher/eclipse/FeatureInstallMode.java | 35 +++++++++++++++++++++ .../p2/publisher/eclipse/IProductDescriptor.java | 20 +++++++++++- .../internal/p2/publisher/eclipse/Messages.java | 1 + .../internal/p2/publisher/eclipse/ProductFile.java | 26 ++++++++++++++-- .../p2/publisher/eclipse/messages.properties | 1 + .../equinox/p2/tests/AdditionalCoreMatchers.java | 36 ++++++++++++++++++++++ .../tests/publisher/actions/ProductFileTest.java | 29 +++++++++++++++-- .../ProductActionTest/rootFeatures.product | 23 ++++++++++++++ 8 files changed, 165 insertions(+), 6 deletions(-) create mode 100644 bundles/org.eclipse.equinox.p2.publisher.eclipse/src/org/eclipse/equinox/internal/p2/publisher/eclipse/FeatureInstallMode.java create mode 100644 bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/AdditionalCoreMatchers.java create mode 100644 bundles/org.eclipse.equinox.p2.tests/testData/ProductActionTest/rootFeatures.product diff --git a/bundles/org.eclipse.equinox.p2.publisher.eclipse/src/org/eclipse/equinox/internal/p2/publisher/eclipse/FeatureInstallMode.java b/bundles/org.eclipse.equinox.p2.publisher.eclipse/src/org/eclipse/equinox/internal/p2/publisher/eclipse/FeatureInstallMode.java new file mode 100644 index 000000000..e21b67456 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.publisher.eclipse/src/org/eclipse/equinox/internal/p2/publisher/eclipse/FeatureInstallMode.java @@ -0,0 +1,35 @@ +/******************************************************************************* + * Copyright (c) 2015 SAP SE 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 + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * SAP SE - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.internal.p2.publisher.eclipse; + +import org.eclipse.osgi.util.NLS; + +enum FeatureInstallMode { + INCLUDE("include"), ROOT("root"); //$NON-NLS-1$ //$NON-NLS-2$ + + private final String attributeValue; + + private FeatureInstallMode(String attributeValue) { + this.attributeValue = attributeValue; + } + + public static FeatureInstallMode parse(String value) { + if (value == null) { + return INCLUDE; + } + for (FeatureInstallMode mode : FeatureInstallMode.values()) { + if (mode.attributeValue.equals(value)) + return mode; + } + throw new IllegalArgumentException(NLS.bind(Messages.exception_invalidFeatureInstallMode, value)); + } + +} diff --git a/bundles/org.eclipse.equinox.p2.publisher.eclipse/src/org/eclipse/equinox/internal/p2/publisher/eclipse/IProductDescriptor.java b/bundles/org.eclipse.equinox.p2.publisher.eclipse/src/org/eclipse/equinox/internal/p2/publisher/eclipse/IProductDescriptor.java index 8bdc4be46..87f7fd0a9 100644 --- a/bundles/org.eclipse.equinox.p2.publisher.eclipse/src/org/eclipse/equinox/internal/p2/publisher/eclipse/IProductDescriptor.java +++ b/bundles/org.eclipse.equinox.p2.publisher.eclipse/src/org/eclipse/equinox/internal/p2/publisher/eclipse/IProductDescriptor.java @@ -28,6 +28,15 @@ import org.eclipse.equinox.p2.repository.IRepositoryReference; */ public interface IProductDescriptor { + /** + * Flag for {@link #getFeatures(int)} to obtain the features included in the product. + */ + int INCLUDED_FEATURES = 0x1; + /** + * Flag for {@link #getFeatures(int)} to obtain the features to be installed as separately updatable roots. + */ + int ROOT_FEATURES = 0x2; + /** * Gets the name of the launcher. */ @@ -48,11 +57,20 @@ public interface IProductDescriptor { public List getFragments(); /** - * Returns the features listed in the product. Note: These features are only part of + * Returns the features listed in the product. Same as getFeatures(INCLUDED_FEATURES). Note: These features are only part of * the product if {@link #useFeatures()} returns true. */ public List getFeatures(); + /** + * Returns the features listed in the product. Note: These features are only part of + * the product if {@link #useFeatures()} returns true. + * @param options bitmask to indicate what kind of features to return. + * @see #INCLUDED_FEATURES + * @see #ROOT_FEATURES + */ + public List getFeatures(int options); + /** * Returns the path to the config.ini file as specified in the .product file. */ diff --git a/bundles/org.eclipse.equinox.p2.publisher.eclipse/src/org/eclipse/equinox/internal/p2/publisher/eclipse/Messages.java b/bundles/org.eclipse.equinox.p2.publisher.eclipse/src/org/eclipse/equinox/internal/p2/publisher/eclipse/Messages.java index c914949a0..8c176ba2d 100644 --- a/bundles/org.eclipse.equinox.p2.publisher.eclipse/src/org/eclipse/equinox/internal/p2/publisher/eclipse/Messages.java +++ b/bundles/org.eclipse.equinox.p2.publisher.eclipse/src/org/eclipse/equinox/internal/p2/publisher/eclipse/Messages.java @@ -22,6 +22,7 @@ public class Messages extends NLS { public static String exception_featureParse; public static String exception_productParse; public static String exception_invalidProductContentType; + public static String exception_invalidFeatureInstallMode; // feature parsing public static String feature_parse_invalidIdOrVersion; diff --git a/bundles/org.eclipse.equinox.p2.publisher.eclipse/src/org/eclipse/equinox/internal/p2/publisher/eclipse/ProductFile.java b/bundles/org.eclipse.equinox.p2.publisher.eclipse/src/org/eclipse/equinox/internal/p2/publisher/eclipse/ProductFile.java index 73fd078dc..109837b64 100644 --- a/bundles/org.eclipse.equinox.p2.publisher.eclipse/src/org/eclipse/equinox/internal/p2/publisher/eclipse/ProductFile.java +++ b/bundles/org.eclipse.equinox.p2.publisher.eclipse/src/org/eclipse/equinox/internal/p2/publisher/eclipse/ProductFile.java @@ -61,6 +61,7 @@ public class ProductFile extends DefaultHandler implements IProductDescriptor { private static final String ATTRIBUTE_OS = "os"; //$NON-NLS-1$ private static final String ATTRIBUTE_ARCH = "arch"; //$NON-NLS-1$ private static final String ATTRIBUTE_ENABLED = "enabled"; //$NON-NLS-1$ + private static final String ATTRIBUTE_FEATURE_INSTALL_MODE = "installMode"; //$NON-NLS-1$ private static final String PROPERTY_ECLIPSE_APPLICATION = "eclipse.application"; //$NON-NLS-1$ private static final String PROPERTY_ECLIPSE_PRODUCT = "eclipse.product"; //$NON-NLS-1$ @@ -183,6 +184,7 @@ public class ProductFile extends DefaultHandler implements IProductDescriptor { protected List plugins = new ArrayList(); protected List fragments = new ArrayList(); private final List features = new ArrayList(); + private final List rootFeatures = new ArrayList(); private String splashLocation = null; private String productName = null; private String application = null; @@ -393,10 +395,21 @@ public class ProductFile extends DefaultHandler implements IProductDescriptor { * Returns a List of features that constitute this product. */ public List getFeatures() { + return getFeatures(INCLUDED_FEATURES); + } + + public List getFeatures(int options) { List result = new LinkedList(); - for (FeatureEntry feature : features) { - result.add(new VersionedId(feature.getId(), feature.getVersion())); + if ((options & INCLUDED_FEATURES) != 0) { + for (FeatureEntry feature : features) { + result.add(new VersionedId(feature.getId(), feature.getVersion())); + } + } + if ((options & ROOT_FEATURES) != 0) { + for (FeatureEntry feature : rootFeatures) { + result.add(new VersionedId(feature.getId(), feature.getVersion())); + } } return result; @@ -1099,9 +1112,16 @@ public class ProductFile extends DefaultHandler implements IProductDescriptor { private void processFeature(Attributes attributes) { String featureId = attributes.getValue(ATTRIBUTE_ID); String featureVersion = attributes.getValue(ATTRIBUTE_VERSION); + FeatureInstallMode installMode = FeatureInstallMode.parse(attributes.getValue(ATTRIBUTE_FEATURE_INSTALL_MODE)); FeatureEntry featureEntry = new FeatureEntry(featureId, featureVersion != null ? featureVersion : GENERIC_VERSION_NUMBER, false); - features.add(featureEntry); + switch (installMode) { + case ROOT : + rootFeatures.add(featureEntry); + break; + default : + features.add(featureEntry); + } } private void processProduct(Attributes attributes) { diff --git a/bundles/org.eclipse.equinox.p2.publisher.eclipse/src/org/eclipse/equinox/internal/p2/publisher/eclipse/messages.properties b/bundles/org.eclipse.equinox.p2.publisher.eclipse/src/org/eclipse/equinox/internal/p2/publisher/eclipse/messages.properties index 4c63bca8c..99db74ae0 100644 --- a/bundles/org.eclipse.equinox.p2.publisher.eclipse/src/org/eclipse/equinox/internal/p2/publisher/eclipse/messages.properties +++ b/bundles/org.eclipse.equinox.p2.publisher.eclipse/src/org/eclipse/equinox/internal/p2/publisher/eclipse/messages.properties @@ -16,6 +16,7 @@ exception_missingElement = Unable to find element: {0}. exception_featureParse = Problems parsing the feature {0}. exception_productParse = Problems parsing the product file {0}. exception_invalidProductContentType=Provided value \"{0}\" for product content type is not valid. Allowed values are {1} +exception_invalidFeatureInstallMode=Invalid value for attribute 'installMode': {0} ### feature parsing feature_parse_invalidIdOrVersion= Invalid ID \"{0}\" or version \"{1}\" encountered. diff --git a/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/AdditionalCoreMatchers.java b/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/AdditionalCoreMatchers.java new file mode 100644 index 000000000..1bd3c120e --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/AdditionalCoreMatchers.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright (c) 2015 SAP SE 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 + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * SAP SE - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.p2.tests; + +import java.util.Collection; +import org.hamcrest.*; + +public class AdditionalCoreMatchers { + + /** + * Creates a matcher matching any collection with the given size. + * + * @see CoreMatchers#hasItem(Matcher) + */ + public static Matcher> hasSize(final int size) { + return new TypeSafeMatcher>() { + + public void describeTo(Description description) { + description.appendText("a collection with size " + size); + } + + protected boolean matchesSafely(Collection item) { + return item.size() == size; + } + }; + } + +} diff --git a/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/publisher/actions/ProductFileTest.java b/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/publisher/actions/ProductFileTest.java index e62ca72bb..8ec7a5fb5 100644 --- a/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/publisher/actions/ProductFileTest.java +++ b/bundles/org.eclipse.equinox.p2.tests/src/org/eclipse/equinox/p2/tests/publisher/actions/ProductFileTest.java @@ -9,13 +9,18 @@ ******************************************************************************/ package org.eclipse.equinox.p2.tests.publisher.actions; +import static org.eclipse.equinox.p2.tests.AdditionalCoreMatchers.hasSize; +import static org.hamcrest.CoreMatchers.hasItem; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; + import java.util.List; import java.util.Map; import junit.framework.TestCase; import org.eclipse.equinox.frameworkadmin.BundleInfo; +import org.eclipse.equinox.internal.p2.publisher.eclipse.IProductDescriptor; import org.eclipse.equinox.internal.p2.publisher.eclipse.ProductFile; -import org.eclipse.equinox.p2.metadata.IVersionedId; -import org.eclipse.equinox.p2.metadata.Version; +import org.eclipse.equinox.p2.metadata.*; import org.eclipse.equinox.p2.tests.TestData; /** @@ -28,6 +33,7 @@ public class ProductFileTest extends TestCase { ProductFile noLauncherFlag = null; ProductFile falseLauncherFlag = null; ProductFile trueLauncherFlag = null; + ProductFile rootFeaturesProduct; String configFile = "/org.eclipse.equinox.p2.tests/testData/ProductActionTest/productWithConfig/config.ini"; private String uidProductFileLocation; @@ -41,6 +47,7 @@ public class ProductFileTest extends TestCase { productFile = new ProductFile(productFileLocation); uidProductFileLocation = TestData.getFile("ProductActionTest/productWithConfig", "uidproduct.product").toString(); uidProductFile = new ProductFile(uidProductFileLocation); + rootFeaturesProduct = new ProductFile(TestData.getFile("ProductActionTest", "rootFeatures.product").toString()); } /** @@ -112,6 +119,24 @@ public class ProductFileTest extends TestCase { assertEquals("1.2", Version.create("3.5.0.v20081110-9C9tEvNEla71LZ2jFz-RFB-t"), ((IVersionedId) features.get(0)).getVersion()); } + public void testGetRootFeatures() { + List features = rootFeaturesProduct.getFeatures(IProductDescriptor.ROOT_FEATURES); + assertThat(features, hasItem(new VersionedId("org.eclipse.help", "2.0.102.v20140128"))); + assertThat(features, hasItem(new VersionedId("org.eclipse.egit", "0.0.0"))); + assertThat(features, hasSize(2)); + } + + public void testGetIncludedFeatures() { + List features = rootFeaturesProduct.getFeatures(IProductDescriptor.INCLUDED_FEATURES); + assertThat(features, hasItem(new VersionedId("org.eclipse.rcp", "4.4.0.v20140128"))); + assertThat(features, hasItem(new VersionedId("org.eclipse.e4.rcp", "0.0.0"))); + assertThat(features, hasSize(2)); + } + + public void testGetFeaturesOnlyReturnsIncludedFeatures() { + assertThat(rootFeaturesProduct.getFeatures(), is(rootFeaturesProduct.getFeatures(IProductDescriptor.INCLUDED_FEATURES))); + } + /** * Test method for {@link org.eclipse.equinox.internal.p2.publisher.eclipse.ProductFile#getIcons(java.lang.String)}. */ diff --git a/bundles/org.eclipse.equinox.p2.tests/testData/ProductActionTest/rootFeatures.product b/bundles/org.eclipse.equinox.p2.tests/testData/ProductActionTest/rootFeatures.product new file mode 100644 index 000000000..9bb6a22ae --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.tests/testData/ProductActionTest/rootFeatures.product @@ -0,0 +1,23 @@ + + + + + + + + + + -XstartOnFirstThread -Dorg.eclipse.swt.internal.carbon.smallFonts + + + + + + + + + + + + + -- cgit v1.2.3