6.3: Monticello
- Page ID
- 36362
\( \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}\)We gave you a quick overview of Monticello, Squeak’s packaging tool, in Section 2.9. However, Monticello has many more features than were discussed there. Because Monticello manages Packages, before telling you more about Monticello, it’s important that we first explain exactly what a package is.
Packages: declarative categorization of Squeak code
The package system is a simple, lightweight way of organizing Smalltalk source code. It leverages the long-used naming convention mentioned above (Section 6.2), but adds to it in an important way.
Let’s explain this using an example. Suppose that you are developing a framework named to facilitate the use of relational databases from Squeak. You have decided to call your framework SqueakLink, and have created a series of system categories to contain all of the classes that you have written, e.g.,
- Category
'SqueakLink-Connections'
containsOracleConnection MySQLConnection PostgresConnection
- Category
'SqueakLink-Model'
containsDBTable DBRow DBQuery
and so on. However, not all of your code will reside in these classes. For example, you may also have a series of methods to convert objects into an SQL-friendly format:
Object»asSQL String»asSQL Date»asSQL
These methods belong in the same package as the classes in the categories SqueakLink-Connections
and SqueakLink-Model
. But clearly the whole of class Object
does not belong in your package! So you need a way of putting certain methods in a package, even though the rest of the class is in another package.
The way that you do this is by placing those methods in a protocol (of Object
, String
, Date
, and so on) named *squeaklink (note the initial asterisk, and the lower-case name). The combination of the SqueakLink-... categories and the *squeaklink protocols form a package named SqueakLink. To be precise, the rules for what goes in a package are as follows.
A package named Foo
contains:
- all class definitions of classes in the category Foo, or in categories with names starting with Foo-, and
- all method definitions in any class in a protocol named *foo or whose name starts with *foo- (when performing this name comparison, the case of the letters in the names is ignored), and
- all methods in classes in the category Foo, or in a category whose name starts with Foo-, except for those methods in protocols whose names start with *.
A consequence of these rules is that each class definition and each method belongs to exactly one package. The except in the last rule has to be there because those methods must belong to other packages. The reason for ignoring case in rule 2 is that, by convention, protocol names are all lower case (and may include spaces), while category names use CamelCase (and don’t include spaces).
The class PackageInfo
implements these rules, and one way to get a feel for them is to experiment with this class.
\(\bigstar\) Try this in your image, which should contain the classes PackageInfo
and RefactoringBrowser
.
The Refactoring Browser code uses these package naming conventions, with RefactoringEngine
as the package name. In a workspace, create a model of this package with
refactory := PackageInfo named: 'RefactoringEngine'.
It is now possible to introspect on this package. For example, refactory classes
will return the long list of classes that make up the Refactoring Engine and the Refactoring Browser. refactory coreMethods
will return a list of MethodReferences
for all of the methods in those classes. refactory extensionMethods
is perhaps one of the most interesting queries: it will return a list of all methods contained in the RefactoringEngine
package but not contained within a RefactoringEngine
class. This includes, for example, ClassDescription»chooseThisClassInstVarThenDo: and SharedPool class»keys.
Packages are a relatively new addition to Squeak, but since the package naming conventions were based on those already in use, it is possible to use PackageInfo
to analyze older code that has not been explicitly adapted to work with it.
\(\bigstar\) Evaluate (PackageInfo named: 'Collections') externalSubclasses
; this expression will answer a list of all subclasses of Collection
that are not in the Collections
package.
You can send fileOut
to an instance of PackageInfo
to get a change set of the entire package. For more sophisticated versioning of packages, we use Monticello.
Basic Monticello
Monticello is named after the mountaintop home of Thomas Jefferson, third president of the United States and author of the Statute of Virginia for Religious Freedom. The name means “little mountain” in Italian, and so it is always pronounced with an Italian “c”, which sounds like the “ch” in chair: Mont-y’-che-llo.
When you open the Monticello browser, you will see two list panes and a row of buttons, as shown in Figure \(\PageIndex{1}\). The left-hand pane lists all of the packages that have been loaded into the image that you are running; the particular version of the package is shown in parentheses after the name.
The right-hand pane lists all of the source-code repositories that Monticello knows about, usually because it has loaded code from them. If you select a package in the left pane, the right pane is filtered to show only those repositories that contain versions of the selected package.
One of the repositories is a directory named package-cache, which is a sub-directory of the directory in which your image is running. When you load code from or write code to a remote repository, a copy is also saved in the package cache. This can be useful if the network is not available and you need to access a package. Also, if you are given a Monticello (.mcz) file directly, for example as an email attachment, the most convenient way to access it is to place it in the package-cache directory.
To add a new repository to the list, click the +Repository
, and choose the kind of repository from the pop-up menu. Let’s add an HTTP repository.
\(\bigstar\) Open Monticello, click on +Repository
, and select HTTP
. Edit the dialog to read:
MCHttpRepository location: 'http://squeaksource.com/SqueakByExample' user: '' password: ''
Then click on Open
to open a repository browser on this repository. You should see something like Figure \(\PageIndex{2}\). On the left is a list of all of the packages in the repository; if you select one, then the pane on the right will show all of the versions of the selected package in this repository.
If you select one of the versions, you can Browse
it (without loading it into your image), Load
it, or look at the Changes
that will be made to your image by loading the selected version. You can also make a Copy
of a version of a package, which you can then write to another repository.
As you can see, the names of versions contain the name of the package, the initials of the author of the version, and a version number. The version name is also the name of the file in the repository. Never change these names; correct operation of Monticello depends on them! Monticello version files are just zip archives, and if you are curious you can unpack them with a zip tool, but the best way to look at their contents is using Monticello itself.
To create a package with Monticello, you have to do two things: write some code, and tell Monticello about it.
\(\bigstar\) Create a category called SBE-Monticello, and put a couple of classes in it, as shown in Figure \(\PageIndex{3}\). Also, create a method in an existing class, and put it in the same package as your classes, using the rules from above — see Figure \(\PageIndex{4}\).
To tell Monticello about your package, click on +Package
, and type the name of the package, in this case “SBE”. Monticello will add SBE
to its list of packages; the package entry will be marked with an asterisk to show that the version in the image has not yet been written to any repository.
Initially, the only repository associated with this package will be your package cache, as shown in Figure \(\PageIndex{5}\). That’s OK: you can still save the code, which will cause it to be written to the package cache. Just click Save
and you will be invited to provide a log message for the version of the package that you are about to save, as shown in Figure \(\PageIndex{6}\); when you accept the message, Monticello will save your package. To indicate this, the asterisk decorating the name in Monticello’s package pane will be removed, and the version number added.
If you then make a change to the package — say by adding a method to one of the classes — the asterisk will re-appear, showing that you have unsaved changes. If you open a repository browser on the package cache, you can select the saved version, and use Changes
and the other buttons. You can of course save the new version to the repository too; once you Refresh
the repository view, it should look like Figure \(\PageIndex{7}\).
To save the new package to a repository other than the package cache, you need to first make sure that Monticello knows about the repository, adding it if necessary. Then you can use the Copy
in the package-cache repository browser, and select the repository to which the package should be copied. You can also associate the desired repository with the package by using the yellow button menu item add to package...
on the repository, as shown in Figure \(\PageIndex{8}\). Once the package knows about a repository, you can save a new version by selecting the repository and the package in the Monticello Browser, and clicking Save
. Of course, you must have permission to write to a repository. The SqueakByExample
repository on SqueakSource is world readable but not world writable, so if you try and save there, you will see an error message. However, you can create your own repository on SqueakSource by using the web interface at http://www.squeaksource.com, and use this to save your work. This is especially useful as a mechanism to share your code with friends, or if you use multiple computers.
If you do try and save to a repository where you don’t have write permission, a version will nevertheless be written to the package-cache.
So you can recover by editing the repository information (yellow button menu in the Monticello Browser) or choosing a different repository, and then using Copy
from the package-cache browser.