Skip to content

Commit

Permalink
Fix #845 - Feature restrictions are not taken into account when using
Browse files Browse the repository at this point in the history
emptyVersion
  • Loading branch information
laeubi committed Apr 7, 2022
1 parent 8c958da commit ab8b241
Show file tree
Hide file tree
Showing 10 changed files with 457 additions and 128 deletions.
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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;

Expand All @@ -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<IInstallableUnit> candidateUnits) throws IllegalArtifactReferenceException {
if (id == null) {
throw new IllegalArtifactReferenceException("ID is required");
}

VersionRange versionRange = getVersionRangeFromReference(version);
IQuery<IInstallableUnit> query = QueryUtil.createLatestQuery(ArtifactTypeHelper.createQueryFor(type, id,
versionRange));
IQuery<IInstallableUnit> query = QueryUtil
.createLatestQuery(ArtifactTypeHelper.createQueryFor(type, id, versionRange));

IQueryResult<IInstallableUnit> matchingIUs = query.perform(candidateUnits.iterator());
if (matchingIUs.isEmpty()) {
Expand All @@ -43,14 +47,17 @@ 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) {
throw new IllegalArtifactReferenceException("The string \"" + version + "\" is not a valid OSGi version");
}
}

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);
Expand All @@ -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);
}
Expand All @@ -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;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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;

Expand All @@ -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;
Expand Down Expand Up @@ -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;

}
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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;

Expand All @@ -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;
Expand Down Expand Up @@ -88,22 +90,38 @@ public final Set<IInstallableUnit> 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);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<?xml version='1.0' encoding='UTF-8'?>
<?artifactRepository version='1.1.0'?>
<repository name='artifacts' type='org.eclipse.equinox.p2.artifact.repository.simpleRepository' version='1'>
</repository>
118 changes: 118 additions & 0 deletions tycho-its/projects/feature.restrictions/repository/content.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
<?xml version='1.0' encoding='UTF-8'?>
<?metadataRepository version='1.2.0'?>
<repository name='metadata' type='org.eclipse.equinox.internal.p2.metadata.repository.LocalMetadataRepository' version='1'>
<properties size='2'>
<property name='p2.timestamp' value='1648817439023'/>
<property name='p2.compressed' value='false'/>
</properties>
<units size='5'>
<unit id='org.apache.activemq.activemq-core' version='5.2.0' singleton='false'>
<update id='org.apache.activemq.activemq-core' range='[0.0.0,5.2.0)' severity='0'/>
<properties size='4'>
<property name='org.eclipse.equinox.p2.name' value='activemq-core'/>
<property name='org.eclipse.equinox.p2.description' value='The ActiveMQ Message Broker and Client implementations'/>
<property name='org.eclipse.equinox.p2.provider' value='The Apache Software Foundation'/>
<property name='org.eclipse.equinox.p2.doc.url' value='http://www.apache.org/'/>
</properties>
<provides size='79'>
<provided namespace='org.eclipse.equinox.p2.iu' name='org.apache.activemq.activemq-core' version='5.2.0'/>
<provided namespace='osgi.bundle' name='org.apache.activemq.activemq-core' version='5.2.0'/>
<provided namespace='osgi.identity' name='org.apache.activemq.activemq-core' version='5.2.0'>
<properties size='1'>
<property name='type' value='osgi.bundle'/>
</properties>
</provided>
<provided namespace='org.eclipse.equinox.p2.eclipse.type' name='bundle' version='1.0.0'/>
</provides>
<artifacts size='1'>
<artifact classifier='osgi.bundle' id='org.apache.activemq.activemq-core' version='5.2.0'/>
</artifacts>
<touchpoint id='org.eclipse.equinox.p2.osgi' version='1.0.0'/>
<touchpointData size='1'>
<instructions size='1'>
<instruction key='manifest'>
Bundle-SymbolicName: org.apache.activemq.activemq-core&#xA;Bundle-Version: 5.2.0&#xA;
</instruction>
</instructions>
</touchpointData>
</unit>
<unit id='com.test.base.feature.feature.group' version='1.0.0' singleton='false'>
<update id='com.test.base.feature.feature.group' range='[0.0.0,1.0.0)' severity='0'/>
<properties size='1'>
<property name='org.eclipse.equinox.p2.type.group' value='true'/>
</properties>
<provides size='1'>
<provided namespace='org.eclipse.equinox.p2.iu' name='com.test.base.feature.feature.group' version='1.0.0'/>
</provides>
<requires size='2'>
<required namespace='org.eclipse.equinox.p2.iu' name='org.apache.activemq.activemq-core' range='[5.2.0,5.2.0]'/>
<required namespace='org.eclipse.equinox.p2.iu' name='com.test.base.feature.feature.jar' range='[1.0.0,1.0.0]'>
<filter>
(org.eclipse.update.install.features=true)
</filter>
</required>
</requires>
<touchpoint id='null' version='0.0.0'/>
</unit>
<unit id='com.test.base.feature.feature.group' version='2.0.0' singleton='false'>
<update id='com.test.base.feature.feature.group' range='[0.0.0,2.0.0)' severity='0'/>
<properties size='1'>
<property name='org.eclipse.equinox.p2.type.group' value='true'/>
</properties>
<provides size='1'>
<provided namespace='org.eclipse.equinox.p2.iu' name='com.test.base.feature.feature.group' version='2.0.0'/>
</provides>
<requires size='2'>
<required namespace='org.eclipse.equinox.p2.iu' name='org.apache.activemq.activemq-core' range='[5.4.0,5.4.0]'/>
<required namespace='org.eclipse.equinox.p2.iu' name='com.test.base.feature.feature.jar' range='[2.0.0,2.0.0]'>
<filter>
(org.eclipse.update.install.features=true)
</filter>
</required>
</requires>
<touchpoint id='null' version='0.0.0'/>
</unit>
<unit id='com.test.base.feature.feature.jar' version='1.0.0'>
<provides size='3'>
<provided namespace='org.eclipse.equinox.p2.iu' name='com.test.base.feature.feature.jar' version='1.0.0'/>
<provided namespace='org.eclipse.equinox.p2.eclipse.type' name='feature' version='1.0.0'/>
<provided namespace='org.eclipse.update.feature' name='com.test.base.feature' version='1.0.0'/>
</provides>
<filter>
(org.eclipse.update.install.features=true)
</filter>
<artifacts size='1'>
<artifact classifier='org.eclipse.update.feature' id='com.test.base.feature' version='1.0.0'/>
</artifacts>
<touchpoint id='org.eclipse.equinox.p2.osgi' version='1.0.0'/>
<touchpointData size='1'>
<instructions size='1'>
<instruction key='zipped'>
true
</instruction>
</instructions>
</touchpointData>
</unit>
<unit id='com.test.base.feature.feature.jar' version='2.0.0'>
<provides size='3'>
<provided namespace='org.eclipse.equinox.p2.iu' name='com.test.base.feature.feature.jar' version='2.0.0'/>
<provided namespace='org.eclipse.equinox.p2.eclipse.type' name='feature' version='1.0.0'/>
<provided namespace='org.eclipse.update.feature' name='com.test.base.feature' version='2.0.0'/>
</provides>
<filter>
(org.eclipse.update.install.features=true)
</filter>
<artifacts size='1'>
<artifact classifier='org.eclipse.update.feature' id='com.test.base.feature' version='2.0.0'/>
</artifacts>
<touchpoint id='org.eclipse.equinox.p2.osgi' version='1.0.0'/>
<touchpointData size='1'>
<instructions size='1'>
<instruction key='zipped'>
true
</instruction>
</instructions>
</touchpointData>
</unit>
</units>
</repository>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
bin.includes = feature.xml
10 changes: 10 additions & 0 deletions tycho-its/projects/feature.restrictions/sample.feature/feature.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<feature
id="com.test.sample.feature"
version="1.0.0">
<includes id="com.test.base.feature" version="0.0.0"/>
<requires>
<import feature="com.test.base.feature" match="compatible" version="1.0.0"/>
</requires>

</feature>
34 changes: 34 additions & 0 deletions tycho-its/projects/feature.restrictions/sample.feature/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com.test</groupId>
<version>1.0.0</version>
<artifactId>com.test.sample.feature</artifactId>
<packaging>eclipse-feature</packaging>
<properties>
<tycho-version>2.7.0</tycho-version>
<repo-url>file:/${project.basedir}/../repository</repo-url>
</properties>

<repositories>
<repository>
<id>featureRepo</id>
<layout>p2</layout>
<url>${repo-url}</url>
</repository>
</repositories>

<build>
<plugins>
<plugin>
<groupId>org.eclipse.tycho</groupId>
<artifactId>tycho-maven-plugin</artifactId>
<version>${tycho-version}</version>
<extensions>true</extensions>
</plugin>
</plugins>
</build>
</project>
Loading

0 comments on commit ab8b241

Please sign in to comment.