Subversion Repositories DevTools

Rev

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

Rev Author Line No. Line
263 dpurdie 1
########################################################################
6177 dpurdie 2
# COPYRIGHT - VIX IP PTY LTD ("VIX"). ALL RIGHTS RESERVED.
227 dpurdie 3
#
5499 dpurdie 4
# Module name   : create_dpkg.pl
4549 dpurdie 5
# Module type   : Makefile system
263 dpurdie 6
# Compiler(s)   : Perl
4549 dpurdie 7
# Environment(s): jats
227 dpurdie 8
#
263 dpurdie 9
# Description   : This script is used to create a dpkg_archive.
5527 dpurdie 10
#                 Features:
4549 dpurdie 11
#                   * No user interaction
5527 dpurdie 12
#                   * Generates files list for ReleaseNote integration
13
#                   * Can generate package fragemts as a tarball for build system
227 dpurdie 14
#
4549 dpurdie 15
# Usage:        : See POD
227 dpurdie 16
#
263 dpurdie 17
#......................................................................#
227 dpurdie 18
 
4549 dpurdie 19
 
263 dpurdie 20
require 5.008_002;
227 dpurdie 21
 
22
# Include Standard Perl Functions
23
#
24
use strict;
263 dpurdie 25
use warnings;
227 dpurdie 26
use Cwd;
27
use Getopt::Long;
28
use File::Basename;
29
use File::Find;
30
use File::Path;
31
use File::Copy;
32
use Pod::Usage;
263 dpurdie 33
use Digest::MD5;
4549 dpurdie 34
use XML::Simple;
4633 dpurdie 35
use Encode qw(decode encode);
227 dpurdie 36
 
37
use JatsError;
263 dpurdie 38
use JatsEnv;
227 dpurdie 39
use DescPkg;
40
use FileUtils;
5527 dpurdie 41
use JatsSystem;
6177 dpurdie 42
use JatsVersionUtils;
227 dpurdie 43
 
363 dpurdie 44
#
45
#   Under Windows we need the Win32::FileSecurity module
46
#   It only exists under windows
47
#
48
my $Win32 = eval "require Win32::FileSecurity";
49
 
227 dpurdie 50
# define Global variables
51
#
4549 dpurdie 52
my $VERSION = "3.0.0";
227 dpurdie 53
my $PROGNAME = "create_dpkg.pl";
54
 
279 dpurdie 55
# Globals imported from environment
56
#
57
our $GBE_MACHTYPE;
58
our $GBE_HOSTNAME;
59
our $USER;
60
our $GBE_ABT;
227 dpurdie 61
 
279 dpurdie 62
# Global variables
63
#
227 dpurdie 64
my $DPKG_NAME     = "";
65
my $DESC_NAME     = "";
66
my $DPKG_VERSION  = "";
6177 dpurdie 67
my $DPKG_PRJ      = "";
227 dpurdie 68
my $DESCPKG_FILE  = "";
69
my $DESCPKG_TYPE  = "";
70
my $CWD_DIR       = cwd;
71
my $SRC_ROOT;
72
my $DPKG_DIR;
73
my $DPKG_ROOT;
4003 dpurdie 74
my $PKG_BASE;
263 dpurdie 75
my $bad_merge_count = 0;
4424 dpurdie 76
my @bad_symlinks;
4549 dpurdie 77
my @fileList;
78
my $descPkgCount = 0;
5578 dpurdie 79
my @tmpFiles;
227 dpurdie 80
 
81
#
82
#   Option variables
83
#
84
my $opt_help = 0;
85
my $opt_manual = 0;
86
my $opt_verbose = 0;
87
my $opt_quiet = 0;
4549 dpurdie 88
my $opt_delete = 0;
227 dpurdie 89
my $opt_override = 0;
90
my $opt_merge = 0;
91
my $opt_archive;
92
my $opt_generic;
93
my $opt_pname;
94
my $opt_pversion;
95
my $opt_test;
263 dpurdie 96
my $opt_md5 = 1;
4549 dpurdie 97
my $opt_outfile;
98
my $opt_info;
5527 dpurdie 99
my $opt_tarmode;
100
my $opt_testArchive;
5550 dpurdie 101
my $opt_noBuild;
5578 dpurdie 102
my $opt_keepTemp;
227 dpurdie 103
 
104
 
105
#
106
#   Structure to translate -archive=xxx option to archive variable
107
#   These are the various dpkg_archives known to JATS
108
#
4688 dpurdie 109
my %Archive2Var =( 'main'      => 'GBE_DPKG',
110
                   'store'     => 'GBE_DPKG_STORE',
111
                   'cache'     => 'GBE_DPKG_CACHE',
112
                   'local'     => 'GBE_DPKG_LOCAL',
113
                   'sandbox'   => 'GBE_DPKG_SBOX',
114
                   'deploy'    => 'GBE_DPLY',
115
                   'replica'   => 'GBE_DPKG_REPLICA',
6276 dpurdie 116
                   'escrow'    => 'GBE_DPKG_ESCROW',
227 dpurdie 117
                   );
118
 
119
#------------------------------------------------------------------------------
120
#------------------------------------------------------------------------------
121
# Subroutines
122
#------------------------------------------------------------------------------
123
#------------------------------------------------------------------------------
124
 
125
#------------------------------------------------------------------------------
126
sub LogFileOp
127
#
128
# Description:
129
#       This sub-routine is used to generate a consistent informational log
130
#------------------------------------------------------------------------------
131
{
132
    my ($opr, $file) = @_;
5582 dpurdie 133
 
6177 dpurdie 134
    $file =~ s/\Q$DPKG_DIR\E/PKGDIR/;
5532 dpurdie 135
    $file =~ s/\Q$DPKG_ROOT\E/DPKG/;
136
    $file =~ s/\Q$SRC_ROOT\E/PKG/;
5578 dpurdie 137
    $file =~ s/\Q$CWD_DIR\E/CWD/;
227 dpurdie 138
 
139
    Information (sprintf( "%-15s [%s]", $opr, $file));
140
}
141
 
4549 dpurdie 142
#-------------------------------------------------------------------------------
143
# Function        : addFile 
144
#
145
# Description     : Add a file to the list of transferred files
146
#
147
# Inputs          : $type           - File type
148
#                   $source         - Source file - full path
149
#                                     Use local copy, not network copy for file ops
150
#                   $target         - Target file name
151
#                   $md5sum         - Precalculated MD5 sum 
152
#
153
# Returns         : 
154
#
155
sub addFile
156
{
157
    my ($type, $source, $target, $md5sum) = @_;
158
    my %data;
159
 
160
    if ((not defined $md5sum) && ($type eq 'file'))
161
    {
162
        Verbose("Calculate MD5 Digest: $source");
163
        open(my $fh , $source) or Error ("Can't open '$source': $!");
164
        binmode $fh, ':crlf';
165
        $md5sum = Digest::MD5->new->addfile($fh)->hexdigest;
166
        close $fh;
167
    }
168
 
5532 dpurdie 169
    $target =~ s~\Q$DPKG_DIR\E~~;
4549 dpurdie 170
    $target =~ s~^/~~;
171
    $target =~ s~/$~~;
172
 
4633 dpurdie 173
    #
174
    #   Convert from iso-8859-1 into utf-8
175
    #
176
    $target = decode( 'iso-8859-1', $target );
177
    $target = encode( 'utf-8', $target );
178
 
4549 dpurdie 179
    if ($type eq 'dir')
180
    {
181
        $data{path} = $target;
182
    }
183
    else
184
    {
185
        $data{path} = StripFileExt($target);
186
        $data{name} = StripDir($target);
187
        if ($type eq 'file')
188
        {
189
            $data{size} = (stat($source))[7];
190
            $data{md5sum} = $md5sum;
191
        }
192
    }
193
 
194
    $data{fullname} = $target;
195
    $data{type} = $type;
196
    $data{machtype} = $GBE_MACHTYPE;
197
    $data{host} = $GBE_HOSTNAME;
198
 
5499 dpurdie 199
    # Put a nice '/' on the end of the path elements
4549 dpurdie 200
    $data{path} .= '/'
201
        if ( exists ($data{path}) && length($data{path}) > 0);
202
 
203
    push @fileList, \%data;
204
}
205
 
206
#-------------------------------------------------------------------------------
207
# Function        : writeFileInfo 
208
#
209
# Description     : Write out an XML file that contains this processes
210
#                   contribution to the output package 
211
#
5527 dpurdie 212
# Inputs          : $targetDir          - Base directory for the file 
4549 dpurdie 213
#
214
# Returns         : 
215
#
216
sub writeFileInfo
217
{
5527 dpurdie 218
    my ($targetDir) = @_;
4549 dpurdie 219
    my $data;
220
    $data->{file} = \@fileList;
221
 
222
    #
223
    #   Write out sections of XML
224
    #       Want control over the output order
225
    #       Use lots of attributes and only elements for arrays
226
    #       Save as one attribute per line - for readability
227
    #
5527 dpurdie 228
    $opt_outfile = $opt_generic ? "built.files.generic.xml" : "built.files.$GBE_HOSTNAME.xml";
229
    $opt_outfile = catfile( $targetDir, $opt_outfile); 
4549 dpurdie 230
 
231
    LogFileOp ('Meta File', $opt_outfile);
232
    my $xs = XML::Simple->new( NoAttr =>0, AttrIndent => 1 );
233
 
234
    open (my $XML, '>', $opt_outfile) || Error ("Cannot create output file: $opt_outfile", $!);
235
    $xs->XMLout($data, 
236
                'RootName' => 'files', 
237
                'XMLDecl'  => '<?xml version="1.0" encoding="UTF-8"?>',
238
                'OutputFile' => $XML);
239
    close $XML;
240
 
241
}
242
 
227 dpurdie 243
#------------------------------------------------------------------------------
244
sub Init
245
#
246
# Description:
247
#     This function is used to process any command line arguements
248
#     and print the start banner.
249
#
250
#------------------------------------------------------------------------------
251
{
252
    # Process any command line arguements...
253
    my $result = GetOptions (
5527 dpurdie 254
                'help:+'        => \$opt_help,              # flag, multiple use allowed
255
                'manual:3'      => \$opt_help,              # flag
256
                'verbose:+'     => \$opt_verbose,           # flag, multiple use allowed
257
                'override!'     => \$opt_override,          # [no]flag (No longer used. Backward compat with build tool)
258
                'delete!'       => \$opt_delete,            # [no]flag
259
                'merge|m!'      => \$opt_merge,             # [no]flag.
260
                'archive=s'     => \$opt_archive,           # string
261
                'quiet+'        => \$opt_quiet,             # Flag
262
                'generic!'      => \$opt_generic,           # [no]Flag
263
                'pname=s'       => \$opt_pname,             # string
264
                'pversion=s'    => \$opt_pversion,          # string
265
                'test!'         => \$opt_test,              # [no]flag
266
                'md5!'          => \$opt_md5,               # [no]flag
267
                'info!'         => \$opt_info,              # [no]flag
268
                'tarmode!'      => \$opt_tarmode,           # [no]flag
269
                'testArchive'   => \$opt_testArchive,       # [no]flag
5550 dpurdie 270
                'nobuild'       => \$opt_noBuild,           # flag
5578 dpurdie 271
                'keepTemp'      => \$opt_keepTemp,          # flag
227 dpurdie 272
                );
273
 
274
 
275
    #
276
    #   Process help and manual options
277
    #
278
    pod2usage(-verbose => 0, -message => "Version: $VERSION")  if ($opt_help == 1  || ! $result);
279
    pod2usage(-verbose => 1)  if ($opt_help == 2 );
263 dpurdie 280
    pod2usage(-verbose => 2)  if ($opt_help > 2);
227 dpurdie 281
 
282
    #
283
    #   Init the error and message subsystem
284
    #
285
    ErrorConfig( 'name'    =>'CREATE_DPKG',
286
                 'verbose' => $opt_verbose,
287
                 'quiet'   => $opt_quiet );
288
 
289
    if ($opt_verbose)
290
    {
291
       Verbose ("Program: $PROGNAME");
292
       Verbose ("Version: $VERSION");
293
    }
294
 
295
    #
263 dpurdie 296
    #   Needed EnvVars
297
    #
298
    EnvImport ('GBE_MACHTYPE');
279 dpurdie 299
    EnvImport ('GBE_HOSTNAME');
300
    EnvImport ('USER' );
301
    EnvImportOptional ('GBE_ABT', "");
6276 dpurdie 302
    EnvImportOptional ('GBE_DPKG_ESCROW', "");
5578 dpurdie 303
    $CWD_DIR = catdir($CWD_DIR);
263 dpurdie 304
 
4003 dpurdie 305
    #
306
    #   Determine the target archive
307
    #   The default archive is GBE_DPKG, but this may be changed
308
    #
6276 dpurdie 309
    unless ( $opt_archive )
310
    {
311
        $opt_archive = 'main';
312
        $opt_archive = 'escrow' if ($::GBE_DPKG_ESCROW);
313
    }
4003 dpurdie 314
    my $archive_tag = $Archive2Var{$opt_archive};
315
    Error("Unknown archive specified: $opt_archive")
316
        unless ( $archive_tag );
317
    $DPKG_ROOT = $ENV{$archive_tag} || '';
318
    Verbose ("Archive Variable: $archive_tag" );
319
    Verbose2 ("Archive Path: $DPKG_ROOT" );
279 dpurdie 320
 
263 dpurdie 321
    #
5527 dpurdie 322
    #   Append testArchive path
323
    #
324
    $DPKG_ROOT = catdir ($DPKG_ROOT, '.dpkg_archive', 'test_dpkg') if $opt_testArchive;
325
 
326
    #
4003 dpurdie 327
    #   Detect NoBuild marker
328
    #   This will bypass most of the operation of this package
329
    #
5550 dpurdie 330
    $opt_noBuild = 2 if -f 'noBuild.gbe';
331
    if ( $opt_noBuild)
4003 dpurdie 332
    {
6276 dpurdie 333
        Verbose ("NoBuild Marker file found");
4003 dpurdie 334
 
335
        $SRC_ROOT = '';
336
        $DPKG_NAME = 'pkg';
337
        $DESCPKG_FILE = 'descpkg';
338
        $PKG_BASE =$CWD_DIR;
5550 dpurdie 339
 
6281 dpurdie 340
        #
341
        #   Use provided name and version
342
        #   Comparatbility only with ANT build system. Not needed by JATS
343
        #
344
        if ($opt_pname && $opt_pversion) {
345
            $DPKG_NAME = $opt_pname;
346
            $DPKG_VERSION = $opt_pversion;
347
        }
348
 
4003 dpurdie 349
        return;
350
    }
351
 
352
    #
227 dpurdie 353
    #   Check for a "pkg" directory
354
    #   This may be in:
355
    #       1) The deploy directory (DEPLOY) build/deploy/descpkg
356
    #       2) The build directory (ANT)     build/pkg/descpkg
357
    #       3) The current directory (JATS)  pkg/xxxx/descpkg
358
    #
4003 dpurdie 359
    $PKG_BASE = "$CWD_DIR/build/deploy";
227 dpurdie 360
    Verbose2 ("Looking for descpkg: $PKG_BASE");
361
    if ( -f "$PKG_BASE/descpkg" )
362
    {
363
        #
364
        #   This is a deployment package.
365
        #   Force the use of the GBE_DPLY
366
        #
367
        $opt_archive = 'deploy' unless ( $opt_archive );
368
    }
369
    else
370
    {
371
        $PKG_BASE = "$CWD_DIR/build/pkg";
372
        Verbose ("Looking for descpkg: $PKG_BASE");
373
        if ( ! -f  "$PKG_BASE/descpkg" )
374
        {
375
            $PKG_BASE = "$CWD_DIR/pkg";
376
            Verbose ("Looking for descpkg: $PKG_BASE");
377
            Error("Failed to find a package to transfer. Looked in:",
378
                  "./build/deploy",
379
                  "./build/pkg",
380
                  "./pkg"
381
                  )
382
                unless( -d $PKG_BASE );
383
        }
384
    }
385
    Verbose("Package directory: $PKG_BASE");
386
 
387
    Error("Repository location not specified: $archive_tag")
388
        unless $DPKG_ROOT;
389
 
390
    Error("Failed to find Repository: $DPKG_ROOT")
391
        unless ( -d $DPKG_ROOT );
392
 
393
    #   Locate the package
394
    #   Packages are located by looking for a file called descpkg within the
395
    #   main package directory.
396
    #
397
    #   This installation process only handles one such file
398
    #
4549 dpurdie 399
    $descPkgCount = 0;
227 dpurdie 400
    File::Find::find( \&pkgFind, $PKG_BASE);
4549 dpurdie 401
 
402
    if ($descPkgCount > 1 )
403
    {
404
        Warning ("Package contains multiple ($descPkgCount) descpkg files");
405
    }
4003 dpurdie 406
}
227 dpurdie 407
 
4003 dpurdie 408
#-------------------------------------------------------------------------------
409
# Function        : CheckDescPkg
410
#
411
# Description     : Check the descpkg file
412
#
413
# Inputs          : Globals
414
#
415
# Returns         : Will not return on error
416
#
417
sub CheckDescPkg
418
{
6281 dpurdie 419
    #
420
    #   May not need a package description if performing a no-build
421
    #       The package name and version will may be provided on the command line
422
    #   Compatability for ANT builds
423
    #       
424
    #
425
    if ($opt_noBuild) {
426
        if ($opt_pname && $opt_pversion) {
427
            return;
428
        }
429
        Error("NoBuild operation requires package name and version")
430
    }
5550 dpurdie 431
 
6281 dpurdie 432
 
227 dpurdie 433
    # Get the dpkg_archive version number we are  going to create.
434
    #
435
    Error("Descpkg file not found in package directory: $PKG_BASE")
436
        unless ( -f "$DESCPKG_FILE" );
437
 
438
    #
439
    #   Read in the package description and validate essential fields
440
    #
441
    GetDpkgArchiveVersion($DESCPKG_FILE);
442
    unless ( "$DPKG_VERSION" )
443
    {
444
        Error ("Incorrect descpkg content detected.",
445
               "Check JATS build.pl config.");
446
    }
447
 
448
    #
449
    #   Need to support two forms of pkg subdirectory
450
    #       1) packages are in a named subdir within 'pkg'
451
    #       2) package is within 'pkg' or 'deploy'
452
    #
453
    if ( $DPKG_NAME eq 'pkg' || $DPKG_NAME eq 'deploy' )
454
    {
455
        $DPKG_NAME = $DESC_NAME;
456
        unless ( $DESC_NAME )
457
        {
458
            Error ("Cannot determine package name",
459
                   "The packages 'descpkg' file is bad or missing");
460
        }
461
    }
462
    elsif ( $DESC_NAME ne $DPKG_NAME )
463
    {
464
        Error ("Package name MUST match package description",
465
               "Check build.pl and package.pl",
466
               "Package name: $DPKG_NAME",
467
               "Description : $DESC_NAME" );
468
    }
469
 
470
    #
471
    # lets just check to see if we have a version number before
472
    # we proceed.
473
    #
474
    unless ( $DPKG_VERSION )
475
    {
476
        Error("Cannot determine dpkg_archive version number.",
477
              "Check JATS build config.");
478
    }
479
 
6177 dpurdie 480
    my ($pn, $pv, $ps ) = SplitPackage ($DPKG_NAME, $DPKG_VERSION );
481
    $DPKG_PRJ = '.' . $ps if ( $ps ); 
482
 
227 dpurdie 483
    #
484
    #   Sanity test package name and version, if provided
485
    #
486
    if ( $opt_pname )
487
    {
488
        ReportError ("Package Name does not match expected name",
489
                     "Expected: '$opt_pname'",
490
                     "Descpkg : '$DPKG_NAME'") unless ( $DPKG_NAME eq $opt_pname );
491
    }
492
    if ( $opt_pversion )
493
    {
494
        ReportError ("Package Version does not match expected version",
495
                     "Expected: '$opt_pversion'",
496
                     "Descpkg : '$DPKG_VERSION'") unless ( $DPKG_VERSION eq $opt_pversion );
497
    }
498
    ErrorDoExit();
4003 dpurdie 499
}
227 dpurdie 500
 
4003 dpurdie 501
#-------------------------------------------------------------------------------
502
# Function        : ShowInfo
503
#
504
# Description     : Show info to the user
505
#
506
# Inputs          : 
507
#
508
# Returns         : 
509
#
510
sub ShowInfo
511
{
227 dpurdie 512
    #
513
    #   Set up the target directory path and name
514
    #   It will be created later
515
    #
5527 dpurdie 516
    if ($opt_tarmode)
517
    {
518
        $DPKG_DIR = catdir($DPKG_ROOT, '.dpkg_archive', 'fragments');
519
    }
520
    else
521
    {
522
        $DPKG_DIR = catdir($DPKG_ROOT, $DPKG_NAME, $DPKG_VERSION );
523
    }
4003 dpurdie 524
 
227 dpurdie 525
    #
526
    #   Information for the user
527
    #
528
    Information ("---------------------------------------------------------------");
529
    Information ("Dpkg archive creation tool...");
530
    Information ("Version: $VERSION");
531
    Information ("");
532
    Information ("Information:");
6276 dpurdie 533
    Information ("Escrow Build") if ($opt_archive eq 'escrow');
227 dpurdie 534
    Information ("Working dir   = [$CWD_DIR]");
535
    Information ("Package Root  = [$SRC_ROOT]");
4549 dpurdie 536
    Information ("Repository    = [$DPKG_ROOT]");
6276 dpurdie 537
    Information ("                *Non Standard archive") unless ($opt_archive eq 'main' || $opt_archive eq 'escrow');
227 dpurdie 538
    Information ("Target dir    = [$DPKG_DIR]");
539
    Information1("DPKG_NAME     = [$DPKG_NAME]");
540
    Information1("DPKG_VERSION  = [$DPKG_VERSION]");
6177 dpurdie 541
    Information1("DPKG_PRJ      = [$DPKG_PRJ]");
227 dpurdie 542
    Information1("GBE_MACHTYPE  = [$GBE_MACHTYPE]");
279 dpurdie 543
    Information1("GBE_HOSTNAME  = [$GBE_HOSTNAME]");
544
    Information1("GBE_ABT       = [$GBE_ABT]");
545
    Information1("USER          = [$USER]");
5550 dpurdie 546
    Information ("")                                if ( $opt_merge || $opt_delete || $opt_info || $opt_tarmode || $opt_testArchive || $opt_noBuild);
547
    Information ("Opt:NoBuild       = Enabled")     if ( $opt_noBuild );
5527 dpurdie 548
    Information ("Opt:TarMode       = Enabled")     if ( $opt_tarmode );
549
    Information ("Opt:Delete        = Enabled")     if ( $opt_delete );
550
    Information ("Opt:Merge         = Enabled")     if ( $opt_merge );
551
    Information ("Opt:testArchive   = Enabled")     if ( $opt_testArchive );
552
    Information ("Opt:TestMode      = Enabled. No Package Transferred") if ( $opt_test );
553
    Information ("Opt:Info          = Enabled. No Package Transferred") if ( $opt_info );
554
    Warning     ("Sandbox Build     = Yes") if ($ENV{GBE_DPKG_SBOX}) ;
227 dpurdie 555
    Information ("---------------------------------------------------------------");
556
 
369 dpurdie 557
    #
558
    #   If the environment variable GBE_DPKG_SBOX is defined then the package
559
    #   is being built within a development sandbox. In such a sandbox the
560
    #   version numbers of the packages are ignored. Publishing a package
5499 dpurdie 561
    #   from such an environment is certainly not reproducible - so don't allow
369 dpurdie 562
    #   it to happen
563
    #
564
    #   Allow versions of 99.99.99 as these are known to be test versions
565
    #
6276 dpurdie 566
    unless ( $opt_archive eq 'local' || $opt_archive eq 'sandbox' || $opt_testArchive || $::GBE_DPKG_ESCROW)
369 dpurdie 567
    {
568
        if ( $ENV{GBE_DPKG_SBOX} )
569
        {
570
            unless ( $DPKG_VERSION =~ /^99.99.99/ )
571
            {
572
                Error("Cannot not publish a package that has been generated",
573
                   "within a Sandbox as the version of dependent packages",
574
                   "is not guaranteed.",
575
                   "Only version 99.99.99 is allowed");
576
            }
577
        }
578
    }
4003 dpurdie 579
}
369 dpurdie 580
 
581
 
227 dpurdie 582
#------------------------------------------------------------------------------
583
sub pkgFind
584
#
585
# Description:
235 dpurdie 586
#     This subroutine is used to locate the FIRST descpkg file in
227 dpurdie 587
#     the local pkg dir.
588
#
589
#------------------------------------------------------------------------------
590
{
591
    my($item)= "$File::Find::name";
592
    my($file)= File::Basename::basename($item);
593
 
594
    # we get the absolute path from the find, but we only require
595
    # a relative path from the starting dir.
596
    # so our start dir.
597
 
598
    # we need to determine which file we are dealing with
235 dpurdie 599
    if ( ! -d $item && $file =~ /^descpkg$/ )
227 dpurdie 600
    {
4549 dpurdie 601
        $descPkgCount++;
602
 
235 dpurdie 603
        #
604
        #   Only grab the first one
605
        #
606
        if ( $DESCPKG_FILE )
607
        {
5532 dpurdie 608
            $item =~ s~\Q$PKG_BASE\E/~~;
4549 dpurdie 609
            Verbose ("Multiple descpkg files:", $item );
235 dpurdie 610
            return;
611
        }
612
 
227 dpurdie 613
        $DESCPKG_FILE = $item;
614
        my($dir)= File::Basename::dirname($item);
615
        $DPKG_NAME = File::Basename::basename($dir);
5582 dpurdie 616
        $SRC_ROOT = catdir($dir);
227 dpurdie 617
    }
618
}
619
 
620
 
621
#------------------------------------------------------------------------------
622
sub GetDpkgArchiveVersion
623
#
624
# Description:
625
#     This subroutine is used to determine the version of the dpkg_archive.
626
#     We assume that the version number is in the descpkg file.
627
#
628
#     Need to allow for two forms of descpkg. Some one decided that a Java
629
#     Manifest would be a good descpkg file - a long time after the rest of the
630
#     world had been using an existing file format.
631
#
632
#     Lines are tagged
633
#
634
#     Once the version number is determined we set the
635
#     global DPKG_VERSION variable.
636
#
637
#------------------------------------------------------------------------------
638
{
639
    my ($path) = @_;
640
    my $line;
641
    my $type;
642
 
643
    #
644
    #   Use a common routine to parse the package descriptor
645
    #   There are several forms that may need to be processed
646
    #
647
    my $pkg_data = ReadDescpkg( $path );
648
    Error("Failed to open file [$path].") unless $pkg_data;
649
 
650
    $DESC_NAME    = $pkg_data->{'NAME'};
651
    $DPKG_VERSION = $pkg_data->{'VERSION_FULL'};
652
}
653
 
654
#-------------------------------------------------------------------------------
655
# Function        : TransferDescpkg
656
#
657
# Description     : Copy and process the descpkg file to the target
658
#
659
# Inputs          :
660
#
661
# Returns         :
662
#
663
sub TransferDescpkg
664
{
665
    my $result = CopyDescpkg( @_ );
666
    Error("Transfer descpkg: $result") if ( $result );
667
}
668
 
669
#------------------------------------------------------------------------------
670
sub CreateDpkgArchive
671
#
672
# Description:
673
#     This subroutine is used to create the dpkg_archive in the $DPKG_ROOT
674
#     location 
675
#
4969 dpurdie 676
#     We use the global DPKG_ROOT, DPKG_DIR, DPKG_NAME, and DPKG_VERSION
227 dpurdie 677
#     to create the required directory structure.
678
#
679
#     If the dpkg_archive is new (ie not a new version) it is assumed the user
680
#     has access to create the top level dir for the new dpkg_archive.
681
#
682
#     The new dpkg_archive is created with the permission of the user 
683
#     executing this script.
684
#
685
#     If an error ocurs during the dpkg_archive creation the script
686
#     will terminate.
687
#
688
#------------------------------------------------------------------------------
689
{
263 dpurdie 690
    #
227 dpurdie 691
    # first we need to ensure we have the top level directory
692
    #
693
    if ( -d $DPKG_DIR )
694
    {
695
        Warning("Detected previous dpkg_archive [$DPKG_DIR]");
4549 dpurdie 696
        Error ("Package already exists and Package merging not selected")
697
            unless ( $opt_delete || $opt_merge );
263 dpurdie 698
 
699
        #
700
        #   Target exists
701
        #   Unless we are merging, we need to blow the entire tree away
702
        #
703
        unless ( $opt_merge )
704
        {
705
            LogFileOp("Remove Prev Pkg",$DPKG_DIR);
706
            rmtree($DPKG_DIR);
707
 
708
            #
709
            #   At this point the target directory 'should not' exist
710
            #   but it may. Some packges (like JATS) have Unix links within
711
            #   dpkg_archive filesystem. These cannot be deleted under windows
712
            #
713
            #   Not nice, but we live with it.
714
            #
715
            Warning ("Unable to delete previous instance of the package")
716
                if ( -d $DPKG_DIR );
717
        }
227 dpurdie 718
    }
719
    Information("");
720
 
721
    #
722
    #   Create the top level directory
723
    #
724
    mkpath($DPKG_DIR, 0, 0775);
725
 
726
    #
4003 dpurdie 727
    #   Transfer source directory, unless this is a noBuild
728
    #
729
    if ( $SRC_ROOT ne '' )
227 dpurdie 730
    {
4003 dpurdie 731
        # Process the files
732
        #
733
        if ( -d $SRC_ROOT )
734
        {
735
            File::Find::find( \&pkgFind2, $SRC_ROOT );
263 dpurdie 736
 
4424 dpurdie 737
            if (@bad_symlinks)
738
            {
739
                my $msg = "Bad Symlinks: " . scalar @bad_symlinks;
740
                $opt_test ? ReportError($msg, @bad_symlinks) : Warning($msg, @bad_symlinks);
741
            }
742
 
4003 dpurdie 743
            if ( $bad_merge_count )
744
            {
745
                my $msg = "Merged files that differ: $bad_merge_count";
4424 dpurdie 746
                $opt_md5 ? ReportError($msg) : Warning($msg);
4003 dpurdie 747
            }
4424 dpurdie 748
            ErrorDoExit();
4003 dpurdie 749
        }
750
        else
263 dpurdie 751
        {
4003 dpurdie 752
            Error("Failed to find dir [$SRC_ROOT]",
753
                  "Check JATS config.");
263 dpurdie 754
        }
227 dpurdie 755
    }
756
 
757
    #
758
    #   Transfer of data is complete
4424 dpurdie 759
    #       Mark the archive with the build machine to indicate which parts of
760
    #       a multi-machine build have been performed
227 dpurdie 761
    #
5527 dpurdie 762
    my $touchfile = createBuiltFile($DPKG_DIR);
4634 dpurdie 763
    addFile('file', $touchfile, $touchfile);
227 dpurdie 764
 
765
    #
766
    #   If there is a .lnk file in the archive then remove it now that the
767
    #   archive has been transferred. The .lnk files are created in 'local'
768
    #   archives in order to simplify multi-package builds
769
    #
770
    my $link_file = "$DPKG_ROOT/$DPKG_NAME/$DPKG_VERSION.lnk";
771
    if ( -f $link_file )
772
    {
773
        LogFileOp("Removing Link",$link_file);
774
        unlink $link_file;
775
    }
776
 
4969 dpurdie 777
    #
5527 dpurdie 778
    #   Create the MD5 info file
779
    #   
780
    writeFileInfo($DPKG_DIR);
227 dpurdie 781
    return 1;
782
}
783
 
784
#------------------------------------------------------------------------------
785
sub pkgFind2
786
#
787
# Description:
788
#   This subroutine is used to locate all associated pkg files in
789
#   the local pkg dir.
790
#
791
#   This routine is called for each file and directory within the package
792
#   Some files and directories are treated in a special manner
793
#       - Top level directory is ignored
794
#
795
#
796
#
797
#------------------------------------------------------------------------------
798
{
799
    my $item = $File::Find::name;
800
    my $base = File::Basename::basename($item);
801
 
802
    #
803
    #   Calculate the target directory name
804
    #
805
    my $target = $item;
241 dpurdie 806
    $target = $DPKG_DIR . substr ( $item, length ($SRC_ROOT) );
227 dpurdie 807
 
808
    if ( -d $item )
809
    {
810
        #
811
        #   Ignore the top level directory
812
        #   It has already been created
813
        #
814
        return
815
            if ( $item eq $SRC_ROOT );
816
 
817
        #
818
        #   Directories are handled differently
819
        #       - Directories are created with nice permissions
263 dpurdie 820
        #       - If the directory already exists then it is being merged.
227 dpurdie 821
        #
822
        if ( ! -d "$target" )
823
        {
824
            LogFileOp("Creating Dir", $target);
825
            mkpath("$target", 0, 0775);
4549 dpurdie 826
            addFile('dir', $item , $target);
227 dpurdie 827
        }
828
    }
829
    else
830
    {
831
        #
832
        #   File copy
833
        #   If merging then do not overwrite an existing file
834
        #
835
        unless ( $opt_merge && -f $target )
836
        {
837
            if ( $item =~ m~/descpkg$~ )
838
            {
839
                LogFileOp("Rewrite File",$target);
4549 dpurdie 840
                TransferDescpkg( $item, $target );
363 dpurdie 841
                CORE::chmod oct("0664"), $target;
4549 dpurdie 842
                addFile('file', $item, $target);
227 dpurdie 843
            }
844
            else
845
            {
846
                #
847
                #   Copy file to destination
848
                #   If the file is a link, then duplicate the link contents
849
                #   Use: Unix libraries are created as two files:
850
                #        lib.xxxx.so -> libxxxx.so.vv.vv.vv
851
                #
852
                if ( -l $item )
853
                {
6387 dpurdie 854
                    my $niceBase = substr ( $item, 1+length ($SRC_ROOT) );
6276 dpurdie 855
                    if (TestSymlink( $niceBase,$_))
227 dpurdie 856
                    {
6276 dpurdie 857
                        # Don't copy broken Symlinks
858
                        # Perhaps this should be an error - but is will break escrow builds
859
                        #
860
                        LogFileOp("Bad SymLink", $target);
861
                    }
862
                    elsif (-f $item)
863
                    {
4424 dpurdie 864
                        LogFileOp("Copying Link", $target);
865
                        my $link = readlink $item;
866
                        Verbose( "Link: $item, $link");
867
                        symlink ($link, $target );
868
                        unless ( $link && -l $target )
869
                        {
870
                            Error("Failed to copy link [$item] to [$target]: $!");
871
                        }
4549 dpurdie 872
                        addFile('link', $item , $target);
227 dpurdie 873
                    }
874
                }
875
                elsif (File::Copy::copy($item, $target))
876
                {
877
                    LogFileOp("Copying File",$target);
363 dpurdie 878
                    #
879
                    #   Mark the file as executable by all
880
                    #   Under windows, this is tricky
881
                    #
882
                    if ( $Win32 )
883
                    {
884
                        my %hash;
885
                        $hash{Everyone} = Win32::FileSecurity::MakeMask( qw( FULL  ) );
886
                        Win32::FileSecurity::Set( $target, \%hash );
887
                    }
888
                    else
889
                    {
890
                        CORE::chmod oct("0775"), $target;
891
                    }
4549 dpurdie 892
                    addFile('file', $item, $target);
227 dpurdie 893
                }
894
                else
895
                {
896
                    Error("Failed to copy file [$item] to [$target]: $!");
897
                }
898
            }
899
        }
900
        else
901
        {
902
            #
903
            #   Merging packages
904
            #   Ensure that the descpkg file is "touched" so that caches
905
            #   that use this file as a timestamp can be updated
906
            #
907
            if ( $item =~ m~/descpkg$~ )
908
            {
909
                LogFileOp("Touch File",$target);
910
                TouchFile( $target ) && Error ( "Failed to touch: $target" );
4549 dpurdie 911
                addFile('merge', $item, $target);
227 dpurdie 912
            }
913
            else
914
            {
263 dpurdie 915
                #
916
                #   MD5 digest the files that are being merged
917
                #   Ignore version_*.h files as these are generated
918
                #   and may contain different dates and line endings
919
                #
267 dpurdie 920
                #   Don't put the files into 'binmode'
921
                #   Need to handle some level of Unix/DOS file endings
922
                #
923
                #
263 dpurdie 924
                my $msg = "Merge Skip File";
925
                unless ( $target =~ m~/version[^/]*\.h$~ )
926
                {
927
                    $msg = "Merge Test File";
928
                    #
929
                    #   Compare the two files with an MD5
930
                    #
931
                    local *FILE;
932
                    open(FILE, $target) or Error ("Can't open '$target': $!");
267 dpurdie 933
                    binmode FILE, ':crlf';
263 dpurdie 934
                    my $target_md5 = Digest::MD5->new->addfile(*FILE)->hexdigest;
935
                    close FILE;
936
 
937
                    open(FILE, $item) or Error ("Can't open '$item': $!");
267 dpurdie 938
                    binmode FILE, ':crlf';
263 dpurdie 939
                    my $source_md5 = Digest::MD5->new->addfile(*FILE)->hexdigest;
940
                    close FILE;
941
 
942
                    unless ( $source_md5 eq $target_md5 )
943
                    {
944
                        $msg = "DIFF: Merge Test File";
945
                        $bad_merge_count ++;
946
                    }
4549 dpurdie 947
                    addFile('merge', $item, $target, $target_md5);
263 dpurdie 948
                }
949
                LogFileOp($msg,$target);
227 dpurdie 950
            }
951
        }
952
    }
953
}
954
 
955
#-------------------------------------------------------------------------------
5527 dpurdie 956
# Function        : CreateDpkgArchiveTarBall 
957
#
958
# Description     : Similar to CreateDpkgArchive, but it will create a tar file within the target
959
#                   directory.
960
#                   
961
#                   This is used by the build system to:
962
#                       1) Greatly speedup the transfer of packages with a very large number of files
963
#                       2) Remove the need for an multi-filesytem, multi OS atomic lock on the package
964
#                       
965
#                   The build system will process the tarball and create the package archive
966
#                   In doing so it will handle merge errors
967
#
968
# Inputs          : 
969
#
970
# Returns         : 
971
#
972
sub CreateDpkgArchiveTarBall
973
{
974
    Information("");
975
    InitFileUtils();
976
 
977
 
978
    #
979
    #   If a 'noBuild' then create a dummy package directory simply
980
    #   to contain the metadata. 
981
    #   Delete any existing dir of the same name to ensure its clean.
982
    #
983
    if ( $SRC_ROOT eq '' )
984
    {
5582 dpurdie 985
        $SRC_ROOT = catdir(AbsPath('pkg/noBuild'));
5527 dpurdie 986
        RmDirTree ($SRC_ROOT);
987
        mkpath($SRC_ROOT, 0, 0775);
988
    }
989
 
990
    #
991
    #   Mark the archive with the build machine to indicate which parts of
992
    #   a multi-machine build have been performed
993
    #
994
    createBuiltFile($SRC_ROOT);
995
 
996
    #   Process the source directory
997
    #   A NoBuild will contain one metafile
998
    #
999
    if ( -d $SRC_ROOT )
1000
    {
1001
        File::Find::find( \&pkgFindTarBall, $SRC_ROOT );
1002
 
1003
        if (@bad_symlinks)
1004
        {
1005
            my $msg = "Bad Symlinks: " . scalar @bad_symlinks;
1006
            $opt_test ? ReportError($msg, @bad_symlinks) : Warning($msg, @bad_symlinks);
1007
        }
1008
        ErrorDoExit();
1009
    }
1010
    else
1011
    {
1012
        Error("Failed to find dir [$SRC_ROOT]",
1013
              "Check JATS config.");
1014
    }
1015
 
1016
    #
1017
    #   Create the MD5 info file
5582 dpurdie 1018
    #   Mark it as a temp file as it not being created locally
5527 dpurdie 1019
    #   
1020
    writeFileInfo($SRC_ROOT);
5582 dpurdie 1021
    push @tmpFiles, $opt_outfile;
5527 dpurdie 1022
 
1023
    #
1024
    #   Create the target path in the target archive
1025
    #
1026
    LogFileOp ('Creating', $DPKG_DIR);
1027
    mkpath($DPKG_DIR, 0, 0775);
1028
 
1029
    #
5578 dpurdie 1030
    #   Create a tar.gz file an transfer to the final location
5527 dpurdie 1031
    #
5578 dpurdie 1032
    #   Have failed to find a nice windows utility to create a tar.gz
1033
    #       bsdtar - crashed under server 2003
1034
    #       cygwin - design decision. JATS will not include cygwin
1035
    #
5527 dpurdie 1036
    my $tarTarget = join('_', $DPKG_NAME, $DPKG_VERSION, $GBE_HOSTNAME) . '.tar.gz';
1037
    my $tarPath = catfile($DPKG_DIR, $tarTarget);
5578 dpurdie 1038
    $FileUtils::isUnix ? createUnixTar($tarPath) : createWindowsTar($tarPath); 
1039
}
1040
 
1041
#-------------------------------------------------------------------------------
1042
# Function        : createUnixTar  
1043
#
1044
# Description     : Create a tar.gz file under unix
1045
#
1046
# Inputs          : $tarPath    - Place tarfile here 
1047
#                   $SRC_ROOT   - Directory to tar
1048
#
1049
# Returns         : Will not return on error
1050
#
1051
sub createUnixTar
1052
{
1053
    my ($tarPath) = @_;
1054
 
1055
    #
1056
    #   Locate the tar utility
1057
    #   Use gtar if its available otherwise use tar
1058
    #   
1059
    my $tarProg = LocateProgInPath('gtar', '--All');
1060
    $tarProg = LocateProgInPath('tar', '--All') unless $tarProg;
1061
    Error ("Tar utility not found in path") unless $tarProg;
1062
 
1063
    #
1064
    #   Tar and gzip file directly into the final location
5527 dpurdie 1065
    LogFileOp ('TarZip', $tarPath);
1066
    my @tarArgs;
1067
    push @tarArgs, '-v' if IsVerbose(1);
1068
    my $rv = System ('--NoShell', '--NoExit',$tarProg, @tarArgs, '-czf', $tarPath, '-C', $SRC_ROOT, '.' );
1069
    if ($rv)
1070
    {
5578 dpurdie 1071
        push @tmpFiles, $tarPath;
5527 dpurdie 1072
        Error ('Cannot create tarball', "Path:$tarPath");
1073
    }
5578 dpurdie 1074
}
5527 dpurdie 1075
 
5578 dpurdie 1076
#-------------------------------------------------------------------------------
1077
# Function        : createWindowsTar  
1078
#
1079
# Description     : Create a tar.gz file under Windows
1080
#                   Use 7zip (part of JATS)
1081
#                   7zip cannot do this in one step
1082
#                       Create tar file
1083
#                       Create zip file
1084
#
1085
# Inputs          : $tarPath    - Place tarfile here 
1086
#                   $SRC_ROOT   - Directory to tar
1087
#
1088
# Returns         : Will not return on error
1089
#
1090
sub createWindowsTar
1091
{
1092
    my ($tarPath) = @_;
5582 dpurdie 1093
    my @verboseArgs = qw(-bb1);
5578 dpurdie 1094
    my $verboseCopyArg = '9';
1095
    #
1096
    #   Ensure that the target file does not exist
1097
    #   7z cannot ovewrite it
1098
    #
1099
    LogFileOp ('Delete', $tarPath);
1100
    RmDirTree($tarPath) && Error ("Target file cannot be deleted", "Target: $tarPath");
1101
 
1102
    #
1103
    #   Setup NON-verbose arguments for 7zip
1104
    # 
1105
    unless (IsVerbose(1)) {
1106
        @verboseArgs = qw(-bb0 -bso0 -bsp0);
1107
        $verboseCopyArg = '0';
1108
    }
1109
 
1110
    #
1111
    #   Create a tar file of the required output
1112
    #   Create the tar file into a temp file that will be deleted on exit
1113
    #   
1114
    my $tmpTarFile = catfile($CWD_DIR, join('_', $DPKG_NAME, $DPKG_VERSION) . '.tar' );
1115
    Verbose("TempTar: $tmpTarFile");
1116
    RmDirTree($tmpTarFile) && Error ("Target file cannot be deleted", "Target: $tmpTarFile");
1117
    push @tmpFiles, $tmpTarFile;
1118
    LogFileOp ('TempTar', $tmpTarFile);
1119
 
1120
    chdir ($SRC_ROOT) || Error ("Cannot change directory: $?", "Dir: $SRC_ROOT");
1121
    my $rv = System ('--NoShell', '--NoExit','7z.exe', 'a', '-r','-y', @verboseArgs, '-ttar', $tmpTarFile, '.' );
1122
    if ($rv)
1123
    {
1124
        Error ('Cannot create tar file');
1125
    }
1126
    chdir ($CWD_DIR) || Error ("Cannot change directory: $?", "Dir: $CWD_DIR");
1127
 
1128
    #
1129
    #   gzip the tar file to a temp (local) location
1130
    # 
1131
    my $tmpTarGzFile = catfile($CWD_DIR, join('_', $DPKG_NAME, $DPKG_VERSION) . '.tar.gz' );
1132
    Verbose("TempTarGz: $tmpTarGzFile");
1133
    RmDirTree($tmpTarGzFile) && Error ("Target file cannot be deleted", "Target: $tmpTarFile");
1134
    push @tmpFiles, $tmpTarGzFile;
1135
    LogFileOp ('TempTarGz', $tmpTarGzFile);
1136
 
1137
    $rv = System ('--NoShell', '--NoExit','7z.exe', 'a', '-y', @verboseArgs, '-tgzip', $tmpTarGzFile, $tmpTarFile );
1138
    if ($rv)
1139
    {
1140
        Error ('Cannot gzip tar file');
1141
    }
1142
 
1143
    #
1144
    #   Copy the file to the target
1145
    #   Note: Jats internal copy
1146
    #         Args are strange as it was designed to work with makefile stuff
1147
    #
1148
    LogFileOp ('CopyTarZip', $tarPath);
1149
    $rv = System ('--NoShell', '--NoExit','JatsFileUtil.exe', 'c' . $verboseCopyArg, 'copyFile', $tarPath, $tmpTarGzFile, '+w' );
1150
    if ($rv)
1151
    {
1152
        push @tmpFiles, $tarPath;
1153
        Error ('Cannot transfer tarball', "Path:$tarPath");
1154
    }
5527 dpurdie 1155
}
1156
 
5578 dpurdie 1157
 
5527 dpurdie 1158
#-------------------------------------------------------------------------------
1159
# Function        : pkgFindTarBall 
1160
#
1161
# Description     : Used by CreateDpkgArchiveTarBall
1162
#                   File::Find processing function
1163
#                   
1164
#                   This routine is called for each file and directory within the package
1165
#
1166
# Inputs          : As per File::Find 
1167
#
1168
# Returns         : Nothing
1169
#
1170
sub pkgFindTarBall
1171
{
1172
    my $item = $File::Find::name;
1173
    my $base = File::Basename::basename($item);
1174
    my $type;
1175
 
1176
    #
1177
    #   Ignore the top level directory
1178
    #
6294 dpurdie 1179
    return if ( $item eq $SRC_ROOT );
5527 dpurdie 1180
 
1181
    #
1182
    #   Determine type of this item
1183
    #       file
1184
    #       link, badlink
1185
    #       dir
1186
    if ( -l $item)
1187
    {
6294 dpurdie 1188
        my $niceBase = substr ( $item, 1+length ($SRC_ROOT) );
6276 dpurdie 1189
        if (TestSymlink( $niceBase,$_)) {
1190
            #
1191
            # Broken/Bad symlink
5527 dpurdie 1192
            #   Remove it from the 'pkg'
1193
            #   Could try other ways of excluding it from the tar, but this is the simplest  
6276 dpurdie 1194
            LogFileOp("Bad SymLink", $item);
5527 dpurdie 1195
            $type = 'badlink';
1196
            unlink $item;
1197
            return;
6276 dpurdie 1198
 
1199
        } else {
1200
            $type = 'link';
5527 dpurdie 1201
        }
1202
    } elsif ( -f $item) {
1203
        $type = 'file';
1204
    } elsif ( -d $item) {
1205
        $type = 'dir';
1206
    } else {
1207
        Error("Unknown file type. Cannot be packaged");
1208
    }
1209
 
1210
    #
1211
    #   Calculate the target directory name
1212
    #
1213
    my $target = $item;
1214
    $target = $DPKG_DIR . substr ( $item, length ($SRC_ROOT) );
1215
 
1216
    addFile($type, $item, $target);
1217
    LogFileOp('Process',$item);
1218
}
1219
 
1220
#-------------------------------------------------------------------------------
227 dpurdie 1221
# Function        : TestDpkgArchive
1222
#
1223
# Description     : Test the structure of the source achive
1224
#                   Ensure that it has some files
1225
#                   Warn if files are present in the root directory
1226
#
1227
# Inputs          : None
1228
#
1229
# Returns         : Warnings
1230
#
1231
my $test_dir_count = 0;
1232
my $test_file_count = 0;
1233
my @test_root_file = ();
1234
sub TestDpkgArchive
1235
{
1236
    $test_dir_count = 0;
1237
    $test_file_count = 0;
1238
    @test_root_file = ();
1239
 
4003 dpurdie 1240
    if ( $SRC_ROOT ne '' )
1241
    {
1242
        Error("Failed to find dir [$SRC_ROOT]",
1243
              "Check JATS config.") unless ( -d $SRC_ROOT );
1244
 
1245
 
1246
        #
1247
        #   Scan the package counting files and folders
1248
        #
1249
        File::Find::find( \&pkgFind3, $SRC_ROOT );
1250
    }
1251
 
227 dpurdie 1252
    Information ("Package contains:",
1253
                 "Files: $test_file_count",
1254
                 "Dirs: $test_dir_count",
1255
                 );
1256
    #
1257
    #   There shouldn't be any files in the root directory
1258
    #   other than the descpkg and incpkg.
1259
    #
1260
    Warning ("Unexpected files in package root:", @test_root_file)
1261
        if ( @test_root_file  );
4424 dpurdie 1262
 
1263
    Error ("Bad symbolic links found:", @bad_symlinks)
1264
            if ( @bad_symlinks );
1265
 
227 dpurdie 1266
}
1267
 
1268
sub pkgFind3
1269
{
1270
 
1271
    #
1272
    #   Calculate the target directory name
1273
    #
1274
    my $target = $File::Find::dir;
263 dpurdie 1275
    $target = substr ( $target, length ($SRC_ROOT) );
1276
    $target =~ s~^.~~;
227 dpurdie 1277
 
1278
    if ( -d $_ ) {
1279
        $test_dir_count++;
1280
    } else {
1281
        $test_file_count++;
1282
        unless ( $target )
1283
        {
241 dpurdie 1284
            #
1285
            #   Locate files in the package root directory that
1286
            #   are not expected to be there.
1287
            #
6276 dpurdie 1288
            unless ((  $_ eq 'descpkg' ) || ( $_ eq 'incpkg' ) || $_ =~ m~built\.*~)
263 dpurdie 1289
            {
1290
                push @test_root_file, $_;
1291
            }
227 dpurdie 1292
        }
6276 dpurdie 1293
        TestSymlink($target, $_);
1294
    }
1295
}
1296
 
1297
#-------------------------------------------------------------------------------
1298
# Function        : TestSymlink 
1299
#
1300
# Description     : Test a symlink for validity
1301
#                   Current drectory will be $dir
1302
#
1303
# Inputs          : $dir
1304
#                   $fname
1305
#
1306
# Returns         : True if a bad symlink
1307
#                   Add error messages to @bad_symlinks 
1308
#
1309
sub TestSymlink 
1310
{
1311
    my ($dir, $fname) = @_;
1312
    my $msg;
1313
    my $rv = 0;
1314
    my $file = join ('/', $dir, $fname) ;
1315
#Debug0("Testing: $file");
1316
 
1317
    if (-l $fname) {
1318
        my $link = readlink $fname;
1319
 
1320
        if ($link =~ m~^/~) {
1321
            $msg = '[Absolute link not allowed]:' . $file . ' -> ' . $link;
1322
 
1323
        #   Need to test if the symlink escapes the package
1324
        #        } elsif ($link =~ m~/~) {
1325
        #            push @bad_symlinks, '[Symlink out of directory]:' . $file . ' -> ' . $link;
1326
        } elsif (! -f $fname) {
1327
            $msg =  '[Broken Link]:' . $file . ' -> ' . $link;
1328
        } else {
1329
            my @cleanParts = split ('/', CleanPath($link));
1330
            my @dirParts = split('/', $dir);
1331
            my $upCount = 0;
1332
            foreach ( @cleanParts ) {
1333
                if ($_ eq '..') {
1334
                    $upCount++;
1335
                } else {
1336
                    last;
1337
                }
1338
            }
1339
 
1340
            if ($upCount > scalar @dirParts) {
1341
                $msg =  '[Escapes Package]:' . $file . ' -> ' . $link;
1342
            }
4424 dpurdie 1343
        }
227 dpurdie 1344
    }
6276 dpurdie 1345
    if ($msg) {
1346
        push @bad_symlinks, $msg;
1347
        $rv = 1;
1348
    }
1349
 
1350
    return $rv;
1351
 
227 dpurdie 1352
}
1353
 
6276 dpurdie 1354
 
5527 dpurdie 1355
#-------------------------------------------------------------------------------
1356
# Function        : createBuiltFile 
1357
#
1358
# Description     : Create the packages built.xxxx file
1359
#                   Used to track which build machines have contributed to the build 
1360
#
1361
# Inputs          : $targetDir          - Base directory for the file 
1362
#
1363
# Returns         : Full pathname of the generatde file
1364
#
1365
sub createBuiltFile
1366
{
1367
    my ($targetDir) = @_;
1368
 
1369
    #
1370
    #   Mark the archive with the build machine to indicate which parts of
1371
    #   a multi-machine build have been performed
1372
    #
1373
    my $touchfile = catfile( $targetDir, $opt_generic ? 'built.generic' : "built.$GBE_HOSTNAME");
1374
 
1375
    #
1376
    #   Create a string to be appended to the 'built' file
1377
    #   Comma seperated list of (possibly) useful info
1378
    #       Date-Time ( Local and GMT)
1379
    #       machine type, machine name and the user
1380
    #       GBE_ABT value
1381
    #
1382
    #   Having build issues where the file is not seen for a very long time
1383
    #
1384
    my $built_info = localtime() ."," . gmtime() . " GMT,$GBE_MACHTYPE,$GBE_HOSTNAME,$USER,$GBE_ABT";
1385
    LogFileOp("Mark File",$touchfile);
1386
    FileAppend ( $touchfile, $built_info );
1387
 
1388
    return $touchfile;
1389
}
1390
 
5578 dpurdie 1391
#-------------------------------------------------------------------------------
1392
# Function        : END Block 
1393
#
1394
# Description     : Post execution cleanup
1395
#
1396
# Inputs          : 
1397
#
1398
# Returns         : 
1399
#
1400
END
1401
{
1402
    #
1403
    #   Save the programs exit code
1404
    #   This END block may use the 'system' call and this will clobber the value in $?
1405
    #   which is the systems exit code
1406
    #
1407
    Verbose2("Cleanup processing");
1408
    local $?;
5527 dpurdie 1409
 
5578 dpurdie 1410
    #
1411
    #   Delete temp files
1412
    #
1413
    foreach my $tmpFile ( @tmpFiles)
1414
    {
1415
        if ($opt_keepTemp)
1416
        {
1417
            Information("Retain Temp file: " . $tmpFile);
1418
        }
1419
        else
1420
        {
1421
            Verbose ("Delete file: " . $tmpFile);
1422
            RmDirTree ($tmpFile) && Warning("$tmpFile not deleted");
1423
        }
1424
    }
1425
 
1426
}
1427
 
1428
 
227 dpurdie 1429
# ---------------------------------------------------------
1430
# ---------------------------------------------------------
1431
# Main
1432
# ---------------------------------------------------------
1433
# ---------------------------------------------------------
1434
 
1435
 
1436
# Initialise our world
1437
#
1438
Init();
4003 dpurdie 1439
CheckDescPkg();
1440
ShowInfo();
4549 dpurdie 1441
unless ($opt_info)
227 dpurdie 1442
{
4549 dpurdie 1443
    unless ( $opt_test )
227 dpurdie 1444
    {
5527 dpurdie 1445
        if ($opt_tarmode)
1446
        {
6177 dpurdie 1447
            LogFileOp("Creating dpkg_archive tarball:", $DPKG_DIR);
5527 dpurdie 1448
            CreateDpkgArchiveTarBall();
1449
        }
1450
        else
1451
        {
6177 dpurdie 1452
            LogFileOp("Creating dpkg_archive package:", $DPKG_DIR);
5527 dpurdie 1453
            CreateDpkgArchive();
1454
        }
227 dpurdie 1455
    }
4549 dpurdie 1456
    else
1457
    {
1458
        Information("Testing user package.");
1459
        TestDpkgArchive();
1460
    }
227 dpurdie 1461
}
1462
 
1463
# Done
1464
#
1465
Information ("Done.");
1466
exit 0;
1467
 
1468
 
1469
#-------------------------------------------------------------------------------
1470
#   Documentation
1471
#
1472
 
1473
=pod
1474
 
361 dpurdie 1475
=for htmltoc    SYSUTIL::
1476
 
227 dpurdie 1477
=head1 NAME
1478
 
1479
create_dpkg - Create a dpkg_archive entry
1480
 
1481
=head1 SYNOPSIS
1482
 
1483
 jats create_dpkg [options]
1484
 
1485
 Options:
1486
    -help              - Brief help message
1487
    -help -help        - Detailed help message
1488
    -man               - Full documentation
1489
    -quiet             - Suppress progress messages, then warning messages
1490
    -verbose           - Display additional progress messages
4549 dpurdie 1491
    -override          - Deprecated option
1492
    -delete            - Delete any previous version of the package
263 dpurdie 1493
    -[no]merge         - merge with existing version of the package
6276 dpurdie 1494
    -archive=name      - Specify archive (cache, local, main, store, sandbox, deploy, escrow)
227 dpurdie 1495
    -pname=name        - Ensure package is named correctly
1496
    -pversion=version  - Ensure package version is correct
1497
    -generic           - Create a built.generic file
5550 dpurdie 1498
    -noBuild           - Create dummy build files
5527 dpurdie 1499
    -[no]tarmode       - Transfer package as tarball
4549 dpurdie 1500
    -[no]md5           - Use MD5 comparison of merged files(enabled)
5527 dpurdie 1501
 
1502
  Debug and Testing:
263 dpurdie 1503
    -[no]test          - Test package. Do not transfer.
4549 dpurdie 1504
    -[no]info          - Display packaging info. Do not transfer.
5527 dpurdie 1505
    -[no]testArchive   - Perform operations within a test archive
5578 dpurdie 1506
    -keepTemp          - Do not delete temp files
227 dpurdie 1507
 
1508
=head1 OPTIONS
1509
 
1510
=over 8
1511
 
1512
=item B<-help>
1513
 
1514
Print a brief help message and exits.
1515
 
1516
=item B<-help -help>
1517
 
1518
Print a detailed help message with an explanation for each option.
1519
 
1520
=item B<-man>
1521
 
1522
Prints the manual page and exits.
1523
 
1524
=item B<-quiet>
1525
 
1526
This option will suppress almost all of the progress messages, except for a single
1527
copy message. It is intended to be used when the program is called from another
1528
script.
1529
 
1530
=item B<-override>
1531
 
4549 dpurdie 1532
If this option has been deprecated. It has no effect.
1533
 
1534
It is still present to preserve backward compatability with the automated 
1535
build system.
1536
 
1537
=item B<-delete>
1538
 
227 dpurdie 1539
If this option is enabled then any previous version of the target package will
4549 dpurdie 1540
be deleted.
227 dpurdie 1541
 
1542
=item B<-merge>
1543
 
1544
If this option is enabled then the package will be merged with any existing
4549 dpurdie 1545
package. This option is used by the auto build tool to assemble multi-machine 
1546
packages in dpkg_archive.
227 dpurdie 1547
 
1548
=item B<-archive=name>
1549
 
1550
This option specifies the destination archive to be used. The following names
1551
are supported:
1552
 
361 dpurdie 1553
=over 8
1554
 
1555
=item cache
1556
 
1557
The location of the target archive will be taken from C<GBE_DPKG_CACHE>.
1558
 
1559
=item local
1560
 
1561
The location of the target archive will be taken from C<GBE_DPKG_LOCAL>.
1562
 
1563
=item main (default)
1564
 
1565
The location of the target archive will be taken from C<GBE_DPKG>. This is the
1566
default target archive.
1567
 
1568
=item store
1569
 
1570
The location of the target archive will be taken from C<GBE_DPKG_STORE>.
1571
 
4688 dpurdie 1572
=item replica
1573
 
1574
The location of the target archive will be taken from C<GBE_DPKG_REPLICA>.
1575
 
361 dpurdie 1576
=item sandbox
1577
 
1578
The location of the target archive will be taken from C<GBE_DPKG_SBOX>.
1579
 
1580
=item deploy
1581
 
6276 dpurdie 1582
The location of the target archive will be taken from C<GBE_DPLY>.
361 dpurdie 1583
 
6276 dpurdie 1584
Note: This archive is no longer fully supported.
1585
 
1586
=item escrow
1587
 
1588
The location of the target archive will be taken from C<GBE_DPKG_ESCROW>.
1589
 
1590
This is the default target archive if an escrow build is detected.
1591
 
361 dpurdie 1592
=back
1593
 
227 dpurdie 1594
=item B<-pname=name>
1595
 
1596
If this option is provided, the utility will ensure that the package is named
1597
correctly.
1598
 
1599
=item B<-pversion=version>
1600
 
1601
If this option is provided, the utility will ensure that the package version is
1602
that expected.
1603
 
4549 dpurdie 1604
=item B<-generic>
227 dpurdie 1605
 
4549 dpurdie 1606
This option will create a built.generic file, instead of one based on the machine
1607
that actually built the package. This is used by the AutoBuilder toolchain.
227 dpurdie 1608
 
5550 dpurdie 1609
=item B<-noBuild>
1610
 
1611
This option is only used by the build daemons. It is used to create all required 
1612
files to indicate that the build has occured correctly. It will only be used by ANT 
1613
based builds as true JATS builds handle this situation internally.
1614
 
5527 dpurdie 1615
=item B<-[no]tarmode>
1616
 
1617
This option will cause the package to be transferred into the package archive as
1618
a tar ball. Used in the build system to address two issues:
1619
 
1620
=over 4
1621
 
1622
=item 1 
1623
 
1624
Slow speed in copying lots of files from the build machine to the package server.
1625
 
1626
=item 2 
1627
 
1628
Need for cross platform file lock in order to prevent copy collisions.  
1629
 
1630
=back
1631
 
263 dpurdie 1632
=item B<-[no]md5>
1633
 
1634
If package builds are being merged then a validity check is performed using
1635
an MD5 digest over the current and the existing file.
1636
 
1637
By default, it is an error for the user file to differ from the merged file.
1638
 
1639
This option disabled the error. The test is still done and the results are
1640
reported.
1641
 
4549 dpurdie 1642
=item B<-test>
227 dpurdie 1643
 
4549 dpurdie 1644
If this option is enabled the utility will perform initial sanity testing, but
1645
it will not perform the copy.
227 dpurdie 1646
 
4549 dpurdie 1647
=item B<-[no]info>
1648
 
1649
This option will cause the program to display information about the packaging 
1650
process and then exit. 
1651
 
1652
No data will be transferred to the archive.
1653
 
5527 dpurdie 1654
=item B<-[no]testArchive>
1655
 
1656
If this option is enabled then the assembly operation is performed within a test area within
1657
the currently configured dpkg_archive. The test area is a subdirectory 
1658
called C<.dpkg_archive/test_dpkg>
1659
 
1660
This option is intended for testing use only.
1661
 
5578 dpurdie 1662
=item B<-keepTemp>
1663
 
1664
This option will prevent temp files, created by this utilty, from being deleted when the utilty
1665
exists.
1666
 
1667
This option is intended for testing use only.
1668
 
227 dpurdie 1669
=back
1670
 
1671
=head1 DESCRIPTION
1672
 
1673
This utility program is used to transfer a package that has been built into
1674
dpkg_archive. The package is then available for general consumption.
1675
 
4549 dpurdie 1676
The utility will perform several operations in the transfer process. These incude:
1677
 
1678
=over 4
1679
 
1680
=item * 
1681
 
1682
Create a tag file to indicate the machine that has performed the transfer
1683
 
1684
=item * 
1685
 
1686
Create an XML file of files that have been transferred. This file contains information
1687
used by the build system when it releases the package, including: name, size and MD5SUM.
1688
 
1689
=item *
1690
 
1691
Detect file conflicts when different builds are merged into a single package. Header files are 
1692
allowed to differ in line ending style, but other files must not conflict. The package will not be 
1693
reproducible if file conflicts exist.
1694
 
5527 dpurdie 1695
In 'tarmode' the package merging needs to be done by another utility.
1696
 
4549 dpurdie 1697
=item *
1698
 
1699
Suppress dead symbolic links. A valid symlink will be preserved, but invalid links will be 
1700
removed from the transferred image.
1701
 
1702
=back
1703
 
227 dpurdie 1704
=head2 PACKAGE LOCATION
1705
 
1706
The utility will locate a package by examining the following directores for
1707
the package description file(descpkg).
1708
 
1709
=over 8
1710
 
1711
=item ./build/deploy
1712
 
1713
This format is generated by the deployment builds. The default target archive
1714
will be taken from the environment variable GBE_DPLY.
1715
 
1716
=item ./pkg
1717
 
1718
This format is generated by JATS builds.
1719
 
1720
=item ./build/pkg
1721
 
1722
This format is generated by ANT builds.
1723
 
5527 dpurdie 1724
=item ./pkg/noBuild
1725
 
1726
This format is used internally by this utilty. It will be generated by the build system 
1727
in cases where there is no build to be performs on the current machine.
1728
 
227 dpurdie 1729
=back
1730
 
1731
The program should be run in the same directory as the build control files as
1732
the package subdirectory will be created in that directory.
1733
 
1734
=head1 EXAMPLE
1735
 
1736
=head2 jats create_dpkg
1737
 
1738
This will locate a generated package and install it into the dpkg_archive repository.
1739
 
1740
=cut
1741