Subversion Repositories DevTools

Rev

Rev 255 | Rev 263 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
227 dpurdie 1
#! perl
2
########################################################################
3
# Copyright ( C ) 2004 ERG Limited, All rights reserved
4
#
5
# Module name   : jats
6
# Module type   : Perl Package
7
# Compiler(s)   : n/a
8
# Environment(s): jats
9
#
10
# Description   : A Perl Package to perform error handling within JATS
11
#
12
#                 Uses global variables
13
#                       $::ScmWho;
14
#                       $::ScmVerbose;
15
#                       $::ScmQuiet;
16
#                       $::ScmDebug;
17
#                 For use with existing scripts
18
#
19
# Usage:
20
#
21
# Version   Who      Date        Description
22
#
23
#......................................................................#
24
 
255 dpurdie 25
require 5.006_001;
227 dpurdie 26
use strict;
27
use warnings;
28
use Data::Dumper;
29
use IO::Handle;
30
 
31
package JatsError;
32
 
33
#-------------------------------------------------------------------------------
34
# Function        : BEGIN
35
#
36
# Description     : Standard Package Interface
37
#
38
# Inputs          :
39
#
40
# Returns         :
41
#
42
 
43
BEGIN {
44
    use Exporter   ();
45
    our ($VERSION, @ISA, @EXPORT, @EXPORT_OK, %EXPORT_TAGS);
46
 
47
    # set the version for version checking
48
    $VERSION     = 1.00;
49
 
50
    @ISA         = qw(Exporter);
51
    @EXPORT      = qw(ErrorConfig ErrorDoExit
261 dpurdie 52
                      ReportError Fatal Error Warning
227 dpurdie 53
                      Message Message1
54
                      Information Information1
55
                      Question
56
                      Verbose Verbose2 Verbose3
57
                      Debug0 Debug Debug2 Debug3
58
                      IsVerbose IsDebug IsQuiet
231 dpurdie 59
                      DebugDumpData DebugDumpPackage DebugTraceBack
227 dpurdie 60
                      DebugPush DebugPop
61
                      );
62
 
63
    %EXPORT_TAGS = ( );     # eg: TAG => [ qw!name1 name2! ],
64
 
65
    # your exported package globals go here,
66
    # as well as any optionally exported functions
67
    @EXPORT_OK   = qw();
68
 
69
    #
70
    #   Ensure globals have a defined value
71
    #
72
    $::ScmWho = ''      unless defined( $::ScmWho );
73
    $::ScmVerbose = 0   unless defined( $::ScmVerbose );
74
    $::ScmDebug = 0     unless defined( $::ScmDebug );
75
    $::ScmQuiet = 0     unless defined( $::ScmQuiet );
76
 
77
    #
78
    #   Force autoflush in an attempt to limit the intermingling of
79
    #   Error and non-error output.
80
    #
81
    STDOUT->autoflush(1);
82
    STDERR->autoflush(1);
83
}
84
 
85
 
86
 
87
# exported package globals go here
88
#our $ScmWho;
89
#our $ScmVerbose;
90
#our $ScmDebug;
91
our $ScmOnExit;
92
our $ScmDelayExit;
93
our $ScmErrorCount;
261 dpurdie 94
our $ScmExitCode;
227 dpurdie 95
 
96
# non-exported package globals go here
97
$ScmErrorCount = 0;
261 dpurdie 98
$ScmExitCode = 1;
227 dpurdie 99
 
100
#  initialize package globals, first exported ones
101
 
102
 
103
#-------------------------------------------------------------------------------
104
# Function        : import
105
#
106
# Description     : Package import function
107
#                   This function will examine argumenst provided in the
108
#                   invoking 'uses' list and will configure the package
109
#                   accordingly.
110
#
111
# Inputs          : $pack           - Name of this package
112
#                   @vars           - User Config Options
113
#                   Config Options:
114
#                       :name=xxxx
115
#                       :quiet=xxx
116
#                       :debug=xxx
117
#                       :verbose=xxx
118
#                       :delay_exit=xxx
119
#
120
# Returns         : 
121
#
122
sub import {
123
    my $pack = shift;
124
    my @vars;
125
    my @config;
126
 
127
    #
128
    #   Extract options of the form: :name=value and pass them to the
129
    #   ErrorConfig function. All other arguments will be passed to the
130
    #
131
    foreach ( @_ )
132
    {
133
        if ( m/^:(.+)=(.+)/ ) {
134
            push @config, $1, $2;
135
        } else {
136
            push @vars, $_;
137
        }
138
    }
139
 
140
    ErrorConfig( @config )
141
        if ( @config );
142
 
143
    #
144
    #   Invoke Exporter function to handle the arguments that I don't understand
145
    #
146
    $pack->export_to_level(1, $pack , @vars);
147
}
148
 
149
#-------------------------------------------------------------------------------
150
# Function        : ErrorConfig
151
#
152
# Description     : Configure aspects of the JATS error handle
153
#
154
# Inputs          : A hash of option,value pairs
155
#                   Valid options
156
#                       name        - Name to report in error
157
#                       verbose     - vebosity level
158
#                       debug       - debug level
159
#                       on_exit     - Register on-exit function
160
#                       delay_exit  - Delay exit on error
161
#
162
# Returns         :
163
#
164
sub ErrorConfig
165
{
166
    my %args = @_;
167
    my $name;
168
 
169
    while (my($key, $value) = each %args)
170
    {
171
        if (       $key =~ /^name/ ) {
172
            $::ScmWho = "[$value] ";
173
            $name = $value;
174
 
175
        } elsif ( $key =~ /^debug/ ) {
176
            $::ScmDebug = $value || 0;
177
 
178
        } elsif ( $key =~ /^verbose/ ) {
179
            $::ScmVerbose = $value || 0;
180
 
181
        } elsif ( $key =~ /^quiet/ ) {
182
            $::ScmQuiet = $value || 0;
183
 
184
        } elsif ( $key =~ /^on_exit/ ) {
185
            $ScmOnExit = $value;
186
 
187
        } elsif ( $key =~ /^delay_exit/ ) {
188
            $ScmDelayExit = $value;
189
 
190
        } else {
191
            Error("ErrorConfig, Unknown option: $key");
192
        }
193
    }
194
 
195
    #
196
    #   Extract program specfic debug flags from the environment
197
    #   These will be based on the reporting 'name'
198
    #       GBE_name_DEBUG
199
    #       GBE_name_VERBOSE
200
    #
201
    if ( $name )
202
    {
203
        my ($value, $tag);
204
 
205
        $tag = "GBE_${name}_DEBUG" ;
261 dpurdie 206
        $tag =~ s~\s+~~g;
227 dpurdie 207
        $value = $ENV{ $tag };
208
        if (defined $value)
209
        {
210
            $::ScmDebug = $value;
211
            Warning("Envar: $tag setting debug: $value");
212
        }
213
 
214
        $tag = "GBE_${name}_VERBOSE" ;
261 dpurdie 215
        $tag =~ s~\s+~~g;
227 dpurdie 216
        $value = $ENV{ $tag };
217
        if (defined $value)
218
        {
219
            $::ScmVerbose = $value;
220
            Warning("Envar: $tag setting verbose: $value");
221
        }
222
    }
223
 
224
    #
225
    #   Sanitise quiet and verbose
226
    #   Any verboseness disables quiet
227
    #
228
    $::ScmQuiet = 0 if ( $::ScmVerbose );
229
    $::ScmQuiet = 0 if ( $::ScmDebug );
230
}
231
 
232
 
233
#-------------------------------------------------------------------------------
234
# Function        : Information
235
#                   Message
236
#                   Question
237
#                   Warning
238
#                   Error
239
#                   Verbose
240
#                   Debug
241
#                   _Message ( Internal use only )
242
#
243
# Description     : Error, Warning and Message routines
244
#                   These routines will display a message to the user
245
#                   with the module name.
246
#
247
#                   Multiple arguments are displayed on their own line
248
#                   with suitable spacing.
249
#
250
# Inputs          : Lines of text to display
251
#
252
# Returns         : Nothing
253
#
254
sub _Message
255
{
256
    my $tag = shift;                # First argument is a tag
257
    my $count = 0;
258
 
259
    #
260
    #   Generate the message prefix
261
    #   This will only be used on the first line
262
    #   All other lines will have a space filled prefix
263
    #
264
    my $prefix = $::ScmWho . $tag;
265
    #
266
    #   Kill the eol if the Question is being asked
267
    #
268
    my $eol = ( $tag =~ m/Q/ ) ? "" : "\n";
269
    foreach my $nextline ( @_ )
270
    {
231 dpurdie 271
        next unless ( defined $nextline );              # Ignore undefined arguments
227 dpurdie 272
        chomp( my $line = $nextline );
273
        if ( $count eq 1 )
274
        {
275
            my $bol = $eol ? "" : "\n";
276
            $prefix = $bol . ' ' x length($prefix);
277
        }
278
 
279
        print "$prefix $line$eol";
280
        $count++;
281
    }
282
}
283
 
284
#-------------------------------------------------------------------------------
285
# Function        : Information
286
#                   Information1
287
#
288
# Description     : Will display informational messages
289
#                   These are normal operational messages. These may be
290
#                   supressed through the use of QUIET options
291
#
292
# Inputs          : An array of strings to display
293
#
294
sub Information
295
{
296
    _Message '(I)', @_ unless ( $::ScmQuiet);
297
}
298
 
299
sub Information1
300
{
301
    _Message '(I)', @_ unless ( $::ScmQuiet > 1);
302
}
303
 
304
 
305
#-------------------------------------------------------------------------------
306
# Function        : Message
307
#                   Message1
308
#
309
# Description     : Same as Information, except a different prefix
310
#
311
# Inputs          : An array of strings to display
312
#
313
sub Message
314
{
315
    _Message '(M)', @_ unless ( $::ScmQuiet > 1);
316
}
317
 
318
sub Message1
319
{
320
    _Message '(M)', @_ unless ( $::ScmQuiet);
321
}
322
 
323
#-------------------------------------------------------------------------------
324
# Function        : IsQuiet
325
#
326
# Description     : Determine if an Infrmation or Message will be displayed
327
#                   May be used to reduce excessive processing that may be
328
#                   discarded
329
#
330
# Inputs          : $level      - Level to test
331
#
332
# Returns         : TRUE:       A Message at $level would be displayed
333
#
334
sub IsQuiet
335
{
336
    my( $level) = @_;
337
    return $::ScmQuiet >= $level;
338
}
339
 
340
#-------------------------------------------------------------------------------
341
# Function        : Warning
342
#
343
# Description     : Display a warning message
344
#                   These may be disabled with a high quiet level
345
#
346
# Inputs          : An array of strings to display
347
#
348
sub Warning
349
{
350
    _Message '(W)', @_ unless ( $::ScmQuiet > 2);
351
}
352
 
353
#-------------------------------------------------------------------------------
354
# Function        : Question
355
#
356
# Description     : Display a Question message
357
#                   These cannot be disabled
358
#
359
# Inputs          : An array of strings to display
360
#
361
sub Question
362
{
363
    _Message '(Q)', @_;
364
    STDERR->flush;              # Force output to be displayed
365
    STDOUT->flush;              # Force output to be displayed
366
}
367
 
368
#-------------------------------------------------------------------------------
261 dpurdie 369
# Function        : Fatal
370
#
371
# Description     : Display a multi line fatal message
372
#                   This will cause the program to exit.
373
#
374
#                   Similar to Error(), except
375
#                       Display a (F) prefix
376
#                       Alters the exit code to "2"
377
#                       Will terminate program execution.
378
#                       Will not honor delayed exit configuration.
379
#
380
#                   Fatal is to be used to indicate to consumer processes that
381
#                   the error is a function of the infrastructure and cannot be
382
#                   corrected by a user. ie:
383
#                       clearcase is not available
384
#                           Not just a bad user parameter
385
#                       dpkg_archive is not available
386
#                       release manager database is not available
387
#
388
#                   Intended to be used by build deamons to determine if building
389
#                   should continue, or if the entire build process should be
390
#                   terminated.
391
#
392
# Inputs          : An array of strings to display
393
#
394
# Returns         : May not return
395
#
396
sub Fatal
397
{
398
    _Message '(F)', @_;
399
    $ScmErrorCount++;
400
    $ScmExitCode = 2;
401
    ErrorDoExit() unless ( $ScmDelayExit );
402
}
403
 
404
#-------------------------------------------------------------------------------
227 dpurdie 405
# Function        : Error
406
#
261 dpurdie 407
# Description     : Display a multi line error message
227 dpurdie 408
#                   This may cause the program to exit, or the user may have
409
#                   configured the package to accumulate error messages
410
#
411
#                   This could be used to generate multiple error messages
412
#                   while parsing a file, and then terminate program execution at
413
#                   the end of the phase.
414
#
415
# Inputs          : An array of strings to display
416
#
417
# Returns         : May not return
418
#
419
 
420
sub Error
421
{
422
    _Message '(E)', @_;
423
    $ScmErrorCount++;
424
    ErrorDoExit() unless ( $ScmDelayExit );
425
}
426
 
427
#-------------------------------------------------------------------------------
428
# Function        : ReportError
429
#
430
# Description     : Like Error, but the error exit is delayed
431
#
432
# Inputs          : An array of strings to display
433
#
434
sub ReportError
435
{
436
    _Message '(E)', @_;
437
    $ScmErrorCount++;
438
}
439
 
440
#-------------------------------------------------------------------------------
441
# Function        : ErrorDoExit
442
#
443
# Description     : Will terminate the program if delayed error messages
444
#                   have been seen.
445
#
446
# Inputs          : None
447
#
448
# Returns         : Will return if no errors have been reported
449
#
450
 
451
sub ErrorDoExit
452
{
453
    if ( $ScmErrorCount )
454
    {
455
        #
456
        #   Prevent recusion.
457
        #   Kill error processing while doing error exit processing
458
        #
459
        if ( my $func = $ScmOnExit )
460
        {
461
            $ScmOnExit = undef;
462
            &$func();
463
        }
261 dpurdie 464
        exit $ScmExitCode;
227 dpurdie 465
    }
466
}
467
 
468
#-------------------------------------------------------------------------------
469
# Function        : Verbose
470
#                   Verbose2
471
#                   Verbose3
472
#
473
# Description     : Various levels of progress reporting
474
#                   By default none are displayed
475
#
476
# Inputs          : A single line string
477
#                   Multi-line output is not supported
478
#
479
sub Verbose
480
{
481
    _Message '(V)', "@_" if ($::ScmVerbose);
482
}
483
 
484
sub Verbose2
485
{
486
    _Message '(V)', "@_" if ($::ScmVerbose >= 2);
487
}
488
 
489
sub Verbose3
490
{
491
    _Message '(V)', "@_" if ($::ScmVerbose >= 3);
492
}
493
 
494
sub IsVerbose
495
{
496
    my( $level) = @_;
497
    return $::ScmVerbose >= $level;
498
}
499
 
500
#-------------------------------------------------------------------------------
501
# Function        : Debug
502
#                   Debug0
503
#                   Debug1
504
#                   Debug2
505
#                   Debug3
506
#
507
# Description     : Various levels of debug reporting
508
#                   By default none are displayed
509
#
510
# Inputs          : A single line string
511
#                   Multi-line output is not supported
512
#
513
sub Debug0
514
{
515
    _Message '------', "@_";
516
}
517
 
518
sub Debug
519
{
520
    _Message '(D)', "@_" if ($::ScmDebug >= 1) ;
521
}
522
 
523
 
524
sub Debug2
525
{
526
    _Message '(D)', "@_" if ($::ScmDebug >= 2) ;
527
}
528
 
529
 
530
sub Debug3
531
{
532
    _Message '(D)', "@_" if ($::ScmDebug >= 3) ;
533
}
534
 
535
sub IsDebug
536
{
537
    my( $level) = @_;
538
    return $::ScmDebug >= $level;
539
}
540
 
541
#-------------------------------------------------------------------------------
542
# Function        : DebugDumpData
543
#
544
# Description     : Dump a data structure
545
#
546
# Inputs          : $name           - A name to give the structure
547
#                   @refp           - An array of references
548
#
549
# Returns         :
550
#
551
sub DebugDumpData
552
{
553
    my ($name, @refp) = @_;
554
 
555
    my $ii = 0;
556
    foreach  ( @refp )
557
    {
558
        print Data::Dumper->Dump ( [$_], ["*[Arg:$ii] $name" ]);
559
        $ii++
560
    }
561
}
562
 
563
#-------------------------------------------------------------------------------
231 dpurdie 564
# Function        : DebugTraceBack
565
#
566
# Description     : Display the call stack
567
#
568
# Inputs          : $tag
569
#
570
# Returns         : Nothing
571
#
572
sub DebugTraceBack
573
{
574
    my ($tag) = @_;
575
    $tag = 'TraceBack' unless ( $tag );
576
 
577
    #
578
    #   Limit the stack stace.
579
    #   It can't go on forever
580
    #
581
    foreach my $ii ( 0 .. 20 )
582
    {
583
         my ($package, $filename, $line) = caller($ii);
584
         last unless ( $package );
585
         print "$tag: $ii: $package, $filename, $line\n";
586
    }
587
}
588
 
589
#-------------------------------------------------------------------------------
227 dpurdie 590
# Function        : DebugPush
591
#
592
# Description     : Save the current debug level and then use a new name and
593
#                   debug level for future reporting
594
#
595
# Inputs          : $name       - Nwe program name
596
#                   $level      - New program debug level
597
#
598
# Returns         : Current debug level
599
#
600
 
601
my @DebugStack = ();
602
sub DebugPush
603
{
604
    my ($name, $new_level) = @_;
605
 
606
    push @DebugStack, $::ScmDebug;
607
    push @DebugStack, $::ScmWho;
608
 
609
    $::ScmDebug = $new_level if ( defined $new_level && $new_level );
610
    $::ScmWho =   $name      if ( defined $name && $name );
611
 
612
    return $::ScmDebug;
613
}
614
 
615
#-------------------------------------------------------------------------------
616
# Function        : DebugPop
617
#
618
# Description     : Restores the operation of the DebugPush
619
#
620
# Inputs          : None
621
#
622
sub DebugPop
623
{
624
    $::ScmWho   = pop @DebugStack;
625
    $::ScmDebug = pop @DebugStack;
626
}
627
 
628
#-------------------------------------------------------------------------------
629
# Function        : DebugDumpPackage
630
#
631
# Description     : Dump data within the scope of a given package
632
#
633
# Inputs          : $packageName            - To dump
634
#
635
# Returns         : 
636
#
637
 
638
sub DebugDumpPackage
639
{
640
    no strict "vars";
641
    no strict "refs";
642
    my ($packageName) = @_;
643
    print "==DebugDumpPackage: $packageName =============================\n";
644
 
645
 
646
    local (*alias);             # a local typeglob
647
    local $Data::Dumper::Pad = "\t ";
648
    local $Data::Dumper::Maxdepth = 2;
649
    local $Data::Dumper::Indent  = 1;
650
 
651
    # We want to get access to the stash corresponding to the package name
652
 
653
    *stash = *{"${packageName}::"};  # Now %stash is the symbol table
654
#    $, = " ";                        # Output separator for print
655
    # Iterate through the symbol table, which contains glob values
656
    # indexed by symbol names.
657
    while (my ($varName, $globValue) = each %stash)
658
    {
659
        print "$varName =============================\n";
660
        next if ( $varName eq 'stash' );
661
        *alias = $globValue;
662
        if (defined ($alias)) {
663
            print Data::Dumper->Dump ( [$alias], ["*$varName" ]);
664
#            print "\t \$$varName $alias \n";
665
        } 
666
        if (defined (@alias)) {
667
            print Data::Dumper->Dump ( [\@alias], ["*$varName" ]);
668
#            print "\t \@$varName @alias \n";
669
        } 
670
        if (defined (%alias)) {
671
            print Data::Dumper->Dump ( [\%alias], ["*$varName" ]);
672
#            print "\t \%$varName ",%alias," \n";
673
        }
674
        if (defined (&alias)) {
675
#            print Data::Dumper->Dump ( [\&alias], ["*$varName" ]);
676
            print "\t \&$varName ","Code Fragment"," \n";
677
        }
678
     }
679
}
680
 
681
#
682
#
683
1;