ViewVC Help
View File | Revision Log | Show Annotations | Root Listing
root/cvsroot/COMP/SCRAM/src/BuildSystem/DataCollector.pm
Revision: 1.7
Committed: Fri Oct 7 16:05:44 2005 UTC (19 years, 7 months ago) by sashby
Content type: text/plain
Branch: MAIN
CVS Tags: V1_0_2, V1_0_2_p1
Branch point for: v103_branch
Changes since 1.6: +8 -3 lines
Log Message:
Some more bugfixes.

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.7 # Revision: $Id: DataCollector.pm,v 1.6 2005/07/26 15:14:00 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 sashby 1.2 }
572     }
573     }
574    
575     sub resolve_groups()
576     {
577     my $self=shift;
578     my ($inputgroups,$referrer)=@_;
579     my $data={};
580     $data->{USE} = [];
581    
582     # First of all, resolve group requirements in this BuildFile:
583     foreach my $n_group (@{$inputgroups})
584     {
585     # Recursively check for groups and resolve them to lowest common denom (used packages):
586     $self->recursive_group_check($n_group,$data,$referrer);
587     }
588    
589     # Resolve the $data contents:
590     while (my ($tagname, $tagvalue) = each %{$data})
591     {
592     if ($tagname eq 'USE')
593     {
594     # Add edges to our dep graph for packages needed
595     # by the referring package:
596     foreach my $TV (@{$tagvalue})
597     {
598     $self->{G}->edge($referrer, $TV);
599     }
600     # resolve the USE:
601     $self->resolve_use($tagvalue);
602     }
603     else
604     {
605     # We have another type of data in the resolved group:
606     $self->storedata($tagname,$tagvalue,$referrer);
607     }
608     }
609     }
610    
611     sub recursive_group_check()
612     {
613     my $self=shift;
614     my ($groupname,$data,$referrer)=@_;
615     my ($location);
616    
617     # See if we find the group locally:
618     if ($location = $self->{BUILDCACHE}->findgroup($groupname))
619     {
620     print "- Found group ",$groupname," locally:","\n", if ($ENV{SCRAM_DEBUG});
621     # Get the BuildFile object for the BuildFile where the group is defined;
622     my $groupbuildobject = $self->{BUILDCACHE}->buildobject($location);
623     # Get the data contained in the defined group:
624     my %dataingroup = %{$groupbuildobject->dataforgroup($groupname)};
625    
626     # For this group, check to see if there are groups required (i.e. check for any
627     # groups in data of defined group):
628     while (my ($groupdatakey, $groupdatavalue) = each %dataingroup)
629     {
630     # If we have another group, call ourselves again:
631     if ($groupdatakey eq 'GROUP')
632     {
633     # NB: probably should become recursive by invoking resolve_groups() again
634     # since we might have more than one group to resolve:
635     $self->resolve_groups($groupdatavalue,$referrer);
636     }
637     else
638     {
639     if (ref($groupdatavalue) eq 'ARRAY')
640     {
641     push(@{$data->{$groupdatakey}},@{$groupdatavalue});
642     }
643     else
644     {
645     $data->{$groupdatakey} = $groupdatavalue;
646     }
647     }
648     }
649     }
650     # Check in the release area:
651     elsif ($self->groupsearchinrelease($groupname))
652     {
653     my ($releasegroupdataobject) = $self->groupsearchinrelease($groupname);
654     print "- Found group ",$groupname," in release area of current project:","\n", if ($ENV{SCRAM_DEBUG});
655    
656     # Get the data contained in the defined group:
657     my %datainrelgroup = %{$releasegroupdataobject->dataforgroup($groupname)};
658    
659     # For this group, check to see if there are groups required (i.e. check for any
660     # groups in data of defined group):
661     while (my ($relgroupdatakey, $relgroupdatavalue) = each %datainrelgroup)
662     {
663     # If we have another group, call ourselves again:
664     if ($relgroupdatakey eq 'GROUP')
665     {
666     $self->resolve_groups($relgroupdatavalue,$referrer);
667     }
668     else
669     {
670     if (ref($relgroupdatavalue) eq 'ARRAY')
671     {
672     push(@{$data->{$relgroupdatakey}},@{$relgroupdatavalue});
673     }
674     else
675     {
676     $data->{$relgroupdatakey} = $relgroupdatavalue;
677     }
678     }
679     }
680     }
681     # Look in SCRAM-managed projects:
682     elsif ($self->groupsearchinscramprojects($groupname))
683     {
684     my ($remotegroupdataobject) = $self->groupsearchinscramprojects($groupname);
685     print "- Found group ",$groupname," in remote project:","\n", if ($ENV{SCRAM_DEBUG});
686    
687     # Get the data contained in the defined group:
688     my %datainremgroup = %{$remotegroupdataobject->dataforgroup($groupname)};
689    
690     # For this group, check to see if there are groups required (i.e. check for any
691     # groups in data of defined group):
692     while (my ($rgroupdatakey, $rgroupdatavalue) = each %datainremgroup)
693     {
694     # If we have another group, call ourselves again:
695     if ($rgroupdatakey eq 'GROUP')
696     {
697     # NB: probably should become recursive by invoking resolve_groups() again
698     # since we might have more than one group to resolve:
699     $self->resolve_groups($rgroupdatavalue,$referrer);
700     }
701     else
702     {
703     if (ref($rgroupdatavalue) eq 'ARRAY')
704     {
705     push(@{$data->{$rgroupdatakey}},@{$rgroupdatavalue});
706     }
707     else
708     {
709     $data->{$rgroupdatakey} = $rgroupdatavalue;
710     }
711     }
712     }
713     }
714     else
715     {
716     print "WARNING: Group ",$groupname," not defined. Edit BuildFile at ",$self->{BRANCH},"\n";
717     return(0);
718     }
719    
720     return $data;
721     }
722    
723     sub check_local_use()
724     {
725     my $self=shift;
726     my ($dataposition)=@_;
727    
728     # See if this is a local package that has already been seen. We must check that the package is really
729     # local before we return true if it exists in TRANSIENTCACHE:
730     if (exists ($TRANSIENTCACHE->{$dataposition}) && exists($self->{SEEN_LOCAL_PACKAGES}->{$dataposition}))
731     {
732     # Found and data has already been handled so return OK:
733     return(1);
734     }
735    
736     # Look for the data object for the path locally:
737     if (my $pkdata=$self->{BUILDCACHE}->buildobject($dataposition))
738     {
739     # We check to see if this package exported something and parse/store the data
740     # if true:
741     if (! $self->check_export($pkdata,$dataposition))
742     {
743     print "\n";
744     print "WARNING: $dataposition/BuildFile does not export anything:\n";
745     print " **** $dataposition dependency dropped.","\n";
746     print "You must edit the BuildFile at ",$self->{BRANCH}," to add an <export>.\n";
747     print "\n";
748     }
749     # Found so return OK:
750     return(1);
751     }
752     # Otherwise, not found locally:
753     return(0);
754     }
755    
756     sub check_release_use()
757     {
758     my $self=shift;
759     my ($dataposition)=@_;
760    
761     # See if this is a release package that has already been seen. We must check that the package is really
762     # in the release before we return true if it exists in TRANSIENTCACHE:
763     if (exists ($TRANSIENTCACHE->{$dataposition}) && exists($self->{SEEN_RELEASE_PACKAGES}->{$dataposition}))
764     {
765     # Found and data has already been handled so return OK:
766     return(1);
767     }
768    
769     if (my ($sproject,$scramppkgdata)=@{$self->searchinrelease($dataposition)})
770     {
771     if (! $self->check_remote_export($sproject,$scramppkgdata,$dataposition))
772     {
773     print "\n";
774     print "WARNING: $dataposition/BuildFile in release area of current project does not export anything:\n";
775     print "**** $dataposition dependency dropped.","\n";
776     }
777     # Found so return OK:
778     return(1);
779     }
780     # Otherwise, not found in release area:
781     return(0);
782     }
783    
784     sub check_remote_use()
785     {
786     my $self=shift;
787     my ($dataposition)=@_;
788    
789     # See if this is a package from a SCRAM project that has already been seen. We must check that
790     # the package is really in a remote project before we return true if it exists in TRANSIENTCACHE:
791     if (exists ($TRANSIENTCACHE->{$dataposition}) && exists($self->{SEEN_REMOTE_PACKAGES}->{$dataposition}))
792     {
793     # Found and data has already been handled so return OK:
794     return(1);
795     }
796    
797     if (my ($sproject,$scramppkgdata)=@{$self->searchinscramprojects($dataposition)})
798     {
799     if (! $self->check_remote_export($sproject,$scramppkgdata,$dataposition))
800     {
801     print "\n";
802     print "WARNING: $dataposition/BuildFile in scram project \"",$sproject,"\" does not export anything:\n";
803     print "**** $dataposition dependency dropped.","\n";
804     }
805     # Found so return OK:
806     return(1);
807     }
808     return(0);
809     }
810    
811     sub searchinscramprojects()
812     {
813     my $self=shift;
814     my ($dataposition)=@_;
815    
816     foreach my $pobj (keys %{$self->{SPROJECTS}})
817     {
818     if ($self->{SPROJECTS}->{$pobj}->buildobject($dataposition))
819     {
820     # Add the dependency on this tool (even though it's a scram project, we need the
821     # other settings that the tool provides):
822     $self->{G}->vertex($pobj);
823     $self->tool($pobj,'SCRAM');
824    
825     # Return the data object (tool name, data object):
826     return [$pobj,$self->{SPROJECTS}->{$pobj}->buildobject($dataposition)];
827     }
828     }
829    
830     # If we got here, there were no matches:
831     return (0);
832     }
833    
834     sub groupsearchinscramprojects()
835     {
836     my $self=shift;
837     my ($groupname)=@_;
838    
839     foreach my $pobj (keys %{$self->{SPROJECTS}})
840     {
841     if (my $grouplocation = $self->{SPROJECTS}->{$pobj}->findgroup($groupname))
842     {
843     return $self->{SPROJECTS}->{$pobj}->buildobject($grouplocation);
844     }
845     }
846    
847     # If we got here, there were no matches:
848     return (0);
849     }
850    
851     sub searchinrelease()
852     {
853     my $self=shift;
854     my ($dataposition)=@_;
855    
856     if (exists ($self->{SPROJECTS}->{RELEASE}) &&
857     $self->{SPROJECTS}->{RELEASE}->buildobject($dataposition))
858     {
859     # Return the data object (tool name, data object):
860     return ['RELEASE',$self->{SPROJECTS}->{RELEASE}->buildobject($dataposition)];
861     }
862    
863     # If we got here, there were no matches:
864     return (0);
865     }
866    
867     sub groupsearchinrelease()
868     {
869     my $self=shift;
870     my ($groupname)=@_;
871    
872     if (exists($self->{SPROJECTS}->{RELEASE}))
873     {
874     if (my $grouplocation = $self->{SPROJECTS}->{RELEASE}->findgroup($groupname))
875     {
876     return $self->{SPROJECTS}->{RELEASE}->buildobject($grouplocation);
877     }
878     }
879    
880     # If we got here, there were no matches:
881     return (0);
882     }
883    
884     sub local_package()
885     {
886     my $self=shift;
887     my ($package)=@_;
888    
889     if (exists ($self->{SEEN_LOCAL_PACKAGES}->{$package}))
890     {
891     $self->{SEEN_LOCAL_PACKAGES}->{$package}++;
892     }
893     else
894     {
895     $self->{SEEN_LOCAL_PACKAGES}->{$package} = 1;
896     }
897     }
898    
899     sub release_package()
900     {
901     my $self=shift;
902     my ($package)=@_;
903    
904     if (exists ($self->{SEEN_RELEASE_PACKAGES}->{$package}))
905     {
906     $self->{SEEN_RELEASE_PACKAGES}->{$package}++;
907     }
908     else
909     {
910     $self->{SEEN_RELEASE_PACKAGES}->{$package} = 1;
911     }
912     }
913    
914     sub remote_package()
915     {
916     my $self=shift;
917     my ($package)=@_;
918    
919     if (exists ($self->{SEEN_REMOTE_PACKAGES}->{$package}))
920     {
921     $self->{SEEN_REMOTE_PACKAGES}->{$package}++;
922     }
923     else
924     {
925     $self->{SEEN_REMOTE_PACKAGES}->{$package} = 1;
926     }
927     }
928    
929     sub tool()
930     {
931     my $self=shift;
932     my ($tool,$td) = @_;
933    
934     if (! exists($self->{SEEN_TOOLS}->{$tool}))
935     {
936     $self->{SEEN_TOOLS}->{$tool} = $td;
937     }
938     }
939    
940     sub local_package_deps()
941     {
942     my $self=shift;
943     my $orderedpackages=[];
944     # Check the BUILD_ORDER array and store all local
945     # packages found:
946     foreach my $LP (@{$self->{BUILD_ORDER}})
947     {
948     if (exists($self->{SEEN_LOCAL_PACKAGES}->{$LP}))
949 sashby 1.7 {
950     # If there's not a src dir in this package, don't append
951     # the build rule (since there's nothing to build):
952     if ( -d $ENV{SCRAM_SOURCEDIR}."/".$LP."/src")
953     {
954     push(@$orderedpackages, $LP);
955     }
956 sashby 1.2 }
957     }
958    
959     return $orderedpackages;
960     }
961    
962     ####### Now some interface routines ########
963     sub addstore()
964     {
965     my $self=shift;
966     my ($name,$value)=@_;
967 sashby 1.4
968     # Make sure that the name of the store can be used as a
969     # variable, i.e. for paths, replace "/" with "_":
970     $name =~ s|/|_|g;
971 sashby 1.2 # Add a new SCRAMSTORE. First we check to see if there
972     # is already a store with the same name. If there is, we
973     # do nothing since the buildfiles are parsed in the order
974     # LOCAL->PARENT->PROJECT so the first one to be set will be
975     # obtained locally. We want this behaviour so we can override
976     # the main product storage locations locally:
977     if (!exists($self->{SCRAMSTORE}->{$name}))
978     {
979     $self->{SCRAMSTORE}->{$name} = $value;
980     }
981     else
982     {
983     print "INFO: Product storage area \"",$self->{SCRAMSTORE}->{$name},"\" has been redefined locally.","\n"
984     if ($ENV{SCRAM_DEBUG});
985     }
986     }
987    
988     sub scramstore()
989     {
990     my $self=shift;
991     my ($name) = @_;
992     (exists $self->{SCRAMSTORE}->{"SCRAMSTORENAME_".$name}) ?
993     return $self->{SCRAMSTORE}->{"SCRAMSTORENAME_".$name}
994     : return "";
995     }
996    
997     sub allscramstores()
998     {
999     my $self=shift;
1000     # Return a hash of scram stores:
1001     return $self->{SCRAMSTORE};
1002     }
1003    
1004     sub flags()
1005     {
1006     my $self=shift;
1007     my ($flag,$flagvalue) = @_;
1008    
1009     if ($flag && $flagvalue)
1010     {
1011     # If FLAGS already exist, append:
1012     if (exists ($self->{DATA}->{FLAGS}->{$flag}))
1013     {
1014     # Add each flag ONLY if it doesn't already exist:
1015     foreach my $F (@$flagvalue)
1016     {
1017     push(@{$self->{DATA}->{FLAGS}->{$flag}},$F),
1018     if (! grep($F eq $_, @{$self->{DATA}->{FLAGS}->{$flag}}));
1019     }
1020     }
1021     else
1022     {
1023     # Create a new array of flags:
1024     $self->{DATA}->{FLAGS}->{$flag} = [ @$flagvalue ];
1025     }
1026     }
1027     elsif ($flag && $self->{DATA}->{FLAGS}->{$flag}->[0] ne '')
1028     {
1029     return @{$self->{DATA}->{FLAGS}->{$flag}};
1030     }
1031     else
1032     {
1033     return "";
1034     }
1035     }
1036    
1037     sub allflags()
1038     {
1039     my $self=shift;
1040     my $flags={};
1041    
1042     # Return a hash containing FLAGNAME, FLAGSTRING pairs:
1043     while (my ($flagname,$flagvalue) = each %{$self->{DATA}->{FLAGS}})
1044     {
1045     $flags->{$flagname} = join(" ",@{$flagvalue});
1046     }
1047    
1048     return $flags;
1049     }
1050    
1051     sub variables()
1052     {
1053     my $self=shift;
1054     # Return a hash of variables:
1055     return $self->{DATA}->{VARIABLES};
1056     }
1057    
1058     sub data()
1059     {
1060     my $self=shift;
1061     my ($tag)=@_;
1062     my $sep;
1063     my $datastring="";
1064    
1065     if (exists($self->{DATA}->{$tag}))
1066     {
1067     ($tag eq 'MAKEFILE') ? $sep="\n" : $sep=" ";
1068     # Special treatment for LIB to handle libs that must
1069     # appear first in link list:
1070     if ($tag eq 'LIB')
1071     {
1072     if (exists($self->{DATA}->{FIRSTLIB}))
1073     {
1074     $datastring .= join($sep, @{$self->{DATA}->{FIRSTLIB}})." ";
1075     $datastring .= join($sep, @{$self->{DATA}->{LIB}});
1076     }
1077     else
1078     {
1079     $datastring .= join($sep,@{$self->{DATA}->{LIB}});
1080     }
1081     }
1082     else
1083     {
1084     # All other tags just join:
1085     $datastring .= join($sep, @{$self->{DATA}->{$tag}});
1086     }
1087    
1088     # return the data string:
1089     return $datastring;
1090     }
1091    
1092     return "";
1093     }
1094    
1095     sub copy()
1096     {
1097     my $self=shift;
1098     my ($localg)=@_;
1099     my $copy;
1100     # We copy the DataCollector. We only clone the grapher if
1101     # local graphing is being used, otherwise we leave the
1102     # original graph present:
1103     if ($localg) # Working at package-level
1104     {
1105     # Create a copy of our graph:
1106     my $gcopy = $self->{G}->copy();
1107     # Create a new DataCollector object, initialised with same settings as we have
1108     # in our current object:
1109     $copy = ref($self)->new($self->{BUILDCACHE},
1110     $self->{TOOLMGR},
1111     $self->{BRANCH},
1112     $self->{SPROJECTS},
1113     $self->{SPROJECTBASES},
1114     $gcopy); # The copy of the grapher
1115     }
1116     elsif ($localg == 0)
1117     {
1118     # Create a new DataCollector object, initialised with same settings as we have
1119     # in our current object:
1120     $copy = ref($self)->new($self->{BUILDCACHE},
1121     $self->{TOOLMGR},
1122     $self->{BRANCH},
1123     $self->{SPROJECTS},
1124     $self->{SPROJECTBASES},
1125     $self->{G}); # The GLOBAL grapher
1126     }
1127     else
1128     {
1129     # Unknown value:
1130     return undef;
1131     }
1132    
1133     # Copy other counters/tracking vars:
1134     $copy->{SEEN_LOCAL_PACKAGES} = { %{$self->{SEEN_LOCAL_PACKAGES}} };
1135     $copy->{SEEN_RELEASE_PACKAGES} = { %{$self->{SEEN_RELEASE_PACKAGES}} };
1136     $copy->{SEEN_REMOTE_PACKAGES} = { %{$self->{SEEN_REMOTE_PACKAGES}} };
1137     $copy->{SEEN_TOOLS} = { %{$self->{SEEN_TOOLS}} };
1138    
1139     # Copy the "content":
1140     use Data::Dumper;
1141     $Data::Dumper::Purity = 1;
1142     $Data::Dumper::Terse = 1;
1143     my $newcontent=eval(Dumper($self->{content}));
1144    
1145     if (@!)
1146     {
1147     print "SCRAM error [DataCollector]: problems copying content...","\n";
1148     }
1149    
1150     # Now copy the data:
1151     my $newdata=eval(Dumper($self->{DATA}));
1152    
1153     if (@!)
1154     {
1155     print "SCRAM error [DataCollector]: problems copying DATA content...","\n";
1156     }
1157    
1158     # Store the new content:
1159     $copy->{content} = $newcontent;
1160     # Store the new data content:
1161     $copy->{DATA} = $newdata;
1162     # Bless the object:
1163     bless $copy, ref($self);
1164     # Return the copy object:
1165     return $copy;
1166     }
1167    
1168     sub localgraph()
1169     {
1170     my $self=shift;
1171     return $self->{G};
1172     }
1173    
1174     sub attribute_data()
1175     {
1176     my $self=shift;
1177     # Prepare some data which says which packages are local,
1178     # release, remote or tools. This is needed for setting
1179     # graph attributes in SCRAMGrapher:
1180     my $attrdata =
1181     {
1182     LOCAL => [ keys %{ $self->{SEEN_LOCAL_PACKAGES}} ],
1183     RELEASE => [ keys %{ $self->{SEEN_RELEASE_PACKAGES}} ],
1184     REMOTE => [ keys %{ $self->{SEEN_REMOTE_PACKAGES}} ],
1185     TOOLS => [ keys %{ $self->{SEEN_TOOLS}} ]
1186     };
1187    
1188     return $attrdata;
1189     }
1190    
1191     sub clean4storage()
1192     {
1193     my $self=shift;
1194     # Delete all keys except those in KEEP:
1195     my @KEEP = qw( DATA BUILD_ORDER SEEN_LOCAL_PACKAGES SCRAMSTORE );
1196    
1197     foreach my $key (keys %$self)
1198     {
1199     # If this key isn't listed in KEEP, delete it:
1200     if (! grep($key eq $_, @KEEP))
1201     {
1202     delete $self->{$key};
1203     }
1204     }
1205     }
1206    
1207     1;