Introduction

Most of my development projects are Visual Studio .NET projects that are stored in CVS repositories running on a Linux machine. Additionally, we use a third party bug tracking software that runs on Windows 2000 to track bug fixes/customer problems, etc. For auditing reasons, I needed to develop a program that would tie together the history of files changed in the CVS repository between different version tags with problem tracking records in the bug tracking system. To do this, I needed an easy way to access the history data in the CVS repository. In doing so, I created a simple and extensible class for accessing the CVS repository directly from a C# class.

I am not going to cover the part about accessing the bug tracking software. That software stores its information in an ODBC compliant database. That portion of the problem was neither unique nor interesting.

Accessing the CVS Repository: Setup

I do not want to go into great details on how to set up CVS. Suffice it to say that we use WinCVS on the Windows Client machines with SSH server authentication. By using this combination, not only can we access the CVS repository through WinCVS, but we can also access it from the command prompt.

The code

To start, I created a central class called CVSCommand. That class executes an arbitrary CVS command via a command line process. Additionally, it starts a secondary thread that monitors the console output of the CVS command and places it into a buffer for processing. Though you can issue CVS commands directly by using this class, I derived specific CVS command classes from CVSCommand.

To execute a command, the CVSCommand or derived class must know a few things. It must know the CVS Root, the RSH (remote shell) command, and the Working Directory for the command execution. There are property variables created to store this information. For example, to execute an arbitrary command using the CVSCommand class:

Using the CVSGetFileHistory Class

Though you can issue any CVS command using the CVSCommand class, the parsing of the response is still required. For my application, I created a simple derived class called CVSGetFileHistory. That command uses all the built in functionality of the base class to execute the CVS command, but adds special parsing code to parse the CVS response in a familiar and easy to use format. Additionally, the constructor allows you to specify the file you want the history of. For example, the above code can be changed to use the CVSGetFileHistory class as follows:

A Closer Look at CVSCommand

The CVS Command is a rather simple class. As previously stated, its main function is to execute an arbitrary CVS command via a command line process. To do so, it uses the System.Diagnostics.Process class. However, it must also ensure that certain environment variables used by CVS are defined. After it starts the process, it also starts a background thread that monitors the console output of the process and appends it to a buffer. The method Start() is where all of this is handled:

Once the command is started, the Running property can be checked to see if the command is still executing or the WaitDone() method can be called to wait until the process is completed.

The background monitoring thread is rather simple. The code simply reads the StandardOutput property of the process and appends the results to the buffer. Furthermore, it monitors the Running property of the class to determine when it can stop execution.

Deriving a new Class

Deriving a new class is not difficult. All you really need to do is provide a constructor that accepts the proper information for the command and parsing functions to parse the command response. For example, the CVSGetFileHistory constructor looks like this:

public CVSGetFileHistory(string file) : base("log "+file)
{
}

It also has several properties that act as parsing functions for the Output of the CVSCommand class. For example, when a cvs log function is executed on the command line, this is output to the console:

To make this more useable from a programming perspective, the derived class needs to parse this information and present it in a way that can be easily used. For example, CVSGetFileHistory parses all the revision text listed above and places it into a container class called CVSHistoryItemList which is exposed as the History property variable. In doing so, the following can be easily done:

Additional Notes

In closing, this basic class does what I needed it to do, no more and no less. Additional error trapping certainly could be added with not too much difficulty. Additional commands could also be implemented, as well.

History

November 22, 2004 - Initial posting.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

Share

About the Author

I have been developing software professionaly since 1991 writing software in automation and manufacturing environments. For 14 years I worked for companies that built custom robotic automated equipment for the semiconductor, telecommunications, and other industies. Presently, I work for a company that manufacturers industrial robots where I write high level coordination and control software.

My undergraduate degrees are in Mathematics and Philosopy. My graduate degree is in Management Information Systems. I am MCSD certified in Visual C++ 6.0 and MCSD.NET certified in C#. I am also have the PMI-ACP certification.