File Coverage

blib/lib/Shipwright/Backend/SVN.pm
Criterion Covered Total %
statement 23 110 20.9
branch 3 52 5.7
condition 0 14 0.0
subroutine 8 17 47.0
pod 4 4 100.0
total 38 197 19.2


line stmt bran cond sub pod time code
1             package Shipwright::Backend::SVN;
2              
3 2     2   721 use warnings;
  2         3  
  2         60  
4 2     2   7 use strict;
  2         2  
  2         54  
5 2     2   8 use File::Spec::Functions qw/catfile/;
  2         1  
  2         89  
6 2     2   8 use Shipwright::Util;
  2         4  
  2         149  
7 2     2   9 use File::Copy::Recursive qw/rcopy/;
  2         2  
  2         109  
8              
9             our %REQUIRE_OPTIONS = ( import => [qw/source/] );
10              
11 2     2   8 use base qw/Shipwright::Backend::Base/;
  2         2  
  2         2497  
12              
13             =head1 NAME
14              
15             Shipwright::Backend::SVN - SVN repository backend
16              
17             =head1 SYNOPSIS
18              
19             svnadmin create /home/me/shipwright/my_proj
20             shipwright create -r svn:file:///home/me/shipwright/my_proj
21              
22             =head1 DESCRIPTION
23              
24             This module implements a SVN based backend
25             for Shipwright L.
26              
27             =head1 ENVIRONMENT VARIABLES
28              
29             =over 4
30              
31             =item SHIPWRIGHT_SVN - path of F command, default value is F.
32             F command is expected to be in the same directory as F.
33              
34             =back
35              
36             =head1 METHODS
37              
38             =over 4
39              
40             =item build
41              
42             =cut
43              
44              
45              
46             sub build {
47 2     2 1 3 my $self = shift;
48 2 100       18 $self->strip_repository
49             if $self->repository =~ m{^svn:[a-z]+(?:\+[a-z]+)?://};
50 2         7 $self->SUPER::build(@_);
51             }
52              
53             =item initialize
54              
55             initialize a project.
56              
57             =cut
58              
59             sub initialize {
60 0     0 1 0 my $self = shift;
61 0         0 my $dir = $self->SUPER::initialize(@_);
62              
63 0         0 $self->delete; # clean repository in case it exists
64 0         0 $self->import(
65             source => $dir,
66             _initialize => 1,
67             comment => 'created project',
68             );
69 0         0 $self->_initialize_local_dir();
70              
71             }
72              
73             =item import
74              
75             =cut
76              
77             sub import {
78 1     1   7 my $self = shift;
79 1 50       10 return unless ref $self; # get rid of class->import
80 0           return $self->SUPER::import( @_, delete => 1 );
81             }
82              
83             # a cmd generating factory
84             sub _cmd {
85 0     0     my $self = shift;
86 0           my $type = shift;
87 0           my %args = @_;
88 0   0       $args{path} ||= '';
89 0   0       $args{comment} ||= '';
90              
91 0           for ( @{ $REQUIRE_OPTIONS{$type} } ) {
  0            
92 0 0         confess_or_die "$type need option $_" unless $args{$_};
93             }
94              
95 0           my @cmd;
96              
97 0 0         if ( $type eq 'checkout' ) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
98 0           @cmd =
99             [ $ENV{'SHIPWRIGHT_SVN'}, 'checkout', $self->repository . $args{path}, $args{target} ];
100             }
101             elsif ( $type eq 'export' ) {
102 0           @cmd =
103             [ $ENV{'SHIPWRIGHT_SVN'}, 'export', $self->repository . $args{path}, $args{target} ];
104             }
105             elsif ( $type eq 'import' ) {
106 0 0         if ( $args{_initialize} ) {
    0          
107 0   0       @cmd = [
108             $ENV{'SHIPWRIGHT_SVN'}, 'import', $args{source},
109             $self->repository . ( $args{path} || '' ),
110             '-m', $args{comment},
111             ];
112             }
113             elsif ( $args{_extra_tests} ) {
114 0           @cmd = [
115             $ENV{'SHIPWRIGHT_SVN'}, 'import',
116             $args{source}, $self->repository . '/t/extra',
117             '-m', $args{comment},
118             ];
119             }
120             else {
121 0 0         if ( my $script_dir = $args{build_script} ) {
122 0           @cmd = [
123             $ENV{'SHIPWRIGHT_SVN'}, 'import',
124             $script_dir, $self->repository . "/scripts/$args{name}/",
125             '-m', $args{comment},
126             ];
127             }
128             else {
129 0 0         if ( $self->has_branch_support ) {
130 0           @cmd = [
131             $ENV{'SHIPWRIGHT_SVN'},
132             'import',
133             $args{source},
134             $self->repository . "/sources/$args{name}/$args{as}",
135             '-m',
136             $args{comment},
137             ];
138             }
139             else {
140 0           @cmd = [
141             $ENV{'SHIPWRIGHT_SVN'},
142             'import',
143             $args{source},
144             $self->repository . "/dists/$args{name}",
145             '-m',
146             $args{comment},
147             ];
148              
149             }
150             }
151             }
152             }
153             elsif ( $type eq 'list' ) {
154 0           @cmd = [ $ENV{'SHIPWRIGHT_SVN'}, 'list', $self->repository . $args{path} ];
155             }
156             elsif ( $type eq 'commit' ) {
157 0           @cmd =
158             [ $ENV{'SHIPWRIGHT_SVN'}, 'commit', '-m', $args{comment}, $args{path} ];
159             }
160             elsif ( $type eq 'delete' ) {
161 0           @cmd = [
162             $ENV{'SHIPWRIGHT_SVN'}, 'delete',
163             '-m', 'delete ' . $args{path},
164             $self->repository . $args{path},
165             ];
166             }
167             elsif ( $type eq 'move' ) {
168 0           @cmd = [
169             $ENV{'SHIPWRIGHT_SVN'},
170             'move',
171             '-m',
172             "move $args{path} to $args{new_path}",
173             $self->repository . $args{path},
174             $self->repository . $args{new_path}
175             ];
176             }
177             elsif ( $type eq 'info' ) {
178 0           @cmd = [ $ENV{'SHIPWRIGHT_SVN'}, 'info', $self->repository . $args{path} ];
179             }
180             elsif ( $type eq 'cat' ) {
181 0           @cmd = [ $ENV{'SHIPWRIGHT_SVN'}, 'cat', $self->repository . $args{path} ];
182             }
183             else {
184 0           confess_or_die "invalid command: $type";
185             }
186              
187 0           return @cmd;
188             }
189              
190             sub _yml {
191 0     0     my $self = shift;
192 0           my $path = shift;
193 0           my $yml = shift;
194              
195 0           my $file = $self->local_dir . $path;
196              
197 0 0         if ($yml) {
198 0 0         if ( $path =~ /scripts/ ) {
199 0           $self->_sync_local_dir('/scripts');
200             }
201             else {
202 0           $self->_sync_local_dir($path);
203             }
204 0           dump_yaml_file( $file, $yml );
205 0           $self->commit( path => $file, comment => "updated $path" );
206             }
207             else {
208 0           my ($out) = run_cmd(
209             [ $ENV{'SHIPWRIGHT_SVN'}, 'cat', $self->repository . $path ] );
210 0           return load_yaml($out);
211             }
212             }
213              
214             =item info
215              
216             a wrapper around svn's info command.
217              
218             =cut
219              
220             sub info {
221 0     0 1   my $self = shift;
222 0           my ( $info, $err ) = $self->SUPER::info(@_);
223              
224 0 0         if (wantarray) {
225 0           return $info, $err;
226             }
227             else {
228 0 0         if ($err) {
229 0           $err =~ s/\s+$//;
230 0           $self->log->warn($err);
231 0           return;
232             }
233 0           return $info;
234             }
235             }
236              
237             =item check_repository
238              
239             check if the given repository is valid.
240              
241             =cut
242              
243             sub check_repository {
244 0     0 1   my $self = shift;
245 0           my %args = @_;
246              
247 0 0         if ( $args{action} eq 'create' ) {
248              
249 0           my ( $info, $err ) = $self->info;
250              
251 0           my $repo = $self->repository;
252              
253             # $err like
254             # file:///tmp/svn/foo: (Not a valid URL)
255             # usually means foo doesn't exist, which is valid for create
256 0 0         if ($info) {
257 0 0 0       return 1 if $args{force} || $info =~ /Revision: 0/;
258 0           $self->log->fatal("$repo has commits already");
259 0           return;
260             }
261 0 0 0       return 1 if $err && $err =~ m{^\Q$repo\E:}m;
262             }
263             else {
264 0           return $self->SUPER::check_repository(@_);
265             }
266 0           return;
267             }
268              
269             sub _update_file {
270 0     0     my $self = shift;
271 0           my $path = shift;
272 0           my $latest = shift;
273              
274 0           $self->_sync_local_dir( $path );
275 0           my $file = $self->local_dir . $path;
276 0 0         rcopy( $latest, $file ) or confess_or_die "can't copy $latest to $file: $!";
277 0           $self->commit(
278             path => $file,
279             comment => "updated $path",
280             );
281             }
282              
283             sub _update_dir {
284 0     0     my $self = shift;
285 0           my $path = shift;
286 0           my $latest = shift;
287              
288 0           $self->delete( path => $path );
289 0           $self->import( path => $path, source => $latest, _initialize => 1 );
290             }
291              
292             sub _initialize_local_dir {
293 0     0     my $self = shift;
294             # the 0 is very important, or it may results in recursion
295 0           my $target = $self->local_dir( 0 );
296 0 0         remove_tree( $target ) if -e $target;
297              
298 0           run_cmd(
299             [ $ENV{'SHIPWRIGHT_SVN'}, 'checkout', $self->repository, $target ] );
300 0           return $target;
301             }
302              
303             sub _sync_local_dir {
304 0     0     my $self = shift;
305 0   0       my $path = shift || '';
306 0           run_cmd(
307             [ $ENV{'SHIPWRIGHT_SVN'}, 'update', $self->local_dir . $path ], 1 );
308             }
309              
310             =back
311              
312             =cut
313              
314             1;
315              
316             __END__