Wednesday, September 24, 2008

Package management nirvana

Managing the set of package objects and files has been a key challenge for some time now. Obviously, the trick is to keep enough packages around to meet reasonable requirements, but to delete them promptly enough once they are no longer required to avoid consuming too much of the repository's resources.

The "state of the art" since ControlTier 3.0 has been the Builder repoFind command which can (optionally) delete package objects and files (i.e. "purge") following these rules:
  • Identify candidate packages by a type regex
  • Apply a buildstamp/version regex
  • Avoiding deleting any packages that are in use (i.e. have referrer relationships)
(Note that repoFind has a companion command, repoPurge, which it calls directly when the "-purge" option is specified).

I recently improved this state of affairs by adding the Purge workflow and the packagePurgeRegex to the Builder base type in order to add the following rule:
  • Avoid deleting the most recently built package associated with the builder
This is achieved by using the attribute to provide an "inverse" regex of the builder's buildstamp attribute as repoFind's buildstamp option - i.e.:

^(?!^${entity.attribute.buildstamp}$).*$

This works well enough with a simple model that has a single builder creating packages of a distinct type. Trouble arises when - as is the case for standard branch, trunk, release development - there are multiple builders (usually of the same type) creating packages of a given type. Since each builder then has a distinct buildstamp attribute; running the Purge workflow for one builder will erroneously delete the most recent builds of any other builder that also manages the package type. Grrr ... the default inverse regex is too inclusive!

The solution for this is to generate a list of buildstamps to exclude based on all instances of the Builder type in question and use that to constrain the action of repoFind.

I have just revised the Builder type to achieve this by adding the "generateBuildstampExcludes" command to the Builder base type. If the Builder (or Builder sub-type) in question has a "BuilderPackagePurgeRegex" setting resource assigned, the command updates its value with the list of buildstamps to exclude.

The last piece of this particular puzzle, then was to add the new command to the Builder's standard Purge workflow, thus ensuring that "entity.attribute.packagePurgeRegex" is set to the appropriate value prior to the invocation of repoFind.

The Purge command's new usage is:

Purge [-buildertype <${entity.classname}>] [-packagetype <${entity.attribute.packageType}>]

... allowing packages of the selected type (defaulting to the assigned package type of the builder) to be purged excluding buildstamps associated will all instances of the specified builder type (defaulting to the type of the invoking builder).

Typical use cases would be to invoke Purge from an operational builder, or to use a "global" ProjectBuilder (co-deployed with the Workbench package repository) to manage purges for all builder and package types.

I've committed these enhancements to the ControlTier 3.1 support branch (since I implemented them for a particular client); however, I'll get them merged into the 3.2 development branch as soon as possible.

Anthony Shortland,
ControlTier Professional Services.