Customizing p2 metadata

Disclaimer: Authoring p2 metadata is something we expect to support with better tooling in a future release. The support for customizing metadata with a p2.inf file is provisional although we expect to maintain a basic level of compatibility for common tasks.

On occasion the metadata that is automatically generated by p2 for bundles, features and products does not provide everything required to successfully provision an installable unit. For those cases p2 supports the use of an advice file (a p2.inf file) that can be used to augment the metadata for an installable unit. In this release the p2.inf file will allow an author to customize capabilities, properties, and instructions. In addition support is provided for defining additional installable units that are related to the container IU.

The touchpoint advice file is a java properties file and can be placed:

Version substitution is a common practice and two special version parameters are supported:

One common use for advice files is to allow more fine grained control of the generation of categories used by the UI to group installable features


Capability Advice

Note: Capability advice will "replace" an existing capability of the same type on the IU if the name and namespace match.

There are three different type of capability advice:

  1. provides - these are capabilities that an IU will offer to satisfy the needs of other IUs.
  2. requires - these are the capabilities that an IU requires from other IUs in order to resolve correctly.
  3. metaRequirements - these are capabilities that the IU puts on the profile that must already be installed before this IU can be installed.
 provides.{#}.namespace = {namespace}
 provides.{#}.name = {name}
 provides.{#}.version = {version} (optional / default: 1.0.0)
 
 requires.{#}.namespace = {namespace}
 requires.{#}.name = {name}
 requires.{#}.range = {range} (optional / default: 0.0.0)]
 requires.{#}.greedy = {true|false} (optional / default: true)
 requires.{#}.optional = {true|false} (optional / default: false)
 requires.{#}.multiple = {true|false}  (optional / default: false)
 
 metaRequirements.{#}.namespace = {namespace}
 metaRequirements.{#}.name = {name}
 metaRequirements.{#}.range = {range} (optional / default: 0.0.0)
 metaRequirements.{#}.greedy = {true|false} (optional / default: true)
 metaRequirements.{#}.optional = {true|false} (optional / default: false)
 metaRequirements.{#}.multiple = {true|false}  (optional / default: false)
 
Where {#} is an index for the property, {namespace}, and {name} are the associated named strings, {version} and {range} are version and version range strings respectively.
For example:
 provides.0.namespace = testNamespace1
 provides.0.name = testName1
 provides.0.version = 1.2.3.$qualifier$
 provides.1.namespace = testNamespace2
 provides.1.name = testName2
 provides.1.version = $version$
 
 requires.0.namespace = testNamespace1
 requires.0.name = testName1
 requires.0.range = [1.2.3.$qualifier$, 2)
 requires.0.greedy = true
 requires.0.optional = true
 requires.0.multiple = true
 requires.1.namespace = testNamespace2
 requires.1.name = testName2
 requires.1.range = [$version$, $version$]
 requires.1.greedy = false
 
 metaRequirements.0.namespace = testNamespace1
 metaRequirements.0.name = testName1
 metaRequirements.0.range = [1.2.3, 2)
 metaRequirements.0.greedy = true
 metaRequirements.0.optional = true
 metaRequirements.0.multiple = true
 metaRequirements.1.namespace = testNamespace2
 metaRequirements.1.name = testName2
 metaRequirements.1.range = $version$
 metaRequirements.1.greedy = false

Property Advice

 
 properties.{#}.name = {propertyName}
 properties.{#}.value = {propertyValue}
 

Where {#} is an index for the property, {propertyName}, and {propertyValue} hold the name and value strings for the property.
For example:

 properties.0.name = testName1
 properties.0.value = testValue1
 properties.1.name = testName2
 properties.1.value = testValue2

Touchpoint Instruction Advice

 
 instructions.{phase} = {raw actions}
 instructions.{phase}.import = {qualified action name} [,{qualified action name}]* (optional)
Where {phase} is a p2 installation phase (collect, configure, install, uninstall, unconfigure, etc). Note: For example:
 instructions.install = \
    ln(targetDir:@artifact,linkTarget:foo/lib.1.so,linkName:lib.so);\
    chmod(targetDir:@artifact,targetFile:lib/lib.so,permissions:755);
 instructions.install.import= \
    org.eclipse.equinox.p2.touchpoint.natives.ln,\
    org.eclipse.equinox.p2.touchpoint.natives.chmod
Additional information on touchpoint instructions and action syntax can be found here.

Additional Installable Unit Advice

In addition to customizing attributes of the containing IU one can also author additional installable units that work with the container IU. Typically this mechanism is used to author an IU fragment that customizes the containing IU or one of its dependencies.

 iu.{#}.id = {identifier} 
 iu.{#}.version = {version} (optional)
 

Where {#} is an index for the installable unit, so multiple installable units can be declared. A full range of IU customizations are supported including:

 id
 version
 singleton
 copyright
 licenses
 filter
 touchpoint
 update
 artifacts
 properties
 provides
 requires
 metaRequirements
 hostRequirements
 instructions
 

To illustrate all the various settings for these customizations here's a more complete example of: (unit.0) a minimal IU and (unit.1) a full featured IU:

 units.0.id = testid0
 units.0.version = 1.2.3
 units.1.id = testid1
 units.1.version = 1.2.4
 units.1.singleton = true
 units.1.copyright = testCopyright
 units.1.copyright.location = http://localhost/test
 units.1.filter = test=testFilter
 units.1.touchpoint.id = testTouchpointId
 units.1.touchpoint.version = 1.2.5
 units.1.update.id = testid1
 units.1.update.range = (1,2)
 units.1.update.severity = 2
 units.1.update.description = some description
 units.1.artifacts.0.id = testArtifact1
 units.1.artifacts.0.version = 1.2.6
 units.1.artifacts.0.classifier = testClassifier1
 units.1.artifacts.1.id = testArtifact2
 units.1.artifacts.1.version = 1.2.7
 units.1.artifacts.1.classifier = testClassifier2
 units.1.licenses.0 = testLicense
 units.1.licenses.0.location = http://localhost/license
 units.1.properties.0.name = testName1
 units.1.properties.0.value = testValue1
 units.1.properties.1.name = testName2
 units.1.properties.1.value = testValue2
 units.1.requires.0.namespace = testNamespace1
 units.1.requires.0.name = testName1
 units.1.requires.0.range = [1.2.3.$qualifier$, 2)
 units.1.requires.0.greedy = true
 units.1.requires.0.optional = true
 units.1.requires.0.multiple = true
 units.1.requires.1.namespace = testNamespace2
 units.1.requires.1.name = testName2
 units.1.requires.1.range = $version$
 units.1.requires.1.greedy = false
 units.1.requires.1.optional = false
 units.1.metaRequirements.0.namespace = testNamespace1
 units.1.metaRequirements.0.name = testName1
 units.1.metaRequirements.0.range = [1.2.3.$qualifier$, 2)
 units.1.metaRequirements.0.greedy = true
 units.1.metaRequirements.0.optional = true
 units.1.metaRequirements.0.multiple = true
 units.1.metaRequirements.1.namespace = testNamespace2
 units.1.metaRequirements.1.name = testName2
 units.1.metaRequirements.1.range = $version$
 units.1.metaRequirements.1.greedy = false
 units.1.metaRequirements.1.optional = false
 units.1.provides.0.namespace = testNamespace1
 units.1.provides.0.name = testName1
 units.1.provides.0.version = 1.2.3.$qualifier$
 units.1.provides.1.namespace = testNamespace2
 units.1.provides.1.name = testName2
 units.1.provides.1.version = $version$
 units.1.instructions.configure = addProgramArg(programArg:-startup); addProgramArg(programArg:@artifact);
 units.1.instructions.unconfigure = removeProgramArg(programArg:-startup); removeProgramArg(programArg:@artifact);)
 units.1.instructions.unconfigure.import = some.removeProgramArg
 units.1.hostRequirements.0.namespace = testNamespace1
 units.1.hostRequirements.0.name = testName1
 units.1.hostRequirements.0.range = [1.2.3.$qualifier$, 2)
 units.1.hostRequirements.0.greedy = true
 units.1.hostRequirements.0.optional = true
 units.1.hostRequirements.0.multiple = true

Category Generation Using p2.inf

The p2 UI allows for hierarchical organization of installable units based on the concept of "categories" where the children of categories are what's installable. On occasion we might want to take finer grained control of the contents of a category and what it contains. For example we might want to support further categorization of a feature's contents to allow individual plug-ins to be installed instead of the more typical features.

To support this we can tag a feature as a category as follows:

  properties.1.name=org.eclipse.equinox.p2.type.category
  properties.1.value=true

Another possibility is to use "additional IU advice" to create a specialized category IU like this:

  units.1.id=my.product.category
  units.1.version=1.0.0
  units.1.provides.1.namespace=org.eclipse.equinox.p2.iu
  units.1.provides.1.name=my.product.category
  units.1.provides.1.version=1.0.0
  units.1.properties.1.name=org.eclipse.equinox.p2.type.category
  units.1.properties.1.value=true
  units.1.properties.2.name=org.eclipse.equinox.p2.name
  units.1.properties.2.value=My Category Name
  requires.1.namespace=org.eclipse.equinox.p2.iu
  requires.1.name=my.product
  requires.1.range=[1.0.0,1.0.0]
  requires.1.greedy=true