Subversion Repositories DevTools

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

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