ViewVC Help
View File | Revision Log | Show Annotations | Root Listing
root/cvsroot/COMP/SCRAM/src/BuildSystem/DataCollector.pm
Revision: 1.5
Committed: Mon Jul 25 08:16:52 2005 UTC (19 years, 9 months ago) by sashby
Content type: text/plain
Branch: MAIN
Changes since 1.4: +7 -2 lines
Log Message:
*** empty log message ***

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.5 # Revision: $Id: DataCollector.pm,v 1.4 2005/03/11 18:55:28 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     (exists $$H{'path'}) ? ($storename .= $$H{'path'}."/".$ENV{SCRAM_ARCH})
294     : ($storename .= $$H{'name'}."/".$ENV{SCRAM_ARCH});
295     }
296     else
297     {
298     (exists $$H{'path'}) ? ($storename .= $ENV{SCRAM_ARCH}."/".$$H{'path'})
299     : ($storename .= $ENV{SCRAM_ARCH}."/".$$H{'name'});
300     }
301     }
302     else
303     {
304     (exists $$H{'path'}) ? ($storename .= $$H{'path'})
305     : ($storename .= $$H{'name'});
306     }
307    
308     $self->addstore("SCRAMSTORENAME_".uc($$H{'name'}),$storename);
309     }
310     }
311     elsif ($tag eq 'FLAGS')
312     {
313     while (my ($flag,$flagvalue) = each %{$value})
314     {
315     $self->flags($flag,$flagvalue);
316     }
317     }
318     elsif ($tag eq 'MAKEFILE')
319     {
320     if (! exists($self->{DATA}->{MAKEFILE}))
321     {
322     $self->{DATA}->{MAKEFILE} = [ @$value ];
323     }
324     else
325     {
326     push(@{$self->{DATA}->{MAKEFILE}},@$value);
327     }
328     }
329     else
330     {
331     if (exists($self->{content}->{$referrer}))
332     {
333     if (! exists($self->{content}->{$referrer}->{$tag}))
334     {
335     $self->{content}->{$referrer}->{$tag} = [ @$value ];
336     }
337     else
338     {
339     push(@{$self->{content}->{$referrer}->{$tag}},@$value);
340     }
341     }
342     else
343     {
344     $self->{content}->{$referrer} = {};
345     $self->{content}->{$referrer}->{$tag} = [ @$value ];
346     }
347     }
348     }
349    
350     sub check_export()
351     {
352     my $self=shift;
353     my ($pkdata,$package)=@_;
354    
355     if (! $pkdata->hasexport())
356     {
357     # No export so we return:
358     return(0);
359     }
360     else
361     {
362     my $exported = $pkdata->exported();
363    
364     # We've seen this package: make a note
365     $TRANSIENTCACHE->{$package} = 1;
366    
367     # Collect the exported data:
368     $self->{G}->vertex($package);
369     $self->process_export($exported,$package);
370     return(1);
371     }
372     }
373    
374     sub process_export()
375     {
376     my $self=shift;
377     my ($export,$package)=@_;
378    
379     while (my ($tag,$tagvalue) = each %{$export})
380     {
381     # We check for <use> and pull in this data too:
382     if ($tag eq 'USE')
383     {
384     foreach my $TV (@$tagvalue)
385     {
386     $self->{G}->edge($package, $TV);
387     }
388     # Resolve the list of uses:
389     $self->resolve_use($tagvalue);
390     }
391     elsif ($tag eq 'GROUP')
392     {
393     $self->resolve_groups($tagvalue,$package);
394     }
395     else
396     {
397     $self->storedata($tag,$tagvalue,$package);
398     }
399     }
400     }
401    
402     sub check_remote_export()
403     {
404     my $self=shift;
405     my ($projectname, $pkdata, $package)=@_;
406    
407     if (! $pkdata->hasexport())
408     {
409     # No export so we return:
410     return(0);
411     }
412     else
413     {
414     my $exported = $pkdata->exported();
415    
416     # We've seen this release/remote package: make a note
417     $TRANSIENTCACHE->{$package} = 1;
418    
419     # Collect the exported data:
420     $self->{G}->vertex($package);
421     $self->process_remote_export($projectname, $exported, $package);
422     return(1);
423     }
424     }
425    
426     sub process_remote_export()
427     {
428     my $self=shift;
429     my ($projectname,$export,$package)=@_;
430    
431     while (my ($tag,$tagvalue) = each %{$export})
432     {
433     # We check for s <use> and pull in this data too:
434     if ($tag eq 'USE')
435     {
436     foreach my $TV (@$tagvalue)
437     {
438     $self->{G}->edge($package, $TV);
439     }
440     # Resolve the list of uses:
441     $self->resolve_use($tagvalue);
442     }
443     elsif ($tag eq 'GROUP')
444     {
445     $self->resolve_groups($tagvalue,$package);
446     }
447     elsif ($tag eq 'MAKEFILE' || $tag eq 'FLAGS')
448     {
449     $self->storedata($tag, $tagvalue, $package);
450     }
451     else
452     {
453     my $newltop;
454     my $pjname=uc($projectname);
455     # Replace any occurrence of LOCALTOP in variables with <tool>_LOCALTOP unless
456     # the "project" is the release area, in which case we want RELEASETOP:
457     if ($pjname eq 'RELEASE')
458     {
459     $newltop = 'RELEASETOP';
460     }
461     else
462     {
463     $newltop=$pjname."_BASE";
464     }
465    
466     foreach my $val (@{$tagvalue})
467     {
468     $val =~ s/LOCALTOP/$newltop/g;
469     }
470    
471     # Now we store the modified data for variables:
472     $self->storedata($tag,$tagvalue,$package);
473     }
474     }
475     }
476    
477     sub resolve_arch()
478     {
479     my $self=shift;
480     my ($archdata,$referrer)=@_;
481    
482     while (my ($tagname, $tagvalue) = each %{$archdata})
483     {
484     # Look for group tags:
485     if ($tagname eq 'GROUP')
486     {
487     $self->resolve_groups($tagvalue,$referrer);
488     }
489     # Look for <use> tags:
490     elsif ($tagname eq 'USE')
491     {
492     # Add edges to our dep graph for packages needed
493     # by the referring package:
494     foreach my $TV (@{$tagvalue})
495     {
496     $self->{G}->edge($referrer, $TV);
497     }
498     # resolve the USE:
499     $self->resolve_use($tagvalue);
500     }
501     else
502     {
503     # We have another type of data:
504     $self->storedata($tagname,$tagvalue,$referrer);
505     }
506     }
507     }
508    
509     sub resolve_use()
510     {
511     my $self=shift;
512     my ($data) = @_;
513    
514     foreach my $use (@{$data})
515     {
516     # Look for the data object for the path (locally first):
517     if ($self->check_local_use($use))
518     {
519     print "- Found ",$use," locally:","\n", if ($ENV{SCRAM_DEBUG});
520     # Also store full package path for our build rules:
521     $self->local_package($use);
522     }
523     elsif ($self->check_release_use($use))
524     {
525     print "- Found ",$use," in release area:","\n", if ($ENV{SCRAM_DEBUG});
526     $self->release_package($use);
527     }
528     elsif ($self->check_remote_use($use))
529     {
530     print "- Found ",$use," in a scram-managed project:","\n", if ($ENV{SCRAM_DEBUG});
531     $self->remote_package($use);
532     }
533     # Check to see if it's an external tool. Convert the $use to lower-case first:
534     elsif ($self->{TOOLMGR}->definedtool(lc($use))
535     && (my $td=$self->{TOOLMGR}->checkifsetup(lc($use))))
536     {
537     my $toolname = $td->toolname();
538     my @tooldeps = $td->use();
539    
540     print "- Found ",$use," (an external tool):","\n", if ($ENV{SCRAM_DEBUG});
541     # We have a setup tool ($td is a ToolData object). Store the data:
542     $self->tool($td->toolname(), $td); # Store the tool data too to save retrieving again later;
543     $self->{G}->vertex(lc($toolname));
544    
545     foreach my $TD (@tooldeps)
546     {
547     # Make sure all tool refs are lowercase:
548     $self->{G}->edge(lc($toolname), lc($TD));
549     }
550    
551     # We also resolve the dependencies that this tool has on other tools:
552     $self->resolve_use(\@tooldeps);
553     }
554     else
555     {
556     # Check in the toolbox for this tool. If it doesn't
557     # exist, complain:
558     print "\n";
559     print "WARNING: Unable to find package/tool called ",$use,"\n";
560     print " in current project area (declared at ",$self->{BRANCH},")","\n";
561 sashby 1.3
562 sashby 1.5 # Record that this package is not found for the current location:
563     $self->{BUILDCACHE}->unresolved($self->{BRANCH}, $use);
564    
565 sashby 1.3 if ($ENV{SCRAM_DEBUG}) # Print more details if debug mode on
566     {
567     print "It might be that ",$use," is a relic of SCRAM V0_x series BuildFile syntax.","\n";
568     print "If so, ",$use," refers to a SubSystem: the corresponding <use name=",$use,">\n";
569     print "must be removed to get rid of this message.","\n";
570     }
571    
572 sashby 1.5 # FIXME: don't need to return? Otherwise, we miss other missing packages in current loc
573     # if there's more than 1:
574     # return(2);
575 sashby 1.2 }
576     }
577     }
578    
579     sub resolve_groups()
580     {
581     my $self=shift;
582     my ($inputgroups,$referrer)=@_;
583     my $data={};
584     $data->{USE} = [];
585    
586     # First of all, resolve group requirements in this BuildFile:
587     foreach my $n_group (@{$inputgroups})
588     {
589     # Recursively check for groups and resolve them to lowest common denom (used packages):
590     $self->recursive_group_check($n_group,$data,$referrer);
591     }
592    
593     # Resolve the $data contents:
594     while (my ($tagname, $tagvalue) = each %{$data})
595     {
596     if ($tagname eq 'USE')
597     {
598     # Add edges to our dep graph for packages needed
599     # by the referring package:
600     foreach my $TV (@{$tagvalue})
601     {
602     $self->{G}->edge($referrer, $TV);
603     }
604     # resolve the USE:
605     $self->resolve_use($tagvalue);
606     }
607     else
608     {
609     # We have another type of data in the resolved group:
610     $self->storedata($tagname,$tagvalue,$referrer);
611     }
612     }
613     }
614    
615     sub recursive_group_check()
616     {
617     my $self=shift;
618     my ($groupname,$data,$referrer)=@_;
619     my ($location);
620    
621     # See if we find the group locally:
622     if ($location = $self->{BUILDCACHE}->findgroup($groupname))
623     {
624     print "- Found group ",$groupname," locally:","\n", if ($ENV{SCRAM_DEBUG});
625     # Get the BuildFile object for the BuildFile where the group is defined;
626     my $groupbuildobject = $self->{BUILDCACHE}->buildobject($location);
627     # Get the data contained in the defined group:
628     my %dataingroup = %{$groupbuildobject->dataforgroup($groupname)};
629    
630     # For this group, check to see if there are groups required (i.e. check for any
631     # groups in data of defined group):
632     while (my ($groupdatakey, $groupdatavalue) = each %dataingroup)
633     {
634     # If we have another group, call ourselves again:
635     if ($groupdatakey eq 'GROUP')
636     {
637     # NB: probably should become recursive by invoking resolve_groups() again
638     # since we might have more than one group to resolve:
639     $self->resolve_groups($groupdatavalue,$referrer);
640     }
641     else
642     {
643     if (ref($groupdatavalue) eq 'ARRAY')
644     {
645     push(@{$data->{$groupdatakey}},@{$groupdatavalue});
646     }
647     else
648     {
649     $data->{$groupdatakey} = $groupdatavalue;
650     }
651     }
652     }
653     }
654     # Check in the release area:
655     elsif ($self->groupsearchinrelease($groupname))
656     {
657     my ($releasegroupdataobject) = $self->groupsearchinrelease($groupname);
658     print "- Found group ",$groupname," in release area of current project:","\n", if ($ENV{SCRAM_DEBUG});
659    
660     # Get the data contained in the defined group:
661     my %datainrelgroup = %{$releasegroupdataobject->dataforgroup($groupname)};
662    
663     # For this group, check to see if there are groups required (i.e. check for any
664     # groups in data of defined group):
665     while (my ($relgroupdatakey, $relgroupdatavalue) = each %datainrelgroup)
666     {
667     # If we have another group, call ourselves again:
668     if ($relgroupdatakey eq 'GROUP')
669     {
670     $self->resolve_groups($relgroupdatavalue,$referrer);
671     }
672     else
673     {
674     if (ref($relgroupdatavalue) eq 'ARRAY')
675     {
676     push(@{$data->{$relgroupdatakey}},@{$relgroupdatavalue});
677     }
678     else
679     {
680     $data->{$relgroupdatakey} = $relgroupdatavalue;
681     }
682     }
683     }
684     }
685     # Look in SCRAM-managed projects:
686     elsif ($self->groupsearchinscramprojects($groupname))
687     {
688     my ($remotegroupdataobject) = $self->groupsearchinscramprojects($groupname);
689     print "- Found group ",$groupname," in remote project:","\n", if ($ENV{SCRAM_DEBUG});
690    
691     # Get the data contained in the defined group:
692     my %datainremgroup = %{$remotegroupdataobject->dataforgroup($groupname)};
693    
694     # For this group, check to see if there are groups required (i.e. check for any
695     # groups in data of defined group):
696     while (my ($rgroupdatakey, $rgroupdatavalue) = each %datainremgroup)
697     {
698     # If we have another group, call ourselves again:
699     if ($rgroupdatakey eq 'GROUP')
700     {
701     # NB: probably should become recursive by invoking resolve_groups() again
702     # since we might have more than one group to resolve:
703     $self->resolve_groups($rgroupdatavalue,$referrer);
704     }
705     else
706     {
707     if (ref($rgroupdatavalue) eq 'ARRAY')
708     {
709     push(@{$data->{$rgroupdatakey}},@{$rgroupdatavalue});
710     }
711     else
712     {
713     $data->{$rgroupdatakey} = $rgroupdatavalue;
714     }
715     }
716     }
717     }
718     else
719     {
720     print "WARNING: Group ",$groupname," not defined. Edit BuildFile at ",$self->{BRANCH},"\n";
721     return(0);
722     }
723    
724     return $data;
725     }
726    
727     sub check_local_use()
728     {
729     my $self=shift;
730     my ($dataposition)=@_;
731    
732     # See if this is a local package that has already been seen. We must check that the package is really
733     # local before we return true if it exists in TRANSIENTCACHE:
734     if (exists ($TRANSIENTCACHE->{$dataposition}) && exists($self->{SEEN_LOCAL_PACKAGES}->{$dataposition}))
735     {
736     # Found and data has already been handled so return OK:
737     return(1);
738     }
739    
740     # Look for the data object for the path locally:
741     if (my $pkdata=$self->{BUILDCACHE}->buildobject($dataposition))
742     {
743     # We check to see if this package exported something and parse/store the data
744     # if true:
745     if (! $self->check_export($pkdata,$dataposition))
746     {
747     print "\n";
748     print "WARNING: $dataposition/BuildFile does not export anything:\n";
749     print " **** $dataposition dependency dropped.","\n";
750     print "You must edit the BuildFile at ",$self->{BRANCH}," to add an <export>.\n";
751     print "\n";
752     }
753     # Found so return OK:
754     return(1);
755     }
756     # Otherwise, not found locally:
757     return(0);
758     }
759    
760     sub check_release_use()
761     {
762     my $self=shift;
763     my ($dataposition)=@_;
764    
765     # See if this is a release package that has already been seen. We must check that the package is really
766     # in the release before we return true if it exists in TRANSIENTCACHE:
767     if (exists ($TRANSIENTCACHE->{$dataposition}) && exists($self->{SEEN_RELEASE_PACKAGES}->{$dataposition}))
768     {
769     # Found and data has already been handled so return OK:
770     return(1);
771     }
772    
773     if (my ($sproject,$scramppkgdata)=@{$self->searchinrelease($dataposition)})
774     {
775     if (! $self->check_remote_export($sproject,$scramppkgdata,$dataposition))
776     {
777     print "\n";
778     print "WARNING: $dataposition/BuildFile in release area of current project does not export anything:\n";
779     print "**** $dataposition dependency dropped.","\n";
780     }
781     # Found so return OK:
782     return(1);
783     }
784     # Otherwise, not found in release area:
785     return(0);
786     }
787    
788     sub check_remote_use()
789     {
790     my $self=shift;
791     my ($dataposition)=@_;
792    
793     # See if this is a package from a SCRAM project that has already been seen. We must check that
794     # the package is really in a remote project before we return true if it exists in TRANSIENTCACHE:
795     if (exists ($TRANSIENTCACHE->{$dataposition}) && exists($self->{SEEN_REMOTE_PACKAGES}->{$dataposition}))
796     {
797     # Found and data has already been handled so return OK:
798     return(1);
799     }
800    
801     if (my ($sproject,$scramppkgdata)=@{$self->searchinscramprojects($dataposition)})
802     {
803     if (! $self->check_remote_export($sproject,$scramppkgdata,$dataposition))
804     {
805     print "\n";
806     print "WARNING: $dataposition/BuildFile in scram project \"",$sproject,"\" does not export anything:\n";
807     print "**** $dataposition dependency dropped.","\n";
808     }
809     # Found so return OK:
810     return(1);
811     }
812     return(0);
813     }
814    
815     sub searchinscramprojects()
816     {
817     my $self=shift;
818     my ($dataposition)=@_;
819    
820     foreach my $pobj (keys %{$self->{SPROJECTS}})
821     {
822     if ($self->{SPROJECTS}->{$pobj}->buildobject($dataposition))
823     {
824     # Add the dependency on this tool (even though it's a scram project, we need the
825     # other settings that the tool provides):
826     $self->{G}->vertex($pobj);
827     $self->tool($pobj,'SCRAM');
828    
829     # Return the data object (tool name, data object):
830     return [$pobj,$self->{SPROJECTS}->{$pobj}->buildobject($dataposition)];
831     }
832     }
833    
834     # If we got here, there were no matches:
835     return (0);
836     }
837    
838     sub groupsearchinscramprojects()
839     {
840     my $self=shift;
841     my ($groupname)=@_;
842    
843     foreach my $pobj (keys %{$self->{SPROJECTS}})
844     {
845     if (my $grouplocation = $self->{SPROJECTS}->{$pobj}->findgroup($groupname))
846     {
847     return $self->{SPROJECTS}->{$pobj}->buildobject($grouplocation);
848     }
849     }
850    
851     # If we got here, there were no matches:
852     return (0);
853     }
854    
855     sub searchinrelease()
856     {
857     my $self=shift;
858     my ($dataposition)=@_;
859    
860     if (exists ($self->{SPROJECTS}->{RELEASE}) &&
861     $self->{SPROJECTS}->{RELEASE}->buildobject($dataposition))
862     {
863     # Return the data object (tool name, data object):
864     return ['RELEASE',$self->{SPROJECTS}->{RELEASE}->buildobject($dataposition)];
865     }
866    
867     # If we got here, there were no matches:
868     return (0);
869     }
870    
871     sub groupsearchinrelease()
872     {
873     my $self=shift;
874     my ($groupname)=@_;
875    
876     if (exists($self->{SPROJECTS}->{RELEASE}))
877     {
878     if (my $grouplocation = $self->{SPROJECTS}->{RELEASE}->findgroup($groupname))
879     {
880     return $self->{SPROJECTS}->{RELEASE}->buildobject($grouplocation);
881     }
882     }
883    
884     # If we got here, there were no matches:
885     return (0);
886     }
887    
888     sub local_package()
889     {
890     my $self=shift;
891     my ($package)=@_;
892    
893     if (exists ($self->{SEEN_LOCAL_PACKAGES}->{$package}))
894     {
895     $self->{SEEN_LOCAL_PACKAGES}->{$package}++;
896     }
897     else
898     {
899     $self->{SEEN_LOCAL_PACKAGES}->{$package} = 1;
900     }
901     }
902    
903     sub release_package()
904     {
905     my $self=shift;
906     my ($package)=@_;
907    
908     if (exists ($self->{SEEN_RELEASE_PACKAGES}->{$package}))
909     {
910     $self->{SEEN_RELEASE_PACKAGES}->{$package}++;
911     }
912     else
913     {
914     $self->{SEEN_RELEASE_PACKAGES}->{$package} = 1;
915     }
916     }
917    
918     sub remote_package()
919     {
920     my $self=shift;
921     my ($package)=@_;
922    
923     if (exists ($self->{SEEN_REMOTE_PACKAGES}->{$package}))
924     {
925     $self->{SEEN_REMOTE_PACKAGES}->{$package}++;
926     }
927     else
928     {
929     $self->{SEEN_REMOTE_PACKAGES}->{$package} = 1;
930     }
931     }
932    
933     sub tool()
934     {
935     my $self=shift;
936     my ($tool,$td) = @_;
937    
938     if (! exists($self->{SEEN_TOOLS}->{$tool}))
939     {
940     $self->{SEEN_TOOLS}->{$tool} = $td;
941     }
942     }
943    
944     sub local_package_deps()
945     {
946     my $self=shift;
947     my $orderedpackages=[];
948     # Check the BUILD_ORDER array and store all local
949     # packages found:
950     foreach my $LP (@{$self->{BUILD_ORDER}})
951     {
952     if (exists($self->{SEEN_LOCAL_PACKAGES}->{$LP}))
953     {
954     push(@$orderedpackages, $LP);
955     }
956     }
957    
958     return $orderedpackages;
959     }
960    
961     ####### Now some interface routines ########
962     sub addstore()
963     {
964     my $self=shift;
965     my ($name,$value)=@_;
966 sashby 1.4
967     # Make sure that the name of the store can be used as a
968     # variable, i.e. for paths, replace "/" with "_":
969     $name =~ s|/|_|g;
970 sashby 1.2 # Add a new SCRAMSTORE. First we check to see if there
971     # is already a store with the same name. If there is, we
972     # do nothing since the buildfiles are parsed in the order
973     # LOCAL->PARENT->PROJECT so the first one to be set will be
974     # obtained locally. We want this behaviour so we can override
975     # the main product storage locations locally:
976     if (!exists($self->{SCRAMSTORE}->{$name}))
977     {
978     $self->{SCRAMSTORE}->{$name} = $value;
979     }
980     else
981     {
982     print "INFO: Product storage area \"",$self->{SCRAMSTORE}->{$name},"\" has been redefined locally.","\n"
983     if ($ENV{SCRAM_DEBUG});
984     }
985     }
986    
987     sub scramstore()
988     {
989     my $self=shift;
990     my ($name) = @_;
991     (exists $self->{SCRAMSTORE}->{"SCRAMSTORENAME_".$name}) ?
992     return $self->{SCRAMSTORE}->{"SCRAMSTORENAME_".$name}
993     : return "";
994     }
995    
996     sub allscramstores()
997     {
998     my $self=shift;
999     # Return a hash of scram stores:
1000     return $self->{SCRAMSTORE};
1001     }
1002    
1003     sub flags()
1004     {
1005     my $self=shift;
1006     my ($flag,$flagvalue) = @_;
1007    
1008     if ($flag && $flagvalue)
1009     {
1010     # If FLAGS already exist, append:
1011     if (exists ($self->{DATA}->{FLAGS}->{$flag}))
1012     {
1013     # Add each flag ONLY if it doesn't already exist:
1014     foreach my $F (@$flagvalue)
1015     {
1016     push(@{$self->{DATA}->{FLAGS}->{$flag}},$F),
1017     if (! grep($F eq $_, @{$self->{DATA}->{FLAGS}->{$flag}}));
1018     }
1019     }
1020     else
1021     {
1022     # Create a new array of flags:
1023     $self->{DATA}->{FLAGS}->{$flag} = [ @$flagvalue ];
1024     }
1025     }
1026     elsif ($flag && $self->{DATA}->{FLAGS}->{$flag}->[0] ne '')
1027     {
1028     return @{$self->{DATA}->{FLAGS}->{$flag}};
1029     }
1030     else
1031     {
1032     return "";
1033     }
1034     }
1035    
1036     sub allflags()
1037     {
1038     my $self=shift;
1039     my $flags={};
1040    
1041     # Return a hash containing FLAGNAME, FLAGSTRING pairs:
1042     while (my ($flagname,$flagvalue) = each %{$self->{DATA}->{FLAGS}})
1043     {
1044     $flags->{$flagname} = join(" ",@{$flagvalue});
1045     }
1046    
1047     return $flags;
1048     }
1049    
1050     sub variables()
1051     {
1052     my $self=shift;
1053     # Return a hash of variables:
1054     return $self->{DATA}->{VARIABLES};
1055     }
1056    
1057     sub data()
1058     {
1059     my $self=shift;
1060     my ($tag)=@_;
1061     my $sep;
1062     my $datastring="";
1063    
1064     if (exists($self->{DATA}->{$tag}))
1065     {
1066     ($tag eq 'MAKEFILE') ? $sep="\n" : $sep=" ";
1067     # Special treatment for LIB to handle libs that must
1068     # appear first in link list:
1069     if ($tag eq 'LIB')
1070     {
1071     if (exists($self->{DATA}->{FIRSTLIB}))
1072     {
1073     $datastring .= join($sep, @{$self->{DATA}->{FIRSTLIB}})." ";
1074     $datastring .= join($sep, @{$self->{DATA}->{LIB}});
1075     }
1076     else
1077     {
1078     $datastring .= join($sep,@{$self->{DATA}->{LIB}});
1079     }
1080     }
1081     else
1082     {
1083     # All other tags just join:
1084     $datastring .= join($sep, @{$self->{DATA}->{$tag}});
1085     }
1086    
1087     # return the data string:
1088     return $datastring;
1089     }
1090    
1091     return "";
1092     }
1093    
1094     sub copy()
1095     {
1096     my $self=shift;
1097     my ($localg)=@_;
1098     my $copy;
1099     # We copy the DataCollector. We only clone the grapher if
1100     # local graphing is being used, otherwise we leave the
1101     # original graph present:
1102     if ($localg) # Working at package-level
1103     {
1104     # Create a copy of our graph:
1105     my $gcopy = $self->{G}->copy();
1106     # Create a new DataCollector object, initialised with same settings as we have
1107     # in our current object:
1108     $copy = ref($self)->new($self->{BUILDCACHE},
1109     $self->{TOOLMGR},
1110     $self->{BRANCH},
1111     $self->{SPROJECTS},
1112     $self->{SPROJECTBASES},
1113     $gcopy); # The copy of the grapher
1114     }
1115     elsif ($localg == 0)
1116     {
1117     # Create a new DataCollector object, initialised with same settings as we have
1118     # in our current object:
1119     $copy = ref($self)->new($self->{BUILDCACHE},
1120     $self->{TOOLMGR},
1121     $self->{BRANCH},
1122     $self->{SPROJECTS},
1123     $self->{SPROJECTBASES},
1124     $self->{G}); # The GLOBAL grapher
1125     }
1126     else
1127     {
1128     # Unknown value:
1129     return undef;
1130     }
1131    
1132     # Copy other counters/tracking vars:
1133     $copy->{SEEN_LOCAL_PACKAGES} = { %{$self->{SEEN_LOCAL_PACKAGES}} };
1134     $copy->{SEEN_RELEASE_PACKAGES} = { %{$self->{SEEN_RELEASE_PACKAGES}} };
1135     $copy->{SEEN_REMOTE_PACKAGES} = { %{$self->{SEEN_REMOTE_PACKAGES}} };
1136     $copy->{SEEN_TOOLS} = { %{$self->{SEEN_TOOLS}} };
1137    
1138     # Copy the "content":
1139     use Data::Dumper;
1140     $Data::Dumper::Purity = 1;
1141     $Data::Dumper::Terse = 1;
1142     my $newcontent=eval(Dumper($self->{content}));
1143    
1144     if (@!)
1145     {
1146     print "SCRAM error [DataCollector]: problems copying content...","\n";
1147     }
1148    
1149     # Now copy the data:
1150     my $newdata=eval(Dumper($self->{DATA}));
1151    
1152     if (@!)
1153     {
1154     print "SCRAM error [DataCollector]: problems copying DATA content...","\n";
1155     }
1156    
1157     # Store the new content:
1158     $copy->{content} = $newcontent;
1159     # Store the new data content:
1160     $copy->{DATA} = $newdata;
1161     # Bless the object:
1162     bless $copy, ref($self);
1163     # Return the copy object:
1164     return $copy;
1165     }
1166    
1167     sub localgraph()
1168     {
1169     my $self=shift;
1170     return $self->{G};
1171     }
1172    
1173     sub attribute_data()
1174     {
1175     my $self=shift;
1176     # Prepare some data which says which packages are local,
1177     # release, remote or tools. This is needed for setting
1178     # graph attributes in SCRAMGrapher:
1179     my $attrdata =
1180     {
1181     LOCAL => [ keys %{ $self->{SEEN_LOCAL_PACKAGES}} ],
1182     RELEASE => [ keys %{ $self->{SEEN_RELEASE_PACKAGES}} ],
1183     REMOTE => [ keys %{ $self->{SEEN_REMOTE_PACKAGES}} ],
1184     TOOLS => [ keys %{ $self->{SEEN_TOOLS}} ]
1185     };
1186    
1187     return $attrdata;
1188     }
1189    
1190     sub clean4storage()
1191     {
1192     my $self=shift;
1193     # Delete all keys except those in KEEP:
1194     my @KEEP = qw( DATA BUILD_ORDER SEEN_LOCAL_PACKAGES SCRAMSTORE );
1195    
1196     foreach my $key (keys %$self)
1197     {
1198     # If this key isn't listed in KEEP, delete it:
1199     if (! grep($key eq $_, @KEEP))
1200     {
1201     delete $self->{$key};
1202     }
1203     }
1204     }
1205    
1206     1;