SVN::Web, Template::Plugin::{Subst, MultiFilter}

nik on 2005-11-09T11:03:52

As described in an earlier entry, new versions of SVN::Web escaped over the weekend. First there was 0.40, which contained the bulk of the new code. Then 0.41 followed when I realised I'd made a few packaging cock ups.

One of the things you can do with the new version is pass SVN commit messages through multiple TT filters. Each filter can decorate the commit message in some way -- recognise URLs, e-mail addresses, RT ticket numbers, subversion revision numbers, etc, and convert them in to hyperlinks.

Say you've written "Fixes rt#1234" in your commit message. You'd like "rt#1234" to link straight to your bug database.

I thought that would be easy. Obviously, in straight Perl it's just the equivalent of:

$msg =~ s/rt#(\d+)/$1/;

I was quite surprised that TT doesn't offer this functionality. The built in replace method/filter doesn't cut it, as it doesn't handle backreferences. The TT:

[% msg.replace('rt#(\d+)', '$1') %]

results in the literal $1 being inserted into the output instead of the expected back reference.

The two popular suggestions in the TT list archives are to either use s/// directly in a [% PERL %] block, or write a custom filter to do the specific search and replace.

But [% PERL %] blocks might not be enabled in every TT install. And writing multiple filters (one to recognise RT tickets, one for subversion revision numbers, one for Sourceforge tickets, ...) would rapidly get boring.

Hence, Template::Plugin::Subst. With it, you can write:

[% msg.subst('rt#(\d+)', '$1') %]

and it will do the right thing. And as well as working as vmethod, it also works as a filter, so you can use that syntax instead.

The other thing that TT can't easily and cleanly do is stack multiple filters together, ignoring the ones that aren't installed.

SVN::Web ships with a config file that specifies a number of TT plugins to filter log messages through (to convert them to HTML, and make various things in the log clickable). These include plugins that might not be installed. In TT you can't say "Run all these filters, ignoring the ones that aren't installed". Trying to use a missing plugin (sensibly) generates a run-time error.

So, SVN::Web's log_msg_filter() implements this functionality. And the default SVN::Web configuration file can safely specify several different plugins, without the user having to worry about whether or not they're installed. Without them, everything works, and if they are installed then the user gets a slightly nicer output.

At the moment this is hardcoded in to SVN::Web, but I plan on releasing Template::Plugin::MultiFilter in the near future so that others can easily use this functionality.


example config lines

finn on 2006-05-12T23:33:28

It would be helpful if you could post the exact lines in the config.xml file that will result in the transformation of rt#1234 in to a link. (Or better yet, include them in the documentation.) The SVN::Web documentation and this post point in the right direction, but a specific example would be great for those of us not as familiar with the particularities of Template Toolkit.

Re:example config lines

finn on 2006-05-12T23:34:20

config.yaml, I meant.

Re:example config lines

nik on 2006-07-04T15:36:19

Assuming you have Template::Plugin::Subst installed, the following in config.yaml will do it.
log_msg_filters:
  ...
  - name: Subst
    filter: filter
    opts:
      pattern: 'rt#(\d+)'
      replacement: '<a href="http://rt.cpan.org/NoAuth/Bug.html?id=$1">rt#$1</a>'
  ...