Subversion Repositories DevTools

Rev

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

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