We use CVS (Concurrent Version System) to keep track of our sources for various software projects. CVS lets several people work on the same software at the same time, allowing changes to be checked in incrementally.
This section is a set of guidelines for how to use our CVS
repository, and will probably evolve in time. The main thing to
remember is that most mistakes can be undone, but if there's
anything you're not sure about feel free to bug the local CVS
meister (namely Jeff Lewis
<jlewis@galois.com>
).
You can access the repository in one of two ways: read-only (Section 2.1.1, “Remote Read-only CVS Access”), or read-write (Section 2.1.2, “Remote Read-Write CVS Access”).
Read-only access is available to anyone - there's no need to ask us first. With read-only CVS access you can do anything except commit changes to the repository. You can make changes to your local tree, and still use CVS's merge facility to keep your tree up to date, and you can generate patches using 'cvs diff' in order to send to us for inclusion.
To get read-only access to the repository:
Make sure that cvs is installed on your machine.
Set your $CVSROOT
environment variable to
:pserver:anoncvs@glass.cse.ogi.edu:/cvs
If you set $CVSROOT
in a shell script, be sure not to
have any trailing spaces on that line, otherwise CVS will respond with
a perplexing message like
/cvs : no such repository
Run the command
$ cvs login
The password is simply cvs
. This
sets up a file in your home directory called
.cvspass
, which squirrels away the
dummy password, so you only need to do this step once.
Now go to Section 2.2, “Checking Out a Source Tree”.
We generally supply read-write access to folk doing serious development on some part of the source tree, when going through us would be a pain. If you're developing some feature, or think you have the time and inclination to fix bugs in our sources, feel free to ask for read-write access. There is a certain amount of responsibility that goes with commit privileges; we are more likely to grant you access if you've demonstrated your competence by sending us patches via mail in the past.
To get remote read-write CVS access, you need to do the following steps.
Make sure that cvs
and
ssh
are both installed on your
machine.
Generate a DSA private-key/public-key pair, thus:
$ ssh-keygen -d
(ssh-keygen
comes with
ssh
.) Running ssh-keygen
-d
creates the private and public keys in
$HOME/.ssh/id_dsa
and
$HOME/.ssh/id_dsa.pub
respectively
(assuming you accept the standard defaults).
ssh-keygen -d
will only work if
you have Version 2 ssh
installed; it
will fail harmlessly otherwise. If you only have Version
1 you can instead generate an RSA key pair using plain
$ ssh-keygen
Doing so creates the private and public RSA keys in
$HOME/.ssh/identity
and
$HOME/.ssh/identity.pub
respectively.
[Deprecated.] Incidentally, you can force a Version
2 ssh
to use the Version 1 protocol by
creating $HOME/config
with the
following in it:
BatchMode Yes Host cvs.haskell.org Protocol 1
In both cases, ssh-keygen
will
ask for a passphrase. The
passphrase is a password that protects your private key.
In response to the 'Enter passphrase' question, you can
either:
[Recommended.] Enter a passphrase, which you
will quote each time you use CVS.
ssh-agent
makes this entirely
un-tiresome.
[Deprecated.] Just hit return (i.e. use an empty
passphrase); then you won't need to quote the
passphrase when using CVS. The downside is that
anyone who can see into your .ssh
directory, and thereby get your private key, can mess
up the repository. So you must keep the
.ssh
directory with draconian
no-access permissions.
Windows users: see the notes in Section 13.3, “Configuring SSH” about ssh wrinkles!
Send a message to to the CVS repository
administrator (currently Jeff Lewis
<jeff@galois.com>
), containing:
Your desired user-name.
Your .ssh/id_dsa.pub
(or
.ssh/identity.pub
).
He will set up your account.
Set the following environment variables:
$HOME
: points to your home directory. This is where CVS
will look for its .cvsrc
file.
$CVS_RSH
to ssh
[Windows users.] Setting your CVS_RSH
to
ssh
assumes that your CVS client
understands how to execute shell script
("#!"s,really), which is what
ssh
is. This may not be the case on
Win32 platforms, so in that case set CVS_RSH
to
ssh1
.
$CVSROOT
to
:ext:
your-username
@cvs.haskell.org:/home/cvs/root
where your-username
is your user name on
cvs.haskell.org
.
The CVSROOT
environment variable will
be recorded in the checked-out tree, so you don't need to set
this every time.
$CVSEDITOR
: bin/gnuclient.exe
if you want to use an Emacs buffer for typing in those long commit messages.
$SHELL
: To use bash as the shell in Emacs, you need to
set this to point to bash.exe
.
Put the following in $HOME/.cvsrc
:
checkout -P release -d update -P diff -u
These are the default options for the specified CVS commands, and represent better defaults than the usual ones. (Feel free to change them.)
[Windows users.] Filenames starting with .
were illegal in
the 8.3 DOS filesystem, but that restriction should have
been lifted by now (i.e., you're using VFAT or later filesystems.) If
you're still having problems creating it, don't worry; .cvsrc
is entirely
optional.
[Experts.] Once your account is set up, you can get access from other machines without bothering Jeff, thus:
Generate a public/private key pair on the new machine.
Use ssh to log in to
cvs.haskell.org
, from your old
machine.
Add the public key for the new machine to the file
$HOME/ssh/authorized_keys
on
cvs.haskell.org
.
(authorized_keys2
, I think, for Version
2 protocol.)
Make sure that the new version of
authorized_keys
still has 600 file
permissions.
Make sure you set your CVSROOT
environment variable according to either of the remote
methods above. The Approved Way to check out a source tree
is as follows:
$ cvs checkout fpconfig
At this point you have a new directory called
fptools
which contains the basic stuff
for the fptools suite, including the configuration files and
some other junk.
[Windows users.] The following messages appear to be harmless:
setsockopt IPTOS_LOWDELAY: Invalid argument setsockopt IPTOS_THROUGHPUT: Invalid argument
You can call the fptools directory whatever you like, CVS won't mind:
$ mv fptools directory
NB: after you've read the CVS manual you might be tempted to try
$ cvs checkout -d directory
fpconfig
instead of checking out fpconfig
and then renaming it. But this doesn't work, and will
result in checking out the entire repository instead of just
the fpconfig
bit.
$ cd directory
$ cvs checkout ghc hslibs libraries
The second command here checks out the relevant
modules you want to work on. For a GHC build, for instance,
you need at least the ghc
,
hslibs
and libraries
modules (for a full list of the projects available, see
Section 3, “What projects are there?”).
Remember that if you do not have
happy
and/or Alex
installed, you need to check them out as well.
This is only if you have read-write access to the repository. For anoncvs users, CVS will issue a "read-only repository" error if you try to commit changes.
Build the software, if necessary. Unless you're just working on documentation, you'll probably want to build the software in order to test any changes you make.
Make changes. Preferably small ones first.
Test them. You can see exactly what changes you've
made by using the cvs diff
command:
$ cvs diff
lists all the changes (using the
diff
command) in and below the current
directory. In emacs, C-c C-v =
runs
cvs diff
on the current buffer and shows
you the results.
If you changed something in the
fptools/libraries
subdirectories, also run
make html
to check if the documentation can
be generated successfully, too.
Before checking in a change, you need to update your source tree:
$ cd fptools $ cvs update
This pulls in any changes that other people have made, and merges them with yours. If there are any conflicts, CVS will tell you, and you'll have to resolve them before you can check your changes in. The documentation describes what to do in the event of a conflict.
It's not always necessary to do a full cvs update before checking in a change, since CVS will always tell you if you try to check in a file that someone else has changed. However, you should still update at regular intervals to avoid making changes that don't work in conjuction with changes that someone else made. Keeping an eye on what goes by on the mailing list can help here.
When you're happy that your change isn't going to break anything, check it in. For a one-file change:
$ cvs commit filename
CVS will then pop up an editor for you to enter a "commit message", this is just a short description of what your change does, and will be kept in the history of the file.
If you're using emacs, simply load up the file into a
buffer and type C-x C-q
, and emacs will
prompt for a commit message and then check in the file for
you.
For a multiple-file change, things are a bit trickier. There are several ways to do this, but this is the way I find easiest. First type the commit message into a temporary file. Then either
$ cvs commit -Fcommit-message
file_1
....file_n
or, if nothing else has changed in this part of the source tree,
$ cvs commit -Fcommit-message
directory
where directory
is a common
parent directory for all your changes, and
commit-message
is the name of the
file containing the commit message.
Shortly afterwards, you'll get some mail from the relevant mailing list saying which files changed, and giving the commit message. For a multiple-file change, you should still get only one message.
It can be tempting to cvs update just part of a source
tree to bring in some changes that someone else has made, or
before committing your own changes. This is NOT RECOMMENDED!
Quite often changes in one part of the tree are dependent on
changes in another part of the tree (the
mk/*.mk
files are a good example where
problems crop up quite often). Having an inconsistent tree is a
major cause of headaches.
So, to avoid a lot of hassle, follow this recipe for updating your tree:
$ cd fptools $ cvs update -P 2>&1 | tee log
Look at the log file, and fix any conflicts (denoted by a “C” in the first column). New directories may have appeared in the repository; CVS doesn't check these out by default, so to get new directories you have to explicitly do
$ cvs update -d
in each project subdirectory. Don't do this at the top level, because then all the projects will be checked out.
If you're using multiple build trees, then for every build tree you have pointing at this source tree, you need to update the links in case any new files have appeared:
$ cdbuild-tree
$ lndirsource-tree
Some files might have been removed, so you need to remove the links pointing to these non-existent files:
$ find . -xtype l -exec rm '{}' \;
To be really safe, you should do
$ gmake all
from the top-level, to update the dependencies and build any changed files.
If you want to check out a particular version of GHC, you'll need to know how we tag versions in the repository. The policy (as of 4.04) is:
The tree is branched before every major release. The
branch tag is ghc-x-xx-branch
, where
x-xx
is the version number of the release
with the '.'
replaced by a
'-'
. For example, the 4.04 release lives
on ghc-4-04-branch
.
The release itself is tagged with
ghc-x-xx
(on the branch). eg. 4.06 is
called ghc-4-06
.
We didn't always follow these guidelines, so to see
what tags there are for previous versions, do cvs
log
on a file that's been around for a while (like
fptools/ghc/README
).
So, to check out a fresh GHC 4.06 tree you would do:
$ cvs co -r ghc-4-06 fpconfig $ cd fptools $ cvs co -r ghc-4-06 ghc hslibs
As a general rule: commit changes in small units, preferably addressing one issue or implementing a single feature. Provide a descriptive log message so that the repository records exactly which changes were required to implement a given feature/fix a bug. I've found this very useful in the past for finding out when a particular bug was introduced: you can just wind back the CVS tree until the bug disappears.
Keep the sources at least *buildable* at any given time. No doubt bugs will creep in, but it's quite easy to ensure that any change made at least leaves the tree in a buildable state. We do nightly builds of GHC to keep an eye on what things work/don't work each day and how we're doing in relation to previous verions. This idea is truely wrecked if the compiler won't build in the first place!
To check out extra bits into an already-checked-out tree, use the following procedure. Suppose you have a checked-out fptools tree containing just ghc, and you want to add nofib to it:
$ cd fptools $ cvs checkout nofib
or:
$ cd fptools $ cvs update -d nofib
(the -d flag tells update to create a new directory). If you just want part of the nofib suite, you can do
$ cd fptools $ cvs checkout nofib/spectral
This works because nofib
is a
module in its own right, and spectral is a subdirectory of
the nofib module. The path argument to checkout must always
start with a module name. There's no equivalent form of this
command using update
.