最基本的 SourceSafe 日志监视器





5.00/5 (3投票s)
一个简单直接的工具,用于监视和报告 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*),并检测日志文件的路径和名称。如果成功,它就开始监视该文件。
在屏幕上,还有一个多行文本字段,你可以在其中输入要监视的项目名称(每行一个项目,你可以使用 Ctrl+Enter 移到下一行),通过引用它们在 SourceSafe 数据库中的树状结构。
一些示例
- 要监视整个数据库,请输入 "$/"。
- 要监视直接位于根节点下的“Project1”,请输入 "$/Project1"。
你可以通过这种方式指定任意数量的项目,没有限制。但请注意,你只能指定项目,而不能指定文件名。输入的项目名称不区分大小写。
一旦选择了 SourceSafe *ini* 文件路径并输入了要监视的项目列表,就可以开始工作了。如果任何设置已更改,只需单击“Update”以保存它们,然后重新开始监视日志文件。只需最小化应用程序,然后让它运行。如果你关闭它,下次再次打开时,它将显示在它未运行时所做的任何更改。
一旦在 SourceSafe 中执行了操作,就会检测到日志文件的更改,然后读取该文件。在上次查看日志后发现的、属于任何被监视项目的更改,都会在弹出窗口中报告。
幕后一点……
这段代码真的没什么复杂的,所有代码都可以在上面下载的压缩项目中找到。该项目包含三个类
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 日 - 文章撰写完毕。