Introduction
Backing up your SVN repositories is a good idea. Automating it using Powershell and svnadmin is even better.
Background
I have been using Subversion as my main source control tool for a while. It has worked out very well for me. During this time, I have never lost anything that I wasn't intentionally trying to lose. But, it is always a good practice to back up “early and often”. I find that if I don't automate a process like backing up my repositories, I tend to forget about it until it’s too late.
With that in mind, I created a Powershell script that I could schedule to run daily and make sure this is taken care of. I decided to use Powershell because of the power it brings to the Windows environment. As a .NET developer, I like its ability to use the .NET Framework. I am by no means a Powershell Guru, but I was able to get this going by piecing together different examples from the Microsoft website.
Using the Code
My assumptions with this article are that you are already familiar with Powershell and with Subversion. If not, a good starting point for Powershell is here. Information about Subversion is located here.
Before you can use this script, you will need to have access to svnadmin.exe. We will use svnadmin’s “hotcopy
” function to backup the SVN repositories. I use TortoiseSVN and it does not include svnadmin. I was able to get it from the latest version of SlikSVN.
What this script does is it will look in a directory that you set and it will loop through each directory under it making the assumption that it is a repository. It will run svnadmin to copy the repository a temp directory. Then it will zip the copy and add a timestamp to the filename and save it in the backup directory that you will also set. It will also remove any older backup files based on the number of days since it was created.
The Script
Download the script and take a look at it. The first thing to notice is that all of the functions have to be at the top of the script file. Scroll down to where the logic will begin executing. The things that gave me the most trouble were getting Powershell to execute svnadmin and zipping a directory. It turns out that the “&” and placing everything into string
variables was important to running an executable with parameters from within Powershell. The zip function is akin to using the send to compressed folder function in Windows explorer.
Set up Variables
Located at the top of the script file find and modify these variables to get this to work for your environment.
$RepositoryPath = "\\SVN\Repositories"
$RepoBackupPath = \\SVN\Backups\
$svnAdminexe = "C:\Utils\SlikSvn\bin\svnadmin"
$DaysToKeepBackups = 14
In the interest of using “configuration over convention”, the $RepositoryPath
variable is the location of the repositories you want to backup. All of your repositories must be in this directory for this script to back them up.
The $RepoBackupPath
variable is the location where all of the zipped files will be saved. They will all be in separate directories based on repository name.
$svnAdminexe
is self explanatory. It’s the location of svnadmin.exe.
$DaysToKeepBackups
is also self explanatory. This script will delete any backup files with a create date older than the number in days set here unless you set it to 0, then nothing is removed.
Trouble Running the Script
If you have trouble getting it to run and you see this message “The execution of scripts is disabled on this system. Please see "Get-Help about_signing" for more details.” Check out this page about signing your scripts.
Update
Some my repositories were starting to get to the point where the zip function was taking more than a couple of seconds to complete. Since I am using Windows task scheduler to run this, my script was ending before the last zip completed which aborted the zip.
The problem is a result of the .copyHere
method being asynchronous and it was not having enough time to complete before the task ended.
$_zipName.copyHere($_dirToZip)
One work around for this is to sleep for a certain amount of time guessing how long the longest zip will take. I decide to also check to see if all the files I am compressing had been added to the zip. Since I am sending a directory to the zip file, the count when done will be one. The following code will wait until the zip file has at least one item:
do {
$zipCount = $_zipName.Items().count
"Waiting for compression to complete ..."
Start-sleep -Seconds 2
}
While($_zipName.Items().count -lt 1)
I added a wait of 2 seconds between loops to give it some extra time to finish. I also added a 5 second wait at the end of the script file because even after doing this workaround, the task was still ending too quickly to let the compression complete.