File Coverage

blib/lib/Cvs/Simple.pm
Criterion Covered Total %
statement 97 181 53.5
branch 24 70 34.2
condition 11 23 47.8
subroutine 27 37 72.9
pod 20 20 100.0
total 179 331 54.0


line stmt bran cond sub pod time code
1             #!/usr/bin/perl
2             package Cvs::Simple::Hook;
3 10     10   285073 use strict;
  10         25  
  10         371  
4 10     10   54 use warnings;
  10         21  
  10         2237  
5              
6             {
7             my(%PERMITTED) = (
8             'All' => '',
9             'add' => '',
10             'checkout' => '',
11             'commit' => '',
12             'update' => '',
13             'diff' => '',
14             'status' => '',
15             );
16             sub PERM_REQ () {
17 0     0   0 my($patt) = join '|' => keys %PERMITTED;
18 0         0 return qr/$patt/;
19             }
20              
21             sub permitted ($) {
22 4 50   4   18 return exists $PERMITTED{$_[0]} ? 1 : 0;
23             }
24              
25             sub get_hook ($) {
26 0     0   0 my($cmd) = shift;
27              
28 0         0 my($PERM_REQ) = PERM_REQ;
29              
30 0 0       0 if(($cmd)=~/\b($PERM_REQ)\b/) {
31 0         0 return $1;
32             }
33             else {
34 0         0 return;
35             }
36             }
37              
38             }
39              
40             1;
41              
42             package Cvs::Simple;
43 10     10   62 use strict;
  10         23  
  10         456  
44 10     10   67 use warnings;
  10         24  
  10         307  
45 10     10   53 use Carp;
  10         16  
  10         927  
46 10     10   9819 use Class::Std::Utils;
  10         54432  
  10         64  
47 10     10   6192 use Cvs::Simple::Config;
  10         27  
  10         330  
48 10     10   11043 use FileHandle;
  10         165804  
  10         66  
49              
50 10     10   4715 use vars qw($VERSION);
  10         19  
  10         449  
51 10     10   52 use version; $VERSION = version->new( 0.06 );
  10         20  
  10         76  
52              
53             {
54             my(%cvs_bin_of);
55             my(%external_of);
56             my(%callback_of);
57             my(%repos_of);
58              
59             sub new {
60 8     8 1 120 my($class) = shift;
61 8         47 my($self) = bless anon_scalar(), $class;
62 8         71 $self->_init(@_);
63 8         24 return $self;
64             }
65              
66             sub _init {
67 8     8   17 my($self) = shift;
68 8         22 my(%args) = @_;
69              
70 8 50       34 if(exists $args{cvs_bin}) {
71 0         0 $self->cvs_bin($args{cvs_bin});
72             }
73             else {
74 8         44 $self->cvs_bin(Cvs::Simple::Config::CVS_BIN);
75             }
76              
77 8 50       30 if(exists $args{external}) {
78 0         0 $self->external($args{external});
79             }
80             elsif (Cvs::Simple::Config::EXTERNAL) {
81             $self->external(Cvs::Simple::Config::EXTERNAL);
82             }
83             else {
84 8         16 ();
85             }
86              
87 8 50       136 if(exists $args{callback}) {
88 0         0 $self->callback($args{callback});
89             }
90             }
91              
92             sub callback {
93 4     4 1 1189 my($self) = shift;
94 4         6 my($hook) = shift;
95 4         7 my($func) = shift;
96              
97             # If 'hook' is not supplied, callback is global, i.e. apply to all.
98 4   50     14 $hook ||= 'All';
99              
100 4 50       13 unless(Cvs::Simple::Hook::permitted($hook)) {
101 0         0 croak "Invalid hook type in callback: $hook.";
102             }
103              
104 4 100       10 if(defined($func)) {
105 3 50       20 UNIVERSAL::isa(($func), 'CODE') or do {
106 0         0 croak "Argument supplied to callback() should be a coderef.";
107             };
108 3         17 $callback_of{ident $self}{$hook} = $func;
109             }
110              
111 4 50       16 if(exists $callback_of{ident $self}{$hook}) {
112 4         19 return $callback_of{ident $self}{$hook};
113             }
114             else {
115 0         0 return;
116             }
117             }
118              
119             sub unset_callback {
120 0     0 1 0 my($self) = shift;
121 0         0 my($hook) = shift;
122              
123 0 0       0 unless(Cvs::Simple::Hook::permitted($hook)) {
124 0         0 croak "Invalid hook type in unset_callback: $hook.";
125             }
126              
127 0         0 return delete $callback_of{ident $self}{$hook};
128             }
129              
130             sub cvs_bin {
131 14     14 1 27 my($self) = shift;
132              
133 14 100       50 if(@_==1) {
134 8         54 $cvs_bin_of{ident $self} = shift;
135             }
136              
137 14         98 return $cvs_bin_of{ident $self};
138             }
139              
140             sub cvs_cmd {
141 0     0 1 0 my($self) = shift;
142 0         0 my($cmd) = shift;
143              
144 0 0 0     0 croak "Syntax: cvs_cmd(cmd)" unless (defined($cmd) && $cmd);
145              
146 0         0 STDOUT->autoflush;
147              
148 0         0 my($hook)= Cvs::Simple::Hook::get_hook $cmd;
149              
150 0         0 my($fh) = FileHandle->new("$cmd 2>&1 |");
151 0 0       0 defined($fh) or croak "Failed to open $cmd:$!";
152              
153 0         0 while(<$fh>) {
154 0 0       0 if(defined($hook)) {
155 0 0       0 if($self->callback($hook)) {
156 0         0 $self->callback($hook)->($cmd,$_);
157             }
158             else {
159 0         0 print STDOUT $_;
160             }
161             }
162             else {
163 0 0       0 if($self->callback('All')) {
164 0         0 $self->callback('All')->($cmd, $_);
165             }
166             else {
167 0         0 print STDOUT $_;
168             }
169             }
170             }
171              
172 0         0 $fh->close;
173              
174 0         0 return 1;
175             }
176              
177             sub merge {
178             # merge(old_rev,new_rev,file);
179 2     2 1 1425 my($self) = shift;
180 2         4 my(@args) = @_;
181              
182 2 50 66     299 croak "Syntax: merge(old_rev,new_rev,file)"
183             unless (@args && scalar(@args)==3);
184              
185 0         0 my($cmd) = $self->_cmd('-q update');
186 0         0 $cmd .= sprintf("-j%s -j%s %s", @args);
187              
188 0         0 return $self->cvs_cmd($cmd);
189             }
190              
191             sub undo {
192 0     0 1 0 goto &backout;
193             }
194              
195             sub backout {
196             # Revert to previous revision of a file, i.e. backout/undo change(s).
197             # backout(current_rev,revert_rev,file);
198 2     2 1 901 my($self) = shift;
199 2         5 my(@args) = @_;
200              
201 2 50 66     15 unless (@args && scalar(@args)==3) {
202 2         292 croak <
203             Syntax: backout(current_rev,revert_rev,file)
204             undo (current_rev,revert_rev,file)
205             SYN
206             }
207              
208 0         0 return $self->merge(@args);
209             }
210              
211             sub external {
212 4     4 1 6 my($self) = shift;
213              
214 4 50       12 if(@_==1) {
215 0         0 $repos_of{ident $self} = shift;
216             }
217 4         27 return $repos_of{ident $self};
218             }
219              
220             sub _cmd {
221 4     4   6 my($self) = shift;
222 4         5 my($type) = shift;
223              
224 4         11 my($cvs) = $self->cvs_bin;
225              
226 4 50       11 my($cmd) =
227             $self->external ? sprintf("%s -d %s %s ", $cvs,$self->external,$type)
228             : sprintf("%s %s ", $cvs,$type);
229              
230 4         9 return $cmd;
231             }
232              
233             sub add {
234             # Can only be called as:
235             # cvs add file1 [, .... , ]
236 2     2 1 2033 my($self) = shift;
237 2         3 my(@args) = @_;
238              
239 2 50       347 croak "Syntax: add(file1, ...)" unless(@args);
240              
241 0         0 my($cmd) = $self->_cmd('add');
242              
243 0 0       0 if(@args) {
244 0         0 $cmd .= join ' ' => @args;
245             }
246              
247 0         0 return $self->cvs_cmd($cmd);
248             }
249              
250             sub add_bin {
251             # Can only be called as :
252             # cvs add -kb file1 [, .... , ]
253 2     2 1 987 my($self) = shift;
254 2         6 my(@args) = @_;
255              
256 2 50       173 croak "Syntax: add_bin(file1, ...)" unless (@args);
257              
258 0         0 my($cmd) = $self->_cmd('add -kb');
259              
260 0 0       0 if(@args) {
261 0         0 $cmd .= join ' ' => @args;
262             }
263              
264 0         0 return $self->cvs_cmd($cmd);
265             }
266              
267             sub checkout {
268             # Can be called as:
269             # cvs co module
270             # cvs co -r tag module
271             # Calling signature is checkout(tag,module) or checkout(module).
272 4     4 1 1247 my($self) = shift;
273 4         7 my(@args) = @_;
274              
275 4 50 33     25 unless (@args && (scalar(@args)==2 || scalar(@args)==1)) {
      66        
276 4         406 croak <
277             Syntax: co(tag)
278             co(module)
279             checkout(tag)
280             checkout(module)
281             SYN
282              
283             }
284              
285 0         0 my($cmd) = $self->_cmd('co');
286              
287 0 0       0 $cmd .= @args==2 ? sprintf("-r %s %s", @args)
288             : sprintf("%s", @args);
289              
290 0         0 return $self->cvs_cmd($cmd);
291             }
292              
293             sub co {
294 2     2 1 933 goto &checkout;
295             }
296              
297             sub _pattern {
298 0     0   0 return join '' => ('%s ' x @{$_[0]});
  0         0  
299             }
300              
301             sub commit {
302             # Can be called as :
303             # commit()
304             # commit([file_list])
305             # commit(tag1)
306             # commit(tag1, [file_list])
307 4     4 1 1533 my($self) = shift;
308 4         13 my(@args) = @_;
309              
310 4         13 my($cmd) = $self->_cmd('commit -m ""');
311 4 50       39 if(scalar(@args)==0) { # 'cvs commit -m ""'
    100          
    50          
312 0         0 return $self->cvs_cmd($cmd);
313             }
314             elsif(@args==2) { # 'cvs commit -m "" -r TAG file(s)'
315 2 50       195 croak "Syntax: commit([rev],[\@filelist])"
316             unless (UNIVERSAL::isa($args[1], 'ARRAY'));
317 0         0 my($pattern) = join '' => '-r %s ', _pattern($args[1]);
318 0         0 $cmd .= sprintf($pattern, $args[0], @{$args[1]});
  0         0  
319 0         0 return $self->cvs_cmd($cmd);
320             }
321             elsif(@args==1) { # 'cvs commit -m "" -r TAG' or
322             # 'cvs commit -m "" file(s)'
323 0         0 my($pattern);
324 0 0       0 if(UNIVERSAL::isa($args[0], 'ARRAY')) {
325 0         0 $pattern = sprintf(_pattern($args[0]), @{$args[0]});
  0         0  
326             }
327             else {
328 0         0 $pattern = sprintf('-r %s', $args[0]);
329             }
330              
331 0         0 $cmd .= $pattern;
332              
333 0         0 return $self->cvs_cmd($cmd);
334             }
335             else { # Anything else is an error
336 2         284 croak <
337             Syntax: commit([rev],[\@filelist])
338             ci ([rev],[\@filelist])
339             SYN
340              
341             }
342             }
343              
344             sub ci {
345 2     2 1 1417 goto &commit;
346             }
347              
348             sub diff {
349             # Can be called as :
350             # diff(file_or_dir)
351             # diff(tag1,tag2,file_or_dir)
352 2     2 1 873 my($self) = shift;
353 2         5 my(@args) = @_;
354              
355 2 50 33     277 croak "Syntax: diff(file) or diff(tag1,tag2,file)"
      66        
356             unless (@args && (scalar(@args)==1 || scalar(@args)==3));
357              
358 0         0 my($cmd) = $self->_cmd('diff -c');
359              
360 0 0       0 $cmd .= @args==3 ? sprintf("-r %s -r %s %s", @args)
361             : sprintf("%s" , @args);
362              
363 0         0 return $self->cvs_cmd($cmd);
364             }
365              
366             sub status {
367             # status()
368             # status(file1, ... )
369 0     0 1 0 my($self) = shift;
370 0         0 my(@args) = @_;
371              
372 0         0 my($cmd) = $self->_cmd('status -v');
373              
374 0 0       0 if(@args) {
375 0         0 $cmd .= join ' ' => @args;
376             }
377              
378 0         0 return $self->cvs_cmd($cmd);
379             }
380              
381             sub upd {
382 0     0 1 0 goto &update;
383             }
384              
385             sub update {
386             # update() -> update workspace (cvs -q update -d).
387             # update(file) -> update file (cvs -q update file [file ... ]).
388             # Doesn't permit -r.
389 0     0 1 0 my($self) = shift;
390 0         0 my(@args) = @_;
391              
392 0         0 my($cmd) = $self->_cmd('-q update');
393              
394 0 0       0 $cmd .= @args ? join ' ' => @args
395             : '-d';
396              
397 0         0 return $self->cvs_cmd($cmd);
398             }
399              
400             sub up2date {
401             # Checks workspace status. No args.
402 0     0 1 0 my($self) = shift;
403              
404 0         0 my($cmd) = $self->_cmd('-nq update -d');
405              
406 0         0 return $self->cvs_cmd($cmd);
407             }
408              
409             sub DESTROY {
410 8     8   4312 my($self) = shift;
411 8         206 delete($cvs_bin_of {ident $self});
412 8         28 delete($external_of{ident $self});
413 8         34 delete($callback_of{ident $self});
414              
415 8         672 return;
416             }
417              
418             }
419             1;
420             __END__