Updating RCP project to Eclipse Tycho >= 2.0 leads to "Unable to satisfy dependency" for features from different repositories - eclipse-rcp

Using tycho 1.x worked for my target platform definition based RCP application including features with dependencies from different repositories. Because of a bug with tool bars in RCP 4.18, I updated the project to RCP 4.20. With this RCP version, my UI tests does not work anymore with Tycho 1.x. So I updated to Tycho 2.x but get another problem: The dependencies of features from different repositories can not be resolved anymore, but it works, if I add all the repository URLs to features location in my target platform definition (or adding all repositories and units to one location entry). Because of different reasons, these are no options. Is there a possibility to get the old behavior and what is the reason for this change?

Since Tycho >= 2.0 is not scanning all locations of a target platform file, before resolving RCP features, there are two possibilities to fetch plugins, included in the feature, from different p2 repositories:
Add all p2 repositories needed for the feature to the target platform location:
<locations>
<location ...
<unit ... feature
<repository ... of included plugin 1
<repository ... of included plugin 2
</location>
</locations>
Use p2 composite repositories with child repositories to resolve the feature:
<locations>
<location ...
<unit ... feature
<repository ... composite repo with child repos of included plugins
</location>
</locations>
For me, the problem is only solved with composite repositories, because it is not possible to add multiple repositories to a location of a target platform generator file.

Related

Tycho and Eclipse: How to resolve OSGI dependencies to my own bundles at development time within Eclipse, without opening all of them in the IDE

Background
My Eclipse RCP application is built using Tycho. It consists of multiple components (in the form of OSGi bundles/Eclipse plug-ins). One of these component contains the product file and materializes the product.
There is a reactor POM at the application root, which builds all components in order, but I also want to build other components independently (using mvn deploy) .
Building such a single component works as follows:
Retrieve the latest versions of all the component's dependencies from our company (p2) repository.
Build the component.
Deploy the component to our company repository to be used as a dependency for other components itself.
Note: Our repository is a normal maven2 repository hosted on a Nexus, whose RCP artifacts are automatically mapped to a p2 repository format as well. This way, Tycho can use the p2 repository format to find dependencies, while the standard Maven deployment can be used. This works fine.
Note: My parent POM makes sure that we look for dependencies at the p2 repository URL. The deployment URL is the default maven2 format location of the repository. This works fine.
Problem
When building such a single component through the command-line (mvn deploy), Maven looks for intra-project dependencies in the p2 repository and they are correctly resolved (i.e. latest version is automatically downloaded and used in build).
However, when developing in Eclipse, the IDE cannot resolve them. The manifest files gives an error at each of my intra-project dependencies that they cannot be resolved.
Question
My question is: How can I make the Eclipse IDE look for dependencies (and new versions of dependencies) in either:
My local p2 repository (~/.m2/repository/p2/osgi/bundles)
My company p2 repository (nexus.mycompany.com/myproduct-snapshots/.meta/p2)
Ideally, it would look for them every time and fetch the latest version if a newer version is available.
If it does not use the p2 repository URLs in the POM, how should I configure Eclipse?
Example
Consider an eclipse plug-in com.mycompany.myproduct.fancy, which depends on another eclipse plug-in com.mycompany.myproduct.core.
Both also have a POM (configured for Tycho use), which (through their parent POM) have my Nexus repositories configured correctly: maven2 repository URL for deployment and p2 repository URL to look for dependencies.
First I deploy the core plug-in to my maven repository (using the default mvn deploy). The Nexus repository will provide this deployed plug-in in both maven and p2 format.
When I build the fancy component through the command line (using mvn install), the (earlier deployed) core component is found and downloaded automatically.
project/com.mycompany.myproduct.fancy$ mvn clean install
<searches in p2 repository, download core>
<builds fancy>
<SUCCESS>
When I open a new Eclipse workspace and open the fancy component, its Manifest (which contains its dependencies) gives the following error:
Bundle 'com.mycompany.myproduct.core' cannot be resolved.
My question is: how can I develop the fancy component in the Eclipse IDE without the need to open core as project in Eclipse.
Speculation
This is some speculation from my side. Please correct me if I'm wrong and any other solution to the actual problem is also welcome!
I know the m2e plug-in of the Eclipse IDE currently maps Maven POMs to Eclipse concepts (using m2e connectors). I have installed the dedicated Tycho connectors. For example, the mvn compile step is actually performed by the Eclipse JDT compiler.
I also know that when a complete Tycho product is started in Eclipse, it is run in the Eclipse PDE environment. For example, I need to a specify a target platform in my Run configuration.
I know I can open all components in my Eclipse workspace. This would solve the problem, but is not feasible as I have many components and this would break independent component development.
I assume the Eclipse m2e mapping and/or the PDE build environment is not smart enough to fetch (latest) dependencies automatically at build time. Please correct me if I'm wrong. :)
Therefore, I assume I need to specify the target platform at build time too. I have taken a look at Window > Preferences > Plug-in Development > Target Platform. I can add our p2 repository to the Target Platform, which solves the problem. However this gives many problems:
I need a feature containing all components for this to work. Only features can be added.
Every time I deploy a new build of a single component, I would have to rebuild the complete feature (to create a new feature version on our p2 repository).
Every time I update a component and build the feature, I would have to manually change the Target Platform.
If the above is all correct, I speculate I need an m2e connector (or a different one from the current one) that actually checks the p2 repositories specified in the POM when resolving the OSGi dependencies and automatically adds those to the target platform.
As indicated by Nick Wilson, you will need to install the m2e Tycho Configurator, which basically "links up" Eclipse and Tycho (i.e., makes Tycho available in Eclipse).
You should've been pointed towards it after having installed m2e, but you can also install it manually:
Go to Window > Preferences > Maven > Discovery.
Click the "Open Catalog" button. This will open the "m2e Marketplace" window.
Search for "tycho", this should give you the "Tycho Configurator" as sole search result.
Click "Finish", you're done.
I've had this issue as well, and it isn't simple to find the solution, so I hope this helps!
The "most automated" way to configure your target platform in Eclipse is to use a target file. That file can be checked in with your sources, so every developer only needs to open the file and click on "Set as Target Platform" to activate it. AFAIK there is no m2e connector or Eclipse plug-in which does that automatically.
Given your development process, setting up this target file is a little more tricky. Since you don't have a feature which contains the latest version of all your bundles, you need to include the bundles directly in the target file. This is not possible via the rich editor, but can be done with a text editor:
Create a target definition file, add your p2 repository, and select any feature from that p2 repository. Save the file.
Open the target file in a text editor, remove the <unit> entry for the feature you added.
Instead, add an entry for each of your bundles:
<unit id="a.bundle.symbolic.name" version="0.0.0"/>
This target file then contains the latest version of each of the listed bundles. To see the content, open the file with the "Target Editor" again and switch to the "Content" tab. This file can now be used by all developers.
Note: When a new version of one of the bundles is deployed to Nexus, the developers will only see that new version if they open the target file and choose "Set as Target Platform" again.

The best practice to use Tycho/Maven to remove jars dependencies in Eclipse RCP?

I'm working one an Eclipse RCP project. Currently we create a dependencies plug-in project and put all jars libraries into that project and export all packages. This method will give a huge repo, thus we want to use Tycho/Maven and let it figure out the dependencies for us.
The first approach is removing dependenciec project and use p2-maven-pluging to transform existing jars libraries to p2 format repo. Install all libraries from p2 repos and add required bundle in Require-Bundle section in each MANIFEST.MF. This is a little bit tedious since in every project having dependencies in Require-Bundle, I have to manually replace it to corresponding bundle names. And in the end, the project build using Tycho could successfully run, but in Eclipse it gives me java.lan.NoClassDefFoundError: Could not initialize class X.
I think there are few configuration files, where Tycho depends on some of them and Eclipse depends on the rest, but I'm not sure what it is.
The second approach is removing all jars in dependencies project but adding them in Require-Bundle or Import-Package. However, both won't work since in Export-Package section Eclipse will complain these packages are not existed. Thus other projects depends on this dependencies project won't find those packages they need, which causing more errors in Eclipse.
Does anyone know the best practice to deal with this issue?
Update:
I'm using basically the first approach, but add dependencies in Import-Package in each project instead of Require-Bundle. This would eliminate the need to specify the specific bundle version, as long as they provide the same API and they are compatible, your application would work. So everytimes I update private p2 repository, I don't need to change MANIFEST.MF in each project.
The only MANIFEST.MF I need to manually add dependencies in Require-Bundle is a library developed by our self. Without it, Tycho won't fetch required dependencies from private p2 repository. If still get NoClassDefFoundError, try adding all plugins in Run -> Run Configuration .. -> plug-ins, it may help.
I definitely not apply your approach 1, with the mega-plugin of exports. There's a related discussion here: Handling non-OSGi dependencies when integrating Maven, Tycho and Eclipse
As a rule, use Import-Package instead of Require-Bundle.
To get bundles will appear in the Export-Package section Eclipse:
if they are non-Eclipse (maven libraries), then build the project and reference the libraries in the Eclipse runtime section.
if they are Eclipse dependences, they should be in your workspace or Target Platform.
More generally, it may help for you to define a Target Platform. You can build/deploy all of your locally created plugins into a local p2 repository (see http://www.sonatype.org/nexus/). Then add that p2 site to your Target Platform.

p2 repository only with feature content and no dependencies

I need to create p2 repositories to add extra software in my application.
for instance I want to externalize all i18n bundle, so I have a set of features with only i18n fragments.
The way I do that is from a complete p2 repository that was build by pde and containt the product and the i18n plugins and features.
I try to use the p2.mirror ant task to create a p2 repository with only the i18n fragments but the problem is that it always embbed the host bundles that those i18n bundle depend on. This makes my p2 repo huge because it has most of my application along with the i18n.
<p2.mirror source="file://${build.repo.path}" destination="file://${i18n.repo.path}">
<iu id="org.talend.i18n.all-feature.feature.group" version="" />
</p2.mirror>
Is there a way to create a p2 repository including only the bundle that are referenced in a given feature and not the ones that host them ?
You need to add so-called "slicing options" and specify that you only want strict version range dependencies:
<p2.mirror ...>
<slicingoptions followStrict="true" />
</p2.mirror>
The inclusion relationship between features and plug-ins is encoded in p2 as strict version range dependency, so with this option you should only get the feature and its included plug-ins.
Note that p2 relies on the publishers to correctly translate the information from the feature.xml. If you use a non-standard publisher or influence the publishing via a p2.inf, the strict version range dependencies may not correspons 1:1 to the inclusions. In this case, it is not possible to achieve what you want. p2 mirroring will only operate on p2 metadata – there is no option to make it look at the feature.xml again.

How can I use Eclipse p2 repositories from Maven?

I am trying to create an Eclipse based setup where Eclipse projects are Maven based. So it should all work with Maven whether or not Eclipse is used.
I have a dependencies on various Eclipse project libraries, with more to be added. I want to use p2 repositories, and I've managed to pull an Eclipse EMF library and turn it into a jar following this example: Use dependencies from Eclipse p2 repository in a regular Maven build?
The problem is, I could not find a way of streamlining the process. I'd need to manually install the re-packaged dependency from the question given above to local Maven repository so that I can reference that in other projects. I'd like to seamlessly integrate artefacts from p2 repositories to my Maven based setup. m4e does not look like the smooth solution I'm looking for: Ideally I'd like to distribute a set of directories which would do everything in response to a simple mvn clean install : pull libraries from p2 repo, pull other libraries from Maven repositories etc..
Is this doable via Maven and Tycho integration?
Update: first, clarification to the question: just being able to reference to P2 repositories does not help with the scenario where this reference needs to be used from another project. The library (or libraries) referenced from P2 repository must be re-packaged as a jar so that it can be referenced by other Maven projects. The referenced question does the packaging. However, it does not explain how this repackaged output (assembly) can be used from other projects. In my case, this turned out to be referencing the assembly from an aggregating POM, and inheriting form that POM for all projects that would like to use the library with the P2 repository origin.
Tycho projects can pull their dependencies from both p2 repositories and Maven repositories (see this related answer). This could be a solution for you, even if you are not building for an OSGi runtime: Most OSGi bundles also work as "plain" JARs on the classpath.
Limitation: The artifacts referenced from Maven repositories also have to be OSGi bundles, so that Tycho considers them for dependency resolution. If this is not the case (and you can't find replacements which are OSGi bundles), you may be able to combine Tycho's dependency resolution with plain Maven plug-ins:
Use one of Tycho's packaging types (e.g. eclipse-feature) and specify the dependencies to the p2 artifacts in the file format for the packaging type (e.g. a feature.xml)
Additionally configure the plain Maven goals in your POM. Tycho injects the OSGi/p2 dependencies into the Maven model at runtime, so for example a maven-compiler-plugin:compile call would see both the Maven dependencies and the p2 dependencies.
The solution is to create a multi module setup with Maven, and declare a dependency on the outputs of EMF library re-packaging (from the question I've referenced) The parent pom for all projects has this:
<dependencies>
<dependency>
<groupId>com.mymodule</groupId>
<artifactId>myartifact</artifactId>
<version>0.0.1</version>
<classifier>repackaged</classifier>
</dependency>
</dependencies>
<modules>
<module>../mymodule</module>
</modules>
Which lets all modules that has this module as parents access the repackaged P2 artifacts.

How can I automatically build multiple Eclipse Plug-In Projects as one Jenkins project?

we're using Jenkins as our build server. We have a Project which is built out of Eclipse Plug-Ins, a core project and several other plugins. Building the Core on Jenkins and using Sonar on it is relatively.
Now we want to create a Jenkins build where the whole Project is being automatically built and tested by Sonar. Internet research showed to change the packaging to "pom", which can't be done because the Tycho plugin needs to have packaging set to "eclipse-plugin".
What are we doing wrong and how do you setup a project like this in Jenkins?
If any additional information is needed, please do tell.
You should create an "umbrella" Maven project with pom packaging and make all of your other project modules of this aggregator. In addition however the whole group of projects need to be accessible from your SCM tool as a single entity. If you are using Subversion this is easily achievable by means of svn:externals, with other tools I suspect you'd have to alter your configuration. I suggest you also check out whether there's any Jenkins plugins that might be of help.
For git, you can use the submodules feature to achieve the same as with svn:externals. See for example mylyn, which probably comes close to what you are trying to achieve:
git clone git://git.eclipse.org/gitroot/mylyn/org.eclipse.mylyn.git
Given this example directory layout:
+ParentDir
-pom.xml
+ProjectA
-pom.xml
+ProjectB
+SubDirB
-pom.xml
Contents of pom.xml in ParentDir should include the following:
<packaging>pom</packaging>
<modules>
<module>ProjectA/pom.xml</module>
<module>ProjectB/SubDirB/pom.xml</module>
</modules>
And when you invoke Maven on this top-level POM, it will add ProjectA and ProjectB to the reactor list to be built.
This can be adapted for similar projects, and the <module> tag accepts relative paths, for example ../../SomeProject/pom.xml.