Showing posts with label rcp. Show all posts
Showing posts with label rcp. Show all posts

Monday, November 12, 2007

Building Eclipse Plugins with Maven 2

Update: added one step to add some dependencies to the psteclipse plugin after installing it in the repository.

These boys don't place nice. Both strong, both handsome and both sturdy as it gets when trying to make them work together. Getting Maven to compile Eclipse RCP plugins while retaining the ability to develop and test within the IDE has been a tough week's job.

Three different approaches I tried were, in order of appearance:

  1. maven-psteclipse-plugin, developed as a custom solution by PrincetonSoftech and released for public use,
  2. maven-pde-plugin, using Eclipse's PDE Ant scripts to build the plugins,
  3. maven-bundle-plugin, my final sign of desperation, resorting to default OSGi tools and methods.
All of them were fine to generate or manage Eclipse-specific artifacts, each of them I made eventually to build single plugins, but none managed to work properly with dependencies between plugins under development.

Eventually I contacted Peter Hagelund (aka Petersen), co-author of the first solution. We exchanged a couple of e-mails, sorted out matters missing in the original article and finally found a bug in the psteclipse plugin. Here's how the whole procedure gets done.

Preliminary steps

You will need Eclipse obviously. Assuming you have already one installed for day-to-day development, you'll need another dummy one to do the automatic testing of plugins. It's a recommendation of the original article, crucial to ensure your workspace will not sustain any damage from the automatic installing and cleaning.

Download the psteclipse mojos from the link at the bottom of the article. Unpacking the zip will show a folder with the sources and the pom.xml file, trying to build it though will likely fail. The POM requires a parent artifact which is missing from the download. If you're interested, you can checkout the whole structure from Codehaus's SVN. Luckily for us there is a target folder within the download containing an already built .jar with the plugin. That need only be installed, which is done with the following command (the parts in bold need substituting for according values):
mvn install:install-file -Dfile=/[path to folder]/target/maven-psteclipse-plugin-[version].jar -DgroupId=org.apache.maven.plugins -DartifactId=maven-psteclipse-plugin -Dversion=[version] -Dpackaging=jar -DgeneratePom=true
Check your Maven repository whether it contains the file at the specified location, which is:
org/apache/maven/plugins/maven-psteclipse-plugin/[version]
You'll also need to add two dependencies to the file there with the .pom extension. Open it and add:
<dependencies>
<dependency>
<groupid>org.apache.maven</groupid>
<artifactid>maven-project</artifactid>
<version>2.0</version>
</dependency>
<dependency>
<groupid>org.apache.maven</groupid>
<artifactid>maven-archiver</artifactid>
<version>2.2</version>
</dependency>
</dependencies>
You can't really call the psteclipse plugin until after setting up a POM for your project, which first requires deciding on the classpath for your plugins. Eclipse requires plugin names to be the same as their classpaths, in which case if I were to develop plugins foo and bar, I'd call them:
com.buggybrain.foo
com.buggybrain.bar
These will also be the artifactId's Maven uses and in turn the folder names for Maven modules under the super POM. My common classpath for all plugins would in this case be:
com.buggybrain
and that's the groupId for all my plugins as well as for Eclipse plugins required for building the whole project. The latter one is a decision made by the psteclipse team, so unless you feel like messing with their mojo code, you'll have to follow it.

Once the decision is made, you can set up the parent POM (aka the super POM). For this you can easily take the template provided in the article. Just make sure to exchange com.princetonsoftech wherever you can find it to the classpath you just decided to use (eg. com.buggybrain).

A note about versions here - it's easiet to keep the version stated only in the super POM and remove it from separate plugin poms - this way it gets inherited down the hierarchy and updating it requires changing only one value. Make sure though your version name includes the -SNAPSHOT suffix. Psteclipse expects that and requires whenever it looks for dependencies between plugins.

With the super POM in place, you should be able to scrape the Eclipse directory for artifacts needed to build your plugins. This is done with the mvn psteclipse:deploy command, executed in the location of the super POM. You'll need to provide two parameters:
  • eclipseHome - the directory of the Eclipse installation to scrape
  • groupId - the classpath (Maven's group) the plugins will be put in
Psteclipse will also ask you to provide to other parameters - repositoryId and url, but unless you'll be deploying into a remote repository, you need not care about those and provide just any values. The whole command can look like this:
mvn psteclipse:deploy -DeclipseHome=/home/sonic/tmp/eclipse -DgroupId=com.buggybrain -DrepositoryId=a -Durl=a
It will take a moment to fetch all the plugins, copy the jars to the current directory and create two files - install.txt and deploy.txt containing a list of Maven commands to install all the artifacts into a local repository or deploy them to a remote one. Now all you have to do is run commands in whichever file suits you, ie.
bash < install.txt
You'll have to clean up after the deployment and delete all the Eclipse artifacts from the parent POM's directory.

Preparing projects

Decide on which plugins will be binary (no source code, only jars available to other plugins) and which will be source (no jars, only source code). In practice it is possible to have a source plugin containing jars, but psteclipse will make your life hard managing such a combination later, so I recommend you do stick to the convention.

Create folders for some of your plugins, the less for a start the better - you'll have to make sure it all works before adding more stuff later. You can easily use Maven's mvn archetype:create command here. Make sure to change the packaging types to binary-plugin and source-plugin accordingly, as stated in the original article.

Source plugins will require the MANIFEST.MF file in the META-INF directory, which you can easily create empty by hand right now and edit in Eclipse later.

Binary plugins need their pom.xml files edited to include all the dependencies they're suppose to make available to other plugins.

The stuff to commit to your code repository for binary plugins is:
  • pom.xml
while your source plugins will require these elements commited:
  • pom.xml
  • src/ folder
  • META-INF/ folder with the MANIFEST.MF inside
Now you may execute mvn eclipse:eclipse in the parent folder, then mvn psteclipse:eclipse-plugin for binary plugins separately and import all projects into Eclipse according to the procedures described in the original article. Edit the MANIFEST.MF files for all source plugins, make sure to put names, versions, depencencies with versions (those need to be checked with actual values from Eclipse) and exported packages for dependencies between plugins.

At the end of this process Eclipse should report no build errors.

Compiling with Maven

Back in the Maven world the usual thing you'd do now is go to the parent folder and execute mvn compile to make sure everything is OK. You'll fail. The psteclipse plugin contains a bug here (acknowledged by Peter and to be corrected), which prevents it from seeing dependencies on plugins under development, only looking at the repository.

To make it work you'll have to call mvn install. This will compile each plugin and install it into the local repository, then move to the next one. Whenever one plugin depends on another, the previous one should have its jar installed in Maven's repository and the procedure should go smoothly.

If at this point Maven still reports any missing dependencies between plugins you're working on, check the order of module declarations in the super POM and make sure all plugins that are depended on are placed before those that depend on them.


The above should have covered the whole process. I might have missed something on the way, so I'll be more than happy to receive comments with success as well as failure stories.