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}}\)
\( \newcommand{\vectorA}[1]{\vec{#1}} % arrow\)
\( \newcommand{\vectorAt}[1]{\vec{\text{#1}}} % arrow\)
\( \newcommand{\vectorB}[1]{\overset { \scriptstyle \rightharpoonup} {\mathbf{#1}} } \)
\( \newcommand{\vectorC}[1]{\textbf{#1}} \)
\( \newcommand{\vectorD}[1]{\overrightarrow{#1}} \)
\( \newcommand{\vectorDt}[1]{\overrightarrow{\text{#1}}} \)
\( \newcommand{\vectE}[1]{\overset{-\!-\!\rightharpoonup}{\vphantom{a}\smash{\mathbf {#1}}}} \)
\( \newcommand{\vecs}[1]{\overset { \scriptstyle \rightharpoonup} {\mathbf{#1}} } \)
\( \newcommand{\vecd}[1]{\overset{-\!-\!\rightharpoonup}{\vphantom{a}\smash {#1}}} \)
\(\newcommand{\avec}{\mathbf a}\) \(\newcommand{\bvec}{\mathbf b}\) \(\newcommand{\cvec}{\mathbf c}\) \(\newcommand{\dvec}{\mathbf d}\) \(\newcommand{\dtil}{\widetilde{\mathbf d}}\) \(\newcommand{\evec}{\mathbf e}\) \(\newcommand{\fvec}{\mathbf f}\) \(\newcommand{\nvec}{\mathbf n}\) \(\newcommand{\pvec}{\mathbf p}\) \(\newcommand{\qvec}{\mathbf q}\) \(\newcommand{\svec}{\mathbf s}\) \(\newcommand{\tvec}{\mathbf t}\) \(\newcommand{\uvec}{\mathbf u}\) \(\newcommand{\vvec}{\mathbf v}\) \(\newcommand{\wvec}{\mathbf w}\) \(\newcommand{\xvec}{\mathbf x}\) \(\newcommand{\yvec}{\mathbf y}\) \(\newcommand{\zvec}{\mathbf z}\) \(\newcommand{\rvec}{\mathbf r}\) \(\newcommand{\mvec}{\mathbf m}\) \(\newcommand{\zerovec}{\mathbf 0}\) \(\newcommand{\onevec}{\mathbf 1}\) \(\newcommand{\real}{\mathbb R}\) \(\newcommand{\twovec}[2]{\left[\begin{array}{r}#1 \\ #2 \end{array}\right]}\) \(\newcommand{\ctwovec}[2]{\left[\begin{array}{c}#1 \\ #2 \end{array}\right]}\) \(\newcommand{\threevec}[3]{\left[\begin{array}{r}#1 \\ #2 \\ #3 \end{array}\right]}\) \(\newcommand{\cthreevec}[3]{\left[\begin{array}{c}#1 \\ #2 \\ #3 \end{array}\right]}\) \(\newcommand{\fourvec}[4]{\left[\begin{array}{r}#1 \\ #2 \\ #3 \\ #4 \end{array}\right]}\) \(\newcommand{\cfourvec}[4]{\left[\begin{array}{c}#1 \\ #2 \\ #3 \\ #4 \end{array}\right]}\) \(\newcommand{\fivevec}[5]{\left[\begin{array}{r}#1 \\ #2 \\ #3 \\ #4 \\ #5 \\ \end{array}\right]}\) \(\newcommand{\cfivevec}[5]{\left[\begin{array}{c}#1 \\ #2 \\ #3 \\ #4 \\ #5 \\ \end{array}\right]}\) \(\newcommand{\mattwo}[4]{\left[\begin{array}{rr}#1 \amp #2 \\ #3 \amp #4 \\ \end{array}\right]}\) \(\newcommand{\laspan}[1]{\text{Span}\{#1\}}\) \(\newcommand{\bcal}{\cal B}\) \(\newcommand{\ccal}{\cal C}\) \(\newcommand{\scal}{\cal S}\) \(\newcommand{\wcal}{\cal W}\) \(\newcommand{\ecal}{\cal E}\) \(\newcommand{\coords}[2]{\left\{#1\right\}_{#2}}\) \(\newcommand{\gray}[1]{\color{gray}{#1}}\) \(\newcommand{\lgray}[1]{\color{lightgray}{#1}}\) \(\newcommand{\rank}{\operatorname{rank}}\) \(\newcommand{\row}{\text{Row}}\) \(\newcommand{\col}{\text{Col}}\) \(\renewcommand{\row}{\text{Row}}\) \(\newcommand{\nul}{\text{Nul}}\) \(\newcommand{\var}{\text{Var}}\) \(\newcommand{\corr}{\text{corr}}\) \(\newcommand{\len}[1]{\left|#1\right|}\) \(\newcommand{\bbar}{\overline{\bvec}}\) \(\newcommand{\bhat}{\widehat{\bvec}}\) \(\newcommand{\bperp}{\bvec^\perp}\) \(\newcommand{\xhat}{\widehat{\xvec}}\) \(\newcommand{\vhat}{\widehat{\vvec}}\) \(\newcommand{\uhat}{\widehat{\uvec}}\) \(\newcommand{\what}{\widehat{\wvec}}\) \(\newcommand{\Sighat}{\widehat{\Sigma}}\) \(\newcommand{\lt}{<}\) \(\newcommand{\gt}{>}\) \(\newcommand{\amp}{&}\) \(\definecolor{fillinmathshade}{gray}{0.9}\)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:
andrepository:
give Metacello the information that it might need to search for and load classConfigurationOfCoolBrowser
, if it is not present in the image. The argument offile:
is the name of the Monticello package that contains the metadata class, and the argument ofrepository:
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.

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') ].].