Subversion Repositories DevTools

Rev

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

Rev Author Line No. Line
227 dpurdie 1
########################################################################
263 dpurdie 2
# Copyright (C) 2008 ERG Limited, All rights reserved
227 dpurdie 3
#
263 dpurdie 4
# Module name   : jats_sandbox.pl
5
# Module type   : JATS Utility
6
# Compiler(s)   : Perl
7
# Environment(s): JATS
227 dpurdie 8
#
9
# Description   : A script to build a collection of packages in the
10
#                 same sandbox. This script will:
11
#
12
#                   Determine the packages in the sandbox
13
#                   Determine the build order of the packages
14
#                   Build the packages in the correct order
15
#                   Make the packages in the correct order
16
#
17
#                 The script will allow for:
18
#                   The creation of a sandbox
19
#                   The addition of packages to the sandbox
20
#                   Removal of packages from the sandbox
21
#
22
#
23
#                 Command syntax (basic)
24
#                   jats sandbox <command> (options | actions)@
25
#
26
#                 Commands include:
27
#                   create              - Create a sandbox
28
#                   delete              - Delete a sandbox
29
#
30
#                   add package_name    - Add a package to the sandbox
31
#                   rm  package_name    - Remove a package from the sandbox
32
#
33
#                   build               - Build all packages in the sandbox
34
#                   make                - make all packages in the sandbox
35
#
36
#......................................................................#
37
 
263 dpurdie 38
require 5.008_002;
227 dpurdie 39
use strict;
40
use warnings;
41
use JatsError;
42
use JatsSystem;
43
use FileUtils;
245 dpurdie 44
use JatsBuildFiles;
227 dpurdie 45
use JatsVersionUtils;
46
 
47
 
48
use Pod::Usage;                             # required for help support
49
use Getopt::Long qw(:config require_order); # Stop on non-option
50
my $VERSION = "1.0.0";                      # Update this
51
 
52
#
53
#   Options
54
#
55
my $opt_debug   = $ENV{'GBE_DEBUG'};        # Allow global debug
56
my $opt_verbose = $ENV{'GBE_VERBOSE'};      # Allow global verbose
57
my $opt_help = 0;
58
my $opt_manual = 0;
59
 
60
#
61
#   Globals - Provided by the JATS environment
62
#
63
my $USER         = $ENV{'USER'};
64
my $UNIX         = $ENV{'GBE_UNIX'};
65
my $HOME         = $ENV{'HOME'};
66
my $GBE_SANDBOX  = $ENV{'GBE_SANDBOX'};
67
my $GBE_DPKG_SBOX= $ENV{'GBE_DPKG_SBOX'};
68
 
69
#
70
#   Globals
71
#
72
my @build_order = ();                     # Build Ordered list of entries
255 dpurdie 73
my %extern_deps;                          # Hash of external dependencies
227 dpurdie 74
my %packages;                             # Hash of packages
75
 
76
 
77
#-------------------------------------------------------------------------------
78
# Function        : Mainline Entry Point
79
#
80
# Description     :
81
#
82
# Inputs          :
83
#
84
my $result = GetOptions (
85
                "help+"         => \$opt_help,              # flag, multiple use allowed
86
                "manual"        => \$opt_manual,            # flag, multiple use allowed
87
                "verbose+"      => \$opt_verbose,           # flag, multiple use allowed
88
                );
89
 
90
                #
91
                #   UPDATE THE DOCUMENTATION AT THE END OF THIS FILE !!!
92
                #
93
 
94
#
95
#   Process help and manual options
96
#
97
pod2usage(-verbose => 0, -message => "Version: $VERSION")  if ($opt_help == 1  || ! $result);
98
pod2usage(-verbose => 1)  if ($opt_help == 2 );
99
pod2usage(-verbose => 2)  if ($opt_manual || ($opt_help > 2));
100
 
101
#
102
#   Configure the error reporting process now that we have the user options
103
#
104
ErrorConfig( 'name'    => 'SANDBOX',
105
             'verbose' => $opt_verbose );
106
 
107
#
108
#   Validate user options
109
#
110
 
111
#
112
#   Parse the user command and decide what to do
113
#
114
#
115
my $cmd = shift @ARGV || "";
116
help(1)                                 if ( $cmd =~ m/^help$/ || $cmd eq "" );
117
create_sandbox()                        if ( $cmd =~ m/^create$/ );
118
info(@ARGV)                             if ( $cmd =~ m/^info$/ );
119
cmd(@ARGV)                              if ( $cmd =~ m/^cmd$/ );
275 dpurdie 120
cmd($cmd, @ARGV )                       if ( $cmd =~ m/(^all$)|(^build$)|(^make$)/  );
273 dpurdie 121
clean($cmd, @ARGV)                      if ( $cmd =~ m/(^clobber$)|(^clean$)/  );
227 dpurdie 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
    {
245 dpurdie 191
        Message( "    Level:" . $fe->{level} . " Name: " . $fe->{mname} );
227 dpurdie 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
 
255 dpurdie 212
    Message("External Dependencies");
227 dpurdie 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;
255 dpurdie 268
    foreach my $pname ( glob("*") )
227 dpurdie 269
    {
255 dpurdie 270
        next if ( $pname =~ m~^\.~ );
271
        next if ( $pname =~ m~dpkg_archive$~ );
297 dpurdie 272
        next if ( $pname =~ m~^CVS$~ );
255 dpurdie 273
        next unless ( -d $pname );
274
        Verbose ("Package discovered: $pname");
275 dpurdie 275
 
276
        if ( -f "$pname/stop" )
277
        {
278
            Warning("Package contains stop file: $pname");
279
            next;
280
        }
281
 
255 dpurdie 282
        push @dirlist, $pname;
227 dpurdie 283
 
284
        #
285
        #   Locate the build files in each package
245 dpurdie 286
        #   Scan the build files and extract dependancy information
227 dpurdie 287
        #
255 dpurdie 288
        my $bscanner = BuildFileScanner( $pname, 'build.pl', '--LocateAll', '--ScanDependencies' );
245 dpurdie 289
        $bscanner->scan();
290
        my @blist = $bscanner->getInfo();
255 dpurdie 291
        Warning ("Package does not have build files: $pname") unless ( @blist );
292
        Warning ("Package has multiple build files: $pname") if ( $#blist > 0 );
245 dpurdie 293
        push @build_list, @blist;
227 dpurdie 294
    }
295
 
296
    #
297
    #   Process each build file and extract
298
    #       Name of the Package
299
    #       Dependency list
300
    #   Build up a hash of dependence information
301
    #
302
 
303
    my %depends;
245 dpurdie 304
    foreach my $be ( @build_list )
227 dpurdie 305
    {
245 dpurdie 306
        Verbose( DisplayPath ("Build file: " . $be->{dir} . " Name: " . $be->{file} ));
307
#        DebugDumpData ("be", $be );
227 dpurdie 308
 
309
        #
310
        #   Add into dependency struct
311
        #
245 dpurdie 312
        $depends{$be->{package}}{depends} = $be->{depends};
313
        $depends{$be->{package}}{entry} = $be;
227 dpurdie 314
    }
315
 
245 dpurdie 316
#DebugDumpData ("depends", \%depends );
317
 
227 dpurdie 318
    #
319
    #   Determine the build order
320
    #
321
    @build_order = ();
322
    my $more = 1;
323
    my $level = 0;
324
 
325
    #
255 dpurdie 326
    #   Remove any dependencies to 'external' packages
227 dpurdie 327
    #   These will not be met internally and can be regarded as constant
328
    #
329
    foreach my $key ( keys %depends )
330
    {
331
        foreach my $build ( keys( %{$depends{$key}{depends}} ))
332
        {
333
            unless (exists $depends{$build})
334
            {
335
                push @{$extern_deps{$build}{$depends{$key}{depends}{$build}}}, $key;
336
                $depends{$key}{entry}{edeps}{$build} = $depends{$key}{depends}{$build};
337
                delete ($depends{$key}{depends}{$build}) ;
338
                Verbose2( "Not in set: $build");
339
            }
340
            else
341
            {
342
                $depends{$key}{entry}{ideps}{$build} = 1;
343
            }
344
        }
345
    }
346
    while ( $more )
347
    {
348
        $more = 0;
349
        $level++;
350
        my @build;
351
 
352
        #
353
        #   Locate packages with no dependencies
354
        #
355
        foreach my $key ( keys %depends )
356
        {
357
            next if ( keys( %{$depends{$key}{depends}} ) );
358
            push @build, $key;
359
        }
360
 
361
        foreach my $build ( @build )
362
        {
363
            $more = 1;
364
            my $fe = $depends{$build}{entry};
365
            $fe->{level} = $level;
366
            $packages{$build} = $fe;
367
            push @build_order, $fe;
368
            delete $depends{$build};
369
            delete $fe->{depends};                          # remove now its not needed
370
        }
371
 
372
        foreach my $key ( keys %depends )
373
        {
374
            foreach my $build ( @build )
375
            {
376
                delete $depends{$key}{depends}{$build};
377
            }
378
        }
379
    }
380
 
381
    #
382
    #   Just to be sure to be sure
383
    #
245 dpurdie 384
    if ( keys %depends )
385
    {
386
        #DebugDumpData ("depends", \%depends );
387
        Error( "Internal algorithm error: Bad dependancy walk",
388
               "Possible circular dependency");
389
    }
227 dpurdie 390
 
391
#    DebugDumpData ("Order", \@build_order);
392
}
393
 
394
#-------------------------------------------------------------------------------
395
# Function        : cmd
396
#
397
# Description     : Execute a command in all the sandboxes
398
#                       Locate the base of the sandbox
399
#                       Locate all packages in the sandbox
400
#                       Locate all build files in each sandbox
401
#                       Determine build order
402
#                       Issue commands for each sandbox in order
403
#
255 dpurdie 404
# Inputs          : Arguments passed to jats build
227 dpurdie 405
#
406
# Returns         : Will exit
407
#
408
sub cmd
409
{
410
    my @cmds = @_;
411
    #
412
    #   Determine Sandbox information
413
    #   Populate global variables
414
    #
415
    calc_sandbox_info();
416
    foreach my $fe ( @build_order )
417
    {
418
        my $dir = $fe->{dir};
255 dpurdie 419
        Message( "Level:" . $fe->{level} . " Name: " . $fe->{mname} ,
227 dpurdie 420
                  DisplayPath ("        Path: $fe->{dir}" ));
421
 
263 dpurdie 422
        my $result = JatsCmd( "-cd=$dir", @cmds);
255 dpurdie 423
        Error ("Cmd failure") if ( $result );
227 dpurdie 424
    }
425
 
426
    exit 0;
427
}
428
 
429
#-------------------------------------------------------------------------------
273 dpurdie 430
# Function        : clean
431
#
432
# Description     : Execute a command in all the sandboxes
433
#                       Locate the base of the sandbox
434
#                       Locate all packages in the sandbox
435
#                       Locate all build files in each sandbox
436
#                       Determine build order
437
#                       Issue commands for each sandbox in order
438
#
439
# Inputs          : Arguments passed to jats build
440
#
441
# Returns         : Will exit
442
#
443
sub clean
444
{
445
    my ($mode, @cmds ) = @_;
446
    #
447
    #   Determine Sandbox information
448
    #   Populate global variables
449
    #
450
    calc_sandbox_info();
451
 
452
    my @cmd = $mode eq 'clobber' ? ('clobber') : ('make', 'clean' );
453
 
454
    #
455
    #   Clobber and clean need to be done in the reverse order
456
    #
457
    foreach my $fe ( reverse @build_order )
458
    {
459
        my $dir = $fe->{dir};
460
        Message( "Level:" . $fe->{level} . " Name: " . $fe->{mname} ,
461
                  DisplayPath ("        Path: $fe->{dir}" ));
462
 
463
        my $result = JatsCmd( "-cd=$dir", @cmd, @cmds);
464
        Error ("Cmd failure") if ( $result );
465
    }
466
 
467
    exit 0;
468
}
469
 
470
 
471
#-------------------------------------------------------------------------------
227 dpurdie 472
#   Documentation
473
#
474
 
475
=pod
476
 
477
=head1 NAME
478
 
479
jats_sandbox - Build in a Development Sandbox
480
 
481
=head1 SYNOPSIS
482
 
255 dpurdie 483
  jats sandbox [options] [commands]
227 dpurdie 484
 
485
 Options:
486
    -help              - brief help message
487
    -help -help        - Detailed help message
488
    -man               - Full documentation
489
 
490
 Commands:
491
    help                - Same as -help
492
    create              - Create a sandbox in the current directory
255 dpurdie 493
    info [[-v]-v]       - Sandbox information. -v: Be more verbose
227 dpurdie 494
    cmd                 - Do commands in all sandbox components
275 dpurdie 495
    all                 - Do 'build and make' in all sandbox components
496
    build               - Do 'build' in all sandbox components
497
    make                - Do 'make' in all sandbox components
273 dpurdie 498
    clean               - Do 'make clean' in all sandbox components
499
    clobber             - Do 'build clobber' is all sandbox components
227 dpurdie 500
 
501
=head1 OPTIONS
502
 
503
=over 8
504
 
505
=item B<-help>
506
 
507
Print a brief help message and exits.
508
 
509
=item B<-help -help>
510
 
511
Print a detailed help message with an explanation for each option.
512
 
513
=item B<-man>
514
 
515
Prints the manual page and exits.
516
 
279 dpurdie 517
=back
518
 
227 dpurdie 519
=head1 DESCRIPTION
520
 
255 dpurdie 521
This program is the primary tool for the maintenance of Development Sandboxes
227 dpurdie 522
More documentation will follow.
523
 
279 dpurdie 524
=head2 SANDBOX DIRECTORY
525
 
526
The sandbox directory is marked as being a sandbox through the use of the '
527
sandbox create' command. This will create a suitable structure within the
528
current directory.
529
 
530
Several JATS commands operate differently within a sandbox. The 'extract' and
531
'release' commands will create static viwes within the sandbox and not the
532
normal directory. The 'sandbox' sub commands can only be used within a sandbox.
533
 
534
The sandbox directory contains sub directories, each should contain a single
535
package. Sub directories may be created with the 'jats extract' command.
536
 
537
Note: Symbolic links are not supported. They cannot work as he sandbox mechanism
538
requires that all the packages be conatined within a sub directory tree so
539
that the root of the sandbox can be located by a simple scan of the directory
540
tree.
541
 
542
If a package subdirectory contains a file called 'stop', then that package
543
will not be considered as a part of the build-set.
544
 
227 dpurdie 545
=cut
546
 
255 dpurdie 547