Click here to Skip to main content
6,629,377 members and growing! (24,070 online)
Email Password   helpLost your password?
Development Lifecycle » Design and Architecture » Application Design     Beginner License: The Microsoft Public License (Ms-PL)

Use Subversion Revision numbers in your Visual Studio Projects

By Paul Betteridge

SVN Keywords are not sufficient for retrieving the highest revision number for your project. This simple method solves this problem.
C#, VB, Windows, .NET, Architect, Dev, QA, Design, SysAdmin
Posted:17 Jul 2008
Views:21,110
Bookmarked:60 times
Unedited contribution
Announcements
Loading...
 
Search    
Advanced Search
Add to IE Search
printPrint   add Share
      Discuss Discuss   Broken Article?Report  
9 votes for this article.
Popularity: 4.07 Rating: 4.26 out of 5

1
1 vote, 11.1%
2

3
3 votes, 33.3%
4
5 votes, 55.6%
5

Introduction

I have been using TortoiseSVN for a while now and it has proven a great way to use Subversion in the Windows / Visual Studio environment.

I recently discovered how use SVN Keywords in my projects.

If you enable SVN Keywords then every time you check in the project Subversion scans your files for certain "keywords" and replaces the keywords with some information.

For example, At the top of my source files I would create a header contain the following keywords:

'$Author:$
'$Id:$
'$Rev:$

When I check this file into Subversion these keywords are replaced with the following:

'$Author: paulbetteridge $
'$Id: myfile.vb 145 2008-07-16 15:24:29Z paulbetteridge $
'$Rev: 145 $

I thought that if I take the $Rev$ keyword I could use this as part of my software version so that I could keep track of the version and the build when it is released. I would have a version that would look like 1.0.0.145.

The limitation of using the $Rev$ keyword is that it only gives you the revision of the file and not the entire project so using $rev$ keyword cannot work as part of my software versioning.

Reading the Tortoise help files I found a tool supplied with Tortoise SVN called SubWCRev.exe.

SubWCRev is Windows console program which can be used to read the status of a Subversion working copy and perform keyword substitution in a template file.

This article shows you how you can use SubWCRev to embed the top level revision number into your projects.

Using the code

The code performs three tasks:

[1] Creates a template file containing keywords that are read by SubWCRev

[2] Runs the SubWCRev.exe which produces an output text file containing subversion information based on the keywords from the template file.

[3] Reads the output file and returns values from the file into an array for use by your project.

The project attached is written in VB.Net but I have also provided the C# implementation in this article.

Template File

The template file is created by this code and will contain ALL available commands that are read by SubWCRev:

Keyword Description
$WCREV$ Replaced with the highest commit revision in the working copy.
$WCDATE$ Replaced with the commit date/time of the highest commit revision. By default, international format is used: yyyy-mm-dd hh:mm:ss. Alternatively, you can specify a custom format which will be used with strftime(), for example: $WCDATE=%a %b %d %I:%M:%S %p$. For a list of available formatting characters, look at the online reference .
$WCNOW$ Replaced with the current system date/time. This can be used to indicate the build time. Time formatting is as described above.
$WCRANGE$ Replaced with the update revision range in the working copy. If the working copy is in a consistent state, this will be a single revision. If the working copy contains mixed revisions, either due to being out of date, or due to a deliberate update-to-revision, then the range will be shown in the form 100:200
$WCMIXED$ $WCMIXED?TText:FText$ is replaced with TText if there are mixed update revisions, or FText if not.
$WCMODS$ $WCMODS?TText:FText$ is replaced with TText if there are local modifications, or FText if not.
$WCURL$ Replaced with the repository URL of the working copy path passed to SubWCRev.
$WCNOW$ Replaced with the current time and date
$WCNOW= Replaced with the current time and date in standard format
$WCINSVN$ $WCINSVN?TText:FText$ is replaced with TText if the entry is versioned, or FText if not.
$WCNEEDSLOCK$ $WCNEEDSLOCK?TText:FText$ is replaced with TText if the entry has the svn:needs-lock property set, or FText if not.
$WCISLOCKED$ $WCISLOCKED?TText:FText$ is replaced with TText if the entry is locked, or FText if not.
$WCLOCKDATE$ Replaced with the lock date
$WCLOCKOWNER$ Replaced with the name of the lock owner
$WCLOCKCOMMENT$ Replaced with the comment of the lock

VB.NET
        Dim strTemplateFile As String = "SvnTemplate.txt"
        Dim bAns As Boolean = False
        Dim objReader As StreamWriter
        Dim strData As String

        strData = "$WCREV$" + vbCrLf + _
                  "$WCDATE$" + vbCrLf + _
                  "$WCNOW$" + vbCrLf + _
                  "$WCRANGE$" + vbCrLf + _
                  "$WCMIXED?Mixed update revision:Not mixed$" + vbCrLf + _
                  "$WCMODS?Modified:Not modified$" + vbCrLf + _
                  "$WCURL$" + vbCrLf + _
                  "$WCNOW$" + vbCrLf + _
                  "$WCINSVN?Versioned:Not Versioned$" + vbCrLf + _
                  "$WCNEEDSLOCK?Lock Required:Lock not required$" + vbCrLf + _
                  "$WCISLOCKED?Locked:Not Locked$" + vbCrLf + _
                  "$WCLOCKDATE$" + vbCrLf + _
                  "$WCLOCKOWNER$" + vbCrLf + _
                  "$WCLOCKCOMMENT$" + vbCrLf
        Try
            objReader = New StreamWriter(strTemplateFile)
            objReader.Write(strData)
            objReader.Close()
        Catch Ex As Exception
            Console.WriteLine(Ex.Message)
        End Try
         

C#
    string strTemplateFile = @"SvnTemplate.txt"
    bool bAns = false;
    StreamWriter objReader;
    string strData;
    
    strData = "$WCREV$" + Constants.vbCrLf + 
              "$WCDATE$" + Constants.vbCrLf + 
              "$WCNOW$" + Constants.vbCrLf + 
              "$WCRANGE$" + Constants.vbCrLf + 
              "$WCMIXED?Mixed update revision:Not mixed$" + Constants.vbCrLf + 
              "$WCMODS?Modified:Not modified$" + Constants.vbCrLf + 
              "$WCURL$" + Constants.vbCrLf + 
              "$WCNOW$" + Constants.vbCrLf + 
              "$WCINSVN?Versioned:Not Versioned$" + Constants.vbCrLf + 
              "$WCNEEDSLOCK?Lock Required:Lock not required$" + Constants.vbCrLf + 
              "$WCISLOCKED?Locked:Not Locked$" + Constants.vbCrLf + 
              "$WCLOCKDATE$" + Constants.vbCrLf + 
              "$WCLOCKOWNER$" + Constants.vbCrLf + 
              "$WCLOCKCOMMENT$" + Constants.vbCrLf;
    try {
        objReader = new StreamWriter(strTemplateFile);
        objReader.Write(strData);
        objReader.Close();
    }
    catch (Exception Ex) {
        Console.WriteLine(Ex.Message);
    }
    

Create the Revision Information

Once you have your template file you need to run the command line tool SubWCRev.exe passing in three parameters - the Working Directory of your source code, the template file location and the location you want to store your output file containing your revision information.

VB.NET
        Dim strRev As String = ""

        ' Input file containing the SubWcRev keywords
        Dim strTemplateFile As String = "svntemplate.txt"

        ' Output file that will contain the SVN revisions after calling SubWcRev.exe
        Dim strRevOutputFile As String = "svnrev.txt"


        ' If we are running as an exe (i.e. not in the Visual Studio IDE) 
        ' then we dont want to create the revisions but read what is 
        ' already there.  This assumes that the exe is being used on a 
        ' non-subversion machine

        ' Check for the IDE, True is it is or false if it is not 
        ' (assume false is running as an exe)
        If System.Diagnostics.Debugger.IsAttached Then

            ' Get the working directory of the application exe - not the most 
            ' glamourous way to do this so need to rethink this!!!
            Dim dirInfo As New DirectoryInfo(Application.ExecutablePath)
            Dim dirinfoSourceWorkingDir As DirectoryInfo
            dirinfoSourceWorkingDir = dirInfo.Parent().Parent().Parent()
            Dim strSourceWorkingDir As String = dirinfoSourceWorkingDir.FullName

            ' The template file is a text file containing some 
            ' keyword that are recognised by SubWcRev.exe when it 
            ' is run against the root project directory.  
            ' Creates the template file is it is not already there
            SvnCreateTemplate(strTemplateFile)

            ' Now create a process to run the SubWcRec.exe
            Try
                Dim p As New Process

                With p.StartInfo
                    .UseShellExecute = True
                    .FileName = "subwcrev.exe"
                    .Arguments = """" + strSourceWorkingDir + """ """ + _
                                 strTemplateFile + """ """ + _
                                 strRevOutputFile + """"
                    .UseShellExecute = False
                    .RedirectStandardOutput = True

                End With

                ' Execute the process and wait for it to exit
                If p.Start() Then
                    Dim output As String = p.StandardOutput.ReadToEnd()
                    Console.WriteLine(output)

                    p.WaitForExit()
                End If
            Catch ex As Exception
                Console.WriteLine(ex.Message)
                ' Probably because Subversion not installed 
                ' and SubWcRev.exe was not found
            End Try

        End If
     

C#
    string strRev = "";
    
    // Input file containing the SubWcRev keywords
    string strTemplateFile = "svntemplate.txt"
    
    // Output file that will contain the SVN revisions after calling SubWcRev.exe
    string strRevOutputFile = "svnrev.txt";
    
    
    // If we are running as an exe (i.e. not in the Visual Studio IDE) 
    // then we dont want to create the revisions but read what 
    // is already there.  This assumes that the exe is being used 
    // on a non-subversion machine
    
    // Check for the IDE, True is it is or false if it is not 
    // (assume false is running as an exe)
    if (System.Diagnostics.Debugger.IsAttached) {
        
        // Get the working directory of the application exe - not the most 
        // glamourous way to do this so need to rethink this!!!
        DirectoryInfo dirInfo = new DirectoryInfo(Application.ExecutablePath);
        DirectoryInfo dirinfoSourceWorkingDir;
        dirinfoSourceWorkingDir = dirInfo.Parent().Parent().Parent();
        string strSourceWorkingDir = dirinfoSourceWorkingDir.FullName;
        
        // The template file is a text file containing some keyword that are ~
        // recognised by SubWcRev.exe when it 
        // is run against the root project directory.  
        // Creates the template file is it is not already there
        SvnCreateTemplate(strTemplateFile);
        
        // Now create a process to run the SubWcRec.exe
        try {
            Process p = new Process();
            
            {
                p.StartInfo.UseShellExecute = true;
                p.StartInfo.FileName = "subwcrev.exe";
                p.StartInfo.Arguments = "\"" + strSourceWorkingDir + 
                                        "\" \"" + strTemplateFile + "\" \"" +
                                        strRevOutputFile + "\"";
                p.StartInfo.UseShellExecute = false;
                p.StartInfo.RedirectStandardOutput = true;
            }
            
            
            // Execute the process and wait for it to exit
            if (p.Start()) {
                string output = p.StandardOutput.ReadToEnd();
                Console.WriteLine(output);
                
                p.WaitForExit();
            }
        }
        catch (Exception ex) {
            Console.WriteLine(ex.Message);
            // Probably because Subversion not installed and SubWcRev.exe was not found
        }
        
    }

You now have the output file created so next you need to read this file into your application so you can start using the revision information.

VB.Net
        ' The revison should now be available in the output file - 
        ' reading this will get the revision
        ' There are three lines (Rev, Modifed status and Rev Date) 
        Dim strContents As String = ""
        Dim objReader As StreamReader
        Try

            objReader = New StreamReader(strRevOutputFile)
            strContents = objReader.ReadToEnd()
            objReader.Close()

            ' Get the revision from the contents of the file
            aRevData = Split(strContents, vbCrLf)

        Catch Ex As Exception
            Console.WriteLine(Ex.Message)
            ' Probably because Subversion is not installed or this 
            ' project has not been checked into
            ' subversion yet.  You muct make sure it is checked in to create a revision
            If System.Diagnostics.Debugger.IsAttached Then
                MessageBox.Show(Ex.Message + vbCrLf + vbCrLf + _
                                "This is probably because this project is not " + _
                                "under subversion revision control yet or the " + _
                                "output file was not created by ""subwcrev.exe""")
            Else
                MessageBox.Show(Ex.Message + vbCrLf + vbCrLf + _
                                "This is probably because the output file " + _ 
                                """svnrev.txt"" has not been created yet - need " + _
                                "run this using the Visual Studio IDE first to " + _
                                "create the svnrev.txt file containing the SVN values!")
            End If

            aRevData(0) = """svnrev.txt"" file not Found"
        End Try

C#  

{
    // The revison should now be available in the output file - reading this 
    // will get the revision
    // There are three lines (Rev, Modifed status and Rev Date) 
    string strContents = "";
    StreamReader objReader;
    try {
        
        objReader = new StreamReader(strRevOutputFile);
        strContents = objReader.ReadToEnd();
        objReader.Close();
        
        // Get the revision from the contents of the file
        aRevData = Strings.Split(strContents, Constants.vbCrLf);
    }
    
    catch (Exception Ex) {
        Console.WriteLine(Ex.Message);
        // Probably because Subversion is not installed or this project 
        // has not been checked into
        // subversion yet.  You muct make sure it is checked in to create a revision
        if (System.Diagnostics.Debugger.IsAttached) {
            MessageBox.Show(Ex.Message + Constants.vbCrLf + Constants.vbCrLf + 
            "This is probably because this project is not under subversion " + 
            "revision control yet or the output file was not " + 
            "created by \"subwcrev.exe\"");
        }
        else {
            MessageBox.Show(Ex.Message + Constants.vbCrLf + Constants.vbCrLf + 
                            "This is probably because the output file \"svnrev.txt\" " + 
                            "has not been created yet - need run this using the " + 
                            "Visual Studio IDE first to create the svnrev.txt file " + 
                            "containing the SVN values!");
        }
        
        aRevData(0) = "\"svnrev.txt\" file not Found";
    }
}

I return the contents of the file into a string array called "aRevData".

I pre-initialised this array first with values in case the template file is not created or there was a problem somewhere. This would then allow you to use the pre-initialised values in your project if you are unable to get hold of the SVN values (an example is if you dont have subversion installed or you havent checked your project into subversion yet).

Using the Revision Data

Wrapping this article up below shows you show I would use the code - please take a look at the project posted.

I use the variable "AppVersion" in my About forms / Splash Screens etc and as my software version for official releases of the application.

VB.NET
        ' Create the revision data array - initialise to initial values - date will be 
        ' overwritten if reading the svn file is ok
        Dim aRevHeaders() As String = {"$WCREV$", _
                                       "$WCDATE$", _
                                       "$WCNOW$", _
                                       "$WCRANGE$", _
                                       "$WCMIXED$", _
                                       "$WCMODS$", _
                                       "$WCURL$", _
                                       "$WCNOW$", _
                                       "$WCINSVN?Versioned:Not Versioned$", _
                                       "$WCNEEDSLOCK$", _
                                       "$WCISLOCKED$", _
                                       "$WCLOCKDATE$", _
                                       "$WCLOCKOWNER$", _
                                       "$WCLOCKCOMMENT$"}

        Dim aRevData() As String = {"0", "", "", "", "", "", "", "", "", "", "", "", "", "", ""}

        ' Read and write to the svnrevisions text file so that it forces subversion to update 
        ' the file with the latest revision - there are no global revisions keyword so this 
        ' is an alternative!
        Try
            SvnGetlatestRev(aRevData) ' Create and read the svn revision file
        Catch ex As Exception
            Console.WriteLine(ex.Message)
        End Try


        Dim strVersion As String() = Split(Application.ProductVersion, ".")
        Dim AppVersion As String = String.Format("{0}.{1}.{2}.{3}", _
                                                 strVersion(0), _
                                                 strVersion(1), _
                                                 strVersion(2), _
                                                 aRevData(0))

C#
    // Create the revision data array - initialise to initial values - date will be 
    // overwritten if reading the svn file is ok
    string[] aRevHeaders = {"$WCREV$", 
                            "$WCDATE$", 
                            "$WCNOW$", 
                            "$WCRANGE$", 
                            "$WCMIXED$", 
                            "$WCMODS$", 
                            "$WCURL$", 
                            "$WCNOW$", 
                            "$WCINSVN?Versioned:Not Versioned$", 
                            "$WCNEEDSLOCK$", 
                            "$WCISLOCKED$", 
                            "$WCLOCKDATE$", 
                            "$WCLOCKOWNER$", 
                            "$WCLOCKCOMMENT$"};
    
    string[] aRevData = {"0", "", "", "", "", "", "", "", "", "", "", "", "", "", ""};
    
    // Read and write to the svnrevisions text file so that it forces subversion to update 
    // the file with the latest revision - there are no global revisions keyword so this 
    // is an alternative!
    try {
        SvnGetlatestRev(aRevData);
        // Create and read the svn revision file
    }
    catch (Exception ex) {
        Console.WriteLine(ex.Message);
    }
    
    
    string[] strVersion = Strings.Split(Application.ProductVersion, ".");
    string AppVersion = string.Format("{0}.{1}.{2}.{3}", strVersion(0), strVersion(1), strVersion(2), aRevData(0));

  

I have seen in the Tortoise help files that I could make use of the COM interface - this is something for another day.

Thank you for reading this article. Please leave your comments and ways I can improve this.

History

pbRevsion v1.0

License

This article, along with any associated source code and files, is licensed under The Microsoft Public License (Ms-PL)

About the Author

Paul Betteridge


Member

Occupation: Software Developer (Senior)
Company: PB-NET LTD
Location: United Kingdom United Kingdom

Other popular Design and Architecture articles:

Article Top
You must Sign In to use this message board.
FAQ FAQ 
 
Noise Tolerance  Layout  Per page   
 Msgs 1 to 7 of 7 (Total in Forum: 7) (Refresh)FirstPrevNext
GeneralGreat Article , Very Helpful! PinmemberRaputin74:09 5 Jun '09  
GeneralRe: Great Article , Very Helpful! PinmemberPaul Betteridge10:42 7 Jun '09  
GeneralSimpler way to obtain HEAD number Pinmembermrlocus11:33 30 Jul '08  
GeneralNAnt PinmemberUrs Enzler3:11 28 Jul '08  
GeneralAlso have a look at "svnversion" Pinmemberbgs26422:45 21 Jul '08  
GeneralNice, but split the long line. Pinmemberfaulty0:24 18 Jul '08  
GeneralRe: Nice, but split the long line. PinmemberPaul Betteridge1:16 18 Jul '08  

General General    News News    Question Question    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

PermaLink | Privacy | Terms of Use
Last Updated: 17 Jul 2008
Editor:
Copyright 2008 by Paul Betteridge
Everything else Copyright © CodeProject, 1999-2009
Web18 | Advertise on the Code Project