Click here to Skip to main content
Click here to Skip to main content

Accessing CVS Repository with C#

, 24 Nov 2004
Rate this:
Please Sign up or sign in to vote.
An article on accessing a CVS repositry using C#.

Sample Image

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:

// Generic CVS command
CVSCommand cmd = new CVSCommand("log MainForm.cs");

cmd.CvsRoot = "username@myserver.com:/home/cvs";
cmd.CvsRsh = "c:/Program Files/GNU/SSHCVS/ssh.exe"
cmd.WorkingDirectory = @"c:\cvs repository\application 1\";

// Execute the command
cmd.Start();
cmd.WaitDone();

// Output the command response
Console.WriteLine(cmd.Output);

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:

// CVS History File command
CVSGetFileHistory cmd = new CVSGetFileHistory("MainForm.cs");

cmd.CvsRoot = "username@myserver.com:/home/cvs";
cmd.CvsRsh = "c:/Program Files/GNU/SSHCVS/ssh.exe"
cmd.WorkingDirectory = @"c:\cvs repository\application 1\";

// Execute the command
cmd.Start();
cmd.WaitDone();

// Print out the results
foreach (CVSHistoryItem hi in cmd.History)
{
    Console.WriteLine("File: {0}", hi.File);
    Console.WriteLine("Revision: {0}",hi.Revision);
    Console.WriteLine("Date: {0}", hi.Date);
    Console.WriteLine("Author: {0}", hi.Author);
    Console.WriteLine("Description: {0}", hi.Description);
}

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:

public void Start()
{

    // Do not allow if already running
    if (this.Running == true)
        return;

    ProcessStartInfo i = new ProcessStartInfo("cvs", command);
    i.UseShellExecute = false;
    if (this.CvsRoot.Length != 0)
        i.EnvironmentVariables.Add("CVSROOT", this.CvsRoot);
    if (this.CvsRsh.Length != 0)
        i.EnvironmentVariables.Add("CVS_RSH", this.CvsRsh);
    if (this.WorkingDirectory.Length != 0)
        i.WorkingDirectory = this.WorkingDirectory;
    i.RedirectStandardOutput = true;
    i.CreateNoWindow = true;
    p = Process.Start(i);

    monitor = new Thread(new System.Threading.ThreadStart(MonitorMain));
    monitor.Start();

}

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:

C:\MCS\APPLIC~1\NM90>cvs log AssemblyInfo.cs

RCS file: /home/cvs/MCS/Applications/NM90/AssemblyInfo.cs,v
Working file: AssemblyInfo.cs
head: 1.61
branch:
locks: strict
access list:
symbolic names:
        NM90_Version_2_3_Build_52: 1.57
        NM90_Version_2_3_Build_50: 1.56
        NM90_Version_2_3_Build_14: 1.41
        NM90_Version_2_2_Build_44: 1.22
        NM90_Version_2_2_Build_42: 1.21
        NM90_Version_2_2_Build_40: 1.20
        NM90_Version_2_2_Build_32: 1.15
        NM90_Version_2_2_Build_28: 1.12
        NM100_Version_2_2_Build_6: 1.5 
keyword substitution: kv
total revisions: 61;    selected revisions: 61
description:
----------------------------
revision 1.61
date: 2004/11/22 13:50:06;  author: cnelson;  state: Exp;  lines: +1 -1
PRN:302
----------------------------
revision 1.60
date: 2004/11/16 21:04:21;  author: cnelson;  state: Exp;  lines: +1 -1
PRN:310
----------------------------
...

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:

// Execute the command
cmd.Start();
cmd.WaitDone();

// Print out the results
foreach (CVSHistoryItem hi in cmd.History)
{
    Console.WriteLine("File: {0}", hi.File);
    Console.WriteLine("Revision: {0}",hi.Revision);
    Console.WriteLine("Date: {0}", hi.Date);
    Console.WriteLine("Author: {0}", hi.Author);
    Console.WriteLine("Description: {0}", hi.Description);
}

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.

A list of licenses authors might use can be found here

Share

About the Author

Jay Nelson
Web Developer
United States United States
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 medical device manufacturer developing applications for the compact framework.
 
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 enjoy triathlons and reading.

Comments and Discussions

 
QuestionWhat is the License? PinmemberJeremyWilkins7-Apr-14 12:27 
GeneralNeed some technical input PinmemberMember 405876924-Feb-08 23:47 
GeneralRe: Need some technical input PinmemberAndy Creigh27-May-08 2:04 
QuestionAutomate Password With With Login Pinmembergilbo10017-Feb-08 2:41 
AnswerRe: Automate Password With With Login PinmemberHonglonghong9-Jul-11 1:00 
QuestionDon't understand the versioning code Pinmembersmaccona21-Aug-07 6:57 
GeneralAccessing Win2003 server PinmemberYasirA13-Jul-06 4:39 
Generaldoesn't support :ext protocol Pinmembercvsclient21-Jan-05 0:04 
GeneralMinor Problem - with fix! Pinmemberscporich10-Dec-04 10:29 
General#CVSlib Pinmemberynik24-Nov-04 4:18 
GeneralRe: #CVSlib PinmemberJay Nelson24-Nov-04 7:11 
GeneralRe: #CVSlib PinsussAnonymous27-Sep-05 11:26 
GeneralRe: #CVSlib PinmemberDaniel Grunwald28-Sep-05 3:04 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.141223.1 | Last Updated 25 Nov 2004
Article Copyright 2004 by Jay Nelson
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid