A few days ago I finished my bachelor thesis with the title Integrating Xtext in an existing Software development process. I developed a domain specific language with Xtext and some extensions for easily adding new generators as new Eclipse plug-ins.
After finishing the thesis I added a Maven Tycho based build configuration. The build configuration can be easily deployed to TeamCity, Hudson or any other build server of your choice. I assume that you have already developed an Xtext based DSL and you know a little bit about OSGi and Maven.
The complete project source code can be found at https://github.com/schakko/xtext-plugin-with-maven-tycho
First of all you should think about a sensible directory structure. I use the following organization
- /plugins contains your Eclipse based plug-ins
- /features contains the Eclipse features for bundling your plug-ins
- /releng is used for the release engineering process and holds the project for the p2 update site
- /pom.xml is the master POM for your complete project.
Set up the master pom.xml
Every pom.xml inside the subdirectories inherits from the master pom.xml. The configuration defines all modules of your project, sets the needed plug-in repositories and plug-ins. The most interesting part of the lifecycle configuration is, that the xtend-maven-plugin is not executed in generate-sources but generate-resources. This is needed as the MWE2 workflow of your DSL project has to be executed first. If you have both plug-ins inside the generate-sources phase the xtend-maven-plugin will be called first, resulting in a ClassNotFoundException as the DSL infrastructure is not generated yet. So the compilation of Xtend is moved to generate-resources which is executed after generate-sources phase. Another solution would be moving the xtend-maven-plugin to every child pom but this means duplicate configuration code.
Set up your DSL project
The pom.xml contains the plug-in for executing the MWE2 workflow. Notice that your <workflowDescriptor> must begin with src/ or you will receive the message Cannot create a resource for…. All the other stuff is straight forward. The packaging type eclipse-plugin is introduced by the tycho-maven-plugin.
The file build.properties contains the source and binary folders. This is important, as tycho-maven-plugin uses this file as reference for compiling and packaging the sources. The xtend-gen directory must be added.
It is important, that your Bundle-Version must end with the suffix .qualifier, e.g. 1.0.0.qualifier. The string is automatically replaced with the build date.
Set up your test project
Copy generated files
At first the two automatic generated files from src-gen (*InjectorProvider.java and *UiInjectorProvider.java) must be copied to the src folder if you want use the xtend-maven-plugin. The Xtend Maven plug-in does not allow (at least in version 2.2.1) any additional source pathes so that none class in src-gen can be found by xtend-maven-plugin. Remove the src-gen directory from your Eclipse classpath too.
The pom.xml for the test project uses a different Xtend version because I ran into heavy problems with the xtend-maven-plugin using the ValidatorHelper. Referencing the ValidatorHelper class results in a GenericSignatureFormatError. Sven Efftinge mentioned yesterday that the bug should be fixed in the latest snapshot.
The packaging type must be eclipse-test-plugin.
Include the xtend-gen directory and make sure that the src-gen directory is not included because of the xtend-maven-plugin problem.
The MANIFEST.MF uses the Import-Package statement for importing Mockito. See the next section how to set up this dependency.
Creating a dependency project
I used Mockito as mocking framework inside my tests. Adding this dependency is a little bit tricky:
- Adding the mockito-all-1.9.5.jar to your Eclipse build path does not work. Maven does not know anything about your .classpath settings.
- Adding a dependency to the pom.xml means that the compilation with Maven would work but not the installation on the client because there is no OSGi package for Mockito available.
- Converting the mockito package to an OSGi package is not ideal. Every dependeny must be repackaged.
A much better solution is including the required JAR files inside an own OSGi package. I took the idea from the atlassian-connector project.
New Plug-in project
Create a new Eclipse plug-in project, create a folder lib and copy the mockito-all-1.9.5.jar inside.
Nothing new, just use eclipse-plugin as packaging type.
Your build.properties must include the lib directory.
Here comes the interesting part. We use Bundle-ClassPath to define the additional path to the mockito JAR file. Every package inside this JAR file is re-exported via Export-Package.
Set up your UI project
The pom.xml must use the packaging type eclipse-plugin.
I added the schema and icons directory and plugin.xml. This depends on your needs.
Set up your feature projects
Features are bundles which consist of different plug-ins. Lars Vogel made a good tutorial which you can use for more information
We need to create two features:
- A runtime/core feature with your DSL and UI plug-in
- A test feature with the test and dependencies plug-in
Create a pom.xml and use the packaging type eclipse-feature.
Set up your update site
The update site contains every feature the user can install. Lars wrote a tutorial about this but my needs were different. I wanted to deploy the content on a local webserver with a simple copy command.
To do so, generate a new update site project inside your releng directory and add a category definition (in Eclipse: Plug-in Development > Category Definition).
The category.xml contains the features which are available through he update site. First of all, add a new category named “Xtext” and assign both of your previously created features to this category.
The packaging must be eclipse-repository. I use the copy-maven-plugin for copying the update site to the local webserver.
Run it local
With all these settings the project can be build inside Eclipse without m2e plug-in and on the command line. Go to the command line and execute mvn install:
Move it to your build server
Create a new configuration in your TeamCity instance and add a Maven buildstep. I pass the -DupdateSite.target parameter for specifying the destination directory of the update site.
Install your plug-ins
Enter the path to your update site and you will see your installable Xtext DSL