I've recently seen a
couple of
different posts to the newsgroups dealing with problems updating RCP applications using p2.
[edit 2009/10/21, update links to forums]
As an example, I've created my own Eclipse product. It is composed of the
Eclipse Platform,
CVS support, the
CDT and
Mylyn. I'm calling it the ADT (Andrew's Development Tools).
It's not hard to create a feature based product that includes these things, and do a
product build to end up with something like this:
As explained in
this newsgroup post, there are two kinds of things that are included in an Eclipse install:
- Things that are explicitly installed
- Things that are required by the things that are installed.
Here in my example, only my development tools "org.example.adt" is installed, the rest (CDT, CVS, Mylyn) are required by my product.
Only things that are explicitly installed will be searched for when you look for updates. Also, the installed things generally specify the versions of things they require, which makes it hard to install/update those required items independently of the root product. In both the newsgroup postings I referred to above, the problem was trying to install/update one of the required items without updating the root product.
So the question becomes how to allow updating sub-components of the product without updating the product itself.
Composing for Updatability
What we want to do is to update sub-components of the product without updating the root product itself. In this example we do not to allow updating the Eclipse Platform independently, to do that, the user will need to update the product itself.
I have created a example builder to do this. Get it from
cvs (dev.eclipse.org:/cvsroot/eclipse/pde-build-home/examples/adt.builder).
[Edit 2013/07/03: Eclipse CVS has migrated to git starting in 2010. The
examples are now available under the examples folder in
http://git.eclipse.org/gitroot/pde/eclipse.pde.build.git. The example has not been updated to work with git and may require modifications to run properly.]
We need to do two things:
- Use version ranges to include sub-components in our product so that we allow upgrading those components.
- Explicitly install those sub-components so they will be found when checking for updates. This is essentially a book-keeping step.
The ADT .product File
There is a
adt.builder/product/adt.product file which we will use to run a product build. If we were to include the features for our sub-components in the .product file, then we would end up with requirements on specific versions of those components. Instead we only include the platform feature
[1].
To get requirements to our sub-components, we use a
p2.inf file to
customize the metadata. We add requirements with entries that look like this:
requires.1.namespace = org.eclipse.equinox.p2.iu
requires.1.name = org.eclipse.cvs.feature.group
requires.1.range = [1.1.100, 1.2.0)
requires.2.namespace = org.eclipse.equinox.p2.iu
requires.2.name = org.eclipse.mylyn_feature.feature.group
requires.2.range = [3.2.0, 3.3.0)
...
The
.feature.group suffix is the name of the p2
Installable Unit corresponding to the features we are interested in. We specify the version ranges in which we will allow those components to be updated.
The ADT Builder
The adt.builder project includes a
buildADT.xml ant script which will run a headless product build for us. The first thing it does is download zips containing the things we need. This example illustrates three different ways of
reconsuming metadata.
- The CDT and CVS both come as zipped p2 repositories. Things that are not referenced directly by the .product file only need to be available as repositories. We can reuse these zips directly by specifying them as context repositories using jar: urls. See the p2.context.repos property in the adt.builder/build.properties file.
- Mylyn is not a p2 repository, it is a zipped old style update site. For this, we use a publisher task to generate p2 metadata for it. [2]
- The Eclipse Platform is a p2 repository just like the CDT and CVS. It is similar to the delta pack in that it contains the org.eclipse.equinox.executable feature that is need to get launchers in product builds. Because the platform feature is included directly in the product, we can't just specify the platform as a context repository, we need the bundles available to pde.build like in a normal headless build. To do this we transform the repository using the p2.repo2runnable task. See the transformedRepoLocation and repoBaseLocation properties in the build.properties file. The transformed repository automatically gets included along with the pluginPath property used by pde.build.
Adding additional director calls
In order for our sub-components to be independently updatable, they need to be explicitly installed in our resulting product. By default PDE/Build performs a
director install for just the product being built. We can use a
customAssembly.xml script to perform additional director
[3] calls before the final archive is created.
It looks like this:
<target name="pre.archive">
<ant antfile="${genericTargets}" target="runDirector" inheritAll="true">
<property name="p2.repo" value="${p2.build.repo}"/>
<property name="p2.director.iu" value="org.eclipse.cvs.feature.group"/>
<property name="p2.director.installPath" value="${eclipse.base}"/>
</ant>
...
</target>
We make director calls for each of the sub components we allow to be updated. In the example we do CVS, Mylyn, CDT, and the CDT-Mylyn bridge.
The final result
Run the adt.builder by right-clicking on buildADT.xml and choosing Run As -> Ant Build... Be sure to run in the
same JRE as the workspace. After running the build, the results are available under
adt.builder/buildDirectory/I.<timstamp>.
Running the resulting product, we see that the CDT, Mylyn and CVS are all showing up as installed roots, and are therefore independently updatable.
Notes
- PDE/Build will automatically generate start level configuration information, but only for things that are included in the .product file. If we didn't include the platform feature, or at least the bundles that need start level information, then this would not happen automatically and we would need to handle start levels ourselves. See the help page here for more information of configuring start levels.
- We publish the p2 metadata for mylyn into ${p2.build.repo}. This property specifies the location of the p2 repository that will be used internally by the build. Publishing the mylyn metadata here instead of some location specified as a context repository saves the build from mirroring the required IUs into the build repository.
- PDE/Build provides a "runDirector" target that can be used to invoke the director. This works by executing the director application in a new process. Normally, this requires setting the "equinoxLauncherJar" property specifying the location of the equinox launcher to use, but because we are calling the director from customAssembly.xml, we inherit this property from the generated assembly scripts.
- Running this build produces a properly p2 enabled product. It does not produce a corresponding repository for that product other than the build time repository ${p2.build.repo}. To produce a final repository containing the final product, define the properties p2.metadata.repo and p2.artifact.repo in the build.properties. The product and its requirements will then be automatically mirrored into that repo.