Friday, June 12, 2009

Patching features with p2

The Galileo release of Eclipse is in its final days. The eclipse SDK itself is effectively done and the current build is under consideration to be the final release.

Imagine This...

Say I have a feature that I build, it runs on top of the Eclipse Platform. I know Eclipse Galileo is coming out soon, so I download it and try it out with my feature.

Oh No! It doesn't work! I've found a bug in the platform, and its a major blocker for me. (Oops, maybe I should have tried this a couple of months ago when there still would have been time to fix the bug.)

Meta-Comment: The Eclipse Platform Project has a reputation for shipping on time (even if that means there are unresolved bugs). There is a strict end game plan that is followed for the release, lock down started back at the beginning of May. The further we are along in the plan, the harder it is to get a fix approved for release. A lot of people don't seem to relealize this happens, and perhaps wonder why their important bugs are defered with the comment "Its too late".

Ok, I need to patch the platform. How do I do this?

The Example Feature

To work through the steps of patching the platform, I created my own example feature:

  1. Create a New Plug-in Project "org.example.plugin". The plug-in is not a "Rich client Application". On the templates page of the wizard I chose "Plug-in with a view".
  2. Create a New Feature "org.example.feature". Add org.example.plugin to the feature.
  3. Export the feature, and on the Options tab in the export wizard check "Generate metadata repository".
For the purposes of the example, I'm starting from the Eclipse Platform Runtime 3.5RC4. Because I want to strictly control the upgrade path in the example, I removed the Galileo and Eclipse Project repositories from the available sites (Window -> Preferences -> Install/Update->Available Software Sites).

Unzip the platform, and installed the feature from the exported repository. I didn't create any categories for the feature, so "Group items by category" must be unchecked.


The Patch

For the example, I am inspired by bug 279542 which came in very late and almost was not fixed in 3.5. The bundle org.eclipse.equinox.p2.touchpoint.eclips has the bug and this plugin is included by the feature org.eclipse.equinox.p2.user.ui.

Say we have a fix with touchpoint.eclipse version 1.0.101.v20090611. (When following the eclipse versioning guidelines, the maintenance version of this bundle should be 1.0.101 and the version for the next year's release will probably be 1.0.200).

We can easily create a new Feature Patch with the wizard:
We specify the version of p2.user.ui that we are patching (here the one shipped in 3.5RC4). In the feature patch, include org.eclipse.equinox.p2.touchpoint.eclipse with the specific version containing the fix. Then, add the feature patch as an inclusion in our org.example.feature:

<feature id="org.example.feature" label="Feature" version="1.0.0.qualifier">
<includes id="org.example.patch" version="0.0.0" />
<plugin id="org.example.plugin" version="0.0.0" unpack="false"/>
</feature>

<feature id="org.example.patch" label="Patch" version="1.0.0">
<requires>
<import feature="org.eclipse.equinox.p2.user.ui" version="1.1.0.v20090605-1440-7u6Fb3FbPbJP5MiKiZgpdl" patch="true"/>
</requires>
<plugin id="org.eclipse.equinox.p2.touchpoint.eclipse" version="1.0.101.v20090611" unpack="false"/>
</feature>


If we have the bundle containing the fix in our target platform, we can now export a new version of our example feature that includes it. And we can update the platform where our feature is installed to get the new version that brings the patch with it.

The metadata for the Patch installable unit looks like this:

<unit id='org.example.patch.feature.group' version='1.0.0' singleton='false'>
<patchScope>
<scope>
<requires size='1'>
<required namespace='org.eclipse.equinox.p2.iu' name='org.eclipse.equinox.p2.user.ui.feature.group' range='[1.1.0.v20090605-1440-7u6Fb3FbPbJP5MiKiZgpdl,1.1.0.v20090605-1440-7u6Fb3FbPbJP5MiKiZgpdl]'/>
</requires>
</scope>
</patchScope>
<changes>
<change>
<from>
<required namespace='org.eclipse.equinox.p2.iu' name='org.eclipse.equinox.p2.touchpoint.eclipse' range='0.0.0'/>
</from>
<to>
<required namespace='org.eclipse.equinox.p2.iu' name='org.eclipse.equinox.p2.touchpoint.eclipse' range='[1.0.101.v20090611,1.0.101.v20090611]'/>
</to>
</change>
</changes>
...
<requires size='2'>
<required namespace='org.eclipse.equinox.p2.iu' name='org.eclipse.equinox.p2.user.ui.feature.group' range='[1.1.0.v20090605-1440-7u6Fb3FbPbJP5MiKiZgpdl,1.1.0.v20090605-1440-7u6Fb3FbPbJP5MiKiZgpdl]' greedy='false'/>
...


This says, in org.eclipse.equinox.p2.user.ui.feature.group version 1.1.0.v20090605-1440-7u6Fb3FbPbJP5MiKiZgpdl, change whatever version of org.eclipse.equinox.p2.touchpoint.eclipse is there to version 1.0.101.v20090611.

It works! Except...

It works, except that we notice that the patch IU has hard requirements on the version of the p2.user.ui feature. This would prevent upgrading the underlying platform because the feature patch has locked down the version of the p2.user.ui feature.

p2 is much more flexible about patches than the old Update manager was, so there are a few different ways to address this, and I will write another post covering this soon.

(Right now its Friday after 5pm, and time to go home for the weekend :) )

No comments: