From ab8b241f6fe3b4410e249801f461ce52aee975de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20L=C3=A4ubrich?= Date: Tue, 5 Apr 2022 15:29:59 +0200 Subject: [PATCH] Fix #845 - Feature restrictions are not taken into account when using emptyVersion --- .../tycho/p2/target/ArtifactMatcher.java | 45 ++- .../tycho/p2/target/P2TargetPlatform.java | 11 +- .../p2/target/TargetPlatformBaseImpl.java | 36 ++- .../repository/artifacts.xml | 4 + .../repository/content.xml | 118 ++++++++ .../sample.feature/build.properties | 1 + .../sample.feature/feature.xml | 10 + .../sample.feature/pom.xml | 34 +++ .../feature/FeatureWithRestrictionsTest.java | 51 ++++ .../packaging/FeatureXmlTransformer.java | 275 +++++++++++------- 10 files changed, 457 insertions(+), 128 deletions(-) create mode 100644 tycho-its/projects/feature.restrictions/repository/artifacts.xml create mode 100644 tycho-its/projects/feature.restrictions/repository/content.xml create mode 100644 tycho-its/projects/feature.restrictions/sample.feature/build.properties create mode 100644 tycho-its/projects/feature.restrictions/sample.feature/feature.xml create mode 100644 tycho-its/projects/feature.restrictions/sample.feature/pom.xml create mode 100644 tycho-its/src/test/java/org/eclipse/tycho/test/feature/FeatureWithRestrictionsTest.java diff --git a/tycho-bundles/org.eclipse.tycho.p2.resolver.impl/src/main/java/org/eclipse/tycho/p2/target/ArtifactMatcher.java b/tycho-bundles/org.eclipse.tycho.p2.resolver.impl/src/main/java/org/eclipse/tycho/p2/target/ArtifactMatcher.java index 0e15ebfb13..378fd11dd6 100644 --- a/tycho-bundles/org.eclipse.tycho.p2.resolver.impl/src/main/java/org/eclipse/tycho/p2/target/ArtifactMatcher.java +++ b/tycho-bundles/org.eclipse.tycho.p2.resolver.impl/src/main/java/org/eclipse/tycho/p2/target/ArtifactMatcher.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2014 SAP SE and others. + * Copyright (c) 2014, 2022 SAP SE 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 @@ -9,6 +9,7 @@ * * Contributors: * SAP SE - initial API and implementation + * Christoph Läubrich - Issue #845 - Feature restrictions are not taken into account when using emptyVersion *******************************************************************************/ package org.eclipse.tycho.p2.target; @@ -17,22 +18,25 @@ import org.eclipse.equinox.p2.metadata.IInstallableUnit; import org.eclipse.equinox.p2.metadata.Version; import org.eclipse.equinox.p2.metadata.VersionRange; +import org.eclipse.equinox.p2.publisher.eclipse.Feature; +import org.eclipse.equinox.p2.publisher.eclipse.FeatureEntry; +import org.eclipse.equinox.p2.publisher.eclipse.FeaturesAction; import org.eclipse.equinox.p2.query.IQuery; import org.eclipse.equinox.p2.query.IQueryResult; import org.eclipse.equinox.p2.query.QueryUtil; import org.eclipse.tycho.artifacts.IllegalArtifactReferenceException; +@SuppressWarnings("restriction") public class ArtifactMatcher { - public static IInstallableUnit resolveReference(String type, String id, Version version, + public static IInstallableUnit resolveReference(String type, String id, VersionRange versionRange, LinkedHashSet candidateUnits) throws IllegalArtifactReferenceException { if (id == null) { throw new IllegalArtifactReferenceException("ID is required"); } - VersionRange versionRange = getVersionRangeFromReference(version); - IQuery query = QueryUtil.createLatestQuery(ArtifactTypeHelper.createQueryFor(type, id, - versionRange)); + IQuery query = QueryUtil + .createLatestQuery(ArtifactTypeHelper.createQueryFor(type, id, versionRange)); IQueryResult matchingIUs = query.perform(candidateUnits.iterator()); if (matchingIUs.isEmpty()) { @@ -43,6 +47,9 @@ public static IInstallableUnit resolveReference(String type, String id, Version } public static Version parseAsOSGiVersion(String version) throws IllegalArtifactReferenceException { + if (version == null) { + return Version.emptyVersion; + } try { return Version.parseVersion(version); } catch (IllegalArgumentException e) { @@ -50,7 +57,7 @@ public static Version parseAsOSGiVersion(String version) throws IllegalArtifactR } } - private static VersionRange getVersionRangeFromReference(Version version) { + public static VersionRange getVersionRangeFromReference(Version version) { VersionRange range; if (version.getSegmentCount() > 3 && "qualifier".equals(version.getSegment(3))) { range = getRangeOfEquivalentVersions(version); @@ -62,6 +69,28 @@ private static VersionRange getVersionRangeFromReference(Version version) { return range; } + public static VersionRange getVersionRangeFromImport(String version, String rule) { + class DummyFeatureAction extends FeaturesAction { + + public DummyFeatureAction() { + super(new Feature[0]); + } + + @Override + protected VersionRange getVersionRange(FeatureEntry entry) { + VersionRange versionRange = super.getVersionRange(entry); + if (versionRange == null) { + return VersionRange.emptyRange; + } + return versionRange; + } + + } + FeatureEntry entry = FeatureEntry.createRequires("dummy", version, rule, null, false); + + return new DummyFeatureAction().getVersionRange(entry); + } + private static VersionRange getStrictRange(Version version) { return new VersionRange(version, true, version, true); } @@ -74,8 +103,8 @@ private static VersionRange getRangeOfEquivalentVersions(Version version) { Integer major = (Integer) version.getSegment(0); Integer minor = (Integer) version.getSegment(1); Integer micro = (Integer) version.getSegment(2); - VersionRange range = new VersionRange(Version.createOSGi(major, minor, micro), true, Version.createOSGi(major, - minor, micro + 1), false); + VersionRange range = new VersionRange(Version.createOSGi(major, minor, micro), true, + Version.createOSGi(major, minor, micro + 1), false); return range; } diff --git a/tycho-bundles/org.eclipse.tycho.p2.resolver.impl/src/main/java/org/eclipse/tycho/p2/target/P2TargetPlatform.java b/tycho-bundles/org.eclipse.tycho.p2.resolver.impl/src/main/java/org/eclipse/tycho/p2/target/P2TargetPlatform.java index 0e7f114056..14ddd8bf8b 100644 --- a/tycho-bundles/org.eclipse.tycho.p2.resolver.impl/src/main/java/org/eclipse/tycho/p2/target/P2TargetPlatform.java +++ b/tycho-bundles/org.eclipse.tycho.p2.resolver.impl/src/main/java/org/eclipse/tycho/p2/target/P2TargetPlatform.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2011, 2015 SAP SE and others. + * Copyright (c) 2011, 2022 SAP SE 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 @@ -9,6 +9,7 @@ * * Contributors: * SAP SE - initial API and implementation + * Christoph Läubrich - Issue #845 - Feature restrictions are not taken into account when using emptyVersion *******************************************************************************/ package org.eclipse.tycho.p2.target; @@ -20,6 +21,7 @@ import org.eclipse.equinox.p2.metadata.IArtifactKey; import org.eclipse.equinox.p2.metadata.IInstallableUnit; import org.eclipse.equinox.p2.metadata.Version; +import org.eclipse.equinox.p2.metadata.VersionRange; import org.eclipse.equinox.p2.repository.metadata.IMetadataRepository; import org.eclipse.tycho.ReactorProjectIdentities; import org.eclipse.tycho.artifacts.DependencyResolutionException; @@ -82,7 +84,10 @@ public interface P2TargetPlatform extends TargetPlatform { * Note: "artifact" in "resolveArtifact" refers to a Tycho artifact, which technically represent * a p2 installable unit and optionally the associated p2 artifact. */ - IInstallableUnit resolveUnit(String type, String id, Version version) throws IllegalArtifactReferenceException, - DependencyResolutionException; + IInstallableUnit resolveUnit(String type, String id, Version version) + throws IllegalArtifactReferenceException, DependencyResolutionException; + + IInstallableUnit resolveUnit(String type, String id, VersionRange versionRange) + throws IllegalArtifactReferenceException, DependencyResolutionException; } diff --git a/tycho-bundles/org.eclipse.tycho.p2.resolver.impl/src/main/java/org/eclipse/tycho/p2/target/TargetPlatformBaseImpl.java b/tycho-bundles/org.eclipse.tycho.p2.resolver.impl/src/main/java/org/eclipse/tycho/p2/target/TargetPlatformBaseImpl.java index 0ec406955e..abb918283a 100644 --- a/tycho-bundles/org.eclipse.tycho.p2.resolver.impl/src/main/java/org/eclipse/tycho/p2/target/TargetPlatformBaseImpl.java +++ b/tycho-bundles/org.eclipse.tycho.p2.resolver.impl/src/main/java/org/eclipse/tycho/p2/target/TargetPlatformBaseImpl.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2011, 2014 SAP SE and others. + * Copyright (c) 2011, 2022 SAP SE 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 @@ -9,6 +9,7 @@ * * Contributors: * SAP SE - initial API and implementation + * Christoph Läubrich - Issue #845 - Feature restrictions are not taken into account when using emptyVersion *******************************************************************************/ package org.eclipse.tycho.p2.target; @@ -20,6 +21,7 @@ import org.eclipse.equinox.p2.metadata.IArtifactKey; import org.eclipse.equinox.p2.metadata.IInstallableUnit; import org.eclipse.equinox.p2.metadata.Version; +import org.eclipse.equinox.p2.metadata.VersionRange; import org.eclipse.tycho.DefaultArtifactKey; import org.eclipse.tycho.ReactorProjectIdentities; import org.eclipse.tycho.artifacts.DependencyResolutionException; @@ -88,22 +90,38 @@ public final Set getInstallableUnits() { @Override public final org.eclipse.tycho.ArtifactKey resolveArtifact(String type, String id, String version) throws IllegalArtifactReferenceException, DependencyResolutionException { - IInstallableUnit resolvedUnit = resolveUnit(type, id, ArtifactMatcher.parseAsOSGiVersion(version)); + IInstallableUnit resolvedUnit; + if (version != null && (version.startsWith("[") || version.startsWith("("))) { + resolvedUnit = resolveUnit(type, id, VersionRange.create(version)); + } else if (version != null && version.contains("|")) { + String[] split = version.split("\\|", 2); + resolvedUnit = resolveUnit(type, id, ArtifactMatcher.getVersionRangeFromImport(split[0], split[1])); + } else { + resolvedUnit = resolveUnit(type, id, ArtifactMatcher.parseAsOSGiVersion(version)); + } return new DefaultArtifactKey(type, id, resolvedUnit.getVersion().toString()); } @Override public final IInstallableUnit resolveUnit(String type, String id, Version version) throws IllegalArtifactReferenceException, DependencyResolutionException { + VersionRange versionRange = ArtifactMatcher.getVersionRangeFromReference(version); + return resolveUnit(type, id, versionRange); + } - IInstallableUnit matchingUnit = ArtifactMatcher.resolveReference(type, id, version, installableUnits); + @Override + public IInstallableUnit resolveUnit(String type, String id, VersionRange versionRange) + throws IllegalArtifactReferenceException, DependencyResolutionException { + IInstallableUnit matchingUnit = ArtifactMatcher.resolveReference(type, id, versionRange, installableUnits); if (matchingUnit == null) { - String message; - if (version == null) { - message = type + " artifact with ID \"" + id + "\" was not found in the target platform"; - } else { - message = type + " artifact with ID \"" + id + "\" and version matching \"" + version - + "\" was not found in the target platform"; + String message = type + " artifact with ID \"" + id + "\" and version matching \"" + versionRange + + "\" was not found in the target platform"; + String candidates = installableUnits.stream() + .sorted(Comparator.comparing(IInstallableUnit::getId).thenComparing(IInstallableUnit::getVersion)) + .filter(iu -> iu.getId().contains(id)).map(iu -> iu.getId() + ":" + iu.getVersion()) + .collect(Collectors.joining(System.lineSeparator())); + if (!candidates.isBlank()) { + message = message + ", did you probably mean: " + candidates; } throw new DependencyResolutionException(message); } diff --git a/tycho-its/projects/feature.restrictions/repository/artifacts.xml b/tycho-its/projects/feature.restrictions/repository/artifacts.xml new file mode 100644 index 0000000000..ee8ae96723 --- /dev/null +++ b/tycho-its/projects/feature.restrictions/repository/artifacts.xml @@ -0,0 +1,4 @@ + + + + diff --git a/tycho-its/projects/feature.restrictions/repository/content.xml b/tycho-its/projects/feature.restrictions/repository/content.xml new file mode 100644 index 0000000000..96f6bace25 --- /dev/null +++ b/tycho-its/projects/feature.restrictions/repository/content.xml @@ -0,0 +1,118 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Bundle-SymbolicName: org.apache.activemq.activemq-core Bundle-Version: 5.2.0 + + + + + + + + + + + + + + + + + (org.eclipse.update.install.features=true) + + + + + + + + + + + + + + + + + + (org.eclipse.update.install.features=true) + + + + + + + + + + + + + (org.eclipse.update.install.features=true) + + + + + + + + + true + + + + + + + + + + + + (org.eclipse.update.install.features=true) + + + + + + + + + true + + + + + + diff --git a/tycho-its/projects/feature.restrictions/sample.feature/build.properties b/tycho-its/projects/feature.restrictions/sample.feature/build.properties new file mode 100644 index 0000000000..64f93a9f0b --- /dev/null +++ b/tycho-its/projects/feature.restrictions/sample.feature/build.properties @@ -0,0 +1 @@ +bin.includes = feature.xml diff --git a/tycho-its/projects/feature.restrictions/sample.feature/feature.xml b/tycho-its/projects/feature.restrictions/sample.feature/feature.xml new file mode 100644 index 0000000000..edd7e0c961 --- /dev/null +++ b/tycho-its/projects/feature.restrictions/sample.feature/feature.xml @@ -0,0 +1,10 @@ + + + + + + + + diff --git a/tycho-its/projects/feature.restrictions/sample.feature/pom.xml b/tycho-its/projects/feature.restrictions/sample.feature/pom.xml new file mode 100644 index 0000000000..6d127df6af --- /dev/null +++ b/tycho-its/projects/feature.restrictions/sample.feature/pom.xml @@ -0,0 +1,34 @@ + + + 4.0.0 + + com.test + 1.0.0 + com.test.sample.feature + eclipse-feature + + 2.7.0 + file:/${project.basedir}/../repository + + + + + featureRepo + p2 + ${repo-url} + + + + + + + org.eclipse.tycho + tycho-maven-plugin + ${tycho-version} + true + + + + diff --git a/tycho-its/src/test/java/org/eclipse/tycho/test/feature/FeatureWithRestrictionsTest.java b/tycho-its/src/test/java/org/eclipse/tycho/test/feature/FeatureWithRestrictionsTest.java new file mode 100644 index 0000000000..c19ec347d9 --- /dev/null +++ b/tycho-its/src/test/java/org/eclipse/tycho/test/feature/FeatureWithRestrictionsTest.java @@ -0,0 +1,51 @@ +/******************************************************************************* + * Copyright (c) 2022 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.test.feature; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.io.File; +import java.util.List; +import java.util.Optional; + +import org.apache.maven.it.Verifier; +import org.eclipse.tycho.test.AbstractTychoIntegrationTest; +import org.eclipse.tycho.test.util.ResourceUtil; +import org.junit.Test; + +import de.pdark.decentxml.Document; +import de.pdark.decentxml.Element; +import de.pdark.decentxml.XMLParser; + +public class FeatureWithRestrictionsTest extends AbstractTychoIntegrationTest { + + @Test + public void testFeatureRestriction() throws Exception { + Verifier verifier = getVerifier("feature.restrictions/sample.feature", false, true); + verifier.setSystemProperty("repo-url", "file:" + + ResourceUtil.resolveTestResource("projects/feature.restrictions/repository").getAbsolutePath()); + verifier.executeGoals(List.of("clean", "package")); + verifier.verifyErrorFreeLog(); + File contentXml = new File(verifier.getBasedir(), "target/p2content.xml"); + Document artifactsDocument = XMLParser.parse(contentXml); + String unitId = "com.test.sample.feature.feature.group"; + Optional unit = artifactsDocument.getChild("units").getChildren("unit").stream().filter(elem -> { + return unitId.equals(elem.getAttributeValue("id")); + }).findFirst(); + assertTrue("Unit with id " + unitId + " not found", unit.isPresent()); + assertFalse("Version 2 was required by unit", + unit.stream().flatMap(elem -> elem.getChild("requires").getChildren("required").stream()) + .anyMatch(elem -> "[2.0.0,2.0.0]".equals(elem.getAttributeValue("range")))); + } +} diff --git a/tycho-packaging-plugin/src/main/java/org/eclipse/tycho/packaging/FeatureXmlTransformer.java b/tycho-packaging-plugin/src/main/java/org/eclipse/tycho/packaging/FeatureXmlTransformer.java index 383d59006b..276156b61d 100644 --- a/tycho-packaging-plugin/src/main/java/org/eclipse/tycho/packaging/FeatureXmlTransformer.java +++ b/tycho-packaging-plugin/src/main/java/org/eclipse/tycho/packaging/FeatureXmlTransformer.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2011, 2014 Sonatype Inc. and others. + * Copyright (c) 2011, 2022 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 @@ -9,19 +9,25 @@ * * Contributors: * Sonatype Inc. - initial API and implementation + * Christoph Läubrich - Issue #845 - Feature restrictions are not taken into account when using emptyVersion *******************************************************************************/ package org.eclipse.tycho.packaging; import java.io.File; import java.io.IOException; import java.util.Enumeration; +import java.util.Map; +import java.util.Objects; +import java.util.function.Function; import java.util.jar.JarEntry; import java.util.jar.JarFile; +import java.util.stream.Collectors; import org.apache.maven.plugin.MojoFailureException; import org.codehaus.plexus.component.annotations.Component; import org.codehaus.plexus.component.annotations.Requirement; import org.codehaus.plexus.logging.Logger; +import org.eclipse.equinox.p2.metadata.Version; import org.eclipse.tycho.ArtifactKey; import org.eclipse.tycho.ArtifactType; import org.eclipse.tycho.artifacts.IllegalArtifactReferenceException; @@ -29,120 +35,173 @@ import org.eclipse.tycho.locking.facade.FileLockService; import org.eclipse.tycho.locking.facade.FileLocker; import org.eclipse.tycho.model.Feature; +import org.eclipse.tycho.model.Feature.ImportRef; import org.eclipse.tycho.model.FeatureRef; import org.eclipse.tycho.model.PluginRef; @Component(role = FeatureXmlTransformer.class) public class FeatureXmlTransformer { - private static final int KBYTE = 1024; - - @Requirement - private Logger log; - - @Requirement - private FileLockService fileLockService; - - public FeatureXmlTransformer() { - } - - public FeatureXmlTransformer(Logger log, FileLockService fileLockService) { - this.log = log; - this.fileLockService = fileLockService; - } - - /** - * Replaces references in the feature model with versions from the target platform. - * - * @param feature - * The feature model to have plug-in and feature references completed. - */ - public Feature expandReferences(Feature feature, TargetPlatform targetPlatform) throws MojoFailureException { - - for (PluginRef pluginRef : feature.getPlugins()) { - ArtifactKey plugin = resolvePluginReference(targetPlatform, pluginRef); - pluginRef.setVersion(plugin.getVersion()); + private static final int KBYTE = 1024; + + @Requirement + private Logger log; + + @Requirement + private FileLockService fileLockService; + + public FeatureXmlTransformer() { + } + + public FeatureXmlTransformer(Logger log, FileLockService fileLockService) { + this.log = log; + this.fileLockService = fileLockService; + } + + /** + * Replaces references in the feature model with versions from the target + * platform. + * + * @param feature The feature model to have plug-in and feature references + * completed. + */ + public Feature expandReferences(Feature feature, TargetPlatform targetPlatform) throws MojoFailureException { + + Map featureImports = feature.getRequires().stream().flatMap(req -> req.getImports().stream()) + .filter(imp -> Objects.nonNull(imp.getFeature()) && !imp.getFeature().isBlank()) + .collect(Collectors.toMap(ImportRef::getFeature, Function.identity())); + Map pluginImports = feature.getRequires().stream().flatMap(req -> req.getImports().stream()) + .filter(imp -> Objects.nonNull(imp.getPlugin()) && !imp.getPlugin().isBlank()) + .collect(Collectors.toMap(ImportRef::getPlugin, Function.identity())); + + for (PluginRef pluginRef : feature.getPlugins()) { + String version = pluginRef.getVersion(); + if (Version.emptyVersion.toString().equals(version)) { + ImportRef importRef = pluginImports.get(pluginRef.getId()); + if (importRef != null) { + version = importRef.getVersion() + "|" + importRef.getMatch(); + } + } + ArtifactKey plugin = resolvePluginReference(targetPlatform, pluginRef, version); + pluginRef.setVersion(plugin.getVersion()); - File location = targetPlatform.getArtifactLocation(plugin); + File location = targetPlatform.getArtifactLocation(plugin); if (location == null) { throw new MojoFailureException("location is missing for plugin " + plugin); } - setDownloadAndInstallSize(pluginRef, location); - } - - for (FeatureRef featureRef : feature.getIncludedFeatures()) { - ArtifactKey includedFeature = resolveFeatureReference(targetPlatform, featureRef); - featureRef.setVersion(includedFeature.getVersion()); - } - - return feature; - } - - private ArtifactKey resolvePluginReference(TargetPlatform targetPlatform, PluginRef pluginRef) - throws MojoFailureException { - try { - return targetPlatform.resolveArtifact(ArtifactType.TYPE_ECLIPSE_PLUGIN, pluginRef.getId(), - pluginRef.getVersion()); - } catch (IllegalArtifactReferenceException e) { - throw new MojoFailureException("Invalid plugin reference with id=" + quote(pluginRef.getId()) - + " and version=" + quote(pluginRef.getVersion()) + ": " + e.getMessage(), e); - } - } - - private ArtifactKey resolveFeatureReference(TargetPlatform targetPlatform, FeatureRef featureRef) - throws MojoFailureException { - try { - return targetPlatform.resolveArtifact(ArtifactType.TYPE_ECLIPSE_FEATURE, featureRef.getId(), - featureRef.getVersion()); - } catch (IllegalArtifactReferenceException e) { - throw new MojoFailureException("Invalid feature reference with id=" + quote(featureRef.getId()) - + " and version " + quote(featureRef.getVersion()) + ": " + e.getMessage(), e); - } - } - - private static String quote(String nullableString) { - if (nullableString == null) - return null; - else - return "\"" + nullableString + "\""; - } - - private void setDownloadAndInstallSize(PluginRef pluginRefToEdit, File artifact) { - // TODO 375111 optionally disable this? - long downloadSize = 0; - long installSize = 0; - if (artifact.isFile()) { - installSize = getInstallSize(artifact); - downloadSize = artifact.length(); - } else { - log.info("Download/install size is not calculated for directory based bundle " + pluginRefToEdit.getId()); - } - - pluginRefToEdit.setDownloadSize(downloadSize / KBYTE); - pluginRefToEdit.setInstallSize(installSize / KBYTE); - } - - protected long getInstallSize(File location) { - long installSize = 0; - FileLocker locker = fileLockService.getFileLocker(location); - locker.lock(); - try { - try { - try (JarFile jar = new JarFile(location)) { - Enumeration entries = jar.entries(); - while (entries.hasMoreElements()) { - JarEntry entry = entries.nextElement(); - long entrySize = entry.getSize(); - if (entrySize > 0) { - installSize += entrySize; - } - } - } - } catch (IOException e) { - throw new RuntimeException("Could not determine installation size of file " + location, e); - } - } finally { - locker.release(); - } - return installSize; - } + setDownloadAndInstallSize(pluginRef, location); + } + + for (FeatureRef featureRef : feature.getIncludedFeatures()) { + String version = featureRef.getVersion(); + if (Version.emptyVersion.toString().equals(version)) { + ImportRef importRef = featureImports.get(featureRef.getId()); + if (importRef != null) { + version = importRef.getVersion() + "|" + importRef.getMatch(); + } + } + ArtifactKey includedFeature = resolveFeatureReference(targetPlatform, featureRef, version); + featureRef.setVersion(includedFeature.getVersion()); + } + + return feature; + } +//from features action.... +// protected VersionRange getVersionRange(FeatureEntry entry) { +// String versionSpec = entry.getVersion(); +// if (versionSpec == null) +// return VersionRange.emptyRange; +// String match = entry.getMatch(); +// if ("versionRange".equals(match)) //$NON-NLS-1$ +// return VersionRange.create(versionSpec); +// Version version = Version.parseVersion(versionSpec); +// if (version.equals(Version.emptyVersion)) +// return VersionRange.emptyRange; +// if (!entry.isRequires()) +// return new VersionRange(version, true, version, true); +// if (match == null) +// // TODO should really be returning VersionRange.emptyRange here... +// return null; +// if (match.equals("perfect")) //$NON-NLS-1$ +// return new VersionRange(version, true, version, true); +// +// org.osgi.framework.Version osgiVersion = PublisherHelper.toOSGiVersion(version); +// if (match.equals("equivalent")) { //$NON-NLS-1$ +// Version upper = Version.createOSGi(osgiVersion.getMajor(), osgiVersion.getMinor() + 1, 0); +// return new VersionRange(version, true, upper, false); +// } +// if (match.equals("compatible")) { //$NON-NLS-1$ +// Version upper = Version.createOSGi(osgiVersion.getMajor() + 1, 0, 0); +// return new VersionRange(version, true, upper, false); +// } +// if (match.equals("greaterOrEqual")) //$NON-NLS-1$ +// return new VersionRange(version, true, Version.MAX_VERSION, true); +// return null; +// } + + private ArtifactKey resolvePluginReference(TargetPlatform targetPlatform, PluginRef pluginRef, String version) + throws MojoFailureException { + try { + return targetPlatform.resolveArtifact(ArtifactType.TYPE_ECLIPSE_PLUGIN, pluginRef.getId(), version); + } catch (IllegalArtifactReferenceException e) { + throw new MojoFailureException("Invalid plugin reference with id=" + quote(pluginRef.getId()) + + " and version=" + quote(pluginRef.getVersion()) + ": " + e.getMessage(), e); + } + } + + private ArtifactKey resolveFeatureReference(TargetPlatform targetPlatform, FeatureRef featureRef, String version) + throws MojoFailureException { + try { + return targetPlatform.resolveArtifact(ArtifactType.TYPE_ECLIPSE_FEATURE, featureRef.getId(), version); + } catch (IllegalArtifactReferenceException e) { + throw new MojoFailureException("Invalid feature reference with id=" + quote(featureRef.getId()) + + " and version " + quote(featureRef.getVersion()) + ": " + e.getMessage(), e); + } + } + + private static String quote(String nullableString) { + if (nullableString == null) + return null; + else + return "\"" + nullableString + "\""; + } + + private void setDownloadAndInstallSize(PluginRef pluginRefToEdit, File artifact) { + // TODO 375111 optionally disable this? + long downloadSize = 0; + long installSize = 0; + if (artifact.isFile()) { + installSize = getInstallSize(artifact); + downloadSize = artifact.length(); + } else { + log.info("Download/install size is not calculated for directory based bundle " + pluginRefToEdit.getId()); + } + + pluginRefToEdit.setDownloadSize(downloadSize / KBYTE); + pluginRefToEdit.setInstallSize(installSize / KBYTE); + } + + protected long getInstallSize(File location) { + long installSize = 0; + FileLocker locker = fileLockService.getFileLocker(location); + locker.lock(); + try { + try { + try (JarFile jar = new JarFile(location)) { + Enumeration entries = jar.entries(); + while (entries.hasMoreElements()) { + JarEntry entry = entries.nextElement(); + long entrySize = entry.getSize(); + if (entrySize > 0) { + installSize += entrySize; + } + } + } + } catch (IOException e) { + throw new RuntimeException("Could not determine installation size of file " + location, e); + } + } finally { + locker.release(); + } + return installSize; + } }