<grin>I've had a lot of free time lately. So much, in fact, that I don't know what to do with myself.</grin>
With this copious free time I've dabbled a bit in Subversion. I'd experimented with it before, but not on a grand scale. In fact, I've used SourceSafe (which in my experience isn't as bad as people would have you believe), SourceGear's Vault (which I use presently and absolutely love), and I've experimented a bit with CVS, Perforce, et al. I've been very impressed with Subversion and thought I'd give it a whirl for all of my personal software development. If nothing else, I get a good, rock-solid SCM system and a more well-rounded understanding of this other system.
Thus, with that in mind, I set out to establish a new source code control system.
First of all, I downloaded the current version (version 1.4.3) and installed it on my server. This gave me the %ProgramFiles%\Subversion folder and added the %ProgramFiles%\Subversion\bin folder to my path.
Next, I don't ever have to want to logon to that server interactively just to start the application 'listening'. So, I set it up as a service with the following command line:
sc.exe create svnserve binpath= "C:\Program Files\Subversion\bin\svnserve.exe --service --root C:\SVN" displayname= "SubVersion" depend= tcpip start= auto obj= "NT AUTHORITY\NetworkService"
(Note that there is no space before the equal sign for each parameter but there is one afterwards. Personally, I think this is a silly construct for the sc.exe command, but maybe it made the command line easier to deal with. Oh well, I didn't write it)
That statement will register the svnserve.exe application as an NT Service so in the event that I have to restart the server the service will automatically start.
Next, I created the root folder for my repositories (which for purposes of this example is C:\SVN) and granted the NT AUTHORITY\NetworkService account the appropriate rights to it.
The very first thing that I didn't really care for with respect to Subversion was the way it does authentication. I wanted to have a single source for all authentication and not maintain it for each repository. While not a show stopper, I don't like the idea of having to change n passwd files (one for each repository) in the event my password changes. Now that I mention it, I don't like the idea of having to put it in a file at all (especially in clear text!) - there are oh so many security issues with this. I have seen some articles on how to set it up to use Windows Authentication (which would be ideal in my situation), but I'm not that far along with it yet.
Nonetheless, I set up a simple folder named “C:\SVN\(auth)” to hold the authz and passwd files (I like to use parens on folder names like this so they filter to the top of my directory lists and stand out).
I then edited the files accordingly:
authz
[/]
Aaron = rw
passwd
[users]
Aaron = xxxxxx
As is traditional with SCM systems (and in keeping with that tradition), each repository has three folders: \trunk, \tags, and \branches. However, when you create a repository those don't get created automatically for you. Rather than always remembering to create these for each repository, I created a template folder called “C:\SVN\(template_repo)” which contains the structure and helper files for new repositories. In addition to the folders there's a simple svnserve.conf configuration file that is designed to replace the automatically created svnserve.conf file in each new repository and point back to the (auth) folder. That way, each new repository uses the same catalog of credentials. Then I have a batch file that simplifies the creation of a repository and automatically imports the folder structure, replaces the files, and deletes extraneous ones. I put this batch file in the root C:\SVN folder:
CreateRepo.bat
@echo off
if "%1" == "" goto USAGE
echo Creating SVN repository "%1".
svnadmin create "%1"
echo Establishing default credentials.
copy "(template_repo)\svnserve.conf" "%1\conf\svnserve.conf" > NUL
del "%1\conf\authz." > NUL
del "%1\conf\passwd." > NUL
echo Building folder structure.
svn import "(template_repo)\folders" svn://%COMPUTERNAME%/%1 --message "Initialize folder structure for repository." --quiet
echo Done. "%1" repository created.
goto DONE
:USAGE
echo.
echo Invalid usage. Please specify a repository name.
:DONE
I guess the last thing I needed to do to set it all up was to configure my backups. There's not much point in having an SCM system without a good backup system in place. Well, everything done to this point was done with a purpose. I intentionally put everything in the C:\SVN folder to have a single point of reference for all repositories and file, and to simplify backups. I can simply walk the directories therein and back them up. If I add a new repository it's automatically included in my backups and there's nothing more to set up.
In the Subversion documentation they warn against simply 'copying' the repository tree or your backup might be completely invalid and useless. Instead, you're recommended to run svnadmin.exe with the hotcopy argument.
I wrote a very simple VBScript (appropriately named BackupSVN.vbs) to take care of my backups. I put this file one level out of the repository root (e.g., C:\ for this example).
Essentially the script file enumerates all of the directories, determining whether they are Subversion repositories or not. For those that are, it runs svnadmin hotcopy. For those that aren't, it simply runs xcopy. All backups are then made to the \SVNBackup\SVN folder. The script then executes WinRar to archive the tree into a date-stamped .rar file which is placed in the \SVNBackup folder.
Though it doesn't do it yet, I'll soon have this archiving the .rar files to a remote store (e.g., a network share) because a backup on the same physical drive isn't much good if the drive crashes.
BackupSVN.vbs
' ************************************************************************************
Dim fso, shell, f, root, fileName
Set fso = CreateObject("Scripting.FileSystemObject")
Set shell = CreateObject("WScript.Shell")
Set root = fso.GetFolder(".\SVN")
'
' copy each folder to the svn backup directory
'
For Each f in root.SubFolders
if ( IsSVNFolder(f) ) then
cmd = "svnadmin hotcopy ""SVN\" + f.Name + """ ""SVNBackup\SVN\" + f.Name + """"
else
cmd = "xcopy ""SVN\" + f.Name + "\*.*"" ""SVNBackup\SVN\" + f.Name + """ /I /E /Y /H"
end if
Call Exec(cmd)
next
'
' copy each file in the \SVN directory to the backup directory and archive it
'
fileName = """SVNBackup\SVNBackup (" + Replace(FormatDateTime(Date, 2), "/", "-") + ").rar"""
Call Exec("xcopy SVN\*.* SVNBackup\SVN /Y")
Call Exec("""%ProgramFiles%\WinRar\rar.exe"" a " + fileName + " SVNBackup\SVN\*.* /ep1 /r /df")
fso.DeleteFolder(".\SVNBackup\SVN")
' ************************************************************************************
Function Exec(cmd)
Dim result
Set result = shell.Exec(cmd)
Do While ( result.Status = 0 )
WScript.Sleep 100
Loop
End Function
Function IsSVNFolder(folder)
IsSVNFolder = HasFolder(f, "conf")
End Function
Function HasFolder(folder, name)
Dim f
for each f in folder.SubFolders
if ( f.Name = name ) then
hasFolder = true
exit function
end if
next
hasFolder = false
End Function
I simply set this VBScript to run nightly and I'm off to the races.