Subversion Restore

A way to restore an svn repository from dumps of individual commits. This is a companion to the Subversion backup script.

#!/usr/bin/env ruby
floor = start_revision
ceiling = end_revision
 
floor.upto(ceiling) do |i|
  puts `gunzip #{i}.dump.gz`
  puts `svnadmin load /path/to/repos < #{i}.dump`
  puts `rm -f #{i}.dump`
end

Bare Bones Subversion Backup

This is a basic incremental Subversion backup script. It is meant to be run daily by cron. It requires Ruby.

There are many other excellent svn backup scripts out there that do way more than this one. But my goal was just to create something simple and hopefully easy to use.

The script checks that a dump of every revision in the repository exists, if not, it dumps the revision and gzips it.

#!/usr/bin/env ruby
# This program writes incremental backups from a Subversion repository to the filesystem

# Configure the paths to the svn repository and backup directory 
# full paths to the executables are not necessary if they are on the cron user's $PATH
config = {
  :backup_dir => "/path/to/backup/", # Path to backup directory
  :repos      => "/path/to/repos/",  # Path to SVN repository
  :svnlook    => "svnlook",          # Path to svnlook executable
  :svnadmin   => "svnadmin",         # Path to svnadmin executable
  :gzip       => "gzip"              # Path to gzip executable
}

# Dumps svn gzipped revisions incrementally.
def svn_dump(config)
  
  # Start revision
  oldest = 1

  # Get the youngest (most recent) revision
  youngest = `#{config[:svnlook]} youngest #{config[:repos]}`.to_i

  # Save start time
  output = `date`.chomp + " - Subversion backup started\n"
  
  # Check if the revision exists, if not, dump it to the filesystem
  oldest.upto(youngest) do |i|
    unless File.exist? "#{config[:backup_dir]}#{i}.dump.gz"
      if system "#{config[:svnadmin]} dump #{config[:repos]} -r #{i} --incremental 2>/dev/null | #{config[:gzip]} -9 > #{config[:backup_dir]}#{i}.dump.gz"
        output += "* Dumped revision #{i}\n"
      end
    end
  end
  
  output += `date`.chomp + " - Subversion backup complete"
end

# execute dump, writing to stdout for cron
puts svn_dump(config)

Block Sort TextMate Command

Here’s a quick TextMate command to take a document with double return separated blocks of text and sort them.

For example if you had some HTML block you wanted to sort like:

<p>
    Company B
    <br />Company description.
</p>

<p>
    Company A
    <br />Company description.
</p>

Running this through Block Sort would give you:

<p>
    Company A
    <br />Company description.
</p>

<p>
    Company B
    <br />Company description.
</p>

For the command settings, I have:

  • Input: Selected Text or Document
  • Output: Create New Document

And here is the command:

#!/usr/bin/env php 
<?php
$document = file_get_contents('php://stdin'); 
$blocks = explode("\n\n", $document); 
sort($blocks);

foreach ($blocks as $block)
{
    print $block . "\n\n";
}
?>

Notes on Jekyll

This site uses Jekyll as a publishing tool. These are my notes on getting it set up.

Installation

Installation was a pain, but only because I recently upgraded to Snow Leopard which broke my MacPorts rubygems install. Since rubygems is a decency of Jekyll, I could not install it until I fixed that. I’ve seen a number of ways to fix MacPorts after upgrading to Snow Leopard, but what worked best for me was just to wipe out the entire MacPorts directory by running sudo rm -Rf /opt/local, installing the latest version of MacPorts and reinstalling the packages I use.

After getting rubygems running again, installation was easy (the Jekyll wiki has all the details on installing the gem). I also went ahead and installed Pygments, for syntax highlighting. The easiest way to install is with MacPorts, however this means you also have install Python with MacPorts, which in turn seems to have just about every Unix utility and library on the planet as a dependency, so it takes a while.

Templates

I went through many of the sites using Jekyll listed on the GitHub wiki to get an idea on how to structure the project and to see how the Liquid Template system was implemented. From that I was able to start plugging template tags into my layouts.

I had some trouble getting date to show up on my individual post pages. I thought it was a post variable, but it is a actually a page variable when the post is the page, i.e. page.date. Another issue I had was actually displaying Liquid tags without them being parsed. I ended up creating a class, .liquid-tag, then wrapping the classified content with curly braces using jQuery: .

One unexpected thing I noticed is the Markdown interpreter used by Jekyll, Maruku, will make an empty tag self closing. This seems to cause the most problems with the <script> tag, which will usually be empty when you are referencing a JavaScript file. The workaround here is to insert a space between the opening and closing tags.

Some other observations I had were that you can use markdown or textile for a standard page as well i.e. my about page, but it has to have the right extension (.markdown .mkdn, .md for Markdown, .textile for Textile). Also, you can use Liquid template tags on a post or a page, not just a template.

Deployment

The easiest way to deploy a Jekyll site is probably just to push the generated HTML up to a server. The advantage of this is that you only need to have anything special running on your host. However the disadvantage is that you can only deploy from a machine that has Jekyll installed.

I wanted to be able to deploy from anywhere using git. I’ve been using Slicehost as a host, so installing all the necessary software was no problem since you get root access to your own VPS. After installation, I was able to clone my git repository and run Jekyll on the server. The Apache VirtualHost entry doesn't need anything special, just to be pointed to the _sites directory inside the cloned repository. For example:

<VirtualHost *:80>
    ServerName benubois.com
    ServerAlias www.benubois.com
    DocumentRoot /var/www/com.benubois/_site
    <Directory /var/www/com.benubois/_site>
        RewriteEngine on
        RewriteCond %{HTTP_HOST} ^www\.benubois\.com$ [NC]
        RewriteRule ^(.*)$ http://benubois.com/$1 [L,R=301]
    </Directory>
    <FilesMatch "\.(js|css|html|xml)$">
        SetOutputFilter DEFLATE
    </FilesMatch>
</VirtualHost>

In the future, I hope to update the setup so that a push to github will trigger a commit hook that will update the server automatically.

Drawbacks

There are some things that I don't like about the approach though. Since the site is generated infrequently, it rules out a lot of dynamic functionality.

Blog staples like comments and social network aggregation are commonly loaded through JavaScript. It’s bothersome to visit a page and be staring at a spinner while your browser downloads someones last five tweets or photos using JavaScript. I’d much prefer to have this work be done on the server side, cached and then served quickly, which is why I’m using Jekyll in the first place. You end up throwing away all the performance benefits you get from having a static site by forcing the client to do all the work. It seems like it might be possible to work around this by embedding other code in your templates, but there isn’t much built in support for these things.

Minor complaints aside, I’m really enjoying Jekyll. It’s a great mix of interesting technologies, built to be revision control friendly, lightweight and have excellent performance.

Delicious Shortwaves

Delicious has a feature I like. When you bookmark something, you have the option of assigning a keyword, similar to the Firefox Smart Keywords feature. For example if I wanted to assign a shortcut for Google, I would bookmark the url http://www.google.com/search?&q=%s, and assign the letter g. In this instance I could go the the location bar, type g peanut and I would be taken to the search results page for that excellent nut.

The advantage the Delicious implementation has over browser bound versions, is that it provides an easy way to synchronize all of your bookmarks, including keywords, across multiple computers by installing the Delicious Bookmarks plugin.

I prefer Safari to Firefox which means I can’t use any of this in my favorite browser. Fortunately there’s Shaun Inman’s Shortwave. Shortwave provides the same URL keyword functionality of Delicious, but does it using a JavaScript bookmarklet. This means it will work on just about any browser, including Safari for the iPhone.

Shortwave stores all of your keywords in a text file on your own webserver, so it will work from any location. However, I wanted a way to import my existing Delicious keywords AND an easy way to add new keywords. Using the Delicious Feeds API I'm able to do this. The process is straightforward. I query my bookmarks looking for a specific tag, then write the results to a text file in the format that Shortwave expects.

First I tagged all of the bookmarks I wanted with shortcut then uploaded the following script to my webserver and set cron to run it automatically once a day to keep it up-to-date with Delicious. For any future keywords I just have to remember to add the extra tag and it will be updated in my shortwave file.

Here is the script: