Additions and changes in Eclipse Update release 2.0.2

Introduction

Although Eclipse release 2.0.2 was mostly a bug-fixing release and didn't include new features elsewhere, Update team used it to deliver significant changes. These changes are backward compatible and feature written against the 2.0.0 specification still work. The changes were added to provide for more robust, flexible and manageable installs and updates of large and complex Eclipse products. You can read the updated specifications for more details. 

Partial (branch) updates

In Eclipse 2.0.0, features were allowed to be organized in hierarchies using the inclusion capability (element includes in feature manifest). The inclusion was exact - included feature was specified using the exact identifier and version. The consequence of this limitation was that the only way to update a branch of a hierarchy was to update the root feature. 

In large, complex Eclipse products it is not always possible to provide update of the root feature every time there is a change somewhere in the hierarchy. For example, nodes in the tree may be Eclipse products themselves. It was needed to allow branches to be updated independent of the root.

However, teams that own feature roots may still want to control where features go for updates. A feature in the hierarchy may be on a different schedule and may have updates available that are not yet tested with the root feature. For this reason, in 2.0.2 branches can be updated but must go to the update site of the root feature to look for updates. This way, root feature can control what updates are found and can publish only tested and verified (supported) updated of the branches.

When a branch feature is updated, its version changes. This automatically breaks 'includes' specification unless it is somehow capable of handling this change. Additional attribute match was added to formally express this capability:

<includes id="com.example.acme" version ="4.0.0" match="equivalent"/>

In the example above, feature hierarchy will not be broken if com.example.acme is updated to 4.0.1, 4.0.2 and so on. However, the update potential is limited by the value of the match attribute. Value equivalent allows only service number increments. In contrast, compatible would allow both service and minor increments.

The suggested use of this attribute is to allow only service updates. Anything more would be a significant change and we suggest a full root update instead (a service pack). Branch updates should be used as a short-term measure (for patches and other minor updates).

By default, included feature will look for updates in the update site defined by the root. This can be changed by defining search_location attribute and setting it to self:

<includes id="com.example.acme" version="4.0.0" match="equivalent" search_location="self"/>

Default value of this attribute (when not specified) is root. When set to self, updates will be searched for in the update site defined by the feature itself, instead of that of a root feature.

NOTE: match attribute is only considered when feature is part of the local configuration. It is ignored when on the remote server. In the example above, feature "com.example.acme" version "4.0.0" must be present on the server. It is only when it is downloaded into the Eclipse product that match attribute takes effect in reference resolution.

Optional features

All of the features included by the root one must be present within the same site in order to be resolved. The exception are optional features. Optional features are included features that users can opt not to install. Optional features are declared using the attribute optional:

<includes id="com.example.acme" version="4.0.0" match="equivalent" optional="true"/>

Optional features have the following properties:

When not installed, optional features are hidden using the same filter as disabled features and can be seen by turning the filter off (the local tool bar button on the Configurations view in the Update Manager).

Feature requires

In 2.0.0, install/update prerequisites for features were plug-ins only:

<requires>
	<import plugin="org.eclipse.jdt" version="2.0.0" match="compatible"/>
</requires>

Since 2.0.2, feature may require other features as a precondition for installation:

<requires>
<import feature="org.eclipse.jdt" version="2.0.0" match="compatible"/>
</requires>

The rest of the semantics didn't change. Prior to the installation, Update will check all the constraints in 'requires' and block the operation if any of them is not satisfied.

Patches

Update version 2.0.2 introduces a notion of patches. Patches are regular features that are configured to bring partial updates to complex feature tree hierarchies. Prior to 2.0.2, the only way to update a branch of a feature tree was to update the entire hierarchy, including the root. Patches serve as carriers that bring in partial updates to other features without updating their roots.

Each patch consists of at least two features: the carrier (root) and the update (the actual feature that has been modified). The role of the carrier is to represent the patch entity in the configuration and to establish the relationship with the hierarchy that is being patched. A patch can me more complex and include several features, or entire branches.

Definition

For a regular feature to be a patch, two changes have to be made:

<feature 	id="org.eclipse.sdk.win32.e334" 
		version="2.0.2" 
		name="Patch e334" 
		colocation-affinity="org.eclipse.sdk.win32">
.....
     <requires>
        <import feature="org.eclipse.sdk.win32" version="2.0.2" patch="true"/>
     </requires>
     <includes id="org.eclipse.pde" version="2.0.2.e334" match="equivalent"/>
</feature>

The feature above will be a patch number e334. Its identifier is composed that way, although this is not a requirement. Similarly, patch version is not important but is convenient to use the same version as the feature that it should patch. The important part is colocation-affinity attribute. We used it to indicate that we want the patch installed in the same location as the feature it patches (note that colocation-affinity is not new - it is part of the 2.0.0 specification).

The second important change is the dependency on the patched feature. We used attribute 'patch=true' to indicate that this feature is a patch for the dependent feature. This will cause the following consequences:

A very important precondition for patches is that the feature hierarchy of a patched product is capable of accepting them. In other words, all child features in the product must be included using the 'match' attribute other than 'perfect'. Partial (branch) updates must be possible for patches to be used.

Grouping

Patches can include any number of features that patch any point of the patched feature's tree. In addition:

Patches can also be cumulative. In other words, a patch may bring an upgrade to a feature already patched by a previous patch. Since two patches include the same feature (just different versions), it is important that patches include their features with a match set to a value that is not perfect (typically equivalent). In the example above, patch e334 includes patched version of the PDE feature. If a newer patch (e.g. e444) also fixes PDE and includes version 2.0.2.e444 of it, the previously installed patch e334 will not be broken upon installation of e444. When expanded in the Configuration view, both patches will resolve to PDE version 2.0.2.e444. This is consistent because 2.0.2.e444 subsumes 2.0.2.e334. It is a good practice to document that fact in the description of the patch (something like 'this patch also includes a fix for problem fixed by e334').

Reverting a patch install

When a patch is installed, current configuration is saved as a backup and placed in the 'Saved Configurations'. This configuration has the following name convention:

@<id>_<version> backup

For example: 

@org.eclipse.sdk.win32.e334_2.0.2 backup

The naming convention is selected so that Update can programmatically locate this configuration for cleanup. If a patch installation didn't produce a desired result (the fix does not solve the problem or introduces side-effects), users can back out of the installation by restoring this configuration. Patch install is a complex operation and for that reason a revert must be used for this (simply disabling a patch would leave the configuration in a wrong state and is prevented for that reason).

Cleanup

Patches have limited life span. Since they are registered for a specific feature ID and version, they become obsolete the moment the referenced feature is upgraded to a new version. When a feature is disabled, all referencing patches are disabled with it. In addition, all backup configurations for these patches are removed.

It is important to understand the role patches are supposed to play in feature updates. Patches should be used for emergency fixes (e-fixes) between two official fix packs. Official fix pack is a full revision of a feature that starts from the root (e.g. 2.0.1, 2.0.2, 2.0.3 etc.). Between two fix packs, emergency fixes are used to provide a quick solution for a problem until the fix pack becomes available. The implicit contract for patches is that the next regular fix pack subsumes all the fixes provided between it and the previous fix pack.

Update activity log

Since 2.0.2, Update is now writing an ever-growing file called .install-log in the ./metadata/.config directory of the active workspace. This file records all install activities as they are performed in the platform and is not subject to configuration history limit set in the Update preferences.

Configuration history timelines

Eclipse Update is designed to cope with changes on the file system and try to reconcile these changes with its internal state. When these changes are considered controlled (e.g. when a new feature is added by a native installer), it reconciles the change within the same timeline. A timeline is a sequence of installation events that are considered mutually compatible. Stable states in the timeline (shown as configurations in the history) can be subject to the 'revert' operation (i.e. it is allowed to revert to any configuration within the same timeline).

Sometimes, the change made to the file system is considered so radical (location has changed, critical platform files have changed etc.) that Update throws the towel and initiates full reconciliation. Full reconciliation discards previous state and re-computes it from the ground up, enabling all the features in the process. Full reconciliation starts a new timeline. Once that happens, it is not possible to go back to a previous timeline using the 'revert' command. Configuration elements that belong to a different timeline are clearly marked in the configuration history with an icon overlay.

Other changes