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

2.1. Getting access to the CVS Repository

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

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.

To get read-only access to the repository:

  1. Make sure that cvs is installed on your machine.

  2. Set your $CVSROOT environment variable to :pserver:[email protected]:/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
  3. 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.

  4. Now go to Section 2.2, “Checking Out a Source Tree”.

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.

  1. Make sure that cvs and ssh are both installed on your machine.

  2. 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!

  3. Send a message to to the CVS repository administrator (currently Jeff Lewis ), containing:

    • Your desired user-name.

    • Your .ssh/id_dsa.pub (or .ssh/identity.pub).

    He will set up your account.

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

  5. 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:

  1. Generate a public/private key pair on the new machine.

  2. Use ssh to log in to cvs.haskell.org, from your old machine.

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

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

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

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-message file_1 .... file_n

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

    $ cvs commit -F commit-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.

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

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

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.