Click here to Skip to main content
Click here to Skip to main content

Subversion (SVN) Post-Commit Organizer for Shadow Copy

, 13 Apr 2009
Rate this:
Please Sign up or sign in to vote.
Subversion (SVN) Post-Commit Organizer for Shadow Copy

Introduction

Subversion, popularly abbreviated as SVN, is a powerful open source version control system. A version control system organizes the source code in such a way that you can keep track of the changes you make, mark some milestones throughout the evolution of the software and perhaps differentiate some specialized versions according to some certain needs, i.e. platform or OS, professional or standard, etc. Subversion accomplishes these needs as it should and goes well beyond, too.

If you are developing software, you have to have some conventions. Separating the production environment on which the software actually runs to deliver service to clients and the development environment on which you debug your code or experiment on new features.

In our organization, we had already adopted SVN for managing the desktop applications but had been using Visual Sourcesafe for web applications as the version control and code sharing system. Everything was straightforward until we found out that SVN did not have a built-in shadow copy feature. As the name implies, this feature enables us to have a synchronized copy of the code-base at some specified location.

We were not aware of this fact as we did not need it for desktop applications. But for web applications, we needed to have the latest copy of the code-base somewhere on the web server. After examining a few links Hook Scripts, we discovered the post commit hook - Repository Hooks - which is a notification of a successful commit and it has a wide range of usability. See also: Creating a post-commit hook for Subversion.

If you simply put an executable file with the name post-commit (for example EXE, BAT, CMD on Windows, SH, PL, PY on Linux) in the hooks folder under a repository, it is run everytime a successful commit occurs. There are some Perl, Python and lisp scripts for a variety of needs already for Linux systems. (Using Subversion Hooks to send out build Emails).

We tried some Perl scripts, but consequently were not satisfied with the results as we are no Perl hackers.

We decided to have our own post-commit.bat batch file which invokes a C# executable to synchronize our shadow copy folder. The executable is a simple console application that spawns a process to issue an SVN checkout if the repository is newly created or an SVN update if a file is changed. It, additionally, keeps a log about what happened. SVNPostCommitConfiguration.exe is a WinForms utility that keeps the settings, generates the appropriate batch file in the specified repository.

I would like to evolve this simple project and the article into a general hook manager if a need in this context arises. I would also like to thank Thomas Weller for his comment and supportive critique to enhance this article.

Using the Code

SVNPostCommit.exe makes a shadow copy of your repository with incoming parameters, and it logs your commits.

SVNHelper.cs

        
public static class SvnHelper
{
    const int EXPECTED_ARGS_COUNT  = 6;
    const string LOGDIRECTORY_NAME = "logs";
    const string LOGFILE_EXTENSION = ".log";
    
    static readonly string _startupPath = 
	Path.GetDirectoryName( Assembly.GetEntryAssembly().Location );
    
    public static void ExecuteSvnCommand
	( string svnExePath, string destFolder, string repoName
         , string repoUrl, string userName, string password )
    {        
        if (String.IsNullOrEmpty(svnExePath))
            throw new
               ArgumentNullException("svnExePath");

        if (String.IsNullOrEmpty(repoName))
            throw new
               ArgumentNullException("repoName");

        //Building svn commandtype
        string svnCheckout = 
	BuildSvnArgs("checkout", userName, password, repoUrl, destFolder);

        string svnUpdate = BuildSvnArgs("update", userName, password, "", destFolder);

        string svnCommand = svnUpdate;

        if (!Directory.Exists(destFolder))
        {
            Directory.CreateDirectory(destFolder);
            svnCommand = svnCheckout;
        }

        if (Directory.GetFiles(destFolder).Count() == 0)
	        svnCommand = svnCheckout;
        
        string svnExecutable = Path.Combine(svnExePath, "svn.exe");
        //Making process to run SVN executable
        Process process = PrepareSVNProcess(svnCommand, svnExecutable);
            
        process.Start();

        string line = null;
        //Write process output to log file
        while ((line = process.StandardOutput.ReadLine()) != null)
        {            
            WriteLogLine( repoName, line );
        }
        
        process.Close();

    }//ExecuteSvnCommand

    public static Process PrepareSVNProcess(string arg, string cmd)
    {
        Process process = new Process();

        process.StartInfo.RedirectStandardOutput = true;
        process.StartInfo.RedirectStandardError = true;
        process.StartInfo.CreateNoWindow = true;
        process.StartInfo.UseShellExecute = false;

        process.StartInfo.Arguments = arg;
        process.StartInfo.FileName = cmd;

        return process;
    }

    static string BuildSvnArgs(string commandType,  string username, string password,
                               string repoUrl, string destFolder)
    {
        if (String.IsNullOrEmpty(commandType))
            throw new
               ArgumentNullException("commandType");        

        if (repoUrl == null)
            throw new
               ArgumentNullException("repoURL");

        var command = string.Empty;

        if (String.IsNullOrEmpty(username) || String.IsNullOrEmpty(password))
            throw new
                ArgumentNullException("username or password required");

        command = string.Format(
                  " {0} --ignore-externals --username {1} --password {2} {3} {4}",
                  commandType,username,password,repoUrl, destFolder);            
       
        return command;

    }//BuildArguments

    public static void WriteLogLine(string repoName, string logText)
    {
        string logFolder = Path.Combine(_startupPath, LOGDIRECTORY_NAME );
        if ( ! Directory.Exists(logFolder) )
            Directory.CreateDirectory( logFolder );

        string logFile = Path.Combine( logFolder, repoName + LOGFILE_EXTENSION );
        string logLine = 
		String.Format( "[{0}] {1}\r\n", DateTime.Now.ToString(), logText );

        File.AppendAllText( logFile, logLine , Encoding.UTF8);

    }//WriteLogLine

}//class
}//namespace

Main void

static void Main(string[] args)
{
    //
    //Expecting six commandline parameters 
    //Usage : SVNPostCommit username password repoURL destFolder svn location repoName
    try
    {
        //Console.ReadLine();
        
        if ( args.Length == 0 ) 
           PrintUsage();
        
        string repoUrl = args[2];
        string repoName = args[5];
         string destFolder = args[3];
        
        string svnExePath = args[4];
        
        SvnHelper.ExecuteSvnCommand( svnExePath, destFolder, 
				repoName, repoUrl, args[0], args[1] ); 
     }
    catch (Exception ex)
    {
        const string LOGFILE = "Application";
        SvnHelper.WriteLogLine(LOGFILE, string.Format
				(FORMAT_ERROR, DateTime.Now.ToString()));
        SvnHelper.WriteLogLine(LOGFILE, ex.Message);
    }
}

SVNPostCommitConfiguration.exe helps you to manage the saved post-commit hooks. It uses an XML file as the database.

History

  • 30th March, 2009: Initial post

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Ahmet Göktaş
Software Developer Istanbul Bilgi University
Turkey Turkey
- Software developer from İstanbul/Turkey
- Programmed with C#.NET, ASP.NET, ASP, PHP, T-SQL
- SQL Server Administration
- Experiencing about NHibernate

Comments and Discussions

 
GeneralNot working Pinmemberluisthesaint4-Oct-10 14:02 
GeneralBranch vs Trunk PinmemberPancini Paolo28-May-09 21:41 
GeneralRe: Branch vs Trunk PinmemberAhmet Göktaş28-May-09 22:59 
GeneralA bit more context please PinmemberThomas Weller30-Mar-09 8:17 
Hi Ahmet,
 
while your 'article' is not bad in itself, it is totally lacking any kind of context, such as e.g.:
- What is a SVN hook?
- Why would I want to use this mechanism?
- What are my possibilites to write one myself?
- Where do I need to install it, how to name it?
etc.
 
What you are posting here, isn't really an article but a pure code snippet that would be only useful for somebody who already knows exactly what he/she needs and is in search of exactly that...
 
Regards
Thomas
 
www.thomas-weller.de
 
Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the Universe trying to produce bigger and better idiots. So far, the Universe is winning.
Programmer - an organism that turns coffee into software.


General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web01 | 2.8.140827.1 | Last Updated 14 Apr 2009
Article Copyright 2009 by Ahmet Göktaş
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid