Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Bare bones SourceSafe journal monitor

0.00/5 (No votes)
6 Sep 2008 2  
A simple and straightforward tool to monitor and report SourceSafe database changes.

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.

SourceSafeChangeMonitor.jpg

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.

ChangesDetected.jpg

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.

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

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.

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