Subversion Repositories gelsvn

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
107 bj 1
package Driver;
2
 
3
# ************************************************************
4
# Description   : Functionality to call a workspace or project creator
5
# Author        : Chad Elliott
6
# Create Date   : 5/28/2002
7
# ************************************************************
8
 
9
# ************************************************************
10
# Pragmas
11
# ************************************************************
12
 
13
use strict;
14
use File::Basename;
15
 
16
use Options;
17
use Parser;
18
use Version;
19
 
20
use vars qw(@ISA);
21
@ISA = qw(Parser Options);
22
 
23
# ************************************************************
24
# Data Section
25
# ************************************************************
26
 
27
my($index)    = 0;
28
my(@progress) = ('|', '/', '-', '\\');
29
my($cmdenv)   = 'MPC_COMMANDLINE';
30
my($minperl)  = 5.006;
31
 
32
# ************************************************************
33
# Subroutine Section
34
# ************************************************************
35
 
36
sub new {
37
  my($class)    = shift;
38
  my($path)     = shift;
39
  my($name)     = shift;
40
  my(@creators) = @_;
41
  my($self)     = $class->SUPER::new();
42
 
43
  $self->{'path'}     = $path;
44
  $self->{'name'}     = $name;
45
  $self->{'types'}    = {};
46
  $self->{'creators'} = \@creators;
47
  $self->{'default'}  = $creators[0];
48
  $self->{'reldefs'}  = {};
49
  $self->{'relorder'} = [];
50
 
51
  return $self;
52
}
53
 
54
 
55
sub convert_slashes {
56
  #my($self) = shift;
57
  return 0;
58
}
59
 
60
 
61
sub parse_line {
62
  my($self)        = shift;
63
  my($ih)          = shift;
64
  my($line)        = shift;
65
  my($status)      = 1;
66
  my($errorString) = undef;
67
 
68
  if ($line eq '') {
69
  }
70
  elsif ($line =~ /^([\w\*]+)(\s*,\s*(.*))?$/) {
71
    my($name)  = $1;
72
    my($value) = $3;
73
    if (defined $value) {
74
      $value =~ s/^\s+//;
75
      $value =~ s/\s+$//;
76
    }
77
    if ($name =~ /\*/) {
78
      $name =~ s/\*/.*/g;
79
      foreach my $key (keys %ENV) {
80
        if ($key =~ /^$name$/ && !exists $self->{'reldefs'}->{$key}) {
81
          ## Put this value at the front since it doesn't need
82
          ## to be built up from anything else.  It is a stand-alone
83
          ## relative definition.
84
          $self->{'reldefs'}->{$key} = undef;
85
          unshift(@{$self->{'relorder'}}, $key);
86
        }
87
      }
88
    }
89
    else {
90
      $self->{'reldefs'}->{$name} = $value;
91
      if (defined $value) {
92
        ## This relative definition may need to be built up from an
93
        ## existing value, so it needs to be put at the end.
94
        push(@{$self->{'relorder'}}, $name);
95
      }
96
      else {
97
        ## Put this value at the front since it doesn't need
98
        ## to be built up from anything else.  It is a stand-alone
99
        ## relative definition.
100
        unshift(@{$self->{'relorder'}}, $name);
101
      }
102
    }
103
  }
104
  else {
105
    $status = 0;
106
    $errorString = "Unrecognized line: $line";
107
  }
108
 
109
  return $status, $errorString;
110
}
111
 
112
 
113
sub optionError {
114
  my($self) = shift;
115
  my($line) = shift;
116
 
117
  $self->printUsage($line, $self->{'name'}, Version::get(),
118
                    $self->extractType($self->{'default'}),
119
                    keys %{$self->{'types'}});
120
  exit(0);
121
}
122
 
123
 
124
sub run {
125
  my($self) = shift;
126
  my(@args) = @_;
127
 
128
  ## If the minimum version of perl is not met, then it is an error
129
  if ($] < $minperl) {
130
    $self->error("Perl version $minperl is required.");
131
    return 1;
132
  }
133
 
134
  ## Dynamically load in each perl module and set up
135
  ## the type tags and project creators
136
  my($creators) = $self->{'creators'};
137
  foreach my $creator (@$creators) {
138
    my($tag) = $self->extractType($creator);
139
    $self->{'types'}->{$tag} = $creator;
140
  }
141
 
142
  ## Before we process the arguments, we will prepend the $cmdenv
143
  ## environment variable.
144
  if (defined $ENV{$cmdenv}) {
145
    my($envargs) = $self->create_array($ENV{$cmdenv});
146
    unshift(@args, @$envargs);
147
  }
148
 
149
  my($options) = $self->options($self->{'name'},
150
                                $self->{'types'},
151
                                1,
152
                                @args);
153
  if (!defined $options) {
154
    ## If options are not defined, that means that calling options
155
    ## took care of whatever functionality that was required and
156
    ## we can now return with a good status.
157
    return 0;
158
  }
159
 
160
  ## Set up a hash that we can use to keep track of what
161
  ## has been 'required'
162
  my(%loaded) = ();
163
 
164
  ## Set up the default creator, if no type is selected
165
  if (!defined $options->{'creators'}->[0]) {
166
    push(@{$options->{'creators'}}, $self->{'default'});
167
  }
168
 
169
  if ($options->{'recurse'}) {
170
    if (defined $options->{'input'}->[0]) {
171
      ## This is an error.
172
      ## -recurse was used and input files were specified.
173
      $self->optionError('No files should be ' .
174
                         'specified when using -recurse');
175
    }
176
    else {
177
      ## We have to load at least one creator here in order
178
      ## to call the generate_recursive_input_list virtual function.
179
      my($name) = $options->{'creators'}->[0];
180
      if (!$loaded{$name}) {
181
        require "$name.pm";
182
        $loaded{$name} = 1;
183
      }
184
 
185
      ## Generate the recursive input list
186
      my($creator) = $name->new();
187
      my(@input) = $creator->generate_recursive_input_list(
188
                                              '.', $options->{'exclude'});
189
      $options->{'input'} = \@input;
190
 
191
      ## If no files were found above, then we issue a warning
192
      ## that we are going to use the default input
193
      if (!defined $options->{'input'}->[0]) {
194
        $self->information('No files were found using the -recurse option. ' .
195
                           'Using the default input.');
196
      }
197
    }
198
  }
199
 
200
  ## Set the global feature file
201
  my($global_feature_file) = $self->{'path'} . '/config/global.features';
202
 
203
  ## Set up default values
204
  if (!defined $options->{'input'}->[0]) {
205
    push(@{$options->{'input'}}, '');
206
  }
207
  if (!defined $options->{'feature_file'}) {
208
    my($feature_file) = $self->{'path'} . '/config/default.features';
209
    if (-r $feature_file) {
210
      $options->{'feature_file'} = $feature_file;
211
    }
212
  }
213
  if (!defined $options->{'global'}) {
214
    my($global) = $self->{'path'} . '/config/global.mpb';
215
    if (-r $global) {
216
      $options->{'global'} = $global;
217
    }
218
  }
219
  ## Save the original directory outside of the loop
220
  ## to avoid calling it multiple times.
221
  my($orig_dir) = $self->getcwd();
222
 
223
  ## Always add the default include paths
224
  unshift(@{$options->{'include'}}, $orig_dir);
225
  unshift(@{$options->{'include'}}, $self->{'path'} . '/templates');
226
  unshift(@{$options->{'include'}}, $self->{'path'} . '/config');
227
 
228
  if ($options->{'reldefs'}) {
229
    ## Only try to read the file if it exists
230
    my($rel) = $self->{'path'} . '/config/default.rel';
231
    if (-r $rel) {
232
      my($srel, $errorString) = $self->read_file($rel);
233
      if (!$srel) {
234
        $self->error("$errorString\nin $rel");
235
        return 1;
236
      }
237
    }
238
 
239
    foreach my $key (@{$self->{'relorder'}}) {
240
      if (defined $ENV{$key} &&
241
          !defined $options->{'relative'}->{$key}) {
242
        $options->{'relative'}->{$key} = $ENV{$key};
243
      }
244
      if (defined $self->{'reldefs'}->{$key} &&
245
          !defined $options->{'relative'}->{$key}) {
246
        my($value) = $self->{'reldefs'}->{$key};
247
        if ($value =~ /\$(\w+)(.*)?/) {
248
          my($var)   = $1;
249
          my($extra) = $2;
250
          $options->{'relative'}->{$key} =
251
                     (defined $options->{'relative'}->{$var} ?
252
                              $options->{'relative'}->{$var} : '') .
253
                     (defined $extra ? $extra : '');
254
        }
255
        else {
256
          $options->{'relative'}->{$key} = $value;
257
        }
258
      }
259
 
260
      ## If a relative path is defined, remove all trailing slashes
261
      ## and replace any two or more slashes with a single slash.
262
      if (defined $options->{'relative'}->{$key}) {
263
        $options->{'relative'}->{$key} =~ s/([\/\\])[\/\\]+/$1/g;
264
        $options->{'relative'}->{$key} =~ s/[\/\\]$//g;
265
      }
266
    }
267
  }
268
 
269
  ## Set up un-buffered output for the progress callback
270
  $| = 1;
271
 
272
  ## Keep the starting time for the total output
273
  my($startTime) = time();
274
  my($loopTimes) = 0;
275
 
276
  ## Generate the files
277
  my($status) = 0;
278
  foreach my $cfile (@{$options->{'input'}}) {
279
    ## To correctly reference any pathnames in the input file, chdir to
280
    ## its directory if there's any directory component to the specified path.
281
    my($base) = basename($cfile);
282
 
283
    if (-d $cfile) {
284
      $base = '';
285
    }
286
 
287
    foreach my $name (@{$options->{'creators'}}) {
288
      ++$loopTimes;
289
 
290
      if (!$loaded{$name}) {
291
        require "$name.pm";
292
        $loaded{$name} = 1;
293
      }
294
      my($file) = $cfile;
295
      my($creator) = $name->new($options->{'global'},
296
                                $options->{'include'},
297
                                $options->{'template'},
298
                                $options->{'ti'},
299
                                $options->{'dynamic'},
300
                                $options->{'static'},
301
                                $options->{'relative'},
302
                                $options->{'addtemp'},
303
                                $options->{'addproj'},
304
                                (-t 1 ? \&progress : undef),
305
                                $options->{'toplevel'},
306
                                $options->{'baseprojs'},
307
                                $global_feature_file,
308
                                $options->{'feature_file'},
309
                                $options->{'features'},
310
                                $options->{'hierarchy'},
311
                                $options->{'exclude'},
312
                                $options->{'coexistence'},
313
                                $options->{'name_modifier'},
314
                                $options->{'apply_project'},
315
                                $options->{'genins'},
316
                                $options->{'into'},
317
                                $options->{'language'},
318
                                $options->{'use_env'},
319
                                $options->{'expand_vars'});
320
      if ($base ne $file) {
321
        my($dir) = ($base eq '' ? $file : $self->mpc_dirname($file));
322
        if (!$creator->cd($dir)) {
323
          $self->error("Unable to change to directory: $dir");
324
          $status++;
325
          last;
326
        }
327
        $file = $base;
328
      }
329
      my($diag) = 'Generating ' . $self->extractType($name) . ' output using ';
330
      if ($file eq '') {
331
        $diag .= 'default input';
332
      }
333
      else {
334
        my($partial)  = $self->getcwd();
335
        my($oescaped) = $self->escape_regex_special($orig_dir) . '(/)?';
336
        $partial =~ s/^$oescaped//;
337
        $diag .= ($partial ne '' ? "$partial/" : '') . $file;
338
      }
339
      $self->diagnostic($diag);
340
      my($start) = time();
341
      if (!$creator->generate($file)) {
342
        $self->error("Unable to process: " .
343
                     ($file eq '' ? 'default input' : $file));
344
        $status++;
345
        last;
346
      }
347
      my($total) = time() - $start;
348
      $self->diagnostic('Generation Time: ' .
349
                        (int($total / 60) > 0 ? int($total / 60) . 'm ' : '') .
350
                        ($total % 60) . 's');
351
      $creator->cd($orig_dir);
352
    }
353
    if ($status) {
354
      last;
355
    }
356
  }
357
 
358
  ## If we went through the loop more than once, we need to print
359
  ## out the total amount of time
360
  if ($loopTimes > 1) {
361
    my($total) = time() - $startTime;
362
    $self->diagnostic('     Total Time: ' .
363
                      (int($total / 60) > 0 ? int($total / 60) . 'm ' : '') .
364
                      ($total % 60) . 's');
365
  }
366
 
367
  return $status;
368
}
369
 
370
 
371
sub progress {
372
  ## This method will be called before each output file is written.
373
  print "$progress[$index]\r";
374
  $index++;
375
  if ($index > $#progress) {
376
    $index = 0;
377
  }
378
}
379
 
380
 
381
1;