Currently GemStone2.4, PharoCore 1.3, PharoCore 1.4, Pharo5 and Squeak4.3 are supported.
- Set up git.
- Create a GitHub repository.
- Create
filetree:
repository directory - Install Metacello
- Attach to git repository
- Create baseline
- Converting an existing baseline
- Prime Metacello registry
- Saving your work
- Create configuration
- Git workflow
Technically the FileTree repository into which packages have to be persisted can be located in the root of your git checkout, but I like to provide some initial structure to the git repository so there is room for adding artifacts (like documentation) in addition to the packages.
I start my projects with the following files and directories:
+-Sample
+-docs
| +-README.md
+-license.txt
+-repository
+-README.md
I put the Monticello packages in the repository
directory.
Some like to use other names. Common spotted naming schemes include: mc
, src
, packages
(the use of this last one is actually not recommended because of some obscure GitHub reason related to MSProject).
These expressions install the Metacello Preview and FileTree.
"Get the Metacello configuration"
Gofer new
url: 'http://seaside.gemtalksystems.com/ss/metacello/';
package: 'ConfigurationOfMetacello';
load.
"Bootstrap Metacello Preview, using mcz files (#'previewBootstrap' symbolic version)"
((Smalltalk at: #ConfigurationOfMetacello) project
version: #'previewBootstrap') load.
"Load the Preview version of Metacello from GitHub"
(Smalltalk at: #Metacello) new
configuration: 'MetacelloPreview';
version: #stable;
repository: 'github://dalehenrich/metacello-work:configuration';
load.
For Pharo 5 and beyond, Metacello/FileTree/GitFileTree are already in the base image.
For Squeak, you will want to use Installer to load the ConfigurationOfMetacello.
When you install FileTree, a new Monticello repository type, filetree: is added to the MonticelloBrowser menu. Selecting the filetree: menu item will bring up a directory selector. Select the directory in your git repository where you want the packages installed.
If you prefer you can execute the following:
| pathToPackageDirectory packageDirectory repo |
"edit to match the path to your chosen package directory"
pathToPackageDirectory := '/opt/git/Sample/repository'.
packageDirectory := FileDirectory on: pathToPackageDirectory.
"create a FileTree repository"
repo := MCFileTreeRepository new
directory: packageDirectory.
"add repo to default repositories"
MCRepositoryGroup default addRepository: repo.
^repo
MCFileTreeRepository can be used anywhere that normal Monticello repositories can be used. I.e., you can copy packages into and out of an MCFileTreeRepository repository like any other repository.
During development phase of a project using a FileTree repository, you only need to create a baseline for your project.
Start by creating a subclass of BaselineOf:
BaselineOf subclass: #BaselineOfSample
instanceVariableNames: ''
classVariableNames: ''
poolDictionaries: ''
category: 'BaselineOfSample'
Next, you need to create a baseline: method.
If you've already got a configuration created for your project, you can use one of your baselineXXX: methods as a starting point and make the following edits:
- make sure that the versionString: for each project is pointing at an explicit version.
- remove the repository: statement. The baseline references the repository that it is loaded from.
If you don't have a configuration, here is a sample baseline:
baseline: spec
<baseline>
spec for: #common do: [
spec configuration: 'Seaside30' with: [
spec
version: #stable;
repository: 'http://www.squeaksource.com/MetacelloRepository' ].
spec
package: 'Sample-Core' with: [
spec requires: 'Seaside30' ];
package: 'Sample-Tests' with: [
spec requires: 'Sample-Core' ]].
For more information about creating Metacello configurations, see the Metacello chapter of Pharo by Example.
After you've created the BaselineOf, save it into your project repository.
To use a BaselineOf in another configuration or baseline simply do this:
baseline: spec
<baseline>
spec for: #common do: [
spec baseline: 'Sample' with: [
spec repository: 'github://dalehenrich/Sample:master' ].
spec package: 'OtherProject-Core' with: [
spec requires: 'Sample' ] ].
If your BaselineOf provides groups or multiple packages, you need to tell
Metacello that it shouldn't complain about names it can not initially resolve.
Names defined by a BaselineOf can only be resolved after it has been loaded,
so Metacello needs to assume that unresolved names will be resolvable in the
BaselineOf.
Use the message #import:
to do that:
baseline: spec
<baseline>
spec for: #common do: [
spec baseline: 'Sample' with: [
spec repository: 'github://dalehenrich/Sample:master' ].
spec import: 'Sample'.
spec package: 'OtherProject-Core with: [
spec requires: 'default' ] ].
The #import:
message has one drawback: if your configuration references multiple
BaselineOf Metacello does not know with which one to resolve ambiguous names.
Example:
baseline: spec
<baseline>
spec for: #common do: [
"Sample defines the group 'default'"
spec baseline: 'Sample' with: [
spec repository: 'github://dalehenrich/Sample:master' ].
spec import: 'Sample'.
"OtherSample *also* defines the group 'default'"
spec baseline: 'OtherSample' with: [
spec repository: 'github://dalehenrich/Sample:master' ].
spec import: 'OtherSample'.
"'default' is now ambiguous"
spec package: 'OtherProject-Core with: [
spec requires: 'default' ] ].
To solve these ambiguities, newer versions of Metacello include the message
#import:provides:
which allows you to specify the explicit relationship:
baseline: spec
<baseline>
spec for: #common do: [
"Sample defines the group 'default'"
spec baseline: 'Sample' with: [
spec repository: 'github://dalehenrich/Sample:master' ].
spec import: 'Sample' provides: #('default').
"OtherSample *also* defines the group 'default'"
spec baseline: 'OtherSample' with: [
spec repository: 'github://dalehenrich/Sample:master' ].
spec import: 'OtherSample' provides: #('default').
"'default' can now be successfully resolved, even though
both projects define the same name"
spec package: 'OtherProject-Core with: [
spec requires: 'default' ] ].
If you are converting a project for which you have an existing baseline, there are a few simple rules to follow:
- change the name of the baeline method to
baseline:
. - switch the pragma to
<baseline>
. - remove the
blessing:
andrepository:
messages at the project level
For example given the following baseline method from a ConfigurationOfXXX:
baseline122: spec
<version: '1.022-baseline'>
spec
for: #'common'
do: [
spec blessing: #'baseline'.
spec repository: 'http://ss3.gemtalksystems.com/ss/Application'.
spec
project: 'XMLSupport'
with: [
spec
className: 'ConfigurationOfXMLSupport';
versionString: '1.2.2.1';
loads: #('Core');
file: 'ConfigurationOfXMLSupport';
repository: 'http://www.squeaksource.com/XMLSupport' ].
spec package: 'Application' with: [ spec requires: 'XMLSupport' ] ]
The converted baseline:
for your BaselineOfXXX would be:
baseline: spec
<baseline>
spec
for: #'common'
do: [
spec repository: 'http://ss3.gemtalksystems.com/ss/Application'.
spec
project: 'XMLSupport'
with: [
spec
className: 'ConfigurationOfXMLSupport';
versionString: '1.2.2.1';
loads: #('Core');
file: 'ConfigurationOfXMLSupport';
repository: 'http://www.squeaksource.com/XMLSupport' ].
spec package: 'Application' with: [ spec requires: 'XMLSupport' ] ]
for extra credit you can use the new configuration:
message to streamline the specification of your required project to produce the following:
baseline: spec
<baseline>
spec
for: #'common'
do: [
spec repository: 'http://ss3.gemtalksystems.com/ss/Orbeon'.
spec
configuration: 'XMLSupport'
with: [
spec
versionString: '1.2.2.1';
loads: #('Core');
repository: 'http://www.squeaksource.com/XMLSupport' ].
spec package: 'Orbeon-BrunoBB' with: [ spec requires: 'XMLSupport' ] ]
You must do at least one fully-specified load of a project to make sure that the project is correctly registered in the Metacello Project Registry:
| pathToPackageDirectory |
"edit to match the path to your chosen package directory"
pathToPackageDirectory := '/opt/git/Sample/repository'.
Metacello new
baseline: 'Sample';
repository: 'filetree://', pathToPackageDirectory;
load.
For GitHub repositories specifically you can use the following to fetch your project from GitHub:
| repositorySpec |
"edit to match your username, repository name and branch"
repositorySpec := 'dalehenrich/metacello-work:master'.
Metacello new
baseline: 'Sample';
repository: 'github://', repositorySpec;
load.
For more information on the github://dalehenrich/sample:cecd1626d27f67175f22e6075ca2d1177da1d525/repository
description see the section on
github:// in the Metacello Scripting API
reference.
Once you've done the first load, you can execute the following
expressions to refresh the baseline and reload the project (useful if
you've done a git checkout
or pull
):
Metacello image
baseline: 'Sample';
get;
load.
When you've finished a unit of work, you need to perform the following steps to save your work to GitHub:
- Monticello
commit
from the MonticelloBrowser for each of your dirty packages. - Git
commit
to save your work into your local git repository. - Git
push
to share the work with your GitHub repository.
Note that I do a git commit
after every Monticello commit
, but I don't always do a git push
after every git commit
. The push
is only necessary when I'm ready to share my work with others.
When you are ready to make a release of your project, you should create a configuration.
Start by creating a subclass of ConfigurationOf:
ConfigurationOf subclass: #ConfigurationOfSample
instanceVariableNames: ''
classVariableNames: ''
poolDictionaries: ''
category: 'ConfigurationOfSample'
version100: spec
<version: '1.0.0'>
spec
for: #'common'
do: [
spec blessing: #'release'.
spec description: 'a lot of cool stuff'.
spec author: 'dkh'.
spec timestamp: '7/30/2012 15:52'.
spec
baseline: 'Sample' with: [ spec repository: 'github://dalehenrich/sample:cecd1626d27f67175f22e6075ca2d1177da1d525/repository' ];
import: 'Sample' ]
Note that you should only use this approach if you are sharing your configuration with folks who are participating in the Metacello Preview.
For more information on the github://dalehenrich/sample:cecd1626d27f67175f22e6075ca2d1177da1d525/repository
description see the section on
github:// in the Metacello Scripting API
reference.
For the most part I tend to follow the GitHub Flow model. It is worth reading about git-flow.