views:

74

answers:

1

I have an Eclipse feature which includes several bundles. I want to tell p2 to mark one of those bundles as started when the feature is installed. This is possible using the bundles own META-INF/p2.inf like so,

instructions.configure = markStarted(started: true)

but I want to do this at the feature-level rather than the bundle-level (the bundle in question is third-party, and I'd prefer not to modify it in any way, if possible).

Some research has led me to this document which suggests that it should be possible to move the configure instructions to the containing feature's p2.inf. I've tried all the obvious things like,

units.0.id = <bundle symbolic name>
units.0.instructions.configure = \
  org.eclipse.equinox.p2.touchpoint.eclipse.markStarted(started: true)

but so far none of the permutations I've tried have any effect: as in nothing happens, the bundle isn't marked as started and no errors are reported).

Any pointers would be very welcome. The is with Eclipse Equinox Galileo (3.5.2) ... answers relating to Helios would also be very useful.

+3  A: 

The "units.#." p2.inf entries create a new Installable Unit, they don't modify other existing IUs.

You basically have to create an entire Installable Unit fragment. The fragment has the relevant instructions and attaches to your bundle's IU. Then you need to add a requirement from your feature to this new IU.

PDE/Build does this automatically when building products. You could see the generated p2.inf by creating a little rcp product build which has a start level for your bundle.
The generated p2.inf in a product build will be buildDirectory/features/org.eclipse.pde.build.container.feature/product/p2.inf

Here is an example I modified from a build which sets the start level for org.eclipse.equinox.common. The $version$ will get replaced by the version from the feature that the p2.inf belongs to. Notice the "hostRequirements", which is specifying the bundle we are a fragment of.

#create a requirement on the IU fragment we are creating
requires.2.namespace=org.eclipse.equinox.p2.iu
requires.2.name=configure.org.eclipse.equinox.common
requires.2.range=[$version$,$version$]
requires.2.greedy=true

#create a IU frament named configure.org.eclipse.equinox.common
units.0.id=configure.org.eclipse.equinox.common
units.0.version=$version$
units.0.provides.1.namespace=org.eclipse.equinox.p2.iu
units.0.provides.1.name=configure.org.eclipse.equinox.common
units.0.provides.1.version=$version$
units.0.instructions.install=installBundle(bundle:${artifact});
units.0.instructions.uninstall=uninstallBundle(bundle:${artifact});
units.0.instructions.unconfigure=setStartLevel(startLevel:-1);markStarted(started:false);
units.0.instructions.configure=setStartLevel(startLevel:2);markStarted(started:true);
units.0.hostRequirements.1.namespace=osgi.bundle
units.0.hostRequirements.1.name=org.eclipse.equinox.common
units.0.hostRequirements.1.range=[3.6.0.v20100503,3.6.0.v20100503]
units.0.hostRequirements.1.greedy=false
units.0.hostRequirements.2.namespace=org.eclipse.equinox.p2.eclipse.type
units.0.hostRequirements.2.name=bundle
units.0.hostRequirements.2.range=[1.0.0,2.0.0)
units.0.hostRequirements.2.greedy=false
units.0.requires.1.namespace=osgi.bundle
units.0.requires.1.name=org.eclipse.equinox.common
units.0.requires.1.range=[3.6.0.v20100503,3.6.0.v20100503]
units.0.requires.1.greedy=false

Answers to questions:

  1. 0's, 1's, 2's

    These numbers are somewhat arbitrary, they serve only to separate one set of properties (requires or units or whatever) from another. The requires here used a '2' simply because I copied it from a large p2.inf that was generated by pde.build and forgot to change it like I did the units.0.

  2. Is all this necessary?

    Yes. The second hostRequirements on the type=bundle is needed. In Helios, with the exception of translation fragments, only one fragment can be attached to an IU. Generally a default IU is available that sets the default start level for all osgi bundles. In order for the our custom fragment to be chosen over the default one, it must have a higher "specificity" which is the number of satisfied host requirements.

    For "install"

    units.0.instructions.install=installBundle(bundle:${artifact}); units.0.instructions.uninstall=uninstallBundle(bundle:${artifact});

    The instructions.install and instructions.uninstall refer to phases of the p2 process. The installBundle and uninstallBundle refer to install/uninstall in the OSGi sense. Your bundle must be installed into the OSGi system before you can do anything else. This basically invovles adding it to the config.ini or org.eclipse.equinox.simpleconfigurator/bundles.info files.

    Most p2 installs will already contain a default configuration IU that will install and set the default start level (4) for bundles. However, currently only one configuration fragment can be applied to each bundle, so when you add your own like this the default no longer applied to your bundle.

  3. hostRequirements. The installable Unit fragments page just describes what a fragment is with no reference on how to create one. It is biefly mentioned on the Customizing Metadata page, but not explained.

    Documentation, there is a bunch of stuff on the wiki under the p2 category. the page on the touchpoint instructions might be interesting. There is some help on help.eclipse.org, but in general, I think this is a bit more advanced that what there is documentation for.

Andrew Niefer
It looks like there's quite a bit of magic here. Can you explain the significance of 0's, 1's and 2's ... are they arbitrary (in which case, why start with requires.2 rather than requires.0?) or determined by the context?Also, are all of these necessary? For instance units.0.instructions.install looks redundant to me.More generally, where is this stuff documented? For example, you say that it's the hostRequirements entry which specifies which bundle this is a fragment of, but nowhere on the page you link to describing Installable Unit fragments is this mentioned.
Miles Sabin
Just to be sure I've understood the arbitrariness of the numbering correctly, would the meaning remain the same if "requires.2" were replaced with "requires.0" throughout; "units.0.provides.1" replaced by "units.0.provides.0"; "units.0.hostRequirements.1" replaced by "units.0.hostRequirements.0"; "units.0.hostRequirements.2" replaced by "units.0.hostRequirements.1"; "units.0.requires.1" by "units.0.requires.0"
Miles Sabin
Yes it should be equivalent.
Andrew Niefer
I can confirm that this mechanism works perfectly.
Miles Sabin