Skip to content

Commit

Permalink
Add support for TargetDefinition#implicitDependencies
Browse files Browse the repository at this point in the history
PDE has support for implicitDependencies defined in the target that
Tycho currently ignores.

This adds the required support to Tycho to understand dependencies
defined in this way.
  • Loading branch information
laeubi committed Dec 16, 2024
1 parent d823700 commit dd0c8df
Show file tree
Hide file tree
Showing 12 changed files with 672 additions and 467 deletions.
7 changes: 7 additions & 0 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,18 @@ If you are reading this in the browser, then you can quickly jump to specific ve

## 5.0.0 (under development)

## Support for implicit dependencies in target definitions

In target definitions Tycho now supports to use the `<implicitDependencies>`,
see [Eclipse Help](https://help.eclipse.org/latest/topic/org.eclipse.pde.doc.user/guide/tools/editors/target_editor/environment_page.htm)
for more details.

## Support for version ranges and no version for units in target definitions

In target definitions Tycho now supports to use a range as version of a unit or to skip the version entirely in `InstallableUnit` locations, just like Eclipse-PDE.
Specifying no version is equivalent to `0.0.0` which resolves to the latest version available.
All of the following variants to specify a version are now possible:

```
<target name="my-target">
<locations>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,13 @@
import java.util.Map;
import java.util.Set;
import java.util.function.Supplier;
import java.util.stream.Stream;

import org.codehaus.plexus.util.xml.Xpp3Dom;
import org.eclipse.equinox.p2.metadata.IRequirement;
import org.eclipse.tycho.ArtifactKey;
import org.eclipse.tycho.ArtifactType;
import org.eclipse.tycho.DefaultArtifactKey;
import org.eclipse.tycho.OptionalResolutionAction;
import org.eclipse.tycho.TargetEnvironment;
import org.eclipse.tycho.core.resolver.shared.IncludeSourceMode;
Expand Down Expand Up @@ -267,7 +270,9 @@ public DependencyResolverConfiguration getDependencyResolverConfiguration() {

@Override
public List<ArtifactKey> getAdditionalArtifacts() {
return extraRequirements;
Stream<DefaultArtifactKey> targetFiles = getTargets().stream().flatMap(tdf -> tdf.implicitDependencies())
.map(id -> new DefaultArtifactKey(ArtifactType.TYPE_ECLIPSE_PLUGIN, id.getId()));
return Stream.concat(extraRequirements.stream(), targetFiles).distinct().toList();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
/*******************************************************************************
* Copyright (c) 2024 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.core.osgitools.targetplatform;

import java.io.File;
import java.util.Collection;
import java.util.List;
import java.util.Objects;

import org.apache.maven.project.MavenProject;
import org.codehaus.plexus.component.annotations.Component;
import org.codehaus.plexus.component.annotations.Requirement;
import org.codehaus.plexus.logging.Logger;
import org.eclipse.tycho.ArtifactKey;
import org.eclipse.tycho.ArtifactType;
import org.eclipse.tycho.ClasspathEntry;
import org.eclipse.tycho.ReactorProject;
import org.eclipse.tycho.TargetPlatform;
import org.eclipse.tycho.classpath.ClasspathContributor;
import org.eclipse.tycho.core.TargetPlatformConfiguration;
import org.eclipse.tycho.core.TychoProjectManager;
import org.eclipse.tycho.targetplatform.TargetDefinition.ImplicitDependency;

@Component(role = ClasspathContributor.class, hint = "target-platform")
public class TargetPlatformClasspathContributor implements ClasspathContributor {

@Requirement
private Logger logger;

@Requirement
private TychoProjectManager projectManager;

@Override
public List<ClasspathEntry> getAdditionalClasspathEntries(MavenProject project, String scope) {

TargetPlatform platform = projectManager.getTargetPlatform(project).orElse(null);
if (platform == null) {
return List.of();
}
TargetPlatformConfiguration configuration = projectManager.getTargetPlatformConfiguration(project);
List<ImplicitDependency> dependencies = configuration.getTargets().stream()
.flatMap(tdf -> tdf.implicitDependencies()).distinct().toList();
return dependencies.stream().map(dependency -> getClasspathEntry(platform, dependency)).filter(Objects::nonNull)
.toList();
}

private ClasspathEntry getClasspathEntry(TargetPlatform targetPlatform, ImplicitDependency dependency) {
try {
ArtifactKey key = targetPlatform.resolveArtifact(ArtifactType.TYPE_ECLIPSE_PLUGIN, dependency.getId(),
null);

return new TargetPlatformClasspathEntry(targetPlatform, key);
} catch (Exception e) {
logger.warn("Can't resolve ImplicitDependency with id " + dependency.getId(), e);
return null;
}
}

private static final class TargetPlatformClasspathEntry implements ClasspathEntry {
private final TargetPlatform targetPlatform;
private final ArtifactKey key;
private List<File> files;

private TargetPlatformClasspathEntry(TargetPlatform targetPlatform, ArtifactKey key) {
this.targetPlatform = targetPlatform;
this.key = key;
}

@Override
public ReactorProject getMavenProject() {
return null;
}

@Override
public synchronized List<File> getLocations() {
if (files == null) {
File file = targetPlatform.getArtifactLocation(getArtifactKey());
if (file == null) {
files = List.of();
} else {
files = List.of(file);
}
}
return files;
}

@Override
public ArtifactKey getArtifactKey() {
return key;
}

@Override
public Collection<AccessRule> getAccessRules() {
return null;
}

@Override
public String toString() {
return "TargetPlatformClasspathEntry[" + key + "]";
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.stream.Stream;

import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
import org.eclipse.equinox.p2.core.IProvisioningAgent;
Expand Down Expand Up @@ -303,6 +304,11 @@ public String getTargetEE() {
return null;
}

@Override
public Stream<ImplicitDependency> implicitDependencies() {
return Stream.empty();
}

}

enum TestRepositories {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.stream.Stream;

import javax.inject.Inject;
import javax.inject.Named;
Expand Down Expand Up @@ -215,6 +216,11 @@ public String getTargetEE() {
return delegate.getTargetEE();
}

@Override
public Stream<ImplicitDependency> implicitDependencies() {
return delegate.implicitDependencies();
}

}

private static final class LatestVersionLocation implements InstallableUnitLocation {
Expand Down
11 changes: 10 additions & 1 deletion tycho-its/projects/compiler.annotations/annotations.target
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,14 @@
<?pde version="3.8"?>
<target name="annotations">
<locations>
<location includeDependencyDepth="none" includeSource="true" missingManifest="error" type="Maven">
<location includeDependencyDepth="none" includeDependencyScopes="compile" missingManifest="error" type="Maven">
<dependencies>
<dependency>
<groupId>org.eclipse.jdt</groupId>
<artifactId>org.eclipse.jdt.annotation</artifactId>
<version>2.3.100</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.annotation.bundle</artifactId>
Expand All @@ -19,4 +25,7 @@
</dependencies>
</location>
</locations>
<implicitDependencies>
<plugin id="org.eclipse.jdt.annotation"/>
</implicitDependencies>
</target>
10 changes: 1 addition & 9 deletions tycho-its/projects/compiler.annotations/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,8 @@
<version>1.0.0-SNAPSHOT</version>
<packaging>eclipse-plugin</packaging>
<properties>
<tycho-version>3.0.0-SNAPSHOT</tycho-version>
<repo-url>https://download.eclipse.org/releases/2022-03/</repo-url>
<tycho-version>5.0.0-SNAPSHOT</tycho-version>
</properties>
<repositories>
<repository>
<id>featureRepo</id>
<layout>p2</layout>
<url>${repo-url}</url>
</repository>
</repositories>
<build>
<plugins>
<plugin>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package test.jdt.annotations;

import org.eclipse.jdt.annotation.Nullable;

public class TestJDT {

public void callMeWithNull(@Nullable Object obj) {

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -108,13 +108,25 @@ public void testOSGiAnnotations() throws Exception {
assertTrue(dependencies.getAbsoluteFile() + " not found!", dependencies.isFile());
List<String> lines = Files.readAllLines(dependencies.toPath());
String collect = lines.stream().collect(Collectors.joining(",\r\n"));
// TODO we should possibly accept others that supply the ds annotations here?
assertTrue("org.eclipse.osgi.services not found in dependencies: " + collect,
lines.stream().anyMatch(s -> s.contains("org.eclipse.osgi.services")));
lines.stream().anyMatch(s -> s.contains("org.osgi.service.component.annotations")));
assertTrue("org.osgi.annotation.bundle not found in dependencies: " + collect,
lines.stream().anyMatch(s -> s.contains("org.osgi.annotation.bundle")));
assertTrue("org.osgi.annotation.versioning not found in dependencies: " + collect,
lines.stream().anyMatch(s -> s.contains("org.osgi.annotation.versioning")));
}

@Test
public void testImplicitJDTAnnotations() throws Exception {
Verifier verifier = getVerifier("compiler.annotations", false, true);
verifier.executeGoal("verify");
verifier.verifyErrorFreeLog();
File dependencies = new File(verifier.getBasedir(), "target/dependencies-list.txt");
assertTrue(dependencies.getAbsoluteFile() + " not found!", dependencies.isFile());
List<String> lines = Files.readAllLines(dependencies.toPath());
String collect = lines.stream().collect(Collectors.joining(",\r\n"));
assertTrue("org.eclipse.osgi.services not found in dependencies: " + collect,
lines.stream().anyMatch(s -> s.contains("org.eclipse.jdt.annotation")));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import java.util.Collection;
import java.util.List;
import java.util.Properties;
import java.util.stream.Stream;

import org.eclipse.tycho.IArtifactFacade;
import org.eclipse.tycho.MavenArtifactRepositoryReference;
Expand Down Expand Up @@ -54,9 +55,21 @@ public interface TargetDefinition {
@Override
public boolean equals(Object obj);

/**
*
* @return a stream of implicit dependencies defined in the target to add as an
* additional dependency to every project
*/
Stream<ImplicitDependency> implicitDependencies();

@Override
public int hashCode();

public interface ImplicitDependency {

String getId();
}

public interface Location {

/**
Expand Down
Loading

0 comments on commit dd0c8df

Please sign in to comment.