Subversion Repositories DevTools

Rev

Go to most recent revision | Details | 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
#
4549 dpurdie 4
# Module name   : create_dpkg2.pl
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.
4549 dpurdie 10
#                 Based on create_dpkg with following changes
11
#                   * No user interaction
12
#                   * Generates files list for ReleaseNote integration 
227 dpurdie 13
#
4549 dpurdie 14
# Usage:        : See POD
227 dpurdie 15
#
263 dpurdie 16
#......................................................................#
227 dpurdie 17
 
4549 dpurdie 18
 
263 dpurdie 19
require 5.008_002;
227 dpurdie 20
 
21
# Include Standard Perl Functions
22
#
23
use strict;
263 dpurdie 24
use warnings;
227 dpurdie 25
use Cwd;
26
use Getopt::Long;
27
use File::Basename;
28
use File::Find;
29
use File::Path;
30
use File::Copy;
31
use Pod::Usage;
263 dpurdie 32
use Digest::MD5;
4549 dpurdie 33
use XML::Simple;
4633 dpurdie 34
use Encode qw(decode encode);
227 dpurdie 35
 
36
use JatsError;
263 dpurdie 37
use JatsEnv;
227 dpurdie 38
use DescPkg;
39
use FileUtils;
40
 
363 dpurdie 41
#
42
#   Under Windows we need the Win32::FileSecurity module
43
#   It only exists under windows
44
#
45
my $Win32 = eval "require Win32::FileSecurity";
46
 
227 dpurdie 47
# define Global variables
48
#
4549 dpurdie 49
my $VERSION = "3.0.0";
227 dpurdie 50
my $PROGNAME = "create_dpkg.pl";
51
 
279 dpurdie 52
# Globals imported from environment
53
#
54
our $GBE_MACHTYPE;
55
our $GBE_HOSTNAME;
56
our $USER;
57
our $GBE_ABT;
227 dpurdie 58
 
279 dpurdie 59
# Global variables
60
#
227 dpurdie 61
my $DPKG_NAME     = "";
62
my $DESC_NAME     = "";
63
my $DPKG_VERSION  = "";
64
my $DESCPKG_FILE  = "";
65
my $DESCPKG_TYPE  = "";
66
my $CWD_DIR       = cwd;
67
my $SRC_ROOT;
68
my $DPKG_DIR;
69
my $DPKG_ROOT;
4003 dpurdie 70
my $PKG_BASE;
263 dpurdie 71
my $bad_merge_count = 0;
4424 dpurdie 72
my @bad_symlinks;
4549 dpurdie 73
my @fileList;
74
my $descPkgCount = 0;
227 dpurdie 75
 
76
#
77
#   Option variables
78
#
79
my $opt_help = 0;
80
my $opt_manual = 0;
81
my $opt_verbose = 0;
82
my $opt_quiet = 0;
4549 dpurdie 83
my $opt_delete = 0;
227 dpurdie 84
my $opt_override = 0;
85
my $opt_merge = 0;
86
my $opt_archive;
87
my $opt_generic;
88
my $opt_pname;
89
my $opt_pversion;
90
my $opt_test;
263 dpurdie 91
my $opt_md5 = 1;
4549 dpurdie 92
my $opt_outfile;
93
my $opt_info;
227 dpurdie 94
 
95
 
96
#
97
#   Structure to translate -archive=xxx option to archive variable
98
#   These are the various dpkg_archives known to JATS
99
#
100
my %Archive2Var =( 'main'       =>  'GBE_DPKG',
101
                   'store'      =>  'GBE_DPKG_STORE',
102
                   'cache'      =>  'GBE_DPKG_CACHE',
103
                   'local'      =>  'GBE_DPKG_LOCAL',
104
                   'sandbox'    =>  'GBE_DPKG_SBOX',
105
                   'deploy'     =>  'GBE_DPLY',
106
                   );
107
 
108
#------------------------------------------------------------------------------
109
#------------------------------------------------------------------------------
110
# Subroutines
111
#------------------------------------------------------------------------------
112
#------------------------------------------------------------------------------
113
 
114
#------------------------------------------------------------------------------
115
sub LogFileOp
116
#
117
# Description:
118
#       This sub-routine is used to generate a consistent informational log
119
#------------------------------------------------------------------------------
120
{
121
    my ($opr, $file) = @_;
122
    $file =~ s/$DPKG_ROOT/DPKG/;
123
 
124
    Information (sprintf( "%-15s [%s]", $opr, $file));
125
}
126
 
4549 dpurdie 127
#-------------------------------------------------------------------------------
128
# Function        : addFile 
129
#
130
# Description     : Add a file to the list of transferred files
131
#
132
# Inputs          : $type           - File type
133
#                   $source         - Source file - full path
134
#                                     Use local copy, not network copy for file ops
135
#                   $target         - Target file name
136
#                   $md5sum         - Precalculated MD5 sum 
137
#
138
# Returns         : 
139
#
140
sub addFile
141
{
142
    my ($type, $source, $target, $md5sum) = @_;
143
    my %data;
144
 
145
    if ((not defined $md5sum) && ($type eq 'file'))
146
    {
147
        Verbose("Calculate MD5 Digest: $source");
148
        open(my $fh , $source) or Error ("Can't open '$source': $!");
149
        binmode $fh, ':crlf';
150
        $md5sum = Digest::MD5->new->addfile($fh)->hexdigest;
151
        close $fh;
152
    }
153
 
154
    $target =~ s~$DPKG_DIR~~;
155
    $target =~ s~^/~~;
156
    $target =~ s~/$~~;
157
 
4633 dpurdie 158
    #
159
    #   Convert from iso-8859-1 into utf-8
160
    #
161
    $target = decode( 'iso-8859-1', $target );
162
    $target = encode( 'utf-8', $target );
163
 
4549 dpurdie 164
    if ($type eq 'dir')
165
    {
166
        $data{path} = $target;
167
    }
168
    else
169
    {
170
        $data{path} = StripFileExt($target);
171
        $data{name} = StripDir($target);
172
        if ($type eq 'file')
173
        {
174
            $data{size} = (stat($source))[7];
175
            $data{md5sum} = $md5sum;
176
        }
177
    }
178
 
179
    $data{fullname} = $target;
180
    $data{type} = $type;
181
    $data{machtype} = $GBE_MACHTYPE;
182
    $data{host} = $GBE_HOSTNAME;
183
 
184
    # Put a nice '/' on the end of the patch elements
185
    $data{path} .= '/'
186
        if ( exists ($data{path}) && length($data{path}) > 0);
187
 
188
    push @fileList, \%data;
189
}
190
 
191
#-------------------------------------------------------------------------------
192
# Function        : writeFileInfo 
193
#
194
# Description     : Write out an XML file that contains this processes
195
#                   contribution to the output package 
196
#
197
# Inputs          : 
198
#
199
# Returns         : 
200
#
201
sub writeFileInfo
202
{
203
    my $data;
204
    $data->{file} = \@fileList;
205
 
206
    #
207
    #   Write out sections of XML
208
    #       Want control over the output order
209
    #       Use lots of attributes and only elements for arrays
210
    #       Save as one attribute per line - for readability
211
    #
212
    $opt_outfile = $opt_generic ? "$DPKG_DIR/built.files.generic.xml" : "$DPKG_DIR/built.files.$GBE_HOSTNAME.xml";
213
 
214
    LogFileOp ('Meta File', $opt_outfile);
215
    my $xs = XML::Simple->new( NoAttr =>0, AttrIndent => 1 );
216
 
217
    open (my $XML, '>', $opt_outfile) || Error ("Cannot create output file: $opt_outfile", $!);
218
    $xs->XMLout($data, 
219
                'RootName' => 'files', 
220
                'XMLDecl'  => '<?xml version="1.0" encoding="UTF-8"?>',
221
                'OutputFile' => $XML);
222
    close $XML;
223
 
224
}
225
 
227 dpurdie 226
#------------------------------------------------------------------------------
227
sub Init
228
#
229
# Description:
230
#     This function is used to process any command line arguements
231
#     and print the start banner.
232
#
233
#------------------------------------------------------------------------------
234
{
235
    # Process any command line arguements...
236
    my $result = GetOptions (
263 dpurdie 237
                "help:+"        => \$opt_help,              # flag, multiple use allowed
238
                "manual:3"      => \$opt_help,              # flag
239
                "verbose:+"     => \$opt_verbose,           # flag, multiple use allowed
4549 dpurdie 240
                "override!"     => \$opt_override,          # [no]flag (No longer used. Backward compat with build tool)
241
                "delete!"       => \$opt_delete,            # [no]flag
227 dpurdie 242
                "merge|m!"      => \$opt_merge,             # [no]flag.
243
                "archive=s"     => \$opt_archive,           # string
244
                "quiet+"        => \$opt_quiet,             # Flag
245
                "generic!"      => \$opt_generic,           # [no]Flag
246
                "pname=s"       => \$opt_pname,             # string
247
                "pversion=s"    => \$opt_pversion,          # string
248
                "test!"         => \$opt_test,              # [no]flag
263 dpurdie 249
                "md5!"          => \$opt_md5,               # [no]flag
4549 dpurdie 250
                "info!"         => \$opt_info,              # [no]flag
227 dpurdie 251
                );
252
 
253
 
254
    #
255
    #   Process help and manual options
256
    #
257
    pod2usage(-verbose => 0, -message => "Version: $VERSION")  if ($opt_help == 1  || ! $result);
258
    pod2usage(-verbose => 1)  if ($opt_help == 2 );
263 dpurdie 259
    pod2usage(-verbose => 2)  if ($opt_help > 2);
227 dpurdie 260
 
261
    #
262
    #   Init the error and message subsystem
263
    #
264
    ErrorConfig( 'name'    =>'CREATE_DPKG',
265
                 'verbose' => $opt_verbose,
266
                 'quiet'   => $opt_quiet );
267
 
268
    if ($opt_verbose)
269
    {
270
       Verbose ("Program: $PROGNAME");
271
       Verbose ("Version: $VERSION");
272
    }
273
 
274
    #
263 dpurdie 275
    #   Needed EnvVars
276
    #
277
    EnvImport ('GBE_MACHTYPE');
279 dpurdie 278
    EnvImport ('GBE_HOSTNAME');
279
    EnvImport ('USER' );
280
    EnvImportOptional ('GBE_ABT', "");
263 dpurdie 281
 
4003 dpurdie 282
    #
283
    #   Determine the target archive
284
    #   The default archive is GBE_DPKG, but this may be changed
285
    #
286
    $opt_archive = 'main' unless ( $opt_archive );
287
    my $archive_tag = $Archive2Var{$opt_archive};
288
    Error("Unknown archive specified: $opt_archive")
289
        unless ( $archive_tag );
290
    $DPKG_ROOT = $ENV{$archive_tag} || '';
291
    Verbose ("Archive Variable: $archive_tag" );
292
    Verbose2 ("Archive Path: $DPKG_ROOT" );
279 dpurdie 293
 
263 dpurdie 294
    #
4003 dpurdie 295
    #   Detect NoBuild marker
296
    #   This will bypass most of the operation of this package
297
    #
298
    if ( -f 'noBuild.gbe' )
299
    {
300
        Verbose ("No Build Marker file found");
301
        Error("Use of noBuild marker should only be done by a build daemon")
302
            unless ( $GBE_ABT );
303
 
304
        $SRC_ROOT = '';
305
        $DPKG_NAME = 'pkg';
306
        $DESCPKG_FILE = 'descpkg';
307
        $PKG_BASE =$CWD_DIR;
308
        return;
309
    }
310
 
311
    #
227 dpurdie 312
    #   Check for a "pkg" directory
313
    #   This may be in:
314
    #       1) The deploy directory (DEPLOY) build/deploy/descpkg
315
    #       2) The build directory (ANT)     build/pkg/descpkg
316
    #       3) The current directory (JATS)  pkg/xxxx/descpkg
317
    #
4003 dpurdie 318
    $PKG_BASE = "$CWD_DIR/build/deploy";
227 dpurdie 319
    Verbose2 ("Looking for descpkg: $PKG_BASE");
320
    if ( -f "$PKG_BASE/descpkg" )
321
    {
322
        #
323
        #   This is a deployment package.
324
        #   Force the use of the GBE_DPLY
325
        #
326
        $opt_archive = 'deploy' unless ( $opt_archive );
327
    }
328
    else
329
    {
330
        $PKG_BASE = "$CWD_DIR/build/pkg";
331
        Verbose ("Looking for descpkg: $PKG_BASE");
332
        if ( ! -f  "$PKG_BASE/descpkg" )
333
        {
334
            $PKG_BASE = "$CWD_DIR/pkg";
335
            Verbose ("Looking for descpkg: $PKG_BASE");
336
            Error("Failed to find a package to transfer. Looked in:",
337
                  "./build/deploy",
338
                  "./build/pkg",
339
                  "./pkg"
340
                  )
341
                unless( -d $PKG_BASE );
342
        }
343
    }
344
    Verbose("Package directory: $PKG_BASE");
345
 
346
    Error("Repository location not specified: $archive_tag")
347
        unless $DPKG_ROOT;
348
 
349
    Error("Failed to find Repository: $DPKG_ROOT")
350
        unless ( -d $DPKG_ROOT );
351
 
352
    #   Locate the package
353
    #   Packages are located by looking for a file called descpkg within the
354
    #   main package directory.
355
    #
356
    #   This installation process only handles one such file
357
    #
4549 dpurdie 358
    $descPkgCount = 0;
227 dpurdie 359
    File::Find::find( \&pkgFind, $PKG_BASE);
4549 dpurdie 360
 
361
    if ($descPkgCount > 1 )
362
    {
363
        Warning ("Package contains multiple ($descPkgCount) descpkg files");
364
    }
4003 dpurdie 365
}
227 dpurdie 366
 
4003 dpurdie 367
#-------------------------------------------------------------------------------
368
# Function        : CheckDescPkg
369
#
370
# Description     : Check the descpkg file
371
#
372
# Inputs          : Globals
373
#
374
# Returns         : Will not return on error
375
#
376
sub CheckDescPkg
377
{
227 dpurdie 378
    # Get the dpkg_archive version number we are  going to create.
379
    #
380
    Error("Descpkg file not found in package directory: $PKG_BASE")
381
        unless ( -f "$DESCPKG_FILE" );
382
 
383
    #
384
    #   Read in the package description and validate essential fields
385
    #
386
    GetDpkgArchiveVersion($DESCPKG_FILE);
387
    unless ( "$DPKG_VERSION" )
388
    {
389
        Error ("Incorrect descpkg content detected.",
390
               "Check JATS build.pl config.");
391
    }
392
 
393
    #
394
    #   Need to support two forms of pkg subdirectory
395
    #       1) packages are in a named subdir within 'pkg'
396
    #       2) package is within 'pkg' or 'deploy'
397
    #
398
    if ( $DPKG_NAME eq 'pkg' || $DPKG_NAME eq 'deploy' )
399
    {
400
        $DPKG_NAME = $DESC_NAME;
401
        unless ( $DESC_NAME )
402
        {
403
            Error ("Cannot determine package name",
404
                   "The packages 'descpkg' file is bad or missing");
405
        }
406
    }
407
    elsif ( $DESC_NAME ne $DPKG_NAME )
408
    {
409
        Error ("Package name MUST match package description",
410
               "Check build.pl and package.pl",
411
               "Package name: $DPKG_NAME",
412
               "Description : $DESC_NAME" );
413
    }
414
 
415
    #
416
    # lets just check to see if we have a version number before
417
    # we proceed.
418
    #
419
    unless ( $DPKG_VERSION )
420
    {
421
        Error("Cannot determine dpkg_archive version number.",
422
              "Check JATS build config.");
423
    }
424
 
425
    #
426
    #   Sanity test package name and version, if provided
427
    #
428
    if ( $opt_pname )
429
    {
430
        ReportError ("Package Name does not match expected name",
431
                     "Expected: '$opt_pname'",
432
                     "Descpkg : '$DPKG_NAME'") unless ( $DPKG_NAME eq $opt_pname );
433
    }
434
    if ( $opt_pversion )
435
    {
436
        ReportError ("Package Version does not match expected version",
437
                     "Expected: '$opt_pversion'",
438
                     "Descpkg : '$DPKG_VERSION'") unless ( $DPKG_VERSION eq $opt_pversion );
439
    }
440
    ErrorDoExit();
4003 dpurdie 441
}
227 dpurdie 442
 
4003 dpurdie 443
#-------------------------------------------------------------------------------
444
# Function        : ShowInfo
445
#
446
# Description     : Show info to the user
447
#
448
# Inputs          : 
449
#
450
# Returns         : 
451
#
452
sub ShowInfo
453
{
227 dpurdie 454
    #
455
    #   Set up the target directory path and name
456
    #   It will be created later
457
    #
458
    $DPKG_DIR = "$DPKG_ROOT/$DPKG_NAME/$DPKG_VERSION";
4003 dpurdie 459
 
227 dpurdie 460
    #
461
    #   Information for the user
462
    #
463
    Information ("---------------------------------------------------------------");
464
    Information ("Dpkg archive creation tool...");
465
    Information ("Version: $VERSION");
466
    Information ("");
467
    Information ("Information:");
468
    Information ("Working dir   = [$CWD_DIR]");
469
    Information ("Package Root  = [$SRC_ROOT]");
4549 dpurdie 470
    Information ("Repository    = [$DPKG_ROOT]");
471
    Information ("                *Non Standard archive") unless $opt_archive eq 'main';
227 dpurdie 472
    Information ("Target dir    = [$DPKG_DIR]");
473
    Information1("DPKG_NAME     = [$DPKG_NAME]");
474
    Information1("DPKG_VERSION  = [$DPKG_VERSION]");
475
    Information1("GBE_MACHTYPE  = [$GBE_MACHTYPE]");
279 dpurdie 476
    Information1("GBE_HOSTNAME  = [$GBE_HOSTNAME]");
477
    Information1("GBE_ABT       = [$GBE_ABT]");
478
    Information1("USER          = [$USER]");
4549 dpurdie 479
    Information ("")                                if ( $opt_merge || $opt_delete || $opt_info);
480
    Information ("Opt:Delete    = Enabled")         if ( $opt_delete );
227 dpurdie 481
    Information ("Opt:Merge     = Enabled")         if ( $opt_merge );
482
    Information ("Opt:TestMode  = Enabled. No Package Transferred") if ( $opt_test );
4549 dpurdie 483
    Information ("Opt:Info      = Enabled. No Package Transferred") if ( $opt_info );
369 dpurdie 484
    Warning     ("Sandbox Build = Yes") if ($ENV{GBE_DPKG_SBOX}) ;
227 dpurdie 485
    Information ("---------------------------------------------------------------");
486
 
369 dpurdie 487
    #
488
    #   If the environment variable GBE_DPKG_SBOX is defined then the package
489
    #   is being built within a development sandbox. In such a sandbox the
490
    #   version numbers of the packages are ignored. Publishing a package
491
    #   fromm such an environment is certainly not reproducible - so don't allow
492
    #   it to happen
493
    #
494
    #   Allow versions of 99.99.99 as these are known to be test versions
495
    #
496
    unless ( $opt_archive eq 'local' || $opt_archive eq 'sandbox' )
497
    {
498
        if ( $ENV{GBE_DPKG_SBOX} )
499
        {
500
            unless ( $DPKG_VERSION =~ /^99.99.99/ )
501
            {
502
                Error("Cannot not publish a package that has been generated",
503
                   "within a Sandbox as the version of dependent packages",
504
                   "is not guaranteed.",
505
                   "Only version 99.99.99 is allowed");
506
            }
507
        }
508
    }
4003 dpurdie 509
}
369 dpurdie 510
 
511
 
227 dpurdie 512
#------------------------------------------------------------------------------
513
sub pkgFind
514
#
515
# Description:
235 dpurdie 516
#     This subroutine is used to locate the FIRST descpkg file in
227 dpurdie 517
#     the local pkg dir.
518
#
519
#------------------------------------------------------------------------------
520
{
521
    my($item)= "$File::Find::name";
522
    my($file)= File::Basename::basename($item);
523
 
524
    # we get the absolute path from the find, but we only require
525
    # a relative path from the starting dir.
526
    # so our start dir.
527
 
528
    # we need to determine which file we are dealing with
235 dpurdie 529
    if ( ! -d $item && $file =~ /^descpkg$/ )
227 dpurdie 530
    {
4549 dpurdie 531
        $descPkgCount++;
532
 
235 dpurdie 533
        #
534
        #   Only grab the first one
535
        #
536
        if ( $DESCPKG_FILE )
537
        {
4549 dpurdie 538
            $item =~ s~$PKG_BASE/~~;
539
            Verbose ("Multiple descpkg files:", $item );
235 dpurdie 540
            return;
541
        }
542
 
227 dpurdie 543
        $DESCPKG_FILE = $item;
544
        my($dir)= File::Basename::dirname($item);
545
        $DPKG_NAME = File::Basename::basename($dir);
546
        $SRC_ROOT = $dir;
547
    }
548
}
549
 
550
 
551
#------------------------------------------------------------------------------
552
sub GetDpkgArchiveVersion
553
#
554
# Description:
555
#     This subroutine is used to determine the version of the dpkg_archive.
556
#     We assume that the version number is in the descpkg file.
557
#
558
#     Need to allow for two forms of descpkg. Some one decided that a Java
559
#     Manifest would be a good descpkg file - a long time after the rest of the
560
#     world had been using an existing file format.
561
#
562
#     Lines are tagged
563
#
564
#     Once the version number is determined we set the
565
#     global DPKG_VERSION variable.
566
#
567
#------------------------------------------------------------------------------
568
{
569
    my ($path) = @_;
570
    my $line;
571
    my $type;
572
 
573
    #
574
    #   Use a common routine to parse the package descriptor
575
    #   There are several forms that may need to be processed
576
    #
577
    my $pkg_data = ReadDescpkg( $path );
578
    Error("Failed to open file [$path].") unless $pkg_data;
579
 
580
    $DESC_NAME    = $pkg_data->{'NAME'};
581
    $DPKG_VERSION = $pkg_data->{'VERSION_FULL'};
582
}
583
 
584
#-------------------------------------------------------------------------------
585
# Function        : TransferDescpkg
586
#
587
# Description     : Copy and process the descpkg file to the target
588
#
589
# Inputs          :
590
#
591
# Returns         :
592
#
593
sub TransferDescpkg
594
{
595
    my $result = CopyDescpkg( @_ );
596
    Error("Transfer descpkg: $result") if ( $result );
597
}
598
 
599
#------------------------------------------------------------------------------
600
sub CreateDpkgArchive
601
#
602
# Description:
603
#     This subroutine is used to create the dpkg_archive in the $DPKG_ROOT
604
#     location 
605
#
606
#     We use the global DPKG_DIR, DPKG_NAME, and DPKG_VERSION
607
#     to create the required directory structure.
608
#
609
#     If the dpkg_archive is new (ie not a new version) it is assumed the user
610
#     has access to create the top level dir for the new dpkg_archive.
611
#
612
#     The new dpkg_archive is created with the permission of the user 
613
#     executing this script.
614
#
615
#     If an error ocurs during the dpkg_archive creation the script
616
#     will terminate.
617
#
618
#------------------------------------------------------------------------------
619
{
263 dpurdie 620
    #
227 dpurdie 621
    # first we need to ensure we have the top level directory
622
    #
623
    if ( -d $DPKG_DIR )
624
    {
625
        Warning("Detected previous dpkg_archive [$DPKG_DIR]");
4549 dpurdie 626
        Error ("Package already exists and Package merging not selected")
627
            unless ( $opt_delete || $opt_merge );
263 dpurdie 628
 
629
        #
630
        #   Target exists
631
        #   Unless we are merging, we need to blow the entire tree away
632
        #
633
        unless ( $opt_merge )
634
        {
635
            LogFileOp("Remove Prev Pkg",$DPKG_DIR);
636
            rmtree($DPKG_DIR);
637
 
638
            #
639
            #   At this point the target directory 'should not' exist
640
            #   but it may. Some packges (like JATS) have Unix links within
641
            #   dpkg_archive filesystem. These cannot be deleted under windows
642
            #
643
            #   Not nice, but we live with it.
644
            #
645
            Warning ("Unable to delete previous instance of the package")
646
                if ( -d $DPKG_DIR );
647
        }
227 dpurdie 648
    }
649
    Information("");
650
 
651
    #
652
    #   Create the top level directory
653
    #
654
    mkpath($DPKG_DIR, 0, 0775);
655
 
656
    #
4003 dpurdie 657
    #   Transfer source directory, unless this is a noBuild
658
    #
659
    if ( $SRC_ROOT ne '' )
227 dpurdie 660
    {
4003 dpurdie 661
        # Process the files
662
        #
663
        if ( -d $SRC_ROOT )
664
        {
665
            File::Find::find( \&pkgFind2, $SRC_ROOT );
263 dpurdie 666
 
4424 dpurdie 667
            if (@bad_symlinks)
668
            {
669
                my $msg = "Bad Symlinks: " . scalar @bad_symlinks;
670
                $opt_test ? ReportError($msg, @bad_symlinks) : Warning($msg, @bad_symlinks);
671
            }
672
 
4003 dpurdie 673
            if ( $bad_merge_count )
674
            {
675
                my $msg = "Merged files that differ: $bad_merge_count";
4424 dpurdie 676
                $opt_md5 ? ReportError($msg) : Warning($msg);
4003 dpurdie 677
            }
4424 dpurdie 678
            ErrorDoExit();
4003 dpurdie 679
        }
680
        else
263 dpurdie 681
        {
4003 dpurdie 682
            Error("Failed to find dir [$SRC_ROOT]",
683
                  "Check JATS config.");
263 dpurdie 684
        }
227 dpurdie 685
    }
686
 
687
    #
688
    #   Transfer of data is complete
4424 dpurdie 689
    #       Mark the archive with the build machine to indicate which parts of
690
    #       a multi-machine build have been performed
227 dpurdie 691
    #
345 dpurdie 692
    my $touchfile = $opt_generic ? "$DPKG_DIR/built.generic" : "$DPKG_DIR/built.$GBE_HOSTNAME";
279 dpurdie 693
 
227 dpurdie 694
    #
4003 dpurdie 695
    #   Create a string to be appended to the 'built' file
696
    #   Comma seperated list of (possibly) useful info
279 dpurdie 697
    #       Date-Time ( Local and GMT)
698
    #       machine type, machine name and the user
699
    #       GBE_ABT value
700
    #
701
    my $built_info = localtime() ."," . gmtime() . " GMT,$GBE_MACHTYPE,$GBE_HOSTNAME,$USER,$GBE_ABT";
227 dpurdie 702
    LogFileOp("Mark File",$touchfile);
279 dpurdie 703
    FileAppend ( $touchfile, $built_info );
227 dpurdie 704
 
705
    #
706
    #   If there is a .lnk file in the archive then remove it now that the
707
    #   archive has been transferred. The .lnk files are created in 'local'
708
    #   archives in order to simplify multi-package builds
709
    #
710
    my $link_file = "$DPKG_ROOT/$DPKG_NAME/$DPKG_VERSION.lnk";
711
    if ( -f $link_file )
712
    {
713
        LogFileOp("Removing Link",$link_file);
714
        unlink $link_file;
715
    }
716
 
717
    return 1;
718
}
719
 
720
 
721
#------------------------------------------------------------------------------
722
sub pkgFind2
723
#
724
# Description:
725
#   This subroutine is used to locate all associated pkg files in
726
#   the local pkg dir.
727
#
728
#   This routine is called for each file and directory within the package
729
#   Some files and directories are treated in a special manner
730
#       - Top level directory is ignored
731
#
732
#
733
#
734
#------------------------------------------------------------------------------
735
{
736
    my $item = $File::Find::name;
737
    my $base = File::Basename::basename($item);
738
 
739
    #
740
    #   Calculate the target directory name
741
    #
742
    my $target = $item;
241 dpurdie 743
    $target = $DPKG_DIR . substr ( $item, length ($SRC_ROOT) );
227 dpurdie 744
 
745
    if ( -d $item )
746
    {
747
        #
748
        #   Ignore the top level directory
749
        #   It has already been created
750
        #
751
        return
752
            if ( $item eq $SRC_ROOT );
753
 
754
        #
755
        #   Directories are handled differently
756
        #       - Directories are created with nice permissions
263 dpurdie 757
        #       - If the directory already exists then it is being merged.
227 dpurdie 758
        #
759
        if ( ! -d "$target" )
760
        {
761
            LogFileOp("Creating Dir", $target);
762
            mkpath("$target", 0, 0775);
4549 dpurdie 763
            addFile('dir', $item , $target);
227 dpurdie 764
        }
765
    }
766
    else
767
    {
768
        #
769
        #   File copy
770
        #   If merging then do not overwrite an existing file
771
        #
772
        unless ( $opt_merge && -f $target )
773
        {
774
            if ( $item =~ m~/descpkg$~ )
775
            {
776
                LogFileOp("Rewrite File",$target);
4549 dpurdie 777
                TransferDescpkg( $item, $target );
363 dpurdie 778
                CORE::chmod oct("0664"), $target;
4549 dpurdie 779
                addFile('file', $item, $target);
227 dpurdie 780
            }
781
            else
782
            {
783
                #
784
                #   Copy file to destination
785
                #   If the file is a link, then duplicate the link contents
786
                #   Use: Unix libraries are created as two files:
787
                #        lib.xxxx.so -> libxxxx.so.vv.vv.vv
788
                #
789
                if ( -l $item )
790
                {
4424 dpurdie 791
                    if (-f $item)
227 dpurdie 792
                    {
4424 dpurdie 793
                        LogFileOp("Copying Link", $target);
794
                        my $link = readlink $item;
795
                        Verbose( "Link: $item, $link");
796
                        symlink ($link, $target );
797
                        unless ( $link && -l $target )
798
                        {
799
                            Error("Failed to copy link [$item] to [$target]: $!");
800
                        }
4549 dpurdie 801
                        addFile('link', $item , $target);
227 dpurdie 802
                    }
4424 dpurdie 803
                    else
804
                    {
805
                        # Don't copy broken Symlinks
806
                        # Perhaps this should be an error - but is will break escrow builds
807
                        #
808
                        LogFileOp("Broken SymLink", $target);
809
                        push @bad_symlinks, substr ( $item, 1+length ($SRC_ROOT) );
810
                    }
227 dpurdie 811
                }
812
                elsif (File::Copy::copy($item, $target))
813
                {
814
                    LogFileOp("Copying File",$target);
363 dpurdie 815
                    #
816
                    #   Mark the file as executable by all
817
                    #   Under windows, this is tricky
818
                    #
819
                    if ( $Win32 )
820
                    {
821
                        my %hash;
822
                        $hash{Everyone} = Win32::FileSecurity::MakeMask( qw( FULL  ) );
823
                        Win32::FileSecurity::Set( $target, \%hash );
824
                    }
825
                    else
826
                    {
827
                        CORE::chmod oct("0775"), $target;
828
                    }
4549 dpurdie 829
                    addFile('file', $item, $target);
227 dpurdie 830
                }
831
                else
832
                {
833
                    Error("Failed to copy file [$item] to [$target]: $!");
834
                }
835
            }
836
        }
837
        else
838
        {
839
            #
840
            #   Merging packages
841
            #   Ensure that the descpkg file is "touched" so that caches
842
            #   that use this file as a timestamp can be updated
843
            #
844
            if ( $item =~ m~/descpkg$~ )
845
            {
846
                LogFileOp("Touch File",$target);
847
                TouchFile( $target ) && Error ( "Failed to touch: $target" );
4549 dpurdie 848
                addFile('merge', $item, $target);
227 dpurdie 849
            }
850
            else
851
            {
263 dpurdie 852
                #
853
                #   MD5 digest the files that are being merged
854
                #   Ignore version_*.h files as these are generated
855
                #   and may contain different dates and line endings
856
                #
267 dpurdie 857
                #   Don't put the files into 'binmode'
858
                #   Need to handle some level of Unix/DOS file endings
859
                #
860
                #
263 dpurdie 861
                my $msg = "Merge Skip File";
862
                unless ( $target =~ m~/version[^/]*\.h$~ )
863
                {
864
                    $msg = "Merge Test File";
865
                    #
866
                    #   Compare the two files with an MD5
867
                    #
868
                    local *FILE;
869
                    open(FILE, $target) or Error ("Can't open '$target': $!");
267 dpurdie 870
                    binmode FILE, ':crlf';
263 dpurdie 871
                    my $target_md5 = Digest::MD5->new->addfile(*FILE)->hexdigest;
872
                    close FILE;
873
 
874
                    open(FILE, $item) or Error ("Can't open '$item': $!");
267 dpurdie 875
                    binmode FILE, ':crlf';
263 dpurdie 876
                    my $source_md5 = Digest::MD5->new->addfile(*FILE)->hexdigest;
877
                    close FILE;
878
 
879
                    unless ( $source_md5 eq $target_md5 )
880
                    {
881
                        $msg = "DIFF: Merge Test File";
882
                        $bad_merge_count ++;
883
                    }
4549 dpurdie 884
                    addFile('merge', $item, $target, $target_md5);
263 dpurdie 885
                }
886
                LogFileOp($msg,$target);
227 dpurdie 887
            }
888
        }
889
    }
890
}
891
 
892
#-------------------------------------------------------------------------------
893
# Function        : TestDpkgArchive
894
#
895
# Description     : Test the structure of the source achive
896
#                   Ensure that it has some files
897
#                   Warn if files are present in the root directory
898
#
899
# Inputs          : None
900
#
901
# Returns         : Warnings
902
#
903
my $test_dir_count = 0;
904
my $test_file_count = 0;
905
my @test_root_file = ();
906
sub TestDpkgArchive
907
{
908
    $test_dir_count = 0;
909
    $test_file_count = 0;
910
    @test_root_file = ();
911
 
4003 dpurdie 912
    if ( $SRC_ROOT ne '' )
913
    {
914
        Error("Failed to find dir [$SRC_ROOT]",
915
              "Check JATS config.") unless ( -d $SRC_ROOT );
916
 
917
 
918
        #
919
        #   Scan the package counting files and folders
920
        #
921
        File::Find::find( \&pkgFind3, $SRC_ROOT );
922
    }
923
 
227 dpurdie 924
    Information ("Package contains:",
925
                 "Files: $test_file_count",
926
                 "Dirs: $test_dir_count",
927
                 );
928
    #
929
    #   There shouldn't be any files in the root directory
930
    #   other than the descpkg and incpkg.
931
    #
932
    Warning ("Unexpected files in package root:", @test_root_file)
933
        if ( @test_root_file  );
4424 dpurdie 934
 
935
    Error ("Bad symbolic links found:", @bad_symlinks)
936
            if ( @bad_symlinks );
937
 
227 dpurdie 938
}
939
 
940
sub pkgFind3
941
{
942
 
943
    #
944
    #   Calculate the target directory name
945
    #
946
    my $target = $File::Find::dir;
263 dpurdie 947
    $target = substr ( $target, length ($SRC_ROOT) );
948
    $target =~ s~^.~~;
227 dpurdie 949
 
950
    if ( -d $_ ) {
951
        $test_dir_count++;
952
    } else {
953
        $test_file_count++;
954
        unless ( $target )
955
        {
241 dpurdie 956
            #
957
            #   Locate files in the package root directory that
958
            #   are not expected to be there.
959
            #
263 dpurdie 960
            unless ((  $_ eq 'descpkg' ) || ( $_ eq 'incpkg' ))
961
            {
962
                push @test_root_file, $_;
963
            }
227 dpurdie 964
        }
4424 dpurdie 965
        if (-l $_ && ! -f $_)
966
        {
967
            push @bad_symlinks, substr ( $File::Find::name, 1+length ($SRC_ROOT) );
968
        }
227 dpurdie 969
    }
970
}
971
 
972
# ---------------------------------------------------------
973
# ---------------------------------------------------------
974
# Main
975
# ---------------------------------------------------------
976
# ---------------------------------------------------------
977
 
978
 
979
# Initialise our world
980
#
981
Init();
4003 dpurdie 982
CheckDescPkg();
983
ShowInfo();
4549 dpurdie 984
unless ($opt_info)
227 dpurdie 985
{
4549 dpurdie 986
    unless ( $opt_test )
227 dpurdie 987
    {
4549 dpurdie 988
        Information("Creating dpkg_archive package:", $DPKG_DIR);
989
        CreateDpkgArchive();
990
        writeFileInfo();
227 dpurdie 991
    }
4549 dpurdie 992
    else
993
    {
994
        Information("Testing user package.");
995
        TestDpkgArchive();
996
    }
227 dpurdie 997
}
998
 
999
# Done
1000
#
1001
Information ("Done.");
1002
exit 0;
1003
 
1004
 
1005
#-------------------------------------------------------------------------------
1006
#   Documentation
1007
#
1008
 
1009
=pod
1010
 
361 dpurdie 1011
=for htmltoc    SYSUTIL::
1012
 
227 dpurdie 1013
=head1 NAME
1014
 
1015
create_dpkg - Create a dpkg_archive entry
1016
 
1017
=head1 SYNOPSIS
1018
 
1019
 jats create_dpkg [options]
1020
 
1021
 Options:
1022
    -help              - Brief help message
1023
    -help -help        - Detailed help message
1024
    -man               - Full documentation
1025
    -quiet             - Suppress progress messages, then warning messages
1026
    -verbose           - Display additional progress messages
4549 dpurdie 1027
    -override          - Deprecated option
1028
    -delete            - Delete any previous version of the package
263 dpurdie 1029
    -[no]merge         - merge with existing version of the package
227 dpurdie 1030
    -archive=name      - Specify archive (cache, local, main, store, sandbox, deploy)
1031
    -pname=name        - Ensure package is named correctly
1032
    -pversion=version  - Ensure package version is correct
1033
    -generic           - Create a built.generic file
4549 dpurdie 1034
    -[no]md5           - Use MD5 comparison of merged files(enabled)
263 dpurdie 1035
    -[no]test          - Test package. Do not transfer.
4549 dpurdie 1036
    -[no]info          - Display packaging info. Do not transfer.
227 dpurdie 1037
 
1038
=head1 OPTIONS
1039
 
1040
=over 8
1041
 
1042
=item B<-help>
1043
 
1044
Print a brief help message and exits.
1045
 
1046
=item B<-help -help>
1047
 
1048
Print a detailed help message with an explanation for each option.
1049
 
1050
=item B<-man>
1051
 
1052
Prints the manual page and exits.
1053
 
1054
=item B<-quiet>
1055
 
1056
This option will suppress almost all of the progress messages, except for a single
1057
copy message. It is intended to be used when the program is called from another
1058
script.
1059
 
1060
=item B<-override>
1061
 
4549 dpurdie 1062
If this option has been deprecated. It has no effect.
1063
 
1064
It is still present to preserve backward compatability with the automated 
1065
build system.
1066
 
1067
=item B<-delete>
1068
 
227 dpurdie 1069
If this option is enabled then any previous version of the target package will
4549 dpurdie 1070
be deleted.
227 dpurdie 1071
 
1072
=item B<-merge>
1073
 
1074
If this option is enabled then the package will be merged with any existing
4549 dpurdie 1075
package. This option is used by the auto build tool to assemble multi-machine 
1076
packages in dpkg_archive.
227 dpurdie 1077
 
1078
=item B<-archive=name>
1079
 
1080
This option specifies the destination archive to be used. The following names
1081
are supported:
1082
 
361 dpurdie 1083
=over 8
1084
 
1085
=item cache
1086
 
1087
The location of the target archive will be taken from C<GBE_DPKG_CACHE>.
1088
 
1089
=item local
1090
 
1091
The location of the target archive will be taken from C<GBE_DPKG_LOCAL>.
1092
 
1093
=item main (default)
1094
 
1095
The location of the target archive will be taken from C<GBE_DPKG>. This is the
1096
default target archive.
1097
 
1098
=item store
1099
 
1100
The location of the target archive will be taken from C<GBE_DPKG_STORE>.
1101
 
1102
=item sandbox
1103
 
1104
The location of the target archive will be taken from C<GBE_DPKG_SBOX>.
1105
 
1106
=item deploy
1107
 
1108
The location of the target archive will be taken from C<GBE_DPLY>. This is the
1109
default target archive is a deployment package is detected.
1110
 
1111
=back
1112
 
227 dpurdie 1113
=item B<-pname=name>
1114
 
1115
If this option is provided, the utility will ensure that the package is named
1116
correctly.
1117
 
1118
=item B<-pversion=version>
1119
 
1120
If this option is provided, the utility will ensure that the package version is
1121
that expected.
1122
 
4549 dpurdie 1123
=item B<-generic>
227 dpurdie 1124
 
4549 dpurdie 1125
This option will create a built.generic file, instead of one based on the machine
1126
that actually built the package. This is used by the AutoBuilder toolchain.
227 dpurdie 1127
 
263 dpurdie 1128
=item B<-[no]md5>
1129
 
1130
If package builds are being merged then a validity check is performed using
1131
an MD5 digest over the current and the existing file.
1132
 
1133
By default, it is an error for the user file to differ from the merged file.
1134
 
1135
This option disabled the error. The test is still done and the results are
1136
reported.
1137
 
4549 dpurdie 1138
=item B<-test>
227 dpurdie 1139
 
4549 dpurdie 1140
If this option is enabled the utility will perform initial sanity testing, but
1141
it will not perform the copy.
227 dpurdie 1142
 
4549 dpurdie 1143
=item B<-[no]info>
1144
 
1145
This option will cause the program to display information about the packaging 
1146
process and then exit. 
1147
 
1148
No data will be transferred to the archive.
1149
 
227 dpurdie 1150
=back
1151
 
1152
=head1 DESCRIPTION
1153
 
1154
This utility program is used to transfer a package that has been built into
1155
dpkg_archive. The package is then available for general consumption.
1156
 
4549 dpurdie 1157
The utility will perform several operations in the transfer process. These incude:
1158
 
1159
=over 4
1160
 
1161
=item * 
1162
 
1163
Create a tag file to indicate the machine that has performed the transfer
1164
 
1165
=item * 
1166
 
1167
Create an XML file of files that have been transferred. This file contains information
1168
used by the build system when it releases the package, including: name, size and MD5SUM.
1169
 
1170
=item *
1171
 
1172
Detect file conflicts when different builds are merged into a single package. Header files are 
1173
allowed to differ in line ending style, but other files must not conflict. The package will not be 
1174
reproducible if file conflicts exist.
1175
 
1176
=item *
1177
 
1178
Suppress dead symbolic links. A valid symlink will be preserved, but invalid links will be 
1179
removed from the transferred image.
1180
 
1181
=back
1182
 
227 dpurdie 1183
=head2 PACKAGE LOCATION
1184
 
1185
The utility will locate a package by examining the following directores for
1186
the package description file(descpkg).
1187
 
1188
=over 8
1189
 
1190
=item ./build/deploy
1191
 
1192
This format is generated by the deployment builds. The default target archive
1193
will be taken from the environment variable GBE_DPLY.
1194
 
1195
=item ./pkg
1196
 
1197
This format is generated by JATS builds.
1198
 
1199
=item ./build/pkg
1200
 
1201
This format is generated by ANT builds.
1202
 
1203
=back
1204
 
1205
The program should be run in the same directory as the build control files as
1206
the package subdirectory will be created in that directory.
1207
 
1208
=head1 EXAMPLE
1209
 
1210
=head2 jats create_dpkg
1211
 
1212
This will locate a generated package and install it into the dpkg_archive repository.
1213
 
1214
=cut
1215