Skip to content

Commit

Permalink
Fix #406 Resolve DS classpath entry and generate component xmls
Browse files Browse the repository at this point in the history
  • Loading branch information
laeubi committed Apr 14, 2022
1 parent 24a8bba commit be74d52
Show file tree
Hide file tree
Showing 21 changed files with 609 additions and 89 deletions.
24 changes: 24 additions & 0 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,30 @@ This page describes the noteworthy improvements provided by each release of Ecli

## 3.0.0 (under development)

### Support for PDE Declarative Component Annotation progressing

One can enable either global or per project the generation of component xmls in PDE. Until now it was required for Tycho to still import the annotation package even though `classpath=true` was set, beside that one needs to check in the generated xmls.

Tycho now has improved support for this with the following:

1. if there is a `.settings/org.eclipse.pde.ds.annotations.prefs` in the project, tycho adapts the settings there and if `classpath=true` is set no more imports are required.
2. one can enable a new `tycho-ds-plugin` where global default settings can be configured if project settings are not present, the below shows an example with default values:
```
<plugin>
<groupId>org.eclipse.tycho</groupId>
<artifactId>tycho-ds-plugin</artifactId>
<version>${tycho-version}</version>
<configuration>
<classpath>true</classpath>
<dsVersion>1.3</dsVersion>
<enabled>false</enabled>
<path>OSGI-INF</path>
<skip>false</skip>
</configuration>
</plugin>
```
If the `tycho-ds-plugin` is enabled for a project it generated the necessary xml files if not already present in the project.

### Improved P2 transport for more efficiently http-cache handling and improved offline mode

P2 default transport is more designed as a weak cache that assumes the user is always online.
Expand Down
1 change: 1 addition & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -476,6 +476,7 @@
<module>tycho-source-plugin</module>
<module>target-platform-configuration</module>
<module>tycho-maven-plugin</module>
<module>tycho-ds-plugin</module>
<!-- surefire -->
<module>tycho-surefire</module>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import org.eclipse.equinox.p2.metadata.IInstallableUnit;
import org.eclipse.tycho.ArtifactKey;
import org.eclipse.tycho.ArtifactType;
import org.eclipse.tycho.artifacts.DependencyResolutionException;
import org.eclipse.tycho.artifacts.IllegalArtifactReferenceException;
import org.eclipse.tycho.artifacts.TargetPlatform;
import org.junit.Before;
Expand Down Expand Up @@ -159,9 +160,9 @@ public void testResolveFeature() throws Exception {

@Test
public void testResolveUnknownType() throws Exception {
IllegalArtifactReferenceException e = assertThrows(IllegalArtifactReferenceException.class,
DependencyResolutionException e = assertThrows(DependencyResolutionException.class,
() -> subject.resolveArtifact("invalid-type", "unit", ANY_VERSION));
assertTrue(e.getMessage().contains("Unknown artifact type"));
assertTrue(e.getMessage().contains("invalid-type"));
}

private FinalTargetPlatformImpl createTP() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
import org.eclipse.equinox.p2.metadata.VersionRange;
import org.eclipse.equinox.p2.metadata.expression.IMatchExpression;
import org.eclipse.equinox.p2.publisher.eclipse.BundlesAction;
import org.eclipse.equinox.p2.query.IQuery;
import org.eclipse.equinox.p2.query.IQueryResult;
import org.eclipse.equinox.p2.query.QueryUtil;
import org.eclipse.equinox.spi.p2.publisher.PublisherHelper;
Expand Down Expand Up @@ -148,11 +149,9 @@ public Map<TargetEnvironment, P2ResolutionResult> resolveArtifactDependencies(Ta
for (ArtifactKey artifactKey : artifacts) {
QueryableCollection queriable = new QueryableCollection(targetPlatform.getInstallableUnits());
VersionRange range = new VersionRange(artifactKey.getVersion());
IRequirement requirement = MetadataFactory.createRequirement(IInstallableUnit.NAMESPACE_IU_ID,
artifactKey.getId(), range, null, 1 /* min */, Integer.MAX_VALUE /* max */,
false /* greedy */);
IQueryResult<IInstallableUnit> result = queriable
.query(QueryUtil.createLatestQuery(QueryUtil.createMatchQuery(requirement.getMatches())), monitor);
IQuery<IInstallableUnit> query = ArtifactTypeHelper.createQueryFor(artifactKey.getType(),
artifactKey.getId(), range);
IQueryResult<IInstallableUnit> result = queriable.query(QueryUtil.createLatestQuery(query), monitor);
roots.addAll(result.toUnmodifiableSet());
}
Map<TargetEnvironment, P2ResolutionResult> results = new LinkedHashMap<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,8 @@ public class ArtifactTypeHelper {
*
* @param type
* Eclipse artifact type as defined in Tycho's {@link ArtifactType}
* @throws IllegalArtifactReferenceException
* if the given artifact type is unknown
*/
public static IQuery<IInstallableUnit> createQueryFor(String type, String id, VersionRange versionRange)
throws IllegalArtifactReferenceException {
public static IQuery<IInstallableUnit> createQueryFor(String type, String id, VersionRange versionRange) {

if (ArtifactType.TYPE_ECLIPSE_PLUGIN.equals(type)) {
return QueryUtil.createMatchQuery(createBundleRequirement(id, versionRange).getMatches());
Expand All @@ -63,7 +60,10 @@ public static IQuery<IInstallableUnit> createQueryFor(String type, String id, Ve
return QueryUtil.createIUQuery(id, versionRange);

} else {
throw new IllegalArtifactReferenceException("Unknown artifact type \"" + type + "\"");

IRequirement requirement = MetadataFactory.createRequirement(type, id, versionRange, null,
1 /* min */, Integer.MAX_VALUE /* max */, false /* greedy */);
return QueryUtil.createMatchQuery(requirement.getMatches());
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
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.ArtifactType;
import org.eclipse.tycho.DefaultArtifactKey;
import org.eclipse.tycho.ReactorProjectIdentities;
import org.eclipse.tycho.artifacts.DependencyResolutionException;
Expand Down Expand Up @@ -101,7 +102,10 @@ public final org.eclipse.tycho.ArtifactKey resolveArtifact(String type, String i
} else {
resolvedUnit = resolveUnit(type, id, ArtifactMatcher.parseAsOSGiVersion(version));
}
return new DefaultArtifactKey(type, id, resolvedUnit.getVersion().toString());
if (ArtifactType.TYPE_ECLIPSE_FEATURE.equals(type)) {
return new DefaultArtifactKey(type, id, resolvedUnit.getVersion().toString());
}
return new DefaultArtifactKey(type, resolvedUnit.getId(), resolvedUnit.getVersion().toString());
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/*******************************************************************************
* Copyright (c) 2022 Christoph Läubrich 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
* https://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Christoph Läubrich - initial API and implementation
*******************************************************************************/
package org.eclipse.tycho.artifacts.configuration;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Properties;

import org.apache.maven.model.Plugin;
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.codehaus.plexus.util.xml.Xpp3Dom;
import org.eclipse.tycho.core.DeclarativeServicesConfiguration;
import org.osgi.framework.Version;

@Component(role = DeclarativeServiceConfigurationReader.class)
public class DeclarativeServiceConfigurationReader {

public static final String DEFAULT_ADD_TO_CLASSPATH = "true";
public static final String DEFAULT_DS_VERSION = "1.3";
private static final String PROPERTY_CLASSPATH = "classpath";
private static final String PROPERTY_DS_VERSION = "dsVersion";
private static final String PROPERTY_ENABLED = "enabled";

private static final String PDE_DS_ANNOTATIONS_PREFS = ".settings/org.eclipse.pde.ds.annotations.prefs";

@Requirement
private Logger logger;

public DeclarativeServicesConfiguration getConfiguration(MavenProject mavenProject) throws IOException {
Properties settings = getProjectSettings(mavenProject.getBasedir(), getMojoSettings(mavenProject, logger),
mavenProject, logger);
if (Boolean.parseBoolean(settings.getProperty(PROPERTY_ENABLED))) {
return new DeclarativeServicesConfiguration() {

@Override
public boolean isAddToClasspath() {
return Boolean.parseBoolean(settings.getProperty(PROPERTY_CLASSPATH, DEFAULT_ADD_TO_CLASSPATH));
}

@Override
public Version getSpecificationVersion() {
String property = settings.getProperty(PROPERTY_DS_VERSION, DEFAULT_DS_VERSION);
if (property.startsWith("V")) {
property = property.substring(1).replace('_', '.');
}
return Version.parseVersion(property);
}
};
}
return null;
}

private static Properties getProjectSettings(File basedir, Properties mojoProperties, MavenProject mavenProject,
Logger logger) throws FileNotFoundException, IOException {
Properties properties = new Properties(mojoProperties);
File prefs = new File(basedir, PDE_DS_ANNOTATIONS_PREFS);
if (prefs.exists()) {
try (FileInputStream stream = new FileInputStream(prefs)) {
properties.load(stream);
logger.debug("declarative-services project configuration for " + mavenProject.toString() + ":"
+ System.lineSeparator() + properties);
}
}
return properties;
}

private static Properties getMojoSettings(MavenProject project, Logger logger) {
Properties properties = new Properties();
Plugin plugin = project.getPlugin("org.eclipse.tycho:tycho-ds-plugin");
if (plugin != null) {
Xpp3Dom configuration = (Xpp3Dom) plugin.getConfiguration();
if (configuration != null) {
if (logger.isDebugEnabled()) {
logger.debug("declarative-services mojo configuration for " + project.toString() + ":"
+ System.lineSeparator() + configuration.toString());
}
setProperty(properties, PROPERTY_CLASSPATH, configuration.getAttribute(PROPERTY_CLASSPATH));
setProperty(properties, PROPERTY_DS_VERSION, configuration.getAttribute(PROPERTY_DS_VERSION));
setProperty(properties, PROPERTY_ENABLED, configuration.getAttribute(PROPERTY_ENABLED));
}
}
return properties;
}

private static void setProperty(Properties properties, String key, String attribute) {
if (attribute != null && !attribute.isEmpty()) {
properties.setProperty(key, attribute);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*******************************************************************************
* Copyright (c) 2022 Christoph Läubrich 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
* https://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Christoph Läubrich - initial API and implementation
*******************************************************************************/
package org.eclipse.tycho.core;

import org.osgi.framework.Version;

public interface DeclarativeServicesConfiguration {

/**
* Controls if the DS components annotations are made available on the compile-classpath, this
* means no explicit import is required.
*/
boolean isAddToClasspath();

/**
* Controls the declarative services specification version to use.
*/
Version getSpecificationVersion();

}
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
import org.codehaus.plexus.component.annotations.Component;
import org.codehaus.plexus.component.annotations.Requirement;
import org.codehaus.plexus.logging.Logger;
import org.eclipse.equinox.spi.p2.publisher.PublisherHelper;
import org.eclipse.osgi.container.Module;
import org.eclipse.osgi.container.ModuleContainer;
import org.eclipse.osgi.container.ModuleRevision;
Expand All @@ -47,16 +48,21 @@
import org.eclipse.tycho.ArtifactDescriptor;
import org.eclipse.tycho.ArtifactKey;
import org.eclipse.tycho.ArtifactType;
import org.eclipse.tycho.DefaultArtifactKey;
import org.eclipse.tycho.PackagingType;
import org.eclipse.tycho.ReactorProject;
import org.eclipse.tycho.TychoConstants;
import org.eclipse.tycho.artifacts.DependencyArtifacts;
import org.eclipse.tycho.artifacts.DependencyResolutionException;
import org.eclipse.tycho.artifacts.IllegalArtifactReferenceException;
import org.eclipse.tycho.artifacts.TargetPlatform;
import org.eclipse.tycho.artifacts.configuration.DeclarativeServiceConfigurationReader;
import org.eclipse.tycho.classpath.ClasspathEntry;
import org.eclipse.tycho.classpath.ClasspathEntry.AccessRule;
import org.eclipse.tycho.core.ArtifactDependencyVisitor;
import org.eclipse.tycho.core.ArtifactDependencyWalker;
import org.eclipse.tycho.core.BundleProject;
import org.eclipse.tycho.core.DeclarativeServicesConfiguration;
import org.eclipse.tycho.core.PluginDescription;
import org.eclipse.tycho.core.TargetPlatformConfiguration;
import org.eclipse.tycho.core.TychoProject;
Expand Down Expand Up @@ -118,6 +124,9 @@ public class OsgiBundleProject extends AbstractTychoProject implements BundlePro
@Requirement
private EquinoxServiceFactory equinox;

@Requirement
private DeclarativeServiceConfigurationReader dsConfigReader;

@Override
public ArtifactDependencyWalker getDependencyWalker(ReactorProject project, TargetEnvironment environment) {
return getDependencyWalker(project);
Expand Down Expand Up @@ -508,6 +517,27 @@ private void addExtraClasspathEntries(List<ClasspathEntry> classpath, ReactorPro
.add(new DefaultClasspathEntry(project, projectKey, Collections.singletonList(location), null));
}
}
try {
DeclarativeServicesConfiguration configuration = dsConfigReader.getConfiguration(getMavenProject(project));
if (configuration != null && configuration.isAddToClasspath()) {
TargetPlatform tp = TychoProjectUtils.getTargetPlatform(project);
org.osgi.framework.Version specificationVersion = configuration.getSpecificationVersion();
ArtifactKey dsJar = tp.resolveArtifact(PublisherHelper.CAPABILITY_NS_JAVA_PACKAGE,
"org.osgi.service.component.annotations",
"[" + specificationVersion + "," + (specificationVersion.getMajor() + 1) + ".0.0)");
File location = tp.getArtifactLocation(
new DefaultArtifactKey(ArtifactType.TYPE_ECLIPSE_PLUGIN, dsJar.getId(), dsJar.getVersion()));
logger.debug("Resolved declarative service specification " + specificationVersion + " to "
+ dsJar.getId() + " " + dsJar.getVersion() + " " + location);
DefaultAccessRule rule = new DefaultAccessRule("org/osgi/service/component/annotations/*", false);
classpath.add(new DefaultClasspathEntry(project, getArtifactKey(project),
Collections.singletonList(location), List.of(rule)));
}
} catch (IOException e) {
logger.warn("Can't read Declarative Services Configuration: " + e.getMessage(), e);
} catch (IllegalArtifactReferenceException | DependencyResolutionException e) {
logger.warn("Can't find declarative service specification in target platform: " + e.getMessage(), e);
}
}

protected DefaultClasspathEntry addBundleToClasspath(ArtifactDescriptor matchingBundle, String path) {
Expand Down
42 changes: 42 additions & 0 deletions tycho-ds-plugin/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.eclipse.tycho</groupId>
<artifactId>tycho</artifactId>
<version>3.0.0-SNAPSHOT</version>
</parent>
<artifactId>tycho-ds-plugin</artifactId>
<packaging>maven-plugin</packaging>

<name>Tycho OSGi Declarative Services Plugin</name>
<description>A plugin for handling OSGi Declarative Services</description>

<dependencies>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-compat</artifactId>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-plugin-api</artifactId>
</dependency>
<dependency>
<groupId>org.apache.maven.plugin-tools</groupId>
<artifactId>maven-plugin-annotations</artifactId>
</dependency>
<dependency>
<groupId>org.codehaus.plexus</groupId>
<artifactId>plexus-utils</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.tycho</groupId>
<artifactId>tycho-core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>biz.aQute.bnd</groupId>
<artifactId>biz.aQute.bndlib</artifactId>
<version>6.2.0</version>
</dependency>
</dependencies>
</project>
Loading

0 comments on commit be74d52

Please sign in to comment.