root/juggler/tags/2.0_alpha_2/cvs-gather.pl

Revision 12714, 37.7 kB (checked in by patrickh, 5 years ago)

Update to the official 0.1.9 version from Doozer++.

  • Property svn:eol-style set to native
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
Line 
1 #!/usr/bin/env perl
2
3 # ************** <auto-copyright.pl BEGIN do not edit this line> **************
4 #
5 # Doozer++ is (C) Copyright 2000-2003 by Iowa State University
6 #
7 # Original Author:
8 #   Patrick Hartling
9 #
10 # This library is free software; you can redistribute it and/or
11 # modify it under the terms of the GNU Library General Public
12 # License as published by the Free Software Foundation; either
13 # version 2 of the License, or (at your option) any later version.
14 #
15 # This library is distributed in the hope that it will be useful,
16 # but WITHOUT ANY WARRANTY; without even the implied warranty of
17 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18 # Library General Public License for more details.
19 #
20 # You should have received a copy of the GNU Library General Public
21 # License along with this library; if not, write to the
22 # Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23 # Boston, MA 02111-1307, USA.
24 #
25 # *************** <auto-copyright.pl END do not edit this line> ***************
26
27 # cvs-gather.pl,v 1.30 2003/06/06 16:30:07 patrickh Exp
28
29 use 5.005;
30
31 use Cwd qw(chdir getcwd);
32 use File::Basename;
33 use File::Path;
34 use Getopt::Long;
35 use Pod::Usage;
36
37 use strict 'vars';
38 use vars qw($indent $log_file $full_path $debug_level $override $max_cvs_tries);
39 use vars qw($CRITICAL_LVL $WARNING_LVL $CONFIG_LVL $STATE_LVL $VERB_LVL
40             $HVERB_LVL $HEX_LVL);
41
42 # Subroutine prototypes.
43 sub printVersion();
44 sub parse($$);
45 sub parseModule($$$;$);
46 sub handleInclude($$$);
47 sub expandWildcardLine($$);
48 sub expandWildcards($$$$$);
49 sub doOverride($$);
50 sub overrideValue($$$);
51 sub checkoutModules($);
52 sub updateModule($$$$$$);
53 sub checkoutModule($$$$$$$);
54 sub runCvsCommand($);
55 sub modifyCvsEntries($$);
56 sub expandEnvVars($);
57 sub printDebug($@);
58 sub nextSpinnerFrame($);
59
60 # *********************************************************************
61 # Here is the version for this script!
62
63 my $VERSION = '0.1.9';
64 # *********************************************************************
65
66 my $cfg_file         = '';
67 my $help             = 0;
68 my $ignore_overrides = 0;
69 my $print_version    = 0;
70 my $verbose          = 0;
71 my $entry_mod        = 0;
72 my $force_install    = 0;
73 my $manual           = 0;
74
75 my (@limit_modules) = ();
76 my (@overrides)     = ();
77 my (%cmd_overrides) = ();
78
79 $max_cvs_tries = 10;
80
81 $CRITICAL_LVL = 0;
82 $WARNING_LVL  = 1;
83 $CONFIG_LVL   = 2;
84 $STATE_LVL    = 3;
85 $VERB_LVL     = 4;
86 $HVERB_LVL    = 5;
87 $HEX_LVL      = 6;
88
89 $debug_level = $CRITICAL_LVL;
90 GetOptions('cfg=s' => \$cfg_file, 'help' => \$help, 'override=s' => \@overrides,
91            'ignore-overrides' => \$ignore_overrides,
92            'debug=i' => \$debug_level, 'set=s' => \%cmd_overrides,
93            'version' => \$print_version, 'verbose' => \$verbose,
94            'entry-mod' => \$entry_mod, 'force-install' => \$force_install,
95            'target=s' => \@limit_modules, 'manual' => \$manual,
96            'cvs-tries=i' => \$max_cvs_tries)
97    or pod2usage(2);
98
99 # Print the help output and exit if --help was on the command line.
100 pod2usage(1) if $help;
101 pod2usage(-exitstatus => 0, -verbose => 2) if $manual;
102
103 # Print the version number and exit if --version was on the command line.
104 printVersion() && exit(0) if $print_version;
105
106 # If we are doing verbose output and the user did not change the debug level,
107 # then we push the debug level up to the max.
108 $debug_level = $HVERB_LVL if $verbose && $debug_level <= $CRITICAL_LVL;
109
110 if ( ! $cfg_file )
111 {
112    if ( -r "Gatherrc" )
113    {
114       $cfg_file = 'Gatherrc';
115    }
116    elsif ( -r ".gatherrc" )
117    {
118       $cfg_file = '.gatherrc';
119    }
120    else
121    {
122       $cfg_file = "$ENV{'HOME'}/.gatherrc";
123    }
124 }
125
126 $log_file = "gather.log";
127 open(LOG_FILE, "> $log_file")
128    or warn "WARNING: Could not create log file $log_file: $!\n";
129
130 my (%orig_modules) = ();
131 parse("$cfg_file", \%orig_modules) or die "ERROR: Failed to parse $cfg_file\n";
132
133 # %orig_modules contains the set of modules with all options set as read from
134 # $cfg_file.  %override_modules is a copy of that information that will be
135 # passed around to doOverride() below.  In this way, we can retain the original
136 # module information if we need it for comparison purposes or something.  Once
137 # all the doOverride() calls are complete, %override_modules will contain
138 # exactly what the user wants in terms of modules to retrieve and what options
139 # should be used in the retrieval process.
140 my %override_modules = %orig_modules;
141
142 # If --ignore-overrides was not passed in, process any override files and
143 # override command-line arguments.
144 if ( ! $ignore_overrides )
145 {
146    # If the list of override files is empty, try the default files.
147    if ( $#overrides == -1 )
148    {
149       if ( -r ".gatherrc-override" )
150       {
151          push(@overrides, '.gatherrc-override');
152       }
153       elsif ( -r "$ENV{'HOME'}/.gatherrc-override" )
154       {
155          push(@overrides, "$ENV{'HOME'}/.gatherrc-override");
156       }
157    }
158
159    # This is a global variable (argh!) that will contain the name of the
160    # current override file being processed.
161    $override = '';
162
163    # Iterate over the list of override files passed in on the command line and
164    # apply each of them to the current environment.
165    foreach $override ( @overrides )
166    {
167       if ( open(OVERRIDE, "$override") )
168       {
169          my $line;
170          while ( $line = <OVERRIDE> )
171          {
172             chomp($line);
173
174             # Strip comments.
175             $line =~ s/#.*$//;
176
177             # Skip blank lines.
178             next if $line =~ /^\s*$/;
179
180             # The current line has at least one wildcard.
181             if ( $line =~ /\*/ )
182             {
183                if ( $line !~ /\*\./ )
184                {
185                   warn "ERROR: Invalid wildcard use at $override:$.\n";
186                }
187                else
188                {
189                   my(@override_lines) = expandWildcardLine("$line",
190                                                            \%orig_modules);
191
192                   foreach ( @override_lines )
193                   {
194                      doOverride("$_", \%override_modules);
195                   }
196                }
197             }
198             # The current line has no wildcards.
199             else
200             {
201                doOverride("$line", \%override_modules);
202             }
203          }
204
205          close(OVERRIDE);
206       }
207       else
208       {
209          warn "WARNING: Could not open override file $override: $!\n";
210       }
211    }
212
213    # Loop over all the command-line overrides (--set key=value arguments) and
214    # apply them to the current environment.
215    my $key;
216    foreach $key ( keys(%cmd_overrides) )
217    {
218       # This is needed because expandWildcardLine() and doOverride() expect to
219       # see something of the form "<key> = <value>".
220       my $line = "$key = $cmd_overrides{$key}";
221
222       # The current line has at least one wildcard.
223       if ( $key =~ /\*/ )
224       {
225          if ( $key !~ /\*\./ )
226          {
227             warn "ERROR: Invalid wildcard use at $override:$.\n";
228          }
229          else
230          {
231             my(@override_lines) = expandWildcardLine("$line", \%orig_modules);
232
233             foreach ( @override_lines )
234             {
235                doOverride("$_", \%override_modules);
236             }
237          }
238       }
239       # The current line has no wildcards.
240       else
241       {
242          doOverride("$line", \%override_modules);
243       }
244    }
245 }
246
247 my (%targeted_modules) = ();
248
249 # If the list of target modules is empty, then %override_modules contains the
250 # module list we will use.  This hash may be different from %orig_modules
251 # depending on what command-line options were given.
252 if ( $#limit_modules == -1 )
253 {
254    %targeted_modules = %override_modules;
255 }
256 else
257 {
258    foreach ( @limit_modules )
259    {
260       if ( ! defined($override_modules{"$_"}) )
261       {
262          warn "WARNING: Trying to target unknown module '$_'\n";
263          next;
264       }
265
266       $targeted_modules{"$_"} = $override_modules{"$_"};
267    }
268 }
269
270 checkoutModules(\%targeted_modules);
271 exit 0;
272
273 # -----------------------------------------------------------------------------
274 # Subroutines follow.
275 # -----------------------------------------------------------------------------
276
277 sub printVersion ()
278 {
279    print "$VERSION\n";
280
281    return 1;
282 }
283
284 sub parse ($$)
285 {
286    my $file       = shift;
287    my $module_ref = shift;
288
289    my $status = 1;
290
291    open(INPUT, "$file") or die "ERROR: Could not open $file: $!\n";
292
293    my $cfg_data = '';
294    while ( <INPUT> )
295    {
296       $cfg_data .= $_;
297    }
298    close(INPUT);
299
300    $cfg_data =~ s|/\*.*?\*/||gs; # Strip out C-style comments
301    $cfg_data =~ s/#.*$//gm;      # Strip out shell-style comments
302    $cfg_data =~ s|//.*$||gm;     # Strip out C++-style comments
303
304    my $mod_count = 0;
305    while ( $cfg_data =~ /\s*(\w.*?\w?)\s*{\s*(.*?)\s*}\s*;\s*/s )
306    {
307       my $module_name = "$1";
308       my $module_body = "$2";
309       $cfg_data       = $';
310
311       $indent = 0;
312       print "Loading $module_name from $file ...\n";
313       my $parse_stat = parseModule("$module_body", "$module_name", $module_ref);
314       return 0 if $parse_stat == -1;
315       $mod_count++
316    }
317
318    warn "WARNING: Nothing happened which probably means a parse error\n"
319       unless $mod_count > 0;
320
321    return $status;
322 }
323
324 sub parseModule ($$$;$)
325 {
326    my $module_body = shift;
327    my $module_name = shift;
328    my $module_ref  = shift;
329    my $in_module   = shift || 0;
330
331    print " " x $indent, "Parsing $module_name\n";
332
333    my $status = 1;
334
335    # Ensure that all of these are initialized just for safety's sake.
336    $$module_ref{"$module_name"}{'CVSROOT'} = '';
337    $$module_ref{"$module_name"}{'Module'}  = [];
338    $$module_ref{"$module_name"}{'Date'}    = '';
339    $$module_ref{"$module_name"}{'Tag'}     = '';
340    $$module_ref{"$module_name"}{'Path'}    = '.';
341
342    # Initialize this module's dependency hash with an anonymous hash
343    # reference.
344    $$module_ref{"$module_name"}{'deps'} = {};
345
346    while ( "$module_body" ne "" && $status == 1 )
347    {
348       printDebug $HEX_LVL, ">" x 78, "\nNew module body:\n$module_body\n",
349                            "<" x 78, "\n";
350
351       SWITCH:
352       {
353          # Matched an include.
354          if ( $module_body =~ /^(s?include\s+(.+?);)/s )
355          {
356             my $inc_string = "$1";
357             my $inc_file   = "$2";
358
359             $indent += 4;
360             $status = handleInclude("$inc_string", "$inc_file", \$module_body);
361             $indent -= 4;
362
363             last SWITCH;
364          }
365
366          if ( $module_body =~ /^CVSROOT:\s+(\S+?)\s*;/s )
367          {
368             $$module_ref{"$module_name"}{'CVSROOT'} = "$1";
369             $module_body = $';
370             last SWITCH;
371          }
372
373          if ( $module_body =~ /^Module:\s+(.+?)\s*;/s )
374          {
375             my $temp = "$1";
376             $module_body = $';
377
378             my($cvs_module_name, $install_name) = ('', '');
379
380             if ( $temp =~ /^(.+?)\s*\[(.*)\]\s*$/ )
381             {
382                $cvs_module_name = "$1";
383                $install_name    = "$2";
384             }
385             else
386             {
387                $cvs_module_name = "$temp";
388             }
389
390             push(@{$$module_ref{"$module_name"}{'Module'}},
391                  {$cvs_module_name => $install_name});
392             last SWITCH;
393          }
394
395          # Matched a tag/branch setting for this module.
396          if ( $module_body =~ /^Tag:\s+(\S+?)\s*;/s )
397          {
398             $$module_ref{"$module_name"}{'Tag'}  = "$1";
399             $module_body = $';
400             last SWITCH;
401          }
402
403          # Matched a date setting for this module.
404          if ( $module_body =~ /^Date:\s+(.+?)\s*;/s )
405          {
406             $$module_ref{"$module_name"}{'Date'}  = "$1";
407             $module_body = $';
408             last SWITCH;
409          }
410
411          # Matched a path setting for this module.
412          if ( $module_body =~ /^Path:\s+(.+?)\s*;/s )
413          {
414             my $path = "$1";
415             expandEnvVars(\$path);
416             $$module_ref{"$module_name"}{'Path'}  = "$path";
417             $module_body   = $';
418             last SWITCH;
419          }
420
421          # Matched the beginning of a sub-module.
422          if ( $module_body =~ /^(\w.*?\w?)\s*{\s*(.*)/s )
423          {
424             $indent += 4;
425             ($module_body = parseModule("$2", "$1",
426                                         $$module_ref{"$module_name"}{'deps'},
427                                         1))
428                or return 0;
429             $indent -= 4;
430             print " " x $indent, "Returning to $module_name\n";
431             last SWITCH;
432          }
433
434          # We have reached the end of the module.
435          if ( $module_body =~ /^}/ && $in_module )
436          {
437             print " " x $indent, "Finished parsing $module_name\n";
438             return $';
439          }
440
441          warn "Parse error in the following:\n$module_body\n";
442          $status = -1;
443       }
444
445       $module_body =~ s/^\s+(\S*)/$1/s;
446    }
447
448    return $status;
449 }
450
451 sub handleInclude ($$$)
452 {
453    my $inc_string = shift;
454    my $inc_file   = shift;
455    my $text_ref   = shift;
456
457    my $sinclude = 1 if $inc_string =~ /^sinclude/;
458
459    my $status = 1;
460
461    expandEnvVars(\$inc_file);
462
463    if ( open(INC_FILE, "$inc_file") )
464    {
465       my $loaded_body = '';
466       while ( <INC_FILE> )
467       {
468          $loaded_body .= $_;
469       }
470       close(INC_FILE);
471
472       $$text_ref =~ s/\Q$inc_string\E/$loaded_body/s;
473    }
474    else
475    {
476       warn "WARNING: Failed to load $inc_file: $!\n" unless $sinclude;
477       $$text_ref =~ s/\Q$inc_string\E//s;
478       $status = 0;
479    }
480
481    return $status;
482 }
483
484 sub expandWildcardLine ($$)
485 {
486    my $line       = shift;
487    my $module_ref = shift;
488
489    my (@expanded_lines) = ();
490
491    my ($path, $value) = split(/\s*=\s*/, "$line");
492    my (@path_arr)     = split(/\./, "$path");
493
494    local $full_path = "$path";
495
496    if ( $#path_arr < 1 )
497    {
498       warn "ERROR: Invalid hierarchy in $line ($override:$.)\n";
499    }
500    else
501    {
502       my (@modules) = ();
503
504       if ( "$path_arr[0]" eq "*" )
505       {
506          @modules = keys(%$module_ref);
507       }
508       else
509       {
510          $modules[0] = $path_arr[0];
511       }
512
513       my $module;
514       foreach $module ( @modules )
515       {
516          my (@work_arr) = @path_arr;
517          $work_arr[0] = "$module";
518          my $work_path = "$full_path";
519          $work_path =~ s/^\*/$module/;
520
521          expandWildcards(\@work_arr, $module_ref, $value, \@expanded_lines,
522                          $work_path);
523       }
524    }
525
526    return @expanded_lines;
527 }
528
529 sub expandWildcards ($$$$$)
530 {
531    my $path_ref       = shift;
532    my $module_ref     = shift;
533    my $override_value = shift;
534    my $lines_ref      = shift;
535    my $work_path      = shift;
536
537    my $current_value = shift(@$path_ref);
538    printDebug $VERB_LVL, "current_value: $current_value\n";
539
540    if ( "$current_value" eq "*" )
541    {
542       die "This should never happen!\n";
543    }
544    else
545    {
546       # A wildcard in this position (<Module>.*) must always indicate a
547       # project dependency.
548       if ( $$path_ref[0] && $$path_ref[0] eq "*" )
549       {
550          my (@temp_arr) = ();
551          my ($dep_name, $new_path);
552
553          shift(@$path_ref);
554          my $save_path = $work_path;
555          printDebug $VERB_LVL, "Unexpanded Path: $work_path\n";
556
557          foreach $dep_name ( keys(%{$$module_ref{"$current_value"}{'deps'}}) )
558          {
559             printDebug $VERB_LVL, "Dep: $dep_name\n";
560             @temp_arr = @$path_ref;
561             unshift(@temp_arr, "$dep_name");
562             printDebug $HVERB_LVL, "path_arr: @$path_ref\n";
563             printDebug $HVERB_LVL, "temp_arr: @temp_arr\n";
564
565             $work_path =~ s/\*/$dep_name/;
566             printDebug $VERB_LVL, "New Path: $work_path\n";
567
568             expandWildcards(\@temp_arr, $$module_ref{"$current_value"}{'deps'},
569                             $override_value, $lines_ref, $work_path);
570             $work_path = $save_path;
571          }
572
573          # If the above expansion gave us <Module>.<Setting>, we now have
574          # only <Setting> which is meaningless.
575          # XXX: It seems like this should not be necessary, but it may be the
576          # result of using a different array reference in the recursive calls.
577          shift(@$path_ref) if $#$path_ref == 0;
578       }
579       elsif ( defined($$module_ref{"$current_value"}) )
580       {
581          printDebug $STATE_LVL, "Matched $current_value\n";
582          printDebug $VERB_LVL, "Checking for $$path_ref[0] in $current_value\n";
583
584          # We have reached the end of the recursion.
585          if ( defined($$module_ref{"$current_value"}{$$path_ref[0]}) )
586          {
587             printDebug $STATE_LVL,
588                        "Adding line '$work_path = $override_value'\n";
589             push(@$lines_ref, "$work_path = $override_value");
590          }
591          elsif ( defined($$module_ref{"$current_value"}{'deps'}{$$path_ref[0]}) )
592          {
593             printDebug $STATE_LVL, "Matched dependency $$path_ref[0]\n";
594             expandWildcards($path_ref, $$module_ref{"$current_value"}{'deps'},
595                             $override_value, $lines_ref, $work_path);
596          }
597          else
598          {
599             warn "WARNING: $work_path not found!\n";
600          }
601       }
602       else
603       {
604          warn "WARNING: $work_path not found!\n";
605       }
606    }
607 }
608
609 sub doOverride ($$)
610 {
611    my $line       = shift;
612    my $module_ref = shift;
613
614    my ($path, $value) = split(/\s*=\s*/, "$line");
615    my (@path_arr)     = split(/\./, "$path");
616
617    if ( $#path_arr < 1 )
618    {
619       warn "ERROR: Invalid hierarchy in $line ($override:$.)\n";
620    }
621    else
622    {
623       local $full_path = "$path";
624       overrideValue(\@path_arr, $module_ref, "$value");
625    }
626 }
627
628 sub overrideValue ($$$)
629 {
630    my $path_ref       = shift;
631    my $module_ref     = shift;
632    my $override_value = shift;
633
634    my $current_value = shift(@$path_ref);
635
636    if ( defined($$module_ref{"$current_value"}) )
637    {
638 #      print "Matched $current_value\n";
639 #      print "Checking for ", $$path_ref[0], " in $current_value\n";
640
641       # We have reached the end of the recursion.
642       if ( defined($$module_ref{"$current_value"}{$$path_ref[0]}) )
643       {
644          if ( $$path_ref[0] eq "Module" )
645          {
646             my $module_list = "$override_value";
647             $module_list =~ s/;/ /g;
648
649             my(@modules)       = split(/;/, "$module_list");
650             my(@mod_overrides) = ();
651
652             my $mod;
653             foreach $mod ( @modules )
654             {
655                my($module_name, $install_name) = ('', '');
656
657                if ( $mod =~ /^\s*(.+?)\s*\[(.*)\]\s*$/ )
658                {
659                   $module_name  = "$1";
660                   $install_name = "$2";
661                }
662                else
663                {
664                   $module_name = "$mod";
665                }
666
667                push(@mod_overrides, {$module_name => $install_name});
668             }
669
670             print "Overriding $full_path with $module_list\n";
671             $$module_ref{"$current_value"}{'Module'} = \@mod_overrides;
672          }
673          elsif ( $$path_ref[0] eq "Path" )
674          {
675             my $new_path = "$override_value";
676             expandEnvVars(\$new_path);
677
678             print "Overriding $full_path with $new_path\n";
679             $$module_ref{"$current_value"}{'Path'} = "$new_path";
680          }
681          else
682          {
683             print "Overriding $full_path with $override_value\n";
684             $$module_ref{"$current_value"}{$$path_ref[0]} = "$override_value";
685          }
686       }
687       elsif ( defined($$module_ref{"$current_value"}{'deps'}{$$path_ref[0]}) )
688       {
689 #         print "Matched dependency $$path_ref[0]\n";
690          overrideValue($path_ref, $$module_ref{"$current_value"}{'deps'},
691                        $override_value);
692       }
693       else
694       {
695          warn "WARNING: $full_path not found!\n";
696       }
697    }
698    else
699    {
700       warn "WARNING: $full_path not found!\n";
701    }
702 }
703
704 sub checkoutModules ($)
705 {
706    my $mod_ref = shift;
707
708    my $mod_name;
709    foreach $mod_name ( keys(%$mod_ref) )
710    {
711       my $module = '';
712       foreach $module ( @{$$mod_ref{"$mod_name"}{'Module'}} )
713       {
714          my($cvs_module_name, $install_name) = each(%$module);
715
716          if ( defined($$mod_ref{"$mod_name"}{'CVSROOT'}) && $cvs_module_name )
717          {
718             # If a module is already checked out, update it instead of doing
719             # a new checkout.
720             if ( ($install_name &&
721                     -d "$$mod_ref{$mod_name}{'Path'}/$install_name") ||
722                  -d "$$mod_ref{$mod_name}{'Path'}/$cvs_module_name" )
723             {
724                updateModule("$mod_name", $$mod_ref{"$mod_name"}{'Tag'},
725                             $$mod_ref{"$mod_name"}{'Date'},
726                             $$mod_ref{"$mod_name"}{'Path'},
727                             "$cvs_module_name", "$install_name");
728             }
729             else
730             {
731                printDebug $VERB_LVL, "$mod_name --> ",
732                           "$$mod_ref{$mod_name}{'CVSROOT'} ",
733                           "$$mod_ref{$mod_name}{'Tag'} ",
734                           "$$mod_ref{$mod_name}{'Date'} ",
735                           "$cvs_module_name (to $$mod_ref{$mod_name}{'Path'}";
736                printDebug $VERB_LVL, "/$install_name" if $install_name;
737                printDebug $VERB_LVL, ")\n";
738
739                checkoutModule($mod_name, $$mod_ref{"$mod_name"}{'CVSROOT'},
740                               $$mod_ref{"$mod_name"}{'Tag'},
741                               $$mod_ref{"$mod_name"}{'Date'},
742                               "$cvs_module_name",
743                               $$mod_ref{"$mod_name"}{'Path'},
744                               "$install_name");
745             }
746          }
747       }
748
749       checkoutModules($$mod_ref{"$mod_name"}{'deps'});
750    }
751 }
752
753 sub updateModule ($$$$$$)
754 {
755    my $name         = shift;
756    my $tag          = shift;
757    my $date         = shift;
758    my $path         = shift;
759    my $cvs_module   = shift;
760    my $install_name = shift;
761
762    my $module = ("$install_name" ne "") ? "$install_name" : "$cvs_module";
763
764    print "Updating $name ($module) in $path ...\n";
765
766    my $cur_dir = getcwd();
767    chdir("$path") if "$path" ne "" && "$path" ne ".";
768
769    my $status;
770
771    if ( chdir("$module") )
772    {
773       my $cmd_line = "cvs update ";
774
775       # If we are updating on the HEAD branch and no date is specified, use
776       # 'cvs update -A' to remove any sticky tags that may exist from an
777       # earlier update or checkout.
778       if ( "$tag" eq "HEAD" && ! $date )
779       {
780          $cmd_line .= "-A ";
781       }
782       # If we are not updating on the HEAD branch or a date is given, then we
783       # need extra arguments to get sticky tags put into place.
784       else
785       {
786          # Do not use -r when the tag name is HEAD.  CVS doesn't like this.
787          $cmd_line .= "-r $tag " if $tag && "$tag" ne "HEAD";
788          $cmd_line .= "-D \"$date\" " if $date;
789       }
790
791       $status = runCvsCommand("$cmd_line");
792    }
793    else
794    {
795       warn "WARNING: Update of $module in $path failed: $!\n";
796       $status =  0;
797    }
798
799    chdir(