Displaying Newsletter
Issue 10, 27 Jan 2002


  In This Issue:
 
Getting to know CVS by Daniel Reinhold 
I recently received an email requesting that I write an article about CVS and how to use it with Sourceforge. Hmmm, well...I'd been planning to write something about CVS anyway, but more in the way of a developer's guide for the website. Still, those plans had been sitting idle for many weeks while I worked on other stuff, so maybe a newsletter article wouldn't be such a bad idea after all -- at least it would get me to finally put something down on the subject.

There's lots of information out there about CVS, so I don't intend to write a full treatise on the subject. But I do want to cover the basics of getting it running and using common commands. By no means am I a CVS expert (to put it mildly), but, in a way, that's a good thing as far as this article goes -- it means that I won't bowl you over with technical mumbo jumbo or try to impress you with some deviously subtle tricks. Nope, I just want to explain the major points and, hopefully, get some people up and running on this valuable tool. Maybe even convince you why it's a good idea.

Most of what I've written here comes from a combination of trial and error and reading online CVS docs and tutorials. One of the best, and a good source for alot of what I've learned is Red Bean's CVS Book. Use this doc for a truly thorough explanation of CVS. I would consider it the ultimate reference for any questions you might have. As many points as this article covers, it really only scratches the surface of this large topic.

While writing this piece, I assumed the target audience would be largely BeOS developers who are on or plan to be on a Sourceforge project. Some of the info, however, especially on anonymous CVS, can be used by anyone. The OpenBeOS project and its CVS repository is used as an example for many points (including many of the sample command lines), but most of the info presented here is not specific to any particular project.


Overview

CVS is a program for tracking and controlling the content of a group of related files. Consider that you have a program consisting of several dozen source code files. How would you go about making changes to that code base -- for example, adding a new feature that would require altering multiple files? If you had either brains or bitter experience (or both) on your side, you'd create a new copy of the source code tree and edit that one. Only when the new code appeared to be in good shape would you replace (or merge with) the older code.

CVS is also based on that simple idea. There is one master directory of files that contains the best or most up-to-date version of all files. It is called the repository. From this repository you can checkout individual files or entire directories. Checking out just means making a temporary copy elsewhere so that you can edit safely. No matter what bungled-up-of-a-mess you make of the working copy, the repository remains unharmed. Whenever the new versions are in good shape and working correctly, you can check them into the repository -- which just copies back the updated versions.


 Repository                               Working Copy
+--------------+   ===> Checkout ===>   +--------------+
| /FooDir      |                        | /FooDir      |
|    /SubDir1  |                        |    /SubDir1  |
|    /SubDir2  |                        |    /SubDir2  |  (Edit Here)
|    /SubDir3  |                        |    /SubDir3  | 
|     . . .    |                        |     . . .    | 
+--------------+   <=== Checkin <===    +--------------+

The initial working copy is almost a clone of the directory from the repository. The difference is that the repository stores version info inside the files themselves. The file names are altered as well, to reflect this. For example, when file.c is imported into the repository, it becomes file.c,v and contains embedded version info at the top and bottom of the file. But when you checkout the file, it becomes the regular file.c again inside the working copy, without the embedded info.

Naturally, you can have many different working copies checked out from the same repository. This is usually done for the purpose of working independently on different features. It may be one programmer working on several branches, or multiple programmers each working on their own copy, or a mix of the above.

Repository
    |
    +==> CopyA (working on feature A)
    |
    +==> CopyB (working on feature B)
    |
    +==> CopyC (working on feature C)
    |
    v

You can use CVS to manage your own programming projects locally on your machine -- i.e. the repository and the working copy are just different directories on your computer. There are many advantages to this, some of which I'll discuss later in this article. But the real power of CVS comes from using it in a collaborative way with others across a network. For this, you will also need a program called SSH. Sourceforge requires SSH in order to checkin files to the repository on the server. SSH handles the login to the server and then encrypts/decrypts the data sent along the network for security.


Preliminaries

First, you will need to get BeOS versions of CVS and SSH. There are several of these available. I don't want to list all the URLs for these here as the info may quickly become outdated -- refer to the 'Resources' section of the website for the latest on this. However, in the interest of disclosure, I'll tell you which versions of these programs that I am using:

CVS:
http://www.planetmirror.com/pub/beos/experimental/tools/cvs-1.10.7-x86.zip
(Version 1.10.7 from Be)

SSH:
http://www.bebits.com/app/2378
(Andreas Bobaks port of ssh-1.2.26 )

Mind you, I'm not saying that you have to use these versions or that they're better than the others ones available. These are simply the ones that I've used and so I know that they work just fine.

Once you have installed these programs, be sure and copy the binaries 'cvs' and 'ssh' (or at least a link to them) to your /boot/home/config/bin directory. This is to make your life easier -- you don't want to spell out the full path to these programs every time you type a command.

Next, you'll need to register with Sourceforge. That is, you'll need to setup a username/password. Once you've done this, you can join any number of Sourceforge projects. If you don't already have a user account with Sourceforge, go to their home page and click on the 'Register' link. It's simple and takes just a few minutes.

Now you will need to get added to a project. This is handled by the project admin(s). For OpenBeOS, this is Michael Phipps. New members to OpenBeOS will need to contact Michael and have him add their username to Sourceforge's internal list of members for the project. Once this is done, you'll have CVS write access and will be able to checkin source code to the OpenBeOS repository.

There is one final step, however, before you can start using SSH with CVS. You must login once to the Sourceforge CVS server. Use the following command:
ssh username@cvs.open-beos.sf.net

Of course, put your Sourceforge username in the command. The first time you attempt to ssh into a new server, you'll receive this prompt:

Host key not found from the list of known hosts.
Are you sure you want to continue connecting (yes/no)?
Type in "yes" and press ENTER. SSH will store "cvs.open-beos.sf.net" as one of the known hosts in the file /boot/home/.ssh/known_hosts.

Then you'll be prompted for your password. Enter that and you'll be logged onto the CVS server, receive an error message (about not having access rights to the files), and then logged off. Don't worry about the error message -- it's simply stating that you can't alter the files in the repository directly via a shell. That's fine, because you'll only be making changes to the repository via CVS. The point of this is that the very act of trying to log in causes Sourceforge to create a /users/username entry for you on the server. This will allow you to perform CVS checkins later (that is, provided you have been added to the project member list).


Anonymous CVS

Probably the first thing you would like to do is checkout some code. You'll need to specify the directory that you want to fetch. Let's say that you want to checkout the game kit from the OpenBeOS repository. It is located in a folder called 'game_kit', so you should be able to run the following command:
cvs checkout game_kit

Notice that I said "should be able". You can make the command above work, but not until you've taken care of some details regarding the repository path. In order to checkout from a repository, CVS needs to know where the repository is. You specify that with the "-d" option. For example:
cvs -d /boot/home/repos checkout my_file

This would work if you happen to have a repository on your local /boot/home/repos directory. But for grabbing the files from the Sourceforge CVS server, you need to specify its network name. This takes the form of:
:access-method:username@cvs.project.sf.net:/cvsroot/project

There are several network access methods available for CVS. The two most common are 'pserver' and 'ext'. Pserver stands for "password authentication server". This program is already resident on the CVS server, so you don't need to obtain it. The trouble with pserver is that is uses a relatively unsafe method of storing passwords on the server, so it is not recommended for anything but anonymous logins. But for that purpose, it's very useful. That is, anyone, with a CVS client can login anonymously to any Sourceforge project repository using pserver and checkout the source code.

One curiosity about pserver is that you must login first. No other network access method requires this. If you are logging on as an anonymous user, you don't need to enter any password -- just hit ENTER at the password prompt. Here are the commands for checking out the game kit from the OpenBeOS repository:
cvs -d :pserver:anonymous@cvs.open-beos.sf.net:/cvsroot/open-beos login
cvs -d :pserver:anonymous@cvs.open-beos.sf.net:/cvsroot/open-beos checkout game_kit

Eek! That's alot of text to type in. Fortunately you can save yourself some work. You can specify the location of the CVS repository using the CVSROOT environment variable. When you open a new Terminal window, type in the following command:
export CVSROOT=:pserver:anonymous@cvs.open-beos.sf.net:/cvsroot/open-beos

Now you can use the simple 'cvs checkout game_kit' command from above. You can get simpler still -- you can use "co" instead of "checkout". Just specify a different directory name to checkout something else. If you want to checkout the entire repository, just use "." for the path. Here's a simple shell script that I use to checkout the entire repository and store it in a local directory called "cvsall" in my /boot/home folder:

#!/bin/sh
# check out the entire CVS repository for OpenBeOS
export CVSROOT=:pserver:anonymous@cvs.open-beos.sf.net:/cvsroot/open-beos
cvs login
cd ~/cvsall
cvs co .
cvs logout


SSH

Anonymous CVS is fine if you just want to checkout files. But to checkin files as well, you'll need SSH. SSH stands for secure shell. This is because it is most commonly used as a remote shell client, similar to telnet, but with better security. But it can also be used by CVS to handle secure communications with a server. Sourceforge requires SSH in order to checkin files to their CVS server, so it's a necessity.

SSH logs into the server, delivers the password (after prompting you for it), does some handshaking for setting up the encryption method, then sends/receives the CVS commands across the network in encrypted format. There are a number of encryption techniques that any SSH client will have available. The default one is triple DES (3DES) -- i.e. every SSH client is required to support 3DES as a fallback in case no other encryption technique is available. Sourceforge's CVS server uses 3DES, so this should not be an issue.

Whenever you use SSH to access the CVS server, you need to use the 'ext' access method. Ext stands for "external program". In this case, the external program is SSH. To let CVS know it should use SSH for the remote shell, set the CVS_RSH environment variable. While you're at it, set the CVSROOT environment variable as well, but, unlike the sample shell script above, remove the ":pserver:" at the front. You could replace it with ":ext:" -- however, the 'ext' access method is the default method for CVS, so if you don't specify one, 'ext' will be used anyway. Here are the commands for setting the environment:

export CVS_RSH=ssh
export CVSROOT=username@cvs.open-beos.sf.net:/cvsroot/open-beos

Of course, put in your own username in the text above. Typing in these two lines every time you open a Terminal window is not going to be alot of fun, so save yourself the effort. Put these into your ".profile" file. If you don't already have a file called /boot/home/.profile then create it. It is simply a text file. Add the commands above, and you are set.

There are a couple of annoyances in using SSH with CVS that you should be aware of. First, you need to use the "-z3" command option for accessing remote servers. This is a compression flag that is used for transmitting the data across a network. I'm not sure that other compression settings such as "-z4" or "-z5" won't work as well, but "-z3" is the one recommended by Sourceforge, so that's what I use. For example:
cvs -z3 co app_kit

If you don't use this flag, the command will still get executed, but SSH never returns control to the CVS program, and thus you don't ever get back to a command prompt. You have to kill the process (Control-C) to continue. So you definitely want to use it. But typing in "-z3" before every CVS command gets tiresome very quickly. So it's ".profile" to the rescue again. Add the following line to /boot/home/.profile and you're saved from all that icky typing:
alias cvs="cvs -z3"

The other annoyance, though a minor one, is that SSH uses a pty (pseudo-terminal) for communicating with CVS. This in itself is no big deal, but it creates a somewhat irritating side-effect. When you resize the Terminal window while doing remote CVS, a 'resize window' command is sent to SSH which then gets confused (probably mistakes it for bogus encrypted data) and loses the connection to the server. I'm bad about this because I tend to 'futz' around, resizing windows while waiting for the transfer to finish. The lesson here is, resize the window *between* executing CVS commands.


The CVS Development Cycle

Now that you have CVS and SSH, initialized these programs, created your Sourceforge account, secured CVS write access, and set your local .profile, you are finally ready to start using CVS for real work. After all the preliminary stuff from above, it's pretty simple from here on out.

The basic pattern of using CVS is this: checkout, edit, checkin.

This is the development cycle you will use over and over while working on a project. You checkout the files/folders relating to the work that you are assigned to. You then edit local copies on your computer. Whenever you've got a good working new version, you checkin the source code to the CVS repository.

CVS will keep track of what changes were made and when. It will allow you to back up to a previous version if you find out you didn't like the changes after all. All of your new work is marked with version info and tagged with comments (by you) explaining the changes.

We've already covered checking out files. So how do you check them back in? You use the "commit" command if the file already exists in the repository. If it's a new file, first "add" the file, then "commit" it. For example:

cvs add my_new_file
cvs commit -m "initial checkin" my_new_file
How does CVS know where to put the file? Because it knows the directory structure of the folder you checked out. Consider the diagram at the top of this article. The working copy you checkout is a clone (minus the embedded tracking info) of the directory tree from the repository. If you create several new files, or even a new directory with files, the "add" command will copy the structure from your working copy back to the repository to make it match your local setup.

I already mentioned that you can use "co" as an abbreviation for "checkout" command. Well, you can also use "ci" as the short form for "commit". This is fairly clean and symmetrical -- "co" to checkout, "ci" to checkin. So the CVS development cycle will basically be:

cvs co your_assignment
(... edit/test/debug like a madman ...)
cvs ci -m "added feature X" your_assignment
Whenever you checkin files, you must make some kind of comment about the change. You could just put in "blah, blah, blah", but don't do that. It is truly a useful feature to have additions/fixes/updates marked with meaningful explanations. If the file is new, the phrase "initial checkin" is somewhat standard (saves you from having to think up something every time). But for updated files, type in something descriptive and useful.


Quick-n-Dirty Vi

The "-m" option precedes the comment text for any commits. If you forget to use this option (or don't want to), you will be automatically thrown into a vi session. Vi is a prehistoric Unix text editor dating from the early Jurassic period (hehe, couldn't resist). I'm sure there are fans of vi out there... but I'm not one of them. However, you don't need to know much in order to enter a few lines of text and then exit. So here is my *very* brief summary of using vi to edit text:

Vi operates in two modes: command, and insert. Insert mode is where you type in the text normally. Command mode will interpret keystrokes as commands. When you first enter vi, you will be in command mode. To get to insert mode, type 'a'. Now you can type in your comments and edit your little heart out. When you're through, hit the ESC key to go back to command mode. Now type 'ZZ' (i.e. hold down the shift key and type 'Z' twice)... this will save your work and exit. That's not too bad.

Here's the world's smallest vi primer again, in summary:

Enter Vi Session:
=======================================
a     ==> change to insert mode
...edit away until finished...
ESC   ==> change back to command mode
ZZ    ==> save work and exit
=======================================

Btw, you can specify a different editor for putting in comments. Just use the "-e" option and specify the editor path. This may or may not be worth it. For me, using the few simple keystrokes above to edit with vi is sufficient to get my comments down. You're not writing a novel, after all.


Other Commands

If you type in:
cvs --help-commands

You will see all the available commands you can use in CVS.

Type in:
cvs --help-synonyms

This will show you all the shortened, abbreviated forms you can use for those commands.

Also, particularly useful is:
cvs -H command

This will show you all the options that can be used with that particular command.

By far the most common commands you are likely to use are "co" and "ci", since checking out and checking in files is the main activity. But a few others are useful.

The "update" command updates your working copy to the latest version from the repository. But then again, this is what "co" does anyway: if there is no working copy, one is created, otherwise that copy is updated. In other words, the "checkout" command does everything the "update" command does plus it handles creating new working copies. For this reason, I never use "update" -- "co" handles all your updating needs.

The "diff" command will let you see the difference between your local file in the working copy and the original in the repository. As such, it will show what changes you have made to files since the last checkout.

The "log" command is very useful. It will show you every checkin made to the repository for the directory which you have checked out: who made it, on what date, the revision number, the checkin comments. It's a complete history of activity for the source tree.

The "import" command is used to put files into a new repository. It can also be used to create a new branch of an existing repository. You can always use "add" to add files, but "import" handles large numbers of new files more systematically.

The "remove" command, naturally, is used to remove files. What if you want to remove an entire directory? Well, you can do so for your working copy, but not for the repository itself. More on this later.

There are other commands, some covering more esoteric functions and some relating to admin tasks. I won't cover these in this article.


Handling conflicts

When you first checkout a file from the repository, it is an exact copy of the original (well, excepting, of course, the embedded version info). But as you edit the file, making changes, your working copy and the repository are no longer in synch. If you try to checkout the file again, you'll get a merge conflict.

Here's a simple test: checkout one of the OpenBeOS kits. Then load one of the files into your editor and make a minor change and save. Now checkout this same kit again. You'll notice that, for the edited file, instead of the usual 'U' at the beginning of the status line, there is an 'M' instead. This lets you know there is a merge conflict between the version of the file on your working copy and the repository. This conflict will remain until you checkin the new version of your file (or revert to the previous one locally).

If you run "diff" on the file in question, you can see your changes. For example:
cvs diff edited_file

This will display all the lines in the file that you changed.

This is how CVS works. It doesn't fix problems for you. It merely keeps very accurate records on what you (and others) have done and reports any conflicts it finds. It's not an artificial intelligence agent that attempts to work out remedies for you. It's just a flawless bookkeeper, or better yet, a tireless secretary, constantly taking notes and letting you know when there's a problem. But it's up to you to decide how to handle the conflict. You are in charge.

If several developers are working on the same source tree of the project and checkin different versions of the same file, CVS does not try to "fix" the problem itself or attempt to decide which is better. It merely combines the two versions. The next time either of the developers checks out the file again, they will get the merge conflict. By running the "diff" command as above, they can both see where they have deviated from each other. They can then contact each other and hash out what changes should be made, whose version is best, etc.


Removing files and directories

The question always comes up shortly after someone starts working with CVS, "how do I get rid of files?" Well, it's easy enough, in a way, using the "remove" (or "rm") command. For example:
cvs rm some_file

This will remove 'some_file' from the repository. As always, the location of the file is based on its relative location within the working copy -- e.g. if you're working on the /src/lib/foo subdirectory of the working copy, then it will remove /src/lib/foo/some_file from the repository source tree.

Did I say that it will remove the file from the repository? Well, that's almost true. Actually, the file is moved into an "attic". This is like a trash bin directory. When browsing the CVS repository, you'll notice that deleted files are actually still there, but tucked away in an Attic/ subdirectory. At least that makes sense because it makes it possible to recover the files later. Besides, the next time you do a checkout, a deleted file sitting in the attic is not copied over. So for all appearances, the file is really gone.

But it's not so clean for directories. CVS stores tracking/version info for files, but not for directories. It's true that it knows about and understands the directory structure where the files reside, but there is no actual version info for directories themselves. The effect of this is that you can't remove directories from the repository using just CVS commands. You can remove them from your working copy. That's as close as you can get.

To remove a directory from your working copy, you must delete all the files in it. You don't have to do this manually, because there is a "-f" option that will delete the contained files for you before removing the directory. Combine this with the "-R" option for recursing thru subdirectories and you can swat an entire directory with one command:
cvs rm -fR some_dir

All the files within 'some_dir' and every subdirectory below it will be removed (i.e. put in the attic), but the directories and subdirectories below are all still there. They're empty but still there.

You can use the "-P" option when checking out: this will prune empty directories -- i.e. not put them into the working copy. Thus 'some_dir' will not appear in a checked out working copy. But it's still really there in the repository. This means anyone else who checks out a copy will still see 'some_dir' unless they also use "-P" when checking out. And even if everyone always uses the prune option when doing checkouts, you can still see the directories when using the online CVS browser that Sourceforge provides. It really is quite annoying.

Mind you, it's not impossible to get rid of directories. You just can't do it using CVS commands. If you really wanted to kill a directory very badly, you could ask the project admin to handle this for you. For example, an OpenBeOS developer could email Michael Phipps and ask him to please axe directory_foo. Michael can't remove the directory himself -- he doesn't have any more access to the server files than anyone else. But as project admin, he could send an email to Sourceforge tech support and say "excuse me, could you please kill 'directory_foo' in the OpenBeOS CVS repository". This isn't something that the CVS maintainers at Sourceforge want to get alot of requests for, and Michael does not really want to make the request either. So don't expect him to cover for you.

The moral here is: be very careful before adding any subdirectories to the CVS repository. CVS commands make it easy to create new directories, but practically impossible to get rid of them once created. Think about your directory structure carefully and make sure it will expand with usage and time. And don't be surprised if, nevertheless, you get stuck with empty, 'dead' directories somewhere down the line.


Testing with a local repository

Ok, we've covered alot of the basic ground so far. You know enough to start using CVS and getting into the CVS development cycle. However, perhaps you're still a bit concerned about messing with the "real" repository at Sourceforge while trying to get familiar with how CVS works. Well, in that case, you should create a local repository.

If you have a CVS program, you can create your own CVS repository just a surely as Sourceforge does for other projects. And since you don't have to make the files available on a server, it's very easy to administer... it's just local files on your computer. You won't even have to worry about the problem of removing directories, because you own all the files and can prune the repository to your heart's content. It's a pretty easy and safe way to become familiar with CVS. You'll be able to see all the changes from both sides of the fence: repository and working copy. Try it, you'll like it!

Ok, before you start, decide where you would like to put the repository. As an example, let's assume you decide to put it in /boot/home/test/repos. Now open a Terminal window and type in the following:

export CVSROOT=/boot/home/test/repos
cd ~
mkdir test
cd test
mkdir repos
cvs init
There, you now have your very own spanking new repository. Of course, it doesn't have much yet... just the CVSROOT folder with stub versions of the basic admin files. All you need now is to import some files.

You could import files from any directory on your computer. But I don't know what you have on your computer. Since we've played around with sample command lines for checking out the OpenBeOS game kit, let's assume that this has been done. And assume that this has been checked out into the home directory, i.e. you have a /boot/home/game_kit folder. This gives you a code base to work with and play around. So enter the following into the Terminal window:

cd ~/game_kit
cvs import -m "initial checkin" game_stuff mybranch game_stuff_1_0
This assumes that you're in the same Terminal window as above and thus the CVSROOT environment variable still points to /boot/home/test/repos. If not, retype the export command or use the "-d" option to set the repository path in the command above.

The last three parameters (after the comment text) of the import command are not obvious. First is the name of the folder in the repository where the imported files will be stored. The next is a tag designating this particular branch of the source tree. Since this is just a test repository, you could name it just about anything. The last param is a release version tag. To be honest, I'm not really sure what its purpose is. I think it's meant to be a symbolic tag containing something about the release version that this branch designates. Again, since this is only a test repository, you can use about anything. Just don't use the '.' character in tag names.

There, now you have a repository full of source code. You can continue to add/import more files if you like. You can checkout/checkin files to/from working copies located elsewhere on your computer. In nearly all respects, you can treat it the same as you would the remote repository at Sourceforge. Only this one is totally in your control.

If you want to test with this repository over a period of time, it may be useful to add another alias in your ".profile" to avoid constantly specifying the repository location. You could use:
alias tcvs="cvs -d ~/test/repos"

This uses a slightly different command name, tcvs, to let you know you are working with your local test repository. Here's a recap of all the commands so far that I've recommended for your ".profile":

export CVS_RSH=ssh
export CVSROOT=username@cvs.open-beos.sf.net:/cvsroot/open-beos
alias tcvs="cvs -d ~/test/repos"
alias cvs="cvs -z3"
The 'tcvs' alias is placed before the 'cvs' alias so that the aliased version isn't substituted first. This would cause the tcvs command to use the "-z3" flag as well, which isn't needed for local file copying. Probably wouldn't hurt though.

With a local test repository in place, you can truly have fun and try every command with reckless abandon. You can clearly see what effects each command actually produces. Once you've become familiar with how CVS operates, doing the "real" updates on the Sourceforge repository will be a piece of cake.


Getting into the CVS habit

Before I finish this article, I'd like to make some final comments...

You may be surprised to hear this, but using CVS to regularly checkin code is good for you. It belongs right up there with exercising, brushing your teeth, and eating green leafy vegetables.

But why is this? What's so great about CVS? Well, it's not so much CVS itself as any good source control system, but we're talking about CVS in this article. The point is, using CVS causes you to be a better administrator of your code.

Programmers know that they should routinely do certain things such as: make regular backups, comment all changes, develop and test incrementally, plan carefully for future directions, separate new experimental code from proven tested code, document and communicate the progress to others, etc.

These practices are the lore of many seasoned programmers and have been written about extensively. Most programmers know that they should do these things, because it will make them more professional, more reliable, possibly even speedier in their craft. But knowing you should do this and actually doing it are two different things (just like exercising, brushing your teeth, and eating green leafy vegetables).

But using CVS will force you to attend to many of these items. By continually checking in code, you don't have to worry such much about backups, because the repository will store previous versions. When you checkin the code, you are forced to comment the changes. The cycle of checkout/edit/checkin encourages you to develop in an incremental style where you tackle problems in little bites. Because you share the repository with others who are working on similar tasks, you must think more carefully about your design and how it meets future needs. The very process of checking out code helps separate the development of new code from the existing, solid base. And all the features just listed combined with the open availabililty of the repository makes documentation and communication of the progress almost a built-in side effect of using source control.

I think that some (many?) programmers on the OpenBeOS project have been timid about using CVS because they have the idea that only finished, polished, ready-to-distribute source code should be checked in. This means that they will spend alot of time slaving away in secret on their local computer without any of the benefits just mentioned. Then, finally, after much time has passed, when they judge the code ready for public inspection, they will checkin to the repository. Unfortunately, this is as wrong as you can get. If you only use the repository as a final resting place for source code, then CVS itself has been rendered totally useless.

You see, the whole point of source control is to assist you in the process of developing quality code. Think about it: no one sits down and types out the final version of their source code files on their first attempt. Hardly. Software construction is an iterative process: you create an initial version, test it, make fixes, and test again. Then you add more features and repeat the process over. Source control was created precisely to help assist in this very cycle; to help automate the drudgery tasks while keeping the code well managed. If you don't use CVS and the project repository for developing the code, you are missing out on precisely the benefits it was designed to produce.

Even if a programmer is working on a really experimental, off-the-beaten path prototype, he can still use CVS to assist with the development. Experimental or prototype subdirectories can be created in the repository for storing and working on this type of code. As it matures, it can be moved to more stable sections of the repository. The nature of the work should not hinder using CVS. It can be useful for any software development because the process is always the same, regardless of the content or purpose of the source code.

So don't lightly dismiss the idea of using CVS to assist with program development. Don't be afraid to regularly checkin files to the repository. The process will become fairly painless, even second nature after awhile. Then you can reap the benefits of doing things the smart way.

 
GUI Building by remote control by Michael Phipps 
Towards the beginning of OBOS, there was a raging debate on binary compatibility. Some people argued that it was too tough to do. Others argued that without it, we would have no applications. I decided to investigate the possibility before answering that question. So I chose the smallest kit that I could find (ScreenSaver) and started to implement it. After about a week, I had the server and the input_server add-on working (not complete, but close). So I thought that I would take a day or two and throw together the preferences app. Truly, the epitome of hubris.

Three weeks later, the Screen Saver preferences app was not yet complete. It was close, and almost looked like it would work. But not complete, after three weeks. Part of the problem was my lack of experience - most of my BeOS coding had been shell and/or file IO based. I had thrown together a couple of GUI apps, but nothing big. There has to be a better way.

One of the things that fascinates me about X Windows is the layout system and the resources. For the uninitiated, in X Windows, you can have a resource file that can define how widgets (UI objects) relate to each other. If you change the resource file (which is pretty easy to understand and manage), you change as much or as little about the GUI as the developer allowed when writing the app. In other words, if the author of the code didn't specify the background color, you can do so. You can rearrange widgets and more.

So I thought that this would be a good opportunity to kick off a series of articles combining several of my favorite topics: programming languages, client-server programming, extreme programming and coding. Caveat: this is not quite an extreme programming (XP) project. XP requires pair programming. Since I don't have any BeOS devs nearby, well, I am improvising. I am also the "customer", from an XP standard, so I am dispensing with the notecards.

XP very simply (for this project) means that you write your test case, then your code. Code the minimal amount you need to for this iteration, until your test cases pass. Make the tests repeatable.

OK, so what is this all about? I thought that I would write a program and/or library that parses a simple language and produces a functioning GUI. Writing a programming language? Isn't that hard? Yes, in a way. But this is a little different case. We are not compiling to machine language, but to BeOS API calls. We are not optimizing, and we are providing little in the way of error handling (for now).

Processing a programming language is, in this case, simply breaking an IO stream into "words" and passing them into a "machine" that expects words to occur in a certain order. I am using Lex and Yacc as the "lexer" (to break the IO into words) and the "parser" (the machine). While this is not meant as a Lex and Yacc tutorial, here are the relevant parts of the code:

language.l (the lexer):
\n {return EOS;}
[\t ]+          {;}
new             {return NEW;}
=               {return EQUALS;}
window  {return WINDOW;}
label  {return LABEL;}
end  {return END;}
[a-zA-Z0-9]+ {return NAME;}  

Basically, when the IO stream contains the "thing" on the left, it executes the thing on the right.

language.y (the parser):
commands: | commands command
command: EOS | NAME EQUALS NEW WINDOW EOS options end
options: | options option
option: EOS | LABEL NAME EOS
end: END    

When the return values from the lexer add up to the item after the colon, the condition on the left is satisfied. "commands" consist of either nothing or a "commands" and a command. An empty file is acceptable. A file with one command processes to this:

commands
which becomes
commands command
which becomes
<nothing> command 

In this particular case, a command looks like this example:

newName = new window
end

or maybe

newName = new window
label MyWindow
end

These types of test cases were coded first. Then the lexer and parser were written. After some work, they successfully parsed these test cases. I then added a BApplication and some code to display the windows.

Next time, we will add more commands and some parameters for BWindow to make this a bit more useful.

 
On the need for apps by Michael Phipps 
One of the greatest things about software is also one of the worst. Nearly anything can be done in software. When one sits down in front of a blank VIM screen (what else would you use), what you can build is limited only by your imagination. MP3 player? Great game? Desktop publisher? Operating system? All constrained, for all practical purposes, only by your time.

That is the great part. Unlimited freedom. Software Development, especially open source software, is very egalitarian. The computer doesn't care about race, creed or financial status. The downside is that, since anything *can* be created, there is a tendency among software developers to wander the map. If you could look at my development directory, you would see several started projects that never finished. And some projects with more than 1 (or 2 or 3) code bases, as new ideas were tried and discarded. Often times, developers get discouraged. I have, at times. Sometimes the task is too monumental. Or the drain on personal or family time is too great. But, I think, more often than not, people get bored. Once the "engine" is done, they lose interest. So what if the UI isn't all that it should be. So what if it leaks memory. It works. I solved the problem and I can use the code.

BeOS certainly faced an issue with this. An exercise for the reader - go to BeBits. Count the number of applications that have a final release number less than 1.0. Or, maybe, that *should* have a final release number less than 1.0. There are a good number. Another example - the classic first Be app (besides Hello World) is an IRC client. For a while, on BeDevTalk, it seemed like every other week, someone was writing a new IRC client. Why? Because most of the ones that exist are incomplete or broken.

One of the reasons that OBOS is making progress is that we encourage each other. The progress of one is, really, the progress of all. People who have seen the state of the printing kit or what I checked in for screen saver have become excited. People who know how much work is going on in the kernel (Travis is the MAN!) are excited. And I am excited. I can hardly wait to finish my 8 hours of paying work so that I can come home and put in another 8 on OBOS. Because it is exciting!

I wonder if, maybe, the Be affair wouldn't have turned out differently if the community had swarmed BeUnited with a ton of team work and finished apps. But that is neither here nor there. It didn't happen. But it needs to.

Let's fast forward into the future - I am beaming, holding the first official OBOS CD in my hands. What software will be on there, other than some servers and .so files? What *apps* can we deliver, to make this more than just a pretty platform to play FreeCell on (oh - wait - that is an app, too)?

The OBOS team is maxed out. We are doing all we can do. We have no desire to manage a dozen app building groups. But we need them. There is the ubiquitous web browser question. There are a dozen other, more mundane apps. Many of which exist, either in part or in whole, but could use an update. And there are some that are not started. One example - I would *love* to have a clone of Deluxe Paint IV from my Amiga days. Not into paint programs? How about a game? Take over Eugena's unofficial "job" of "porting" SDL games. Or maybe some other need that I don't even see. There are tons of apps that *can* be written. In fact, virtually an infinite number. I know that not everyone is an OS developer. Most of us were not, before we started this. But we don't need just an OS, so we don't need just OS developers.

OBOS started a Creative Design team, recently, for those who have an interest in the arts. They will be designing all sorts of good multimedia stuff for us. BU needs tons of help. GOOD help. Not "Oh, I want to help" and then disappearing. But dedicated, fired up people who will do what it takes to get BeOS successfull. Not all technical, not all artistic. There are many jobs (both in OBOS and BU and other places) that need just plain bodies willing and able to do some grunt work.

BeOS stands at something of a crossroads. We are on our way to a first release. Not close, but definitely along the path. The question is, when we get to our (initial) destination, what will we find there?