ViewVC Help
View File | Revision Log | Show Annotations | Root Listing
root/cvsroot/COMP/SCRAM/src/BuildSystem/DataCollector.pm
Revision: 1.9
Committed: Fri Jan 14 17:36:42 2011 UTC (14 years, 3 months ago) by muzaffar
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 1.8: +1 -1 lines
State: FILE REMOVED
Log Message:
merged SCRAM_V2 branch in to head

File Contents

# Content
1 #____________________________________________________________________
2 # File: DataCollector.pm
3 #____________________________________________________________________
4 #
5 # Author: Shaun Ashby <Shaun.Ashby@cern.ch>
6 # Update: 2004-06-30 11:13:06+0200
7 # Revision: $Id: DataCollector.pm,v 1.8 2006/09/11 14:53:39 sashby Exp $
8 #
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 $storename .= $$H{'name'}."/".$ENV{SCRAM_ARCH};
294 }
295 else
296 {
297 $storename .= $ENV{SCRAM_ARCH}."/".$$H{'name'};
298 }
299 }
300 else
301 {
302 $storename .= $$H{'name'};
303 }
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
559 # Record that this package is not found for the current location:
560 $self->{BUILDCACHE}->unresolved($self->{BRANCH}, $use);
561
562 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 }
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 {
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 }
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
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 # 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;