Subversion Repositories DevTools

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
227 dpurdie 1
#! /usr/bin/perl
2
########################################################################
3
# Copyright (C) 1998-2004 ERG Limited, All rights reserved
4
#
5
# Module name   : jats_cbuilder.pl
6
# Module type   : Makefile system
7
# Compiler(s)   : n/a
8
# Environment(s):
9
#
10
# Description   : A script to build a collection of packages in the
11
#                 same sandbox. This script will:
12
#
13
#                   Determine the packages in the sandbox
14
#                   Determine the build order of the packages
15
#                   Build the packages in the correct order
16
#                   Make the packages in the correct order
17
#
18
#                 The script will allow for:
19
#                   The creation of a sandbox
20
#                   The addition of packages to the sandbox
21
#                   Removal of packages from the sandbox
22
#
23
#
24
#                 Command syntax (basic)
25
#                   jats sandbox <command> (options | actions)@
26
#
27
#                 Commands include:
28
#                   create              - Create a sandbox
29
#                   delete              - Delete a sandbox
30
#
31
#                   add package_name    - Add a package to the sandbox
32
#                   rm  package_name    - Remove a package from the sandbox
33
#
34
#                   build               - Build all packages in the sandbox
35
#                   make                - make all packages in the sandbox
36
#
37
#......................................................................#
38
 
39
require 5.6.1;
40
use strict;
41
use warnings;
42
use JatsError;
43
use JatsSystem;
44
use FileUtils;
45
use BuildName;
46
use JatsVersionUtils;
47
 
48
 
49
use File::Find;
50
use Pod::Usage;                             # required for help support
51
use Getopt::Long qw(:config require_order); # Stop on non-option
52
my $VERSION = "1.0.0";                      # Update this
53
 
54
#
55
#   Options
56
#
57
my $opt_debug   = $ENV{'GBE_DEBUG'};        # Allow global debug
58
my $opt_verbose = $ENV{'GBE_VERBOSE'};      # Allow global verbose
59
my $opt_help = 0;
60
my $opt_manual = 0;
61
 
62
#
63
#   Globals - Provided by the JATS environment
64
#
65
my $USER         = $ENV{'USER'};
66
my $UNIX         = $ENV{'GBE_UNIX'};
67
my $HOME         = $ENV{'HOME'};
68
my $GBE_SANDBOX  = $ENV{'GBE_SANDBOX'};
69
my $GBE_DPKG_SBOX= $ENV{'GBE_DPKG_SBOX'};
70
 
71
#
72
#   Globals
73
#
74
my @build_order = ();                     # Build Ordered list of entries
75
my %extern_deps;                          # Hash of external dependancies
76
my %packages;                             # Hash of packages
77
 
78
 
79
#-------------------------------------------------------------------------------
80
# Function        : Mainline Entry Point
81
#
82
# Description     :
83
#
84
# Inputs          :
85
#
86
my $result = GetOptions (
87
                "help+"         => \$opt_help,              # flag, multiple use allowed
88
                "manual"        => \$opt_manual,            # flag, multiple use allowed
89
                "verbose+"      => \$opt_verbose,           # flag, multiple use allowed
90
                );
91
 
92
                #
93
                #   UPDATE THE DOCUMENTATION AT THE END OF THIS FILE !!!
94
                #
95
 
96
#
97
#   Process help and manual options
98
#
99
pod2usage(-verbose => 0, -message => "Version: $VERSION")  if ($opt_help == 1  || ! $result);
100
pod2usage(-verbose => 1)  if ($opt_help == 2 );
101
pod2usage(-verbose => 2)  if ($opt_manual || ($opt_help > 2));
102
 
103
#
104
#   Configure the error reporting process now that we have the user options
105
#
106
ErrorConfig( 'name'    => 'SANDBOX',
107
             'verbose' => $opt_verbose );
108
 
109
#
110
#   Validate user options
111
#
112
 
113
#
114
#   Parse the user command and decide what to do
115
#
116
#
117
my $cmd = shift @ARGV || "";
118
help(1)                                 if ( $cmd =~ m/^help$/ || $cmd eq "" );
119
create_sandbox()                        if ( $cmd =~ m/^create$/ );
120
info(@ARGV)                             if ( $cmd =~ m/^info$/ );
121
cmd(@ARGV)                              if ( $cmd =~ m/^cmd$/ );
122
 
123
Error ("Unknown sandbox command: $cmd");
124
exit 1;
125
 
126
 
127
#-------------------------------------------------------------------------------
128
#
129
#   Give the user a clue
130
#
131
sub help
132
{
133
    my ($level) = @_;
134
    $level = $opt_help unless ( $level );
135
 
136
    pod2usage(-verbose => 0, -message => "Version: ". $VERSION)  if ($level == 1 );
137
    pod2usage(-verbose => $level -1 );
138
}
139
 
140
#-------------------------------------------------------------------------------
141
# Function        : create_sandbox
142
#
143
# Description     : create a sandbox in the current current directory
144
#
145
# Inputs          : None
146
#
147
#
148
sub create_sandbox
149
{
150
    Error ("Cannot create a sandbox within a sandbox",
151
           "Sandbox base is: $GBE_SANDBOX" ) if ( $GBE_SANDBOX );
152
    mkdir ('sandbox_dpkg_archive') || Error ("Cannot create the directory: sandbox_dpkg_archive") ;
153
    exit  0;
154
}
155
 
156
#-------------------------------------------------------------------------------
157
# Function        : info
158
#
159
# Description     : Display Sandbox information
160
#
161
# Inputs          : Command line args
162
#                   -v  - Be more verbose
163
#
164
# Returns         : Will exit
165
#
166
sub info
167
{
168
    #
169
    #   Allow user to specify verboseness as an argument
170
    #
171
    foreach  ( @_ )
172
    {
173
        $opt_verbose++ if ( m/^-v/ )
174
    }
175
 
176
    #
177
    #   Determine Sandbox information
178
    #   Populate global variables
179
    #
180
    calc_sandbox_info();
181
 
182
    #
183
    #   Display information
184
    #
185
    Message ("Base: $GBE_SANDBOX");
186
    Message ("Archive: $GBE_DPKG_SBOX");
187
 
188
    Message ("Build Order");
189
    foreach my $fe ( @build_order )
190
    {
191
        Message( "    Level:" . $fe->{level} . " Name: " . $fe->{pname} );
192
        Message( DisplayPath ("        Path: $fe->{dir}" )) if $opt_verbose;
193
 
194
        if ( $opt_verbose )
195
        {
196
            foreach my $idep ( sort keys %{$fe->{ideps}} )
197
            {
198
                my ($ppn,$pps) = split( $; , $idep);
199
                Message ("        I:$ppn.$pps");
200
            }
201
 
202
            foreach my $edep ( sort keys %{$fe->{edeps}} )
203
            {
204
                my ($ppn,$pps) = split( $; , $edep);
205
                my $pv = $fe->{edeps}{$edep};
206
                Message ("        E:$ppn $pv.$pps");
207
            }
208
 
209
        }
210
    }
211
 
212
    Message("External Dependancies");
213
    foreach my $de ( sort keys %extern_deps )
214
    {
215
        my ($pn,$ps) = split( $; , $de);
216
        my @vlist = keys %{$extern_deps{$de}};
217
        my $flag = $#vlist ? '*' : ' ';
218
        foreach my $pv ( @vlist )
219
        {
220
            Message ("   $flag$pn $pv.$ps");
221
            if ( $opt_verbose )
222
            {
223
                foreach my $pkg ( @{$extern_deps{$de}{$pv}} )
224
                {
225
                    my ($ppn,$pps) = split( $; , $pkg);
226
                    Message ("        U:$ppn.$pps");
227
 
228
                }
229
            }
230
        }
231
    }
232
 
233
    if ( $opt_verbose > 2 )
234
    {
235
        DebugDumpData( "extern_deps", \%extern_deps);
236
        DebugDumpData( "build_order", \@build_order);
237
        DebugDumpData( "packages", \%packages);
238
    }
239
    exit (0);
240
}
241
 
242
#-------------------------------------------------------------------------------
243
# Function        : calc_sandbox_info
244
#
245
# Description     : Examine the sandbox and determine all the important
246
#                   information
247
#
248
# Inputs          : None
249
#
250
# Returns         : Will exit if not in a sandbox
251
#                   Populates global variables
252
#                       @build_order - build ordered array of build entries
253
#
254
sub calc_sandbox_info
255
{
256
    #
257
    #   Start from the root of the sandbox
258
    #
259
    Error ("Command must be executed from within a Sandbox") unless ( $GBE_SANDBOX );
260
    chdir ($GBE_SANDBOX) || Error ("Cannot chdir to $GBE_SANDBOX");
261
 
262
    #
263
    #   Locate all packages within the sandbox
264
    #   These will be top-level directories - one per package
265
    #
266
    my @dirlist;
267
    my @build_list;
268
    foreach ( glob("*") )
269
    {
270
        next if ( m~^\.~ );
271
        next if ( m~dpkg_archive$~ );
272
        next unless ( -d $_ );
273
        Verbose ("Package discovered: $_");
274
        push @dirlist, $_;
275
 
276
        #
277
        #   Locate the build files in each package
278
        #
279
        my @blist = locate_build_files( $_ );
280
        Warning ("Package does not have build files: $_") unless ( @blist );
281
        Warning ("Package has multiple build files: $_") if ( $#blist > 0 );
282
 
283
        foreach my $fe ( @blist )
284
        {
285
            push @build_list, $fe;
286
        }
287
    }
288
 
289
    #
290
    #   Process each build file and extract
291
    #       Name of the Package
292
    #       Dependency list
293
    #   Build up a hash of dependence information
294
    #
295
 
296
#    Verbose "Packages Found: @dirlist\n";
297
 
298
    my %depends;
299
    foreach my $fe ( @build_list )
300
    {
301
        Verbose( DisplayPath ("Build file: " . $fe->{dir} . " Name: " . $fe->{file} ));
302
        process_build_file ( $fe );
303
#        DebugDumpData ("fe", $fe );
304
 
305
        #
306
        #   Add into dependency struct
307
        #
308
        $depends{$fe->{package}}{depends} = $fe->{depends};
309
        $depends{$fe->{package}}{entry} = $fe;
310
    }
311
 
312
    #
313
    #   Determine the build order
314
    #
315
    @build_order = ();
316
    my $more = 1;
317
    my $level = 0;
318
 
319
    #
320
    #   Remove any dependancies to 'external' packages
321
    #   These will not be met internally and can be regarded as constant
322
    #
323
    foreach my $key ( keys %depends )
324
    {
325
        foreach my $build ( keys( %{$depends{$key}{depends}} ))
326
        {
327
            unless (exists $depends{$build})
328
            {
329
                push @{$extern_deps{$build}{$depends{$key}{depends}{$build}}}, $key;
330
                $depends{$key}{entry}{edeps}{$build} = $depends{$key}{depends}{$build};
331
                delete ($depends{$key}{depends}{$build}) ;
332
                Verbose2( "Not in set: $build");
333
            }
334
            else
335
            {
336
                $depends{$key}{entry}{ideps}{$build} = 1;
337
            }
338
        }
339
    }
340
    while ( $more )
341
    {
342
        $more = 0;
343
        $level++;
344
        my @build;
345
 
346
        #
347
        #   Locate packages with no dependencies
348
        #
349
        foreach my $key ( keys %depends )
350
        {
351
            next if ( keys( %{$depends{$key}{depends}} ) );
352
            push @build, $key;
353
        }
354
 
355
        foreach my $build ( @build )
356
        {
357
            $more = 1;
358
            my $fe = $depends{$build}{entry};
359
            $fe->{level} = $level;
360
            $packages{$build} = $fe;
361
            push @build_order, $fe;
362
            delete $depends{$build};
363
            delete $fe->{depends};                          # remove now its not needed
364
        }
365
 
366
        foreach my $key ( keys %depends )
367
        {
368
            foreach my $build ( @build )
369
            {
370
                delete $depends{$key}{depends}{$build};
371
            }
372
        }
373
    }
374
 
375
    #
376
    #   Just to be sure to be sure
377
    #
378
    Error( "Internal algorithm error: Bad dependancy walk") if ( keys %depends );
379
 
380
#    DebugDumpData ("Order", \@build_order);
381
}
382
 
383
#-------------------------------------------------------------------------------
384
# Function        : cmd
385
#
386
# Description     : Execute a command in all the sandboxes
387
#                       Locate the base of the sandbox
388
#                       Locate all packages in the sandbox
389
#                       Locate all build files in each sandbox
390
#                       Determine build order
391
#                       Issue commands for each sandbox in order
392
#
393
# Inputs          : Arugments passed to jats build
394
#
395
# Returns         : Will exit
396
#
397
sub cmd
398
{
399
    my @cmds = @_;
400
    #
401
    #   Determine Sandbox information
402
    #   Populate global variables
403
    #
404
    calc_sandbox_info();
405
    foreach my $fe ( @build_order )
406
    {
407
        my $dir = $fe->{dir};
408
        Message( "Level:" . $fe->{level} . " Name: " . $fe->{pname} ,
409
                  DisplayPath ("        Path: $fe->{dir}" ));
410
 
411
        my $result = JatsCmd( "-cd=$dir @cmds");
412
        Error ("Cmd faulure") if ( $result );
413
    }
414
 
415
    exit 0;
416
}
417
 
418
#-------------------------------------------------------------------------------
419
# Function        : parse_build_file
420
#
421
# Description     : Parse a build file and extract useful information
422
#
423
#
424
# Inputs          : fe  - Reference to a build entry
425
#
426
# Returns         : Populates data into the build entry
427
#
428
sub process_build_file
429
{
430
    my ($fe) = @_;
431
    Debug ("Processing build file: " . $fe->{dir} );
432
    my $infile =  $fe->{dir} . "/" . $fe->{file};
433
 
434
    #
435
    #   Open the input and output files
436
    #
437
    my $build_info;
438
    my $release_name;
439
    my $release_version;
440
 
441
    open ( INFILE, "<$infile" ) || Error( "Cannot open $infile" );
442
    while ( <INFILE> )
443
    {
444
        next if ( m~^\s*#~ );            # Skip comments
445
        #
446
        #   Process BuildName
447
        #
448
        if ( m~\s*BuildName[\s\(]~ )
449
        {
450
            #   Build names come in many flavours, luckily we have a function
451
            #
452
            m~\(\s*(.*?)\s*\)~;
453
            my @args = split /\s*,\s*/, $1;
454
            my $build_info = parseBuildName( @args );
455
            $fe->{package} = join $;, $build_info->{BUILDNAME_PACKAGE},$build_info->{BUILDNAME_PROJECT};
456
            $fe->{pname}= $build_info->{BUILDNAME};
457
        }
458
 
459
        #
460
        #   Process BuildPkgArchive and LinkPkgArchive
461
        #   Retain the Name and the ProjectSuffix and the version
462
        #
463
        if ( m/^LinkPkgArchive/ or m/^BuildPkgArchive/ )
464
        {
465
            m/['"](.*?)['"][^'"]*['"](.*?)['"]/;
466
 
467
            my ( $package, $rel, $suf, $full ) = SplitPackage( $1, $2 );
468
            $fe->{depends}{$package,$suf} = $rel;
469
        }
470
    }
471
    close INFILE;
472
}
473
 
474
 
475
#-------------------------------------------------------------------------------
476
# Function        : locate_build_files
477
#
478
# Description     : Locate all potential buildfiles in the view
479
#
480
# Inputs          : base_dir     - Start directory
481
#
482
# Returns         : An array of build file entries
483
#                   Each entry in the array is a hash
484
#                       dir =>  Directory to the build files
485
#                       file => Name of the build file
486
#
487
my @located_files;
488
my $locate_files_base;
489
sub locate_build_files
490
{
491
    my ( $base_dir) = @_;
492
 
493
    #
494
    #   Locate build files ( JATS and ANT )
495
    #
496
    sub locate_build_files_wanted
497
    {
498
 
499
        my $dir = "$File::Find::dir";
500
        my $file = $_;
501
        my $arg = "$dir/$file";
502
 
503
        return if ( -d $arg );
504
 
505
        #
506
        #   Detect a JATS build file
507
        #
508
        if ( $file eq "build.pl"  )
509
        {
510
            push @located_files, { 'dir' =>$dir, 'file' => $file };
511
            return;
512
        }
513
 
514
        #
515
        #   Detect ANT {packagename}depends.xml file
516
        #
517
        if ( $file =~ m/(.+)depends.xml$/ )
518
        {
519
            if ( -f $1 . ".xml" )
520
            {
521
                push @located_files, { 'dir' =>$dir, 'file' => $file, 'ant' => $1 . ".xml" };
522
                return;
523
            }
524
        }
525
    }
526
 
527
    @located_files = ();
528
    $locate_files_base = $base_dir;
529
    File::Find::find ( \&locate_build_files_wanted, $base_dir );
530
    return @located_files;
531
}
532
 
533
 
534
#-------------------------------------------------------------------------------
535
#   Documentation
536
#
537
 
538
=pod
539
 
540
=head1 NAME
541
 
542
jats_sandbox - Build in a Development Sandbox
543
 
544
=head1 SYNOPSIS
545
 
546
  jats sandbox [options] [comamnds]
547
 
548
 Options:
549
    -help              - brief help message
550
    -help -help        - Detailed help message
551
    -man               - Full documentation
552
 
553
 Commands:
554
    help                - Same as -help
555
    create              - Create a sandbox in the current directory
556
    info [-v]           - Sandbox information. -v: Be more verbose
557
    cmd                 - Do commands in all sandbox components
558
 
559
=head1 OPTIONS
560
 
561
=over 8
562
 
563
=item B<-help>
564
 
565
Print a brief help message and exits.
566
 
567
=item B<-help -help>
568
 
569
Print a detailed help message with an explanation for each option.
570
 
571
=item B<-man>
572
 
573
Prints the manual page and exits.
574
 
575
=head1 DESCRIPTION
576
 
577
This program is the primary tool for the maintainnace of Development Sandboxes
578
More documentation will follow.
579
 
580
=cut
581