File Coverage

blib/lib/Cvs.pm
Criterion Covered Total %
statement 61 101 60.4
branch 15 44 34.0
condition 4 8 50.0
subroutine 13 15 86.6
pod 4 6 66.6
total 97 174 55.7


line stmt bran cond sub pod time code
1             package Cvs;
2              
3 9     9   86845 use strict;
  9         25  
  9         364  
4 9     9   49 use Carp;
  9         21  
  9         593  
5 9     9   70 use Cwd;
  9         21  
  9         474  
6 9     9   9952 use FileHandle;
  9         157017  
  9         62  
7 9     9   4548 use File::Path qw(rmtree);
  9         19  
  9         639  
8 9     9   12160 use Cvs::Cvsroot;
  9         135  
  9         80  
9 9     9   383 use base qw(Class::Accessor);
  9         22  
  9         990  
10 9     9   52 use vars qw($AUTOLOAD %LOADED);
  9         17  
  9         12470  
11              
12             $Cvs::VERSION = 0.07;
13              
14             Cvs->mk_accessors(qw(debug pwd workdir));
15              
16             =pod
17              
18             =head1 NAME
19              
20             Cvs - Object oriented interface to the CVS command
21              
22             =head1 SYNOPSIS
23              
24             use Cvs;
25              
26             my $cvs = new Cvs
27             (
28             '/path/to/repository/for/module',
29             cvsroot => ':pserver:user@host:/path/to/cvs',
30             password => 'secret'
31             ) or die $Cvs::ERROR;
32              
33             $cvs->checkout('module');
34              
35             ...
36              
37             my $status = $cvs->status('file');
38             if($status->is_modified)
39             {
40             $cvs->commit('file');
41             }
42              
43             $cvs->release({delete_after => 1});
44             $cvs->logout();
45              
46             =head1 DESCRIPTION
47              
48             bla bla
49              
50             =head1 LEGACY CVS METHODS
51              
52             =head2 new
53              
54             Cvs = new Cvs ["workdir"] [key => "value" [, ...]];
55              
56             my $obj = new Cvs "workdir";
57              
58             my $obj = new Cvs "workdir", cvsroot => "/path/to/cvsroot";
59              
60             my $obj = new Cvs cvsroot => ":pserver:user\@host:/path/to/cvs";
61              
62             Create a new Cvs object for the repository given in argument. Note
63             that the working directory doesn't need to already exist.
64              
65             Allowed parameters are:
66              
67             =over 4
68              
69             =item workdir
70              
71             Path to the working directory. You don't need it if you plan to use
72             only remote commands like rdiff or rtag.
73              
74             =item cvsroot
75              
76             Address of the cvsroot. See the Cvs::Cvsroot module documentation for
77             more information on supported CVSROOT. Note that if you don't supply a
78             cvs root but a working directory, Cvs will try to guess the CVSROOT
79             value. You still need to supply password and others authentication
80             values. If Cvs can't determine the CVSROOT value, an error will be
81             thrown and the object will not be created.
82              
83             =item password, passphrase, ...
84              
85             All options supported by Cvs::Cvsroot are supported here. Please see
86             Cvs::Cvsroot documentation for more details.
87              
88             =back
89              
90             =head2 checkout
91              
92             Cvs::Result::Checkout = $obj->checkout("module", {key => "value"});
93              
94             Checkout the module "module" in the repository (the one that served to
95             create the Cvs object) from the cvsroot given in parameter.
96              
97             Allowed parameters are:
98              
99             =over 4
100              
101             =item reset
102              
103             Boolean value used to reset any sticky tags, dates or options (See the
104             -A cvs checkout option).
105              
106             =item revision
107              
108             Specify the revision to checkout the module (See the -r cvs checkout
109             option).
110              
111             =item date
112              
113             Specify the date from when to checkout the module (See the -D cvs
114             checkout option).
115              
116             =back
117              
118             L.
119              
120             =head2 update
121              
122             Cvs::Result::Update = $cvs->update();
123              
124             L.
125              
126             =head2 status
127              
128             Cvs::Result::StatusItem = $cvs->status("file");
129              
130             Cvs::Result::StatusList =
131             $cvs->status("file1", "file2", {multiple => 1});
132              
133             Get the status of one of more files.
134              
135             Allowed parameters are:
136              
137             =over 4
138              
139             =item multiple
140              
141             Boolean value that specify the type of object returned. If true, a
142             Cvs::Result::StatusList object is returned, and status on more than
143             one files can be handled. If false, a Cvs::Result::StatusItem object
144             is return and only one file status can be handled (the first one if
145             several).
146              
147             =item recursive
148              
149             If a directory is supplied, process it recursively (Default true).
150              
151             =back
152              
153             L, L
154              
155             =head2 diff
156              
157             Cvs::Result::DiffItem = $cvs->diff();
158              
159             Cvs::Result::DiffList = $cvs->diff({multiple => 1});
160              
161             L, L.
162              
163             =head2 rdiff
164              
165             Cvs::Result::RdiffList =
166             $cvs->rdiff("module", {from_revision => $rev});
167              
168             L.
169              
170             =head2 log
171              
172             Cvs::Result::Log = $cvs->log();
173              
174             L.
175              
176             =head2 tag
177              
178             Cvs::Result::Tag = $cvs->tag("tag");
179              
180             L.
181              
182             =head2 rtag
183              
184             Cvs::Result::Tag = $cvs->rtag("module", "tag");
185              
186             L.
187              
188             =head2 release
189              
190             Cvs::Result::Release = $cvs->release();
191              
192             Cvs::Result::Release = $cvs->release('module', ..., {force => 1});
193              
194             Call the release command.
195              
196             If call with no directories to release, self repository will be
197             released.
198              
199             =over 4
200              
201             =item force
202              
203             Boolean value that activate a forced directory release even if some
204             files was not committed. Defaults to false.
205              
206             =item delete_after
207              
208             Boolean value that activate directory removal after a release. Default
209             to false.
210              
211             =back
212              
213             L
214              
215             =head2 export
216              
217             Cvs::Result::Export = $obj->export("module", {key => "value"});
218              
219             Checkout the module "module" in the repository (the one that served to
220             create the Cvs object) from the cvsroot given in parameter, but without
221             the CVS administrative directories.
222              
223             Allowed parameters are the same as for checkout. However, one of the
224             options 'revision' or 'date' must be specified.
225              
226             =head1 OTHERS METHODS
227              
228             =cut
229              
230             sub new
231             {
232 9     9 1 41923 my $proto = shift;
233 9   33     188 my $class = ref $proto || $proto;
234 9         52 my $self = {};
235 9         46 bless($self, $class);
236              
237 9 100       97 my $workdir = @_ % 2 ? shift : undef;
238 9         71 my %args = @_;
239              
240 9   50     207 $self->debug($args{debug} or 0);
241              
242             # we need a full path
243 9 100       547 if(defined $workdir)
244             {
245 8         54 $workdir =~ s/\/$//g;
246 8 50       59 if($workdir =~ /^(.*\/)(.*)/)
247             {
248 0         0 $self->workdir($2);
249 0 0       0 if(index($1, '/') == 0)
250             {
251 0         0 $self->pwd($1);
252             }
253             else
254             {
255 0         0 $self->pwd(cwd().'/'.$1);
256             }
257             }
258             else
259             {
260 8         58 $self->workdir($workdir);
261 8         56636 $self->pwd(cwd().'/');
262             }
263              
264 8 50       557 unless(-d $self->pwd())
265             {
266 0         0 $Cvs::ERROR = "Directory doesn't exists: ".$self->pwd();
267 0         0 return;
268             }
269              
270 8 50 66     1479 if(not defined $args{cvsroot}
271             and -f join('/', $self->working_directory(), 'CVS/Root'))
272             {
273             # trying to guess the cvsroot if working directory
274             # exists... this will not work if cvsroot is - for example -
275             # on a remote ssh server an need an interaction like a
276             # password prompt
277 0         0 my $_conf = new FileHandle
278             join('/', $self->working_directory(), 'CVS/Root');
279 0 0       0 if(defined $_conf)
280             {
281 0         0 $args{cvsroot} = $_conf->getline();
282 0 0       0 chomp($args{cvsroot})
283             if defined $args{cvsroot};
284             }
285             }
286             }
287             else
288             {
289 1         2466 $self->pwd(cwd().'/');
290             }
291              
292 9 100       605 if(defined $args{cvsroot})
293             {
294             $self->cvsroot($args{cvsroot}, %args) or do
295 4 50       140 {
296 0         0 $Cvs::ERROR = $self->error();
297 0         0 return;
298             };
299             }
300             else
301             {
302 5         36 $Cvs::ERROR = 'Can\'t find CVSROOT';
303 5         237 return;
304             }
305              
306 4         59 return $self;
307             }
308              
309             =pod
310              
311             =head2 module_list
312              
313             my @modules = $cvs->module_list();
314              
315             Returns the list of all modules which can be riched on the
316             CVSROOT. This method do something that cvs doesn't implement by itself,
317             we use a little trick to get this list, and this perhaps not work with
318             all cvs versions.
319              
320             Do not mix up this method with the "-c" argument of the cvs' checkout
321             sub-command.
322              
323             =cut
324              
325             sub module_list
326             {
327 0     0 1 0 my($self) = @_;
328              
329 0 0       0 my $cvsroot = $self->cvsroot()
330             or return $self->error('Cannot determine CVSROOT');
331              
332 0         0 my $tmpdir = "/tmp/cvs-$$-".time();
333 0 0       0 mkdir($tmpdir, 0700)
334             or return $self->error("Cannot create directory: $tmpdir");
335 0 0       0 chdir($tmpdir)
336             or return $self->error("Cannot chdir to directory: $tmpdir");
337 0 0       0 mkdir("$tmpdir/CVS")
338             or return $self->error("Cannot create directory: $tmpdir/CVS");
339              
340             # create the Root control file
341 0 0       0 my $root = new FileHandle ">$tmpdir/CVS/Root"
342             or return $self->error("Cannot create file: $tmpdir/CVS/Root");
343 0         0 $root->print($cvsroot->cvsroot() . "\n");
344 0         0 $root->close();
345              
346             # create an empty Repository control file
347 0 0       0 my $repository = new FileHandle ">$tmpdir/CVS/Repository"
348             or return $self->error("Cannot create file: $tmpdir/CVS/Repository");
349 0         0 $repository->print("\n");
350 0         0 $repository->close();
351              
352             # keep some parameters
353 0         0 my $old_pwd = $self->pwd();
354 0         0 my $old_workdir = $self->workdir();
355 0         0 $tmpdir =~ /^(.*\/)(.*)$/;
356 0         0 $self->pwd($1);
357 0         0 $self->workdir($2);
358              
359             # do the trick
360 0         0 my $result =
361             $self->update({send_to_stdout => 1, build_directories => 1});
362              
363             # cleanup and restore parameters
364 0         0 rmtree($tmpdir);
365 0         0 $self->pwd($old_pwd);
366 0         0 $self->workdir($old_workdir);
367              
368 0 0       0 return $self->error($result->error())
369             unless $result->success();
370              
371 0         0 return $result->ignored_directories();
372             }
373              
374             =pod
375              
376             =head1 ACCESSORS
377              
378             =head2 cvsroot
379              
380             Returns the Cvs::Cvsroot object.
381              
382             =cut
383              
384             sub cvsroot
385             {
386 8     8 1 248 my($self, $cvsroot, %args) = @_;
387              
388 8 100       93 if(defined $cvsroot)
389             {
390 4 50       181 $self->{cvsroot} = new Cvs::Cvsroot $cvsroot, %args
391             or return $self->error('Cannot init cvsroot object');
392             }
393              
394 8         76 return $self->{cvsroot};
395             }
396              
397             =pod
398              
399             =head2 working_directory
400              
401             Returns the full path of the working directory
402              
403             =cut
404              
405             sub working_directory
406             {
407 5     5 1 30 my($self) = @_;
408 5         50 return $self->pwd() . $self->workdir();
409             }
410              
411             sub AUTOLOAD
412             {
413 4     4   2378 my $self = shift;
414              
415 4         16 my $name = $AUTOLOAD;
416 4         139 $name =~ s/.*://;
417 4 50       32 return if $name eq 'DESTROY';
418              
419 4         33 my $module = $self->load($name);
420 4 50       47 my $cmd = $module->new($self, @_)
421             or return $self->error($module->error());
422              
423 4         26 return $cmd->run();
424             }
425              
426             sub load
427             {
428 4     4 0 13 my($self, $name) = @_;
429 4         19 $name = ucfirst $name;
430 4         13569 require "Cvs/Command/${name}.pm";
431 4         29 return "Cvs::Command::$name";
432             }
433              
434             sub error
435             {
436 0     0 0   my($self, @msg) = @_;
437 0 0         if(@msg)
438             {
439 0           $self->{_error} = join(' ', @msg);
440 0           return undef;
441             }
442             else
443             {
444 0           return $self->{_error};
445             }
446             }
447              
448              
449             1;
450             =pod
451              
452             =head1 LICENCE
453              
454             This library is free software; you can redistribute it and/or modify
455             it under the terms of the GNU Lesser General Public License as
456             published by the Free Software Foundation; either version 2.1 of the
457             License, or (at your option) any later version.
458              
459             This library is distributed in the hope that it will be useful, but
460             WITHOUT ANY WARRANTY; without even the implied warranty of
461             MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
462             Lesser General Public License for more details.
463              
464             You should have received a copy of the GNU Lesser General Public
465             License along with this library; if not, write to the Free Software
466             Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
467             USA
468              
469             =head1 COPYRIGHT
470              
471             Copyright (C) 2003 - Olivier Poitrey