File Coverage

blib/lib/SVN/Hook.pm
Criterion Covered Total %
statement 24 73 32.8
branch 0 24 0.0
condition 0 2 0.0
subroutine 8 17 47.0
pod 1 7 14.2
total 33 123 26.8


line stmt bran cond sub pod time code
1             package SVN::Hook;
2 1     1   1014 use strict;
  1         3  
  1         34  
3 1     1   4 use warnings;
  1         2  
  1         52  
4             our $VERSION = '0.28';
5              
6             =head1 NAME
7              
8             SVN::Hook - Managing subversion hooks
9              
10             =head1 SYNOPSIS
11              
12             my $hooks = SVN::Hook->new({ repospath => '/path/to/repos' });
13              
14             $hooks->init($_) for SVN::Hook->ALL_HOOKS;
15              
16             my $pre_commit = $hooks->scripts('pre-commit');
17             print $_->path."\n" for (@$pre_commit);
18              
19             =head1 DESCRIPTION
20              
21             C provides a programmable interface to manage hook scripts
22             for Subversion. See L for the CLI usage.
23              
24             =cut
25              
26 1     1   14 use base 'Class::Accessor::Fast';
  1         3  
  1         729  
27             __PACKAGE__->mk_accessors(qw(repospath));
28              
29 1     1   3786 use SVN::Hook::Script;
  1         3  
  1         8  
30 1         62 use constant ALL_HOOKS =>
31             qw
32 1     1   38 pre-lock pre-revprop-change pre-unlock start-commit>;
  1         2  
33              
34 1     1   6 use Cwd 'abs_path';
  1         1  
  1         80  
35             sub _this_perl {
36 0     0     return join(' ', $^X, map { "-I$_" } map { abs_path($_) } @INC);
  0            
  0            
37              
38             }
39              
40 1     1   871 use File::Spec::Functions 'catfile';
  1         749  
  1         66  
41 1     1   6 use Path::Class;
  1         2  
  1         711  
42             sub hook_path {
43 0     0 0   my ($self, $hook) = @_;
44 0           return Path::Class::Dir->new($self->repospath)->subdir('hooks')->file($hook);
45             }
46              
47             sub new {
48 0     0 1   my $class = shift;
49 0           my $self = $class->SUPER::new(@_);
50 0 0         die $self->repospath." is not a svn repository.\n"
51             unless -e catfile($self->repospath, 'format');
52 0           return $self;
53             }
54              
55             sub init {
56 0     0 0   my ($self, $hook) = @_;
57 0           my $path = $self->hook_path($hook);
58 0 0         die "There is already $hook file.\n" if -e $path;
59              
60 0   0       my $svnlook = $ENV{SVNLOOK} || 'svnlook';
61 0           $self->_install_perl_hook( $path, <<"EOF");
62             # Generated by svnhook version $VERSION.
63             # This $hook hook is managed by svnook.
64              
65             BEGIN {
66             \$ENV{SVNLOOK} = "$svnlook";
67             eval 'require SVN::Hook::Redispatch; 1' or exit 0;
68             }
69             use SVN::Hook::Redispatch {
70             '' => '',
71             # Add other dispatch mapping here:
72             # 'foo' => 'bar'
73             # will run scripts under _$hook/bar/ when commit are solely within foo.
74             }, \@ARGV;
75             exit 0;
76             EOF
77              
78 0 0         mkdir catfile($self->repospath, 'hooks', "_$hook") or die $!;
79             }
80              
81             sub _install_perl_hook {
82 0     0     my ($self, $hook_file, $perl_code) = @_;
83 0           my $perl = _this_perl();
84 0 0         open my $fh, '>', $hook_file or die "$hook_file: $!";
85 0           print $fh "#!$perl\n$perl_code";
86 0           close $fh;
87 0 0         chmod 0755, $hook_file or die $!;
88             }
89              
90             sub scripts {
91 0     0 0   my ( $self, $hook ) = @_;
92 0           SVN::Hook::Script->load_from_dir($self->hook_path("_$hook"));
93             }
94              
95             sub run_hook {
96 0     0 0   my $self = shift;
97 0           my $hook = shift;
98 0 0         my $ignore_error = $hook =~ m/^post-/? 1 : 0;
99              
100 0           $self->run_scripts( [grep { $_->enabled } $self->scripts($hook)],
  0            
101             $ignore_error, @_ );
102             }
103              
104             sub run_scripts {
105 0     0 0   my $self = shift;
106 0           my $scripts = shift;
107              
108 0           my $ignore_error = shift;
109              
110 0           for my $script (@$scripts) {
111 0           system($script->path, @_);
112              
113 0 0         if ($? == -1) {
    0          
114 0           die "Failed to execute $_: $!.\n";
115             }
116             elsif ($?) {
117 0 0         exit ($? >> 8) unless $ignore_error;
118             }
119             }
120 0           return 0;
121             }
122              
123             sub status {
124 0     0 0   my $self = shift;
125 0           my $result;
126 0           for (ALL_HOOKS) {
127 0           my $path = $self->hook_path($_);
128 0 0         if (-x $path) {
129 0 0         open my $fh, '<', $path or die $!;
130 0           local $/;
131 0 0         if (<$fh> =~ m/managed by svnook/) {
132 0           $result->{$_} = scalar $self->scripts($_);
133 0           next;
134             }
135             }
136 0           $result->{$_} = undef;
137             }
138 0           return $result;
139             }
140              
141             =head1 TODO
142              
143             =over
144              
145             =item *
146              
147             CLI to manage enable/disable scripts
148              
149             =item *
150              
151             CLI to display and dry-run for subdir scripts for redispatch
152              
153             =item *
154              
155             More tests and doc
156              
157             =back
158              
159             =head1 LICENSE
160              
161             Copyright 2007 Best Practical Solutions, LLC.
162              
163             Licensed under the Apache License, Version 2.0 (the "License");
164             you may not use this file except in compliance with the License.
165             You may obtain a copy of the License at
166              
167             http://www.apache.org/licenses/LICENSE-2.0
168              
169             Unless required by applicable law or agreed to in writing, software
170             distributed under the License is distributed on an "AS IS" BASIS,
171             WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
172             See the License for the specific language governing permissions and
173             limitations under the License.
174              
175             =head1 AUTHORS
176              
177             Chia-liang Kao Eclkao@bestpractical.com
178              
179             =cut
180              
181             1;