line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package SVN::Hooks::CheckStructure; |
2
|
|
|
|
|
|
|
# ABSTRACT: Check the structure of a repository. |
3
|
|
|
|
|
|
|
$SVN::Hooks::CheckStructure::VERSION = '1.34'; |
4
|
1
|
|
|
1
|
|
33940
|
use strict; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
55
|
|
5
|
1
|
|
|
1
|
|
8
|
use warnings; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
45
|
|
6
|
|
|
|
|
|
|
|
7
|
1
|
|
|
1
|
|
7
|
use Carp; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
290
|
|
8
|
1
|
|
|
1
|
|
991
|
use Data::Util qw(:check); |
|
1
|
|
|
|
|
1474
|
|
|
1
|
|
|
|
|
324
|
|
9
|
1
|
|
|
1
|
|
697
|
use SVN::Hooks; |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
use Exporter qw/import/; |
12
|
|
|
|
|
|
|
my $HOOK = 'CHECK_STRUCTURE'; |
13
|
|
|
|
|
|
|
our @EXPORT = ($HOOK, 'check_structure'); |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
my $Structure; |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
sub CHECK_STRUCTURE { |
19
|
|
|
|
|
|
|
($Structure) = @_; |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
PRE_COMMIT(\&pre_commit); |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
return 1; |
24
|
|
|
|
|
|
|
} |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
sub _check_structure { |
27
|
|
|
|
|
|
|
my ($structure, $path) = @_; |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
@$path > 0 or croak "Can't happen!"; |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
if (is_string($structure)) { |
32
|
|
|
|
|
|
|
if ($structure eq 'DIR') { |
33
|
|
|
|
|
|
|
return (1) if @$path > 1; |
34
|
|
|
|
|
|
|
return (0, "the component ($path->[0]) should be a DIR in"); |
35
|
|
|
|
|
|
|
} elsif ($structure eq 'FILE') { |
36
|
|
|
|
|
|
|
return (0, "the component ($path->[0]) should be a FILE in") if @$path > 1; |
37
|
|
|
|
|
|
|
return (1); |
38
|
|
|
|
|
|
|
} elsif (is_integer($structure)) { |
39
|
|
|
|
|
|
|
return (1) if $structure; |
40
|
|
|
|
|
|
|
return (0, "invalid path"); |
41
|
|
|
|
|
|
|
} else { |
42
|
|
|
|
|
|
|
return (0, "syntax error: unknown string spec ($structure), while checking"); |
43
|
|
|
|
|
|
|
} |
44
|
|
|
|
|
|
|
} elsif (is_array_ref($structure)) { |
45
|
|
|
|
|
|
|
return (0, "syntax error: odd number of elements in the structure spec, while checking") |
46
|
|
|
|
|
|
|
unless scalar(@$structure) % 2 == 0; |
47
|
|
|
|
|
|
|
return (0, "the component ($path->[0]) should be a DIR in") |
48
|
|
|
|
|
|
|
unless @$path > 1; |
49
|
|
|
|
|
|
|
shift @$path; |
50
|
|
|
|
|
|
|
# Return ok if the directory doesn't have subcomponents. |
51
|
|
|
|
|
|
|
return (1) if @$path == 1 && length($path->[0]) == 0; |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
for (my $s=0; $s<$#$structure; $s+=2) { |
54
|
|
|
|
|
|
|
my ($lhs, $rhs) = @{$structure}[$s, $s+1]; |
55
|
|
|
|
|
|
|
if (is_string($lhs)) { |
56
|
|
|
|
|
|
|
if ($lhs eq $path->[0]) { |
57
|
|
|
|
|
|
|
return _check_structure($rhs, $path); |
58
|
|
|
|
|
|
|
} elsif (is_integer($lhs)) { |
59
|
|
|
|
|
|
|
if ($lhs) { |
60
|
|
|
|
|
|
|
return _check_structure($rhs, $path); |
61
|
|
|
|
|
|
|
} elsif (is_string($rhs)) { |
62
|
|
|
|
|
|
|
return (0, "$rhs, while checking"); |
63
|
|
|
|
|
|
|
} else { |
64
|
|
|
|
|
|
|
return (0, "syntax error: the right hand side of a number must be string, while checking"); |
65
|
|
|
|
|
|
|
} |
66
|
|
|
|
|
|
|
} |
67
|
|
|
|
|
|
|
} elsif (is_rx($lhs)) { |
68
|
|
|
|
|
|
|
if ($path->[0] =~ $lhs) { |
69
|
|
|
|
|
|
|
return _check_structure($rhs, $path); |
70
|
|
|
|
|
|
|
} |
71
|
|
|
|
|
|
|
} else { |
72
|
|
|
|
|
|
|
my $what = ref $lhs; |
73
|
|
|
|
|
|
|
return (0, "syntax error: the left hand side of arrays in the structure spec must be scalars or qr/Regexes/, not $what, while checking"); |
74
|
|
|
|
|
|
|
} |
75
|
|
|
|
|
|
|
} |
76
|
|
|
|
|
|
|
return (0, "the component ($path->[0]) is not allowed in"); |
77
|
|
|
|
|
|
|
} else { |
78
|
|
|
|
|
|
|
my $what = ref $structure; |
79
|
|
|
|
|
|
|
return (0, "syntax error: invalid reference to a $what in the structure spec, while checking"); |
80
|
|
|
|
|
|
|
} |
81
|
|
|
|
|
|
|
} |
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
sub check_structure { |
85
|
|
|
|
|
|
|
my ($structure, $path) = @_; |
86
|
|
|
|
|
|
|
$path = "/$path" unless $path =~ m@^/@; # make sure it's an absolute path |
87
|
|
|
|
|
|
|
my @path = split '/', $path, -1; # preserve trailing empty components |
88
|
|
|
|
|
|
|
my ($code, $error) = _check_structure($structure, \@path); |
89
|
|
|
|
|
|
|
croak "$error: $path\n" if $code == 0; |
90
|
|
|
|
|
|
|
return 1; |
91
|
|
|
|
|
|
|
} |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
sub pre_commit { |
94
|
|
|
|
|
|
|
my ($svnlook) = @_; |
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
my @errors; |
97
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
foreach my $added ($svnlook->added()) { |
99
|
|
|
|
|
|
|
# Split the $added path in its components. We prefix $added |
100
|
|
|
|
|
|
|
# with a slash to make it look like an absolute path for |
101
|
|
|
|
|
|
|
# _check_structure. The '-1' is to preserve trailing empty |
102
|
|
|
|
|
|
|
# components so that we can differentiate directory paths from |
103
|
|
|
|
|
|
|
# file paths. |
104
|
|
|
|
|
|
|
my @added = split '/', "/$added", -1; |
105
|
|
|
|
|
|
|
my ($code, $error) = _check_structure($Structure, \@added); |
106
|
|
|
|
|
|
|
push @errors, "$error: $added" if $code == 0; |
107
|
|
|
|
|
|
|
} |
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
croak join("\n", "$HOOK:", @errors), "\n" |
110
|
|
|
|
|
|
|
if @errors; |
111
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
return; |
113
|
|
|
|
|
|
|
} |
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
1; # End of SVN::Hooks::CheckStructure |
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
__END__ |