Customizing p2 metadata
Disclaimer: Authoring p2 metadata is new in 3.5 and 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 in the 3.5 release 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:
- In bundles (META-INF/p2.inf): The instructions are added to the installable unit for the bundle.
- In features (a p2.inf file co-located with the feature.xml): The instructions are added to the installable unit for the feature group.
- In products (a p2.inf file co-located with the .product file): The instructions are added to the root installable unit for that product.
Version substitution is a common practice and two special version parameters are supported:
-
$version$ - returns the string form of the containing IU's version
-
$qualifier$ - returns just the string form of the qualifier of the containing IU's version
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:
-
provides - these are capabilities that an IU will offer to satisfy the needs of other IUs.
-
requires - these are the capabilities that an IU requires from other IUs in order to resolve correctly.
-
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:
- The {raw actions} will be "appended" to the end of any instructions already being generated.
- The qualified action names for the IU's touchpoint type are implicitly imported. All other actions need to be imported.
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 = https://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 = https://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