Subversion Repositories DevTools

Rev

Rev 255 | Rev 267 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
245 dpurdie 1
########################################################################
2
# Copyright (C) 2008 ERG Limited, All rights reserved
3
#
4
# Module name   : jats.sh
5
# Module type   : Makefile system
6
# Compiler(s)   : n/a
7
# Environment(s): jats
8
#
9
# Description   : Class to provide utilities associated with a locating
10
#                 build files and build file dependencies.
11
#
12
#......................................................................#
13
 
14
require 5.006_001;
15
use strict;
16
use warnings;
17
 
18
package JatsBuildFiles;
19
use JatsError;
20
use File::Find;
21
use BuildName;
22
use JatsVersionUtils;
23
 
24
our (@ISA, @EXPORT, @EXPORT_OK, %EXPORT_TAGS, $VERSION);
25
use Exporter;
26
 
27
$VERSION = 1.00;
28
@ISA = qw(Exporter);
29
 
30
# Symbols to autoexport (:DEFAULT tag)
31
@EXPORT = qw( BuildFileScanner
32
            );
33
 
34
 
35
#-------------------------------------------------------------------------------
36
# Function        : BuildEntry
37
#
38
# Description     : Create a BuildEntry Object
39
#                   This object describes a build file. It is passed to the
40
#                   user of this class.
41
#
42
#                   There are no object accessors.
43
#                   Just use the object as a reference to hash.
44
#
45
# Inputs          : $dir                - Dir of the build file
46
#                   $file               - Name of the build file
47
#                   $type               - Type 1:Jats, 2:ANT
48
#
49
# Returns         : Reference to an object
50
#
51
sub BuildEntry
52
{
53
    my $self  = {};
54
 
55
    $self->{dir} = shift;
56
    $self->{file}  = shift;
57
    $self->{type} = shift;
58
 
59
    #
60
    #   Other fields that are known:
61
    #       name
62
    #       version
63
    #       full
64
    #       mname
65
    #       project
66
    #
67
 
68
    bless ($self, 'BuildEntry');
69
    return $self;
70
}
71
 
72
#-------------------------------------------------------------------------------
73
# Function        : BuildFileScanner
74
#
75
# Description     : Create a new instance of a build file class
76
#                   This is the one exported function of this class
77
#                   It is a constructor to allow scanning for build files
78
#
79
# Inputs          : root            - Base pathname
80
#                   file            - Build filename
81
#                   options         - Options to be processed
82
#
83
#                   Options are:
84
#                   --ScanDependencies  - Collect information on dependent packages
85
#                   --LocateAll         - Scan for ANT and JATS build files
86
#
87
#
88
# Returns         : A reference to class.
89
#
90
sub BuildFileScanner {
91
    my $self  = {};
92
 
93
    $self->{root} = shift;
94
    $self->{file}  = shift;
95
    $self->{info} = [];
96
    $self->{scandeps} = 0;
97
    $self->{locateAll} = 0;             # Scan Jats and Ant files
98
 
99
    bless ($self);
100
 
101
    Error ("Locating Build files. Root directory not found",
102
           "Path: $self->{root}" ) unless ( -d $self->{root} );
103
    #
104
    #   Process user arguments.
105
    #   These are treated as options. Leading '--' is optional
106
    #
107
    foreach ( @_ )
108
    {
109
        my $opt = '--' . $_;
110
        $opt =~ s~^----~--~;
111
        $self->option ($opt) || Error( "BuildFileScanner. Unknown initialiser: $_");
112
    }
113
    return $self;
114
}
115
 
116
#-------------------------------------------------------------------------------
117
# Function        : option
118
#
119
# Description     : Function to simplify the processing of arguments
120
#                   Given an argument this function will act on it or
121
#                   return false
122
#
123
# Inputs          : option          - One possible standard search option
124
#
125
# Returns         : True            - Option is an  option and its been
126
#                                     processed
127
#
128
sub option
129
{
130
    my ($self, $opt) = @_;
131
    my $result = 1;
132
 
133
    if ( $opt =~ m/^--ScanDependencies/ ) {
134
        $self->{scandeps} = 1;
135
 
136
    } elsif ( $opt =~ m/^--LocateAll/ ) {
137
        $self->{locateAll} = 1;
138
 
139
    } else {
140
        $result = 0;
141
 
142
    }
143
    return $result;
144
}
145
 
146
#-------------------------------------------------------------------------------
147
# Function        : locate
148
#
149
# Description     : Locate all build files within a given directory tree
150
#                   Collects the data and builds up a data structure
151
#
152
# Inputs          : $self
153
#
154
# Returns         : Number of buildfiles found 0,1 ....
155
#
156
sub locate
157
{
158
    my ($self) = @_;
159
 
160
    #
161
    #   Locate all the build files that match the users request
162
    #   Use 'our' to avoid closure issues
163
 
164
    our  $ff_datap = \@{$self->{info}};
165
    our  $ff_file = $self->{file};
166
    our  $ff_all = $self->{locateAll};
167
    our  $ff_self = $self;
168
 
169
    sub find_file_wanted
170
    {
171
        if ( $_ eq $ff_file  )
172
        {
173
            Verbose ("find_file_wanted: FOUND $File::Find::dir, $_");
174
            push @{$ff_datap}, BuildEntry( $File::Find::dir, $_, 1);
175
        }
176
 
177
        #
178
        #   Detect ANT {packagename}depends.xml file
179
        #   These are file pairs (mostly)
180
        #
181
        if ( $ff_all && $_ =~ m/(.+)depends.xml$/ )
182
        {
183
            if ( -f $1 . '.xml' )
184
            {
185
                Verbose ("find_file_wanted: FOUND $File::Find::dir, $_");
186
                push @{$ff_datap}, BuildEntry( $File::Find::dir, $_, 2);
187
            }
188
        }
189
    }
190
 
191
    #
192
    #   Find all matching files
255 dpurdie 193
    #   Call helper rouine to populate the data strcutures
245 dpurdie 194
    #
195
    File::Find::find ( \&find_file_wanted, $self->{root} );
196
 
197
    #
198
    #   Flag that the directories have been scanned
199
    #
200
    $self->{locate_done} = 1;
201
    return scalar  @{$self->{info}};
202
}
203
 
204
#-------------------------------------------------------------------------------
205
# Function        : scan
206
#
207
# Description     : Scan all buildfiles and determine the packages that are
208
#                   created by file(s)
209
#
210
#                   This routine can extract build dependency information, but
211
#                   this is not done by default
212
#
213
# Inputs          : $self
214
#
215
# Returns         : 
216
#
217
sub scan
218
{
219
    my ($self) = @_;
220
 
221
    #
222
    #   Locate the buildfiles, unless this has been done
223
    #
224
    locate ( $self ) unless ( $self->{locate_done} );
225
 
226
    #
227
    #   Scan all build files and determine the target package name
228
    #
229
    #
230
    foreach my $be ( @{$self->{info}} )
231
    {
232
        if ( $be->{type} == 2 ) {
233
            scan_ant ( $be, $self->{scandeps} );
234
        } else {
235
            scan_jats ( $be, $self->{scandeps} );
236
        }
237
 
238
        #
261 dpurdie 239
        #   Skip invalid build files
240
        #
241
        next unless ( $be->{name} &&  $be->{version}  );
242
 
243
        #
245 dpurdie 244
        #   Calculate internal information from the basic information
245
        #   full  - Full package version and extension
246
        #   mname - name and extension
247
        #   package - name and extension with a $; joiner
248
        #
249
        $be->{version} .= '.' . $be->{prj} if ( $be->{prj} );
250
        $be->{full} = $be->{name} . '.' . $be->{version};
251
        $be->{mname} = $be->{name};
252
        $be->{mname} .= '.' . $be->{prj} if ( $be->{prj} );
253
 
254
        $be->{package} = join $;, $be->{name}, $be->{prj};
253 dpurdie 255
        Verbose2( "Buildfile: $be->{dir}, $be->{file},$be->{name}");
245 dpurdie 256
    }
257
    $self->{scan_done} = 1;
258
}
259
 
260
#-------------------------------------------------------------------------------
261
# Function        : scan_jats
262
#
263
# Description     : Scan a jats build file
264
#
265
# Inputs          : $be         - Reference to a BuildEntry
266
#                   $scanDeps   - Include dependency information
267
#
268
# Returns         : Nothing
269
#
270
sub scan_jats
271
{
272
    my ($be, $scanDeps ) = @_;
273
 
274
    my $infile = "$be->{dir}/$be->{file}";
275
    open ( INFILE, "<$infile" ) || Error( "Cannot open $infile" );
276
    while ( <INFILE> )
277
    {
278
        next if ( m~^\s*#~ );            # Skip comments
279
        #
280
        #   Process BuildName
281
        #
282
        if ( m~\s*BuildName[\s\(]~ )
283
        {
284
            #   Build names come in many flavours, luckily we have a function
285
            #
286
            m~\(\s*(.*?)\s*\)~;
287
            my @args = split /\s*,\s*/, $1;
288
            my $build_info = BuildName::parseBuildName( @args );
289
 
290
            $be->{name} = $build_info->{BUILDNAME_PACKAGE};
291
            $be->{version} = $build_info->{BUILDNAME_VERSION};
292
            $be->{prj} = $build_info->{BUILDNAME_PROJECT};
293
        }
294
 
295
        #
296
        #   (Optional) Process BuildPkgArchive and LinkPkgArchive
297
        #   Retain the Name and the ProjectSuffix and the version
298
        #
299
        if ( $scanDeps && ( m/^LinkPkgArchive/ or m/^BuildPkgArchive/ ))
300
        {
301
            m/['"](.*?)['"][^'"]*['"](.*?)['"]/;
302
 
303
            my ( $package, $rel, $suf, $full ) = SplitPackage( $1, $2 );
304
            $be->{depends}{$package,$suf} = $rel;
305
        }
306
    }
307
    close INFILE;
308
}
309
 
310
 
311
#-------------------------------------------------------------------------------
312
# Function        : scan_ant
313
#
314
# Description     : Scan an ant build file
315
#
316
# Inputs          : $be         - Reference to a BuildEntry
317
#                   $scanDeps   - Include dependency information
318
#
319
# Returns         : Nothing
320
#
321
sub scan_ant
322
{
323
    my ($be, $scanDeps ) = @_;
324
    my $infile = "$be->{dir}/$be->{file}";
325
    my $release_name;
326
    my $release_version;
327
 
328
    open ( INFILE, "<$infile" ) || Error( "Cannot open $infile" );
329
    while ( <INFILE> )
330
    {
331
        #
332
        #   Process "property" statements
333
        #
334
        if ( m~<property~ )
335
        {
336
            my $name;
337
            my $value;
338
 
339
            #
340
            #   Extract the name and version
341
            #
342
            $name = $1 if m~name=\"([^"]*)"~;
343
            $value = $1 if m~value=\"([^"]*)"~;
344
 
345
            if ( $name && $value )
346
            {
347
                if ( $name eq 'packagename' ) {
348
                    $release_name = $value;
349
 
350
                } elsif ( $name eq 'packageversion' ) {
351
                    $release_version = $value;
352
                    my ( $package, $rel, $suf, $full ) = SplitPackage( $release_name, $release_version );
353
                    $be->{name} = $package;
354
                    $be->{version} = $rel;
355
                    $be->{prj} = $suf;
356
 
255 dpurdie 357
                } elsif ( $name eq 'releasemanager.releasename' ) {
358
                    next;
359
 
360
                } elsif ( $name eq 'releasemanager.projectname' ) {
361
                    next;
362
 
245 dpurdie 363
                } elsif ( $scanDeps ) {
364
                    my ( $package, $rel, $suf, $full ) = SplitPackage( $name, $value );
365
                    $be->{depends}{$package,$suf} = $rel;
366
                }
367
            }
368
        }
369
    }
370
    close INFILE;
371
}
372
 
373
#-------------------------------------------------------------------------------
374
# Function        : getInfo
375
#
376
# Description     : Returns an array of stuff that can be used to iterate
377
#                   over the collected data.
378
#
379
#                   Will perform a 'locate' if not already done
380
#
381
#                   The elements are BuildEntries
382
#                   These are pretty simple
383
#
384
# Inputs          : $self
385
#
386
# Returns         : 
387
#
388
sub getInfo
389
{
390
    my ($self) = @_;
391
 
392
    #
393
    #   Locate the buildfiles, unless this has been done
394
    #
395
    locate ( $self ) unless ( $self->{locate_done} );
396
 
397
    return @{$self->{info}};
398
}
399
 
400
#-------------------------------------------------------------------------------
401
# Function        : match
402
#
403
# Description     : Determine build files that match a given package
404
#                   A full package name has three fields
405
#                       1) Name
406
#                       2) Version
407
#                       3) Extension (optional)
408
#                   The package can be specified as:
409
#                       Name.Version.Extension
410
#                       Name.Extension
411
#
412
# Inputs          : $self
413
#                   $package                - See above
414
#
415
# Returns         : Number of buildfiles that match
416
#
417
sub match
418
{
419
    my ($self, $package) = @_;
420
    return 0 unless ( $package );
421
    scan ( $self ) unless ( $self->{scan_done} );
422
 
423
    $self->{match} = [];
424
 
425
    foreach my $be ( @{$self->{info}} )
426
    {
427
        if ( $package eq $be->{mname} || $package eq $be->{full} )
428
        {
429
            push @{$self->{match}}, $be;
430
        }
431
    }
432
 
433
    $self->{match_done} = 1;
434
    return scalar @{$self->{match}}
435
}
436
 
437
#-------------------------------------------------------------------------------
438
# Function        : getMatchList
439
#
440
# Description     : Get the results of a match
441
#                   If no match has been done, then return the complete
442
#                   list - Like getInfo
443
#
444
# Inputs          : $self
445
#
446
# Returns         : Array of directories that matched the last match
447
#
448
sub getMatchList
449
{
450
    my ($self) = @_;
451
    my $set = 'info';
452
    $set = 'match' if ( $self->{match_done} );
453
 
454
    return @{$self->{$set}};
455
}
456
 
457
#-------------------------------------------------------------------------------
458
# Function        : getMatchDir
459
#
460
# Description     : Get the results of a match
461
#                   Can be an array or a scalar. If a scalar is requested
462
#                   then this rouitne will ensure that only one entry
463
#                   has been matched.
464
#
465
# Inputs          : $self
466
#
467
# Returns         : Array of directories that matched the last match
468
#
469
sub getMatchDir
470
{
471
    my ($self) = @_;
472
    my @list;
473
    foreach my $be ( $self->getMatchList() )
474
    {
475
        push @list, $be->{dir};
476
    }
477
 
478
    if ( wantarray )
479
    {
480
        return @list;
481
    }
482
 
483
    Error ("Locate Build file. Internal error",
484
           "Multiple build files have been located. This condition should have",
485
           "been handled by the application") if ( $#list > 0 );
486
 
487
    return $list[0];
488
}
489
 
490
#-------------------------------------------------------------------------------
491
# Function        : formatData
492
#
493
# Description     : Create an array of build files and package names
494
#                   Used to pretty print error messages
495
#
496
# Inputs          : $self
497
#
498
# Returns         : Array of text strings formatted as:
499
#                   path : packagename
500
#
501
#
502
sub formatData
503
{
504
 
505
    my ($self) = @_;
506
    my @text;
507
 
508
    my $max_len = 0;
509
    my %data;
510
 
511
    #
512
    #   Travserse the internal data
513
    #
514
    foreach my $be ( @{$self->{info}} )
515
    {
516
        my $package = $be->{mname};
517
        my $path = "$be->{dir}/$be->{file}";
518
        my $len = length $path;
519
        $max_len = $len if ( $len > $max_len );
520
        $data{$path} = $package;
521
    }
522
 
523
    foreach my $path ( sort keys %data )
524
    {
525
        push (@text, sprintf ("%${max_len}s : %s", $path, $data{$path} ));
526
    }
527
 
528
    return @text;
529
}
530
 
531
1;