Using the Subversion ‘svnlook tree’ command from Perl

After switching the GBdirect website to being stored in Subversion I thought I needed to put together some Perl to parse the output of the svnlook tree command. Now, it turns out that this command doesn't do what I want, but it might be useful to someone else. The command shows the complete hierarchy of files and directories stored in a subversion repository in the current revision, or any particular revision you want if you supply the -r option. It accesses the repository directly, so unlike the svn commands, you have to supply a full path to the repository, not a URL.

The svnlook tree command prints one line for each directory or file that exists in the revision you're looking at. Single-space indentation is used to indicate how deep in the directory hierarchy you are on each line. For example:

$ svnlook tree /var/lib/svn/website
/
 trunk/
  Themes/
   gbdirect.xcf
   ebusiness-banner.png
   gbdirect.gif
   GBdirect.gif
   banner.png
   printer-friendly-12x12.png
   Quarters.css
  Content/
   open-source/
    index.src.html
  ...

The command actually goes through all versions of the tree, including all your branches and tags. Usually you'll want to ignore anything outside the trunk.

So anyway, here's some code I had spare to run the command and read it's output:

my $SVN_REPOS_PATH = '/var/lib/svn/website';

# We'll put each path in this hash as the key, with the
# value being 'F' for file, or 'D' for directory.
my %path;

# This is a stack of directories, for keeping track of where
# we are in the hierarchy.  It's necessary because only one
# path component is shown on each line.
my @path;

# Run the command and read output from it.
open my $tree, '-|', "svnlook tree $SVN_REPOS_PATH"
  or die "$0: error reading from 'svnlook tree' command: $!\n";

while (<$tree>) {
    chomp;

    # Directories are always shown with '/' after their names.
    if (/\/$/) {
        /^( *)(.*)\/$/
          or die "$0: bad line $. ($_) from 'svnlook tree'.\n";
        my ($depth, $dirname) = (length $1, $2);

        # Adjust the @path stack for our new place in the tree.
        pop @path while @path && @path >= $depth;
        push @path, $dirname;

        # We seem to be using @path, %path, and $path all at
        # once here.  Pay attention!
        my $path = join '/', @path;
        $path{$path} = 'D';
    }
    else {
        s/^\s+//;
        my $path = join '/', @path;
        $path{"$path/$_"} = 'F';
    }
}

# Print the lot out to prove that it worked.
foreach (sort keys %path) {
    print "$path{$_} $_\n";
}

< No-brainer technologies | Migrating from CVS to Subversion >

Miniblog

(nuggets of inanity)

Tuesday Apr 24th 2007, 16:54 »
Just took the annual web design survey that AListApart do. I don't realy consider myself to be a web designer, but I have been doing a lot of HTML and CSS lately.
Monday Apr 23rd 2007, 18:23 »
Strange, there appears to be a bare-knuckle boxing match going on in the field outside my flat. Wish they wouldn't make so much noise about it.
Thursday Mar 1st 2007, 18:47 »
“In its written form, Hebrew has no vowels, making it the ideal language for texting.”
—Said in jest on some Radio 4 programme just now.

Archive: 2007 · 2006 · 2005 · 2004
Feed