Friday, February 24, 2012

RPM + OSGi automation: Step 1 completed

Recent RPM versions include the concept of dependency generators. This opens the door for a number of automations and simplifications for people using RPM as their distribution format. 

In Fedora we stepped in and worked on making Java land fell less of an alien in Linux distributions. 

Not every OSGi feature is considered because some of them don't match with the goals of distributing a single project. Everything is based on the Bundle-SymbolicName and Require-Bundle headers (for now). 

  • Bundle-SymbolicName header is used for generating a virtual provide for the rpm the bundle is part of in the format Provides: osgi(bundle-symbolicName) = bundle-version . This is done for every OSGi bundle in the RPM so the number of these provides will be the same as the number of bundles in it. This provides generation was enabled early in the Fedora 17 development phase and will be available for use in the soon to be released Fedora 17. How will this improve the packager's life one may ask?  - Do you know which package e.g. javax.servlet bundle is in? You don't have to anymore. Put Requires: osgi(javax.servlet) in your spec file is all you need. Or you can use yum to query for it `repoquery --whatprovides "osgi(javax.servlet)"`
  • Require-Bundle headers are used for auto generating requires so people don't end up with dependencies not being installed. The format used is pretty much the same Requires: osgi(bundle-symbolicName). Few things needs mentioning here - optional requires are discarded because RPM(in Fedora) doesn't have the concept of soft-requires and versions are not added to the requires for a reason that will be explained later. The requires generator have just been enabled in Rawhide(future Fedora 18) and up to now it's showing no major problems with a pretty huge test case - the Eclipse SDK.
 Import/Export-Package is a huge part of the OSGi specification and even the recommended way for specifying dependencies. Here I'll explain why it doesn't make sense for RPM packages without questioning it's general usability, it just doesn't fit our workflow.
  • having provides/requires for every package import/export is way too verbose and will polute the rpm metadata that much to make it hurt every user with unneeded time to download metadata
  • we don't want multiple providers for the same package - we want  a single, stable and well tested provider. 
This is big enough difference to even make me think of Step 2 where Import-Package headers are used at build time to map them to Require-Bundle. This will not be an easy task but it is possible because at build time we know which bundle exports the needed package. 
Now to not having versions in requires. First of all there is no easy mapping between OSGi version ranges and RPM. OSGi recommends using version ranges while in RPM it's considered a really bad practice to use anything else but setting the lowest version supported. Second, we usually have only one package that provides given osgi bundle. Third , more than one OSGi bundles are usually grouped in a single RPM. All of the above combined makes the requires generated satisfying 90 % or even more of the cases and for the rest one can still add the requires manually (like we do now).
This isn't by any mean a complete solution it covers only the most common case but still it will prevent a number of problems like Eclipse failing to provision because of missing requires for some plugin and etc. Once the current automation makes its way through the whole distribution work on the next integration step can continue because there would be less time spend on simple but timeconsuming things.