Skip to main content
Engineering LibreTexts

8.13: Milestoning Development- Symbolic Versions

  • Page ID
    45284
  • \( \newcommand{\vecs}[1]{\overset { \scriptstyle \rightharpoonup} {\mathbf{#1}} } \) \( \newcommand{\vecd}[1]{\overset{-\!-\!\rightharpoonup}{\vphantom{a}\smash {#1}}} \)\(\newcommand{\id}{\mathrm{id}}\) \( \newcommand{\Span}{\mathrm{span}}\) \( \newcommand{\kernel}{\mathrm{null}\,}\) \( \newcommand{\range}{\mathrm{range}\,}\) \( \newcommand{\RealPart}{\mathrm{Re}}\) \( \newcommand{\ImaginaryPart}{\mathrm{Im}}\) \( \newcommand{\Argument}{\mathrm{Arg}}\) \( \newcommand{\norm}[1]{\| #1 \|}\) \( \newcommand{\inner}[2]{\langle #1, #2 \rangle}\) \( \newcommand{\Span}{\mathrm{span}}\) \(\newcommand{\id}{\mathrm{id}}\) \( \newcommand{\Span}{\mathrm{span}}\) \( \newcommand{\kernel}{\mathrm{null}\,}\) \( \newcommand{\range}{\mathrm{range}\,}\) \( \newcommand{\RealPart}{\mathrm{Re}}\) \( \newcommand{\ImaginaryPart}{\mathrm{Im}}\) \( \newcommand{\Argument}{\mathrm{Arg}}\) \( \newcommand{\norm}[1]{\| #1 \|}\) \( \newcommand{\inner}[2]{\langle #1, #2 \rangle}\) \( \newcommand{\Span}{\mathrm{span}}\)\(\newcommand{\AA}{\unicode[.8,0]{x212B}}\)

    In any large evolving application it is difficult to know which version of a configuration to use with a specific system. ConfigurationOfOmniBrowser provides a good example of the problem: version 1.1.3 is used in the Pharo1.0 one-click image, version 1.1.3 cannot be loaded into Pharo1.2, version 1.1.5 is for Pharo1.1, version 1.2.3 is for Pharo1.2, and it cannot load in Pharo1.0, and there is no version for Pharo2.0. We provide this example as an illustration of what we can do with Metacello.

    Metacello introduces symbolic versions to describe versions in terms of existing literal versions (like 1.1.3, 1.1.5, and 1.2.3). Symbolic versions are specified using the symbolicVersion: pragma. Here we defined the stable versions for OmniBrowser for each version of Pharo.

    OmniBrowser>>stable: spec
        <symbolicVersion: #stable>
        spec for: #'pharo1.0.x' version: '1.1.3'.
        spec for: #'pharo1.1.x' version: '1.1.5'.
        spec for: #'pharo1.2.x' version: '1.2.3'.
    

    Symbolic versions can be used anywhere that a literal version can be used. From load expressions such as

    (ConfigurationOfXMLParser project version: #stable) load
    
    (ConfigurationOfXMLParser project version: #stable) load: 'Tests'
    

    to a project reference in a baseline version:

    baseline10: spec
        <version: '1.0-baseline'>
        spec for: #squeakCommon do: [
            spec blessing: #baseline.
            spec repository: 'http://seaside.gemstone.com/ss/GLASSClient'.
        spec
            project: 'OmniBrowser' with: [
            spec
                className: 'OmniBrowser';
                versionString: #stable;
                repository: 'http://www.squeaksource.com/MetacelloRepository' ].
        spec
            package: 'OB-SUnitGUI' with: [
                spec requires: #('OmniBrowser') ];
            package: 'GemTools-Client' with: [
                spec requires: #('OB-SUnitGUI') ];
            package: 'GemTools-Platform' with: [
                spec requires: #('GemTools-Client') ]].
    

    Note that the #stable here overrides the bleeding edge loading behavior that you would get if you were (fool enough) to load a baseline (remember loading a baseline loads bleeding edge versions). Here we make sure that the stable version of OmniBrowser for your platform will be loaded (and not the latest one). The next section is about the different symbolic versions.

    Standard Symbolic Versions

    A couple of standard symbolic versions are defined:

    stable. A symbolic version that specifies the stable literal version for a particular platform and version of such a platform. The stable version is the version that should be used for loading. With the exception of the bleedingEdge version (which has a pre-defined default), you will need to edit your configuration to add the stable or development version information: I want a certified version for the platform. Now pay attention because if you rely on a stable version of a package it does not mean that the package cannot change. Indeed the package implementor may produce a new version that may be incompatible with your system.

    development. A symbolic version that specifies the literal version to use under development (i.e., whose blessing is development). Typically a development version is used by developers for managing pre-release activities as the project transitions from bleedingEdge to stable. It means: I want a certified version for the platform but in development mode.

    bleedingEdge. A symbolic version that specifies the latest mcz files and project versions. By default the bleedingEdge symbolic version is defined as the latest baseline version available. The default specification for bleedingEdge is defined for all projects. The bleedingEdge version is primarily for developers who know what they are doing. There are no guarantees that the bleedingEdge version will even load, let alone function correctly: I want the latest published file.

    When specifying a symbolic version with a symbolicVersion: pragma it is legal to use another symbolic version like the following definition for the symbolic version stable:

    stable: spec
        <symbolicVersion: #stable>
    
        spec for: #gemstone version: '1.5'.
        spec for: #'squeak' version: '1.4'.
        spec for: #'pharo1.0.x' version: '1.5'.
        spec for: #'pharo1.1.x' version: '1.5'.
        spec for: #'pharo1.2.x' version: #development.
    

    Or to use the special symbolic version notDefined: as in the following definition of the symbolic version development:

    development: spec
        <symbolicVersion: #development>
    
        spec for: #common version: #notDefined.
        spec for: #'pharo1.1.x' version: '1.6'.
        spec for: #'pharo1.2.x' version: '1.6'.
    

    Here it indicates that there is no version for the common tag. Using a symbolic version that resolves to notDefined will result in a MetacelloSymbolicVersionNotDefinedError being signaled.

    For the development symbolic version you can use any version that you wouldd like (including another symbolic version). As the following code shows it, we can specify a specific version, a baseline (which will load the latest versions specified by the baseline) or a stable version.

    development: spec
        <symbolicVersion: #'development'>
        spec for: #'common' version: '1.1'
    
    development: spec
        <symbolicVersion: #'development'>
        spec for: #'common' version: '1.1-baseline'
    
    development: spec
        <symbolicVersion: #'development'>
        spec for: #'common' version: #stable
    

    Warning. The term stable is misleading. It does not mean that you will always load exactly the same version because the developer of the system you rely on may change the meaning of stable to point to another stable version. But such a stable version may introduce incompatibility with your own code. So when you release your code you should use a specific version to be sure that you will not get impacted by other changes.

    Project Blessing and Loading

    Packages or projects pass through several stages or steps during the software development process or life cycle such as: development, alpha, beta, release.

    Blessings are taken into account by the load logic. The result of the following expression:

    ConfigurationOfCoolBrowser project latestVersion.
    

    is not always the last version. This is because latestVersion answers the latest version whose blessing is not #development, #broken, or #blessing. To find the latest #development version for example, you should execute this expression:

    ConfigurationOfCoolBrowser project latestVersion: #development.
    

    Nevertheless, you can get the very last version independently of blessing using the lastVersion method as illustrated below

    ConfigurationOfCoolBrowser project lastVersion.
    

    In general, the #development blessing should be used for any version that is unstable. Once a version has stabilized, a different blessing should be applied.

    The following expression will load the latest version of all of the packages for the latest #baseline version:

    (ConfigurationOfCoolBrowser project latestVersion: #baseline) load.
    

    Since the latest #baseline version should reflect the most up-to-date project structure, executing the previous expression loads the absolute bleeding edge version of the project.

    Hints.

    Some patterns emerge when working with Metacello. Here is one: Create a baseline version and use the #stable version for all of the projects in the baseline. In the literal version, use the explicit version, so that you get an explicit repeatable specification for a set of projects that were known to work together.

    Here is an example, the pharo 1.2.2-baseline would include specs that look like this:

    spec
        project: 'OB Dev' with: [
            spec
                className: 'ConfigurationOfOmniBrowser';
                versionString: #stable;
                ...];
        project: 'ScriptManager' with: [
            spec
                className: 'ConfigurationOfScriptManager';
                versionString: #stable;
                ...];
        project: 'Shout' with: [
            spec
                className: 'ConfigurationOfShout';
                versionString: #stable;
                ...];
        ....].
    

    Loading Pharo 1.2.2-baseline would cause the #stable version for each of those projects to be loaded ... but remember over time the #stable version will change and incompatibilities between packages can creep in. By using #stable versions you will be in better shape than using #bleedingEdge, because the #stable version is known to work.

    Pharo 1.2.2 (literal version) will have corresponding specs that look like this:

    spec
        project: 'OB Dev' with: '1.2.4';
        project: 'ScriptManager' with: '1.2';
        project: 'Shout' with: '1.2.2';
        ....].
    

    So that you have driven a stake into the ground stating that these versions are known to work together (have passed tests as a unit). Five years in the future, you will be able to load Pharo 1.2.2 and get exactly the same packages every time, whereas the #stable versions may have drifted over time.

    If you are just bringing up a PharoCore1.2 image and would like to load the Pharo dev code, you should load the #stable version of Pharo (which may be 1.2.2 today and 1.2.3 tomorrow). If you want to duplicate the environment that someone is working in, you will ask them for the version of Pharo and load that explicit version to reproduce the bug or whatever request you may need.

    How to Deal with Package Structure Changes

    Imagine that you want to develop an application on both Pharo13 and Pharo14, and that your application has only a package for one version: ei- ther because you changed your application or because the package was inte- grated into the base system.

    The solution is to define the dependencies and use the symbolic tag as a marker, as follows:

    spec for: #'pharo' do: [
        spec package: 'that depends upon zinc' with: [
            "the common required packages for your package"
        ].
    
        spec for: #'pharo1.3.x' do: [
            spec project: 'Zinc' with: [
                spec
                    className: 'ConfigurationOfZinc';
                    versionString: #'stable';
                    repository: 'http://www.squeaksource.com/MetacelloRepository' ].
            spec package: 'that depends upon zinc' with: [
                spec requires: #('Zinc') ].
    ].
    

    If you use the stable version in your baseline there is no need to do anything special in your version specification.


    This page titled 8.13: Milestoning Development- Symbolic Versions is shared under a CC BY-SA 3.0 license and was authored, remixed, and/or curated by Alexandre Bergel, Damien Cassou, Stéphane Ducasse, Jannik Laval (Square Bracket Associates) via source content that was edited to the style and standards of the LibreTexts platform; a detailed edit history is available upon request.