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;
|