65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 C# 访问 CVS 存储库

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.77/5 (11投票s)

2004 年 11 月 24 日

4分钟阅读

viewsIcon

80010

downloadIcon

914

一篇关于使用 C# 访问 CVS 存储库的文章。

Sample Image

引言

我开发的大多数项目都是存储在 Linux 机器上运行的 CVS 存储库中的 Visual Studio .NET 项目。此外,我们使用一个运行在 Windows 2000 上的第三方错误跟踪软件来跟踪错误修复/客户问题等。出于审计原因,我需要开发一个程序来关联 CVS 存储库中不同版本标签之间的文件更改历史与错误跟踪系统中的问题跟踪记录。为了做到这一点,我需要一种简单的方法来访问 CVS 存储库中的历史数据。在这个过程中,我创建了一个简单且可扩展的类,可以直接从 C# 类访问 CVS 存储库。

我不会详细介绍访问错误跟踪软件的部分。该软件将其信息存储在符合 ODBC 标准的数据库中。这个问题的这部分既不独特也不有趣。

访问 CVS 存储库:设置

我不想详细介绍如何设置 CVS。 suffice 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. 足够了。我们使用 Windows 客户端机器上的 WinCVS 并进行 SSH 服务器身份验证。通过使用这种组合,我们不仅可以通过 WinCVS 访问 CVS 存储库,还可以从命令提示符访问它。

代码

首先,我创建了一个名为 CVSCommand 的中心类。该类通过命令行进程执行任意 CVS 命令。此外,它启动一个辅助线程,该线程监视 CVS 命令的控制台输出并将其放入缓冲区进行处理。虽然您可以通过使用此类直接发出 CVS 命令,但我从 CVSCommand 派生了特定的 CVS 命令类。

要执行命令,CVSCommand 或派生类必须知道几件事。它必须知道 CVS Root、RSH(远程 shell)命令以及命令执行的工作目录。创建了属性变量来存储此信息。例如,要使用 CVSCommand 类执行任意命令

// 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);

使用 CVSGetFileHistory 类

虽然您可以使用 CVSCommand 类发出任何 CVS 命令,但仍然需要解析响应。对于我的应用程序,我创建了一个名为 CVSGetFileHistory 的简单派生类。该命令使用基类的所有内置功能来执行 CVS 命令,但添加了特殊的解析代码,以便以熟悉且易于使用的格式解析 CVS 响应。此外,构造函数允许您指定要获取其历史记录的文件。例如,上面的代码可以更改为使用 CVSGetFileHistory 类,如下所示

// 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);
}

深入了解 CVSCommand

CVS Command 是一个相当简单的类。如前所述,它的主要功能是通过命令行进程执行任意 CVS 命令。为此,它使用 System.Diagnostics.Process 类。但是,它还必须确保定义了 CVS 使用的某些环境变量。启动进程后,它还会启动一个后台线程,该线程监视进程的控制台输出并将其附加到缓冲区。 `Start()` 方法是处理所有这些的地方

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();

}

一旦命令启动,就可以检查 `Running` 属性来查看命令是否仍在执行,或者可以调用 `WaitDone()` 方法来等待进程完成。

后台监视线程相当简单。代码只是读取进程的 `StandardOutput` 属性并将结果附加到缓冲区。此外,它监视类的 `Running` 属性来确定何时可以停止执行。

派生新类

派生新类并不困难。您真正需要做的就是提供一个接受命令的正确信息的构造函数以及解析命令响应的解析函数。例如,`CVSGetFileHistory` 构造函数如下所示

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

它还有几个属性,充当 `CVSCommand` 类 `Output` 的解析函数。例如,当在命令行上执行 `cvs log` 函数时,这会输出到控制台

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

为了从编程角度使其更易于使用,派生类需要解析此信息并以易于使用的方式呈现。例如,`CVSGetFileHistory` 解析上面列出的所有修订文本,并将其放入一个名为 `CVSHistoryItemList` 的容器类中,该类作为 `History` 属性变量公开。这样做,可以轻松完成以下操作

// 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);
}

其他说明

总之,这个基本类完成了我需要它做的事情,不多也不少。当然可以毫不费力地添加额外的错误处理。还可以实现额外的命令。

历史

  • 2004 年 11 月 22 日 - 初次发布。
© . All rights reserved.