ViewVC Help
View File | Revision Log | Show Annotations | Root Listing
root/cvsroot/COMP/SCRAM/src/BuildSystem/BuildManager.pm
Revision: 1.1.2.1
Committed: Fri Feb 27 15:34:54 2004 UTC (21 years, 2 months ago) by sashby
Content type: text/plain
Branch: SCRAM_V1_BRANCH
CVS Tags: SCRAM_V1, SCRAMV1_IMPORT
Changes since 1.1: +510 -0 lines
Log Message:
First import of new SCRAM packages into CMS cvs repos.

File Contents

# User Rev Content
1 sashby 1.1.2.1 #____________________________________________________________________
2     # File: BuildManager.pm
3     #____________________________________________________________________
4     #
5     # Author: Shaun Ashby <Shaun.Ashby@cern.ch>
6     # Update: 2004-02-23 14:53:38+0100
7     # Revision: $Id: BuildManager.pm,v 1.7 2004/02/27 13:33:03 sashby Exp $
8     #
9     # Copyright: 2004 (C) Shaun Ashby
10     #
11     #--------------------------------------------------------------------
12     package BuildSystem::BuildManager;
13     require 5.004;
14     use Exporter;
15     use BuildSystem::TransientDataObject;
16     @ISA=qw(Exporter);
17     @EXPORT_OK=qw( );
18    
19     sub new()
20     ###############################################################
21     # new #
22     ###############################################################
23     # modified : Mon Feb 23 14:53:51 2004 / SFA #
24     # params : #
25     # : #
26     # function : #
27     # : #
28     ###############################################################
29     {
30     my $proto=shift;
31     my $class=ref($proto) || $proto;
32     my $self={};
33    
34     # Pass in the top-level data key (dir), working dir, global
35     # cache and tool manager object:
36     my ($configbfdir, $workingdir, $dataobject, $toolmanager)=@_;
37     bless $self,$class;
38    
39     $self->{CONFIGBFDIR} = $configbfdir;
40     $self->{CACHEDATA} = $dataobject; # Global buildfile data cache
41     $self->{TOOLMANAGER} = $toolmanager;
42    
43     # Process the top-level data (path and datapos are the same):
44     $self->location($self->{CONFIGBFDIR}, $self->{CONFIGBFDIR});
45     $self->process_buildfile();
46    
47     return $self;
48     }
49    
50     sub location()
51     {
52     my $self=shift;
53     my ($path,$dataposition)=@_;
54     # Store current path:
55     $self->path($path);
56     # Store the safe path:
57     $self->safepath($self->make_safepath($path));
58     # Set pointer to current buildfile object:
59     chomp($dataposition);
60     $self->level($dataposition);
61     return $self;
62     }
63    
64     sub safepath()
65     {
66     my $self=shift;
67     # Return the safe version of the current path:
68     @_ ? $self->{SAFEPATH} = shift
69     : $self->{SAFEPATH};
70     }
71    
72     sub make_safepath()
73     {
74     my $self=shift;
75     my ($path)=@_;
76     my $safepath;
77     # Make a safe path from our path:
78     ($safepath = $path) =~ s|/|_|g;
79     return $safepath;
80     }
81    
82     sub path()
83     {
84     my $self=shift;
85     @_ ? $self->{CURRENTPATH} = shift
86     : $self->{CURRENTPATH};
87     }
88    
89     sub class()
90     {
91     my $self=shift;
92     # Set/return the part of the ClassPath that matched a template name:
93     @_ ? $self->{CLASS} = shift
94     : $self->{CLASS};
95     }
96    
97     sub classdir()
98     {
99     my $self=shift;
100     # Set/return the part of the ClassPath that matched:
101     @_ ? $self->{CLASSDIR} = shift
102     : $self->{CLASSDIR};
103     }
104    
105     sub suffix()
106     {
107     my $self=shift;
108     # Set/return the part of the ClassPath that didn't match:
109     @_ ? $self->{SUFFIX} = shift
110     : $self->{SUFFIX};
111     }
112    
113     sub generate_makefile()
114     {
115     my $self=shift;
116     my ($templatedir)=@_;
117     $templatedir ||= $ENV{LOCALTOP}."/".$ENV{SCRAM_CONFIGDIR};
118    
119     use Template;
120    
121     # Set up Template opts:
122     my $template_config =
123     {
124     INCLUDE_PATH => $templatedir,
125     PLUGIN_BASE => 'BuildSystem::Template::Plugins',
126     EVAL_PERL => 1
127     };
128    
129     # Data to be used inside the template engine:
130     my $data =
131     { # Maybe buildmanager is not needed....
132     projectdata => $self->{BUILD}->{$self->{CONFIGBFDIR}},
133     dirdata => $self->{THISTDO},
134     cachedata => $self->{CACHEDATA},
135     toolmanager => $self->{TOOLMANAGER},
136     buildmanager => $self,
137     safepath => $self->safepath(),
138     path => $self->path(),
139     class => $self->class(),
140     classdir => $self->classdir(),
141     suffix => $self->suffix()
142     };
143    
144     # Check to see if there was a "class" given via ClassPath. If there
145     # wasn't, don't do anything:
146     if ($self->class() ne '')
147     {
148     my $template = $self->class()."_template.tmpl";
149     my $ptemplate = Template->new($template_config);
150    
151     # Run the engine:
152     $ptemplate->process($template, $data, $self->makefile())#, STDOUT for tests !!! $self->makefile())
153     || die "Template error: ",$ptemplate->error;
154     }
155     else
156     {
157     print "BuildManager: No CLASS, therefore no template to apply to generate a Makefile.","\n";
158     }
159     }
160    
161     sub makefile()
162     {
163     my $self=shift;
164    
165     if (@_)
166     {
167     if ($self->safepath() =~ m|^$ENV{SCRAM_SOURCEDIR}$|)
168     {
169     $self->{OUTFILE} = $_[0]."/Makefile";
170     }
171     else
172     {
173     $self->{OUTFILE} = $_[0]."/".$self->safepath().".mk";
174     }
175     }
176     else
177     {
178     ($self->{OUTFILE} ne '') ? return $self->{OUTFILE} : return 'Makefile';
179     }
180     }
181    
182     sub level()
183     {
184     my $self=shift;
185     # Arg is the data position. CURRENTBF then points to build data
186     # for current location:
187     @_ ? $self->{CURRENTBF} = $self->{CACHEDATA}->buildobject($_[0])
188     : $self->{CURRENTBF};
189     }
190    
191     sub tool_dependency()
192     {
193     my $self=shift;
194     my ($tool) = @_;
195    
196     if (exists $self->{THISTDO}->{SEENTOOLS}->{$tool})
197     {
198     $self->{THISTDO}->{SEENTOOLS}->{$tool}++;
199     }
200     else
201     {
202     $self->{THISTDO}->{SEENTOOLS}->{$tool} = 1;
203     # Store this tool data object:
204     push(@{$self->{THISTDO}->{TOOLS}},$tool);
205     }
206     }
207    
208     sub package_dependency()
209     {
210     my $self=shift;
211     my ($pkg)=@_;
212    
213     if ($pkg)
214     {
215     # Store the required package path (hash removes dups):
216     $self->{THISTDO}->{PACKAGES}->{$pkg} = 1;
217     }
218     else
219     {
220     # Otherwise return array of required packages (jsut the keys):
221     return [keys %{$self->{THISTDO}->{PACKAGES}}];
222     }
223     }
224    
225     sub check_deps()
226     {
227     my $self=shift;
228     my ($dep)=@_;
229     # Return 0/1 according to whether package has
230     # already been seen in PACKAGES:
231     (exists $self->{THISTDO}->{PACKAGES}->{$dep}) ? return 0 : return 1;
232     }
233    
234     sub process_buildfile()
235     {
236     my $self=shift;
237     # Somewhere to store the data:
238     $self->{THISTDO} = BuildSystem::TransientDataObject->new();
239     # Groups first:
240     $self->resolve_groups();
241    
242     # Check to see which are external tools:
243     if (my @otheruses=$self->{CURRENTBF}->use())
244     {
245     $self->resolve_use(\@otheruses);
246     }
247    
248     # Now look for architecture-specific tags:
249     while (my ($archtag,$archval) = each %{$self->{CURRENTBF}->archspecific()})
250     {
251     if ($archtag eq 'USE')
252     {
253     $self->resolve_use($archval);
254     }
255     else
256     {
257     # We have another type of data in the resolved group:
258     $self->{THISTDO}->storedata($archtag, $archval);
259     }
260     }
261    
262     # For each tag type that has associated data in this buildfile
263     # data object, get the data and store it in the package builder:
264     map { my $subname = lc($_); $self->{THISTDO}->storedata($_, $self->{CURRENTBF}->$subname()); }
265     $self->{CURRENTBF}->basic_tags();
266    
267     # Handle productstore variables. Store in a hash with "SCRAMSTORE_x" as the key
268     # pointing to correct path as it should appear in the Makefiles:
269     map
270     {
271     my $storename="";
272     # Probably want the store value to be set to <name/<arch> or <arch>/<name> with
273     # <path> only prepending to this value rather than replacing <name>: FIXME...
274     if ($$_{'type'} eq 'arch')
275     {
276     if ($$_{'swap'} eq 'true')
277     {
278     (exists $$_{'path'}) ? ($storename .= $$_{'path'}."/".$ENV{SCRAM_ARCH})
279     : ($storename .= $$_{'name'}."/".$ENV{SCRAM_ARCH});
280     }
281     else
282     {
283     (exists $$_{'path'}) ? ($storename .= $ENV{SCRAM_ARCH}."/".$$_{'path'})
284     : ($storename .= $ENV{SCRAM_ARCH}."/".$$_{'name'});
285     }
286     }
287     else
288     {
289     (exists $$_{'path'}) ? ($storename .= $$_{'path'})
290     : ($storename .= $$_{'name'});
291     }
292    
293     $self->{THISTDO}->addstore("SCRAMSTORENAME_".uc($$_{'name'}),$storename);
294     } @{$self->{THISTDO}->{PRODUCTSTORE}};
295    
296     # Clean up:
297     delete $self->{THISTDO}->{PRODUCTSTORE};
298    
299     # Next, tools:
300     # my @keyvars = qw(VARIABLES LIB LIBDIR INCLUDE MAKEFILE FLAGS);
301     # Sort according to how often a tool was seen: the more often, the further
302     # down the list it should appear:
303     foreach $k ( sort { %{$self->{THISTDO}->{SEENTOOLS}}->{$a}
304     <=> %{$self->{THISTDO}->{SEENTOOLS}}->{$b}}
305     keys %{$self->{THISTDO}->{SEENTOOLS}} )
306     {
307     my $t = $self->{TOOLMANAGER}->checkifsetup($k);
308    
309     # Deal with any variables first:
310     foreach my $tvar ($t->list_variables())
311     {
312     $self->{THISTDO}->{VARIABLES}->{$tvar} = $t->variable_data($tvar);
313     }
314     # Makefile:
315     push(@{$self->{THISTDO}->{MAKEFILE}}, $t->makefile());
316    
317     ### These must be filterable:
318     # Lib:
319     push(@{$self->{THISTDO}->{LIB}}, $t->lib());
320     # Libdir:
321     push(@{$self->{THISTDO}->{LIBDIR}}, $t->libdir());
322     # Include:
323     push(@{$self->{THISTDO}->{INCLUDE}}, $t->include());
324     ###############
325    
326     # Flags:
327     if (defined (my $fhash=$t->allflags()))
328     {
329     while (my ($flag, $flagvalue) = each %{$fhash})
330     {
331     $self->{THISTDO}->flags($flag,$flagvalue);
332     }
333     }
334     }
335    
336     # Now save the TDO:
337     $self->{BUILD}->{$self->path()} = $self->{THISTDO};
338     delete $self->{THISTDO};
339     return $self;
340     }
341    
342     sub check_use()
343     {
344     my $self=shift;
345     my ($dataposition)=@_;
346    
347     # Look for the data object for the path:
348     if (my $pkdata=$self->{CACHEDATA}->buildobject($dataposition))
349     {
350     if (! $self->check_export($pkdata))
351     {
352     print "\n";
353     print " WARNING: $dataposition/BuildFile does not export anything:\n";
354     print " **** $dataposition dependency dropped.","\n";
355     }
356     }
357     # elsif (my $relpkdata=$self->searchinscramprojects($dataposition))
358     # {
359     # }
360     else
361     {
362     # Check in the toolbox for this tool. If it doesn't
363     # exist, complain:
364     print "\n";
365     print "WARNING: Unable to find package/tool called ",$dataposition,"\n";
366     print " in current project area.","\n";
367     return(2);
368     }
369     }
370    
371     sub check_export()
372     {
373     my $self=shift;
374     my ($pkdata)=@_;
375    
376     if (! $pkdata->hasexport())
377     {
378     # No export so we return:
379     return(0);
380     }
381     else
382     {
383     # Collect the exported data and store in PackageBuilder object:
384     $self->process_export($pkdata->exported());
385     return(1);
386     }
387     }
388    
389     sub process_export()
390     {
391     my $self=shift;
392     my ($export)=@_;
393    
394     while (my ($tag,$tagvalue) = each %{$export})
395     {
396     $self->{THISTDO}->storedata($tag,$tagvalue);
397     }
398     }
399    
400     sub resolve_use()
401     {
402     my $self=shift;
403     my ($data) = @_;
404    
405     foreach my $use (@{$data})
406     {
407     # Check to see which are just external tools:
408     if ($self->{TOOLMANAGER}->definedtool($use) && (my $td=$self->{TOOLMANAGER}->checkifsetup($use)))
409     {
410     # We have a setup tool ($td is a ToolData object). Store the data in
411     # the PackageBuilder:
412     $self->tool_dependency($td->toolname());
413     # We also resolve the dependencies that this tool has on other tools:
414     $self->resolve_use([ $td->use() ]);
415     }
416     else
417     {
418     # We have a local or release-area package dependency. Check
419     # that the appropriate BuildFile exports something and grab the data:
420     $self->check_use($use),
421     if ($self->check_deps($use));
422     # Also store full package path for our build rules:
423     $self->package_dependency($use);
424     }
425     }
426     }
427    
428     sub resolve_groups()
429     {
430     my $self=shift;
431    
432     # First of all, resolve group requirements in this BuildFile:
433     my $groupdata=$self->check_groups();
434    
435     while (my ($tagname, $tagvalue) = each %{$groupdata})
436     {
437     # Look for <use> tags:
438     if ($tagname eq 'USE')
439     {
440     $self->resolve_use($tagvalue);
441     }
442     else
443     {
444     # We have another type of data in the resolved group:
445     $self->{THISTDO}->storedata($tagname,$tagvalue);
446     }
447     }
448     }
449    
450     sub check_groups()
451     {
452     my $self=shift;
453     my $data={};
454     $data->{USE} = [];
455    
456     # - For current BuildFile object, check to see if there are any group tags;
457     my @needed_groups=$self->{CURRENTBF}->group();
458    
459     # - For each group required, get the corresponding path to the BuildFile where they are defined;
460     foreach my $n_group (@needed_groups)
461     {
462     my $location = $self->{CACHEDATA}->findgroup($n_group);
463    
464     if (defined $location)
465     {
466     $self->recursive_group_check($n_group,$location,$data);
467     }
468     else
469     {
470     print "Warning: Group ",$n_group," not defined.\n";
471     }
472     }
473     return $data;
474     }
475    
476     sub recursive_group_check
477     {
478     my $self=shift;
479     my ($groupname,$location,$data)=@_;
480    
481     # - Get the BuildFile object for the BuildFile where the group is defined;
482     my $groupbuildobject = $self->{CACHEDATA}->buildobject($location);
483     # - Look for defined_groups in the BuildFile object and find match to group tag required;
484     # - For this group, check to see if there are groups required (i.e. check for any
485     # groups in data of defined group)
486     while (my ($gkey,$gvalue) = each %{$groupbuildobject->dataforgroup($groupname)})
487     {
488     if ($gkey eq 'GROUP')
489     {
490     # - For those required groups, check the path to the BuildFile object;
491     my $nextlocation = $self->{CACHEDATA}->findgroup(@{$gvalue});
492     if (defined $nextlocation)
493     {
494     $self->recursive_group_check(@{$gvalue},$nextlocation,$data);
495     }
496     else
497     {
498     print "Warning: Group ",@{$gvalue}," not defined.\n";
499     }
500     ##
501     }
502     else
503     {
504     push(@{$data->{$gkey}},@{$gvalue});
505     }
506     }
507     return $data;
508     }
509    
510     1;