Developers in a software project use the versionMap to communicate to other developers (consumers of their software project):
- which packages belong to a particular version of the software project
- the load order of the packages on a version by version basis
- the operations to be performed pre/post load/unload.
- which other versionMaps (software projects) are required for a particular
version to function correctly.
- which groups of packages are intended to work together as loadable units.
As a first approximation for a versionMap we're looking at a dictionary of versions, keyed by a version string. Each version has a list of packages (including; package versions, package dependencies/ordering, pre/post load/unload operations, and dependencies on other projects/versionMaps), a list of repositories (including: repository location and type) and a list of groups (including; package membership, group dependencies, and dependencies on other projects/versionMaps). The list of packages/groups/repositories have conditional elements.
Lets talk about conditional elements a bit.
Platform-dependent code is the at the top of the list of 'conditional elements'. If a project doesn't have platform-dependent code, then it hasn't been ported to enough platforms yet:)
One of the goals of Metacello is to make it possible to manage conditional elements for a project without putting the onus for defining and maintaining those conditional elements on the core software developers.
Take Seaside2.9 as an example. It is asking enough of the core developers of Seaside to carve up the code into platform dependent/independent chunks. When they are ready to release version 2.9.0-alpha4, they should be able to publish a versionMap that covers the platforms that they care about. At the same time, when the port of 2.9.0-alpha4 to GemStone is done, I want to be able to publish a versionMap that includes the GemStone-specific version information:
1. ideally I can publish the versionMap without disturbing the non-GemStone
information.
2. ideally I can publish the versionMap as a new version of the original package.
3. ideally the core developers can easily verify (via diff) that I did indeed
leave their information undisturbed.
By dynamically building versionMap information and using Pragmas in the versionMap methods I think it's possible to achieve the ideals.
During the creation of a versionMap instance, methods are retrieved and executed based upon a specific pattern of Pragmas. There are two Pragma patterns used (the exact patterns used is open to debate as is whether Pragmas are the 'right' answer here):
<groups: 'versionString' attribute: #attributeSybol>
<packages: 'versionString' attribute: #attributeSybol>
Using Adrian's example (ARoot project) we'll be defining the ARootVersionMap based upon the followimg organization:
Production group
- A-view
- A-model
- B-library
Developer group
- A-view
- A-model
- A-model-tests
- B-library
- B-library-tests
To make things a little more complex we'll assume that 'A-model' must be loaded before 'B-library'.
Let's assume that when I initially port the ARoot project to GemStone, I add a GemStone-specific package, 'GS-library', and have a GemStone-specific version of the package 'A-model'.:
Production group
- A-view
- A-model
- B-library
- GS-library
Developer group
- A-view
- A-model
- A-model-tests
- B-library
- B-library-tests
- GS-library
Furthermore, 'GS-library' is to be loaded after 'B-library' and an ARoot specific operations is to be performed after loading (performing ARootVersionMap>>afterLoad100GemStone) 'GS-library'.
We'll start by defining the methods that use the 'groups' Pragma pattern:
groups100
<groups: '1.0.0' attributes: #common>
^(MetacelloGroupsSpec for: self)
addGroup:
((MetacelloGroupSpec for: self)
groupName: 'Production'
description: 'production packages for the ARoot project';
addMembers: {'A-view'. 'A-model'. 'B-library'. };
yourself);
addGroup:
((MetacelloGroupSpec for: self)
groupName: 'Developer'
description: 'developer packages for the ARoot project';
addMembers: { 'Production'. 'A-model-tests'. 'B-library-tests'. };
yourself);
yourself
groups100GemStone
<groups: '1.0.0' attributes: #gemstone>
^(MetacelloGroupsSpec for: self)
addGroup:
((MetacelloGroupSpec for: self)
groupName: 'Production';
addMember: 'GS-library';
yourself);
yourself
When the groups data structure of the versionMap is built, an ordered list of attributes is generated. For our example, when the versionMap is built on Squeak, the attribute list will be #(common squeak) and #(common gemstone) when the versionMap is built on GemStone.
To build the MetacelloGroupsSpec for version '1.0.0', the attribute list is traversed in order and the methods matching the #groups:attributes: whose arguments are '1.0.0' and #common are executed first, each subsequent method result is #merged: with the previous MetacelloGroupsSpec instance.
On Squeak only the #groups100 method would be executed, but on GemStone, since the #gemstone attribute is in the list, the results of #groups100 is #merged: with #groups100GemStone resulting in the following group definitions:
Production group
- A-view
- A-model
- B-library
- GS-library
Developer group
- A-view
- A-model
- A-model-tests
- B-library
- B-library-tests
- GS-library
This is important (to me). By using Pragmas, I can extend the groups definition for the ARootVersionMap _noninvasively_. Note that the list of attributes can be extended on a project by project basis. I think this is pretty powerful, but maybe what I'm smoking is powerful:)
Continuing with the 'packages' Pragma pattern, we define the list of package, their versions, dependencies, afterLoad operations, etc.:
packages100
<packageVersions: '1.0.0' attributes: #common>
^(MetacelloPackagesSpec for: self)
addPackage: 'A-view' file: 'A-View-al.1';
addPackage:
((MetacelloPackageSpec for: self)
packageName: 'A-model';
file: 'A-Model-al.2';
before: { 'B-library'. };
yourself);
addPackage: 'A-view-tests' file: 'A-view-tests-al.3';
addPackage: 'A-model-tests' file: 'A-model-tests-al.4';
addPackage: 'B-library' file: 'B-library-al.5';
addPackage: 'B-library-tests' file: 'B-library-tests-al.6';
addRepository: 'http://repsitoryX' type: 'http';
addRepository: 'http://repsitoryY' type: 'http';
yourself
packages100GemStone
<packageVersions: '1.0.0' attributes: #gemstone>
^(MetacelloPackageVersionsSpec for: self)
addPackage: 'A-model' file: 'A-Model.g-dkh.3';
addPackage:
((MetacelloPackageSpec for: self)
packageName: 'GS-library';
file: 'GS-library-dkh.1';
after: { 'B-library'. };
afterLoad: [ self afterLoad100GemStone ];
yourself);
addRepository: 'http://repsitoryGS' type: 'http';
yourself
afterLoad100GemStone
Smalltalk
at: #AViewClass
ifPresent: [:aView |
Smalltalk
at: #GSLibraryClass
ifPresent: [:gsLib aView register: gsLib ]]
When the packages data structure of the versionMap is built, the #packages100 packagesSpec will be created and the #packages100GemStone packagesSpec will be #merged:, adding the 'GS-library' package (with its afterLoad operation) to the list of packages.
Internally, the ARootVersionMap class has two sets of lists. The packages list representing the full set of packages that can be loaded. The groups list defining useful sets of packages that can be loaded together.
I think that it is important that the package names and group names be used interchangeably, in the #before/#after/#addMembers lists and in the #load/#unLoad directives.
When operating on a list of names, group names get replaced by the list of their members, until no group names remain.
That's probably enough for today ... There are a couple of more things that I want to cover:
- versionMap subclassing
- integration of different loaders like MC2
- changing versionMap definition rules - evolution of the things I covered today
- project to project dependencies (required versionMaps)
- development support (steps to creating a new version)
- reporting (load -N) and discovery
- load/update/unload nitty gritty
When I've exhausted that list, I think I will be exhausted:)
Dale
I think we'll all be exhausted! :) I'm really glad you're delving so
far into this - somebody has to. I'm sorry for my silence on this so
far; I'm trying to keep up as best I can but my personal life is
making it impossible at the moment for me to dive in deep enough to
engage in the debate.
Hopefully things will settle down for me sooner rather than later...
Julian
I understand how it goes ...
I do look forward to your comments, tho. Much of the previous post is pseudo code and represents my current thinking ... so if you see things that raise a red flag in your mind, but don't have a concrete con argument, feel free to post the question/concern without worrying about rationale - knowing that a potential red flag would be good enough for me.
Dale
| On May 22, 2009, at 12:28 AM, Dale Henrichs wrote:
|
| >
| > In Metacello, the versionMap is _the_ package management artifact.
| > Developers in a software project use the versionMap to communicate
| > to other developers (consumers of their software project):
| >
| > - which packages belong to a particular version of the software
| > project
| > - the load order of the packages on a version by version basis
| > - the operations to be performed pre/post load/unload.
| > - which other versionMaps (software projects) are required for a
| > particular
| > version to function correctly.
| > - which groups of packages are intended to work together as loadable
| > units.
|
| sounds good to me.
| Dale I think that when you have something stable we could give a try
| to manage moose with it.
Stef,
The current version is stable (Metacello-dkh.147). I'm holding off development until I feel comfortable with the requirements for the next wholesale rewrite.
I think it would be useful for you to take a cut at using Metacello to configure Moose and identify the things that are difficult to express or just plain wacky:) There should be enough functionality there for you to do a proof-of-concept for Moose.
WAVersionMap is a functional prototype and is based on Metacello-dkh.147, so I'd recommend that you use WAVersionMap as a guide as to what you can and can't do and then asking me questions if things aren't obvious. With that said, be prepared to toss everything you've done for Moose against Metacello-dkh.147, because the API will be changing with the next rewrite.
Dale