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;
299 dpurdie 46
use File::Path qw(rmtree);
227 dpurdie 47
 
48
 
49
use Pod::Usage;                             # required for help support
50
use Getopt::Long qw(:config require_order); # Stop on non-option
51
my $VERSION = "1.0.0";                      # Update this
52
 
53
#
54
#   Options
55
#
56
my $opt_debug   = $ENV{'GBE_DEBUG'};        # Allow global debug
57
my $opt_verbose = $ENV{'GBE_VERBOSE'};      # Allow global verbose
58
my $opt_help = 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'};
325 dpurdie 68
my $GBE_MACHTYPE = $ENV{'GBE_MACHTYPE'};
227 dpurdie 69
 
70
#
71
#   Globals
72
#
73
my @build_order = ();                     # Build Ordered list of entries
255 dpurdie 74
my %extern_deps;                          # Hash of external dependencies
227 dpurdie 75
my %packages;                             # Hash of packages
76
 
77
 
78
#-------------------------------------------------------------------------------
79
# Function        : Mainline Entry Point
80
#
81
# Description     :
82
#
83
# Inputs          :
84
#
85
my $result = GetOptions (
299 dpurdie 86
                "help|h:+"      => \$opt_help,
87
                "manual:3"      => \$opt_help,
227 dpurdie 88
                "verbose+"      => \$opt_verbose,           # flag, multiple use allowed
89
                );
90
 
91
                #
92
                #   UPDATE THE DOCUMENTATION AT THE END OF THIS FILE !!!
93
                #
94
 
95
#
96
#   Process help and manual options
97
#
98
pod2usage(-verbose => 0, -message => "Version: $VERSION")  if ($opt_help == 1  || ! $result);
99
pod2usage(-verbose => 1)  if ($opt_help == 2 );
299 dpurdie 100
pod2usage(-verbose => 2)  if ($opt_help > 2 );
227 dpurdie 101
 
102
#
103
#   Configure the error reporting process now that we have the user options
104
#
105
ErrorConfig( 'name'    => 'SANDBOX',
106
             'verbose' => $opt_verbose );
107
 
108
#
109
#   Validate user options
110
#
111
 
112
#
113
#   Parse the user command and decide what to do
114
#
115
#
116
my $cmd = shift @ARGV || "";
117
help(1)                                 if ( $cmd =~ m/^help$/ || $cmd eq "" );
299 dpurdie 118
delete_sandbox()                        if ( $cmd =~ m/^delete$/ );
227 dpurdie 119
create_sandbox()                        if ( $cmd =~ m/^create$/ );
120
info(@ARGV)                             if ( $cmd =~ m/^info$/ );
121
cmd(@ARGV)                              if ( $cmd =~ m/^cmd$/ );
275 dpurdie 122
cmd($cmd, @ARGV )                       if ( $cmd =~ m/(^all$)|(^build$)|(^make$)/  );
273 dpurdie 123
clean($cmd, @ARGV)                      if ( $cmd =~ m/(^clobber$)|(^clean$)/  );
227 dpurdie 124
 
125
Error ("Unknown sandbox command: $cmd");
126
exit 1;
127
 
128
 
129
#-------------------------------------------------------------------------------
130
#
131
#   Give the user a clue
132
#
133
sub help
134
{
135
    my ($level) = @_;
136
    $level = $opt_help unless ( $level );
137
 
138
    pod2usage(-verbose => 0, -message => "Version: ". $VERSION)  if ($level == 1 );
139
    pod2usage(-verbose => $level -1 );
140
}
141
 
142
#-------------------------------------------------------------------------------
143
# Function        : create_sandbox
144
#
145
# Description     : create a sandbox in the current current directory
146
#
147
# Inputs          : None
148
#
149
#
150
sub create_sandbox
151
{
152
    Error ("Cannot create a sandbox within a sandbox",
153
           "Sandbox base is: $GBE_SANDBOX" ) if ( $GBE_SANDBOX );
154
    mkdir ('sandbox_dpkg_archive') || Error ("Cannot create the directory: sandbox_dpkg_archive") ;
155
    exit  0;
156
}
157
 
158
#-------------------------------------------------------------------------------
299 dpurdie 159
# Function        : delete_sandbox
160
#
161
# Description     : Delete a sandbox
162
#                   Its up to the user the delete the components in the sandbox
163
#
164
# Inputs          : None
165
#
166
# Returns         : 
167
#
168
sub delete_sandbox
169
{
170
    unless ( $GBE_SANDBOX )
171
    {
172
        Warning("No sandbox found to delete");
173
    }
174
    else
175
    {
176
        my $sdir = "$GBE_SANDBOX/sandbox_dpkg_archive";
177
        rmtree($sdir,0,0);
178
        Error ("Sandbox directory not completly removed")
179
            if ( -e $sdir );
180
 
181
        Message("Sandbox information deleted",
182
                "Sandbox components must be manually deleted");
183
    }
184
    exit 0;
185
}
186
 
187
#-------------------------------------------------------------------------------
227 dpurdie 188
# Function        : info
189
#
190
# Description     : Display Sandbox information
191
#
192
# Inputs          : Command line args
193
#                   -v  - Be more verbose
194
#
195
# Returns         : Will exit
196
#
197
sub info
198
{
199
    #
200
    #   Allow user to specify verboseness as an argument
201
    #
202
    foreach  ( @_ )
203
    {
204
        $opt_verbose++ if ( m/^-v/ )
205
    }
206
 
207
    #
208
    #   Determine Sandbox information
209
    #   Populate global variables
210
    #
211
    calc_sandbox_info();
212
 
213
    #
214
    #   Display information
215
    #
216
    Message ("Base: $GBE_SANDBOX");
217
    Message ("Archive: $GBE_DPKG_SBOX");
218
 
219
    Message ("Build Order");
220
    foreach my $fe ( @build_order )
221
    {
245 dpurdie 222
        Message( "    Level:" . $fe->{level} . " Name: " . $fe->{mname} );
227 dpurdie 223
        Message( DisplayPath ("        Path: $fe->{dir}" )) if $opt_verbose;
224
 
225
        if ( $opt_verbose )
226
        {
227
            foreach my $idep ( sort keys %{$fe->{ideps}} )
228
            {
229
                my ($ppn,$pps) = split( $; , $idep);
230
                Message ("        I:$ppn.$pps");
231
            }
232
 
233
            foreach my $edep ( sort keys %{$fe->{edeps}} )
234
            {
235
                my ($ppn,$pps) = split( $; , $edep);
236
                my $pv = $fe->{edeps}{$edep};
237
                Message ("        E:$ppn $pv.$pps");
238
            }
239
 
240
        }
241
    }
242
 
255 dpurdie 243
    Message("External Dependencies");
227 dpurdie 244
    foreach my $de ( sort keys %extern_deps )
245
    {
246
        my ($pn,$ps) = split( $; , $de);
247
        my @vlist = keys %{$extern_deps{$de}};
248
        my $flag = $#vlist ? '*' : ' ';
249
        foreach my $pv ( @vlist )
250
        {
251
            Message ("   $flag$pn $pv.$ps");
252
            if ( $opt_verbose )
253
            {
254
                foreach my $pkg ( @{$extern_deps{$de}{$pv}} )
255
                {
256
                    my ($ppn,$pps) = split( $; , $pkg);
257
                    Message ("        U:$ppn.$pps");
258
 
259
                }
260
            }
261
        }
262
    }
263
 
264
    if ( $opt_verbose > 2 )
265
    {
266
        DebugDumpData( "extern_deps", \%extern_deps);
267
        DebugDumpData( "build_order", \@build_order);
268
        DebugDumpData( "packages", \%packages);
269
    }
270
    exit (0);
271
}
272
 
273
#-------------------------------------------------------------------------------
274
# Function        : calc_sandbox_info
275
#
276
# Description     : Examine the sandbox and determine all the important
277
#                   information
278
#
279
# Inputs          : None
280
#
281
# Returns         : Will exit if not in a sandbox
282
#                   Populates global variables
283
#                       @build_order - build ordered array of build entries
284
#
285
sub calc_sandbox_info
286
{
287
    #
288
    #   Start from the root of the sandbox
289
    #
290
    Error ("Command must be executed from within a Sandbox") unless ( $GBE_SANDBOX );
291
    chdir ($GBE_SANDBOX) || Error ("Cannot chdir to $GBE_SANDBOX");
292
 
293
    #
294
    #   Locate all packages within the sandbox
295
    #   These will be top-level directories - one per package
296
    #
297
    my @dirlist;
298
    my @build_list;
255 dpurdie 299
    foreach my $pname ( glob("*") )
227 dpurdie 300
    {
255 dpurdie 301
        next if ( $pname =~ m~^\.~ );
302
        next if ( $pname =~ m~dpkg_archive$~ );
297 dpurdie 303
        next if ( $pname =~ m~^CVS$~ );
255 dpurdie 304
        next unless ( -d $pname );
305
        Verbose ("Package discovered: $pname");
275 dpurdie 306
 
325 dpurdie 307
        if ( -f "$pname/stop" || -f "$pname/stop.$GBE_MACHTYPE" )
275 dpurdie 308
        {
309
            Warning("Package contains stop file: $pname");
310
            next;
311
        }
312
 
255 dpurdie 313
        push @dirlist, $pname;
227 dpurdie 314
 
315
        #
316
        #   Locate the build files in each package
245 dpurdie 317
        #   Scan the build files and extract dependancy information
227 dpurdie 318
        #
255 dpurdie 319
        my $bscanner = BuildFileScanner( $pname, 'build.pl', '--LocateAll', '--ScanDependencies' );
245 dpurdie 320
        $bscanner->scan();
321
        my @blist = $bscanner->getInfo();
255 dpurdie 322
        Warning ("Package does not have build files: $pname") unless ( @blist );
323
        Warning ("Package has multiple build files: $pname") if ( $#blist > 0 );
245 dpurdie 324
        push @build_list, @blist;
227 dpurdie 325
    }
326
 
327
    #
328
    #   Process each build file and extract
329
    #       Name of the Package
330
    #       Dependency list
331
    #   Build up a hash of dependence information
332
    #
333
 
334
    my %depends;
299 dpurdie 335
    my %multi;
245 dpurdie 336
    foreach my $be ( @build_list )
227 dpurdie 337
    {
245 dpurdie 338
        Verbose( DisplayPath ("Build file: " . $be->{dir} . " Name: " . $be->{file} ));
339
#        DebugDumpData ("be", $be );
227 dpurdie 340
 
341
        #
299 dpurdie 342
        #   Catch multiple builds for the same package
343
        #   Report later - when we have all
344
        #
321 dpurdie 345
        next unless ( $be->{mname} );
299 dpurdie 346
        push @{$multi{$be->{mname}}},$be->{dir};
347
 
348
        #
227 dpurdie 349
        #   Add into dependency struct
350
        #
245 dpurdie 351
        $depends{$be->{package}}{depends} = $be->{depends};
352
        $depends{$be->{package}}{entry} = $be;
227 dpurdie 353
    }
354
 
299 dpurdie 355
    foreach my $mname ( sort keys %multi )
356
    {
357
        ReportError ("Mutiple builders for : $mname", @{$multi{$mname}} )
358
            if ( scalar @{$multi{$mname}} > 1 );
359
    }
360
    ErrorDoExit();
361
 
245 dpurdie 362
#DebugDumpData ("depends", \%depends );
363
 
227 dpurdie 364
    #
365
    #   Determine the build order
366
    #
367
    @build_order = ();
368
    my $more = 1;
369
    my $level = 0;
370
 
371
    #
255 dpurdie 372
    #   Remove any dependencies to 'external' packages
227 dpurdie 373
    #   These will not be met internally and can be regarded as constant
374
    #
375
    foreach my $key ( keys %depends )
376
    {
377
        foreach my $build ( keys( %{$depends{$key}{depends}} ))
378
        {
379
            unless (exists $depends{$build})
380
            {
381
                push @{$extern_deps{$build}{$depends{$key}{depends}{$build}}}, $key;
382
                $depends{$key}{entry}{edeps}{$build} = $depends{$key}{depends}{$build};
383
                delete ($depends{$key}{depends}{$build}) ;
384
                Verbose2( "Not in set: $build");
385
            }
386
            else
387
            {
388
                $depends{$key}{entry}{ideps}{$build} = 1;
389
            }
390
        }
391
    }
392
    while ( $more )
393
    {
394
        $more = 0;
395
        $level++;
396
        my @build;
397
 
398
        #
399
        #   Locate packages with no dependencies
400
        #
401
        foreach my $key ( keys %depends )
402
        {
403
            next if ( keys( %{$depends{$key}{depends}} ) );
404
            push @build, $key;
405
        }
406
 
407
        foreach my $build ( @build )
408
        {
409
            $more = 1;
410
            my $fe = $depends{$build}{entry};
411
            $fe->{level} = $level;
412
            $packages{$build} = $fe;
413
            push @build_order, $fe;
414
            delete $depends{$build};
415
            delete $fe->{depends};                          # remove now its not needed
416
        }
417
 
418
        foreach my $key ( keys %depends )
419
        {
420
            foreach my $build ( @build )
421
            {
422
                delete $depends{$key}{depends}{$build};
423
            }
424
        }
425
    }
426
 
427
    #
428
    #   Just to be sure to be sure
429
    #
245 dpurdie 430
    if ( keys %depends )
431
    {
432
        #DebugDumpData ("depends", \%depends );
433
        Error( "Internal algorithm error: Bad dependancy walk",
434
               "Possible circular dependency");
435
    }
227 dpurdie 436
 
437
#    DebugDumpData ("Order", \@build_order);
438
}
439
 
440
#-------------------------------------------------------------------------------
441
# Function        : cmd
442
#
443
# Description     : Execute a command in all the sandboxes
444
#                       Locate the base of the sandbox
445
#                       Locate all packages in the sandbox
446
#                       Locate all build files in each sandbox
447
#                       Determine build order
448
#                       Issue commands for each sandbox in order
449
#
255 dpurdie 450
# Inputs          : Arguments passed to jats build
227 dpurdie 451
#
452
# Returns         : Will exit
453
#
454
sub cmd
455
{
456
    my @cmds = @_;
457
    #
458
    #   Determine Sandbox information
459
    #   Populate global variables
460
    #
461
    calc_sandbox_info();
462
    foreach my $fe ( @build_order )
463
    {
464
        my $dir = $fe->{dir};
255 dpurdie 465
        Message( "Level:" . $fe->{level} . " Name: " . $fe->{mname} ,
227 dpurdie 466
                  DisplayPath ("        Path: $fe->{dir}" ));
467
 
263 dpurdie 468
        my $result = JatsCmd( "-cd=$dir", @cmds);
255 dpurdie 469
        Error ("Cmd failure") if ( $result );
227 dpurdie 470
    }
471
 
472
    exit 0;
473
}
474
 
475
#-------------------------------------------------------------------------------
273 dpurdie 476
# Function        : clean
477
#
478
# Description     : Execute a command in all the sandboxes
479
#                       Locate the base of the sandbox
480
#                       Locate all packages in the sandbox
481
#                       Locate all build files in each sandbox
482
#                       Determine build order
483
#                       Issue commands for each sandbox in order
484
#
485
# Inputs          : Arguments passed to jats build
486
#
487
# Returns         : Will exit
488
#
489
sub clean
490
{
491
    my ($mode, @cmds ) = @_;
492
    #
493
    #   Determine Sandbox information
494
    #   Populate global variables
495
    #
496
    calc_sandbox_info();
497
 
498
    my @cmd = $mode eq 'clobber' ? ('clobber') : ('make', 'clean' );
499
 
500
    #
501
    #   Clobber and clean need to be done in the reverse order
502
    #
503
    foreach my $fe ( reverse @build_order )
504
    {
505
        my $dir = $fe->{dir};
506
        Message( "Level:" . $fe->{level} . " Name: " . $fe->{mname} ,
507
                  DisplayPath ("        Path: $fe->{dir}" ));
508
 
509
        my $result = JatsCmd( "-cd=$dir", @cmd, @cmds);
510
        Error ("Cmd failure") if ( $result );
511
    }
512
 
513
    exit 0;
514
}
515
 
516
 
517
#-------------------------------------------------------------------------------
227 dpurdie 518
#   Documentation
519
#
520
 
521
=pod
522
 
523
=head1 NAME
524
 
525
jats_sandbox - Build in a Development Sandbox
526
 
527
=head1 SYNOPSIS
528
 
255 dpurdie 529
  jats sandbox [options] [commands]
227 dpurdie 530
 
531
 Options:
299 dpurdie 532
    -help[=n]          - Display help with specified detail
227 dpurdie 533
    -help -help        - Detailed help message
534
    -man               - Full documentation
535
 
536
 Commands:
537
    help                - Same as -help
538
    create              - Create a sandbox in the current directory
299 dpurdie 539
    delete              - Delete the sandbox
255 dpurdie 540
    info [[-v]-v]       - Sandbox information. -v: Be more verbose
227 dpurdie 541
    cmd                 - Do commands in all sandbox components
275 dpurdie 542
    all                 - Do 'build and make' in all sandbox components
543
    build               - Do 'build' in all sandbox components
544
    make                - Do 'make' in all sandbox components
273 dpurdie 545
    clean               - Do 'make clean' in all sandbox components
546
    clobber             - Do 'build clobber' is all sandbox components
227 dpurdie 547
 
548
=head1 OPTIONS
549
 
550
=over 8
551
 
299 dpurdie 552
=item B<-help[=n]>
227 dpurdie 553
 
554
Print a brief help message and exits.
299 dpurdie 555
There are three levels of help
227 dpurdie 556
 
299 dpurdie 557
=over 8
558
 
559
=item   1 Brief synopsis
560
 
561
=item   2 Synopsis and option summary
562
 
563
=item   3 Detailed help in man format
564
 
565
=back 8
566
 
227 dpurdie 567
=item B<-help -help>
568
 
569
Print a detailed help message with an explanation for each option.
570
 
571
=item B<-man>
572
 
299 dpurdie 573
Prints the manual page and exits. This is the same a -help=3
227 dpurdie 574
 
279 dpurdie 575
=back
576
 
227 dpurdie 577
=head1 DESCRIPTION
578
 
299 dpurdie 579
This program is the primary tool for the maintenance of Development Sandboxes.
580
 
227 dpurdie 581
More documentation will follow.
582
 
279 dpurdie 583
=head2 SANDBOX DIRECTORY
584
 
299 dpurdie 585
The sandbox directory is marked as being a sandbox through the use of the
586
'sandbox create' command. This will create a suitable structure within the
279 dpurdie 587
current directory.
588
 
589
Several JATS commands operate differently within a sandbox. The 'extract' and
590
'release' commands will create static viwes within the sandbox and not the
591
normal directory. The 'sandbox' sub commands can only be used within a sandbox.
592
 
593
The sandbox directory contains sub directories, each should contain a single
594
package. Sub directories may be created with the 'jats extract' command.
595
 
596
Note: Symbolic links are not supported. They cannot work as he sandbox mechanism
597
requires that all the packages be conatined within a sub directory tree so
598
that the root of the sandbox can be located by a simple scan of the directory
599
tree.
600
 
325 dpurdie 601
If a package subdirectory contains a file called 'stop' or 'stop.
602
<GBE_MACHTYPE>', then that package will not be considered as a part of the
603
build-set. A 'stop' file will prevent consideration all build platforms. The 'stop.
604
<GBE_MACHTYPE>' will only prevent consideration if being built on a GBE_MACHTYPE
605
type of computer.
279 dpurdie 606
 
299 dpurdie 607
=head2 COMMAND SUMMARY
608
 
609
=head3 create
610
 
611
The 'create' command will create a sandbox in the users current directory. It is
612
not possible to create a sandbox within a sandbox.
613
 
614
A sandbox can be created in a directory that contains files and subdirectories.
615
 
616
The create command simply places a known directory in the current directory.
617
This dorectory is used by the sandboxing process. It may be manually deleted, or
618
deleted with the 'delete' command.
619
 
620
=head3 delete
621
 
622
The 'delete' command will delete the sandbox's marker directory. The command may
623
be executed anywhere within the sandbox.
624
 
625
Once the sanbox has been deleted, the user must remove the components within the
626
sandbox.
627
 
628
=head3 info
629
 
630
The 'info' command will display information about the build order and the
631
depenedencies of packages that it finds within the sandbox.
632
 
633
The command will accept one option '-v' to increase the verbosity of the
634
information being displayed.
635
 
636
=over 8
637
 
638
=item * No Verbosity
639
 
640
The basic command will display the build order and the external
641
dependencies
642
 
643
=item Verbosity of 1
644
 
645
This level of verbosoity will display the build order and detailed information
646
on the dependencies. The dependencies will be prefixed with:
647
 
648
=over 8
649
 
650
=item   E   Dependent Package is external to the sandbox
651
 
652
=item   I   Dependent Package is internal to the sandbox
653
 
654
=back
655
 
656
This level of verbosity display information on packages that are external to the
657
sandbox. External dependencies may be prefixed with a '*'. This indicates that
658
multiple versions of this package are being used by sandboxed components.
659
 
660
The internal consumer of the external package is also shown. These are
661
prefixed with a 'U'.
662
 
663
=item Verbosity of 2
664
 
665
Reserved forfuture use
666
 
667
=item Verbosity over 2
668
 
669
This should be considered a debug option. Undocument internal information will
670
be displayed.
671
 
672
=back
673
 
227 dpurdie 674
=cut
675
 
255 dpurdie 676