Subversion Repositories DevTools

Rev

Rev 6177 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
235 dpurdie 1
########################################################################
6177 dpurdie 2
# COPYRIGHT - VIX IP PTY LTD ("VIX"). ALL RIGHTS RESERVED.
235 dpurdie 3
#
4
# Module name   : jats.sh
5
# Module type   : Makefile system
6
# Compiler(s)   : n/a
7
# Environment(s): jats
8
#
9
# Description   : JATS Make Time Support
10
#                 This package contains a collection of very useful functions
11
#                 that are invoked by the JATS generated makefiles to perform
12
#                 complicated operations at Make Time
13
#
14
#                 The functions are designed to be invoked as:
15
#                   $(GBE_PERL) -Mjats_runtime -e <function> -- <args>+
16
#
17
#                 The functions in this packages are designed to take parameters
18
#                 from @ARVG as this makes the interface easier to read.
19
#
20
#                 This package is used to speedup and simplify the JATS builds
21
#                 Speedup (under windows)
22
#                       Its quicker to start up one perl instance than
23
#                       to invoke a shell script that performs multiple commands
24
#                       Windows is very slow in forking another task.
25
#
26
#                 Simplify
27
#                       Removes some of the complications incurred due to different
28
#                       behaviour of utilities on different platforms. In particular
29
#                       the 'rm' command
30
#
31
#                       Perl is a better cross platform language than shell script
32
#                       as we have greater control over the release of perl.
33
#
34
#......................................................................#
35
 
255 dpurdie 36
require 5.006_001;
235 dpurdie 37
use strict;
38
use warnings;
39
 
40
package jats_runtime;
41
 
42
our (@ISA, @EXPORT, @EXPORT_OK, %EXPORT_TAGS, $VERSION);
43
use Exporter;
44
use JatsError qw(:name=jats_runtime);
45
 
46
$VERSION = 1.00;
47
@ISA = qw(Exporter);
48
 
49
# Symbols to autoexport (:DEFAULT tag)
50
@EXPORT = qw( rmlitter
321 dpurdie 51
              rm_opr
235 dpurdie 52
              rm_rf
53
              rm_f
54
              mkpath
55
              printenv
56
              printargs
321 dpurdie 57
              echo
6387 dpurdie 58
              copyDir
59
              unCopyDir
235 dpurdie 60
            );
61
 
62
use File::Path qw(rmtree);
6387 dpurdie 63
use JatsLocateFiles;
64
use JatsSystem;
65
 
321 dpurdie 66
our %opts;
235 dpurdie 67
 
68
#BEGIN
69
#{
70
#    print "-------jats_runtime initiated\n";
71
#}
72
 
73
#-------------------------------------------------------------------------------
321 dpurdie 74
# Function        : process_options
75
#
76
# Description     : Extract options from the front of the command stream
77
#                   Stops at the first argument that doesn't start with a
78
#                   '--'
79
#
80
#                   Options of the form --Opt=Val are split out
81
#                   Options of the form --Opt will set (or increment a value)
82
#
83
# Inputs          : None: Uses global ARGV
84
#
85
# Returns         : None: Resets global argv
86
#                         Populates the %opts hash
87
#
88
sub process_options
89
{
90
    while ( my $entry = shift @ARGV )
91
    {
92
        last if ( $entry eq '--' );
93
        if ( $entry =~  m/^--(.*)/  )
94
        {
95
            if ( $1 =~ m/(.*)=(.*)/ )
96
            {
97
                $opts{$1} = $2;
98
            }
99
            else
100
            {
101
                $opts{$1}++;
102
            }
103
        }
104
        else
105
        {
106
            unshift @ARGV, $entry;
107
            last;
108
        }
109
    }
110
    #
111
    #   Process some known options
112
    #
6387 dpurdie 113
    $opts{'Verbose'} = $opts{'verbose'} if defined $opts{'verbose'}; 
321 dpurdie 114
    $opts{'Progress'} = $opts{'Verbose'}    if ( $opts{'Verbose'} );
115
    ErrorConfig( 'name', $opts{Name})       if ( $opts{'Name'} );
116
    ErrorConfig( 'verbose', $opts{Verbose}) if ( $opts{'Verbose'} );
117
    DebugDumpData("RunTime Opts", \%opts )  if ( $opts{'ShowOpts'} );;
118
    Message ("RunTime args: @ARGV")         if ( $opts{'ShowArgs'} );
119
    printenv()                              if ( $opts{'ShowEnv'} );
120
    Message ($opts{'Message'})              if ( $opts{'Message'} );
121
}
122
 
123
#-------------------------------------------------------------------------------
235 dpurdie 124
# Function        : rmlitter
125
#
126
# Description     : Remove litter from a build directory
127
#
128
# Inputs          : ARGV    A list of files (with wildcards) to delete in the
129
#                           current, and named, directories.
130
#
131
#                           Options:    -f File list follows (default)
132
#                                       -d Dir  list follows
133
#
134
#                           Example:    *.err -d OBJ BIN
135
#                                       Will delete *.err OBJ/*.err BIN/*.err
136
#
137
# Returns         : 0
138
#
139
sub rmlitter
140
{
321 dpurdie 141
    process_options();
142
 
235 dpurdie 143
    my @flist;
144
    my @dlist = '.';
145
 
146
    #
147
    #   Parse arguments
148
    #   Collect filenames and dirnames. Switch between the two collection lists
149
    #
150
    #
151
    my $listp = \@flist;
152
    foreach my $ii ( @ARGV )
153
    {
154
        if ( $ii eq '-f' ) {
155
            $listp = \@flist;
156
 
157
        } elsif ( $ii eq '-d' ) {
158
            $listp = \@dlist;
159
 
160
        } else {
161
            push @$listp, $ii;
162
        }
163
    }
164
 
165
    #
166
    #   Process all directories looking for matching files
167
    #   Delete files
168
    #
169
    foreach my $dir ( @dlist )
170
    {
171
        foreach my $file ( @flist )
172
        {
173
            my $path = "$dir/$file";
174
            $path =~ s~ ~\\ ~g;
175
            my @del = glob ( $path );
176
            if ( @del )
177
            {
321 dpurdie 178
                Message ("rmlitter. @del") if ($opts{'Progress'} );
235 dpurdie 179
                chmod '777', @del;
180
                unlink @del;
181
            }
182
        }
183
    }
184
}
185
 
186
#-------------------------------------------------------------------------------
187
# Function        : expand_wildcards
188
#
189
# Description     : Expand argument wildcards
190
#                   Replace @ARGV with an expanded list of files to process
191
#                   This is a helper function
192
#
193
#
194
# Inputs          : @ARGV
195
#
196
# Returns         : @ARGV
197
#
198
sub expand_wildcards
199
{
200
    #
201
    #   Replace spaces with escaped spaces to assist the 'glob'
202
    #
203
    sub escape_space
204
    {
205
        my ($item) = @_;
206
        $item =~ s~ ~\\ ~g;
207
        return $item;
208
    }
209
    @ARGV = map(/[*?]/o ? glob (escape_space($_)) : $_ , @ARGV);
210
}
211
 
212
#-------------------------------------------------------------------------------
213
# Function        : rm_rf
214
#
215
# Description     : Remove all files and directories specified
216
#
217
# Inputs          : @ARGV       - A list of files and directories
218
#
219
# Returns         : Nothing
220
#
221
sub rm_rf
222
{
321 dpurdie 223
    process_options();
235 dpurdie 224
    expand_wildcards();
225
    my @dirs =  grep -e $_,@ARGV;
226
    if ( @dirs )
227
    {
228
        rmtree(\@dirs,0,0);
229
    }
230
}
231
 
232
#-------------------------------------------------------------------------------
233
# Function        : rm_f
234
#
235
# Description     : Remove all named files
236
#                   Will not remove directores - even if named
237
#
321 dpurdie 238
#                   Unix Note:
239
#                   Need to handle broken soft links
240
#
241
#
235 dpurdie 242
# Inputs          : @ARGV       - A list of files to delete
243
#
244
# Returns         :
245
#
246
sub rm_f {
321 dpurdie 247
    process_options();
235 dpurdie 248
    expand_wildcards();
249
 
250
    foreach my $file (@ARGV) {
321 dpurdie 251
        Message ("Delete: $file") if ($opts{'Progress'} );
252
        next if -d $file;
253
        next unless ( -e $file || -l $file );
235 dpurdie 254
        next if _unlink($file);
321 dpurdie 255
        Warning "Cannot delete $file: $!";
256
    }
257
}
235 dpurdie 258
 
321 dpurdie 259
#-------------------------------------------------------------------------------
260
# Function        : rm_opr
261
#
262
# Description     : Combo deletion operation
263
#                   Parameter driven to delete many things in one command
264
#
265
# Inputs          : Options and paths
266
#                   Options. Set mode for following paths
267
#                       -f   remove named file
268
#                       -d   remove named directory if empty
269
#                       -rf  remove directory or file
270
#                       -fd  remove file and directory if empty
271
#
272
# Returns         : 
273
#
274
sub rm_opr
275
{
276
    my $mode = '-f';
277
    process_options();
278
    foreach my $file (@ARGV) {
279
        if ( $file eq '-f' ) {
280
            $mode = $file;
281
        } elsif ( $file eq '-d' ) {
282
            $mode =$file;
283
        } elsif ( $file eq '-rf' ) {
284
            $mode =$file;
285
        } elsif ( $file eq '-fd' ) {
286
            $mode =$file;
287
        } elsif ( $file =~ m/^-/ ) {
288
            Error ("rm_opr - unknown option: $file");
289
        } else {
290
            #
291
            #   Not an option must be a file/dir to delete
292
            #
293
            if ( $mode eq '-f' ) {
294
                Message ("Delete File: $file") if ($opts{'Progress'} );
295
                _unlink($file);
235 dpurdie 296
 
321 dpurdie 297
            } elsif ( $mode eq '-d' ) {
298
                Message ("Delete Empty Dir: $file") if ($opts{'Progress'} );
299
                rmdir $file;
300
 
301
            } elsif ( $mode eq '-rf' ) {
302
                Message ("Delete Dir: $file") if ($opts{'Progress'} );
303
                rmtree($file,0,0);
304
 
305
            } elsif ( $mode eq '-fd' ) {
306
                Message ("Delete File: $file") if ($opts{'Progress'} );
307
                _unlink($file);
308
                my $dir = $file;
309
                $dir =~ tr~\\/~/~s;
310
                Message ("Remove Empty Dir: $dir") if ($opts{'Progress'} );
311
                if ( $dir =~ s~/[^/]+$~~ )
312
                {
313
                    rmdir $dir;
314
                }
315
            }
316
        }
235 dpurdie 317
    }
318
}
319
 
321 dpurdie 320
 
235 dpurdie 321
#-------------------------------------------------------------------------------
322
# Function        : mkpath
323
#
324
# Description     : Create a directory tree
325
#                   This will create all the parent directories in the path
326
#
327
# Inputs          : @ARGV   - An array of paths to create
328
#
329
# Returns         :
330
#
331
sub mkpath
332
{
321 dpurdie 333
    process_options();
235 dpurdie 334
    expand_wildcards();
335
    File::Path::mkpath([@ARGV],0,0777);
336
}
337
 
338
#-------------------------------------------------------------------------------
6387 dpurdie 339
# Function        : copyDir 
340
#
341
# Description     : Copy a directory tree
342
#                   Used by PackageDir to perform run-time packaging
343
#
344
# Inputs          : @ARGV   - Options
345
#                       -mode=text
346
#                       -src=path
347
#                       -dst=path
348
#                       -execute        - Mark ALL as executable
349
#                       -noSymlink        
350
#                       -noRecurse
351
#                       -stripBase      - Strip first dir from the source
352
#                       -exclude+=filter
353
#                       -include+=filter
354
#
355
# Returns         : 
356
#
357
sub copyDir
358
{
359
    my $copts = processCopyDirArgs('copyDir');
360
    return unless $copts;
361
 
362
    #
363
    #   Create the target directory if required
364
    #
365
    unless (-d  $copts->{dst}) {
366
            Verbose("Create target directory: $copts->{dst}");
367
          File::Path::mkpath([$copts->{dst}],0,0777);
368
    }
369
 
370
    #
371
    #   Configure the use of the System function
372
    #   Don't exit on error - assume used in unpackaging
373
    #
374
    SystemConfig ( UseShell => 0, ExitOnError => 0);
375
 
376
    #
377
    #   Calc mode
378
    #
379
    my $fmode = '';
380
    $fmode .= '+x' if defined $copts->{execute}; 
381
    $fmode .= '+l' unless defined $copts->{noSymlink}; 
382
 
383
    #
384
    #   Configure the use of the System function
385
    #
386
    SystemConfig ( UseShell => 0, ExitOnError => 1);
387
 
388
    #
389
    #   Travserse the source directory and copy files
390
    #
391
    my @elements = $copts->{search}->search ( $copts->{src} );
392
 
393
    #
394
    #   Transfer each file
395
    #   Use the JatsFileUtil as it solves lots of problems
396
    #   Its args are strange - Historic (long Story). Args:
397
    #       'c0'        - Operation is Copy and debug level
398
    #       'Text'      - Text message to display
399
    #       DestPath
400
    #       SrcPath
401
    #       Modes       - wxl
402
    #
403
    #   Do not get the shell involved in invoking the command
404
    #   Quote args in '' not "" as "" will trigger shell usage
405
    #       
406
    #
407
    foreach my $file ( @elements)
408
    {
409
        my $dst = $file;
410
        #
411
        #   Calc target path name
412
        #
413
        if ($copts->{stripBase}) {
414
            $dst = substr($dst, $copts->{stripBase} );
415
        }
416
        $dst = $copts->{dst} . '/' . $dst;
417
 
418
        #
419
        #   If the file exists, then only copy it if the src is newer
420
        #
421
        if (-f $dst) {
422
            my ($file1, $file2) = @_;
423
 
424
            my $f1_timestamp = (stat($file))[9] || 0;
425
            my $f2_timestamp = (stat($dst))[9] || 0;
426
            next unless ($f1_timestamp > $f2_timestamp );
427
        }
428
 
429
        System('JatsFileUtil', 'c0', $copts->{mode} , $dst, $file, $fmode);
430
    }
431
}
432
 
433
#-------------------------------------------------------------------------------
434
# Function        : unCopyDir 
435
#
436
# Description     : Delete files copies with a copy dir command
437
#                   Delete directories if they are empty
438
#                   Used by PackageDir to perform run-time packaging
439
#
440
# Inputs          : @ARGV   - Options
441
#                       -mode=text
442
#                       -src=path
443
#                       -dst=path
444
#                       -execute        - Ignored
445
#                       -noSymlink      - Ignored
446
#                       -noRecurse
447
#                       -stripBase      - Strip first dir from the source
448
#                       -exclude+=filter
449
#                       -include+=filter
450
#                       -excludeRe+=filter
451
#                       -includeRe+=filter
452
#                       
453
#
454
# Returns         : 
455
#
456
sub unCopyDir
457
{
458
    my %dirList;
459
    my $copts = processCopyDirArgs('UnCopyDir');
460
    return unless $copts;
461
 
462
    #
463
    #   Configure the use of the System function
464
    #   Don't exit on error - assume used in unpackaging
465
    #
466
    SystemConfig ( UseShell => 0, ExitOnError => 0);
467
 
468
    #
469
    #   Nothing to do if the target directory does not exist
470
    #
471
    unless (-d $copts->{dst}) {
472
        Verbose("UnCopyDir: No target directory: $copts->{dst}");
473
        return;
474
    }
475
 
476
    #
477
    #   Travserse the source directory and find files that would have been copied
478
    #
479
    my @elements = $copts->{search}->search ( $copts->{src} );
480
 
481
    #
482
    #   Delete each file
483
    #   Use the JatsFileUtil as it solves lots of problems
484
    #   Its args are strange - Historic (long Story). Args:
485
    #       'd0'        - Operation is Copy and debug level
486
    #       'Text'      - Text message to display
487
    #       DestPath
488
    #
489
    #   Do not get the shell involved in invoking the command
490
    #   Quote args in '' not "" as "" will trigger shell usage
491
    #       
492
    #
493
    foreach my $file ( @elements)
494
    {
495
        my $dst = $file;
496
 
497
        #
498
        #   Calc target path name
499
        #
500
        if ($copts->{stripBase}) {
501
            $dst = substr($dst, $copts->{stripBase} );
502
        }
503
        $dst = $copts->{dst} . '/' . $dst;
504
 
505
        #
506
        #   Only delete if the file exists
507
        #
508
        next unless (-f $dst);
509
        System('JatsFileUtil', 'd0', $copts->{mode}, $dst);
510
 
511
        #   Save dir name for later cleanup
512
        if ($dst =~ s~/[^/]+$~~) {
513
            $dirList{$dst} = 1;
514
        }
515
    }
516
 
517
    #
518
    #   Delete all directories encountred in the tree - if they are empty
519
    #   Only delete up the base of the target directory
520
    #       Have a hash of directories - generated by the file deletion process
521
    #       Extend the hash to include ALL subdirectoroy paths too
522
    #   
523
    Verbose("Remove empty directories");
524
    foreach my $entry ( keys %dirList ) {
525
        while ($entry =~ s~/[^/]+$~~ ) {
526
            $dirList{$entry} = 2;
527
        }
528
    }
529
 
530
    my @dirList = sort { length $b <=> length $a } keys %dirList; 
531
    foreach my $tdir ( @dirList ) {
532
        Verbose("Remove dir: $tdir");
533
        rmdir $tdir;
534
    }
535
}
536
 
537
#-------------------------------------------------------------------------------
538
# Function        : processCopyDirArgs 
539
#
540
# Description     : Process the args for CopyDir and UnCopyDir so that the processing
541
#                   is identical
542
#
543
# Inputs          : $cmdName     - Command name
544
#                   From ARGV 
545
#
546
# Returns         : A hash containing
547
#                       copts   - Copy Options
548
#                       search  - For JatsLocateFiles 
549
#                   Empty if nothind to do    
550
#
551
sub processCopyDirArgs
552
{
553
    my ($cmdName) = @_;
554
    process_options();
555
 
556
    #
557
    #   Put the command line arguments into a hash
558
    #   Allow:
559
    #       aaa+=bbb        - An array
560
    #       aaa=bbb         - Value
561
    #       aaa             - Set to one
562
    #
563
    my %copts;
564
    foreach (@ARGV) {
565
        if (m~-(.*)\+=(.*)~) {
566
            push @{$copts{$1}}, $2;
567
 
568
        } elsif (m~-(.*)?=(.*)~){
569
            $copts{$1} = $2;
570
 
571
        } elsif (m~-(.*)~) {
572
            $copts{$1} = 1;
573
        }
574
    }
575
    Message ("$cmdName Dir Tree: $copts{src} -> $copts{dst}") if ($opts{'Progress'} );
576
 
577
    #
578
    #   Ensure the source exists
579
    #
580
    Warning ("$cmdName: Source directory does not exists:" . $copts{src}) unless -d $copts{src};
581
 
582
    #
583
    #   Calc strip length
584
    #
585
    if ($copts{stripBase}) {
586
        $copts{stripBase} = 1 + length($copts{src});
587
    }
588
 
589
    #
590
    #   Set up the search options to traverse the source directory and find files 
591
    #   to process
592
    #
593
    my $search = JatsLocateFiles->new('FullPath' );
594
    $search->recurse(1) unless $copts{noRecurse};
595
    $search->filter_in_re ( $_ ) foreach ( @{$copts{includeRe}} );
596
    $search->filter_out_re( $_ ) foreach ( @{$copts{excludeRe}} );
597
    $search->filter_in ( $_ ) foreach ( @{$copts{include}} );
598
    $search->filter_out( $_ ) foreach ( @{$copts{exclude}} );
599
    $search->filter_out_re( '/\.svn/' );
600
    $search->filter_out_re( '/\.git/' );
601
 
602
    #
603
    #   Return a hash
604
    #
605
    $copts{search} = $search;
606
    return \%copts;
607
}
608
 
609
 
610
#-------------------------------------------------------------------------------
235 dpurdie 611
# Function        : _unlink
612
#
613
# Description     : Helper function
614
#                   Unlink a list of files
615
#
321 dpurdie 616
# Inputs          : A file to delete
235 dpurdie 617
#
321 dpurdie 618
# Returns         : False: File still exists
235 dpurdie 619
#
620
sub _unlink {
321 dpurdie 621
    my ($file) = @_;
622
    if ( ! unlink $file  )
235 dpurdie 623
    {
321 dpurdie 624
        chmod(0777, $file);
625
        return unlink $file;
235 dpurdie 626
    }
321 dpurdie 627
    return 1;
235 dpurdie 628
}
629
 
630
#-------------------------------------------------------------------------------
631
# Function        : printenv
632
#
633
# Description     : 
634
#
635
# Inputs          : 
636
#
637
# Returns         : 
638
#
639
sub printenv
640
{
641
    foreach my $entry ( sort keys %ENV )
642
    {
321 dpurdie 643
        print "    $entry=$ENV{$entry}\n";
235 dpurdie 644
    }
645
}
646
 
647
#-------------------------------------------------------------------------------
648
# Function        : printargs
649
#
650
# Description     : Print my argumements
651
#
652
# Inputs          : User arguments
653
#
654
# Returns         : Nothing
655
#
656
sub printargs
657
{
321 dpurdie 658
    Message "Arguments", @ARGV;
659
}
660
 
661
#-------------------------------------------------------------------------------
662
# Function        : echo
663
#
664
# Description     : echo my argumements
665
#
666
# Inputs          : User arguments
667
#
668
# Returns         : Nothing
669
#
670
sub echo
671
{
672
    process_options();
673
    Message @ARGV;
674
}
675
 
676
#-------------------------------------------------------------------------------
677
# Function        : printArgsEnv
678
#
679
# Description     : Print my argumements nd environmen
680
#
681
# Inputs          : User arguments
682
#
683
# Returns         : Nothing
684
#
685
my $PSPLIT=':';
686
sub printArgsEnv
687
{
235 dpurdie 688
    Message "printargs....";
689
    Message "Program arguments", @ARGV;
690
 
691
    $PSPLIT = ';' if ( $ENV{GBE_MACHTYPE} eq 'win32' );
692
 
693
    sub penv
694
    {
695
        my ($var) = @_;
696
        pvar ($var, $ENV{$var} || '');
697
    }
698
    # Simple print of name and variable
699
    sub pvar
700
    {
701
        my ($text, $data) = @_;
702
        printf "%-17s= %s\n", $text, $data;
703
    }
704
 
705
    sub alist
706
    {
707
        my ($text, @var) = @_;
708
        my $sep = "=";
709
        for ( @var )
710
        {
711
            my $valid = ( -d $_ || -f $_ ) ? " " : "*";
712
            printf "%-17s%s%s%s\n", $text, $sep, $valid, $_;
713
            $text = "";
714
            $sep = " ";
715
        }
716
    }
717
 
718
    #   Display a ';' or ':' separated list, one entry per line
719
    sub dlist
720
    {
721
        my ($text, $var) = @_;
722
        alist( $text, split $PSPLIT, $var || " " );
723
    }
724
 
725
    Message ("Complete environment dump");
726
    foreach my $var ( sort keys(%ENV) )
727
    {
728
       penv  ($var);
729
    }
730
 
731
    dlist   "PATH"            , $ENV{PATH};
732
    exit (999);
733
}
734
 
735
1;