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"; }