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

# User Rev Content
1 sashby 1.1.2.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;