1*b1cdbd2cSJim Jagielski:
2*b1cdbd2cSJim Jagielskieval 'exec perl -wS $0 ${1+"$@"}'
3*b1cdbd2cSJim Jagielski    if 0;
4*b1cdbd2cSJim Jagielski#**************************************************************
5*b1cdbd2cSJim Jagielski#
6*b1cdbd2cSJim Jagielski#  Licensed to the Apache Software Foundation (ASF) under one
7*b1cdbd2cSJim Jagielski#  or more contributor license agreements.  See the NOTICE file
8*b1cdbd2cSJim Jagielski#  distributed with this work for additional information
9*b1cdbd2cSJim Jagielski#  regarding copyright ownership.  The ASF licenses this file
10*b1cdbd2cSJim Jagielski#  to you under the Apache License, Version 2.0 (the
11*b1cdbd2cSJim Jagielski#  "License"); you may not use this file except in compliance
12*b1cdbd2cSJim Jagielski#  with the License.  You may obtain a copy of the License at
13*b1cdbd2cSJim Jagielski#
14*b1cdbd2cSJim Jagielski#    http://www.apache.org/licenses/LICENSE-2.0
15*b1cdbd2cSJim Jagielski#
16*b1cdbd2cSJim Jagielski#  Unless required by applicable law or agreed to in writing,
17*b1cdbd2cSJim Jagielski#  software distributed under the License is distributed on an
18*b1cdbd2cSJim Jagielski#  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
19*b1cdbd2cSJim Jagielski#  KIND, either express or implied.  See the License for the
20*b1cdbd2cSJim Jagielski#  specific language governing permissions and limitations
21*b1cdbd2cSJim Jagielski#  under the License.
22*b1cdbd2cSJim Jagielski#
23*b1cdbd2cSJim Jagielski#**************************************************************
24*b1cdbd2cSJim Jagielski
25*b1cdbd2cSJim Jagielski
26*b1cdbd2cSJim Jagielski#
27*b1cdbd2cSJim Jagielski#
28*b1cdbd2cSJim Jagielski# checkdeliver.pl - compare delivered files on solver with those on SRC_ROOT
29*b1cdbd2cSJim Jagielski#
30*b1cdbd2cSJim Jagielski
31*b1cdbd2cSJim Jagielskiuse strict;
32*b1cdbd2cSJim Jagielskiuse Getopt::Long;
33*b1cdbd2cSJim Jagielskiuse File::stat;
34*b1cdbd2cSJim Jagielskiuse IO::Handle;
35*b1cdbd2cSJim Jagielski
36*b1cdbd2cSJim Jagielskiuse lib ("$ENV{SOLARENV}/bin/modules");
37*b1cdbd2cSJim Jagielski
38*b1cdbd2cSJim Jagielski#### globals #####
39*b1cdbd2cSJim Jagielski
40*b1cdbd2cSJim Jagielskimy $err              = 0;
41*b1cdbd2cSJim Jagielskimy $srcrootdir       = '';
42*b1cdbd2cSJim Jagielskimy $solverdir        = '';
43*b1cdbd2cSJim Jagielskimy $platform         = '';
44*b1cdbd2cSJim Jagielskimy $logfile          = '';
45*b1cdbd2cSJim Jagielskimy $milestoneext     = '';
46*b1cdbd2cSJim Jagielskimy $local_env        = 0;
47*b1cdbd2cSJim Jagielskimy @exceptionmodlist = (
48*b1cdbd2cSJim Jagielski                        "postprocess",
49*b1cdbd2cSJim Jagielski                        "instset.*native",
50*b1cdbd2cSJim Jagielski                        "smoketest.*native",
51*b1cdbd2cSJim Jagielski                        "testgraphical"
52*b1cdbd2cSJim Jagielski                       ); # modules not yet delivered
53*b1cdbd2cSJim Jagielski
54*b1cdbd2cSJim Jagielski#### main #####
55*b1cdbd2cSJim Jagielski
56*b1cdbd2cSJim Jagielskiprint_logged("checkdeliver.pl - checking delivered binaries\n");
57*b1cdbd2cSJim Jagielski
58*b1cdbd2cSJim Jagielskiget_globals();                                  # get global variables
59*b1cdbd2cSJim Jagielskimy $deliverlists_ref = get_deliver_lists();     # get deliver log files
60*b1cdbd2cSJim Jagielskiforeach my $listfile ( @$deliverlists_ref ) {
61*b1cdbd2cSJim Jagielski    $err += check( $listfile );                 # check delivered files
62*b1cdbd2cSJim Jagielski}
63*b1cdbd2cSJim Jagielskiprint_logged("OK\n") if ( ! $err );
64*b1cdbd2cSJim Jagielskiexit $err;
65*b1cdbd2cSJim Jagielski
66*b1cdbd2cSJim Jagielski#### subroutines ####
67*b1cdbd2cSJim Jagielski
68*b1cdbd2cSJim Jagielskisub get_globals
69*b1cdbd2cSJim Jagielski# set global variables using environment variables and command line options
70*b1cdbd2cSJim Jagielski{
71*b1cdbd2cSJim Jagielski    my $help;
72*b1cdbd2cSJim Jagielski
73*b1cdbd2cSJim Jagielski    # set global variables according to environnment
74*b1cdbd2cSJim Jagielski    $platform      = $ENV{INPATH};
75*b1cdbd2cSJim Jagielski    $srcrootdir    = $ENV{SOURCE_ROOT_DIR};
76*b1cdbd2cSJim Jagielski    $solverdir     = $ENV{SOLARVERSION};
77*b1cdbd2cSJim Jagielski    $milestoneext  = $ENV{UPDMINOREXT};
78*b1cdbd2cSJim Jagielski
79*b1cdbd2cSJim Jagielski    # override environment with command line options
80*b1cdbd2cSJim Jagielski    GetOptions('help' => \$help,
81*b1cdbd2cSJim Jagielski               'l=s'  => \$logfile,
82*b1cdbd2cSJim Jagielski               'p=s'  => \$platform
83*b1cdbd2cSJim Jagielski    ) or usage (1);
84*b1cdbd2cSJim Jagielski
85*b1cdbd2cSJim Jagielski    if ( $help ) {
86*b1cdbd2cSJim Jagielski        usage(0);
87*b1cdbd2cSJim Jagielski    }
88*b1cdbd2cSJim Jagielski
89*b1cdbd2cSJim Jagielski    #do some sanity checks
90*b1cdbd2cSJim Jagielski    if ( ! ( $platform && $srcrootdir && $solverdir ) ) {
91*b1cdbd2cSJim Jagielski        die "Error: please set environment\n";
92*b1cdbd2cSJim Jagielski    }
93*b1cdbd2cSJim Jagielski    if ( ! -d $solverdir ) {
94*b1cdbd2cSJim Jagielski        die "Error: cannot find solver directory '$solverdir'\n";
95*b1cdbd2cSJim Jagielski    }
96*b1cdbd2cSJim Jagielski
97*b1cdbd2cSJim Jagielski    # Check for local env., taken from solenv/bin/modules/installer/control.pm
98*b1cdbd2cSJim Jagielski    # In this case the content of SOLARENV starts with the content of SOL_TMP
99*b1cdbd2cSJim Jagielski    my $solarenv = "";
100*b1cdbd2cSJim Jagielski    my $sol_tmp;
101*b1cdbd2cSJim Jagielski    if ( $ENV{'SOLARENV'} ) {
102*b1cdbd2cSJim Jagielski        $solarenv = $ENV{'SOLARENV'};
103*b1cdbd2cSJim Jagielski    }
104*b1cdbd2cSJim Jagielski    if ( $ENV{'SOL_TMP'} ) {
105*b1cdbd2cSJim Jagielski        $sol_tmp = $ENV{'SOL_TMP'};
106*b1cdbd2cSJim Jagielski    }
107*b1cdbd2cSJim Jagielski    if ( defined $sol_tmp && ( $solarenv =~ /^\s*\Q$sol_tmp\E/ )) {
108*b1cdbd2cSJim Jagielski        # Content of SOLARENV starts with the content of SOL_TMP: Local environment
109*b1cdbd2cSJim Jagielski        $local_env = 1;
110*b1cdbd2cSJim Jagielski    }
111*b1cdbd2cSJim Jagielski}
112*b1cdbd2cSJim Jagielski
113*b1cdbd2cSJim Jagielskisub get_deliver_lists
114*b1cdbd2cSJim Jagielski# find deliver log files on solver
115*b1cdbd2cSJim Jagielski{
116*b1cdbd2cSJim Jagielski    my @files;
117*b1cdbd2cSJim Jagielski    my $pattern = "$solverdir/$platform/inc";
118*b1cdbd2cSJim Jagielski    $pattern .= "$milestoneext" if ( $milestoneext );
119*b1cdbd2cSJim Jagielski    $pattern .= "/*/deliver.log";
120*b1cdbd2cSJim Jagielski
121*b1cdbd2cSJim Jagielski    @files = glob( $pattern );
122*b1cdbd2cSJim Jagielski    # do not check modules not yet built
123*b1cdbd2cSJim Jagielski    foreach my $exceptionpattern ( @exceptionmodlist ) {
124*b1cdbd2cSJim Jagielski        @files = grep ! /\/$exceptionpattern\//, @files;
125*b1cdbd2cSJim Jagielski    }
126*b1cdbd2cSJim Jagielski    if ( ! @files ) {
127*b1cdbd2cSJim Jagielski        print_logged( "Error: cannot find deliver log files\n" );
128*b1cdbd2cSJim Jagielski        exit 1;
129*b1cdbd2cSJim Jagielski    }
130*b1cdbd2cSJim Jagielski    return \@files;
131*b1cdbd2cSJim Jagielski}
132*b1cdbd2cSJim Jagielski
133*b1cdbd2cSJim Jagielskisub check
134*b1cdbd2cSJim Jagielski# reads deliver log file given as parameter and compares pairs of files listed there.
135*b1cdbd2cSJim Jagielski{
136*b1cdbd2cSJim Jagielski    my $listname = shift;
137*b1cdbd2cSJim Jagielski    my $error = 0;
138*b1cdbd2cSJim Jagielski    my %delivered;
139*b1cdbd2cSJim Jagielski    my $module;
140*b1cdbd2cSJim Jagielski    my $repository;
141*b1cdbd2cSJim Jagielski    STDOUT->autoflush(1);
142*b1cdbd2cSJim Jagielski    # which module are we checking?
143*b1cdbd2cSJim Jagielski    if ( $listname =~ /\/([\w-]+?)\/deliver\.log$/o) {
144*b1cdbd2cSJim Jagielski        $module = $1;
145*b1cdbd2cSJim Jagielski    } else {
146*b1cdbd2cSJim Jagielski        print_logged( "Error: cannot determine module name from \'$listname\'\n" );
147*b1cdbd2cSJim Jagielski        return 1;
148*b1cdbd2cSJim Jagielski    }
149*b1cdbd2cSJim Jagielski
150*b1cdbd2cSJim Jagielski    if ( -z $listname ) {
151*b1cdbd2cSJim Jagielski        print_logged( "Warning: empty deliver log file \'$listname\'. Module '$module' not delivered correctly?\n\n" );
152*b1cdbd2cSJim Jagielski        return 0;
153*b1cdbd2cSJim Jagielski    }
154*b1cdbd2cSJim Jagielski
155*b1cdbd2cSJim Jagielski    # read deliver log file
156*b1cdbd2cSJim Jagielski    if ( ! open( DELIVERLOG, "< $listname" ) ) {
157*b1cdbd2cSJim Jagielski        print_logged( "Error: cannot open file \'$listname\'\n$!" );
158*b1cdbd2cSJim Jagielski        exit 2;
159*b1cdbd2cSJim Jagielski    }
160*b1cdbd2cSJim Jagielski    while ( <DELIVERLOG> ) {
161*b1cdbd2cSJim Jagielski        next if ( /^LINK / );
162*b1cdbd2cSJim Jagielski        # What's this modules' repository?
163*b1cdbd2cSJim Jagielski        if ( /COPY\s+(.+?)\/$module\/prj\/build.lst/ ) {
164*b1cdbd2cSJim Jagielski#        if ( /COPY (\w[\w\s-]*?)\/$module\/prj\/build.lst/ ) {
165*b1cdbd2cSJim Jagielski            $repository = $1;
166*b1cdbd2cSJim Jagielski        }
167*b1cdbd2cSJim Jagielski        # For now we concentrate on binaries, located in 'bin' or 'lib' and 'misc/build/<...>/[bin|lib]'.
168*b1cdbd2cSJim Jagielski        next if ( (! /\/$module\/$platform\/[bl]i[nb]\//) && (! /\/$module\/$platform\/misc\/build\//));
169*b1cdbd2cSJim Jagielski        next if (! /[bl]i[nb]/);
170*b1cdbd2cSJim Jagielski        next if ( /\.html$/ );
171*b1cdbd2cSJim Jagielski        chomp;
172*b1cdbd2cSJim Jagielski        if ( /^\w+? (\S+) (\S+)\s*$/o ) {
173*b1cdbd2cSJim Jagielski            my $origin = $1;
174*b1cdbd2cSJim Jagielski            $delivered{$origin} = $2;
175*b1cdbd2cSJim Jagielski        } else {
176*b1cdbd2cSJim Jagielski            print_logged( "Warning: cannot parse \'$listname\' line\n\'$_\'\n" );
177*b1cdbd2cSJim Jagielski        }
178*b1cdbd2cSJim Jagielski    }
179*b1cdbd2cSJim Jagielski    close( DELIVERLOG );
180*b1cdbd2cSJim Jagielski
181*b1cdbd2cSJim Jagielski    if ( ! $repository ) {
182*b1cdbd2cSJim Jagielski        print_logged( "Error parsing \'$listname\': cannot determine repository. Module '$module' not delivered correctly?\n\n" );
183*b1cdbd2cSJim Jagielski        $error ++;
184*b1cdbd2cSJim Jagielski        return $error;
185*b1cdbd2cSJim Jagielski    }
186*b1cdbd2cSJim Jagielski
187*b1cdbd2cSJim Jagielski    my $path = "$srcrootdir/$repository/$module";
188*b1cdbd2cSJim Jagielski    # is module physically accessible?
189*b1cdbd2cSJim Jagielski    # there are valid use cases where we build against a prebuild solver whithout having
190*b1cdbd2cSJim Jagielski    # all modules at disk
191*b1cdbd2cSJim Jagielski    my $canread = is_moduledirectory( $path );
192*b1cdbd2cSJim Jagielski    if ( ! $canread ) {
193*b1cdbd2cSJim Jagielski        # do not bother about non existing modules in local environment
194*b1cdbd2cSJim Jagielski        # or on childworkspaces
195*b1cdbd2cSJim Jagielski        if (( $local_env ) || ( $ENV{CWS_WORK_STAMP} )) {
196*b1cdbd2cSJim Jagielski            return $error;
197*b1cdbd2cSJim Jagielski        }
198*b1cdbd2cSJim Jagielski        # in a master build it is considered an error to have deliver leftovers
199*b1cdbd2cSJim Jagielski        # from non exising (removed) modules
200*b1cdbd2cSJim Jagielski        print_logged( "Error: module '$module' not found.\n" );
201*b1cdbd2cSJim Jagielski        $error++;
202*b1cdbd2cSJim Jagielski        return $error;
203*b1cdbd2cSJim Jagielski    }
204*b1cdbd2cSJim Jagielski    if ( $canread == 2 ) {
205*b1cdbd2cSJim Jagielski        # module is linked and not built, no need for checking
206*b1cdbd2cSJim Jagielski        # should not happen any more nowadays ...
207*b1cdbd2cSJim Jagielski        return $error;
208*b1cdbd2cSJim Jagielski    }
209*b1cdbd2cSJim Jagielski
210*b1cdbd2cSJim Jagielski    # compare all delivered files with their origin
211*b1cdbd2cSJim Jagielski    # no strict 'diff' allowed here, as deliver may alter files (hedabu, strip, ...)
212*b1cdbd2cSJim Jagielski    foreach my $file ( sort keys %delivered ) {
213*b1cdbd2cSJim Jagielski        my $ofile = "$srcrootdir/$file";
214*b1cdbd2cSJim Jagielski        my $sfile = "$solverdir/$delivered{$file}";
215*b1cdbd2cSJim Jagielski        if ( $milestoneext ) {
216*b1cdbd2cSJim Jagielski            # deliver log files do not contain milestone extension on solver
217*b1cdbd2cSJim Jagielski            $sfile =~ s/\/$platform\/(...)\//\/$platform\/$1$milestoneext\//;
218*b1cdbd2cSJim Jagielski        }
219*b1cdbd2cSJim Jagielski        my $orgfile_stats = stat($ofile);
220*b1cdbd2cSJim Jagielski        next if ( -d _ );  # compare files, not directories
221*b1cdbd2cSJim Jagielski        my $delivered_stats = lstat($sfile);
222*b1cdbd2cSJim Jagielski        next if ( -d _ );  # compare files, not directories
223*b1cdbd2cSJim Jagielski        if ( $^O !~ /^MSWin/ ) {
224*b1cdbd2cSJim Jagielski            # windows does not know about links.
225*b1cdbd2cSJim Jagielski            # Therefore lstat() is not a lstat, and the following check would break
226*b1cdbd2cSJim Jagielski            next if ( -l _ );  # compare files, not links
227*b1cdbd2cSJim Jagielski        }
228*b1cdbd2cSJim Jagielski
229*b1cdbd2cSJim Jagielski        if ( $orgfile_stats && $delivered_stats ) {
230*b1cdbd2cSJim Jagielski            # Stripping (on unix like platforms) and signing (for windows)
231*b1cdbd2cSJim Jagielski            # changes file size. Therefore we have to compare for file dates.
232*b1cdbd2cSJim Jagielski            # File modification time also can change after deliver, f.e. by
233*b1cdbd2cSJim Jagielski            # rebasing, but only increase. It must not happen that a file on
234*b1cdbd2cSJim Jagielski            # solver is older than it's source.
235*b1cdbd2cSJim Jagielski            if ( ( $orgfile_stats->mtime - $delivered_stats->mtime ) gt 1 ) {
236*b1cdbd2cSJim Jagielski                print_logged( "Error: " );
237*b1cdbd2cSJim Jagielski                print_logged( "delivered file is older than it's source '$ofile' '$sfile'\n" );
238*b1cdbd2cSJim Jagielski                $error ++;
239*b1cdbd2cSJim Jagielski            }
240*b1cdbd2cSJim Jagielski        } elsif ( !$orgfile_stats && $delivered_stats ) {
241*b1cdbd2cSJim Jagielski            # This is not an error if we have a solver and did not build the
242*b1cdbd2cSJim Jagielski            # module!
243*b1cdbd2cSJim Jagielski        } elsif ( !$orgfile_stats && !$delivered_stats ) {
244*b1cdbd2cSJim Jagielski            # This is not necessarily an error.
245*b1cdbd2cSJim Jagielski            # Instead, this seems to be an error of the deliver.log file.
246*b1cdbd2cSJim Jagielski        } else {
247*b1cdbd2cSJim Jagielski            print_logged( "Error: no such file '$ofile'\n" ) if ( ! $orgfile_stats );
248*b1cdbd2cSJim Jagielski            print_logged( "Error: no such file '$sfile'\n" ) if ( ! $delivered_stats );
249*b1cdbd2cSJim Jagielski            $error ++;
250*b1cdbd2cSJim Jagielski        }
251*b1cdbd2cSJim Jagielski    }
252*b1cdbd2cSJim Jagielski    if ( $error ) {
253*b1cdbd2cSJim Jagielski        print_logged( "$error errors found: Module '$module' not delivered correctly?\n\n" );
254*b1cdbd2cSJim Jagielski    }
255*b1cdbd2cSJim Jagielski    STDOUT->autoflush(0);
256*b1cdbd2cSJim Jagielski    return $error;
257*b1cdbd2cSJim Jagielski}
258*b1cdbd2cSJim Jagielski
259*b1cdbd2cSJim Jagielskisub is_moduledirectory
260*b1cdbd2cSJim Jagielski# Test whether we find a module having a d.lst file at a given path.
261*b1cdbd2cSJim Jagielski# Return value: 1: path is valid directory
262*b1cdbd2cSJim Jagielski#               2: path.link is a valid link
263*b1cdbd2cSJim Jagielski#               0: module not found
264*b1cdbd2cSJim Jagielski{
265*b1cdbd2cSJim Jagielski    my $dirname = shift;
266*b1cdbd2cSJim Jagielski    if ( -e "$dirname/prj/d.lst" ) {
267*b1cdbd2cSJim Jagielski        return 1;
268*b1cdbd2cSJim Jagielski    } elsif ( -e "$dirname.link/prj/d.lst" ) {
269*b1cdbd2cSJim Jagielski        return 2
270*b1cdbd2cSJim Jagielski    } else {
271*b1cdbd2cSJim Jagielski        return 0;
272*b1cdbd2cSJim Jagielski    }
273*b1cdbd2cSJim Jagielski}
274*b1cdbd2cSJim Jagielski
275*b1cdbd2cSJim Jagielskisub print_logged
276*b1cdbd2cSJim Jagielski# Print routine.
277*b1cdbd2cSJim Jagielski# If a log file name is specified with '-l' option, print_logged() prints to that file
278*b1cdbd2cSJim Jagielski# as well as to STDOUT. If '-l' option is not set, print_logged() just writes to STDOUT
279*b1cdbd2cSJim Jagielski{
280*b1cdbd2cSJim Jagielski    my $message = shift;
281*b1cdbd2cSJim Jagielski    print "$message";
282*b1cdbd2cSJim Jagielski    if ( $logfile ) {
283*b1cdbd2cSJim Jagielski        open ( LOGFILE, ">> $logfile" ) or die "Can't open logfile '$logfile'\n";
284*b1cdbd2cSJim Jagielski        print LOGFILE "$message";
285*b1cdbd2cSJim Jagielski        close ( LOGFILE) ;
286*b1cdbd2cSJim Jagielski    }
287*b1cdbd2cSJim Jagielski}
288*b1cdbd2cSJim Jagielski
289*b1cdbd2cSJim Jagielski
290*b1cdbd2cSJim Jagielskisub usage
291*b1cdbd2cSJim Jagielski# print usage message and exit
292*b1cdbd2cSJim Jagielski{
293*b1cdbd2cSJim Jagielski    my $retval = shift;
294*b1cdbd2cSJim Jagielski    print STDERR "Usage: checkdeliver.pl [-h] [-p <platform>]\n";
295*b1cdbd2cSJim Jagielski    print STDERR "Compares delivered files on solver with original ones in build tree\n";
296*b1cdbd2cSJim Jagielski    print STDERR "Options:\n";
297*b1cdbd2cSJim Jagielski    print STDERR "    -h              print this usage message\n";
298*b1cdbd2cSJim Jagielski    print STDERR "    -p platform     specify platform\n";
299*b1cdbd2cSJim Jagielski
300*b1cdbd2cSJim Jagielski    exit $retval;
301*b1cdbd2cSJim Jagielski}
302*b1cdbd2cSJim Jagielski
303