Subversion Repositories DevTools

Rev

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