Subversion Repositories DevTools

Rev

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

Rev Author Line No. Line
1031 dpurdie 1
################################################################################
2
# Copyright (C) 2008 ERG Limited, All rights reserved
3
#
4
# Module name   : cabwiz
5
# Module type   : JATS Plugin
6
# Compiler(s)   : PERL
7
# Environment(s): JATS
8
#
9
# Description   : This program is a wrapper around the real CABWIZ
10
#                 binary. It hides, from the user, a number of issues
11
#                 with the CABWIZ program
12
#
13
#                 Intended to be invoked at "make-time"
14
#
15
#                 Will process INF file and locate required files and regenerate
16
#                 the users INF file to access the files required
17
#
18
# --- Help ---------------------------------------------------------------------
19
# Windows CE CAB Wizard
20
# Usage:  inf_file [/dest dest_dir]
21
#                  [/err err_file]
22
#                  [/cpu cpu_type [cpu_type]]
23
#                  [/platform platform_name]
24
#
25
# inf_file                INF source file to use
26
# dest_dir                absolute dest dir for CAB files
27
# err_file                error file
28
# cpu_type                cpu types to support in the INF file
29
# platform_name           the name of the platform to support in the INF file
30
#
31
#
32
# Usage:
33
#
34
#..............................................................................#
35
 
36
require 5.008_002;
37
use strict;
38
use warnings;
39
 
40
use Getopt::Long;
41
use Pod::Usage;
42
 
43
use JatsError qw( :name=CABWIZ );
44
use JatsSystem;
45
use FileUtils;
46
 
47
#
48
#   Globals
49
#
50
my $VERSION = "1.0.0";
51
my $opt_help = 0;
52
my $opt_verbose = 0;
53
my $opt_clean;
54
my $opt_inf;
55
my $opt_outdir;
56
my $opt_outfile;
57
my @opt_cpu;
58
my $opt_platform;
59
my $opt_interface;
60
my $opt_local;
61
my $opt_type;
62
my $opt_target;
63
 
64
my $base_file;
65
my $tmp_inf;
66
my $tmp_err;
67
my $gen_cab;
68
 
69
#
70
#   Configuration options
71
#
72
my $result = GetOptions (
73
                "help:+"        => \$opt_help,              # flag, multiple use allowed
74
                "manual:3"      => \$opt_help,              # flag
75
                "verbose:+"     => \$opt_verbose,           # flag
76
                "interfacedir=s"=> \$opt_interface,
77
                "LocalDir=s"    => \$opt_local,
78
                "platform=s"    => \$opt_target,
79
                "type=s"        => \$opt_type,
80
 
81
                "clean"             => \$opt_clean,
82
                "information=s"     => \$opt_inf,
83
                "output=s"          => \$opt_outfile,
84
                "cpu=s"             => \@opt_cpu,
85
                "platform_name=s"   => \$opt_platform,
86
 
87
                #
88
                #   Update documentation at the end of the file
89
                #
90
                );
91
 
92
#
93
#   Process help and manual options
94
#
95
pod2usage(-verbose => 0, -message => "Version: $VERSION")  if ($opt_help == 1  || ! $result);
96
pod2usage(-verbose => 1)  if ( $opt_help == 2 );
97
pod2usage(-verbose => 2)  if ( $opt_help > 2 );
98
 
99
#
100
#   Configure error reporting system
101
#
102
ErrorConfig( 'verbose' => $opt_verbose );
103
 
104
#
105
#   Configure File Utils
106
#   Setup the CWD
107
#
108
InitFileUtils();
109
 
110
#
111
#   Sanity check
112
#
113
Error ("No INF file") unless ( $opt_inf );
114
Error ("INF File not found: $opt_inf") unless ( -f $opt_inf );
115
Error ("No Output specified" ) unless ( $opt_outfile );
116
Error ("No Interface directory" ) unless ( $opt_interface );
117
Error ("No Local directory" ) unless ( $opt_local );
118
Error ("No Target Platform" ) unless ( $opt_target );
119
Error ("No Build Type" ) unless ( $opt_type );
120
 
121
#
122
#   Use the INF filename as a base
123
#   Determine the output directory
124
#       Do this early so that we can clean up
125
#
126
$base_file = StripDirExt( $opt_inf );
127
$opt_outdir = StripFileExt( $opt_outfile ) || '.';
128
 
129
$tmp_inf = $opt_outdir . '/' . $base_file . '.inf';
130
$tmp_err = $opt_outdir . '/' . $base_file . '.err';
131
 
132
#   The underlying utility generates a .CAB file
133
#   The EXT is in upper case
134
#   Make is case-sensitive
135
#
136
$gen_cab = $opt_outdir . '/' . $base_file . '.CAB';
137
 
138
#
139
#   Perform Clean up
140
#   Invoked during "make clean" or "make clobber"
141
#
142
if ( $opt_clean )
143
{
144
    if ( -d $opt_outdir )
145
    {
146
        unlink ( "$opt_outdir/$base_file.DAT");
147
        unlink ( $gen_cab);
148
        unlink ( $tmp_inf );
149
        unlink ( $tmp_err );
150
        unlink ( $opt_outfile );
151
    }
152
    exit 0;
153
}
154
 
155
#
156
#   Determine the absolute path to the executable
157
#   This is required as CABWIZ uses its own path to locate other
158
#   files that it needs.
159
#
160
my $cabwiz_path = LocateProgInPath( 'cabwiz.exe' );
161
Error ("CabWiz program cannot be found") unless ( $cabwiz_path );
162
 
163
#
164
#   Ensure the output directory is present
165
#
166
Error ("Output Path not found: $opt_outdir") unless ( -d $opt_outdir );
167
 
168
#
169
#   Rewrite the INF file
170
#   Transfer it to the output directory in the process
171
#
172
process_inf_file($opt_inf, $tmp_inf);
173
 
174
#
175
#   Create an array that will be the CabWiz command
176
#       Convert paths to Absolute Windoes form
177
#       Always use an error file: Prevents the app from creating pop-ups
178
#
179
my @cmd = (WinAbs($cabwiz_path), WinAbs($tmp_inf));
180
push @cmd, '/dest', WinAbs($opt_outdir);
181
push @cmd, '/err', WinAbs($tmp_err);
182
push @cmd, '/cpu', @opt_cpu, if ( @opt_cpu );
183
push @cmd, '/platform', $opt_platform if ( $opt_platform );
184
 
185
#
186
#   Execute the command
187
#   Handle errors my self
188
#
189
unlink ( $tmp_err );
190
my $rv = System ('--NoExit',@cmd);
191
 
192
#
193
#   Display any warnings/errors from the CabWiz util
194
#
195
System ('cat', $tmp_err ) if ( -f $tmp_err );
196
 
197
#
198
#   Do we have a CAB file
199
#
200
Error ("CabWiz reported an error") if ( $rv );
201
Error ("Genereted CAB file not found",$gen_cab) unless ( -f $gen_cab );
202
 
203
#
204
#   Fix case/name of the output file
205
#   Note: Both are in Non-Windows format so we can do a direct comparison
206
#
207
Verbose ("Generated File : $gen_cab");
208
Verbose ("User Named File: $opt_outfile");
209
unless ( $opt_outfile eq $gen_cab )
210
{
211
    Verbose ("Renaming output CAB file");
212
    rename $gen_cab,$opt_outfile ;
213
}
214
 
215
exit 0;
216
 
217
 
218
#-------------------------------------------------------------------------------
219
# Function        : WinAbs
220
#
221
# Description     : Convert a relative file name into an absolute
222
#                   widnows Sytle file name
223
#
224
# Inputs          : $_[0]               - Name to convert
225
#
226
# Returns         : Absolute file name with windows \
227
#
228
sub WinAbs
229
{
230
    my $file = FullPath( $_[0] );
231
    $file =~ tr~/~\\~s;
232
    return $file;
233
}
234
 
235
#-------------------------------------------------------------------------------
236
# Function        : process_inf_file
237
#
238
# Description     : Rewrite the INF file
239
#                   Modify 'SourceDisksNames' and 'SourceDisksFiles'
240
#                   to address files found within the scope of the package
241
#
242
# Inputs          : $src            - Source INF file
243
#                   $outfile        - Output filename
244
#
245
# Returns         : Nothing
246
#
247
 
248
sub process_inf_file
249
{
250
    my ($src, $outfile) = @_;
251
    my $section = '';                           # Initial Unknown section
252
    my @sections;                               # Order of the sections
253
    my %info;                                   # Hash of arrays
254
    my @data;                                   # Accumulate data
255
    my %dirs;                                   # Dirs for files
256
    my $dirs_index;                             # Dirs index
257
 
258
 
259
    Error ("Source INF not found: $src") unless ( -f $src );
260
 
261
    #
262
    #   Open the INF file
263
    #   Read it in
264
    #       Break it into sections
265
    #       Retain comment blocks
266
    #
267
    open (PF, "<$src") || Error ("Cannot open file: $src", "Reason: $!");
268
    while ( <PF> )
269
    {
270
        s~\s+$~~ ;                          # Strip trailing white space + eol(s)
271
        if ( m~^\[(.+)\]~ )                 # Detect start of a new section
272
        {
273
            #
274
            #   Save data from current section
275
            #
276
            $info{$section} = [@data];      # Section data
277
            push @sections, $section;       # Retain section ordering
278
            @data = ();
279
 
280
            $section = $1;
281
            next;
282
        }
283
        push @data, $_;
284
    }
285
    $info{$section} = [@data];              # Last section
286
    push @sections, $section;               # Last section
287
    close PF;
288
 
289
    #
290
    #   Scan entries in the "SourceDisksFiles"
291
    #   Locate the files that have been named
292
    #   Allow user to place path into in filename
293
    #
294
    #   Format:
295
    #       <filename> = <source ID>
296
    #       <filename> is the source filename (enclose in doublequotes for long filenames)
297
    #       <source ID> is the ID used in [SourceDisksNames] to specify the source directory
298
    #
299
    @data = ();
300
    $section = 'SourceDisksFiles';
301
    foreach  ( @{$info{$section}} )
302
    {
303
        #
304
        #   Keep coments
305
        #
306
        if ( m~^\s*;~  || m~^\s*$~)
307
        {
308
            push @data, $_;
309
            next;
310
        }
311
 
312
        m~(.+?)\s*=\s*(.+?)(\s*;.*)?$~ || Error ("Could not parse INF line","Line: $_");
313
        my $file = $1;
314
        my $index = $2;
315
        my $comment = $3 || '';
316
 
317
        $file = $1 if ( $file =~ m~^"(.+)"$~ );
318
        my $dir;
319
        ($dir, $file) = locate_file_in_packages ($file);
320
        if ( exists $dirs{$dir} )
321
        {
322
            $index = $dirs{$dir}{index};
323
        }
324
        else
325
        {
326
            $index = ++$dirs_index;
327
            $dirs{$dir}{index} = $index;
328
        }
329
 
330
        push @data, "\"$file\" = $index${comment}";
331
        Verbose ("INF: $section: $file :: $index :: $dir" );
332
    }
333
    $info{$section} = [@data];
334
 
335
 
336
    #
337
    #   Scan entries in SourceDisksNames
338
    #   Comment out the entire section and rewrite it with information
339
    #   that has been collected on the fly
340
    #   Use absolute directory paths
341
    #
342
    #   Format:
343
    #	    <source ID> = ,<label>,,<source directory>
344
    #           <source ID>         will be used to specify the source files
345
    #                               belonging to this directory
346
    #           <label>             is unused
347
    #           <source directory>  is the relative or absolute directory
348
    #                               of the source files
349
    #
350
    #
351
    @data = ();
352
    $section = 'SourceDisksNames';
353
 
354
    #
355
    #   Insert new data
356
    #
357
    foreach my $dir ( keys %dirs )
358
    {
359
        my $tag = $dirs{$dir}{index};
360
        my $sdir = WinAbs($dir);
361
        push @data, "$tag = ,\"Jats Generated\",,\"${sdir}\"";
362
        Verbose ("INF: SourceDisksNames: $tag :: $sdir" );
363
    }
364
    @data = sort @data;
365
 
366
    foreach  ( @{$info{$section}} )
367
    {
368
        #
369
        #   Retain original - but as a comment
370
        #
371
        my $prefix = ($_ =~ m~^\s*;~) ? '' : '; ';
372
        push @data, $prefix . $_;
373
    }
374
 
375
    $info{$section} = [@data];
376
 
377
    #
378
    #   Generate the output file
379
    #   Create an array of arrays to output
380
    #
381
    @data = ();
382
    foreach $section ( @sections )
383
    {
384
        push @data, "[$section]" if ( $section );
385
        push @data, \@{$info{$section}};
386
    }
387
 
388
    Verbose ("Rewrite INF file: $outfile");
389
    FileCreate ($outfile, @data );
390
}
391
 
392
#-------------------------------------------------------------------------------
393
# Function        : locate_file_in_packages
394
#
395
# Description     : Locate a named file in the source packages
396
#                   This is a simple Package File Scanner
397
#                   It is designed to pick up
398
#                       Windows executables (bin)
399
#                       Windows shared libraries (lib)
400
#                       Config files (etc)
401
#
402
# Inputs          : $file           - Name of file to find
403
#                                     May contain a directory
404
#
405
#
406
# Returns         : Path to the file ( without the file name)
407
#                   Filename
408
#
409
my @pkg_paths;
410
my @plat_parts;
411
my @locate_dir_list;
412
sub locate_file_in_packages
413
{
414
    my ($file) = @_;
415
    my @found;
416
    my @scanned;
417
    Debug ("Locate file: $file");
418
 
419
    #
420
    #   Read in package data from build files
421
    #   Determine list of package directories
422
    #   Determine list of platform parts
423
    #
424
    unless ( @plat_parts )
425
    {
426
        use ReadBuildConfig;
427
        ReadBuildConfig( $opt_interface, $opt_target, '--NoTest' );
428
        @pkg_paths = ($opt_local, getPackagePaths("--Interface=$opt_interface"));
429
        @plat_parts = getPlatformParts ();
430
 
431
        #
432
        #   Create a list of available directories
433
        #   Do this once as it may be slow
434
        #
1033 dpurdie 435
        @locate_dir_list  = qw(.); 
1031 dpurdie 436
        foreach my $pkg ( @pkg_paths )
437
        {
438
            foreach my $part ( @plat_parts, '' )
439
            {
440
                foreach my $bit ( 'bin', 'lib', 'etc' )
441
                {
442
                    my @types = ($part) ? ($opt_type) : ();
443
                    foreach my $type ( @types ,'' )
444
                    {
445
                        my @joins = ($part) ? ("$bit.", "$bit/", "$bit/$bit.") : ("$bit/");
446
                        foreach my $join ( @joins )
447
                        {
448
                            my $dir = "$pkg/$join$part$type";
449
                            push @locate_dir_list, $dir if ( -d $dir);
450
                        }
451
                    }
452
                }
453
            }
454
        }
455
        Verbose2 ("Scan Files in:", @locate_dir_list);
456
    }
457
 
458
    #
459
    #   Scan the list of known available directories for the specified file.
460
    #
461
    foreach my $dir ( @locate_dir_list )
462
    {
463
        Verbose2 ("Look at: $file:  $dir");
464
        next unless ( -f "$dir/$file" );
465
        push @found, $dir;
466
    }
467
 
468
    #
469
    #   Report errors and warnings
470
    #
471
    Error ("Required file not found in packages: $file","Scanned:", @locate_dir_list)
472
        if ( $#found < 0 );
473
    Warning ("Required file found in multiple locations. First used",
474
             "File: $file",
475
             "Locations:", @found ) if ( $#found > 0 );
476
 
477
    #
478
    #   All the usr to specify 'subdir/path/file'
479
    #   Return file and dir
480
    #
481
    my $dir = "$found[0]/$file";
482
    return (StripFileExt($dir), StripDir($dir));
483
}
484
 
485
#-------------------------------------------------------------------------------
486
#   Documentation
487
#
488
 
489
=pod
490
 
491
=head1 NAME
492
 
493
cabwiz.pl - CabWiz wrapper
494
 
495
=head1 SYNOPSIS
496
 
497
  cabwiz.pl [options]
498
 
499
 Options:
500
    -help[=n]           - brief help message
501
    -help -help         - Detailed help message
502
    -man[=n]            - Full documentation
503
    -verbose[=n]        - Verbose operation
504
    -clean              - Clean up generated files
505
    -information=path   - Path of the INFO file
506
    -output=file        - Generated CAB file
507
    -cpu=name           - Name of CPU (optional, multiple)
508
    -platform=name      - Named platform (optional)
509
 
510
=head1 OPTIONS
511
 
512
=over 8
513
 
514
=item B<-help[=n]>
515
 
516
Print a brief help message and exits.
517
 
518
The verbosity of the help text can be controlled by setting the help level to a
519
number in the range of 1 to 3, or by invoking the option multiple times.
520
 
521
=item B<-man[=n]>
522
 
523
Without a numeric argument this is the same as -help=3. Full help will be
524
displayed.
525
 
526
With a numeric argument, this option is the same as -help=n.
527
 
528
=item B<-verbose[=n]>
529
 
530
This option will increase the level of verbosity of the utility.
531
 
532
If an argument is provided, then it will be used to set the level, otherwise the
533
existing level will be incremented. This option may be specified multiple times.
534
 
535
=item B<-information=xxxx>
536
 
537
This option specifies the name of source INF file used in the creation of a
538
Cabnet file. This option is mandatory.
539
 
540
=item B<-output=xxxx>
541
 
542
This option specifies the name of the generated CAB file.
543
The directory compoennt of this file will be used by the underlying utilities
544
as a work area and the root of the INF file
545
 
546
This wrapper script will correct the case and name of the generated CAB file
547
to that required by the user.
548
 
549
=item B<-cpu=name>
550
 
551
This option specifies the name of a CPU for which the CAB file will be
552
generated. This option may be specified more than once to allow the
553
specification of multiple CPUs.
554
 
555
=item B<-platform=name>
556
 
557
This option, if present, specifies the name of the platform for which the CAB
558
file will be generated.
559
 
560
=back
561
 
562
=head1 DESCRIPTION
563
 
564
This utility is used to simplify the interface to the CabWiz executable within
565
the JATS build environment.
566
 
567
It will:
568
 
569
=over 8
570
 
571
=item * Scan the SourceDisksFiles section
572
 
573
It scans this section to determine the source files used by the INF file, the
574
utilty will then create a local copy of te INF file and create the
575
SourceDisksNames and SourceDisksFiles to use absolute paths to files located
576
within external packages.
577
 
578
=item * Convert relative pathnames to absolute names
579
 
580
=item * Rename the generated CAB file as required
581
 
582
=item * Clean up intermediate files
583
 
584
=back
585
 
586
=cut
587
 
588