ViewVC Help
View File | Revision Log | Show Annotations | Root Listing
root/cvsroot/COMP/SCRAM/src/BuildSystem/ToolParser.pm
Revision: 1.1.2.1
Committed: Fri Feb 27 15:34:55 2004 UTC (21 years, 2 months ago) by sashby
Content type: text/plain
Branch: SCRAM_V1_BRANCH
CVS Tags: V1_pre0, SCRAM_V1, SCRAMV1_IMPORT
Branch point for: V1_pre1
Changes since 1.1: +760 -0 lines
Log Message:
First import of new SCRAM packages into CMS cvs repos.

File Contents

# Content
1 #____________________________________________________________________
2 # File: ToolParser.pm
3 #____________________________________________________________________
4 #
5 # Author: Shaun Ashby <Shaun.Ashby@cern.ch>
6 # Update: 2004-02-09 20:14:55+0100
7 # Revision: $Id: ToolParser.pm,v 1.4 2004/02/16 11:55:37 sashby Exp $
8 #
9 # Copyright: 2004 (C) Shaun Ashby
10 #
11 #--------------------------------------------------------------------
12 package BuildSystem::ToolParser;
13 require 5.004;
14
15 use Exporter;
16 use ActiveDoc::SimpleDoc;
17 use Utilities::Verbose;
18 use BuildSystem::ToolTagUtils;
19
20 @ISA=qw(Exporter Utilities::Verbose);
21 @EXPORT_OK=qw( );
22
23 #
24 sub new
25 ###############################################################
26 # new #
27 ###############################################################
28 # modified : Thu Nov 13 10:42:08 2003 / SFA #
29 # params : #
30 # : #
31 # function : #
32 # : #
33 ###############################################################
34 {
35 my $proto=shift;
36 my $class=ref($proto) || $proto;
37 my $self={};
38
39 bless $self,$class;
40
41 $self->{cache}=shift;
42 $self->{mydoctype}="BuildSystem::ToolParser";
43 $self->{mydocversion}="1.1";
44 $self->{content} = {};
45 $self->{nested} = 0;
46
47 $self->_initparser();
48
49 return $self;
50 }
51
52 sub _initparser
53 {
54 my $self=shift;
55
56 $self->{simpledoc}=ActiveDoc::SimpleDoc->new();
57 $self->{simpledoc}->newparse("setup");
58 $self->{simpledoc}->addtag("setup","Tool",
59 \&BuildSystem::ToolTagUtils::tooltagOpen, $self,
60 "", $self,
61 \&BuildSystem::ToolTagUtils::tooltagClose, $self);
62
63 $self->{simpledoc}->addtag("setup","Lib",
64 \&BuildSystem::ToolTagUtils::libtagOpen, $self,
65 "", $self,
66 "", $self);
67
68 $self->{simpledoc}->addtag("setup","info",
69 \&BuildSystem::ToolTagUtils::infotagOpen, $self,
70 "", $self,
71 "", $self);
72
73 $self->{simpledoc}->addtag("setup","Use",
74 \&BuildSystem::ToolTagUtils::usetagOpen, $self,
75 "", $self,
76 "", $self);
77
78 $self->{simpledoc}->addtag("setup","Runtime",
79 \&BuildSystem::ToolTagUtils::runtimetagOpen, $self,
80 "", $self,
81 "", $self);
82
83 $self->{simpledoc}->addtag("setup","Flags",
84 \&BuildSystem::ToolTagUtils::flagstagOpen, $self,
85 "", $self,
86 "", $self);
87
88 $self->{simpledoc}->addtag("setup","Client",
89 \&BuildSystem::ToolTagUtils::clienttagOpen, $self,
90 "", $self,
91 \&BuildSystem::ToolTagUtils::clienttagClose, $self);
92
93 $self->{simpledoc}->addtag("setup","Environment",
94 \&BuildSystem::ToolTagUtils::environmenttagOpen, $self,
95 "", $self,
96 "", $self);
97
98 $self->{simpledoc}->addtag("setup","Makefile",
99 \&BuildSystem::ToolTagUtils::makefiletagOpen, $self,
100 \&BuildSystem::ToolTagUtils::makefiletagContent, $self,
101 \&BuildSystem::ToolTagUtils::makefiletagClose, $self);
102
103 $self->{simpledoc}->grouptag("Tool","setup");
104 $self->{simpledoc}->addtag("setup","Architecture",
105 \&BuildSystem::ToolTagUtils::archtagOpen,$self,
106 "", $self,
107 \&BuildSystem::ToolTagUtils::archtagClose,$self);
108
109 }
110
111 sub parse
112 {
113 my $self=shift;
114 my ($tool,$toolver,$file)=@_;
115
116 $self->{tool}=$tool;
117 $self->{version}=$toolver;
118 $self->{simpledoc}->filetoparse($file);
119 $self->verbose("Setup Parse");
120 $self->{simpledoc}->parse("setup");
121
122 delete $self->{simpledoc};
123 return $self;
124 }
125
126 sub pushlevel
127 {
128 my $self = shift;
129 my ($info, $nextlevel)=@_;
130
131 $self->{id} = $info if (defined $info);
132
133 # Check to see if last tag was arch: if so, ceate new level:
134 if ($self->{isarch} == 1)
135 {
136 $self->{nested} = 2;
137 $self->{nexttagcontent}={};
138 }
139 else
140 {
141 $self->{nested} = 1;
142 $self->{tagcontent}={};
143 }
144
145 # Set something which says "last starter tag was ARCH":
146 if ($nextlevel)
147 {
148 $self->{isarch} = 1;
149 }
150 }
151
152 sub poplevel
153 {
154 my $self = shift;
155
156 # Drop level of nesting by one:
157 $self->{nested}--;
158
159 if ($self->{isarch} != 1)
160 {
161 delete $self->{tagcontent};
162 }
163 }
164
165 sub rmenvdata
166 {
167 my $self=shift;
168 delete $self->{ENVDATA};
169 }
170
171 ###################################
172 ## Data Access Methods ##
173 ###################################
174 sub toolname
175 {
176 my $self=shift;
177 # Return tool name:
178 return ($self->{content}->{TOOLNAME});
179 }
180
181 sub toolversion
182 {
183 my $self=shift;
184 # Return tool version:
185 return ($self->{content}->{TOOLVERSION});
186 }
187
188 sub toolcontent
189 {
190 my $self=shift;
191 # Return whole of content hash:
192 return $self->{content};
193 }
194
195 sub get_tags_to_process()
196 {
197 my $self=shift;
198 my $data=[];
199 # Return a list of features (like lib, INCLUDEDIR, LIBDIR etc.):
200
201 map { push(@$data,$_), if ($_ !~ /TOOL*/ && $_ !~ /INFO/) } keys %{$self->{content}};
202 return @{$data};
203 }
204
205 sub get_raw_data()
206 {
207 my $self=shift;
208 my ($tagtype)=@_;
209
210 # Check the number of keys for hash referred to by this object.
211 # If 0, return:
212 if (ref($self->{content}->{$tagtype}) eq 'HASH')
213 {
214 if ((my $nkeys=keys %{$self->{content}->{$tagtype}}) > 0)
215 {
216 # Return the data for the tag $tagtype. ARCH is a bit special because
217 # we want the data for the actual arch (thus, data is on a different level):
218 if ($tagtype eq 'ARCH')
219 {
220 # Check for matching arch key and return hash of relevant data:
221 while (my ($k,$v) = each %{$self->{content}->{ARCH}})
222 {
223 if ( $ENV{SCRAM_ARCH} =~ /$k.*/ )
224 {
225 return $self->{content}->{ARCH}->{$k};
226 }
227 }
228 }
229 else
230 {
231 return $self->{content}->{$tagtype};
232 }
233 }
234 else
235 {
236 print "Warning: $tagtype tags contain no other tag data!","\n";
237 return undef;
238 }
239 }
240 else
241 {
242 # We have an array of data or a scalar:
243 return $self->{content}->{$tagtype};
244 }
245 }
246
247 sub process_raw_tool()
248 {
249 my $self=shift;
250
251 # Somewhere to store the data:
252 use BuildSystem::ToolData;
253 my $tooldataobj = BuildSystem::ToolData->new();
254 $tooldataobj->toolname($self->toolname());
255 $tooldataobj->toolversion($self->toolversion());
256
257 $self->{ENVDATA} = {CLIENT => {}, RUNTIME => {}, ENVIRONMENT => {}};
258
259 foreach my $tag_to_process ($self->get_tags_to_process())
260 {
261 my $thisdata=$self->get_raw_data($tag_to_process);
262
263 # Process this data:
264 $self->process_tool_tag_data($tag_to_process, $thisdata, $tooldataobj);
265 }
266
267 $self->eval_variables($tooldataobj);
268 return $tooldataobj;
269 }
270
271 sub process_tool_tag_data()
272 {
273 my $self=shift;
274 my ($inputtag, $tagdata, $tooldataobj) = @_;
275
276 if (ref($tagdata) eq 'HASH')
277 {
278 while (my ($tag,$value) = each %{$tagdata})
279 {
280 if ($tag eq 'ENVIRONMENT')
281 {
282 # We want to avoid also storing the ARCH tags. Directly add the tags
283 # included in ARCH tags:
284 if ($inputtag eq 'ARCH')
285 {
286 $self->process_tool_tag_data($tag, $value, $tooldataobj);
287 }
288 else
289 {
290 $self->process_tool_tag_data($inputtag, $value, $tooldataobj);
291 }
292 }
293 elsif ($tag eq 'CLIENT')
294 {
295 if ($inputtag eq 'ARCH')
296 {
297 $self->process_tool_tag_data($tag, $value, $tooldataobj);
298 }
299 else
300 {
301 $self->process_tool_tag_data($inputtag, $value, $tooldataobj);
302 }
303 }
304 elsif ($tag eq 'FLAGS')
305 {
306 # We need to collect FLAGS tag data that was within ARCH tags:
307 if ($inputtag eq 'ARCH')
308 {
309 while (my ($flag,$fvalue) = each %{$value})
310 {
311 $tooldataobj->flags($flag,$fvalue);
312 }
313 }
314 }
315 else
316 {
317 if (ref($value) eq 'ARRAY')
318 {
319 my $cptag = $tag;
320 $tag =~ tr/[A-Z]/[a-z]/;
321 # If there is a method to process this kind of tag, use
322 # it to store the data:
323 if ($tooldataobj->can($tag))
324 {
325 $tooldataobj->$tag($value);
326 }
327 else
328 {
329 # Most likely we have flags so store as such:
330 $tooldataobj->flags($cptag,$value);
331 }
332 }
333 else
334 {
335 # This fixes runtime tag data collection when runtime tags are arch-dependent:
336 if ($inputtag eq 'ARCH')
337 {
338 $self->{ENVDATA}->{$tag} = $value;
339 }
340 else
341 {
342 $self->{ENVDATA}->{$inputtag}->{$tag} = $value;
343 }
344 }
345 }
346 }
347 }
348 else
349 {
350 # Only things stored here will be "Makefile", "LIB", "Include", LIBDIR data:
351 $inputtag =~ tr/[A-Z]/[a-z]/;
352 $tooldataobj->$inputtag($tagdata);
353 }
354
355 return $self->{ENVDATA};
356 }
357
358 sub set_value
359 {
360 my $self=shift;
361 my ($varname,$valuehashref) = @_;
362 my $path_from_db;
363
364 # First, check to see if there's an entry in the lookup file
365 # for this tool and that there is an entry for the input tag:
366 if ($::lookupdb->checkTool($self->toolname()))
367 {
368 if ($::lookupdb->lookupTag($self->toolname(),$varname) ne '')
369 {
370 $path_from_db = $::lookupdb->lookupTag($self->toolname(),$varname);
371 ($path)=$self->_path_validate($path_from_db);
372 $valuehashref->{$varname} = $path;
373 return $valuehashref->{$varname};
374 }
375 elsif (exists $valuehashref->{$varname})
376 {
377 return $valuehashref->{$varname};
378 }
379 else
380 {
381 # Ask the user:
382 print "Value for ",$varname," not found in lookup tables....","\n";
383 $valuehashref->{$varname} = $self->ask_user($varname);
384 return $valuehashref->{$varname};
385 }
386 }
387 elsif (exists $valuehashref->{$varname})
388 {
389 return $valuehashref->{$varname};
390 }
391 else
392 {
393 # No path setting in lookup tables so prompt user:
394 $valuehashref->{$varname} = $self->ask_user($varname);
395 return $valuehashref->{$varname};
396 }
397 }
398
399 sub ask_user
400 {
401 my $self=shift;
402 my $varname=shift;
403
404 for (;;)
405 {
406 print " Please Enter the Value for ",$varname,": > ";
407 $path=<STDIN>;
408 chomp $path;
409 my $pathcopy = $path;
410
411 if ($path ne "")
412 {
413 ($path)=$self->_path_validate($path);
414 # If the path is not defined, print
415 # a message and repeat the prompt:
416 if ( ! defined $path )
417 {
418 next;
419 }
420 return $path;
421 }
422 }
423 }
424
425 sub eval_variables
426 {
427 my $self=shift;
428 my $tooldataobj=shift;
429 my %value_hash;
430 my $tagstoprocess=0;
431 my ($good,$error) = ($main::good."[OK]".$main::normal,$main::error."[ERROR]".$main::normal);
432 my $runtime_type;
433
434 if (exists $self->{ENVDATA}->{ENVIRONMENT} &&
435 scalar(keys %{$self->{ENVDATA}->{ENVIRONMENT}}) > 0)
436 {
437 print "\nParsing Environment Settings: ","\n";
438
439 my %env_keytable;
440 map { $env_keytable{$_} = '';} keys %{$self->{ENVDATA}->{ENVIRONMENT}};
441
442 foreach my $env_key (keys %env_keytable)
443 {
444 my $env_hash = $self->{ENVDATA}->{ENVIRONMENT}->{$env_key};
445 my @environ_keys = keys %{$env_hash};
446
447 if ($#environ_keys < 0)
448 {
449 $env_keytable{$env_key} = $self->set_value($env_key,\%value_hash);
450 }
451 else
452 {
453 # There were default/value/type tags given. Pass in the value that is supplied
454 # as the environment key. This should then be evaluated:
455 $env_keytable{$env_key} = $self->set_default_value($env_key,$env_hash,\%value_hash,
456 \$runtime_type,$tooldataobj);
457 }
458 }
459
460 # Print out details of errors:
461 while (my ($k,$v) = each %env_keytable )
462 {
463 if ($v ne '')
464 {
465 printf("\tChecking %-20s : %40s\n",$k, $good);
466 }
467 else
468 {
469 printf("\tChecking %-20s : %40s\n",$k, $error);
470 print "\t\tInvalid: ",$v,"\n";
471 }
472 }
473
474 # Store the settings:
475 while (my ($store_var,$store_val) = each %value_hash)
476 {
477 my $var_copy = $store_var;
478 $store_var =~ tr/[A-Z]/[a-z]/;
479 if ($tooldataobj->can($store_var))
480 {
481 $tooldataobj->$store_var($store_val);
482 }
483 else
484 {
485 $tooldataobj->variable_data($var_copy,$store_val);
486 }
487 }
488 }
489
490 if (exists $self->{ENVDATA}->{CLIENT} &&
491 scalar(keys %{$self->{ENVDATA}->{CLIENT}}) > 0)
492 {
493 print "\nParsing Client Settings: ","\n";
494
495 # Somehow we keep track of which environments have been processed:
496 my %client_env_keytable;
497 # Store the envs we need to process:
498 map { $client_env_keytable{$_} = ''; $tagstoprocess++;} keys %{$self->{ENVDATA}->{CLIENT}};
499
500 # We have client tag so first process these environments:
501 foreach my $client_env_key (keys %client_env_keytable)
502 {
503
504 my $client_env_hash = $self->{ENVDATA}->{CLIENT}->{$client_env_key};
505 my @env_keys = keys %{$client_env_hash};
506
507 if ($#env_keys < 0)
508 {
509 $client_env_keytable{$client_env_key} = $self->set_value($client_env_key,\%value_hash);
510 }
511 else
512 {
513 # There were default/value/type tags given. Pass in the value that is supplied
514 # as the environment key. This should then be evaluated:
515 $client_env_keytable{$client_env_key} = $self->set_default_value($client_env_key,$client_env_hash,
516 \%value_hash,\$runtime_type,$tooldataobj);
517 }
518 }
519
520 # Print out details of errors:
521 while (my ($k,$v) = each %client_env_keytable )
522 {
523 if ($v ne '')
524 {
525 printf("\tChecking %-20s : %40s\n",$k, $good);
526 }
527 else
528 {
529 printf("\tChecking %-20s : %40s\n",$k, $error);
530 print "\t\tInvalid: ",$v,"\n";
531 }
532 }
533
534 # Store the settings:
535 while (my ($store_var,$store_val) = each %value_hash)
536 {
537 my $var_copy = $store_var;
538 $store_var =~ tr/[A-Z]/[a-z]/;
539 if ($tooldataobj->can($store_var))
540 {
541 $tooldataobj->$store_var($store_val);
542 }
543 else
544 {
545 $tooldataobj->variable_data($var_copy,$store_val);
546 }
547 }
548 }
549
550 # Now process RUNTIME tags:
551 if (exists $self->{ENVDATA}->{RUNTIME} &&
552 scalar(keys %{$self->{ENVDATA}->{RUNTIME}}) > 0)
553 {
554 print "\nProcessing Runtime Environment: ","\n";
555
556 my %rt_env_keytable;
557 my %rt_types;
558
559 map { $rt_env_keytable{$_} = '';} keys %{$self->{ENVDATA}->{RUNTIME}};
560
561 foreach my $rt_env_key (keys %rt_env_keytable)
562 {
563 my $rt_env_hash = $self->{ENVDATA}->{RUNTIME}->{$rt_env_key};
564 my @rt_env_keys = keys %{$rt_env_hash};
565
566 if ($#rt_env_keys < 0)
567 {
568 $rt_env_keytable{$rt_env_key} = $self->set_value($rt_env_key,\%value_hash);
569 }
570 else
571 {
572 # There were default/value/type tags given. Pass in the value that is supplied
573 # as the environment key. This should then be evaluated:
574 $rt_env_keytable{$rt_env_key} = $self->set_default_value($rt_env_key,$rt_env_hash,
575 \%value_hash,\$runtime_type,$tooldataobj);
576 $rt_types{$rt_env_key} = $runtime_type;
577 }
578 }
579
580 while (my ($k,$v) = each %rt_env_keytable )
581 {
582 if ($v ne '')
583 {
584 printf("\tChecking %-20s : %40s\n\t\t%s\n",$k, $good,$v);
585 # Store the runtime setting:
586 $tooldataobj->runtime($k,$v,$rt_types{$k});
587 }
588 else
589 {
590 printf("\tChecking %-20s : %40s\n",$k, $error);
591 print "\t\tInvalid: ",$v,"\n";
592 }
593 }
594 }
595
596 # Do some cleaning. Get rid of ENVDATA and TOOLDATA:
597 $self->rmenvdata();
598 return $tooldataobj;
599 }
600
601 sub set_default_value
602 {
603 my $self=shift;
604 my ($varname,$varhash,$valuehashref,$runtime_type,$tooldataobj) = @_;
605 my $error_status;
606
607 # We can only work with a hash ref:
608 if (ref($varhash) eq 'HASH')
609 {
610 # We specify the order in which the tags are parsed:
611 foreach my $keyname (qw(default value))
612 {
613 # See if the tag exists:
614 if (exists $varhash->{$keyname})
615 {
616 # Check to see if there's a variable used...check for $ sign:
617 if ( $varhash->{$keyname} =~ /^\$(.*?)\/.*$/ ||
618 $varhash->{$keyname} =~ /^\$(.*)?$/ )
619 {
620 # Check to see if this variable already has a value. If not,
621 # go find it:
622 if (exists $valuehashref->{$1})
623 {
624 my $expanded_value = $self->_expandvars($valuehashref, $varhash->{$keyname});
625 ($valuehashref->{$varname}) = $self->_path_validate($expanded_value);
626 }
627 elsif (exists $ENV{$1})
628 {
629 my $expanded_value = $self->_expandvars(\%ENV, $varhash->{$keyname});
630 ($valuehashref->{$varname}) = $self->_path_validate($expanded_value);
631 }
632 else
633 {
634 $self->set_value($1,$valuehashref);
635 my $expanded_value = $self->_expandvars($valuehashref, $varhash->{$keyname});
636 ($valuehashref->{$varname}) = $self->_path_validate($expanded_value);
637 }
638 }
639 else
640 {
641 # We just have a value on it's own. Check it and use it:
642 ($valuehashref->{$varname}) = $self->_path_validate($varhash->{$keyname});
643 }
644 }
645 # Otherwise, there wasn't a default or value to use. We continue:
646 }
647
648 # Next see if there was a type:
649 if (exists $varhash->{'type'})
650 {
651 # We store the type for later use:
652 $$runtime_type=$varhash->{'type'};
653 if ($varhash->{'type'} eq 'path' || $varhash->{'type'} eq 'bin')
654 {
655 # For bin and path types, we want to validate the settings:
656 $self->set_value($varname,$valuehashref);
657 }
658 if ($varhash->{'type'} eq 'lib')
659 {
660 print "\n";
661 # Check for the libs:
662 map { $self->_lib_validate($_,$valuehashref->{'LIBDIR'},\$error_status) } $tooldataobj->lib();
663 }
664 do
665 {
666 print "ERROR: Some kind of error while checking existence of libraries.","\n";
667 print " Check your software installation then re-run setup!","\n";
668 } if ($error_status > 0);
669 }
670 print "\n";
671
672 return $valuehashref->{$varname};
673 }
674 else
675 {
676 # If we were passed something other than a hash ref, error:
677 die "set_default_value(): passed a non-hash reference!","\n";
678 }
679 }
680
681 sub _expandvars
682 {
683 my $self=shift;
684 my ($envref,$string) = @_;
685
686 return "" , if ( ! defined $string );
687 $string =~ s{\$\((\w+)\)}
688 {
689 if (defined $envref->{$1})
690 {
691 $self->_expandvars($envref, $envref->{$1});
692 }
693 else
694 {
695 "\$$1";
696 }
697 }egx;
698 $string =~ s{\$(\w+)}
699 {
700 if (defined $envref->{$1})
701 {
702 $self->_expandvars($envref, $envref->{$1});
703 }
704 else
705 {
706 "\$$1";
707 }
708 }egx;
709 return $string;
710 }
711
712 sub _path_validate()
713 {
714 my $self=shift;
715 my ($path) = @_;
716
717 if ( -f $path)
718 {
719 return $path;
720 }
721 else
722 {
723 use DirHandle;
724 my $dh=DirHandle->new();
725 opendir $dh, $path or do
726 {
727 return undef;
728 };
729 }
730 return $path;
731 }
732
733 sub _lib_validate()
734 {
735 my $self=shift;
736 my ($lib,$libpath,$errorstatus) = @_;
737 my ($good,$error)=($main::good."[OK]".$main::normal,$main::error."[ERROR]".$main::normal);
738 my $full_libname_glob=$libpath."/lib".$lib."*";
739
740 # Good status:
741 $$errorstatus = 0;
742
743 # Next we use a glob to get libs matching this string (so we
744 # can see if there's a shared or archive lib):
745 my @possible_libs = glob($full_libname_glob);
746
747 if (scalar(@possible_libs) > 0)
748 {
749 printf("\tChecking for lib%-12s : %40s\n",$lib,$good);
750 }
751 else
752 {
753 printf("\tChecking for lib%-12s : %40s\n",$lib, $error);
754 $$errorstatus++;
755 }
756
757 return $errorstatus;
758 }
759
760 1;