Introduction
One of the things I’ve looked for a long time was a way to be notified when changes occur to a SourceSafe project. I’ve worked in several team projects where changes by one member could make or break a build, or where changes necessitated a "get latest" by everyone else, but there was no automatic way of notifying people. And, when things are not automated, manual procedures start popping up all over the place, and the next thing you know you have batch files calling batch files, VB scripts calling batch files, pigeons carrying messages, and smoke signals. None of those work. Especially when you combine pigeons with smoke signals.
I started searching again recently, and found a few tools that do the job, but they were not free (some even wanted around $1000 for this!!!), and were not as straight forward as I hoped they would be. All I was looking for was something that would monitor SourceSafe and notify me (through email, pop ups, or worst case scenario - smoke signals) that something has changed in a project I’m working on. I could then take a look at the affected project and decide for myself what action needed to be taken.
So, along came CodeProject and the plethora of useful articles it contains, and in it, I found a couple of pearls. One such pearl was an article by Lewis Moten (Visual SourceSafe Journal Monitor Service), which pretty much did what I needed, but still had too much overhead. It involved an installation package, a SQL Server, a SQL script that had to be manually executed ... too much for what I was looking for.
So, I set out to create my own, and the result is the bare bones Source Safe journal monitor you're reading about.
The idea behind it, and the one-and-only prerequisite
One of the things SourceSafe does (and this becomes the only prerequisite you need for this tool to work) is log its actions in a journal file. This option must be turned on in the SourceSafe admin application, under Tools\Options\General. The file name and location are completely up to you, and the result is a pretty straightforward text file that is appended to every time an action is taken on the database. The entries are usually something like this:
$/MyProject/SourceFiles/MyClass.cs
Version: 2
User: Muaddubby Date: 22/10/08 Time: 8:38
Checked in
The application described by this article simply creates and enables a FileSystemWatcher
object that monitors the journal file. When changes are observed, the file is read, and any changes found in line numbers following the last line number we looked at (and belonging to a user-defined list of SourceSafe projects) are reported in a pop-up. Very simple, and very straightforward.
Usage
Running the application is simple. As soon as it loads, it tries to open the SourceSafe ini file (usually srcsafe.ini) it was configured with last time, and detects the path and name of the journal file. If it succeeds, it begins monitoring the file.
On the screen, you also have a multi-line text field into which you can type the names of the projects you want to monitor (one project per line, and you can use Ctrl+Enter to move to the next line), by referring to their tree structure in the SourceSafe database.
Some examples:
- To monitor the entire database, enter "$/".
- To monitor "Project1" which resides directly under the root node, enter "$/Project1".
You can specify any number of projects this way, and there is no limit. Note, however, that you can only specify projects, and not file names. The project names you enter are not case sensitive.
Once you’ve selected the SourceSafe ini file path and entered the list of projects to monitor, you’re good to go. If any of the settings have been changed, simply click on "Update" to save them, and restart monitoring on the journal file. Simply minimize the application, and leave it running. If you do shut it down, the next time you bring it up, it will show any changes made while it was not running.
Once an action is taken in SourceSafe, the change in the journal file is detected, and the file is then read. Any changes found since the last time the journal was looked at, and belonging to any of the monitored projects, is then reported in a pop up window.
A little behind the scenes ...
There really isn't much to this code, and it's all available in the zipped project you can download from above. The project consists of three classes:
FormSourceSafeMonitor
- The main form of the class. It handles the display of the options, initializing the file monitor, and parsing the journal to find any recent changes to the report.
FormShowChanges
- The form that shows the changes. Essentially, a form with a textbox that contains all the changes in the journal that match the user's search criteria.
MonitorSettings
- A serializable class that contains the user settings such as the SourceSafe ini file location, the list of projects to monitor, and the last line number in the journal file that the application stopped reading at.
The following code snippet shows the instantiation of the file monitor, the trapping of the event notification, and the parsing of the journal file (note that the CodeProject article editor doesn't let me put double quotes in the code, so I've had to use single quotes (i.e., ' instead of "). The code in the zipped project, however, is correct.
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);
}
}
private void filesystemWatcher_Changed(object sender, FileSystemEventArgs e)
{
FindAndReportChanges();
}
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();
}
}
}
In conclusion
As mentioned, this really is a bare bones tool, and several things could be done to it for improvement, such as:
- Instead of (or in addition to) pop ups, sends notifications via email.
- Minimize the application to the system tray or run it as a service.
- Scan the database for a list of projects it contains, and show them in a tree control with checkboxes, so the user can select the projects to monitor instead of entering them manually.
- Offer filtering by person’s name.
- Add threading so that long actions (such as preparing and sending emails) do not freeze the UI.
But for now, and for my simple purposes, this suffices. I hope this is useful to more people out there.
History
- August 20, 2008 - Article written up.