Click here to Skip to main content
15,867,835 members
Articles / Programming Languages / C#
Article

Accessing CVS Repository with C#

Rate me:
Please Sign up or sign in to vote.
4.77/5 (12 votes)
24 Nov 20044 min read 75.6K   913   40   13
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:

C#
// 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:

C#
// 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:

C#
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:

C#
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:

C#
// 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


Written By
Architect Omron Adept Technologies, Inc
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 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.

I enjoy karate and reading.

Comments and Discussions

 
QuestionWhat is the License? Pin
JeremyWilkins7-Apr-14 11:27
JeremyWilkins7-Apr-14 11:27 
GeneralNeed some technical input Pin
Member 405876924-Feb-08 22:47
Member 405876924-Feb-08 22:47 
GeneralRe: Need some technical input Pin
Andy Creigh27-May-08 1:04
Andy Creigh27-May-08 1:04 
QuestionAutomate Password With With Login Pin
gilbo10017-Feb-08 1:41
gilbo10017-Feb-08 1:41 
AnswerRe: Automate Password With With Login Pin
Honglonghong9-Jul-11 0:00
Honglonghong9-Jul-11 0:00 
QuestionDon't understand the versioning code Pin
smaccona21-Aug-07 5:57
smaccona21-Aug-07 5:57 
GeneralAccessing Win2003 server Pin
YasirA13-Jul-06 3:39
YasirA13-Jul-06 3:39 
Hi There

I'd like to adapt your code to do the same thing to access a respository on a Windows server on the same local home network.

I see that your program invokes the CVS command (not installed on my pc). The setup that I have involves TortoiseCVS on my pc and CVSNT on my server.

I know that ssh will fall away as we won't need it for this setup.

I'm hoping you can advise me as to how to modify the code the get the same result as the linux setup that you had.

Any information would be appreciated.

Thanks
Generaldoesn't support :ext protocol Pin
cvsclient20-Jan-05 23:04
cvsclient20-Jan-05 23:04 
GeneralMinor Problem - with fix! Pin
scporich10-Dec-04 9:29
scporich10-Dec-04 9:29 
General#CVSlib Pin
Daniel Grunwald24-Nov-04 3:18
Daniel Grunwald24-Nov-04 3:18 
GeneralRe: #CVSlib Pin
Jay Nelson24-Nov-04 6:11
Jay Nelson24-Nov-04 6:11 
GeneralRe: #CVSlib Pin
Anonymous27-Sep-05 10:26
Anonymous27-Sep-05 10:26 
GeneralRe: #CVSlib Pin
Daniel Grunwald28-Sep-05 2:04
Daniel Grunwald28-Sep-05 2:04 

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

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