ViewVC Help
View File | Revision Log | Show Annotations | Root Listing
root/cvsroot/COMP/SCRAM/src/BuildSystem/BuildDataStorage.pm
Revision: 1.19
Committed: Fri Jan 11 11:20:07 2008 UTC (17 years, 3 months ago) by muzaffar
Content type: text/plain
Branch: MAIN
CVS Tags: V1_1_0_reltag3
Changes since 1.18: +2 -2 lines
Log Message:
removed -i for xargs to avoid problem on osx

File Contents

# User Rev Content
1 sashby 1.2 #____________________________________________________________________
2     # File: BuildDataStorage.pm
3     #____________________________________________________________________
4     #
5     # Author: Shaun Ashby <Shaun.Ashby@cern.ch>
6     # Update: 2004-06-22 15:16:01+0200
7 muzaffar 1.19 # Revision: $Id: BuildDataStorage.pm,v 1.18 2007/12/14 09:03:46 muzaffar Exp $
8 sashby 1.2 #
9     # Copyright: 2004 (C) Shaun Ashby
10     #
11     #--------------------------------------------------------------------
12     package BuildSystem::BuildDataStorage;
13     require 5.004;
14 sashby 1.16 use BuildSystem::BuildFile;
15 sashby 1.2 use Exporter;
16 muzaffar 1.17 use File::Basename;
17 sashby 1.16
18 sashby 1.2 @ISA=qw(Exporter);
19     @EXPORT_OK=qw( );
20    
21     sub new()
22     ###############################################################
23     # new #
24     ###############################################################
25     # modified : Tue Jun 22 15:16:08 2004 / SFA #
26     # params : #
27     # : #
28     # function : #
29     # : #
30     ###############################################################
31     {
32     my $proto=shift;
33     my $class=ref($proto) || $proto;
34     my ($configdir) = @_;
35     my $self=
36     {
37     BUILDTREE => {}, # Path/data pairs;
38     STATUS => 0, # Status of cache
39     VERBOSE => 0 # Verbose mode (0/1);
40     };
41    
42     bless $self,$class;
43    
44     # The location of the top-level BuildFile:
45     $self->{CONFIGDIR} = $configdir;
46    
47     # Somewhere to store the dependencies:
48     $self->{DEPENDENCIES} = {}; # GLOBAL dependencies
49 sashby 1.3 $self->{SKIPPEDDIRS} = {}; # Global skipped dirs
50 sashby 1.2
51     # Initialize the Template Engine:
52     $self->init_engine();
53    
54     return $self;
55     }
56    
57     sub grapher()
58     {
59     my $self=shift;
60     my ($mode,$writeopt)=@_;
61    
62     if ($mode)
63     {
64     $mode =~ tr[A-Z][a-z];
65     # Check to see what the mode is:
66     if ($mode =~ /^g.*?/)
67     {
68     $self->{GRAPH_MODE} = 'GLOBAL';
69     # GLOBAL package graphing:
70     use BuildSystem::SCRAMGrapher;
71     $self->{SCRAMGRAPHER} = BuildSystem::SCRAMGrapher->new();
72     }
73     elsif ($mode =~ /^p.*?/)
74     {
75     # All other cases assume per package. This means that each package
76     # is responsible for creating/destroying grapher objects and writing
77     # out graphs, if required:
78     $self->{GRAPH_MODE} = 'PACKAGE';
79     }
80     else
81     {
82     print "SCRAM error: no mode (w=p,w=g) given for graphing utility!","\n";
83     exit(1);
84     }
85    
86     # Set write option:
87     $self->{GRAPH_WRITE} = $writeopt;
88     }
89     else
90     {
91     print "SCRAM error: no mode (w=p,w=g) given for graphing utility!","\n";
92     exit(1);
93     }
94     }
95    
96     sub global_graph_writer()
97     {
98     my $self=shift;
99     my $name='Project';
100     # Only produce graphs with DOT if enabled. This routine is
101     # only used at Project level:
102     if (defined($self->{SCRAMGRAPHER}) && $self->{GRAPH_WRITE})
103     {
104     my $data; # Fake data - there isn't a DataCollector object
105     $self->{SCRAMGRAPHER}->graph_write($data, $name);
106     delete $self->{SCRAMGRAPHER};
107     }
108     else
109     {
110     print "SCRAM error: can't write graph!","\n";
111     exit(1);
112     }
113    
114     return;
115     }
116    
117     #### The methods ####
118     sub datapath()
119     {
120     my $self=shift;
121     my ($path)=@_;
122     my $datapath;
123     # At project-level, the path is src so just return src. Also,
124     # if we received a BuildFile path that we need to determine the data path for,
125     # check first to see if the path matches config/BuildFile. If it does, we have the top-level
126     # datapath which should be src:
127 muzaffar 1.17 my $conf="$ENV{SCRAM_CONFIGDIR}"; my $src=$ENV{SCRAM_SOURCEDIR};
128     my $bf=$ENV{SCRAM_BUILDFILE};
129     if ($path=~/^(${conf}\/${bf}(.xml|)|$src)$/)
130 sashby 1.2 {
131 muzaffar 1.17 return $src;
132 sashby 1.2 }
133    
134     # For other paths, strip off the src dir (part of LOCALTOP) and the final BuildFile to
135     # get a data position to be used as a key:
136 muzaffar 1.17 ($datapath = $path) =~ s|^\Q$src\L/||;
137     if ($datapath =~ m/(.*)\/$bf(.xml|)$/)
138 sashby 1.2 {
139     return $1;
140     }
141    
142     return $datapath;
143     }
144    
145     sub check_global_config()
146     {
147     my $self=shift;
148 muzaffar 1.17 my $found=0;
149     foreach my $bf ("$ENV{SCRAM_BUILDFILE}.xml","$ENV{SCRAM_BUILDFILE}")
150     {
151     if (-f $self->{CONFIGDIR}."/${bf}")
152     {
153     $found=1;
154     last;
155     }
156     }
157     if (! $found)
158 sashby 1.2 {
159 muzaffar 1.17 print "SCRAM error: no $ENV{SCRAM_BUILDFILE} at top-level (config)! Invalid area!","\n";
160 sashby 1.2 exit(1);
161     }
162    
163     return $self;
164     }
165    
166     sub scanbranch()
167     {
168     my $self=shift;
169 sashby 1.7 my ($files, $datapath)=@_;
170     my $bfbranch;
171     my $buildfiles;
172 sashby 1.4 # Fix (or rather hack) so that only the current buildfile is parsed, not the parent.
173     # This is required becuase it's not desired to pick up dependencies from the level lower:
174     # one should always do it via a <use name=x> to get the package deps. We don't care about
175     # deps in subsystems (they're only used to define groups) and project-wide deps are added at
176     # template level:
177 sashby 1.16 my $file = $files->[0];
178     return unless -f $file; # Just in case metabf() is empty...
179     $bfbranch=BuildSystem::BuildFile->new();
180     $bfbranch->parse($file);
181 sashby 1.2 # Store:
182     $self->storebranchmetadata($datapath,$bfbranch);
183     return $self;
184     }
185    
186     sub buildtreeitem()
187     {
188     my $self=shift;
189     my ($datapath)=@_;
190     # This will return the TreeItem object for
191     # the corresponding data path:
192     return $self->{BUILDTREE}->{$datapath};
193     }
194    
195 muzaffar 1.17 sub updatedirbf ()
196     {
197     my ($self,$dircache,$path,$bf,$buildclass)=@_;
198     use BuildSystem::TreeItem;
199     my $treeitem = BuildSystem::TreeItem->new();
200     my $datapath = $self->datapath($path);
201     $self->{BUILDTREE}->{$datapath} = $treeitem;
202     if ($bf)
203     {
204     $treeitem->metabf($bf);
205     $self->scan($bf, $datapath);
206     }
207     if (!$buildclass) {$buildclass=$self->buildclass($path);}
208     my ($class, $classdir, $suffix) = @{$buildclass};
209     $treeitem->class($class);
210     $treeitem->classdir($classdir);
211     $treeitem->suffix($suffix);
212     $treeitem->path($path);
213     $treeitem->safepath($path);
214     $treeitem->parent($datapath);
215     $treeitem->children($dircache->dircache());
216     $treeitem->name();
217     return $treeitem;
218     }
219    
220     sub updateproductstore()
221 sashby 1.2 {
222     my $self=shift;
223 muzaffar 1.17 my $item = shift;
224     if (exists $item->{RAWDATA} && exists $item->{RAWDATA}{content} && exists $item->{RAWDATA}{content}{PRODUCTSTORE})
225     {
226     my $store = {};
227     foreach my $H (@{$item->{RAWDATA}{content}{PRODUCTSTORE}})
228 sashby 1.2 {
229 muzaffar 1.17 my $storename="";
230     if ($H->{'type'} eq 'arch')
231     {
232     if ($H->{'swap'} eq 'true')
233 sashby 1.2 {
234 muzaffar 1.17 $storename .= $H->{'name'}."/".$ENV{SCRAM_ARCH};
235 sashby 1.2 }
236 muzaffar 1.17 else
237 sashby 1.2 {
238 muzaffar 1.17 $storename .= $ENV{SCRAM_ARCH}."/".$H->{'name'};
239 sashby 1.2 }
240 muzaffar 1.17 }
241 sashby 1.2 else
242 sashby 1.3 {
243 muzaffar 1.17 $storename .= $H->{'name'};
244 sashby 1.3 }
245 muzaffar 1.17 my $key ="SCRAMSTORENAME_".uc($H->{'name'});
246     $key=~s/\//_/g;
247     $store->{$key}=$storename;
248 sashby 1.2 }
249 muzaffar 1.17 $item->productstore($store);
250 sashby 1.2 }
251 muzaffar 1.17 }
252 sashby 1.2
253     sub update()
254     {
255     my $self=shift;
256 muzaffar 1.17 my ($dircache, $toolmanager) = @_;
257 sashby 1.2 $self->{TOOLMANAGER} = $toolmanager;
258    
259 muzaffar 1.17 my $newbf = $dircache->get_data("ADDEDBF");
260     my $newdir = $dircache->get_data("ADDEDDIR");
261     use File::Path;
262     my $mkpath = $ENV{LOCALTOP}."/".$ENV{SCRAM_INTwork}."/MakeData";
263     my $mkpubpath = $ENV{LOCALTOP}."/.SCRAM/".$ENV{SCRAM_ARCH}."/MakeData";
264     mkpath("${mkpath}/DirCache",0,0755);
265     mkpath("${mkpath}/RmvDirCache",0,0755);
266     mkpath("$mkpubpath/DirCache",0,0755);
267     my %runeng = ();
268     my $projinfo=undef;
269     eval ("use SCRAM::ProjectInfo");
270     if(!$@) {$projinfo = SCRAM::ProjectInfo->new();}
271     if ($newbf)
272 sashby 1.2 {
273 muzaffar 1.17 foreach my $bf ("$ENV{SCRAM_BUILDFILE}.xml","$ENV{SCRAM_BUILDFILE}")
274     {
275     if (exists $newbf->{$ENV{SCRAM_CONFIGDIR}."/${bf}"})
276     {
277     my $treeitem = $self->updatedirbf($dircache,$ENV{SCRAM_SOURCEDIR},$ENV{SCRAM_CONFIGDIR}."/${bf}");
278     $self->updateproductstore($treeitem);
279     $runeng{$ENV{SCRAM_SOURCEDIR}}=$treeitem;
280     delete $newbf->{$ENV{SCRAM_CONFIGDIR}."/${bf}"};
281     last;
282     }
283     }
284 sashby 1.2 }
285 muzaffar 1.17 if ($newdir)
286 sashby 1.2 {
287 muzaffar 1.17 foreach my $path (keys %{$newdir})
288     {
289     if (!exists $newdir->{$path}) {next;}
290     if ($path!~/^$ENV{SCRAM_SOURCEDIR}\/(.+)/){delete $newdir->{$path};next;}
291     my $cinfo = $self->buildclass($path);
292     if ($cinfo && $cinfo->[2] ne ""){$dircache->prune($path,0,$cinfo->[2]);}
293     else
294 sashby 1.2 {
295 muzaffar 1.17 my $item = $self->updatedirbf($dircache,$path,"",$cinfo);
296     $runeng{$path}=$item;
297     my $flag=0;
298     if (!defined $projinfo)
299     {
300     if ($cinfo->[0] eq "library"){$flag=1;}
301     }
302     else
303     {
304     $flag=$projinfo->ispublic($item);
305     }
306     if ($flag)
307     {
308     my $dpath = $self->datapath($path);
309     my $treeitem = $self->{BUILDTREE}->{$dpath};
310     $dircache->{PACKMAP}{$treeitem->parent()}=$dpath;
311     $item->publictype (1);
312     }
313     }
314 sashby 1.2 }
315     }
316 muzaffar 1.17
317     my %mkrebuild=();
318     $mkrebuild{"${mkpath}/RmvDirCache"}=1;
319     my $remdir = $dircache->get_data("REMOVEDDIR");
320     if ($remdir)
321 sashby 1.2 {
322 muzaffar 1.17 foreach my $path (keys %{$remdir})
323     {
324     delete $remdir->{$path};
325     my $spath = $path; $spath =~ s|/|_|g;
326     open(OFILE,">${mkpath}/RmvDirCache/${spath}.mk");
327     print OFILE "REMOVED_DIRS += $path\n";
328     close(OFILE);
329     my $mpath = "${mkpath}/DirCache/${spath}.mk";
330     if (!-f $mpath)
331     {
332     $mpath = "${mkpubpath}/DirCache/${spath}.mk";
333     }
334     if (-f $mpath)
335 sashby 1.11 {
336 muzaffar 1.17 unlink $mpath;
337     $mkrebuild{dirname($mpath)}=1;
338     }
339 sashby 1.11 }
340 sashby 1.2 }
341    
342 muzaffar 1.17 if ($newbf)
343 sashby 1.9 {
344 muzaffar 1.17 foreach my $bf (keys %{$newbf})
345     {
346     my $dpath = $self->datapath($bf);
347     if (exists $dircache->{PACKMAP}{$dpath})
348     {
349     $dpath = $dircache->{PACKMAP}{$dpath};
350     }
351     $self->scan($bf,$dpath);
352     $self->{BUILDTREE}->{$dpath}->metabf($bf);
353     $runeng{"$ENV{SCRAM_SOURCEDIR}/${dpath}"} = $self->{BUILDTREE}->{$dpath};
354     delete $newbf->{$bf};
355     }
356     }
357     foreach my $path (sort {$a cmp $b} keys %runeng)
358     {
359     my $treeitem = $runeng{$path};
360     delete $newdir->{$path};
361     $self->run_engine($treeitem);
362     if (exists $treeitem->{MKDIR})
363     {
364     foreach my $d (keys %{$treeitem->{MKDIR}})
365     {
366     $d=~s/\/\//\//;
367     $mkrebuild{$d}=1;
368     }
369     delete $treeitem->{MKDIR};
370 sashby 1.2 }
371     }
372 muzaffar 1.17 foreach my $dir (keys %mkrebuild)
373     {
374     open(MKFILE,">${dir}.mk") || die "Can not open file for writing: ${dir}.mk";
375     close(MKFILE);
376     if (-d $dir)
377     {
378 muzaffar 1.19 system("cd $dir; find . -name \"*\" -type f | xargs -n 2000 cat {} >> ${dir}.mk");
379 muzaffar 1.17 }
380     }
381 sashby 1.2 }
382    
383     sub scan()
384     {
385     my $self=shift;
386 sashby 1.16 my ($buildfile, $datapath) = @_;
387 sashby 1.7 my $bfparse;
388 sashby 1.16 $bfparse=BuildSystem::BuildFile->new();
389 sashby 1.7 # Execute the parse:
390 sashby 1.2 $bfparse->parse($buildfile);
391 sashby 1.3 # See if there were skipped dirs:
392     my $skipped = $bfparse->skippeddirs($datapath);
393     # Check to see if there was an info array for this location.
394     # If so, we extract the first element of the array (i.e. ->[1])
395     # and store it under the datapath entry. This is just so that useful
396     # messages explaining why the dir was skipped can be preserved.
397     if (ref($skipped) eq 'ARRAY')
398     {
399     $self->skipdir($datapath,$skipped->[1]);
400     }
401 sashby 1.2
402     $self->storedata($datapath, $bfparse);
403 muzaffar 1.17
404 sashby 1.2 return $self;
405     }
406    
407     sub init_engine()
408     {
409     my $self=shift;
410     # Create the interface to the template engine:
411     use BuildSystem::TemplateInterface;
412     # Pass in the config dir as the location where templates live:
413     $self->{TEMPLATE_ENGINE} = BuildSystem::TemplateInterface->new();
414     }
415    
416     sub run_engine()
417     {
418     my $self=shift;
419     my ($templatedata)=@_;
420    
421     $self->{TEMPLATE_ENGINE}->template_data($templatedata);
422     $self->{TEMPLATE_ENGINE}->run();
423     return $self;
424     }
425    
426     sub buildclass
427     {
428     my $self=shift;
429     my ($path)=@_;
430     my $cache=[];
431 sashby 1.11 # From Lassi TUURA (with mods by me):
432     #
433 sashby 1.2 # Associate a path with ClassPath setting.
434     # For now, just assumes global data has been scanned and class settings
435     # are already known (in $self->{CONFIGDATA}->classpath()).
436     # Generate more optimal classpath data structure, only once.
437     # Split every cache definition into an array of pairs, directory
438     # name and class. So ClassPath of type "+foo/+bar/src+library"
439     # becomes [ [ "" "foo" ] [ "" "bar" ] [ "src" "library" ] ]
440 sashby 1.16 my @CLASSPATHS=@{$self->{BUILDTREE}->{$ENV{SCRAM_SOURCEDIR}}->rawdata()->{content}->{CLASSPATH}};
441     # This does not work, even though classpath() is a valid method and rawdata()
442     # returns an object blessed into the correct type:
443     # my @CLASSPATHS=@{$self->{BUILDTREE}->{$ENV{SCRAM_SOURCEDIR}}->rawdata()->classpath()};
444    
445 sashby 1.2 if (! scalar @$cache)
446     {
447     foreach my $classpath (@CLASSPATHS)
448     {
449     push (@$cache, [map { [ split(/\+/, $_) ] } split(/\//, $classpath)]);
450     }
451     }
452    
453     print "WARNING: No ClassPath definitions, nothing will be done!","\n",
454     if (! scalar @$cache);
455     # Now scan the class paths. All the classpaths are given a rank
456     # to mark how relevant they are, and then the best match is chosen.
457     #
458     # The ranking logic is as follows. We scan each class path and
459     # drop if it doesn't match at all. For paths that match, we
460     # record how many components of the class was *not* used to match
461     # on the class: for a short $path, many classes will match.
462     # For each path component we record whether the match was exact
463     # (if the class part is empty, i.e. "", it's a wildcard that
464     # matches everything). Given these rankings, we pick
465     # - the *first* class that
466     # - has least *unmatched* components
467     # - with *first* or *longest* exact match sequence in
468     # left-to-right order.
469     my @ranks = ();
470     my @dirs = split(/\/+/, $path);
471     CLASS: foreach my $class (@$cache)
472     {
473     # The first two members of $rank are fixed: how much of path
474     # was and was not used in the match.
475     my $rank = [[], [@dirs]];
476     foreach my $component (@$class)
477     {
478     my $dir = $rank->[1][0];
479     if (! defined $dir)
480     {
481     # Path exhausted. Leave used/unused as is.
482     last;
483     }
484     elsif ($component->[0] eq "")
485     {
486     # Wildcard match, push class and use up path
487     push(@$rank, [1, $component->[1]]);
488     push(@{$rank->[0]}, shift(@{$rank->[1]}));
489     }
490     elsif ($component->[0] eq $dir)
491     {
492     # Exact match, push class and use up path
493     push(@$rank, [0, $component->[1]]);
494     push(@{$rank->[0]}, shift(@{$rank->[1]}));
495     }
496     else
497     {
498     # Unmatched, leave used/unused as is.
499     last;
500     }
501     }
502    
503     push(@ranks, $rank);
504     }
505    
506     # If no classes match, bail out:
507     if (! scalar @ranks)
508     {
509     return "";
510     }
511    
512     # Sort in ascending order by how much was of class was not used;
513     # the first entry has least "extra" trailing match data. Then
514     # truncate to only those equal to the best rank.
515     my @sorted = sort { scalar(@{$a->[1]}) <=> scalar(@{$b->[1]}) } @ranks;
516     my @best = grep(scalar(@{$_->[1]}) == scalar(@{$sorted[0][1]}), @sorted);
517    
518     # Now figure which of the best-ranking classes have the longest
519     # exact match in left-to-right order (= which one is first, and
520     # those with equal first exact match, longest exact match).
521     my $n = 0;
522     my $class = $best[$n][scalar @{$best[$n]}-1];
523     # Return the class data:
524     return [ $class->[1], join('/', @{$best[$n][0]}), join('/', @{$best[$n][1]}) ];
525     }
526    
527     sub storedata
528     {
529     my $self=shift;
530     my ($datapath, $data)=@_;
531     # Store the content of this BuildFile in cache:
532     $self->{BUILDTREE}->{$datapath}->rawdata($data);
533     return $self;
534     }
535    
536     sub removedata
537     {
538     my $self=shift;
539     my ($removedpaths) = @_;
540    
541     foreach my $rd (@$removedpaths)
542     {
543     my $datapath = $self->datapath($rd);
544     # Remove all data, recursively, from $datapath:
545     $self->recursive_remove_data($datapath);
546     }
547    
548     return $self;
549     }
550    
551     sub recursive_remove_data()
552     {
553     my $self=shift;
554     my ($datapath)=@_;
555    
556     # Delete main entry in build data via TreeItem:
557     if (exists($self->{BUILDTREE}->{$datapath}))
558     {
559     # We also must modify the parent TreeItem to remove the child
560     # from SAFE_SUBDIRS as well as from CHILDREN array:
561     my $parent = $self->{BUILDTREE}->{$datapath}->parent();
562     $self->{BUILDTREE}->{$parent}->updatechildlist($datapath);
563    
564     # Get the children:
565     my @children = $self->{BUILDTREE}->{$datapath}->children();
566    
567     foreach my $childpath (@children)
568     {
569     # The child path value is the datapath so can be used
570     # directly when deleting data entries
571     $self->recursive_remove_data($childpath);
572     }
573    
574     # Finally, delete the parent data (a TreeItem):
575     delete $self->{BUILDTREE}->{$datapath};
576     }
577    
578     # return:
579     return $self;
580     }
581    
582     sub storebranchmetadata()
583     {
584     my $self=shift;
585     my ($datapath,$data)=@_;
586    
587     # Store the content of this BuildFile in cache:
588     $self->{BUILDTREE}->{$datapath}->branchmetadata($data);
589     return $self;
590     }
591    
592     sub buildobject
593     {
594     my $self=shift;
595     my ($datapath)=@_;
596    
597     if (exists($self->{BUILDTREE}->{$datapath}) && defined($self->{BUILDTREE}->{$datapath}->rawdata()))
598     {
599     return $self->{BUILDTREE}->{$datapath}->rawdata();
600     }
601     else
602     {
603     return undef;
604     }
605     }
606    
607     sub metaobject
608     {
609     my $self=shift;
610     my ($datapath)=@_;
611    
612     if (exists($self->{BUILDTREE}->{$datapath}) && defined($self->{BUILDTREE}->{$datapath}->branchmetadata()))
613     {
614     return $self->{BUILDTREE}->{$datapath}->branchmetadata();
615     }
616     else
617     {
618     return undef;
619     }
620     }
621    
622 sashby 1.6 sub searchprojects()
623     {
624     my $self=shift;
625     my ($group,$projectref)=@_;
626    
627     foreach my $pjt (keys %{$self->{SCRAM_PROJECTS}})
628     {
629     print "Checking for group $group in SCRAM project $pjt","\n", if ($ENV{SCRAM_DEBUG});
630     # As soon as a project is found to have defined $group, we return
631     # the project name:
632     if (exists $self->{SCRAM_PROJECTS}->{$pjt}->{KNOWNGROUPS}->{$group})
633     {
634     # Store the project name and data path:
635 muzaffar 1.17 $$projectref="project ".uc($pjt)." (".$self->{SCRAM_PROJECTS}->{$pjt}->{KNOWNGROUPS}->{$group}."/".$ENV{SCRAM_BUILDFILE}.")";
636 sashby 1.6 return(1);
637     }
638     }
639    
640     # No group found to have been defined already so return false:
641     return (0);
642     }
643    
644 sashby 1.2 sub findgroup
645     {
646     my $self=shift;
647     my ($groupname) = @_;
648    
649     if (exists $self->{KNOWNGROUPS}->{$groupname})
650     {
651     # If group exists, return data:
652     return $self->{KNOWNGROUPS}->{$groupname};
653     }
654     else
655     {
656     # Not found so return:
657     return(0);
658     }
659     }
660    
661     sub knowngroups
662     {
663     my $self=shift;
664     @_ ? $self->{KNOWNGROUPS}=shift
665     : $self->{KNOWNGROUPS}
666     }
667    
668     sub scramprojectbases()
669     {
670     my $self=shift;
671     return $self->{SCRAM_PROJECT_BASES};
672     }
673    
674     sub alldirs
675     {
676     my $self=shift;
677     return @{$self->{ALLDIRS}};
678     }
679    
680 sashby 1.3 sub skipdir
681     {
682     my $self=shift;
683     my ($dir, $message) = @_;
684    
685     # Set the info if we have both args:
686     if ($dir && $message)
687     {
688     $self->{SKIPPEDDIRS}->{$dir} = $message;
689     }
690     # If we have the dir name only, return true if
691     # this dir is to be skipped:
692     elsif ($dir)
693     {
694     (exists($self->{SKIPPEDDIRS}->{$dir})) ? return 1 : return 0;
695     }
696     else
697     {
698     # Dump the list of directories and the message for each:
699     foreach my $directory (keys %{$self->{SKIPPEDDIRS}})
700     {
701     print "Directory \"",$directory,"\" skipped by the build system";
702     if (length($self->{SKIPPEDDIRS}->{$directory}->[0]) > 10)
703     {
704     chomp($self->{SKIPPEDDIRS}->{$directory}->[0]);
705     my @lines = split("\n",$self->{SKIPPEDDIRS}->{$directory}->[0]); print ":\n";
706     foreach my $line (@lines)
707     {
708     next if ($line =~ /^\s*$/);
709     print "\t-- ",$line,"\n";
710     }
711     print "\n";
712     }
713     else
714     {
715     print ".","\n";
716     }
717     }
718     }
719     }
720    
721 sashby 1.11 # Keep a record of which packages are missed by each location
722     # so that, on subsequent updates, these can be inserted auto-
723     # matically in the metadata for the location:
724     sub unresolved()
725     {
726     my $self=shift;
727     my ($location, $pneeded) = @_;
728     # Need to record a mapping "LOCATION -> [ missing packages ]" and a
729     # reverse-lookup "<missing package> -> [ LOCATIONS (where update required) ]"
730     $self->{UNRESOLVED_DEPS_BY_LOC}->{$location}->{$pneeded} = 1;
731     $self->{UNRESOLVED_DEPS_BY_PKG}->{$pneeded}->{$location} = 1;
732     }
733    
734 sashby 1.2 sub verbose
735     {
736     my $self=shift;
737     # Turn on verbose mode:
738     @_ ? $self->{VERBOSE} = shift
739     : $self->{VERBOSE}
740     }
741    
742     sub cachestatus()
743     {
744     my $self=shift;
745     # Set/return the status of the cache:
746     @_ ? $self->{STATUS} = shift
747     : $self->{STATUS}
748     }
749    
750     sub logmsg
751     {
752     my $self=shift;
753     # Print a message to STDOUT if VERBOSE is true:
754     print STDERR @_ if $self->verbose();
755     }
756    
757     sub name()
758     {
759     my $self=shift;
760     # Set/return the name of the cache to use:
761     @_ ? $self->{CACHENAME} = shift
762     : $self->{CACHENAME}
763     }
764    
765     sub save()
766     {
767     my $self=shift;
768     # Delete unwanted stuff:
769     delete $self->{DEPENDENCIES};
770     delete $self->{TOOLMANAGER};
771     delete $self->{TEMPLATE_ENGINE};
772     delete $self->{SCRAM_PROJECTS};
773     delete $self->{SCRAM_PROJECT_BASES};
774     return $self;
775     }
776    
777     1;