Subversion Repositories DevTools

Rev

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