Packages, Monticello, Iceberg & Tonel
A package groups classes and extension methods (methods in protocols named *PackageName).
28.1 Packages
A package groups classes and extension methods (methods in protocols named *PackageName). It is the unit of versioning and loading. Naming convention: Project-Component (Bank-Core, Bank-Tests, Bank-UI), with tags inside a package for finer grouping. Query them with BankAccount package name (→ 'Bank-Core') or (PackageOrganizer default packageNamed: 'Bank-Core') classes.
28.2 Monticello (legacy and Squeak)
Versions are .mcz files (zip archives containing source and metadata), named Package-Author.N.mcz.
Repositories: local directories, HTTP servers (SqueakSource, SqueakMap, the now read-only SmalltalkHub archive), and GemStone/Squeak servers.
The Monticello Browser saves, loads, merges, and diffs package versions.
Still the standard in Squeak and Cuis-adjacent communities (Cuis uses .pck.st files and Git); Pharo keeps Monticello internally as the layer below Iceberg.
28.3 Iceberg: Git in Pharo
Since Pharo 7, Iceberg is the Git client:
Open *Sources → Iceberg* (or *Browse → Git Repositories browser*).
Add a repository: *Clone from github.com* (SSH or HTTPS), *Import from existing local repository*, or *New repository*.
Specify the code subdirectory (convention: src).
Create or select packages and add them to the repository.
Commit (writes Tonel files and commits), then Push.
Use branches, pull, merge (with a diff/merge tool for Smalltalk code), and view history.
SSH credentials are configured in *Settings → Tools → Git/Iceberg* (or Iceberg's credentials window). Under the hood Iceberg uses libgit2 through FFI.
28.4 Tonel: the file format
Tonel stores one file per class, readable and diff-friendly:
A Tonel class file (BankAccount.class.st):
The older FileTree format (one file per method) is still readable by Iceberg and Metacello but no longer recommended.
my-bank/
├── .project {'srcDirectory' : 'src'}
├── README.md
├── .smalltalk.ston (CI configuration)
└── src/
├── .properties {#format : #tonel}
├── BaselineOfBank/
│ ├── BaselineOfBank.class.st
│ └── package.st
├── Bank-Core/
│ ├── BankAccount.class.st
│ ├── InsufficientFunds.class.st
│ ├── Number.extension.st (extension methods)
│ └── package.st
└── Bank-Tests/
├── BankAccountTest.class.st
└── package.st"
I represent a bank account with an owner and a balance.
"
Class {
#name : 'BankAccount',
#superclass : 'Object',
#instVars : [
'owner',
'balance'
],
#category : 'Bank-Core',
#package : 'Bank-Core',
#tag : 'Model'
}
{ #category : 'operations' }
BankAccount >> deposit: anAmount [
anAmount <= 0 ifTrue: [ ^ self error: 'Deposit must be positive' ].
balance := balance + anAmount
]28.5 Continuous integration
smalltalkCI runs tests for Pharo, Squeak, and GemStone on GitHub Actions or other CI services. .smalltalk.ston:
On GitHub Actions, the hpi-swt/setup-smalltalkCI action installs smalltalkCI; a job then runs smalltalkci -s Pharo64-13 (use a matrix such as Pharo64-12, Pharo64-13 to test several versions).
SmalltalkCISpec {
#loading : [
SCIMetacelloLoadSpec {
#baseline : 'Bank',
#directory : 'src',
#platforms : [ #pharo ]
}
],
#testing : { #coverage : { #packages : [ 'Bank-*' ] } }
}