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

最基本的 SourceSafe 日志监视器

starIconstarIconstarIconstarIconstarIcon

5.00/5 (3投票s)

2008年9月6日

CPOL

5分钟阅读

viewsIcon

32317

downloadIcon

282

一个简单直接的工具,用于监视和报告 SourceSafe 数据库的更改。

引言

我长期以来一直在寻找一种方法,以便在 SourceSafe 项目发生更改时收到通知。我曾经参与过几个团队项目,其中一个成员的更改可能会影响或破坏构建,或者更改需要每个人都“获取最新版本”,但当时没有自动通知人们的方法。而且,当事情没有自动化时,手动流程会四处出现,不知不觉中你就会发现批处理文件调用批处理文件,VB 脚本调用批处理文件,信鸽送信,还有烟雾信号。这些方法都不奏效。尤其是当你将信鸽和烟雾信号结合在一起时。

我最近又开始搜索,发现了一些可以完成这项工作的工具,但它们不是免费的(有些甚至要价约 1000 美元!),而且不像我希望的那样直接。我所寻找的只是一个能够监视 SourceSafe 并通过电子邮件、弹出窗口,或者最糟糕的情况下——烟雾信号——通知我正在处理的项目中发生的变化的东西。然后我就可以查看受影响的项目,自己决定需要采取什么行动。

于是,CodeProject 和它上面大量的有用文章出现了,我在其中发现了一些珍宝。其中一颗宝石是 Lewis Moten 的一篇文章(Visual SourceSafe Journal Monitor Service),这基本上能满足我的需求,但仍然有太多开销。它涉及一个安装包、一个 SQL Server、一个必须手动执行的 SQL 脚本……这对我来说太复杂了。

于是,我开始自己动手创建,结果就是你正在阅读的这个精简版的 Source Safe 日志监视器。

它的基本思想,以及唯一的先决条件

SourceSafe 的一个功能(这也是使此工具正常工作的唯一先决条件)是将其操作记录在日志文件中。必须在 SourceSafe 管理应用程序的 *Tools\Options\General* 下启用此选项。文件名和位置完全由你决定,结果是一个非常直接的文本文件,每次对数据库执行操作时都会追加新内容。条目通常如下所示

$/MyProject/SourceFiles/MyClass.cs
Version: 2
User: Muaddubby           Date: 22/10/08  Time:   8:38
Checked in

本文描述的应用程序只是创建一个并启用一个 FileSystemWatcher 对象,该对象监视日志文件。当检测到更改时,会读取该文件,并报告在我们上次查看的行号之后的、属于用户定义的 SourceSafe 项目列表中的任何更改,通过弹出窗口显示。非常简单,非常直接。

用法

运行该应用程序很简单。一旦加载,它会尝试打开上次配置的 SourceSafe *ini* 文件(通常是 *srcsafe.ini*),并检测日志文件的路径和名称。如果成功,它就开始监视该文件。

SourceSafeChangeMonitor.jpg

在屏幕上,还有一个多行文本字段,你可以在其中输入要监视的项目名称(每行一个项目,你可以使用 Ctrl+Enter 移到下一行),通过引用它们在 SourceSafe 数据库中的树状结构。

一些示例

  • 要监视整个数据库,请输入 "$/"。
  • 要监视直接位于根节点下的“Project1”,请输入 "$/Project1"。

你可以通过这种方式指定任意数量的项目,没有限制。但请注意,你只能指定项目,而不能指定文件名。输入的项目名称不区分大小写。

一旦选择了 SourceSafe *ini* 文件路径并输入了要监视的项目列表,就可以开始工作了。如果任何设置已更改,只需单击“Update”以保存它们,然后重新开始监视日志文件。只需最小化应用程序,然后让它运行。如果你关闭它,下次再次打开时,它将显示在它未运行时所做的任何更改。

一旦在 SourceSafe 中执行了操作,就会检测到日志文件的更改,然后读取该文件。在上次查看日志后发现的、属于任何被监视项目的更改,都会在弹出窗口中报告。

ChangesDetected.jpg

幕后一点……

这段代码真的没什么复杂的,所有代码都可以在上面下载的压缩项目中找到。该项目包含三个类

  • FormSourceSafeMonitor - 类的主要窗体。它处理选项的显示、文件监视器的初始化以及日志的解析,以查找要报告的任何近期更改。
  • FormShowChanges - 显示更改的窗体。基本上,一个带有文本框的窗体,其中包含日志中所有匹配用户搜索条件的更改。
  • MonitorSettings - 一个可序列化的类,包含用户设置,如 SourceSafe *ini* 文件位置、要监视的项目列表以及应用程序停止读取日志文件的最后一个行号。

下面的代码片段显示了文件监视器的实例化、事件通知的捕获以及日志文件的解析(请注意,CodeProject 文章编辑器不允许我在代码中放入双引号,因此我不得不使用单引号(例如,' 而不是 ")。但压缩项目中的代码是正确的。

/// <summary>
/// Extract the path and file name of the SourceSafe
/// journal file and, if found, begin 
/// monitoring it for changes.
/// </summary>
private void GetJournalPathAndBeginMonitoring()
{
    mJournalPath = "";
    try
    {
        FileStream iniStream = new FileStream(mTextBoxSourceSafeLocation.Text, 
                                              FileMode.Open, FileAccess.Read);
        StreamReader streamReader = new StreamReader(iniStream);
        string iniString = streamReader.ReadLine();
    
        while (!streamReader.EndOfStream)
        {
            if (iniString.Contains("Journal_File") && 
                iniString.Trim().Substring(0,1) != "")
            {
                mJournalPath = iniString.Substring(iniString.IndexOf("=")).Trim();
                break;
            }
            iniString = streamReader.ReadLine();
        }
        
        if (iniString.Contains("Journal_File") && 
            iniString.Trim().Substring(0, 1) != ";")
        {
            mJournalPath = iniString.Substring(iniString.IndexOf("=") + 1).Trim();
        }

        streamReader.Close();

        if (mJournalPath != "")
        {
            mFileSystemWatcher = new 
              FileSystemWatcher(System.IO.Path.GetDirectoryName(mJournalPath));
            mFileSystemWatcher.Filter = System.IO.Path.GetFileName(mJournalPath);
            mFileSystemWatcher.Changed += new 
              FileSystemEventHandler(filesystemWatcher_Changed);
            mFileSystemWatcher.NotifyFilter = NotifyFilters.LastWrite;
            mFileSystemWatcher.EnableRaisingEvents = true;
        }
    }

    catch (Exception ex)
    {
        MessageBox.Show(
            ex.Message, 
            "Error", 
            MessageBoxButtons.OK, 
            MessageBoxIcon.Error, 
            MessageBoxDefaultButton.Button1);
    }
}

/// <summary>
/// A change to the SourceSafe journal was detected by the OS. find and report any changes 
/// to the database.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void filesystemWatcher_Changed(object sender, FileSystemEventArgs e)
{
    FindAndReportChanges();
}

/// <summary>
/// Read through the SourceSafe journal file until the last line we read last time a change 
/// was reported, and then look for any changes made to the projects monitored by the user. 
/// Report any such changes, and then store the last line number so we can start scanning 
/// from there next time.
/// </summary>
private void FindAndReportChanges()
{
    if (mJournalPath != "")
    {
        FileStream stream = new FileStream(mJournalPath, FileMode.Open, FileAccess.Read);
        StreamReader reader = new StreamReader(stream);
        int lineCtr = -1;
        
        string currentLine = reader.ReadLine();
        StringBuilder journalStringBuilder = new StringBuilder();

        List<string> otherItems = new List<string>();
        bool newSection = false;

        while (!reader.EndOfStream)
        {
            lineCtr++;
            if (lineCtr >= mMonitorSettings.LastLineNumberReportedOn)
            {
                if (currentLine.Length >= 2 && currentLine.Substring(0, 2) == "$/")
                {
                    foreach (string projectToMonitor in
                        mTextBoxProjectsToMonitor.Text.Split(
                        new string[] { Environment.NewLine }, 
                            StringSplitOptions.RemoveEmptyEntries))
                    {
                        if (currentLine.ToLower().Contains(projectToMonitor.ToLower()))
                        {
                            newSection = true;
                            break;
                        }
                    }
                }

                if (newSection)
                {
                    journalStringBuilder.AppendLine(currentLine);
                }

                if (currentLine == "")
                {
                    newSection = false;
                }
            }

            currentLine = reader.ReadLine();
        }

        reader.Close();
        mMonitorSettings.LastLineNumberReportedOn = lineCtr;
        SaveSettings();
        
        if (journalStringBuilder.Length > 0)
        {
            FormShowChanges formShowChanges = 
               new FormShowChanges(journalStringBuilder.ToString());
            formShowChanges.ShowDialog();
        }
    }
}

结论

如前所述,这确实是一个精简的工具,可以通过以下方式进行改进:

  • 通过电子邮件发送通知,而不是(或除了)弹出窗口。
  • 将应用程序最小化到系统托盘或将其作为服务运行。
  • 扫描数据库以获取其包含的项目列表,并在树形控件中显示它们,并带有复选框,以便用户可以选择要监视的项目,而不是手动输入。
  • 提供按姓名过滤的功能。
  • 添加多线程,以便长时间运行的操作(如准备和发送电子邮件)不会冻结 UI。

但目前,对于我的简单目的来说,这就足够了。我希望这对更多人有用。

历史

  • 2008 年 8 月 20 日 - 文章撰写完毕。
© . All rights reserved.