2. Using the CVS repository

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@galconn.com>).

2.1. Getting access to the CVS Repository

2.1.1. Remote Read-only 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.

2.1.2. Remote Read-Write CVS Access

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.

$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.

2.2. Checking Out a Source Tree

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.

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

Remember that if you do not have
happy and/or Alex
installed, you need to check them out as well.

2.3. Committing Changes

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 -F commit-messagefile_1 .... file_n

or, if nothing else has changed in this part of the
source tree,

$ cvs commit -F commit-messagedirectory

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.

2.4. Updating Your Source Tree

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:

$ cd build-tree
$ lndir source-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.

2.5. GHC Tag Policy

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

2.6. General Hints

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.