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.18 |
# Revision: $Id: BuildDataStorage.pm,v 1.14.2.2 2007/11/08 15:25:27 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 |
|
|
system("cd $dir; find . -name \"*\" -type f | xargs -n 2000 -i cat {} >> ${dir}.mk");
|
379 |
|
|
}
|
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;
|