Subversion Repositories DevTools

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
224 hknight 1
#!/usr/bin/perl -w
2
 
3
########################################################################
4
# Copyright (C) 2008 ERG Limited, All rights reserved
5
#
6
# Module name   : schemadump.pl
7
# Module type   : Standalone utility
8
# Compiler(s)   : n/a
9
# Environment(s): windows (dos), unix (solaris and linux)
10
#
11
# Description   : Extracts a directory structure from the output of
12
#                 datapump.  This is useful for creating files to
13
#                 be put into source control from a database.
14
#
15
# History       : Created by Haydon Knight April 2008
16
#
17
# Usage         : schemadump.pl [options] -src=<srcFile> -dest=<destDir>
18
#
19
########################################################################
20
 
21
#######################################################################
22
# Use lines
23
#######################################################################
24
require 5.6.1;
25
use strict;
26
use warnings;
27
use Pod::Usage;                             # required for help support
28
use Getopt::Long;
29
 
30
use commonExports; # see commonExports.pm in this directory
31
 
32
#######################################################################
33
# Function prototypes
34
#######################################################################
35
 
36
sub startupChecks();
37
sub parseCommandLine();
38
sub main();
39
 
40
sub getSubSectionLiness(\@);
41
sub getFullDirs(\@);
42
sub getSubDirs(@);
43
sub writeData(\@\@);
44
sub getFileLines($\$@);
45
sub getFilename($@);
46
sub writeDDLHeader(@);
47
 
48
sub packageBodySplit(\$@);
49
sub splitOnBlank(\$@);
50
sub splitOnSlash(\$@);
51
sub splitOnSemiColon(\$@);
52
sub splitOnCreate(\$@);
53
 
54
#######################################################################
55
# Constant global variables
56
#######################################################################
57
 
58
my $VERSION = "1.0.1";
59
 
60
#######################################################################
61
# Other global variables
62
#######################################################################
63
 
64
my $srcFile;
65
my $destDir;
66
 
67
#######################################################################
68
# Main code
69
#######################################################################
70
 
71
parseCommandLine();
72
startupChecks();
73
main();
74
finish();
75
 
76
#######################################################################
77
# Function definitions
78
#######################################################################
79
 
80
#-------------------------------------------------------------------------------
81
# Function  : main
82
#
83
# Purpose   : Main function of this script
84
#
85
# Arguments : none
86
#
87
# Returns   : none
88
#
89
# Notes     : Does everything but setting up at start and tearing down at end.
90
#
91
sub main()
92
{
93
    my @lines = readArray( $srcFile ); # all the lines in the datapump dump file
94
 
95
    mkdir "$destDir/bookKeeping" unless -d "$destDir/bookKeeping";
96
 
97
    writeDDLHeader( @lines );
98
 
99
    # getFullDirs() returns an array of strings.
100
    # Each of these is of the form '<DIRY_1>/<DIRY_2>/.../<DIRY_N>.
101
    # e.g. one element is 'TABLE/INDEX/STATISTICS/INDEX_STATISTICS'. 
102
    my @fullDirs = getFullDirs( @lines ); 
103
 
104
    # getSubDirs() returns an array of strings.
105
    # Each of these is of the form '<diry_1>/<diry_2>'.
106
    # e.g. the element formed from 'TABLE/INDEX/STATISTICS/INDEX_STATISTICS' is
107
    # 'table/index_statistics'.
108
    my @subDirs = getSubDirs( @fullDirs );
109
 
110
    # This is a 2-D array - i.e. it is an array of (references to arrays)
111
    # Each reference to an array corresponds to an element of @subDirs.
112
    # For each of these there is an array of the lines corresponding to that DDL-data-type.
113
    my @subSectionLiness = getSubSectionLiness(@lines);
114
 
115
    die "BUG!  Did not get the same number of sub directories as blocks of subsection lines (" .
116
        scalar(@subDirs) . " vs " . scalar(@subSectionLiness) . ")\n"
117
            unless scalar(@subDirs) == scalar(@subSectionLiness);
118
 
119
    writeArray( "$destDir/bookKeeping/objectTypes", @fullDirs);
120
    createDirectories( $destDir, @subDirs );
121
 
122
    my $linesWritten = writeData( @subDirs, @subSectionLiness );
123
 
124
    # Minus one for the very first line: the '-- CONNECT RELEASE_MANAGER' line
125
    my $linesDesired = scalar(@lines) - scalar(@subDirs) - 1;
126
 
127
    die "Internal logic error!  Desired to write out $linesDesired lines but wrote out " . 
128
        " $linesWritten lines\n"
129
    unless $linesDesired == $linesWritten;
130
}
131
 
132
 
133
#-------------------------------------------------------------------------------
134
# Function  : writeDDLHeader
135
#
136
# Purpose   : Writes the first line of the enormous datapump dump file to a file
137
#             This line is used by ddlfile.pl to reconstruct the dump file.
138
#
139
# Arguments : @lines (i) - all the lines from the datapump dump file
140
#
141
# Returns   : nothing
142
#
143
# Notes     :
144
#
145
sub writeDDLHeader(@)
146
{
147
    my @lines = @_;
148
 
149
    die "No lines read from input file\n" unless @lines;
150
 
151
    my $connectLine = $lines[0];
152
 
153
    die "Could not read the string 'CONNECT' from first line of input file ('$connectLine')\n"
154
        unless $connectLine =~ m~^-- CONNECT\s+~;
155
 
156
    writeArray( "$destDir/bookKeeping/DDLHeader", ($connectLine) );   
157
}
158
 
159
 
160
#-------------------------------------------------------------------------------
161
# Function  : getSubSectionLiness
162
#
163
# Purpose   : Constructs a 2D array of lines in each DDL-type
164
#             i.e. for each DDL-type (A DDL-type is a sequence or a package or a table etc)
165
#             there is an array of lines
166
#
167
# Arguments : $refLines (i) - Reference to @lines - the list of all lines in the datapump dump file
168
#
169
# Returns   : @subSectionLiness - an array of references to arrays
170
#
171
# Notes     : Simply splits on lines containing $subSectionSplitter 
172
#
173
sub getSubSectionLiness(\@)
174
{
175
    my ($refLines) = @_;
176
 
177
    my @subSectionLiness;
178
    my @tempList;
179
    my $isFirstTime = 1;
180
 
181
    foreach my $line (@$refLines)
182
    {
183
        if( $line =~ m~^$subSectionSplitter~ )
184
        {
185
            push @subSectionLiness, [ @tempList ] unless $isFirstTime;
186
            $isFirstTime = 0;
187
            @tempList = ();
188
        }
189
        else
190
        {
191
            push @tempList, $line;
192
        }
193
    }
194
    push @subSectionLiness, [ @tempList ];
195
 
196
    logprint "Got " . scalar(@subSectionLiness) . " sets of subSection Lines";
197
 
198
    return @subSectionLiness;
199
}
200
 
201
 
202
#-------------------------------------------------------------------------------
203
# Function  : getFullDirs
204
#
205
# Purpose   : Constructs an array of directory paths
206
#
207
# Arguments : $refLines (i) - reference to @lines - all lines in datapump dump file
208
#
209
# Returns   : @fullDirys - array of directory paths
210
#
211
# Notes     : Reads in directory paths from the '--new object' lines in the datapump dump file
212
#             The directory paths have extra subdirectories than what is actually mkdir'ed
213
#             Subsequent functionality (getTopBotDirs() for example) strips out these
214
#             middle subdirectories
215
#
216
sub getFullDirs(\@)
217
{
218
    my ($refLines) = @_;
219
 
220
    ###############################################################
221
    # extract out from lines starting with '-- new object'
222
    # strings of the form 'TABLE/INDEX/STATISTICS/INDEX_STATISTICS'
223
    my @fullDirys;
224
 
225
    foreach my $line (@$refLines)
226
    {
227
        next unless $line =~ m~^$subSectionSplitter~;
228
        (my $fullDiry = $line) =~ s~^$subSectionSplitter~~;
229
        push @fullDirys, $fullDiry;
230
 
231
        logprint "Got fullDiry '$fullDirys[-1]'";
232
    }
233
 
234
    logprint "Got " . scalar(@fullDirys)  . " fullDirys contributing to subDirs\n";
235
 
236
    return @fullDirys;
237
}
238
 
239
 
240
#-------------------------------------------------------------------------------
241
# Function  : getSubDirs
242
#
243
# Purpose   : Constructs the list of subdirectories that will be mkdir'ed and filled
244
#             with .sql files
245
#
246
# Arguments : @fullDirys (i) - list of directories parsed from datapump dump file
247
#
248
# Returns   : @subDirs - list of directories that will exist if script finishes successfully
249
#
250
# Notes     :
251
#
252
sub getSubDirs(@)
253
{
254
    my @fullDirys = @_;
255
 
256
    my @topDirs;
257
    my @botDirs;
258
 
259
    foreach my $fullDiry (@fullDirys)
260
    {
261
        my ($topDir, $botDir) = getTopBotDirs( $fullDiry );
262
 
263
        push @topDirs, $topDir;
264
        push @botDirs, $botDir;
265
    }
266
 
267
    ###############################################################
268
    # combine top/bot dirs
269
    my @subDirs;
270
 
271
    for( my $i = 0; $i < scalar(@topDirs); $i++)
272
    {
273
        push @subDirs, "$topDirs[$i]/$botDirs[$i]";
274
        logprint "Pushed subDir $i: '$subDirs[-1]'";
275
    }
276
 
277
    ###############################################################
278
    # convert to lower case
279
    foreach my $subDir (@subDirs)
280
    {
281
        $subDir =~ tr~A-Z~a-z~;
282
    }
283
 
284
    return @subDirs;
285
}
286
 
287
 
288
#-------------------------------------------------------------------------------
289
# Function  : parseCommandLine
290
#
291
# Purpose   : Parses command line; invokes help if necessary
292
#
293
# Arguments : nothing
294
#
295
# Returns   : nothing
296
#
297
# Notes     : Sets up various global variables; these are not checked here - they should be
298
#             checked in startupChecks()
299
#
300
sub parseCommandLine()
301
{
302
    my $opt_help = 0;
303
    my $opt_manual = 0;
304
 
305
    my $result = GetOptions (
306
    "help"          => \$opt_help,              # flag
307
    "manual"        => \$opt_manual,            # flag
308
    "verbose+"      => \$verbose,               # flag
309
    "src=s"         => \$srcFile,               # String
310
    "dest=s"        => \$destDir,               # String
311
    "log=s"         => \$logFile,               # String
312
    );
313
 
314
    pod2usage(-verbose => 2) if( $opt_manual );
315
    pod2usage(-verbose => 0, -message => "Version: $VERSION") if ($opt_help > 0 || ! $result );
316
}
317
 
318
 
319
#-------------------------------------------------------------------------------
320
# Function  : startupChecks
321
#
322
# Purpose   : Checks that important variables are set sanely
323
#
324
# Arguments : nothing
325
#
326
# Returns   : nothing
327
#
328
# Notes     : Calls die() if things aren't set sanely.
329
#             This function opens the logfile.
330
#
331
sub startupChecks()
332
{
333
    die "You need to specify a source file using '-src=<srcFile>'\n" unless $srcFile;
334
    die "You need to specify an existing destination directory using '-dest=<destDir>'\n"
335
        unless $destDir;
336
 
337
    $srcFile =~ s~\\~/~g;
338
    $destDir =~ s~\\~/~g;
339
 
340
    die "Source file '$srcFile' does not exist\n" if( ! -e $srcFile || -d $srcFile );
341
    die "Destination directory '$destDir' does not exist\n" unless -d $destDir;
342
 
343
    openLog();
344
}
345
 
346
 
347
#-------------------------------------------------------------------------------
348
# Function  : getFileLines
349
#
350
# Purpose   : Extracts from a set of lines only those lines for each DDL-data-object.
351
#             e.g. extracts lines for a package from the lines corresponding to all packages.
352
#             This function also increments the line counter.
353
#
354
# Arguments : $subDir (i) - The subdirectory the DDL-data-object is being created in
355
#             $refIline (io) - Reference to $iline - how far through the current lineset
356
#                              we currently are.  (each lineset might correspond to all
357
#                              packages or all tables or all views etc)
358
#             @lines (i)     - The current lineset
359
#
360
# Returns   : $addedExtraLines - boolean value; true indicates that an 'ALTER PACKAGE'
361
#                                DDL-data-object was appended onto the list of lines for this
362
#                                DDL-data-object.  This only occurs for some 'PACKAGE_BODY'
363
#                                objects in the release manager database.
364
#             @fileLines - The lines corresponding to the DDL-data-object
365
#
366
# Notes     : Invokes helper functions for each type of splitting.  These functions are
367
#             tailored to the release manager database and may
368
#             need to be altered for other databases.
369
#
370
sub getFileLines($\$@)
371
{
372
    my ($subDir, $refIline, @lines) = @_;
373
 
374
    # Skip over blank lines
375
    $$refIline++ while( $$refIline < scalar(@lines) && $lines[$$refIline] =~ m~^\s*$~ );
376
 
377
    return (0,"end of data") if( $$refIline >= scalar(@lines) );
378
 
379
    my %fileLinesFunctions = (
380
        qq(type/type)                    => \&splitOnSlash,
381
        qq(function/function)            => \&splitOnSlash,
382
        qq(procedure/procedure)          => \&splitOnSlash,
383
        qq(package/package_body)         => \&packageBodySplit,
384
        qq(package/package_spec)         => \&splitOnSlash,
385
        qq(synonym/synonym)              => \&splitOnBlank,
386
        qq(sequence/sequence)            => \&splitOnBlank,
387
        qq(table/table)                  => \&splitOnBlank,
388
        qq(view/view)                    => \&splitOnSemiColon,
389
        qq(table/index)                  => \&splitOnCreate,
390
        qq(table/se_tbl_fbm_index_index) => \&splitOnCreate);
391
 
392
    die "Internal coding error: could not find a case for subdirectory" .
393
        " '$subDir' in the fileLinesFunctions hash table\n"
394
        unless $fileLinesFunctions{$subDir};
395
 
396
    return $fileLinesFunctions{$subDir}->( $refIline, @lines );
397
}
398
 
399
 
400
#-------------------------------------------------------------------------------
401
# Function  : splitOnBlank
402
#
403
# Purpose   : Extracts out the next DDL object from a set of lines by
404
#             adding lines until a delineating blank line is found
405
#
406
# Arguments : $refIline (io) - reference to $iline - line to start searching on
407
#             @lines (i) - Array to search through
408
#
409
# Returns   : $addedExtraLines - always 0
410
#             @fileLines - The lines corresponding to the DDL-data-object
411
#
412
# Notes     : 
413
#
414
sub splitOnBlank(\$@)
415
{
416
    my ($refIline, @lines) = @_;
417
 
418
    my @fileLines;
419
 
420
    # Keep adding lines until we get a blank line
421
    while( $$refIline < scalar(@lines) && $lines[$$refIline] !~ m~^\s*$~ )
422
    {
423
        push @fileLines, $lines[$$refIline];
424
        $$refIline++;
425
    }
426
 
427
    # Skip past the blank line
428
    $$refIline++ if $$refIline < scalar(@lines);
429
 
430
    return (0, @fileLines);
431
}
432
 
433
 
434
#-------------------------------------------------------------------------------
435
# Function  : splitOnCreate
436
#
437
# Purpose   : Extracts out the next DDL object from a set of lines by
438
#             searching for the next 'CREATE' keyword.
439
#
440
# Arguments : $refIline (io) - reference to $iline - line to start searching on
441
#             @lines (i) - Array to search through
442
#
443
# Returns   : $addedExtraLines - always 0
444
#             @fileLines - The lines corresponding to the DDL-data-object
445
#
446
# Notes     : 
447
#
448
sub splitOnCreate(\$@)
449
{
450
   my ($refIline, @lines) = @_;
451
 
452
   my @fileLines;
453
 
454
   my $gotFirstCreateLine = 0;
455
 
456
   # Keep adding lines until we reach the second line starting with 'CREATE':
457
   while( $$refIline < scalar(@lines) &&
458
          ( !$gotFirstCreateLine || $lines[$$refIline] !~ m~^\s*CREATE~) )
459
   {
460
       push @fileLines, $lines[$$refIline];
461
       $gotFirstCreateLine = 1 if $lines[$$refIline] =~ m~^\s*CREATE~;
462
       $$refIline++;
463
   } 
464
 
465
   return (0, @fileLines);
466
}
467
 
468
 
469
#-------------------------------------------------------------------------------
470
# Function  : splitOnSemiColon
471
#
472
# Purpose   : Extracts out the next DDL object from a set of lines by
473
#             adding lines until a terminating semicolon is found
474
#
475
# Arguments : $refIline (io) - reference to $iline - line to start searching on
476
#             @lines (i) - Array to search through
477
#
478
# Returns   : $addedExtraLines - always 0
479
#             @fileLines - The lines corresponding to the DDL-data-object
480
#
481
# Notes     : 
482
#
483
sub splitOnSemiColon(\$@)
484
{
485
    my ($refIline, @lines) = @_;
486
 
487
    my @fileLines;
488
 
489
    # Keep adding lines until we get a line ending with a semicolon
490
    while( $$refIline < scalar(@lines) && $lines[$$refIline] !~ m~;\s*$~ )
491
    {
492
        push @fileLines, $lines[$$refIline];
493
        $$refIline++;
494
    }
495
 
496
    # Add the line with the semicolon
497
    if( $$refIline < scalar(@lines) )
498
    {
499
        push @fileLines, $lines[$$refIline];
500
        $$refIline++;
501
    }
502
 
503
    return (0, @fileLines);
504
}
505
 
506
 
507
#-------------------------------------------------------------------------------
508
# Function  : splitOnSlash
509
#
510
# Purpose   : Extracts out the next DDL object from a set of lines by
511
#             adding lines until a terminating slash is found
512
#
513
# Arguments : $refIline (io) - reference to $iline - line to start searching on
514
#             @lines (i) - Array to search through
515
#
516
# Returns   : $addedExtraLines - always 0
517
#             @fileLines - The lines corresponding to the DDL-data-object
518
#
519
# Notes     : 
520
#
521
sub splitOnSlash(\$@)
522
{
523
    my ($refIline, @lines) = @_;
524
 
525
    my @fileLines;
526
 
527
    # Keep adding lines until we get a line starting with a slash
528
    while( $$refIline < scalar(@lines) && $lines[$$refIline] !~ m~^/\s*$~ )
529
    {
530
        push @fileLines, $lines[$$refIline];
531
        $$refIline++;
532
    }
533
 
534
    # Add the line with the slash
535
    if( $$refIline < scalar(@lines) )
536
    {
537
        push @fileLines, $lines[$$refIline];
538
        $$refIline++;
539
    }
540
 
541
    return (0, @fileLines);
542
}
543
 
544
 
545
#-------------------------------------------------------------------------------
546
# Function  : packageBodySplit
547
#
548
# Purpose   : Extracts out the next DDL object from a set of lines by
549
#             adding lines until a terminating slash is found.  It then
550
#             adds extra lines from an 'ALTER PACKAGE' directive
551
#             if such a directive immediately follows the slash.
552
#
553
# Arguments : $refIline (io) - reference to $iline - line to start searching on
554
#             @lines (i) - Array to search through
555
#
556
# Returns   : $addedExtraLines - always 0
557
#             @fileLines - The lines corresponding to the DDL-data-object
558
#
559
# Notes     : 
560
#
561
sub packageBodySplit(\$@)
562
{
563
    my ($refIline, @lines) = @_;
564
 
565
    my ($addedExtraLines, @fileLines) = splitOnSlash($$refIline, @lines);
566
 
567
    # Keep looking for lines if there is a 'ALTER PACKAGE' in the next
568
    # slash-delimited region
569
    if( @fileLines && $$refIline < scalar(@lines) )
570
    {
571
        my $keyWord = $fileLines[0];
572
        $keyWord =~ s~^\s*CREATE\s+PACKAGE\s+BODY\s+".*?"\."(.*?)".*~$1~;
573
 
574
        my @extraLines;
575
        my $jline = $$refIline;
576
 
577
        # Skip over blank lines
578
        $jline++ while( $jline < scalar(@lines) && $lines[$jline] =~ m~^\s*$~ );
579
 
580
        # add lines to @extraLines until we find a slash
581
        while( $jline < scalar(@lines) && $lines[$jline] !~ m~^/\s*$~ )
582
        {
583
            push @extraLines, $lines[$jline];
584
            $jline++;
585
        }
586
 
587
        # add in the line with the slash to @extraLines
588
        if( $jline < scalar(@lines) )
589
        {
590
            push @extraLines, $lines[$jline];
591
            $jline++;
592
        }
593
 
594
        if( @extraLines && 
595
            $extraLines[0] =~ m~^\s*ALTER\s+PACKAGE\s+".*?"\."${keyWord}"~ )
596
        {
597
            # Yes!  Add in the 'ALTER PACKAGE' text
598
            $$refIline = $jline;
599
            push @fileLines, @extraLines;
600
            $addedExtraLines = 1;
601
        }
602
    }
603
 
604
    return ($addedExtraLines, @fileLines); 
605
}
606
 
607
 
608
#-------------------------------------------------------------------------------
609
# Function  : getFilename
610
#
611
# Purpose   : Extracts the name of the .sql file to create from its lines
612
#
613
# Arguments : $subDir (i) - The subdirectory where the .sql file will be created
614
#             @fileLines (i) - The lines to be parsed for the filename
615
#
616
# Returns   : $keyWord - the filename to be created (doesn't have any path attached but
617
#             does have a .sql extension)
618
#
619
# Notes     : This function is tailored specifically for the release manager database, so cannot be
620
#             guaranteed to work for other databases
621
#
622
sub getFilename($@)
623
{
624
    my ($subDir, @fileLines) = @_;
625
 
626
    return "allData.sql" unless defined $wantToExtract{$subDir};
627
 
628
    die "Bug!  No lines scanned for subDir '$subDir'\n" unless scalar(@fileLines);
629
 
630
    my $keyWord = $fileLines[0];
631
 
632
    # Extract out the word that is in the second double quotes
633
    # e.g. for the line:
634
    #CREATE SYNONYM "RELEASE_MANAGER"."APPLICATIONS" FOR "ACCESS_MANAGER"."APPLICATIONS";
635
    # extract out 'APPLICATIONS'
636
    $keyWord =~ s~^.*?".*?"\."(.*?)".*~$1~;
637
 
638
    if( $subDir eq "type/type" )
639
    {
640
        my $firstWord = $fileLines[0];
641
        # $firstWord literally stores the first word of the line
642
        # which for 'type/type' could be 'CREATE' or 'ALTER'
643
        $firstWord =~ s~^\s*(\S+).*~$1~;
644
        $keyWord .= "_$firstWord";
645
    }
646
 
647
    $keyWord .= ".sql";
648
    $keyWord =~ tr~A-Z~a-z~;
649
 
650
    logprint "getFilename() returning '$keyWord' for subdir '$subDir'";
651
 
652
    return $keyWord;
653
}
654
 
655
 
656
#-------------------------------------------------------------------------------
657
# Function  : writeData
658
#
659
# Purpose   : Write out files to disk
660
#
661
# Arguments : $refSubDirs (i) - reference to @subDirs - list of subdirectories having
662
#                               files created.
663
#             $refSubSectionLiness (i) - reference to @subSectionLiness (2D array of lines
664
#                                        per each DDL-data-type)
665
#
666
# Returns   : $linesWritten - a count of the lines written                           
667
#
668
# Notes     : This is a major function as it calls getFileLines() repeatedly to break
669
#             down line-list within @subSectionLiness and also performs a lot of loops.
670
#             So really does a lot more than just writing data.
671
#
672
#             This function also records to file which of the files have had 'extra' bits
673
#             written to them.  (For release manager these are a few 'PACKAGE BODY' functions
674
#             that have had 'ALTER PACKAGE' added on).  This is so that ddlfile.pl can break
675
#             these back into two DDL-data-objects and re-delimit them with a slash.
676
#
677
#             This function also writes out an index file of all filenames created.
678
#             This allows the order in which the files were in the original datapump dump
679
#             file to be recorded.
680
#
681
sub writeData(\@\@)
682
{
683
    my ($refSubDirs, $refSubSectionLiness) = @_;
684
 
685
    my $linesWritten = 0;
686
 
687
    my @filesWithExtras;
688
    my @filenamesCreated;
689
 
690
    for( my $isubdir = 0; $isubdir < scalar(@$refSubDirs); $isubdir++)
691
    {
692
        # Simplify by copying the array of lines for this subdirectory into '@lines'
693
        my @lines = @{ $$refSubSectionLiness[$isubdir] };
694
 
695
        logprint "Working with subdir '$$refSubDirs[$isubdir]'";
696
 
697
        # Recall that wantToExtract hash indicates whether or not we want to
698
        # write one or many (i.e. extract them out) files to each subdirectory.
699
        if( $wantToExtract{$$refSubDirs[$isubdir]} ) 
700
        {
701
            logprint "Going to separate into separate files for subdir '$$refSubDirs[$isubdir]'";
702
 
703
            my $iline = 0;
704
            my %filenames;
705
 
706
            # Keep extracting out lines for files until we run out
707
            until( $iline >= scalar(@lines) )
708
            {
709
                my ($addedExtraLines, @fileLines) = 
710
                    getFileLines( $$refSubDirs[$isubdir], $iline, @lines);
711
 
712
                last if( scalar(@fileLines) == 1 && $fileLines[0] eq "end of data" );
713
 
714
                my $filename = getFilename( $$refSubDirs[$isubdir], @fileLines );
715
                my $fullname = "$destDir/$$refSubDirs[$isubdir]/$filename";
716
 
717
                push @filesWithExtras, "$$refSubDirs[$isubdir]/$filename" if $addedExtraLines;
718
 
719
                die "Duplicate filename '$fullname'" if $filenames{$filename};
720
                $filenames{$filename} = 1;
721
 
722
                writeArray( $fullname, @fileLines);        
723
                push @filenamesCreated, "$$refSubDirs[$isubdir]/$filename";
724
            }
725
        }
726
        else
727
        {
728
            logprint "Writing out just one file in subdir '$$refSubDirs[$isubdir]'";
729
            writeArray( "$destDir/$$refSubDirs[$isubdir]/allData.sql", @lines);
730
            push @filenamesCreated, "$$refSubDirs[$isubdir]/allData.sql";
731
        }
732
 
733
        $linesWritten += scalar( @lines );
734
    }    
735
 
736
    writeArray( "$destDir/bookKeeping/filesWithExtras", @filesWithExtras);
737
    writeArray( "$destDir/bookKeeping/orderedFiles", @filenamesCreated );
738
 
739
    return $linesWritten;
740
}
741
 
742
 
743
#######################################################################
744
# Documentation
745
#######################################################################
746
 
747
=pod
748
 
749
=head1 NAME
750
 
751
schemadump.pl - creates clearcase directory structure from datapump output
752
 
753
=head1 SYNOPSIS
754
 
755
schemadump.pl [options] -src=<srcFile> -dest=<destDir>
756
 
757
Options:
758
 
759
  -help              - brief help message
760
  -man               - Full documentation
761
  -src=srcFile       - File that stores the output of datapump (mandatory)
762
  -dest=destDir      - Directory to unpack to (mandatory)
763
  -log=logFile       - Log messages to this file
764
 
765
=head1 OPTIONS
766
 
767
=over 8
768
 
769
=item B<-help>
770
 
771
Print a brief help message and exits.
772
 
773
=item B<-man>
774
 
775
Prints the manual page and exits.
776
 
777
=item B<-src=srcFile>
778
 
779
Specify what file to extract out the clearcase files from.
780
 
781
=item B<-dest=destDir>
782
 
783
Specify where to unpack the clearcase files to.  This must be an
784
existing directory.
785
 
786
=item B<-log=logFile>
787
 
788
Specify a file to write log messages to.  Default is to just write
789
to the terminal.
790
 
791
=back
792
 
793
=head1 DESCRIPTION
794
 
795
This script is used to break down the output of datapump.  It is
796
designed for use with the release manager database.
797
 
798
=cut