RepositoryHosting.com backup script
by Sam on Mar.07, 2010, under Scripts
We all know the importance of backups, and backups of backups, but even some of the most respected developers occasionally fail to keep their stuff backed up, as we recently learned… So here’s my tiny contribution to the subject, specifically for anyone using the amazingly low-cost RepositoryHosting.com for their SCM (it supports Git, Mercurial and SVN) and project management (by way of Trac).
Whilst RepositoryHosting.com already offers automatic copying of backups to an Amazon S3 bucket, it’s always best to not rely on a single backup location, as many stories confirm. In this light, I whizzed up the following script which you can use to pull your backups down to your local workstation or office file server. It’s a bit rough around the edges, and doesn’t handle errors, so you will have to check the results after each run, but it sure beats logging in and manually downloading the files through your browser each day… (Thanks to Matt White at RepositoryHosting.com for changing the backup URLs to make them more predictable, and suggesting the initial idea that spawned this script.)
This script relies on a Bash shell with cURL available, like the one that comes with msysgit if you’re using Windows. You’ll also need to make sure you set up daily backups in your RepositoryHosting.com project’s settings.
I’m no expert on Bash shell scripting, so if you can think of any improvements (to make the script more concise or handle errors etc.) then please feel free to educate us all in the comments!
Here’s the script… (I named it “backup.sh”). See the comments in-line for configuration instructions.
#!/bin/sh
# RepositoryHosting.com backup download script
#
# This script downloads your daily RepositoryHosting.com backups.
##################################################################
##
### Configuration
##
# Subdomain of your repository
RepoSubdomain=mysubdomain
# Local backup directory
BackupDir=~/Backups/RepositoryHosting.com
# RepositoryHosting.com administrator credentials
Username=myadminusername
Password=mypassword
# List of project names (for naming the backups, the order of these
# equate to the project IDs in your RepositoryHosting.com account.)
ProjectNames=(
MyProject
CoolProject
OtherProject
)
# Backup date formats (e.g. "+%Y%m%d" for YYYYMMDD, or "+%d" for DD)
# NOTE: This affects the number of backups that will be kept, e.g.
# "+%d" will store a month's worth of backups, each numbered as the
# day of the month when it was created, "+%Y%m%d will keep an infinite
# number of backups, as each one will be uniquely dated.
#
# NOTE: This is used only if you specify @Date in the filename format.
#
FileDateFormat="+%d"
# Subdirectory date format (same as above, used only if you specify
# @Date in your SubDirFormat).
#
#SubDirDateFormat="+%m"
# Backup subdirectory format. If specified will place your backups into
# a separate subdirectory for each project.
#
SubDirFormat="@ProjectName"
# Backup file name format (e.g. "@ProjectName.@Date").
# This will automatically be prepended with the $BackupDir/$SubDir/ and
# appended with ".tar.gz".
#
FileNameFormat="@ProjectName.@Date"
##
### End configuration (no need to edit past here)
##
##################################################################
# Resolve URLs
RepoBaseUrl="https://$RepoSubdomain.repositoryhosting.com"
SessionStartUrl="$RepoBaseUrl/session"
ProjectsBaseUrl="$RepoBaseUrl/projects"
# Messages
echo -e "\nDownloading today's backups \n\tFrom:\t$RepoBaseUrl"\
"\n\tTo:\t$BackupDir"
# Cookie file name
CookieFileName="cookies.txt"
# Create backup directory if it doesn't exist
mkdir -p "$BackupDir"
# Go to backup directory
cd "$BackupDir"
# Login
echo -e "\nLogging in..."
curl -sS -X POST $SessionStartUrl -d \
"username=$Username&password=$Password" -c $CookieFileName -o /dev/null
# Copy project backups
ProjectNumber=0
while [ "x${ProjectNames[ProjectNumber]}" != "x" ]
do
# Specify & create backup subdirectory for this project
ProjectBackupSubdir=\
"${SubDirFormat//@ProjectName/${ProjectNames[ProjectNumber]}}"
ProjectBackupSubdir=\
"${ProjectBackupSubdir//@Date/`date $SubDirDateFormat`}"
test "x$ProjectBackupSubdir" != "x" && mkdir -p $ProjectBackupSubdir && \
ProjectBackupSubdir="$ProjectBackupSubdir/"
# Resolve backup filename
ProjectBackupFile=\
"${FileNameFormat//@ProjectName/${ProjectNames[ProjectNumber]}}"
ProjectBackupFile=\
"${ProjectBackupFile//@Date/`date $FileDateFormat`}.tar.gz"
# Copy project backup
echo -e "\nCopying ${ProjectNames[ProjectNumber]} backup to "\
"\n\t$ProjectBackupSubdir$ProjectBackupFile"
curl -L "$ProjectsBaseUrl/$[ProjectNumber+1]/backups/`date +%Y/%m/%d/00`" \
-b $CookieFileName -# \
-o "$BackupDir/$ProjectBackupSubdir$ProjectBackupFile"
ProjectNumber=$[$ProjectNumber+1]
done
# Delete cookies.txt
rm $CookieFileName
echo -e "\nFinished downloading backups!"
If you want to launch this easily in Windows, you can use a simple batch file…
REM Start the RepositoryHosting.com backup download script C: "\Program Files (x86)\Git\bin\sh.exe" -login -c /c/Users/Sam/backup.sh
Automatic properties in VB.NET
by Sam on Sep.01, 2009, under ASP.NET, VB.NET
The mind sometimes boggles at Microsoft’s implementation of VB.NET. One of these logic-defying mysteries is why VB.NET, in the .NET Framework 3.5, does not support automatic properties using similar syntax to C#. Automatic properties are a way to generate a private field, along with a two accessor methods (get and set) with independant levels of data hiding. They look like this in C#…
// A publically readable but only privately writeable string
public string aStringProperty { get; private set; }
The code above is expanded by the compiler to create a private string field, a private set method and a public get method, something that would look something akin to this (with the addition of having the ‘=’ operator overloaded to provide automatic calls to these accessor methods when necessary)…
// A publically readable but only privately writeable string
private string _StringProperty;
public string get_StringProperty { return _aStringProperty; }
private string set_StringProperty { _aStringProperty = value; }
However in VB.NET the situation is much worse! Look at this mess…
Private _StringProperty As String Public Property StringProperty As String Get Return _StringProperty End Get Private Set(ByVal value As String) _StringProperty = value End Set End Property
That’s right, 9 lines of code in VB.NET, that can be written using only 1 in C#. And VB is meant to be easier?!
What’s so great about properties anyway?
One of the main reasons I use properties as opposed to just public data members in my ASP.NET applications is that once you have defined a web user control with public properties, these properties added to the Intellisense database, helping you out when inserting the web user control into another control or page. This is mighty useful when writing a control that will be consumed by people who don’t know, or shouldn’t need to know the internal workings of the control. However, simple public fields, i.e. those declared in VB.NET thusly…
Public SomePublicField As String
…do not get this Intellisense treatment. They can be manually typed into the aspx code as attributes to the web user control, however without Intellisense to guide the way, many developers will thus assume that the attribute with this name is not available to them.
Maybe Microsoft should look into adding Intellisense support for such simple public data members? But I guess that’s something for the commenters to discuss! Even better would be proper automatic properties for VB.NET, as there seems to be something good about only exposing properly encapsulated properties to the aspx code.