Subversion Repositories DevTools

Rev

Rev 1033 | Go to most recent revision | Details | 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
        #
435
        foreach my $pkg ( @pkg_paths )
436
        {
437
            foreach my $part ( @plat_parts, '' )
438
            {
439
                foreach my $bit ( 'bin', 'lib', 'etc' )
440
                {
441
                    my @types = ($part) ? ($opt_type) : ();
442
                    foreach my $type ( @types ,'' )
443
                    {
444
                        my @joins = ($part) ? ("$bit.", "$bit/", "$bit/$bit.") : ("$bit/");
445
                        foreach my $join ( @joins )
446
                        {
447
                            my $dir = "$pkg/$join$part$type";
448
                            push @locate_dir_list, $dir if ( -d $dir);
449
                        }
450
                    }
451
                }
452
            }
453
        }
454
        Verbose2 ("Scan Files in:", @locate_dir_list);
455
    }
456
 
457
    #
458
    #   Scan the list of known available directories for the specified file.
459
    #
460
    foreach my $dir ( @locate_dir_list )
461
    {
462
        Verbose2 ("Look at: $file:  $dir");
463
        next unless ( -f "$dir/$file" );
464
        push @found, $dir;
465
    }
466
 
467
    #
468
    #   Report errors and warnings
469
    #
470
    Error ("Required file not found in packages: $file","Scanned:", @locate_dir_list)
471
        if ( $#found < 0 );
472
    Warning ("Required file found in multiple locations. First used",
473
             "File: $file",
474
             "Locations:", @found ) if ( $#found > 0 );
475
 
476
    #
477
    #   All the usr to specify 'subdir/path/file'
478
    #   Return file and dir
479
    #
480
    my $dir = "$found[0]/$file";
481
    return (StripFileExt($dir), StripDir($dir));
482
}
483
 
484
#-------------------------------------------------------------------------------
485
#   Documentation
486
#
487
 
488
=pod
489
 
490
=head1 NAME
491
 
492
cabwiz.pl - CabWiz wrapper
493
 
494
=head1 SYNOPSIS
495
 
496
  cabwiz.pl [options]
497
 
498
 Options:
499
    -help[=n]           - brief help message
500
    -help -help         - Detailed help message
501
    -man[=n]            - Full documentation
502
    -verbose[=n]        - Verbose operation
503
    -clean              - Clean up generated files
504
    -information=path   - Path of the INFO file
505
    -output=file        - Generated CAB file
506
    -cpu=name           - Name of CPU (optional, multiple)
507
    -platform=name      - Named platform (optional)
508
 
509
=head1 OPTIONS
510
 
511
=over 8
512
 
513
=item B<-help[=n]>
514
 
515
Print a brief help message and exits.
516
 
517
The verbosity of the help text can be controlled by setting the help level to a
518
number in the range of 1 to 3, or by invoking the option multiple times.
519
 
520
=item B<-man[=n]>
521
 
522
Without a numeric argument this is the same as -help=3. Full help will be
523
displayed.
524
 
525
With a numeric argument, this option is the same as -help=n.
526
 
527
=item B<-verbose[=n]>
528
 
529
This option will increase the level of verbosity of the utility.
530
 
531
If an argument is provided, then it will be used to set the level, otherwise the
532
existing level will be incremented. This option may be specified multiple times.
533
 
534
=item B<-information=xxxx>
535
 
536
This option specifies the name of source INF file used in the creation of a
537
Cabnet file. This option is mandatory.
538
 
539
=item B<-output=xxxx>
540
 
541
This option specifies the name of the generated CAB file.
542
The directory compoennt of this file will be used by the underlying utilities
543
as a work area and the root of the INF file
544
 
545
This wrapper script will correct the case and name of the generated CAB file
546
to that required by the user.
547
 
548
=item B<-cpu=name>
549
 
550
This option specifies the name of a CPU for which the CAB file will be
551
generated. This option may be specified more than once to allow the
552
specification of multiple CPUs.
553
 
554
=item B<-platform=name>
555
 
556
This option, if present, specifies the name of the platform for which the CAB
557
file will be generated.
558
 
559
=back
560
 
561
=head1 DESCRIPTION
562
 
563
This utility is used to simplify the interface to the CabWiz executable within
564
the JATS build environment.
565
 
566
It will:
567
 
568
=over 8
569
 
570
=item * Scan the SourceDisksFiles section
571
 
572
It scans this section to determine the source files used by the INF file, the
573
utilty will then create a local copy of te INF file and create the
574
SourceDisksNames and SourceDisksFiles to use absolute paths to files located
575
within external packages.
576
 
577
=item * Convert relative pathnames to absolute names
578
 
579
=item * Rename the generated CAB file as required
580
 
581
=item * Clean up intermediate files
582
 
583
=back
584
 
585
=cut
586
 
587