ViewVC Help
View File | Revision Log | Show Annotations | Root Listing
root/cvsroot/COMP/SCRAM/src/BuildSystem/DataCollector.pm
Revision: 1.8
Committed: Mon Sep 11 14:53:39 2006 UTC (18 years, 7 months ago) by sashby
Content type: text/plain
Branch: MAIN
CVS Tags: V1_1_7, V1_1_6, V1_1_5, V1_2_0-cand1, V1_1_4, V1_1_3, V1_1_2, V1_1_0_reltag8, V1_1_0_reltag7, V1_1_0_reltag6, V1_1_1, V1_1_0_reltag5, V1_1_0_reltag4, V1_1_0_reltag3, V1_1_0_reltag2, V1_1_0_reltag1, V1_1_0_reltag, V1_0_3-p4, V1_1_0_cand3, V1_1_0_cand2, V1_1_0_cand1, HEAD_SM_071214, forV1_1_0, v103_xml_071106, V1_0_3-p3, V1_0_3-p2, V1_1_0, v110p1, V110p6, V110p5, V110p4, V110p3, before110xmlBRmerge, V110p2, V110p1, V1_0_3-p1, V1_0_3
Branch point for: forBinLess_SCRAM, HEAD_BRANCH_SM_071214, v200branch, v103_with_xml
Changes since 1.7: +4 -7 lines
Log Message:
merged from v103_branch

File Contents

# User Rev Content
1 sashby 1.2 #____________________________________________________________________
2     # File: DataCollector.pm
3     #____________________________________________________________________
4     #
5     # Author: Shaun Ashby <Shaun.Ashby@cern.ch>
6     # Update: 2004-06-30 11:13:06+0200
7 sashby 1.8 # Revision: $Id: DataCollector.pm,v 1.7.2.1 2006/09/01 17:31:48 sashby Exp $
8 sashby 1.2 #
9     # Copyright: 2004 (C) Shaun Ashby
10     #
11     #--------------------------------------------------------------------
12     package BuildSystem::DataCollector;
13     require 5.004;
14    
15     # A transient cache for tracking frequency of packages:
16     my $TRANSIENTCACHE = {};
17    
18     use Exporter;
19     @ISA=qw(Exporter);
20     @EXPORT_OK=qw( );
21    
22     sub new()
23     ###############################################################
24     # new #
25     ###############################################################
26     # modified : Wed Jun 30 11:13:20 2004 / SFA #
27     # params : #
28     # : #
29     # function : #
30     # : #
31     ###############################################################
32     {
33     my $proto=shift;
34     my $class=ref($proto) || $proto;
35     my $self={};
36     my ($buildcache,$toolmgr,$path,$scramprojects,$sprojectbases,$scramgrapher)=@_;
37    
38     bless $self,$class;
39    
40     $self->{BUILDCACHE} = $buildcache;
41     $self->{TOOLMGR} = $toolmgr;
42     $self->{BRANCH} = $path;
43    
44     $self->{SPROJECTS} = $scramprojects;
45     $self->{SPROJECTBASES} = $sprojectbases;
46    
47     $self->{SEEN_LOCAL_PACKAGES}={};
48     $self->{SEEN_RELEASE_PACKAGES}={};
49     $self->{SEEN_REMOTE_PACKAGES}={};
50     $self->{SEEN_TOOLS}={};
51    
52     $self->{G} = $scramgrapher;
53    
54     # Somewhere to store the real data:
55     $self->{content} = {};
56    
57     return $self;
58     }
59    
60     sub prepare_meta()
61     {
62     my $self=shift;
63     my ($packdir)=@_;
64     my @itemnames=qw( INCLUDE LIBDIR LIB LIBTYPE MAKEFILE FLAGS ); # the list of tags to be collected
65     my $showgraphs = 1; # We assume we have packages as deps so can show graphs if enabled
66    
67     # See if we can do a topological sort:
68     $self->{BUILD_ORDER} = $self->{G}->sort();
69     $self->{METADATA_ORDER} = [ reverse(@{$self->{BUILD_ORDER}}) ];
70    
71     # Also need to collect other data e.g. INCLUDE LIBDIR LIB LIBTYPE MAKEFILE FLAGS, from
72     # inside product tags:
73     if (exists($self->{content}->{$packdir}))
74     {
75     foreach my $item (@itemnames)
76     {
77     $self->datacollector($item, $self->{content}->{$packdir}->{$item});
78     }
79     }
80    
81     # Check to see if there were any packages:
82     if ($#{$self->{METADATA_ORDER}} >= 0)
83     {
84     # Here is where we actually prepare the INCLUDE, LIB, LIBDIR, FLAGS data for
85     # all tools and packages needed by this package:
86     foreach my $mdobject (@{$self->{METADATA_ORDER}})
87     {
88     if (exists($self->{content}->{$mdobject}))
89     {
90     # We have a local, release or remote package:
91     foreach my $item (@itemnames)
92     {
93     $self->datacollector($item, $self->{content}->{$mdobject}->{$item});
94     }
95     }
96     elsif (exists($self->{SEEN_TOOLS}->{$mdobject}) && $self->{SEEN_TOOLS}->{$mdobject} ne 'SCRAM')
97     {
98     # Check tools
99     # Make a copy of the tool object:
100     my $t = $self->{SEEN_TOOLS}->{$mdobject};
101     $self->tooldatacollector($t);
102     }
103     elsif ($self->{TOOLMGR}->definedtool(lc($mdobject)))
104     {
105     # Maybe this is a tool picked up from another package. We check to see if it's in
106     # our toolbox:
107     my $t=$self->{TOOLMGR}->checkifsetup(lc($mdobject));
108     $self->tooldatacollector($t);
109     }
110     }
111     }
112     else
113     {
114     # There were no entries in METADATA_ORDER but we might have some other data,
115     # especially INCLUDE: handle that here
116     print "SCRAM debug: No packages in our data dir (\"",$packdir,"\")\n",if ($ENV{SCRAM_DEBUG});
117     # Check to see if there's data and collect it:
118     if (exists($self->{content}->{$packdir}))
119     {
120     # We have a local, release or remote package:
121     foreach my $item (@itemnames)
122     {
123     $self->datacollector($item, $self->{content}->{$packdir}->{$item});
124     }
125     }
126     # We don't show graphs:
127     $showgraphs = 0;
128     }
129     # return:
130     return $showgraphs;
131     }
132    
133     sub tooldatacollector()
134     {
135     my $self=shift;
136     my ($tool)=@_;
137     my $TS=[ qw( LIB LIBDIR INCLUDE ) ];
138    
139     # Deal with any variables first .Store directly into the hash
140     # that will be exposed to the template engine:
141     foreach my $toolvar ($tool->list_variables())
142     {
143     $self->{DATA}->{VARIABLES}->{$toolvar} = $tool->variable_data($toolvar);
144     }
145    
146     # Collect Makefile tags and store directly in DATA:
147     $self->storedata(MAKEFILE,[ $tool->makefile() ],''); # No referring name needed:
148    
149     # Store the flags into the DATA hash:
150     if (defined (my $fhash=$tool->allflags()))
151     {
152     while (my ($flag, $flagvalue) = each %{$fhash})
153     {
154     $self->flags($flag,$flagvalue);
155     }
156     }
157    
158     # Finally we get the LIB/LIBDIR/INCLUDE:
159     foreach my $T (@{$TS})
160     {
161     my $sub=lc($T);
162     $self->datacollector($T, [ $tool->$sub() ]);
163     }
164     }
165    
166     sub datacollector()
167     {
168     my $self=shift;
169     my ($tag,$data)=@_;
170    
171     if ($tag eq 'FLAGS') # This data is a hash
172     {
173     $self->storedata($tag,$data);
174     return;
175     }
176    
177     # We need somewhere to store the data:
178     if (! exists($self->{DATA}))
179     {
180     $self->{DATA} = {};
181     }
182    
183     # For libs, we need to check to see if we have a library that should
184     # appear first in list of libs:
185     if ($tag eq 'LIB')
186     {
187     # Now we take the data passed to us and squirrel it away:
188     if (exists($self->{DATA}->{$tag}))
189     {
190     # Only add the item if it doesn't already exist:
191     foreach my $d (@$data)
192     {
193     # If there is a match to F:<lib>, extract the lib name
194     # and store it in a FIRSTLIBS array:
195     if ($d =~ /^F:(.*)?/)
196     {
197     my $libname=$1;
198     if (exists($self->{DATA}->{FIRSTLIB}))
199     {
200     # Check to see if the library already appears in the LIB
201     if (! grep($libname eq $_, @{$self->{DATA}->{FIRSTLIB}}))
202     {
203     push(@{$self->{DATA}->{FIRSTLIB}}, $libname);
204     }
205     }
206     else
207     {
208     # Create the firstlib array:
209     $self->{DATA}->{FIRSTLIB} = [ $libname ];
210     }
211     }
212     else
213     {
214     if (! grep($d eq $_, @{$self->{DATA}->{$tag}}))
215     {
216     push(@{$self->{DATA}->{$tag}},$d);
217     }
218     }
219     }
220     }
221     else
222     {
223     # The storage for lib doesn't exist yet so create it here:
224     $self->{DATA}->{$tag} = [];
225    
226     foreach my $d (@$data)
227     {
228     # If there is a match to F:<lib>, extract the lib name
229     # and store it in a FIRSTLIBS array:
230     if ($d =~ /^F:(.*)?/)
231     {
232     my $libname=$1;
233     if (exists($self->{DATA}->{FIRSTLIB}))
234     {
235     # Check to see if the library already appears in the LIB
236     if (! grep($libname eq $_, @{$self->{DATA}->{FIRSTLIB}}))
237     {
238     push(@{$self->{DATA}->{FIRSTLIB}}, $libname);
239     }
240     }
241     else
242     {
243     # Create the firstlib array:
244     $self->{DATA}->{FIRSTLIB} = [ $libname ];
245     }
246     }
247     else
248     {
249     push(@{$self->{DATA}->{$tag}},$d);
250     }
251     }
252     }
253     }
254     else
255     {
256     # Now we take the data passed to us and squirrel it away:
257     if (exists($self->{DATA}->{$tag}))
258     {
259     # Only add the item if it doesn't already exist:
260     foreach my $d (@$data)
261     {
262     if (! grep($d eq $_, @{$self->{DATA}->{$tag}}))
263     {
264     push(@{$self->{DATA}->{$tag}},$d);
265     }
266     }
267     }
268     else
269     {
270     $self->{DATA}->{$tag} = [ @$data ];
271     }
272     }
273     }
274    
275     sub storedata()
276     {
277     my $self=shift;
278     my ($tag,$value,$referrer)=@_;
279    
280     if ($tag eq 'PRODUCTSTORE')
281     {
282     # Handle productstore variables. Store in a hash with "SCRAMSTORE_x" as the key
283     # pointing to correct path as it should appear in the Makefiles:
284     foreach my $H (@{$value})
285     {
286     my $storename="";
287     # Probably want the store value to be set to <name/<arch> or <arch>/<name> with
288     # <path> only prepending to this value rather than replacing <name>: FIXME...
289     if ($$H{'type'} eq 'arch')
290     {
291     if ($$H{'swap'} eq 'true')
292     {
293 sashby 1.8 $storename .= $$H{'name'}."/".$ENV{SCRAM_ARCH};
294 sashby 1.2 }
295     else
296     {
297 sashby 1.8 $storename .= $ENV{SCRAM_ARCH}."/".$$H{'name'};
298 sashby 1.2 }
299     }
300     else
301     {
302 sashby 1.8 $storename .= $$H{'name'};
303 sashby 1.2 }
304    
305     $self->addstore("SCRAMSTORENAME_".uc($$H{'name'}),$storename);
306     }
307     }
308     elsif ($tag eq 'FLAGS')
309     {
310     while (my ($flag,$flagvalue) = each %{$value})
311     {
312     $self->flags($flag,$flagvalue);
313     }
314     }
315     elsif ($tag eq 'MAKEFILE')
316     {
317     if (! exists($self->{DATA}->{MAKEFILE}))
318     {
319     $self->{DATA}->{MAKEFILE} = [ @$value ];
320     }
321     else
322     {
323     push(@{$self->{DATA}->{MAKEFILE}},@$value);
324     }
325     }
326     else
327     {
328     if (exists($self->{content}->{$referrer}))
329     {
330     if (! exists($self->{content}->{$referrer}->{$tag}))
331     {
332     $self->{content}->{$referrer}->{$tag} = [ @$value ];
333     }
334     else
335     {
336     push(@{$self->{content}->{$referrer}->{$tag}},@$value);
337     }
338     }
339     else
340     {
341     $self->{content}->{$referrer} = {};
342     $self->{content}->{$referrer}->{$tag} = [ @$value ];
343     }
344     }
345     }
346    
347     sub check_export()
348     {
349     my $self=shift;
350     my ($pkdata,$package)=@_;
351    
352     if (! $pkdata->hasexport())
353     {
354     # No export so we return:
355     return(0);
356     }
357     else
358     {
359     my $exported = $pkdata->exported();
360    
361     # We've seen this package: make a note
362     $TRANSIENTCACHE->{$package} = 1;
363    
364     # Collect the exported data:
365     $self->{G}->vertex($package);
366     $self->process_export($exported,$package);
367     return(1);
368     }
369     }
370    
371     sub process_export()
372     {
373     my $self=shift;
374     my ($export,$package)=@_;
375    
376     while (my ($tag,$tagvalue) = each %{$export})
377     {
378     # We check for <use> and pull in this data too:
379     if ($tag eq 'USE')
380     {
381     foreach my $TV (@$tagvalue)
382     {
383     $self->{G}->edge($package, $TV);
384     }
385     # Resolve the list of uses:
386     $self->resolve_use($tagvalue);
387     }
388     elsif ($tag eq 'GROUP')
389     {
390     $self->resolve_groups($tagvalue,$package);
391     }
392     else
393     {
394     $self->storedata($tag,$tagvalue,$package);
395     }
396     }
397     }
398    
399     sub check_remote_export()
400     {
401     my $self=shift;
402     my ($projectname, $pkdata, $package)=@_;
403    
404     if (! $pkdata->hasexport())
405     {
406     # No export so we return:
407     return(0);
408     }
409     else
410     {
411     my $exported = $pkdata->exported();
412    
413     # We've seen this release/remote package: make a note
414     $TRANSIENTCACHE->{$package} = 1;
415    
416     # Collect the exported data:
417     $self->{G}->vertex($package);
418     $self->process_remote_export($projectname, $exported, $package);
419     return(1);
420     }
421     }
422    
423     sub process_remote_export()
424     {
425     my $self=shift;
426     my ($projectname,$export,$package)=@_;
427    
428     while (my ($tag,$tagvalue) = each %{$export})
429     {
430     # We check for s <use> and pull in this data too:
431     if ($tag eq 'USE')
432     {
433     foreach my $TV (@$tagvalue)
434     {
435     $self->{G}->edge($package, $TV);
436     }
437     # Resolve the list of uses:
438     $self->resolve_use($tagvalue);
439     }
440     elsif ($tag eq 'GROUP')
441     {
442     $self->resolve_groups($tagvalue,$package);
443     }
444     elsif ($tag eq 'MAKEFILE' || $tag eq 'FLAGS')
445     {
446     $self->storedata($tag, $tagvalue, $package);
447     }
448     else
449     {
450     my $newltop;
451     my $pjname=uc($projectname);
452     # Replace any occurrence of LOCALTOP in variables with <tool>_LOCALTOP unless
453     # the "project" is the release area, in which case we want RELEASETOP:
454     if ($pjname eq 'RELEASE')
455     {
456     $newltop = 'RELEASETOP';
457     }
458     else
459     {
460     $newltop=$pjname."_BASE";
461     }
462    
463     foreach my $val (@{$tagvalue})
464     {
465     $val =~ s/LOCALTOP/$newltop/g;
466     }
467    
468     # Now we store the modified data for variables:
469     $self->storedata($tag,$tagvalue,$package);
470     }
471     }
472     }
473    
474     sub resolve_arch()
475     {
476     my $self=shift;
477     my ($archdata,$referrer)=@_;
478    
479     while (my ($tagname, $tagvalue) = each %{$archdata})
480     {
481     # Look for group tags:
482     if ($tagname eq 'GROUP')
483     {
484     $self->resolve_groups($tagvalue,$referrer);
485     }
486     # Look for <use> tags:
487     elsif ($tagname eq 'USE')
488     {
489     # Add edges to our dep graph for packages needed
490     # by the referring package:
491     foreach my $TV (@{$tagvalue})
492     {
493     $self->{G}->edge($referrer, $TV);
494     }
495     # resolve the USE:
496     $self->resolve_use($tagvalue);
497     }
498     else
499     {
500     # We have another type of data:
501     $self->storedata($tagname,$tagvalue,$referrer);
502     }
503     }
504     }
505    
506     sub resolve_use()
507     {
508     my $self=shift;
509     my ($data) = @_;
510    
511     foreach my $use (@{$data})
512     {
513     # Look for the data object for the path (locally first):
514     if ($self->check_local_use($use))
515     {
516     print "- Found ",$use," locally:","\n", if ($ENV{SCRAM_DEBUG});
517     # Also store full package path for our build rules:
518     $self->local_package($use);
519     }
520     elsif ($self->check_release_use($use))
521     {
522     print "- Found ",$use," in release area:","\n", if ($ENV{SCRAM_DEBUG});
523     $self->release_package($use);
524     }
525     elsif ($self->check_remote_use($use))
526     {
527     print "- Found ",$use," in a scram-managed project:","\n", if ($ENV{SCRAM_DEBUG});
528     $self->remote_package($use);
529     }
530     # Check to see if it's an external tool. Convert the $use to lower-case first:
531     elsif ($self->{TOOLMGR}->definedtool(lc($use))
532     && (my $td=$self->{TOOLMGR}->checkifsetup(lc($use))))
533     {
534     my $toolname = $td->toolname();
535     my @tooldeps = $td->use();
536    
537     print "- Found ",$use," (an external tool):","\n", if ($ENV{SCRAM_DEBUG});
538     # We have a setup tool ($td is a ToolData object). Store the data:
539     $self->tool($td->toolname(), $td); # Store the tool data too to save retrieving again later;
540     $self->{G}->vertex(lc($toolname));
541    
542     foreach my $TD (@tooldeps)
543     {
544     # Make sure all tool refs are lowercase:
545     $self->{G}->edge(lc($toolname), lc($TD));
546     }
547    
548     # We also resolve the dependencies that this tool has on other tools:
549     $self->resolve_use(\@tooldeps);
550     }
551     else
552     {
553     # Check in the toolbox for this tool. If it doesn't
554     # exist, complain:
555     print "\n";
556     print "WARNING: Unable to find package/tool called ",$use,"\n";
557     print " in current project area (declared at ",$self->{BRANCH},")","\n";
558 sashby 1.3
559 sashby 1.5 # Record that this package is not found for the current location:
560     $self->{BUILDCACHE}->unresolved($self->{BRANCH}, $use);
561    
562 sashby 1.3 if ($ENV{SCRAM_DEBUG}) # Print more details if debug mode on
563     {
564     print "It might be that ",$use," is a relic of SCRAM V0_x series BuildFile syntax.","\n";
565     print "If so, ",$use," refers to a SubSystem: the corresponding <use name=",$use,">\n";
566     print "must be removed to get rid of this message.","\n";
567     }
568 sashby 1.2 }
569     }
570     }
571    
572     sub resolve_groups()
573     {
574     my $self=shift;
575     my ($inputgroups,$referrer)=@_;
576     my $data={};
577     $data->{USE} = [];
578    
579     # First of all, resolve group requirements in this BuildFile:
580     foreach my $n_group (@{$inputgroups})
581     {
582     # Recursively check for groups and resolve them to lowest common denom (used packages):
583     $self->recursive_group_check($n_group,$data,$referrer);
584     }
585    
586     # Resolve the $data contents:
587     while (my ($tagname, $tagvalue) = each %{$data})
588     {
589     if ($tagname eq 'USE')
590     {
591     # Add edges to our dep graph for packages needed
592     # by the referring package:
593     foreach my $TV (@{$tagvalue})
594     {
595     $self->{G}->edge($referrer, $TV);
596     }
597     # resolve the USE:
598     $self->resolve_use($tagvalue);
599     }
600     else
601     {
602     # We have another type of data in the resolved group:
603     $self->storedata($tagname,$tagvalue,$referrer);
604     }
605     }
606     }
607    
608     sub recursive_group_check()
609     {
610     my $self=shift;
611     my ($groupname,$data,$referrer)=@_;
612     my ($location);
613    
614     # See if we find the group locally:
615     if ($location = $self->{BUILDCACHE}->findgroup($groupname))
616     {
617     print "- Found group ",$groupname," locally:","\n", if ($ENV{SCRAM_DEBUG});
618     # Get the BuildFile object for the BuildFile where the group is defined;
619     my $groupbuildobject = $self->{BUILDCACHE}->buildobject($location);
620     # Get the data contained in the defined group:
621     my %dataingroup = %{$groupbuildobject->dataforgroup($groupname)};
622    
623     # For this group, check to see if there are groups required (i.e. check for any
624     # groups in data of defined group):
625     while (my ($groupdatakey, $groupdatavalue) = each %dataingroup)
626     {
627     # If we have another group, call ourselves again:
628     if ($groupdatakey eq 'GROUP')
629     {
630     # NB: probably should become recursive by invoking resolve_groups() again
631     # since we might have more than one group to resolve:
632     $self->resolve_groups($groupdatavalue,$referrer);
633     }
634     else
635     {
636     if (ref($groupdatavalue) eq 'ARRAY')
637     {
638     push(@{$data->{$groupdatakey}},@{$groupdatavalue});
639     }
640     else
641     {
642     $data->{$groupdatakey} = $groupdatavalue;
643     }
644     }
645     }
646     }
647     # Check in the release area:
648     elsif ($self->groupsearchinrelease($groupname))
649     {
650     my ($releasegroupdataobject) = $self->groupsearchinrelease($groupname);
651     print "- Found group ",$groupname," in release area of current project:","\n", if ($ENV{SCRAM_DEBUG});
652    
653     # Get the data contained in the defined group:
654     my %datainrelgroup = %{$releasegroupdataobject->dataforgroup($groupname)};
655    
656     # For this group, check to see if there are groups required (i.e. check for any
657     # groups in data of defined group):
658     while (my ($relgroupdatakey, $relgroupdatavalue) = each %datainrelgroup)
659     {
660     # If we have another group, call ourselves again:
661     if ($relgroupdatakey eq 'GROUP')
662     {
663     $self->resolve_groups($relgroupdatavalue,$referrer);
664     }
665     else
666     {
667     if (ref($relgroupdatavalue) eq 'ARRAY')
668     {
669     push(@{$data->{$relgroupdatakey}},@{$relgroupdatavalue});
670     }
671     else
672     {
673     $data->{$relgroupdatakey} = $relgroupdatavalue;
674     }
675     }
676     }
677     }
678     # Look in SCRAM-managed projects:
679     elsif ($self->groupsearchinscramprojects($groupname))
680     {
681     my ($remotegroupdataobject) = $self->groupsearchinscramprojects($groupname);
682     print "- Found group ",$groupname," in remote project:","\n", if ($ENV{SCRAM_DEBUG});
683    
684     # Get the data contained in the defined group:
685     my %datainremgroup = %{$remotegroupdataobject->dataforgroup($groupname)};
686    
687     # For this group, check to see if there are groups required (i.e. check for any
688     # groups in data of defined group):
689     while (my ($rgroupdatakey, $rgroupdatavalue) = each %datainremgroup)
690     {
691     # If we have another group, call ourselves again:
692     if ($rgroupdatakey eq 'GROUP')
693     {
694     # NB: probably should become recursive by invoking resolve_groups() again
695     # since we might have more than one group to resolve:
696     $self->resolve_groups($rgroupdatavalue,$referrer);
697     }
698     else
699     {
700     if (ref($rgroupdatavalue) eq 'ARRAY')
701     {
702     push(@{$data->{$rgroupdatakey}},@{$rgroupdatavalue});
703     }
704     else
705     {
706     $data->{$rgroupdatakey} = $rgroupdatavalue;
707     }
708     }
709     }
710     }
711     else
712     {
713     print "WARNING: Group ",$groupname," not defined. Edit BuildFile at ",$self->{BRANCH},"\n";
714     return(0);
715     }
716    
717     return $data;
718     }
719    
720     sub check_local_use()
721     {
722     my $self=shift;
723     my ($dataposition)=@_;
724    
725     # See if this is a local package that has already been seen. We must check that the package is really
726     # local before we return true if it exists in TRANSIENTCACHE:
727     if (exists ($TRANSIENTCACHE->{$dataposition}) && exists($self->{SEEN_LOCAL_PACKAGES}->{$dataposition}))
728     {
729     # Found and data has already been handled so return OK:
730     return(1);
731     }
732    
733     # Look for the data object for the path locally:
734     if (my $pkdata=$self->{BUILDCACHE}->buildobject($dataposition))
735     {
736     # We check to see if this package exported something and parse/store the data
737     # if true:
738     if (! $self->check_export($pkdata,$dataposition))
739     {
740     print "\n";
741     print "WARNING: $dataposition/BuildFile does not export anything:\n";
742     print " **** $dataposition dependency dropped.","\n";
743     print "You must edit the BuildFile at ",$self->{BRANCH}," to add an <export>.\n";
744     print "\n";
745     }
746     # Found so return OK:
747     return(1);
748     }
749     # Otherwise, not found locally:
750     return(0);
751     }
752    
753     sub check_release_use()
754     {
755     my $self=shift;
756     my ($dataposition)=@_;
757    
758     # See if this is a release package that has already been seen. We must check that the package is really
759     # in the release before we return true if it exists in TRANSIENTCACHE:
760     if (exists ($TRANSIENTCACHE->{$dataposition}) && exists($self->{SEEN_RELEASE_PACKAGES}->{$dataposition}))
761     {
762     # Found and data has already been handled so return OK:
763     return(1);
764     }
765    
766     if (my ($sproject,$scramppkgdata)=@{$self->searchinrelease($dataposition)})
767     {
768     if (! $self->check_remote_export($sproject,$scramppkgdata,$dataposition))
769     {
770     print "\n";
771     print "WARNING: $dataposition/BuildFile in release area of current project does not export anything:\n";
772     print "**** $dataposition dependency dropped.","\n";
773     }
774     # Found so return OK:
775     return(1);
776     }
777     # Otherwise, not found in release area:
778     return(0);
779     }
780    
781     sub check_remote_use()
782     {
783     my $self=shift;
784     my ($dataposition)=@_;
785    
786     # See if this is a package from a SCRAM project that has already been seen. We must check that
787     # the package is really in a remote project before we return true if it exists in TRANSIENTCACHE:
788     if (exists ($TRANSIENTCACHE->{$dataposition}) && exists($self->{SEEN_REMOTE_PACKAGES}->{$dataposition}))
789     {
790     # Found and data has already been handled so return OK:
791     return(1);
792     }
793    
794     if (my ($sproject,$scramppkgdata)=@{$self->searchinscramprojects($dataposition)})
795     {
796     if (! $self->check_remote_export($sproject,$scramppkgdata,$dataposition))
797     {
798     print "\n";
799     print "WARNING: $dataposition/BuildFile in scram project \"",$sproject,"\" does not export anything:\n";
800     print "**** $dataposition dependency dropped.","\n";
801     }
802     # Found so return OK:
803     return(1);
804     }
805     return(0);
806     }
807    
808     sub searchinscramprojects()
809     {
810     my $self=shift;
811     my ($dataposition)=@_;
812    
813     foreach my $pobj (keys %{$self->{SPROJECTS}})
814     {
815     if ($self->{SPROJECTS}->{$pobj}->buildobject($dataposition))
816     {
817     # Add the dependency on this tool (even though it's a scram project, we need the
818     # other settings that the tool provides):
819     $self->{G}->vertex($pobj);
820     $self->tool($pobj,'SCRAM');
821    
822     # Return the data object (tool name, data object):
823     return [$pobj,$self->{SPROJECTS}->{$pobj}->buildobject($dataposition)];
824     }
825     }
826    
827     # If we got here, there were no matches:
828     return (0);
829     }
830    
831     sub groupsearchinscramprojects()
832     {
833     my $self=shift;
834     my ($groupname)=@_;
835    
836     foreach my $pobj (keys %{$self->{SPROJECTS}})
837     {
838     if (my $grouplocation = $self->{SPROJECTS}->{$pobj}->findgroup($groupname))
839     {
840     return $self->{SPROJECTS}->{$pobj}->buildobject($grouplocation);
841     }
842     }
843    
844     # If we got here, there were no matches:
845     return (0);
846     }
847    
848     sub searchinrelease()
849     {
850     my $self=shift;
851     my ($dataposition)=@_;
852    
853     if (exists ($self->{SPROJECTS}->{RELEASE}) &&
854     $self->{SPROJECTS}->{RELEASE}->buildobject($dataposition))
855     {
856     # Return the data object (tool name, data object):
857     return ['RELEASE',$self->{SPROJECTS}->{RELEASE}->buildobject($dataposition)];
858     }
859    
860     # If we got here, there were no matches:
861     return (0);
862     }
863    
864     sub groupsearchinrelease()
865     {
866     my $self=shift;
867     my ($groupname)=@_;
868    
869     if (exists($self->{SPROJECTS}->{RELEASE}))
870     {
871     if (my $grouplocation = $self->{SPROJECTS}->{RELEASE}->findgroup($groupname))
872     {
873     return $self->{SPROJECTS}->{RELEASE}->buildobject($grouplocation);
874     }
875     }
876    
877     # If we got here, there were no matches:
878     return (0);
879     }
880    
881     sub local_package()
882     {
883     my $self=shift;
884     my ($package)=@_;
885    
886     if (exists ($self->{SEEN_LOCAL_PACKAGES}->{$package}))
887     {
888     $self->{SEEN_LOCAL_PACKAGES}->{$package}++;
889     }
890     else
891     {
892     $self->{SEEN_LOCAL_PACKAGES}->{$package} = 1;
893     }
894     }
895    
896     sub release_package()
897     {
898     my $self=shift;
899     my ($package)=@_;
900    
901     if (exists ($self->{SEEN_RELEASE_PACKAGES}->{$package}))
902     {
903     $self->{SEEN_RELEASE_PACKAGES}->{$package}++;
904     }
905     else
906     {
907     $self->{SEEN_RELEASE_PACKAGES}->{$package} = 1;
908     }
909     }
910    
911     sub remote_package()
912     {
913     my $self=shift;
914     my ($package)=@_;
915    
916     if (exists ($self->{SEEN_REMOTE_PACKAGES}->{$package}))
917     {
918     $self->{SEEN_REMOTE_PACKAGES}->{$package}++;
919     }
920     else
921     {
922     $self->{SEEN_REMOTE_PACKAGES}->{$package} = 1;
923     }
924     }
925    
926     sub tool()
927     {
928     my $self=shift;
929     my ($tool,$td) = @_;
930    
931     if (! exists($self->{SEEN_TOOLS}->{$tool}))
932     {
933     $self->{SEEN_TOOLS}->{$tool} = $td;
934     }
935     }
936    
937     sub local_package_deps()
938     {
939     my $self=shift;
940     my $orderedpackages=[];
941     # Check the BUILD_ORDER array and store all local
942     # packages found:
943     foreach my $LP (@{$self->{BUILD_ORDER}})
944     {
945     if (exists($self->{SEEN_LOCAL_PACKAGES}->{$LP}))
946 sashby 1.7 {
947     # If there's not a src dir in this package, don't append
948     # the build rule (since there's nothing to build):
949     if ( -d $ENV{SCRAM_SOURCEDIR}."/".$LP."/src")
950     {
951     push(@$orderedpackages, $LP);
952     }
953 sashby 1.2 }
954     }
955    
956     return $orderedpackages;
957     }
958    
959     ####### Now some interface routines ########
960     sub addstore()
961     {
962     my $self=shift;
963     my ($name,$value)=@_;
964 sashby 1.4
965     # Make sure that the name of the store can be used as a
966     # variable, i.e. for paths, replace "/" with "_":
967     $name =~ s|/|_|g;
968 sashby 1.2 # Add a new SCRAMSTORE. First we check to see if there
969     # is already a store with the same name. If there is, we
970     # do nothing since the buildfiles are parsed in the order
971     # LOCAL->PARENT->PROJECT so the first one to be set will be
972     # obtained locally. We want this behaviour so we can override
973     # the main product storage locations locally:
974     if (!exists($self->{SCRAMSTORE}->{$name}))
975     {
976     $self->{SCRAMSTORE}->{$name} = $value;
977     }
978     else
979     {
980     print "INFO: Product storage area \"",$self->{SCRAMSTORE}->{$name},"\" has been redefined locally.","\n"
981     if ($ENV{SCRAM_DEBUG});
982     }
983     }
984    
985     sub scramstore()
986     {
987     my $self=shift;
988     my ($name) = @_;
989     (exists $self->{SCRAMSTORE}->{"SCRAMSTORENAME_".$name}) ?
990     return $self->{SCRAMSTORE}->{"SCRAMSTORENAME_".$name}
991     : return "";
992     }
993    
994     sub allscramstores()
995     {
996     my $self=shift;
997     # Return a hash of scram stores:
998     return $self->{SCRAMSTORE};
999     }
1000    
1001     sub flags()
1002     {
1003     my $self=shift;
1004     my ($flag,$flagvalue) = @_;
1005    
1006     if ($flag && $flagvalue)
1007     {
1008     # If FLAGS already exist, append:
1009     if (exists ($self->{DATA}->{FLAGS}->{$flag}))
1010     {
1011     # Add each flag ONLY if it doesn't already exist:
1012     foreach my $F (@$flagvalue)
1013     {
1014     push(@{$self->{DATA}->{FLAGS}->{$flag}},$F),
1015     if (! grep($F eq $_, @{$self->{DATA}->{FLAGS}->{$flag}}));
1016     }
1017     }
1018     else
1019     {
1020     # Create a new array of flags:
1021     $self->{DATA}->{FLAGS}->{$flag} = [ @$flagvalue ];
1022     }
1023     }
1024     elsif ($flag && $self->{DATA}->{FLAGS}->{$flag}->[0] ne '')
1025     {
1026     return @{$self->{DATA}->{FLAGS}->{$flag}};
1027     }
1028     else
1029     {
1030     return "";
1031     }
1032     }
1033    
1034     sub allflags()
1035     {
1036     my $self=shift;
1037     my $flags={};
1038    
1039     # Return a hash containing FLAGNAME, FLAGSTRING pairs:
1040     while (my ($flagname,$flagvalue) = each %{$self->{DATA}->{FLAGS}})
1041     {
1042     $flags->{$flagname} = join(" ",@{$flagvalue});
1043     }
1044    
1045     return $flags;
1046     }
1047    
1048     sub variables()
1049     {
1050     my $self=shift;
1051     # Return a hash of variables:
1052     return $self->{DATA}->{VARIABLES};
1053     }
1054    
1055     sub data()
1056     {
1057     my $self=shift;
1058     my ($tag)=@_;
1059     my $sep;
1060     my $datastring="";
1061    
1062     if (exists($self->{DATA}->{$tag}))
1063     {
1064     ($tag eq 'MAKEFILE') ? $sep="\n" : $sep=" ";
1065     # Special treatment for LIB to handle libs that must
1066     # appear first in link list:
1067     if ($tag eq 'LIB')
1068     {
1069     if (exists($self->{DATA}->{FIRSTLIB}))
1070     {
1071     $datastring .= join($sep, @{$self->{DATA}->{FIRSTLIB}})." ";
1072     $datastring .= join($sep, @{$self->{DATA}->{LIB}});
1073     }
1074     else
1075     {
1076     $datastring .= join($sep,@{$self->{DATA}->{LIB}});
1077     }
1078     }
1079     else
1080     {
1081     # All other tags just join:
1082     $datastring .= join($sep, @{$self->{DATA}->{$tag}});
1083     }
1084    
1085     # return the data string:
1086     return $datastring;
1087     }
1088    
1089     return "";
1090     }
1091    
1092     sub copy()
1093     {
1094     my $self=shift;
1095     my ($localg)=@_;
1096     my $copy;
1097     # We copy the DataCollector. We only clone the grapher if
1098     # local graphing is being used, otherwise we leave the
1099     # original graph present:
1100     if ($localg) # Working at package-level
1101     {
1102     # Create a copy of our graph:
1103     my $gcopy = $self->{G}->copy();
1104     # Create a new DataCollector object, initialised with same settings as we have
1105     # in our current object:
1106     $copy = ref($self)->new($self->{BUILDCACHE},
1107     $self->{TOOLMGR},
1108     $self->{BRANCH},
1109     $self->{SPROJECTS},
1110     $self->{SPROJECTBASES},
1111     $gcopy); # The copy of the grapher
1112     }
1113     elsif ($localg == 0)
1114     {
1115     # Create a new DataCollector object, initialised with same settings as we have
1116     # in our current object:
1117     $copy = ref($self)->new($self->{BUILDCACHE},
1118     $self->{TOOLMGR},
1119     $self->{BRANCH},
1120     $self->{SPROJECTS},
1121     $self->{SPROJECTBASES},
1122     $self->{G}); # The GLOBAL grapher
1123     }
1124     else
1125     {
1126     # Unknown value:
1127     return undef;
1128     }
1129    
1130     # Copy other counters/tracking vars:
1131     $copy->{SEEN_LOCAL_PACKAGES} = { %{$self->{SEEN_LOCAL_PACKAGES}} };
1132     $copy->{SEEN_RELEASE_PACKAGES} = { %{$self->{SEEN_RELEASE_PACKAGES}} };
1133     $copy->{SEEN_REMOTE_PACKAGES} = { %{$self->{SEEN_REMOTE_PACKAGES}} };
1134     $copy->{SEEN_TOOLS} = { %{$self->{SEEN_TOOLS}} };
1135    
1136     # Copy the "content":
1137     use Data::Dumper;
1138     $Data::Dumper::Purity = 1;
1139     $Data::Dumper::Terse = 1;
1140     my $newcontent=eval(Dumper($self->{content}));
1141    
1142     if (@!)
1143     {
1144     print "SCRAM error [DataCollector]: problems copying content...","\n";
1145     }
1146    
1147     # Now copy the data:
1148     my $newdata=eval(Dumper($self->{DATA}));
1149    
1150     if (@!)
1151     {
1152     print "SCRAM error [DataCollector]: problems copying DATA content...","\n";
1153     }
1154    
1155     # Store the new content:
1156     $copy->{content} = $newcontent;
1157     # Store the new data content:
1158     $copy->{DATA} = $newdata;
1159     # Bless the object:
1160     bless $copy, ref($self);
1161     # Return the copy object:
1162     return $copy;
1163     }
1164    
1165     sub localgraph()
1166     {
1167     my $self=shift;
1168     return $self->{G};
1169     }
1170    
1171     sub attribute_data()
1172     {
1173     my $self=shift;
1174     # Prepare some data which says which packages are local,
1175     # release, remote or tools. This is needed for setting
1176     # graph attributes in SCRAMGrapher:
1177     my $attrdata =
1178     {
1179     LOCAL => [ keys %{ $self->{SEEN_LOCAL_PACKAGES}} ],
1180     RELEASE => [ keys %{ $self->{SEEN_RELEASE_PACKAGES}} ],
1181     REMOTE => [ keys %{ $self->{SEEN_REMOTE_PACKAGES}} ],
1182     TOOLS => [ keys %{ $self->{SEEN_TOOLS}} ]
1183     };
1184    
1185     return $attrdata;
1186     }
1187    
1188     sub clean4storage()
1189     {
1190     my $self=shift;
1191     # Delete all keys except those in KEEP:
1192     my @KEEP = qw( DATA BUILD_ORDER SEEN_LOCAL_PACKAGES SCRAMSTORE );
1193    
1194     foreach my $key (keys %$self)
1195     {
1196     # If this key isn't listed in KEEP, delete it:
1197     if (! grep($key eq $_, @KEEP))
1198     {
1199     delete $self->{$key};
1200     }
1201     }
1202     }
1203    
1204     1;