Subversion Repositories DevTools

Rev

Rev 6276 | Rev 6294 | 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);
6276 dpurdie 801
    my $niceBase = substr ( $item, 1+length ($SRC_ROOT) );
227 dpurdie 802
 
803
    #
804
    #   Calculate the target directory name
805
    #
806
    my $target = $item;
241 dpurdie 807
    $target = $DPKG_DIR . substr ( $item, length ($SRC_ROOT) );
227 dpurdie 808
 
809
    if ( -d $item )
810
    {
811
        #
812
        #   Ignore the top level directory
813
        #   It has already been created
814
        #
815
        return
816
            if ( $item eq $SRC_ROOT );
817
 
818
        #
819
        #   Directories are handled differently
820
        #       - Directories are created with nice permissions
263 dpurdie 821
        #       - If the directory already exists then it is being merged.
227 dpurdie 822
        #
823
        if ( ! -d "$target" )
824
        {
825
            LogFileOp("Creating Dir", $target);
826
            mkpath("$target", 0, 0775);
4549 dpurdie 827
            addFile('dir', $item , $target);
227 dpurdie 828
        }
829
    }
830
    else
831
    {
832
        #
833
        #   File copy
834
        #   If merging then do not overwrite an existing file
835
        #
836
        unless ( $opt_merge && -f $target )
837
        {
838
            if ( $item =~ m~/descpkg$~ )
839
            {
840
                LogFileOp("Rewrite File",$target);
4549 dpurdie 841
                TransferDescpkg( $item, $target );
363 dpurdie 842
                CORE::chmod oct("0664"), $target;
4549 dpurdie 843
                addFile('file', $item, $target);
227 dpurdie 844
            }
845
            else
846
            {
847
                #
848
                #   Copy file to destination
849
                #   If the file is a link, then duplicate the link contents
850
                #   Use: Unix libraries are created as two files:
851
                #        lib.xxxx.so -> libxxxx.so.vv.vv.vv
852
                #
853
                if ( -l $item )
854
                {
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);
6276 dpurdie 1174
    my $niceBase = substr ( $item, 1+length ($SRC_ROOT) );
5527 dpurdie 1175
    my $type;
1176
 
1177
    #
1178
    #   Ignore the top level directory
1179
    #
1180
    return
1181
        if ( $item eq $SRC_ROOT );
1182
 
1183
    #
1184
    #   Determine type of this item
1185
    #       file
1186
    #       link, badlink
1187
    #       dir
1188
    if ( -l $item)
1189
    {
6276 dpurdie 1190
        if (TestSymlink( $niceBase,$_)) {
1191
            #
1192
            # Broken/Bad symlink
5527 dpurdie 1193
            #   Remove it from the 'pkg'
1194
            #   Could try other ways of excluding it from the tar, but this is the simplest  
6276 dpurdie 1195
            LogFileOp("Bad SymLink", $item);
5527 dpurdie 1196
            $type = 'badlink';
1197
            unlink $item;
1198
            return;
6276 dpurdie 1199
 
1200
        } else {
1201
            $type = 'link';
5527 dpurdie 1202
        }
1203
    } elsif ( -f $item) {
1204
        $type = 'file';
1205
    } elsif ( -d $item) {
1206
        $type = 'dir';
1207
    } else {
1208
        Error("Unknown file type. Cannot be packaged");
1209
    }
1210
 
1211
    #
1212
    #   Calculate the target directory name
1213
    #
1214
    my $target = $item;
1215
    $target = $DPKG_DIR . substr ( $item, length ($SRC_ROOT) );
1216
 
1217
    addFile($type, $item, $target);
1218
    LogFileOp('Process',$item);
1219
}
1220
 
1221
#-------------------------------------------------------------------------------
227 dpurdie 1222
# Function        : TestDpkgArchive
1223
#
1224
# Description     : Test the structure of the source achive
1225
#                   Ensure that it has some files
1226
#                   Warn if files are present in the root directory
1227
#
1228
# Inputs          : None
1229
#
1230
# Returns         : Warnings
1231
#
1232
my $test_dir_count = 0;
1233
my $test_file_count = 0;
1234
my @test_root_file = ();
1235
sub TestDpkgArchive
1236
{
1237
    $test_dir_count = 0;
1238
    $test_file_count = 0;
1239
    @test_root_file = ();
1240
 
4003 dpurdie 1241
    if ( $SRC_ROOT ne '' )
1242
    {
1243
        Error("Failed to find dir [$SRC_ROOT]",
1244
              "Check JATS config.") unless ( -d $SRC_ROOT );
1245
 
1246
 
1247
        #
1248
        #   Scan the package counting files and folders
1249
        #
1250
        File::Find::find( \&pkgFind3, $SRC_ROOT );
1251
    }
1252
 
227 dpurdie 1253
    Information ("Package contains:",
1254
                 "Files: $test_file_count",
1255
                 "Dirs: $test_dir_count",
1256
                 );
1257
    #
1258
    #   There shouldn't be any files in the root directory
1259
    #   other than the descpkg and incpkg.
1260
    #
1261
    Warning ("Unexpected files in package root:", @test_root_file)
1262
        if ( @test_root_file  );
4424 dpurdie 1263
 
1264
    Error ("Bad symbolic links found:", @bad_symlinks)
1265
            if ( @bad_symlinks );
1266
 
227 dpurdie 1267
}
1268
 
1269
sub pkgFind3
1270
{
1271
 
1272
    #
1273
    #   Calculate the target directory name
1274
    #
1275
    my $target = $File::Find::dir;
263 dpurdie 1276
    $target = substr ( $target, length ($SRC_ROOT) );
1277
    $target =~ s~^.~~;
227 dpurdie 1278
 
1279
    if ( -d $_ ) {
1280
        $test_dir_count++;
1281
    } else {
1282
        $test_file_count++;
1283
        unless ( $target )
1284
        {
241 dpurdie 1285
            #
1286
            #   Locate files in the package root directory that
1287
            #   are not expected to be there.
1288
            #
6276 dpurdie 1289
            unless ((  $_ eq 'descpkg' ) || ( $_ eq 'incpkg' ) || $_ =~ m~built\.*~)
263 dpurdie 1290
            {
1291
                push @test_root_file, $_;
1292
            }
227 dpurdie 1293
        }
6276 dpurdie 1294
        TestSymlink($target, $_);
1295
    }
1296
}
1297
 
1298
#-------------------------------------------------------------------------------
1299
# Function        : TestSymlink 
1300
#
1301
# Description     : Test a symlink for validity
1302
#                   Current drectory will be $dir
1303
#
1304
# Inputs          : $dir
1305
#                   $fname
1306
#
1307
# Returns         : True if a bad symlink
1308
#                   Add error messages to @bad_symlinks 
1309
#
1310
sub TestSymlink 
1311
{
1312
    my ($dir, $fname) = @_;
1313
    my $msg;
1314
    my $rv = 0;
1315
    my $file = join ('/', $dir, $fname) ;
1316
#Debug0("Testing: $file");
1317
 
1318
    if (-l $fname) {
1319
        my $link = readlink $fname;
1320
 
1321
        if ($link =~ m~^/~) {
1322
            $msg = '[Absolute link not allowed]:' . $file . ' -> ' . $link;
1323
 
1324
        #   Need to test if the symlink escapes the package
1325
        #        } elsif ($link =~ m~/~) {
1326
        #            push @bad_symlinks, '[Symlink out of directory]:' . $file . ' -> ' . $link;
1327
        } elsif (! -f $fname) {
1328
            $msg =  '[Broken Link]:' . $file . ' -> ' . $link;
1329
        } else {
1330
            my @cleanParts = split ('/', CleanPath($link));
1331
            my @dirParts = split('/', $dir);
1332
            my $upCount = 0;
1333
            foreach ( @cleanParts ) {
1334
                if ($_ eq '..') {
1335
                    $upCount++;
1336
                } else {
1337
                    last;
1338
                }
1339
            }
1340
 
1341
            if ($upCount > scalar @dirParts) {
1342
                $msg =  '[Escapes Package]:' . $file . ' -> ' . $link;
1343
            }
4424 dpurdie 1344
        }
227 dpurdie 1345
    }
6276 dpurdie 1346
    if ($msg) {
1347
        push @bad_symlinks, $msg;
1348
        $rv = 1;
1349
    }
1350
 
1351
    return $rv;
1352
 
227 dpurdie 1353
}
1354
 
6276 dpurdie 1355
 
5527 dpurdie 1356
#-------------------------------------------------------------------------------
1357
# Function        : createBuiltFile 
1358
#
1359
# Description     : Create the packages built.xxxx file
1360
#                   Used to track which build machines have contributed to the build 
1361
#
1362
# Inputs          : $targetDir          - Base directory for the file 
1363
#
1364
# Returns         : Full pathname of the generatde file
1365
#
1366
sub createBuiltFile
1367
{
1368
    my ($targetDir) = @_;
1369
 
1370
    #
1371
    #   Mark the archive with the build machine to indicate which parts of
1372
    #   a multi-machine build have been performed
1373
    #
1374
    my $touchfile = catfile( $targetDir, $opt_generic ? 'built.generic' : "built.$GBE_HOSTNAME");
1375
 
1376
    #
1377
    #   Create a string to be appended to the 'built' file
1378
    #   Comma seperated list of (possibly) useful info
1379
    #       Date-Time ( Local and GMT)
1380
    #       machine type, machine name and the user
1381
    #       GBE_ABT value
1382
    #
1383
    #   Having build issues where the file is not seen for a very long time
1384
    #
1385
    my $built_info = localtime() ."," . gmtime() . " GMT,$GBE_MACHTYPE,$GBE_HOSTNAME,$USER,$GBE_ABT";
1386
    LogFileOp("Mark File",$touchfile);
1387
    FileAppend ( $touchfile, $built_info );
1388
 
1389
    return $touchfile;
1390
}
1391
 
5578 dpurdie 1392
#-------------------------------------------------------------------------------
1393
# Function        : END Block 
1394
#
1395
# Description     : Post execution cleanup
1396
#
1397
# Inputs          : 
1398
#
1399
# Returns         : 
1400
#
1401
END
1402
{
1403
    #
1404
    #   Save the programs exit code
1405
    #   This END block may use the 'system' call and this will clobber the value in $?
1406
    #   which is the systems exit code
1407
    #
1408
    Verbose2("Cleanup processing");
1409
    local $?;
5527 dpurdie 1410
 
5578 dpurdie 1411
    #
1412
    #   Delete temp files
1413
    #
1414
    foreach my $tmpFile ( @tmpFiles)
1415
    {
1416
        if ($opt_keepTemp)
1417
        {
1418
            Information("Retain Temp file: " . $tmpFile);
1419
        }
1420
        else
1421
        {
1422
            Verbose ("Delete file: " . $tmpFile);
1423
            RmDirTree ($tmpFile) && Warning("$tmpFile not deleted");
1424
        }
1425
    }
1426
 
1427
}
1428
 
1429
 
227 dpurdie 1430
# ---------------------------------------------------------
1431
# ---------------------------------------------------------
1432
# Main
1433
# ---------------------------------------------------------
1434
# ---------------------------------------------------------
1435
 
1436
 
1437
# Initialise our world
1438
#
1439
Init();
4003 dpurdie 1440
CheckDescPkg();
1441
ShowInfo();
4549 dpurdie 1442
unless ($opt_info)
227 dpurdie 1443
{
4549 dpurdie 1444
    unless ( $opt_test )
227 dpurdie 1445
    {
5527 dpurdie 1446
        if ($opt_tarmode)
1447
        {
6177 dpurdie 1448
            LogFileOp("Creating dpkg_archive tarball:", $DPKG_DIR);
5527 dpurdie 1449
            CreateDpkgArchiveTarBall();
1450
        }
1451
        else
1452
        {
6177 dpurdie 1453
            LogFileOp("Creating dpkg_archive package:", $DPKG_DIR);
5527 dpurdie 1454
            CreateDpkgArchive();
1455
        }
227 dpurdie 1456
    }
4549 dpurdie 1457
    else
1458
    {
1459
        Information("Testing user package.");
1460
        TestDpkgArchive();
1461
    }
227 dpurdie 1462
}
1463
 
1464
# Done
1465
#
1466
Information ("Done.");
1467
exit 0;
1468
 
1469
 
1470
#-------------------------------------------------------------------------------
1471
#   Documentation
1472
#
1473
 
1474
=pod
1475
 
361 dpurdie 1476
=for htmltoc    SYSUTIL::
1477
 
227 dpurdie 1478
=head1 NAME
1479
 
1480
create_dpkg - Create a dpkg_archive entry
1481
 
1482
=head1 SYNOPSIS
1483
 
1484
 jats create_dpkg [options]
1485
 
1486
 Options:
1487
    -help              - Brief help message
1488
    -help -help        - Detailed help message
1489
    -man               - Full documentation
1490
    -quiet             - Suppress progress messages, then warning messages
1491
    -verbose           - Display additional progress messages
4549 dpurdie 1492
    -override          - Deprecated option
1493
    -delete            - Delete any previous version of the package
263 dpurdie 1494
    -[no]merge         - merge with existing version of the package
6276 dpurdie 1495
    -archive=name      - Specify archive (cache, local, main, store, sandbox, deploy, escrow)
227 dpurdie 1496
    -pname=name        - Ensure package is named correctly
1497
    -pversion=version  - Ensure package version is correct
1498
    -generic           - Create a built.generic file
5550 dpurdie 1499
    -noBuild           - Create dummy build files
5527 dpurdie 1500
    -[no]tarmode       - Transfer package as tarball
4549 dpurdie 1501
    -[no]md5           - Use MD5 comparison of merged files(enabled)
5527 dpurdie 1502
 
1503
  Debug and Testing:
263 dpurdie 1504
    -[no]test          - Test package. Do not transfer.
4549 dpurdie 1505
    -[no]info          - Display packaging info. Do not transfer.
5527 dpurdie 1506
    -[no]testArchive   - Perform operations within a test archive
5578 dpurdie 1507
    -keepTemp          - Do not delete temp files
227 dpurdie 1508
 
1509
=head1 OPTIONS
1510
 
1511
=over 8
1512
 
1513
=item B<-help>
1514
 
1515
Print a brief help message and exits.
1516
 
1517
=item B<-help -help>
1518
 
1519
Print a detailed help message with an explanation for each option.
1520
 
1521
=item B<-man>
1522
 
1523
Prints the manual page and exits.
1524
 
1525
=item B<-quiet>
1526
 
1527
This option will suppress almost all of the progress messages, except for a single
1528
copy message. It is intended to be used when the program is called from another
1529
script.
1530
 
1531
=item B<-override>
1532
 
4549 dpurdie 1533
If this option has been deprecated. It has no effect.
1534
 
1535
It is still present to preserve backward compatability with the automated 
1536
build system.
1537
 
1538
=item B<-delete>
1539
 
227 dpurdie 1540
If this option is enabled then any previous version of the target package will
4549 dpurdie 1541
be deleted.
227 dpurdie 1542
 
1543
=item B<-merge>
1544
 
1545
If this option is enabled then the package will be merged with any existing
4549 dpurdie 1546
package. This option is used by the auto build tool to assemble multi-machine 
1547
packages in dpkg_archive.
227 dpurdie 1548
 
1549
=item B<-archive=name>
1550
 
1551
This option specifies the destination archive to be used. The following names
1552
are supported:
1553
 
361 dpurdie 1554
=over 8
1555
 
1556
=item cache
1557
 
1558
The location of the target archive will be taken from C<GBE_DPKG_CACHE>.
1559
 
1560
=item local
1561
 
1562
The location of the target archive will be taken from C<GBE_DPKG_LOCAL>.
1563
 
1564
=item main (default)
1565
 
1566
The location of the target archive will be taken from C<GBE_DPKG>. This is the
1567
default target archive.
1568
 
1569
=item store
1570
 
1571
The location of the target archive will be taken from C<GBE_DPKG_STORE>.
1572
 
4688 dpurdie 1573
=item replica
1574
 
1575
The location of the target archive will be taken from C<GBE_DPKG_REPLICA>.
1576
 
361 dpurdie 1577
=item sandbox
1578
 
1579
The location of the target archive will be taken from C<GBE_DPKG_SBOX>.
1580
 
1581
=item deploy
1582
 
6276 dpurdie 1583
The location of the target archive will be taken from C<GBE_DPLY>.
361 dpurdie 1584
 
6276 dpurdie 1585
Note: This archive is no longer fully supported.
1586
 
1587
=item escrow
1588
 
1589
The location of the target archive will be taken from C<GBE_DPKG_ESCROW>.
1590
 
1591
This is the default target archive if an escrow build is detected.
1592
 
361 dpurdie 1593
=back
1594
 
227 dpurdie 1595
=item B<-pname=name>
1596
 
1597
If this option is provided, the utility will ensure that the package is named
1598
correctly.
1599
 
1600
=item B<-pversion=version>
1601
 
1602
If this option is provided, the utility will ensure that the package version is
1603
that expected.
1604
 
4549 dpurdie 1605
=item B<-generic>
227 dpurdie 1606
 
4549 dpurdie 1607
This option will create a built.generic file, instead of one based on the machine
1608
that actually built the package. This is used by the AutoBuilder toolchain.
227 dpurdie 1609
 
5550 dpurdie 1610
=item B<-noBuild>
1611
 
1612
This option is only used by the build daemons. It is used to create all required 
1613
files to indicate that the build has occured correctly. It will only be used by ANT 
1614
based builds as true JATS builds handle this situation internally.
1615
 
5527 dpurdie 1616
=item B<-[no]tarmode>
1617
 
1618
This option will cause the package to be transferred into the package archive as
1619
a tar ball. Used in the build system to address two issues:
1620
 
1621
=over 4
1622
 
1623
=item 1 
1624
 
1625
Slow speed in copying lots of files from the build machine to the package server.
1626
 
1627
=item 2 
1628
 
1629
Need for cross platform file lock in order to prevent copy collisions.  
1630
 
1631
=back
1632
 
263 dpurdie 1633
=item B<-[no]md5>
1634
 
1635
If package builds are being merged then a validity check is performed using
1636
an MD5 digest over the current and the existing file.
1637
 
1638
By default, it is an error for the user file to differ from the merged file.
1639
 
1640
This option disabled the error. The test is still done and the results are
1641
reported.
1642
 
4549 dpurdie 1643
=item B<-test>
227 dpurdie 1644
 
4549 dpurdie 1645
If this option is enabled the utility will perform initial sanity testing, but
1646
it will not perform the copy.
227 dpurdie 1647
 
4549 dpurdie 1648
=item B<-[no]info>
1649
 
1650
This option will cause the program to display information about the packaging 
1651
process and then exit. 
1652
 
1653
No data will be transferred to the archive.
1654
 
5527 dpurdie 1655
=item B<-[no]testArchive>
1656
 
1657
If this option is enabled then the assembly operation is performed within a test area within
1658
the currently configured dpkg_archive. The test area is a subdirectory 
1659
called C<.dpkg_archive/test_dpkg>
1660
 
1661
This option is intended for testing use only.
1662
 
5578 dpurdie 1663
=item B<-keepTemp>
1664
 
1665
This option will prevent temp files, created by this utilty, from being deleted when the utilty
1666
exists.
1667
 
1668
This option is intended for testing use only.
1669
 
227 dpurdie 1670
=back
1671
 
1672
=head1 DESCRIPTION
1673
 
1674
This utility program is used to transfer a package that has been built into
1675
dpkg_archive. The package is then available for general consumption.
1676
 
4549 dpurdie 1677
The utility will perform several operations in the transfer process. These incude:
1678
 
1679
=over 4
1680
 
1681
=item * 
1682
 
1683
Create a tag file to indicate the machine that has performed the transfer
1684
 
1685
=item * 
1686
 
1687
Create an XML file of files that have been transferred. This file contains information
1688
used by the build system when it releases the package, including: name, size and MD5SUM.
1689
 
1690
=item *
1691
 
1692
Detect file conflicts when different builds are merged into a single package. Header files are 
1693
allowed to differ in line ending style, but other files must not conflict. The package will not be 
1694
reproducible if file conflicts exist.
1695
 
5527 dpurdie 1696
In 'tarmode' the package merging needs to be done by another utility.
1697
 
4549 dpurdie 1698
=item *
1699
 
1700
Suppress dead symbolic links. A valid symlink will be preserved, but invalid links will be 
1701
removed from the transferred image.
1702
 
1703
=back
1704
 
227 dpurdie 1705
=head2 PACKAGE LOCATION
1706
 
1707
The utility will locate a package by examining the following directores for
1708
the package description file(descpkg).
1709
 
1710
=over 8
1711
 
1712
=item ./build/deploy
1713
 
1714
This format is generated by the deployment builds. The default target archive
1715
will be taken from the environment variable GBE_DPLY.
1716
 
1717
=item ./pkg
1718
 
1719
This format is generated by JATS builds.
1720
 
1721
=item ./build/pkg
1722
 
1723
This format is generated by ANT builds.
1724
 
5527 dpurdie 1725
=item ./pkg/noBuild
1726
 
1727
This format is used internally by this utilty. It will be generated by the build system 
1728
in cases where there is no build to be performs on the current machine.
1729
 
227 dpurdie 1730
=back
1731
 
1732
The program should be run in the same directory as the build control files as
1733
the package subdirectory will be created in that directory.
1734
 
1735
=head1 EXAMPLE
1736
 
1737
=head2 jats create_dpkg
1738
 
1739
This will locate a generated package and install it into the dpkg_archive repository.
1740
 
1741
=cut
1742