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 );
4634 dpurdie 704
    addFile('file', $touchfile, $touchfile);
227 dpurdie 705
 
4634 dpurdie 706
 
227 dpurdie 707
    #
708
    #   If there is a .lnk file in the archive then remove it now that the
709
    #   archive has been transferred. The .lnk files are created in 'local'
710
    #   archives in order to simplify multi-package builds
711
    #
712
    my $link_file = "$DPKG_ROOT/$DPKG_NAME/$DPKG_VERSION.lnk";
713
    if ( -f $link_file )
714
    {
715
        LogFileOp("Removing Link",$link_file);
716
        unlink $link_file;
717
    }
718
 
719
    return 1;
720
}
721
 
722
 
723
#------------------------------------------------------------------------------
724
sub pkgFind2
725
#
726
# Description:
727
#   This subroutine is used to locate all associated pkg files in
728
#   the local pkg dir.
729
#
730
#   This routine is called for each file and directory within the package
731
#   Some files and directories are treated in a special manner
732
#       - Top level directory is ignored
733
#
734
#
735
#
736
#------------------------------------------------------------------------------
737
{
738
    my $item = $File::Find::name;
739
    my $base = File::Basename::basename($item);
740
 
741
    #
742
    #   Calculate the target directory name
743
    #
744
    my $target = $item;
241 dpurdie 745
    $target = $DPKG_DIR . substr ( $item, length ($SRC_ROOT) );
227 dpurdie 746
 
747
    if ( -d $item )
748
    {
749
        #
750
        #   Ignore the top level directory
751
        #   It has already been created
752
        #
753
        return
754
            if ( $item eq $SRC_ROOT );
755
 
756
        #
757
        #   Directories are handled differently
758
        #       - Directories are created with nice permissions
263 dpurdie 759
        #       - If the directory already exists then it is being merged.
227 dpurdie 760
        #
761
        if ( ! -d "$target" )
762
        {
763
            LogFileOp("Creating Dir", $target);
764
            mkpath("$target", 0, 0775);
4549 dpurdie 765
            addFile('dir', $item , $target);
227 dpurdie 766
        }
767
    }
768
    else
769
    {
770
        #
771
        #   File copy
772
        #   If merging then do not overwrite an existing file
773
        #
774
        unless ( $opt_merge && -f $target )
775
        {
776
            if ( $item =~ m~/descpkg$~ )
777
            {
778
                LogFileOp("Rewrite File",$target);
4549 dpurdie 779
                TransferDescpkg( $item, $target );
363 dpurdie 780
                CORE::chmod oct("0664"), $target;
4549 dpurdie 781
                addFile('file', $item, $target);
227 dpurdie 782
            }
783
            else
784
            {
785
                #
786
                #   Copy file to destination
787
                #   If the file is a link, then duplicate the link contents
788
                #   Use: Unix libraries are created as two files:
789
                #        lib.xxxx.so -> libxxxx.so.vv.vv.vv
790
                #
791
                if ( -l $item )
792
                {
4424 dpurdie 793
                    if (-f $item)
227 dpurdie 794
                    {
4424 dpurdie 795
                        LogFileOp("Copying Link", $target);
796
                        my $link = readlink $item;
797
                        Verbose( "Link: $item, $link");
798
                        symlink ($link, $target );
799
                        unless ( $link && -l $target )
800
                        {
801
                            Error("Failed to copy link [$item] to [$target]: $!");
802
                        }
4549 dpurdie 803
                        addFile('link', $item , $target);
227 dpurdie 804
                    }
4424 dpurdie 805
                    else
806
                    {
807
                        # Don't copy broken Symlinks
808
                        # Perhaps this should be an error - but is will break escrow builds
809
                        #
810
                        LogFileOp("Broken SymLink", $target);
811
                        push @bad_symlinks, substr ( $item, 1+length ($SRC_ROOT) );
812
                    }
227 dpurdie 813
                }
814
                elsif (File::Copy::copy($item, $target))
815
                {
816
                    LogFileOp("Copying File",$target);
363 dpurdie 817
                    #
818
                    #   Mark the file as executable by all
819
                    #   Under windows, this is tricky
820
                    #
821
                    if ( $Win32 )
822
                    {
823
                        my %hash;
824
                        $hash{Everyone} = Win32::FileSecurity::MakeMask( qw( FULL  ) );
825
                        Win32::FileSecurity::Set( $target, \%hash );
826
                    }
827
                    else
828
                    {
829
                        CORE::chmod oct("0775"), $target;
830
                    }
4549 dpurdie 831
                    addFile('file', $item, $target);
227 dpurdie 832
                }
833
                else
834
                {
835
                    Error("Failed to copy file [$item] to [$target]: $!");
836
                }
837
            }
838
        }
839
        else
840
        {
841
            #
842
            #   Merging packages
843
            #   Ensure that the descpkg file is "touched" so that caches
844
            #   that use this file as a timestamp can be updated
845
            #
846
            if ( $item =~ m~/descpkg$~ )
847
            {
848
                LogFileOp("Touch File",$target);
849
                TouchFile( $target ) && Error ( "Failed to touch: $target" );
4549 dpurdie 850
                addFile('merge', $item, $target);
227 dpurdie 851
            }
852
            else
853
            {
263 dpurdie 854
                #
855
                #   MD5 digest the files that are being merged
856
                #   Ignore version_*.h files as these are generated
857
                #   and may contain different dates and line endings
858
                #
267 dpurdie 859
                #   Don't put the files into 'binmode'
860
                #   Need to handle some level of Unix/DOS file endings
861
                #
862
                #
263 dpurdie 863
                my $msg = "Merge Skip File";
864
                unless ( $target =~ m~/version[^/]*\.h$~ )
865
                {
866
                    $msg = "Merge Test File";
867
                    #
868
                    #   Compare the two files with an MD5
869
                    #
870
                    local *FILE;
871
                    open(FILE, $target) or Error ("Can't open '$target': $!");
267 dpurdie 872
                    binmode FILE, ':crlf';
263 dpurdie 873
                    my $target_md5 = Digest::MD5->new->addfile(*FILE)->hexdigest;
874
                    close FILE;
875
 
876
                    open(FILE, $item) or Error ("Can't open '$item': $!");
267 dpurdie 877
                    binmode FILE, ':crlf';
263 dpurdie 878
                    my $source_md5 = Digest::MD5->new->addfile(*FILE)->hexdigest;
879
                    close FILE;
880
 
881
                    unless ( $source_md5 eq $target_md5 )
882
                    {
883
                        $msg = "DIFF: Merge Test File";
884
                        $bad_merge_count ++;
885
                    }
4549 dpurdie 886
                    addFile('merge', $item, $target, $target_md5);
263 dpurdie 887
                }
888
                LogFileOp($msg,$target);
227 dpurdie 889
            }
890
        }
891
    }
892
}
893
 
894
#-------------------------------------------------------------------------------
895
# Function        : TestDpkgArchive
896
#
897
# Description     : Test the structure of the source achive
898
#                   Ensure that it has some files
899
#                   Warn if files are present in the root directory
900
#
901
# Inputs          : None
902
#
903
# Returns         : Warnings
904
#
905
my $test_dir_count = 0;
906
my $test_file_count = 0;
907
my @test_root_file = ();
908
sub TestDpkgArchive
909
{
910
    $test_dir_count = 0;
911
    $test_file_count = 0;
912
    @test_root_file = ();
913
 
4003 dpurdie 914
    if ( $SRC_ROOT ne '' )
915
    {
916
        Error("Failed to find dir [$SRC_ROOT]",
917
              "Check JATS config.") unless ( -d $SRC_ROOT );
918
 
919
 
920
        #
921
        #   Scan the package counting files and folders
922
        #
923
        File::Find::find( \&pkgFind3, $SRC_ROOT );
924
    }
925
 
227 dpurdie 926
    Information ("Package contains:",
927
                 "Files: $test_file_count",
928
                 "Dirs: $test_dir_count",
929
                 );
930
    #
931
    #   There shouldn't be any files in the root directory
932
    #   other than the descpkg and incpkg.
933
    #
934
    Warning ("Unexpected files in package root:", @test_root_file)
935
        if ( @test_root_file  );
4424 dpurdie 936
 
937
    Error ("Bad symbolic links found:", @bad_symlinks)
938
            if ( @bad_symlinks );
939
 
227 dpurdie 940
}
941
 
942
sub pkgFind3
943
{
944
 
945
    #
946
    #   Calculate the target directory name
947
    #
948
    my $target = $File::Find::dir;
263 dpurdie 949
    $target = substr ( $target, length ($SRC_ROOT) );
950
    $target =~ s~^.~~;
227 dpurdie 951
 
952
    if ( -d $_ ) {
953
        $test_dir_count++;
954
    } else {
955
        $test_file_count++;
956
        unless ( $target )
957
        {
241 dpurdie 958
            #
959
            #   Locate files in the package root directory that
960
            #   are not expected to be there.
961
            #
263 dpurdie 962
            unless ((  $_ eq 'descpkg' ) || ( $_ eq 'incpkg' ))
963
            {
964
                push @test_root_file, $_;
965
            }
227 dpurdie 966
        }
4424 dpurdie 967
        if (-l $_ && ! -f $_)
968
        {
969
            push @bad_symlinks, substr ( $File::Find::name, 1+length ($SRC_ROOT) );
970
        }
227 dpurdie 971
    }
972
}
973
 
974
# ---------------------------------------------------------
975
# ---------------------------------------------------------
976
# Main
977
# ---------------------------------------------------------
978
# ---------------------------------------------------------
979
 
980
 
981
# Initialise our world
982
#
983
Init();
4003 dpurdie 984
CheckDescPkg();
985
ShowInfo();
4549 dpurdie 986
unless ($opt_info)
227 dpurdie 987
{
4549 dpurdie 988
    unless ( $opt_test )
227 dpurdie 989
    {
4549 dpurdie 990
        Information("Creating dpkg_archive package:", $DPKG_DIR);
991
        CreateDpkgArchive();
992
        writeFileInfo();
227 dpurdie 993
    }
4549 dpurdie 994
    else
995
    {
996
        Information("Testing user package.");
997
        TestDpkgArchive();
998
    }
227 dpurdie 999
}
1000
 
1001
# Done
1002
#
1003
Information ("Done.");
1004
exit 0;
1005
 
1006
 
1007
#-------------------------------------------------------------------------------
1008
#   Documentation
1009
#
1010
 
1011
=pod
1012
 
361 dpurdie 1013
=for htmltoc    SYSUTIL::
1014
 
227 dpurdie 1015
=head1 NAME
1016
 
1017
create_dpkg - Create a dpkg_archive entry
1018
 
1019
=head1 SYNOPSIS
1020
 
1021
 jats create_dpkg [options]
1022
 
1023
 Options:
1024
    -help              - Brief help message
1025
    -help -help        - Detailed help message
1026
    -man               - Full documentation
1027
    -quiet             - Suppress progress messages, then warning messages
1028
    -verbose           - Display additional progress messages
4549 dpurdie 1029
    -override          - Deprecated option
1030
    -delete            - Delete any previous version of the package
263 dpurdie 1031
    -[no]merge         - merge with existing version of the package
227 dpurdie 1032
    -archive=name      - Specify archive (cache, local, main, store, sandbox, deploy)
1033
    -pname=name        - Ensure package is named correctly
1034
    -pversion=version  - Ensure package version is correct
1035
    -generic           - Create a built.generic file
4549 dpurdie 1036
    -[no]md5           - Use MD5 comparison of merged files(enabled)
263 dpurdie 1037
    -[no]test          - Test package. Do not transfer.
4549 dpurdie 1038
    -[no]info          - Display packaging info. Do not transfer.
227 dpurdie 1039
 
1040
=head1 OPTIONS
1041
 
1042
=over 8
1043
 
1044
=item B<-help>
1045
 
1046
Print a brief help message and exits.
1047
 
1048
=item B<-help -help>
1049
 
1050
Print a detailed help message with an explanation for each option.
1051
 
1052
=item B<-man>
1053
 
1054
Prints the manual page and exits.
1055
 
1056
=item B<-quiet>
1057
 
1058
This option will suppress almost all of the progress messages, except for a single
1059
copy message. It is intended to be used when the program is called from another
1060
script.
1061
 
1062
=item B<-override>
1063
 
4549 dpurdie 1064
If this option has been deprecated. It has no effect.
1065
 
1066
It is still present to preserve backward compatability with the automated 
1067
build system.
1068
 
1069
=item B<-delete>
1070
 
227 dpurdie 1071
If this option is enabled then any previous version of the target package will
4549 dpurdie 1072
be deleted.
227 dpurdie 1073
 
1074
=item B<-merge>
1075
 
1076
If this option is enabled then the package will be merged with any existing
4549 dpurdie 1077
package. This option is used by the auto build tool to assemble multi-machine 
1078
packages in dpkg_archive.
227 dpurdie 1079
 
1080
=item B<-archive=name>
1081
 
1082
This option specifies the destination archive to be used. The following names
1083
are supported:
1084
 
361 dpurdie 1085
=over 8
1086
 
1087
=item cache
1088
 
1089
The location of the target archive will be taken from C<GBE_DPKG_CACHE>.
1090
 
1091
=item local
1092
 
1093
The location of the target archive will be taken from C<GBE_DPKG_LOCAL>.
1094
 
1095
=item main (default)
1096
 
1097
The location of the target archive will be taken from C<GBE_DPKG>. This is the
1098
default target archive.
1099
 
1100
=item store
1101
 
1102
The location of the target archive will be taken from C<GBE_DPKG_STORE>.
1103
 
1104
=item sandbox
1105
 
1106
The location of the target archive will be taken from C<GBE_DPKG_SBOX>.
1107
 
1108
=item deploy
1109
 
1110
The location of the target archive will be taken from C<GBE_DPLY>. This is the
1111
default target archive is a deployment package is detected.
1112
 
1113
=back
1114
 
227 dpurdie 1115
=item B<-pname=name>
1116
 
1117
If this option is provided, the utility will ensure that the package is named
1118
correctly.
1119
 
1120
=item B<-pversion=version>
1121
 
1122
If this option is provided, the utility will ensure that the package version is
1123
that expected.
1124
 
4549 dpurdie 1125
=item B<-generic>
227 dpurdie 1126
 
4549 dpurdie 1127
This option will create a built.generic file, instead of one based on the machine
1128
that actually built the package. This is used by the AutoBuilder toolchain.
227 dpurdie 1129
 
263 dpurdie 1130
=item B<-[no]md5>
1131
 
1132
If package builds are being merged then a validity check is performed using
1133
an MD5 digest over the current and the existing file.
1134
 
1135
By default, it is an error for the user file to differ from the merged file.
1136
 
1137
This option disabled the error. The test is still done and the results are
1138
reported.
1139
 
4549 dpurdie 1140
=item B<-test>
227 dpurdie 1141
 
4549 dpurdie 1142
If this option is enabled the utility will perform initial sanity testing, but
1143
it will not perform the copy.
227 dpurdie 1144
 
4549 dpurdie 1145
=item B<-[no]info>
1146
 
1147
This option will cause the program to display information about the packaging 
1148
process and then exit. 
1149
 
1150
No data will be transferred to the archive.
1151
 
227 dpurdie 1152
=back
1153
 
1154
=head1 DESCRIPTION
1155
 
1156
This utility program is used to transfer a package that has been built into
1157
dpkg_archive. The package is then available for general consumption.
1158
 
4549 dpurdie 1159
The utility will perform several operations in the transfer process. These incude:
1160
 
1161
=over 4
1162
 
1163
=item * 
1164
 
1165
Create a tag file to indicate the machine that has performed the transfer
1166
 
1167
=item * 
1168
 
1169
Create an XML file of files that have been transferred. This file contains information
1170
used by the build system when it releases the package, including: name, size and MD5SUM.
1171
 
1172
=item *
1173
 
1174
Detect file conflicts when different builds are merged into a single package. Header files are 
1175
allowed to differ in line ending style, but other files must not conflict. The package will not be 
1176
reproducible if file conflicts exist.
1177
 
1178
=item *
1179
 
1180
Suppress dead symbolic links. A valid symlink will be preserved, but invalid links will be 
1181
removed from the transferred image.
1182
 
1183
=back
1184
 
227 dpurdie 1185
=head2 PACKAGE LOCATION
1186
 
1187
The utility will locate a package by examining the following directores for
1188
the package description file(descpkg).
1189
 
1190
=over 8
1191
 
1192
=item ./build/deploy
1193
 
1194
This format is generated by the deployment builds. The default target archive
1195
will be taken from the environment variable GBE_DPLY.
1196
 
1197
=item ./pkg
1198
 
1199
This format is generated by JATS builds.
1200
 
1201
=item ./build/pkg
1202
 
1203
This format is generated by ANT builds.
1204
 
1205
=back
1206
 
1207
The program should be run in the same directory as the build control files as
1208
the package subdirectory will be created in that directory.
1209
 
1210
=head1 EXAMPLE
1211
 
1212
=head2 jats create_dpkg
1213
 
1214
This will locate a generated package and install it into the dpkg_archive repository.
1215
 
1216
=cut
1217