42e315280c760afc9a1ddca5efa4e41fe75fb0d4
[clearscm.git] / test / testclearcase.pl
1 #!/usr/bin/env cqperl
2
3 =pod
4
5 =head1 NAME $RCSfile: testclearcase.pl,v $
6
7 Test Clearcase
8
9 =head1 VERSION
10
11 =over
12
13 =item Author
14
15 Andrew DeFaria <Andrew@ClearSCM.com>
16
17 =item Revision
18
19 $Revision: 2.1 $
20
21 =item Created:
22
23 Tue Apr 10 13:14:15 CDT 2007
24
25 =item Modified:
26
27 $Date: 2011/01/09 01:01:32 $
28
29 =back
30
31 =head1 SYNOPSIS
32
33  Usage: testclearcase.pl: [-us|age] [-ve|rbose]
34                           [-c|onfig <file>] [-b|ase] [-uc|m]
35
36  Where:
37    -v|erbose:       Display progress output
38    -d|ebug:         Display debug info
39    -us|age:         Display usage
40
41    -c|onfig <file>: Config file (Default: testclearcase.conf)
42    -[no]b|ase:      Perform base Clearcase tests (Default: base)
43    -[no]uc|m:       Perform UCM Clearcase tests (Default: noucm)
44    -[no]clean:      Cleanup after yourself (Default: clean)
45
46 =head1 DESCRIPTION  
47
48 Clearcase smoke tests. Perform simple Clearcase operations to validate that
49 Clearcase minimally works.
50
51 If -ucm is specified then additional UCM related tests are performed.
52
53 =cut
54
55 use strict;
56 use warnings;
57
58 use Cwd;
59 use FindBin;
60 use Getopt::Long;
61 use Term::ANSIColor qw(:constants);
62
63 use lib "$FindBin::Bin/../lib";
64
65 use Clearcase;
66 use Clearcase::Element;
67 use Clearcase::View;
68 use Clearcase::Views;
69 use Clearcase::Vob;
70 use Clearcase::Vobs;
71
72 use Clearcase::UCM;
73 use Clearcase::UCM::Activity;
74 use Clearcase::UCM::Baseline;
75 use Clearcase::UCM::Component;
76 use Clearcase::UCM::Folder;
77 use Clearcase::UCM::Project;
78 use Clearcase::UCM::Pvob;
79 use Clearcase::UCM::Stream;
80
81 use DateUtils;
82 use Display;
83 use GetConfig;
84 use Logger;
85 use OSDep;
86 use TimeUtils;
87 use Utils;
88
89 # Globals
90 my $VERSION = '2.1';
91
92 my (@ucmobjs, $order);
93
94 my (
95   $test_vob,
96   $test_view,
97   $test_pvob,
98   $test_folder,
99   $test_project,
100   $test_activity,
101   $test_baseline,
102   $test_component,,
103   $test_devstream,
104   $test_intstream,
105   $test_devview,
106   $test_intview,
107 );
108
109 my ($vbs, $vws, %default_opts, %opts);
110
111 my ($script) = ($FindBin::Script =~ /^(.*)\.pl/);
112
113 my $log = Logger->new;
114
115 # LogOpts: Log the %opts has to the log file so we can tell the options used for
116 # this run.
117 sub LogOpts() {
118   $log->msg(
119     "$script v$VERSION run at " 
120   . YMDHM
121   . ' with the following options:'
122   );
123
124   for (sort keys %opts) {
125     if (ref $opts{$_} eq 'ARRAY') {
126       my $name = $_;
127       $log->msg("$name:\t$_") for (@{$opts{$_}});
128     } else {
129       $log->msg("$_:\t$opts{$_}");
130     }  # if
131   } # for
132   
133   return;
134 } # LogOpts
135
136 sub CreateVob($) {
137   my ($tag) = @_;
138
139   my $vobname = Clearcase::vobname $tag;
140
141   $log->msg ("Creating vob $tag");
142
143   my $newvob = Clearcase::Vob->new($tag);
144
145   my ($status, @output) = $newvob->create($opts{vobhost}, "$opts{vobstore}/$vobname.vbs");
146
147   $log->log($_) for (@output);
148
149   return ($status, $newvob);
150 } # CreateVob
151
152 sub CreatePvob($) {
153   my ($tag) = @_;
154
155   my $vobname = Clearcase::vobname $tag;
156
157   my $pvob = Clearcase::UCM::Pvob->new($tag);
158
159   #my ($status, @output) = $pvob->create($opts{vobhost}, "$opts{vobstore}/$vobname.vbs", 'A test Pvob');
160   my ($status, @output) = $pvob->create($opts{vobhost}, "$opts{vobstore}/$vobname.vbs");
161
162   $log->log($_) for (@output);
163
164   push @ucmobjs, $pvob unless $status;
165
166   return ($status, $pvob);
167 } # CreatePvob
168
169 sub MountVob($) {
170   my ($vob) = @_;
171
172   $log->msg('Mounting vob ' . $vob->tag);
173
174   # Create mount directory
175   my ($status, @output);
176   
177   ($status, @output) = Execute 'mkdir -p ' . $vob->tag . ' 2>&1' unless -d $vob->tag;
178
179   $log->log($_) for (@output);
180
181   ($status, @output) = $vob->mount;
182
183   $log->log($_) for (@output);
184
185   return $status;
186 } # MountVob
187
188 sub DestroyVob($) {
189   my ($vob) = @_;
190
191   my ($status, @output);
192
193   ($status, @output) = $Clearcase::CC->execute('cd');
194
195   $log->msg('Unmounting vob ' . $vob->tag);
196
197   ($status, @output) = $vob->umount;
198
199   $log->msg('Removing vob ' . $vob->tag);
200
201   ($status, @output) = $vob->remove;
202
203   $log->log($_) for (@output);
204
205   return $status;
206 } # DestroyVob
207
208 sub CreateView($) {
209   my ($tag) = @_;
210
211   $log->msg("Creating view $tag");
212
213   my $view = Clearcase::View->new($tag);
214
215   my ($status, @output) = $view->create($opts{viewhost}, "$opts{viewstore}/$tag.vws");
216
217   $log->log($_) for (@output);
218
219   return ($status, $view);
220 } # CreateView
221
222 sub SetView($) {
223   my ($view) = @_;
224
225   $log->msg('Setting view ' . $view->tag);
226
227   my ($status, @output) = $view->set;
228
229   $log->log($_) for (@output);
230
231   return $status;
232 } # SetView
233
234 sub DestroyView($) {
235   my ($view) = @_;
236
237   $log->msg('Removing view ' . $view->tag);
238
239   my ($status, @output) = $Clearcase::CC->execute('cd');
240
241   $log->log($_) for (@output);
242
243   chdir $ENV{HOME}
244     or $log->err("Unable to chdir $ENV{HOME}", 1);
245
246   ($status, @output) = $view->remove;
247
248   $log->log($_) for (@output);
249
250   return $status;
251 } # DestroyView
252
253 sub CreateViewPrivateFiles(@) {
254   my (@elements) = @_;
255
256   $log->msg('Creating test files');
257
258   for (@elements) {
259     my $file;
260
261     $log->msg("Creating $_");
262
263     open $file, '>>', $_
264       or $log->err("Unable to open $_ for writing - $!", 1);
265
266     print $file "This is file $_\n";
267
268     close $file;
269   } # for
270   
271   return;
272 } # CreateViewPrivateFiles
273
274 sub CheckOut($) {
275   my ($element) = @_;
276
277   my ($status, @output);
278
279   if (ref $element eq 'ARRAY') {
280     for (@{$element}) {
281       $log->msg("Checking out $_");
282
283       my $newElement = Clearcase::Element->new($_);
284
285       ($status, @output) = $newElement->checkout;
286
287       $log->log($_) for (@output);
288
289       $log->err("Unable to check out $_", $status) if $status;
290     } # for
291   } else {
292     $log->msg("Checking out $element");
293
294     my $newElement = Clearcase::Element->new($element);
295
296     ($status, @output) = $newElement->checkout;
297
298     $log->log($_) for (@output);
299
300     $log->err("Unable to check out $element", $status) if $status;
301   } # if
302   
303   return;
304 } # CheckOut
305
306 sub CheckIn($) {
307   my ($element) = @_;
308
309   my ($status, @output);
310
311   if (ref $element eq 'ARRAY') {
312     for (@{$element}) {
313       $log->msg("Checking in $_");
314
315       my $newElement = Clearcase::Element->new($_);
316
317       ($status, @output) = $newElement->checkin;
318
319       $log->log($_) for (@output);
320
321       $log->err("Unable to check in $_", $status) if $status;
322     } # for
323   } else {
324     $log->msg("Checking in $element");
325
326     my $newElement = Clearcase::Element->new($element);
327
328     ($status, @output) = $newElement->checkin;
329
330     $log->log($_) for (@output);
331
332     $log->err("Unable to check in $element", $status) if $status;
333   } # if
334   
335   return;
336 } # CheckIn
337
338 sub ComparingFiles(@) {
339   my (@elements) = @_;
340
341   for (@elements) {
342     my @lines = ReadFile $_;
343
344     $log->err("Element $_ should contain only two lines", 2) if scalar @lines != 2;
345   } # for
346
347   return;
348 } # ComparingFiles
349
350 sub MakeElements(@) {
351   my (@elements) = @_;
352
353   for (@elements) {
354     $log->msg("Mkelem $_");
355
356     my $newElement = Clearcase::Element->new($_);
357
358     my ($status, @output) = $newElement->mkelem;
359
360     $log->log($_) for (@output);
361
362     $log->err("Unable to make $_ an element", $status) if $status;
363   } # for
364   
365   return;
366 } # MakeElements
367
368 sub RunTests() {
369   # Simple tests:
370   #
371   #   . Create a few elements
372   #   . Check them in
373   #   . Check them out
374   #   . Modify them
375   #   . Check them in
376   #
377   # Assumptions:
378   #
379   #   . $vob_tag is already created
380   #   . $view_tag is already created
381   #   . View is set and we are in the vob
382   #   . There are no vob elements for @elements
383   my @elements = (
384     'cctest.h',
385     'ccsetup.c',
386     'cctest.c',
387     'Makefile',
388   );
389
390   $log->msg("$script: Start Base Clearcase Tests");
391   $log->msg('Removing test files');
392
393   unlink $_ for (@elements);
394
395   $log->msg('Creating view private files');
396
397   CreateViewPrivateFiles @elements;
398
399   $log->msg('Making elements');
400
401   CheckOut      '.';
402   MakeElements  @elements;
403   CheckIn       \@elements;
404   CheckIn       '.';
405
406   $log->msg('Checking out files');
407
408   CheckOut \@elements;
409
410   $log->msg('Modifying files');
411
412   CreateViewPrivateFiles @elements;
413
414   $log->msg('Checking in files');
415
416   CheckIn \@elements;
417
418   $log->msg('Comparing files');
419
420   ComparingFiles @elements;
421
422   $log->msg("$script: End Base Clearcase Tests");
423
424   return 0;
425 } # RunTests
426
427 sub Cleanup(;$$$) {
428   my ($view, $vob) = @_;
429
430   my $status = 0;
431
432   $log->msg('Cleaning up');
433
434   if ($view && $view->exists) {
435     $status += DestroyView($view);
436   } # if
437
438   if ($vob && $vob->exists) {
439     $status += DestroyVob($vob);
440   } # if
441
442   return $status;
443 } # Cleanup
444
445 sub CleanupUCM() {
446   my $status = 0;
447
448   # Need to remove UCM objects in the opposite order in which we created them
449   for (reverse @ucmobjs) {
450     my ($rc, @output);
451
452     if (ref $_ eq 'Clearcase::UCM::Pvob') {
453       $log->msg('Removing Pvob ' . $_->tag);
454
455       $status += DestroyVob $_;
456     } else {
457       $log->msg('Removing ' . ref ($_) . ' ' . $_->name);
458
459       ($rc, @output) = $_->remove;
460
461       $status += $rc;
462     } # if
463   } # for
464
465   return $status;
466 } # CleanupUCM
467
468 sub SetupTest($$) {
469   my ($vob_tag, $view_tag) = @_;
470   
471   my ($status, @output);
472
473   $log->msg('Setup test environment');
474
475   my $view = Clearcase::View->new($view_tag);
476
477   if ($view->exists) {
478     $log->msg('Removing old view ' . $view_tag);
479
480     ($status, @output) = $view->remove;
481
482     $log->err('Unable to remove old view ' . $view->tag, $status) if $status;
483   } # if
484
485   ($status, $test_view) = CreateView($view_tag);
486
487   return $status if $status != 0;
488
489   $status = $test_view->start;
490
491   my $vob = Clearcase::Vob->new($vob_tag);
492
493   if ($vob->exists) {
494     $log->msg('Removing old vob ' . $vob_tag);
495
496     ($status, @output) = DestroyVob($vob);
497
498     $log->err('Unable to remove old vob '. $vob->tag, $status) if $status;
499   } # if
500
501   ($status, $test_vob) = CreateVob($vob_tag);
502
503   return $status if $status != 0;
504
505   $status = MountVob($test_vob);
506
507   return $status if $status != 0;
508
509   my $dir = $Clearcase::VIEWTAG_PREFIX . '/' . $test_view->tag . $test_vob->tag;
510
511   chdir $dir
512     or $log->err("Unable to chdir to $dir", ++$status);
513
514   ($status, @output) = $Clearcase::CC->execute("cd $dir");
515
516   if ($status != 0) {
517     $log->log($_) for (@output);
518   } # if
519
520   return $status;
521 } # SetupTest
522
523 sub SetupUCMTest() {
524   my $status;
525
526   $log->msg("Creating UCM Pvob $Clearcase::VOBTAG_PREFIX/tc.pvob");
527
528   ($status, $test_pvob) = CreatePvob("$Clearcase::VOBTAG_PREFIX/tc.pvob"); 
529   
530   return $status;
531 } # SetupUCMTest
532
533 sub CreateUCMProject() {
534   # Get the root folder to put this project into (may create folders later)
535   my $folder = Clearcase::UCM::Folder->new('tc.folder', $test_pvob);
536
537   $test_project = Clearcase::UCM::Project->new('tc.project', $folder, $test_pvob);
538
539   $log->msg('Creating UCM Project tc.project');
540
541   my ($status, @output) = $test_project->create();
542
543   $log->log($_) for (@output);
544
545   push @ucmobjs, $test_project unless $status;
546
547   return $status;
548 } # CreateUCMProject
549
550 sub CreateUCMIntStream() {
551   $test_intstream = Clearcase::UCM::Stream->new('tc.intstream', $test_pvob);
552
553   $log->msg('Creating UCM Stream tc.intstream');
554
555   my ($status, @output) = $test_intstream->create($test_project, '-integration');
556
557   $log->log($_) for (@output);
558
559   push @ucmobjs, $test_intstream unless $status;
560
561   return $status;
562 } # CreateUCMIntStream
563
564 sub CreateUCMDevStream() {
565   $test_devstream = Clearcase::UCM::Stream->new('tc.devstream', $test_pvob);
566
567   $log->msg('Creating UCM Stream tc.devstream');
568
569   my ($status, @output) = $test_devstream->create($test_project);
570
571   $log->log($_) for (@output);
572
573   push @ucmobjs, $test_devstream unless $status;
574
575   return $status;
576 } # CreateUCMIntStream
577
578 sub CreateUCMComponent() {
579   $test_component = Clearcase::UCM::Component->new('tc.component', $test_pvob);
580
581   $log->msg('Creating UCM Component tc.component');
582
583   my ($status, @output) = $test_component->create(
584     "$Clearcase::VIEWTAG_PREFIX/" . $test_intview->tag . $test_vob->tag
585   );
586
587   $log->log($_) for (@output);
588
589   push @ucmobjs, $test_component unless $status;
590
591   return $status;
592 } # CreateUCMComponent
593
594 sub AddModifiableComponent() {
595   my ($status, @output) = $Clearcase::CC->execute(
596     'chproj -nc -amodcomp ' . $test_component->name . '@' . $test_pvob->tag .
597     ' '                     . $test_project->name   . '@' . $test_pvob->tag
598   );
599
600   $log->log($_) for (@output);
601
602   return $status;
603 } # AddModifiableCOmponent
604
605 sub CreateUCMIntView() {
606   $log->msg("Creating UCM Int View tc.intview");
607
608   $test_intview = Clearcase::View->new('tc.intview');
609
610   my ($status, @output) = $test_intview->create(
611     $opts{viewhost}, "$opts{viewstore}/tc.intview.vws",
612     '-stream ' . $test_intstream->name . '@' . $test_pvob->tag
613   );
614
615   $log->log($_) for (@output);
616
617   push @ucmobjs, $test_intview unless $status;
618
619   $test_intview->start unless $status;
620
621   return $status;
622 } # CreateUCMIntView
623
624 sub CreateUCMDevView() {
625   $log->msg("Creating UCM Dev View tc.devview");
626
627   $test_devview = Clearcase::View->new('tc.devview');
628
629   my ($status, @output) = $test_devview->create(
630     $opts{viewhost}, "$opts{viewstore}/tc.devview.vws",
631     '-stream ' . $test_devstream->name . '@' . $test_pvob->tag
632   );
633
634   $log->log($_) for (@output);
635
636   push @ucmobjs, $test_devview unless $status;
637
638   $test_devview->start unless $status;
639
640   return $status;
641 } # CreateUCMDevView
642
643 sub CreateUCMBaseline() {
644   $test_baseline = Clearcase::UCM::Baseline->new('tc.baseline', $test_pvob);
645
646   $log->msg('Creating UCM Baseline tc.baseline');
647
648   my ($status, @output) = $test_baseline->create($test_intview, undef, '-identical');
649
650   $log->log($_) for (@output);
651
652   push @ucmobjs, $test_baseline unless $status;
653
654   return $status;
655 } # CreateUCMBaseline
656
657 sub CreateUCMActivity() {
658   $test_activity = Clearcase::UCM::Activity->new('tc.activity', $test_pvob);
659
660   $log->msg('Creating UCM Activity tc.activity');
661
662   my ($status, @output) = $test_activity->create($test_devstream, 'A UCM Test Activity');
663
664   $log->log($_) for (@output);
665
666   push @ucmobjs, $test_activity unless $status;
667
668   return $status;
669 } # CreateUCMActivity
670
671 sub RebaseStream($$;$) {
672   my ($stream, $baseline, $opts) = @_;
673
674   my ($status, @output) = $stream->rebase($baseline, $opts);
675
676   $log->log($_) for (@output);
677
678   return $status;
679 } # RebaseStream
680
681 sub RecommendBaseline($) {
682   my ($baseline) = @_;
683
684   my ($status, @output) = $test_intstream->recommend($baseline);
685
686   $log->log($_) for (@output);
687
688   return $status;
689 } # RecommentBaseline
690
691 sub RunUCMTests() {
692   my $status = 0;
693
694   $log->msg("$script: Start UCM Clearcase Tests");
695
696   $status += CreateUCMProject;
697   $status += CreateUCMIntStream;
698   $status += CreateUCMDevStream;
699   $status += CreateUCMIntView;
700   $status += CreateUCMDevView;
701   $status += CreateUCMComponent;
702   $status += AddModifiableComponent;
703   $status += RebaseStream($test_intstream, 'tc.component_INITIAL', '-complete');
704   $status += RecommendBaseline('tc.component_INITIAL');
705   $status += CreateUCMBaseline;
706   $status += RebaseStream($test_devstream, 'tc.baseline', '-complete');
707   $status += CreateUCMActivity;
708   
709   $log->msg("$script: End UCM Clearcase Tests");
710
711   return $status;
712 } # RunUCMTests
713
714 ## Main
715 my $startTime = time;
716 my $conf_file = "$FindBin::Bin/$script.conf";
717 my $status    = 0;
718
719 $opts{base}  = 1;
720 $opts{clean} = 1;
721
722 GetOptions(
723   \%opts,
724   'verbose' => sub { set_verbose },
725   'debug'   => sub { set_debug },
726   'usage'   => sub { Usage },
727   'config=s',
728   'base!',
729   'ucm!',
730   'clean!',
731 ) or Usage;
732
733 # Read the config file
734 if (-f $conf_file) {
735   %default_opts = GetConfig $conf_file;
736 } else {
737   $log->err("Unable to find config file $conf_file", 1);
738 } # if
739
740 # Overlay default opts if not specified
741 for (keys %default_opts) {
742   $opts{$_} = $default_opts{$_} if !$opts{$_};
743 } # for
744
745 $log->msg("$script: Start");
746
747 LogOpts;
748
749 # Since we are creating private vobs (to avoid complications with having to
750 # know and code the registry password when making public vobs), we'll simply
751 # change $Clearcase::VOBTAG_PREFIX
752 $Clearcase::VOBTAG_PREFIX = $ENV{TMP} || '/tmp';
753
754 if ($opts{base}) {
755   $status = SetupTest "$Clearcase::VOBTAG_PREFIX/tc.vob", 'tc.view';
756
757   if ($status == 0) {
758     $status += RunTests;
759   } else {
760     $log->err('Tests not run. Failure occurred in SetupTest - check logfile');
761   } # if
762
763   # Note if we are doing UCM tests then we need the view and vob here...
764   $status += Cleanup($test_view, $test_vob) if $opts{clean} and !$opts{ucm};
765
766   if ($status != 0) {
767     $log->err("$script: Failed (Base Clearcase)");
768   } else {
769     $log->msg("$script: Passed (Base Clearcase)");
770   } # if
771 } # if
772
773 if ($opts{ucm}) {
774   $status = SetupUCMTest;
775
776   if ($status == 0) {
777     $status += RunUCMTests;
778   } else {
779     $log->err('UCM Tests not run. Failure occurred in SetupUCMTest - check logfile');
780   } # if
781
782   if ($opts{clean}) {
783     $status += CleanupUCM;
784     $status += Cleanup($test_view, $test_vob);
785   } # if
786
787   if ($status != 0) {
788     $log->err("$script Failed (UCM Clearcase)");
789   } else {
790     $log->msg("$script: Passed (UCM Clearcase)");
791   } # if
792 } # if
793
794 display_duration $startTime, $log;
795
796 $log->msg("$script: End");
797
798 exit $status;
799
800 =pod
801
802 =head1 CONFIGURATION AND ENVIRONMENT
803
804 DEBUG: If set then $debug is set to this level.
805
806 VERBOSE: If set then $verbose is set to this level.
807
808 TRACE: If set then $trace is set to this level.
809
810 =head1 DEPENDENCIES
811
812 =head2 Perl Modules
813
814 L<Cwd>
815
816 L<FindBin>
817
818 L<Getopt::Long|Getopt::Long>
819
820 L<Term::ANSIColor|Term::ANSIColor>
821
822 =head2 ClearSCM Perl Modules
823
824 =begin man 
825
826  Clearcase
827  Clearcase::Element
828  Clearcase::View
829  Clearcase::Views
830  Clearcase::Vob
831  Clearcase::Vobs
832  DateUtils
833  Display
834  GetConfig
835  Logger
836  OSDep
837  Utils
838
839 =end man
840
841 =begin html
842
843 <blockquote>
844 <a href="http://clearscm.com/php/scm_man.php?file=lib/Clearcase.pm">Clearcase</a><br>
845 <a href="http://clearscm.com/php/scm_man.php?file=lib/Clearcase/Element.pm">Element</a><br>
846 <a href="http://clearscm.com/php/scm_man.php?file=lib/Clearcase/View.pm">View</a><br>
847 <a href="http://clearscm.com/php/scm_man.php?file=lib/Clearcase/Views.pm">Views</a><br>
848 <a href="http://clearscm.com/php/scm_man.php?file=lib/Clearcase/Vob.pm">Vob</a><br>
849 <a href="http://clearscm.com/php/scm_man.php?file=lib/Clearcase/Vobs.pm">Vobs</a><br>
850 <a href="http://clearscm.com/php/scm_man.php?file=lib/Clearcase/UCM.pm">UCM</a><br>
851 <a href="http://clearscm.com/php/scm_man.php?file=lib/Clearcase/UCM/Activity.pm">Activity</a><br>
852 <a href="http://clearscm.com/php/scm_man.php?file=lib/Clearcase/UCM/Baseline.pm">Baseline</a><br>
853 <a href="http://clearscm.com/php/scm_man.php?file=lib/Clearcase/UCM/Component.pm">Component</a><br>
854 <a href="http://clearscm.com/php/scm_man.php?file=lib/Clearcase/UCM/Project.pm">Project</a><br>
855 <a href="http://clearscm.com/php/scm_man.php?file=lib/Clearcase/UCM/Pvob.pm">Pvob</a><br>
856 <a href="http://clearscm.com/php/scm_man.php?file=lib/Clearcase/UCM/Stream.pm">Stream</a><br>
857 <a href="http://clearscm.com/php/scm_man.php?file=lib/DateUtils.pm">DateUtils</a><br>
858 <a href="http://clearscm.com/php/scm_man.php?file=lib/Display.pm">Display</a><br>
859 <a href="http://clearscm.com/php/scm_man.php?file=lib/GetConfig.pm">GetConfig</a><br>
860 <a href="http://clearscm.com/php/scm_man.php?file=lib/Logger.pm">Logger</a><br>
861 <a href="http://clearscm.com/php/scm_man.php?file=lib/OSDep.pm">OSDep</a><br>
862 <a href="http://clearscm.com/php/scm_man.php?file=lib/Utils.pm">Utils</a><br>
863 </blockquote>
864
865 =end html
866
867 =head1 BUGS AND LIMITATIONS
868
869 There are no known bugs in this script
870
871 Please report problems to Andrew DeFaria <Andrew@ClearSCM.com>.
872
873 =head1 LICENSE AND COPYRIGHT
874
875 Copyright (c) 2010, ClearSCM, Inc. All rights reserved.
876
877 =cut