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$~ );
272
        next unless ( -d $pname );
273
        Verbose ("Package discovered: $pname");
275 dpurdie 274
 
275
        if ( -f "$pname/stop" )
276
        {
277
            Warning("Package contains stop file: $pname");
278
            next;
279
        }
280
 
255 dpurdie 281
        push @dirlist, $pname;
227 dpurdie 282
 
283
        #
284
        #   Locate the build files in each package
245 dpurdie 285
        #   Scan the build files and extract dependancy information
227 dpurdie 286
        #
255 dpurdie 287
        my $bscanner = BuildFileScanner( $pname, 'build.pl', '--LocateAll', '--ScanDependencies' );
245 dpurdie 288
        $bscanner->scan();
289
        my @blist = $bscanner->getInfo();
255 dpurdie 290
        Warning ("Package does not have build files: $pname") unless ( @blist );
291
        Warning ("Package has multiple build files: $pname") if ( $#blist > 0 );
245 dpurdie 292
        push @build_list, @blist;
227 dpurdie 293
    }
294
 
295
    #
296
    #   Process each build file and extract
297
    #       Name of the Package
298
    #       Dependency list
299
    #   Build up a hash of dependence information
300
    #
301
 
302
    my %depends;
245 dpurdie 303
    foreach my $be ( @build_list )
227 dpurdie 304
    {
245 dpurdie 305
        Verbose( DisplayPath ("Build file: " . $be->{dir} . " Name: " . $be->{file} ));
306
#        DebugDumpData ("be", $be );
227 dpurdie 307
 
308
        #
309
        #   Add into dependency struct
310
        #
245 dpurdie 311
        $depends{$be->{package}}{depends} = $be->{depends};
312
        $depends{$be->{package}}{entry} = $be;
227 dpurdie 313
    }
314
 
245 dpurdie 315
#DebugDumpData ("depends", \%depends );
316
 
227 dpurdie 317
    #
318
    #   Determine the build order
319
    #
320
    @build_order = ();
321
    my $more = 1;
322
    my $level = 0;
323
 
324
    #
255 dpurdie 325
    #   Remove any dependencies to 'external' packages
227 dpurdie 326
    #   These will not be met internally and can be regarded as constant
327
    #
328
    foreach my $key ( keys %depends )
329
    {
330
        foreach my $build ( keys( %{$depends{$key}{depends}} ))
331
        {
332
            unless (exists $depends{$build})
333
            {
334
                push @{$extern_deps{$build}{$depends{$key}{depends}{$build}}}, $key;
335
                $depends{$key}{entry}{edeps}{$build} = $depends{$key}{depends}{$build};
336
                delete ($depends{$key}{depends}{$build}) ;
337
                Verbose2( "Not in set: $build");
338
            }
339
            else
340
            {
341
                $depends{$key}{entry}{ideps}{$build} = 1;
342
            }
343
        }
344
    }
345
    while ( $more )
346
    {
347
        $more = 0;
348
        $level++;
349
        my @build;
350
 
351
        #
352
        #   Locate packages with no dependencies
353
        #
354
        foreach my $key ( keys %depends )
355
        {
356
            next if ( keys( %{$depends{$key}{depends}} ) );
357
            push @build, $key;
358
        }
359
 
360
        foreach my $build ( @build )
361
        {
362
            $more = 1;
363
            my $fe = $depends{$build}{entry};
364
            $fe->{level} = $level;
365
            $packages{$build} = $fe;
366
            push @build_order, $fe;
367
            delete $depends{$build};
368
            delete $fe->{depends};                          # remove now its not needed
369
        }
370
 
371
        foreach my $key ( keys %depends )
372
        {
373
            foreach my $build ( @build )
374
            {
375
                delete $depends{$key}{depends}{$build};
376
            }
377
        }
378
    }
379
 
380
    #
381
    #   Just to be sure to be sure
382
    #
245 dpurdie 383
    if ( keys %depends )
384
    {
385
        #DebugDumpData ("depends", \%depends );
386
        Error( "Internal algorithm error: Bad dependancy walk",
387
               "Possible circular dependency");
388
    }
227 dpurdie 389
 
390
#    DebugDumpData ("Order", \@build_order);
391
}
392
 
393
#-------------------------------------------------------------------------------
394
# Function        : cmd
395
#
396
# Description     : Execute a command in all the sandboxes
397
#                       Locate the base of the sandbox
398
#                       Locate all packages in the sandbox
399
#                       Locate all build files in each sandbox
400
#                       Determine build order
401
#                       Issue commands for each sandbox in order
402
#
255 dpurdie 403
# Inputs          : Arguments passed to jats build
227 dpurdie 404
#
405
# Returns         : Will exit
406
#
407
sub cmd
408
{
409
    my @cmds = @_;
410
    #
411
    #   Determine Sandbox information
412
    #   Populate global variables
413
    #
414
    calc_sandbox_info();
415
    foreach my $fe ( @build_order )
416
    {
417
        my $dir = $fe->{dir};
255 dpurdie 418
        Message( "Level:" . $fe->{level} . " Name: " . $fe->{mname} ,
227 dpurdie 419
                  DisplayPath ("        Path: $fe->{dir}" ));
420
 
263 dpurdie 421
        my $result = JatsCmd( "-cd=$dir", @cmds);
255 dpurdie 422
        Error ("Cmd failure") if ( $result );
227 dpurdie 423
    }
424
 
425
    exit 0;
426
}
427
 
428
#-------------------------------------------------------------------------------
273 dpurdie 429
# Function        : clean
430
#
431
# Description     : Execute a command in all the sandboxes
432
#                       Locate the base of the sandbox
433
#                       Locate all packages in the sandbox
434
#                       Locate all build files in each sandbox
435
#                       Determine build order
436
#                       Issue commands for each sandbox in order
437
#
438
# Inputs          : Arguments passed to jats build
439
#
440
# Returns         : Will exit
441
#
442
sub clean
443
{
444
    my ($mode, @cmds ) = @_;
445
    #
446
    #   Determine Sandbox information
447
    #   Populate global variables
448
    #
449
    calc_sandbox_info();
450
 
451
    my @cmd = $mode eq 'clobber' ? ('clobber') : ('make', 'clean' );
452
 
453
    #
454
    #   Clobber and clean need to be done in the reverse order
455
    #
456
    foreach my $fe ( reverse @build_order )
457
    {
458
        my $dir = $fe->{dir};
459
        Message( "Level:" . $fe->{level} . " Name: " . $fe->{mname} ,
460
                  DisplayPath ("        Path: $fe->{dir}" ));
461
 
462
        my $result = JatsCmd( "-cd=$dir", @cmd, @cmds);
463
        Error ("Cmd failure") if ( $result );
464
    }
465
 
466
    exit 0;
467
}
468
 
469
 
470
#-------------------------------------------------------------------------------
227 dpurdie 471
#   Documentation
472
#
473
 
474
=pod
475
 
476
=head1 NAME
477
 
478
jats_sandbox - Build in a Development Sandbox
479
 
480
=head1 SYNOPSIS
481
 
255 dpurdie 482
  jats sandbox [options] [commands]
227 dpurdie 483
 
484
 Options:
485
    -help              - brief help message
486
    -help -help        - Detailed help message
487
    -man               - Full documentation
488
 
489
 Commands:
490
    help                - Same as -help
491
    create              - Create a sandbox in the current directory
255 dpurdie 492
    info [[-v]-v]       - Sandbox information. -v: Be more verbose
227 dpurdie 493
    cmd                 - Do commands in all sandbox components
275 dpurdie 494
    all                 - Do 'build and make' in all sandbox components
495
    build               - Do 'build' in all sandbox components
496
    make                - Do 'make' in all sandbox components
273 dpurdie 497
    clean               - Do 'make clean' in all sandbox components
498
    clobber             - Do 'build clobber' is all sandbox components
227 dpurdie 499
 
500
=head1 OPTIONS
501
 
502
=over 8
503
 
504
=item B<-help>
505
 
506
Print a brief help message and exits.
507
 
508
=item B<-help -help>
509
 
510
Print a detailed help message with an explanation for each option.
511
 
512
=item B<-man>
513
 
514
Prints the manual page and exits.
515
 
279 dpurdie 516
=back
517
 
227 dpurdie 518
=head1 DESCRIPTION
519
 
255 dpurdie 520
This program is the primary tool for the maintenance of Development Sandboxes
227 dpurdie 521
More documentation will follow.
522
 
279 dpurdie 523
=head2 SANDBOX DIRECTORY
524
 
525
The sandbox directory is marked as being a sandbox through the use of the '
526
sandbox create' command. This will create a suitable structure within the
527
current directory.
528
 
529
Several JATS commands operate differently within a sandbox. The 'extract' and
530
'release' commands will create static viwes within the sandbox and not the
531
normal directory. The 'sandbox' sub commands can only be used within a sandbox.
532
 
533
The sandbox directory contains sub directories, each should contain a single
534
package. Sub directories may be created with the 'jats extract' command.
535
 
536
Note: Symbolic links are not supported. They cannot work as he sandbox mechanism
537
requires that all the packages be conatined within a sub directory tree so
538
that the root of the sandbox can be located by a simple scan of the directory
539
tree.
540
 
541
If a package subdirectory contains a file called 'stop', then that package
542
will not be considered as a part of the build-set.
543
 
227 dpurdie 544
=cut
545
 
255 dpurdie 546