Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Consider restrictions when resolving the build version of depending features/plugins #845 #846

Merged
merged 1 commit into from
Apr 7, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -22,6 +23,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 @@ -90,23 +92,32 @@ 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())
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