Skip to main content
Engineering LibreTexts

8.9: Dependencies Between Projects

  • Page ID
    45276
  • \( \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 the same way that a package can depend on other packages, a project can depend on other projects. For example, Pier, a content management system (CMS), depends on Magritte and Seaside. A project can depend on the entirety of one or more other projects, on a group of packages from another project, or on just one or two packages from another project.

    Depending on a project without a Metacello description

    Suppose that package A from project X depends on package B from project Y, and that project Y has not been described using Metacello. In this case we can describe the dependency as follows:

        "In a baseline method"
        spec
            package: 'PackageA' with: [ spec requires: #('PackageB')];
            package: 'PackageB' with: [ spec
                repository: 'http://www.smalltalkhub.com/ProjectB' ].
    
        "In the version method"
        package: 'PackageB' with: 'PackageB-JuanCarlos.80'.
    

    This works, up to a point. The shortcoming of this approach is that because project B is not described by a Metacello configuration, the dependencies of B are not managed. That is, any dependencies of package B will not be loaded. Our recommendation is that in this case, you take the time to create a configuration for project B.

    Depending on a project with a Metacello configuration

    Now let us look at the case where the projects on which we depend are described using Metacello. Let’s introduce a new project called CoolToolSet, which uses the packages from the CoolBrowser project. Its configuration class is called ConfigurationOfCoolToolSet. Suppose that there are two packages in CoolToolSet called CoolToolSet-Core and CoolToolSet-Tests. These packages depend on packages from CoolBrowser.

    Version 0.1 of CoolToolSet is just a normal version that imports a baseline:

    ConfigurationOfCoolToolSet>>version01: spec
        <version: '0.1' imports: #('0.1-baseline')>
        spec for: #common do: [
            spec
                package: 'CoolToolSet-Core' with: 'CoolToolSet-Core-AlanJay.1';
                package: 'CoolToolSet-Tests' with: 'CoolToolSet-Tests-AlanJay.1'.].
    

    If the project you depend on follows the conventions (i.e., class ConfigurationOfCoolBrowser in package ConfigurationOfCoolBrowser), the definition of the baseline is simple. By default you just need to specify the version (using versionString:) you want to load and the project repository (using repository: ).

    ConfigurationOfCoolToolSet >>baseline01: spec
        <version: '0.1-baseline'>
        spec for: #common do: [
            spec repository: 'http://www.example.com/CoolToolSet'.
            spec project: 'CoolBrowser ALL' with: [
                spec
                    repository: 'http://www.example.com/CoolBrowser';
                    loads: #('Core' 'Tests');
                    versionString: '2.5' ]
            spec
                package: 'CoolToolSet-Core' with: [ spec requires: 'CoolBrowser ALL' ];
                package: 'CoolToolSet-Tests' with: [ spec requires: 'CoolToolSet-Core' ]].
    

    We have named the project reference CoolBrowser ALL. The name of the project reference is arbitrary. You can select the name you want, although is it recommended that you choose a name that makes sense to that project reference. In the specification for the CoolToolSet-Core package, we have specified that CoolBrowser ALL is required. As will be explained later, the message project:with: allows one to specify the exact version of the project you want to load.

    The message loads: specify which packages or groups to load. The parameter of loads: can be the same as the one of load, i.e., the name of a package, the name of a group, or a collection of these things. Notice that calling loads: is optional, you only need it if you want to load something different from the default.

    Now we can load CoolToolSet like this:

    (ConfigurationOfCoolToolSet project version: '0.1') load.
    

    For unconventional projects

    Now if the project you depend on does not follow the default convention you will have to provide more information to identify the configuration. Let’s assume that the configuration is stored in a class ConfigurationOfCoolBrowser that is stored in a Monticello package called CoolBrowser-Metacello instead of the recommended ConfigurationOfCoolBrowser.

    ConfigurationOfCoolToolSet >>baseline01: spec
        <version: '0.1-baseline'>
        spec for: #common do: [
            spec repository: 'http://www.example.com/CoolToolSet'.
            spec project: 'CoolBrowser ALL' with: [
                spec
                    className: 'ConfigurationOfCoolBrowser';
                    loads: #('ALL' );
                    file: 'CoolBrowser-Metacello';
                    repository: 'http://www.example.com/CoolBrowser' ].
            spec
                package: 'CoolToolSet-Core' with: [ spec requires: 'CoolBrowser ALL' ];
                package: 'CoolToolSet-Tests' with: [ spec requires: 'CoolToolSet-Core' ]].
    
    • The message className: specifies the name of the class that contains the project metadata; in this case ConfigurationOfCoolBrowser.
    • The messages file: and repository: give Metacello the information that it might need to search for and load class ConfigurationOfCoolBrowser, if it is not present in the image. The argument of file: is the name of the Monticello package that contains the metadata class, and the argument of repository: is the URL of the Monticello repository that contains that package. If the Monticello repository is protected, then you should use the message: repository:username:password: instead.

    Now we can load CoolToolSet like this:

    (ConfigurationOfCoolToolSet project version: '0.1') load.
    
    Diagram showing dependencies between configurations.
    Figure \(\PageIndex{1}\): Dependencies between configurations.

    Depending on Multiple Projects

    Using ’ALL’ will cause the entire CoolBrowser project to be loaded before CoolToolSet-Core. If we wanted to specify dependencies on CoolBrowser’s test package separately from those on the core package, we define this baseline:

    ConfigurationOfCoolToolSet>>baseline02: spec
        <version: '0.2-baseline'>
        spec for: #common do: [
            spec blessing: #baseline.
            spec repository: 'http://www.example.com/CoolToolSet'.
            spec
                project: 'CoolBrowser default' with: [
                    spec
                        className: 'ConfigurationOfCoolBrowser'; "this is optional"
                        loads: #('default'); "this is optional"
                        repository: 'http://www.example.com/CoolBrowser' ].
                project: 'CoolBrowser Tests' with: [
                    spec
                        loads: #('Tests' );
                        repository: 'http://www.example.com/CoolBrowser' ].
            spec
                package: 'CoolToolSet-Core' with: [ spec requires: 'CoolBrowser default' ];
                package: 'CoolToolSet-Tests' with: [
                    spec requires: #(’CoolToolSet-Core’ ’CoolBrowser Tests’) ].].
    

    This baseline creates two project references: the reference named CoolBrowser default loads the default group and the reference named ’Cool-Browser Tests’ loads the ’Tests’ group of the configuration of CoolBrowser. We declare that CoolToolSet-Core requires CoolBrowser default and CoolToolSet-Tests requires CoolToolSet-Core and CoolBrowser Tests. Note also the use of requires: with a collection of dependent projects.

    Now it is possible to load just the core packages:

    (ConfigurationOfCoolToolSet project version: '0.2') load: 'CoolToolSet-Core'.
    

    or the tests (which will also load the core):

    (ConfigurationOfCoolToolSet project version: '0.2') load: 'CoolToolSet-Tests'.
    

    As we did for internal dependencies, baseline 0.2-baseline (and also in 0.1-baseline) does not specify the version of the project the configuration depends on. Instead, we do this in the version method using the message project:with:.

    ConfigurationOfCoolToolSet>>version02: spec
        <version: '0.2' imports: #('0.2-baseline' )>
        spec for: #common do: [
            spec blessing: #beta.
            spec
                package: 'CoolToolSet-Core' with: 'CoolToolSet-Core-AlanJay.1';
                package: 'CoolToolSet-Tests' with: 'CoolToolSet-Tests-AlanJay.1';
                project: 'CoolBrowser default' with: '1.3';
                project: 'CoolBrowser Tests' with: '1.3'].
    

    Loading specific packages

    In addition to baseline methods, version methods can specify which packages to load. Here in the ConfigurationOfSoup, we say that we want to load in the version 1.2 the packages ’XML-Parser’ and ’XML-Tests-Parser’.

    ConfigurationOfSoup>>version10: spec
        <version: '1.0' imports: #('1.0-baseline')>
    
        spec for: #common do: [
            spec
                project: 'XMLSupport'
                with: [spec
                    loads: #(’XML-Parser’ ’XML-Tests-Parser’);
                    versionString: ’1.2.0’].
    
        spec
            package: 'Soup-Core' with: 'Soup-Core-sd.11';
            package: 'Soup-Tests-Core' with: 'Soup-Tests-Core-sd.3';
            package: 'Soup-Help' with: 'Soup-Help-StephaneDucasse.2' ].
    

    What you can also do is to use the loads: message in the project reference to specify which packages of the project you want to load. Such solution is nice because you factor the information in the project reference and you do not have to duplicate it in all the versions.

    ConfigurationOfSoup>>version10: spec
        <version: '1.0' imports: #('1.0-baseline')>
    
        spec for: #pharo do: [
            spec project: 'XMLSupport' with: [
                    spec
                        versionString: #stable;
                        loads: #('XML-Parser' 'XML-Tests-Parser');
                        repository: 'http://ss3.gemstone.com/ss/xmlsupport' ].
    
        spec
            package: 'Soup-Core' with: 'Soup-Core-sd.11';
            package: 'Soup-Tests-Core' with: 'Soup-Tests-Core-sd.3';
            package: 'Soup-Help' with: 'Soup-Help-StephaneDucasse.2' ].
    

    Version in Baselines. Even if this is not recommended, nothing prevents you from specifying versions from baselines. The same happens with project references. So, in addition to messages like file:, className:, repository:, etc., there is a message called versionString: which lets you specify the version of the project directly in the project reference. Example:

    ConfigurationOfCoolToolSet >>baseline011: spec
        <version: '0.1.1-baseline'>
        spec for: #common do: [
            spec repository: 'http://www.example.com/CoolToolSet'.
            spec project: 'CoolBrowser ALL' with: [
                    spec
                        className: 'ConfigurationOfCoolBrowser';
                        loads: #('ALL' );
                        versionString: '0.6' ;
                        file: 'CoolBrowser-Metacello';
                        repository: 'http://www.example.com/CoolBrowser' ].
            spec
                package: 'CoolToolSet-Core' with: [ spec requires: 'CoolBrowser ALL' ];
                package: 'CoolToolSet-Tests' with: [ spec requires: 'CoolToolSet-Core' ]].
    

    If we don’t define a version for the references CoolBrowser default and CoolBrowser Tests in the version method, then the version specified in the baseline (using versionString:) is used. If there is no version specified in the baseline method, then Metacello loads the most recent version of the project.

    Reusing information. As you can see, in baseline02: information is duplicated in the two project references. To remove that duplication, we can use the project:copyFrom:with: method. For example:

    ConfigurationOfCoolToolSet >>baseline02: spec
        <version: '0.2-baseline'>
        spec for: #common do: [
            spec blessing: #baseline.
            spec repository: 'http://www.example.com/CoolToolSet'.
            spec
                project: 'CoolBrowser default' with: [
                    spec
                        loads: #('default');
                        repository: 'http://www.example.com/CoolBrowser';
                        file: 'CoolBrowser-Metacello']
                project: 'CoolBrowser Tests'
                    copyFrom: 'CoolBrowser default'
                    with: [ spec loads: #('Tests').].
            spec
                package: 'CoolToolSet-Core' with: [ spec requires: 'CoolBrowser default' ];
                package: 'CoolToolSet-Tests' with: [
                    spec requires: #('CoolToolSet-Core' 'CoolBrowser Tests') ].].
    

    This page titled 8.9: Dependencies Between Projects 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.