File Coverage

blib/lib/SVN/Hooks.pm
Criterion Covered Total %
statement 16 18 88.8
branch n/a
condition n/a
subroutine 6 6 100.0
pod n/a
total 22 24 91.6


line stmt bran cond sub pod time code
1             package SVN::Hooks;
2             # ABSTRACT: Framework for implementing Subversion hooks
3             $SVN::Hooks::VERSION = '1.28';
4 1     1   4 use strict;
  1         1  
  1         28  
5 1     1   3 use warnings;
  1         6  
  1         19  
6              
7 1     1   4 use File::Basename;
  1         1  
  1         65  
8 1     1   413 use File::Spec::Functions;
  1         606  
  1         64  
9 1     1   4 use Data::Util qw(:check);
  1         2  
  1         114  
10 1     1   841 use SVN::Look;
  0            
  0            
11              
12             use Exporter qw/import/;
13              
14             our @EXPORT = qw/run_hook POST_COMMIT POST_LOCK POST_REVPROP_CHANGE
15             POST_UNLOCK PRE_COMMIT PRE_LOCK PRE_REVPROP_CHANGE
16             PRE_UNLOCK START_COMMIT/;
17              
18             our @Conf_Files = (catfile('conf', 'svn-hooks.conf'));
19             our $Repo = undef;
20             our %Hooks = ();
21              
22             sub run_hook {
23             my ($hook_name, $repo_path, @args) = @_;
24              
25             $hook_name = basename $hook_name;
26              
27             -d $repo_path or die "not a directory ($repo_path): $_\n";
28              
29             $Repo = $repo_path;
30              
31             # Reload all configuration files
32             foreach my $conf (@Conf_Files) {
33             my $conffile = file_name_is_absolute($conf) ? $conf : catfile($Repo, $conf);
34             next unless -e $conffile; # Configuration files are optional
35              
36             # The configuration file must be evaluated in the main:: namespace
37             package main;
38             $main::VERSION = '1.28';
39             unless (my $return = do $conffile) {
40             die "couldn't parse '$conffile': $@\n" if $@;
41             die "couldn't do '$conffile': $!\n" unless defined $return;
42             die "couldn't run '$conffile'\n" unless $return;
43             }
44             }
45              
46             # Substitute a SVN::Look object for the first argument
47             # in the hooks where this makes sense.
48             if ($hook_name eq 'pre-commit') {
49             # The next arg is a transaction number
50             $repo_path = SVN::Look->new($repo_path, '-t' => $args[0]);
51             } elsif ($hook_name =~ /^(?:post-commit|(?:pre|post)-revprop-change)$/) {
52             # The next arg is a revision number
53             $repo_path = SVN::Look->new($repo_path, '-r' => $args[0]);
54             }
55              
56             foreach my $hook (@{$Hooks{$hook_name}}) {
57             if (is_code_ref($hook)) {
58             $hook->($repo_path, @args);
59             } elsif (is_array_ref($hook)) {
60             foreach my $h (@$hook) {
61             $h->($repo_path, @args);
62             }
63             } else {
64             die "SVN::Hooks: internal error!\n";
65             }
66             }
67              
68             return;
69             }
70              
71             ## no critic (Subroutines::ProhibitSubroutinePrototypes)
72              
73             # post-commit(SVN::Look)
74              
75             sub POST_COMMIT (&) {
76             my ($hook) = @_;
77             push @{$Hooks{'post-commit'}}, sub { $hook->(@_); };
78             return;
79             }
80              
81             # post-lock(repos-path, username)
82              
83             sub POST_LOCK (&) {
84             my ($hook) = @_;
85             push @{$Hooks{'post-lock'}}, sub { $hook->(@_); };
86             return;
87             }
88              
89             # post-revprop-change(SVN::Look, username, property-name, action)
90              
91             sub POST_REVPROP_CHANGE (&) {
92             my ($hook) = @_;
93             push @{$Hooks{'post-revprop-change'}}, sub { $hook->(@_); };
94             return;
95             }
96              
97             # post-unlock(repos-path, username)
98              
99             sub POST_UNLOCK (&) {
100             my ($hook) = @_;
101             push @{$Hooks{'post-unlock'}}, sub { $hook->(@_); };
102             return;
103             }
104              
105             # pre-commit(SVN::Look)
106              
107             sub PRE_COMMIT (&) {
108             my ($hook) = @_;
109             push @{$Hooks{'pre-commit'}}, sub { $hook->(@_); };
110             return;
111             }
112              
113             # pre-lock(repos-path, path, username, comment, steal-lock-flag)
114              
115             sub PRE_LOCK (&) {
116             my ($hook) = @_;
117             push @{$Hooks{'pre-lock'}}, sub { $hook->(@_); };
118             return;
119             }
120              
121             # pre-revprop-change(SVN::Look, username, property-name, action)
122              
123             sub PRE_REVPROP_CHANGE (&) {
124             my ($hook) = @_;
125             push @{$Hooks{'pre-revprop-change'}}, sub { $hook->(@_); };
126             return;
127             }
128              
129             # pre-unlock(repos-path, path, username, lock-token, break-unlock-flag)
130              
131             sub PRE_UNLOCK (&) {
132             my ($hook) = @_;
133             push @{$Hooks{'pre-unlock'}}, sub { $hook->(@_); };
134             return;
135             }
136              
137             # start-commit(repos-path, username, capabilities, txt-name)
138              
139             sub START_COMMIT (&) {
140             my ($hook) = @_;
141             push @{$Hooks{'start-commit'}}, sub { $hook->(@_); };
142             return;
143             }
144              
145             ## use critic
146              
147             1; # End of SVN::Hooks
148              
149             __END__