xref: /aoo42x/main/solenv/bin/deliver.pl (revision 7e90fac2)
1cdf0e10cSrcweir:
2cdf0e10cSrcweireval 'exec perl -wS $0 ${1+"$@"}'
3cdf0e10cSrcweir    if 0;
4*7e90fac2SAndrew Rist#**************************************************************
5*7e90fac2SAndrew Rist#
6*7e90fac2SAndrew Rist#  Licensed to the Apache Software Foundation (ASF) under one
7*7e90fac2SAndrew Rist#  or more contributor license agreements.  See the NOTICE file
8*7e90fac2SAndrew Rist#  distributed with this work for additional information
9*7e90fac2SAndrew Rist#  regarding copyright ownership.  The ASF licenses this file
10*7e90fac2SAndrew Rist#  to you under the Apache License, Version 2.0 (the
11*7e90fac2SAndrew Rist#  "License"); you may not use this file except in compliance
12*7e90fac2SAndrew Rist#  with the License.  You may obtain a copy of the License at
13*7e90fac2SAndrew Rist#
14*7e90fac2SAndrew Rist#    http://www.apache.org/licenses/LICENSE-2.0
15*7e90fac2SAndrew Rist#
16*7e90fac2SAndrew Rist#  Unless required by applicable law or agreed to in writing,
17*7e90fac2SAndrew Rist#  software distributed under the License is distributed on an
18*7e90fac2SAndrew Rist#  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
19*7e90fac2SAndrew Rist#  KIND, either express or implied.  See the License for the
20*7e90fac2SAndrew Rist#  specific language governing permissions and limitations
21*7e90fac2SAndrew Rist#  under the License.
22*7e90fac2SAndrew Rist#
23*7e90fac2SAndrew Rist#**************************************************************
24*7e90fac2SAndrew Rist
25*7e90fac2SAndrew Rist
26cdf0e10cSrcweir
27cdf0e10cSrcweir#
28cdf0e10cSrcweir# deliver.pl - copy from module output tree to solver
29cdf0e10cSrcweir#
30cdf0e10cSrcweir
31cdf0e10cSrcweiruse Cwd;
32cdf0e10cSrcweiruse File::Basename;
33cdf0e10cSrcweiruse File::Copy;
34cdf0e10cSrcweiruse File::DosGlob 'glob';
35cdf0e10cSrcweiruse File::Path;
36cdf0e10cSrcweiruse File::Spec;
37cdf0e10cSrcweir
38cdf0e10cSrcweir#### script id #####
39cdf0e10cSrcweir
40cdf0e10cSrcweir( $script_name = $0 ) =~ s/^.*\b(\w+)\.pl$/$1/;
41cdf0e10cSrcweir
42cdf0e10cSrcweir$id_str = ' $Revision: 275594 $ ';
43cdf0e10cSrcweir$id_str =~ /Revision:\s+(\S+)\s+\$/
44cdf0e10cSrcweir  ? ($script_rev = $1) : ($script_rev = "-");
45cdf0e10cSrcweir
46cdf0e10cSrcweir
47cdf0e10cSrcweir#### globals ####
48cdf0e10cSrcweir
49cdf0e10cSrcweir### valid actions ###
50cdf0e10cSrcweir# if you add a action 'foo', than add 'foo' to this list and
51cdf0e10cSrcweir# implement 'do_foo()' in the implemented actions area
52cdf0e10cSrcweir@action_list        =   (           # valid actions
53cdf0e10cSrcweir                        'copy',
54cdf0e10cSrcweir                        'dos',
55cdf0e10cSrcweir                        'addincpath',
56cdf0e10cSrcweir                        'linklib',
57cdf0e10cSrcweir                        'mkdir',
58cdf0e10cSrcweir                        'symlink',
59cdf0e10cSrcweir                        'touch'
60cdf0e10cSrcweir                        );
61cdf0e10cSrcweir
62cdf0e10cSrcweir# copy filter: files matching these patterns won't be copied by
63cdf0e10cSrcweir# the copy action
64cdf0e10cSrcweir@copy_filter_patterns = (
65cdf0e10cSrcweir                        );
66cdf0e10cSrcweir
67cdf0e10cSrcweir$strip              = '';
68cdf0e10cSrcweir$is_debug           = 0;
69cdf0e10cSrcweir
70cdf0e10cSrcweir$error              = 0;
71cdf0e10cSrcweir$module             = 0;            # module name
72cdf0e10cSrcweir$repository         = 0;            # parent directory of this module
73cdf0e10cSrcweir$base_dir           = 0;            # path to module base directory
74cdf0e10cSrcweir$dlst_file          = 0;            # path to d.lst
75cdf0e10cSrcweir$ilst_ext           = 'ilst';       # extension of image lists
76cdf0e10cSrcweir$umask              = 22;           # default file/directory creation mask
77cdf0e10cSrcweir$dest               = 0;            # optional destination path
78cdf0e10cSrcweir$common_build       = 0;            # do we have common trees?
79cdf0e10cSrcweir$common_dest        = 0;            # common tree on solver
80cdf0e10cSrcweir
81cdf0e10cSrcweir@action_data        = ();           # LoL with all action data
82cdf0e10cSrcweir@macros             = ();           # d.lst macros
83cdf0e10cSrcweir@addincpath_list    = ();           # files which have to be filtered through addincpath
84cdf0e10cSrcweir@dirlist            = ();           # List of 'mkdir' targets
85cdf0e10cSrcweir@zip_list           = ();           # files which have to be zipped
86cdf0e10cSrcweir@common_zip_list    = ();           # common files which have to be zipped
87cdf0e10cSrcweir@log_list           = ();           # LoL for logging all copy and link actions
88cdf0e10cSrcweir@common_log_list    = ();           # LoL for logging all copy and link actions in common_dest
89cdf0e10cSrcweir$logfiledate        = 0;            # Make log file as old as newest delivered file
90cdf0e10cSrcweir$commonlogfiledate  = 0;            # Make log file as old as newest delivered file
91cdf0e10cSrcweir
92cdf0e10cSrcweir$files_copied       = 0;            # statistics
93cdf0e10cSrcweir$files_unchanged    = 0;            # statistics
94cdf0e10cSrcweir
95cdf0e10cSrcweir$opt_force          = 0;            # option force copy
96cdf0e10cSrcweir$opt_check          = 0;            # do actually execute any action
97cdf0e10cSrcweir$opt_zip            = 0;            # create an additional zip file
98cdf0e10cSrcweir$opt_silent         = 0;            # be silent, only report errors
99cdf0e10cSrcweir$opt_verbose        = 0;            # be verbose (former default behaviour)
100cdf0e10cSrcweir$opt_log            = 1;            # create an additional log file
101cdf0e10cSrcweir$opt_link           = 0;            # hard link files into the solver to save disk space
102cdf0e10cSrcweir$opt_deloutput      = 0;            # delete the output tree for the project once successfully delivered
103cdf0e10cSrcweir$opt_checkdlst      = 0;
104cdf0e10cSrcweir$delete_common      = 1;            # for "-delete": if defined delete files from common tree also
105cdf0e10cSrcweir
106cdf0e10cSrcweirif ($^O ne 'cygwin') {              # iz59477 - cygwin needes a dot "." at the end of filenames to disable
107cdf0e10cSrcweir    $maybedot     = '';             # some .exe transformation magic.
108cdf0e10cSrcweir} else {
109cdf0e10cSrcweir    my $cygvernum = `uname -r`;
110cdf0e10cSrcweir    my @cygvernum = split( /\./, $cygvernum);
111cdf0e10cSrcweir    $cygvernum = shift @cygvernum;
112cdf0e10cSrcweir    $cygvernum .= shift @cygvernum;
113cdf0e10cSrcweir    if ( $cygvernum < 17 ) {
114cdf0e10cSrcweir        $maybedot     = '.';
115cdf0e10cSrcweir    } else {
116cdf0e10cSrcweir        $maybedot     = '';               # no longer works with cygwin 1.7. other magic below.
117cdf0e10cSrcweir    }
118cdf0e10cSrcweir}
119cdf0e10cSrcweir
120cdf0e10cSrcweir($gui		= lc($ENV{GUI})) 		|| die "Can't determine 'GUI'. Please set environment.\n";
121cdf0e10cSrcweir$tempcounter        = 0;
122cdf0e10cSrcweir
123cdf0e10cSrcweir# zip is default for RE master builds
124cdf0e10cSrcweir$opt_zip = 1 if ( defined($ENV{DELIVER_TO_ZIP}) && uc($ENV{DELIVER_TO_ZIP}) eq 'TRUE' && ! defined($ENV{CWS_WORK_STAMP}));
125cdf0e10cSrcweir
126cdf0e10cSrcweir$has_symlinks       = 0;            # system supports symlinks
127cdf0e10cSrcweir
128cdf0e10cSrcweirfor (@action_list) {
129cdf0e10cSrcweir    $action_hash{$_}++;
130cdf0e10cSrcweir}
131cdf0e10cSrcweir
132cdf0e10cSrcweir# trap normal signals (HUP, INT, PIPE, TERM)
133cdf0e10cSrcweir# for clean up on unexpected termination
134cdf0e10cSrcweiruse sigtrap 'handler' => \&cleanup_and_die, 'normal-signals';
135cdf0e10cSrcweir
136cdf0e10cSrcweir#### main ####
137cdf0e10cSrcweir
138cdf0e10cSrcweirparse_options();
139cdf0e10cSrcweir
140cdf0e10cSrcweirprint "$script_name -- version: $script_rev\n" if !$opt_silent;
141cdf0e10cSrcweir
142cdf0e10cSrcweirif ( ! $opt_delete ) {
143cdf0e10cSrcweir    if ( $ENV{GUI} eq 'WNT' ) {
144cdf0e10cSrcweir        if ($ENV{COM} eq 'GCC') {
145cdf0e10cSrcweir            initialize_strip() ;
146cdf0e10cSrcweir        };
147cdf0e10cSrcweir    } else {
148cdf0e10cSrcweir        initialize_strip();
149cdf0e10cSrcweir    }
150cdf0e10cSrcweir}
151cdf0e10cSrcweir
152cdf0e10cSrcweirinit_globals();
153cdf0e10cSrcweirpush_default_actions();
154cdf0e10cSrcweirparse_dlst();
155cdf0e10cSrcweircheck_dlst() if $opt_checkdlst;
156cdf0e10cSrcweirwalk_action_data();
157cdf0e10cSrcweirwalk_addincpath_list();
158cdf0e10cSrcweirwrite_log() if $opt_log;
159cdf0e10cSrcweirzip_files() if $opt_zip;
160cdf0e10cSrcweircleanup() if $opt_delete;
161cdf0e10cSrcweirdelete_output() if $opt_deloutput;
162cdf0e10cSrcweirprint_stats();
163cdf0e10cSrcweir
164cdf0e10cSrcweirexit($error);
165cdf0e10cSrcweir
166cdf0e10cSrcweir#### implemented actions #####
167cdf0e10cSrcweir
168cdf0e10cSrcweirsub do_copy
169cdf0e10cSrcweir{
170cdf0e10cSrcweir    # We need to copy two times:
171cdf0e10cSrcweir    # from the platform dependent output tree
172cdf0e10cSrcweir    # and from the common output tree
173cdf0e10cSrcweir    my ($dependent, $common, $from, $to, $file_list);
174cdf0e10cSrcweir    my $line = shift;
175cdf0e10cSrcweir    my $touch = 0;
176cdf0e10cSrcweir
177cdf0e10cSrcweir    $dependent = expand_macros($line);
178cdf0e10cSrcweir    ($from, $to) = split(' ', $dependent);
179cdf0e10cSrcweir    print "copy dependent: from: $from, to: $to\n" if $is_debug;
180cdf0e10cSrcweir    glob_and_copy($from, $to, $touch);
181cdf0e10cSrcweir
182cdf0e10cSrcweir    if ($delete_common && $common_build && ( $line !~ /%COMMON_OUTDIR%/ ) ) {
183cdf0e10cSrcweir        $line =~ s/%__SRC%/%COMMON_OUTDIR%/ig;
184cdf0e10cSrcweir        if ( $line =~ /%COMMON_OUTDIR%/ ) {
185cdf0e10cSrcweir            $line =~ s/%_DEST%/%COMMON_DEST%/ig;
186cdf0e10cSrcweir            $common = expand_macros($line);
187cdf0e10cSrcweir            ($from, $to) = split(' ', $common);
188cdf0e10cSrcweir            print "copy common: from: $from, to: $to\n" if $is_debug;
189cdf0e10cSrcweir            glob_and_copy($from, $to, $touch);
190cdf0e10cSrcweir        }
191cdf0e10cSrcweir    }
192cdf0e10cSrcweir}
193cdf0e10cSrcweir
194cdf0e10cSrcweirsub do_dos
195cdf0e10cSrcweir{
196cdf0e10cSrcweir    my $line = shift;
197cdf0e10cSrcweir
198cdf0e10cSrcweir    my $command = expand_macros($line);
199cdf0e10cSrcweir    if ( $opt_check ) {
200cdf0e10cSrcweir        print "DOS: $command\n";
201cdf0e10cSrcweir    }
202cdf0e10cSrcweir    else {
203cdf0e10cSrcweir        # HACK: remove MACOSX stuff which is wrongly labled with dos
204cdf0e10cSrcweir        # better: fix broken d.lst
205cdf0e10cSrcweir        return if ( $command =~ /MACOSX/ );
206cdf0e10cSrcweir        $command =~ s#/#\\#g if $^O eq 'MSWin32';
207cdf0e10cSrcweir        system($command);
208cdf0e10cSrcweir    }
209cdf0e10cSrcweir}
210cdf0e10cSrcweir
211cdf0e10cSrcweirsub do_addincpath
212cdf0e10cSrcweir{
213cdf0e10cSrcweir    # just collect all addincpath files, actual filtering is done later
214cdf0e10cSrcweir    my $line = shift;
215cdf0e10cSrcweir    my ($from, $to);
216cdf0e10cSrcweir    my @globbed_files = ();
217cdf0e10cSrcweir
218cdf0e10cSrcweir    $line = expand_macros($line);
219cdf0e10cSrcweir    ($from, $to) = split(' ', $line);
220cdf0e10cSrcweir
221cdf0e10cSrcweir    push( @addincpath_list, @{glob_line($from, $to)});
222cdf0e10cSrcweir}
223cdf0e10cSrcweir
224cdf0e10cSrcweirsub do_linklib
225cdf0e10cSrcweir{
226cdf0e10cSrcweir    my ($lib_base, $lib_major,$from_dir, $to_dir);
227cdf0e10cSrcweir    my $lib = shift;
228cdf0e10cSrcweir    my @globbed_files = ();
229cdf0e10cSrcweir    my %globbed_hash = ();
230cdf0e10cSrcweir
231cdf0e10cSrcweir    print "linklib: $lib\n" if $is_debug;
232cdf0e10cSrcweir    print "has symlinks\n" if ( $has_symlinks && $is_debug );
233cdf0e10cSrcweir
234cdf0e10cSrcweir    return unless $has_symlinks;
235cdf0e10cSrcweir
236cdf0e10cSrcweir    $from_dir = expand_macros('../%__SRC%/lib');
237cdf0e10cSrcweir    $to_dir = expand_macros('%_DEST%/lib%_EXT%');
238cdf0e10cSrcweir
239cdf0e10cSrcweir    @globbed_files = glob("$from_dir/$lib");
240cdf0e10cSrcweir
241cdf0e10cSrcweir    if ( $#globbed_files == -1 ) {
242cdf0e10cSrcweir       return;
243cdf0e10cSrcweir    }
244cdf0e10cSrcweir
245cdf0e10cSrcweir    foreach $lib (@globbed_files) {
246cdf0e10cSrcweir        $lib = basename($lib);
247cdf0e10cSrcweir        if ( $lib =~ /^(lib\S+(\.so|\.dylib))\.(\d+)\.(\d+)(\.(\d+))?$/
248cdf0e10cSrcweir             || $lib =~ /^(lib\S+(\.so|\.dylib))\.(\d+)$/ )
249cdf0e10cSrcweir        {
250cdf0e10cSrcweir           push(@{$globbed_hash{$1}}, $lib);
251cdf0e10cSrcweir        }
252cdf0e10cSrcweir        else {
253cdf0e10cSrcweir            print_warning("invalid library name: $lib");
254cdf0e10cSrcweir        }
255cdf0e10cSrcweir    }
256cdf0e10cSrcweir
257cdf0e10cSrcweir    foreach $lib_base ( sort keys %globbed_hash ) {
258cdf0e10cSrcweir        $lib = get_latest_patchlevel(@{$globbed_hash{$lib_base}});
259cdf0e10cSrcweir
260cdf0e10cSrcweir        if ( $lib =~ /^(lib\S+(\.so|\.dylib))\.(\d+)\.(\d+)(\.(\d+))?$/ )
261cdf0e10cSrcweir        {
262cdf0e10cSrcweir            $lib_major = "$lib_base.$3";
263cdf0e10cSrcweir            $long = 1;
264cdf0e10cSrcweir        }
265cdf0e10cSrcweir        else
266cdf0e10cSrcweir        {
267cdf0e10cSrcweir            # $lib =~ /^(lib[\w-]+(\.so|\.dylib))\.(\d+)$/;
268cdf0e10cSrcweir            $long = 0;
269cdf0e10cSrcweir        }
270cdf0e10cSrcweir
271cdf0e10cSrcweir        if ( $opt_check ) {
272cdf0e10cSrcweir            if ( $opt_delete ) {
273cdf0e10cSrcweir                print "REMOVE: $to_dir/$lib_major\n" if $long;
274cdf0e10cSrcweir                print "REMOVE: $to_dir/$lib_base\n";
275cdf0e10cSrcweir            }
276cdf0e10cSrcweir            else {
277cdf0e10cSrcweir                print "LINKLIB: $to_dir/$lib -> $to_dir/$lib_major\n" if $long;
278cdf0e10cSrcweir                print "LINKLIB: $to_dir/$lib -> $to_dir/$lib_base\n";
279cdf0e10cSrcweir            }
280cdf0e10cSrcweir        }
281cdf0e10cSrcweir        else {
282cdf0e10cSrcweir            if ( $opt_delete ) {
283cdf0e10cSrcweir                print "REMOVE: $to_dir/$lib_major\n" if ($long && $opt_verbose);
284cdf0e10cSrcweir                print "REMOVE: $to_dir/$lib_base\n" if $opt_verbose;
285cdf0e10cSrcweir                unlink "$to_dir/$lib_major" if $long;
286cdf0e10cSrcweir                unlink "$to_dir/$lib_base";
287cdf0e10cSrcweir                if ( $opt_zip ) {
288cdf0e10cSrcweir                    push_on_ziplist("$to_dir/$lib_major") if $long;
289cdf0e10cSrcweir                    push_on_ziplist("$to_dir/$lib_base");
290cdf0e10cSrcweir                }
291cdf0e10cSrcweir                return;
292cdf0e10cSrcweir            }
293cdf0e10cSrcweir            my $symlib;
294cdf0e10cSrcweir            my @symlibs;
295cdf0e10cSrcweir            if ($long)
296cdf0e10cSrcweir            {
297cdf0e10cSrcweir                @symlibs = ("$to_dir/$lib_major", "$to_dir/$lib_base");
298cdf0e10cSrcweir            }
299cdf0e10cSrcweir            else
300cdf0e10cSrcweir            {
301cdf0e10cSrcweir                @symlibs = ("$to_dir/$lib_base");
302cdf0e10cSrcweir            }
303cdf0e10cSrcweir            # remove old symlinks
304cdf0e10cSrcweir            unlink(@symlibs);
305cdf0e10cSrcweir            foreach $symlib (@symlibs) {
306cdf0e10cSrcweir                print "LINKLIB: $lib -> $symlib\n" if $opt_verbose;
307cdf0e10cSrcweir                if ( !symlink("$lib", "$symlib") ) {
308cdf0e10cSrcweir                    print_error("can't symlink $lib -> $symlib: $!",0);
309cdf0e10cSrcweir                }
310cdf0e10cSrcweir                else {
311cdf0e10cSrcweir                    push_on_ziplist($symlib) if $opt_zip;
312cdf0e10cSrcweir                    push_on_loglist("LINK", "$lib", "$symlib") if $opt_log;
313cdf0e10cSrcweir                }
314cdf0e10cSrcweir            }
315cdf0e10cSrcweir        }
316cdf0e10cSrcweir    }
317cdf0e10cSrcweir}
318cdf0e10cSrcweir
319cdf0e10cSrcweirsub do_mkdir
320cdf0e10cSrcweir{
321cdf0e10cSrcweir    my $path = expand_macros(shift);
322cdf0e10cSrcweir    # strip whitespaces from path name
323cdf0e10cSrcweir    $path =~ s/\s$//;
324cdf0e10cSrcweir    if (( ! $opt_delete ) && ( ! -d $path )) {
325cdf0e10cSrcweir        if ( $opt_check ) {
326cdf0e10cSrcweir            print "MKDIR: $path\n";
327cdf0e10cSrcweir        } else {
328cdf0e10cSrcweir            mkpath($path, 0, 0777-$umask);
329cdf0e10cSrcweir            if ( ! -d $path ) {
330cdf0e10cSrcweir                print_error("mkdir: could not create directory '$path'", 0);
331cdf0e10cSrcweir            }
332cdf0e10cSrcweir        }
333cdf0e10cSrcweir    }
334cdf0e10cSrcweir}
335cdf0e10cSrcweir
336cdf0e10cSrcweirsub do_symlink
337cdf0e10cSrcweir{
338cdf0e10cSrcweir    my $line = shift;
339cdf0e10cSrcweir
340cdf0e10cSrcweir    $line = expand_macros($line);
341cdf0e10cSrcweir    ($from, $to) = split(' ',$line);
342cdf0e10cSrcweir    my $fullfrom = $from;
343cdf0e10cSrcweir    if ( dirname($from) eq dirname($to) ) {
344cdf0e10cSrcweir        $from = basename($from);
345cdf0e10cSrcweir    }
346cdf0e10cSrcweir    elsif ( dirname($from) eq '.' ) {
347cdf0e10cSrcweir        # nothing to do
348cdf0e10cSrcweir    }
349cdf0e10cSrcweir    else {
350cdf0e10cSrcweir        print_error("symlink: link must be in the same directory as file",0);
351cdf0e10cSrcweir        return 0;
352cdf0e10cSrcweir    }
353cdf0e10cSrcweir
354cdf0e10cSrcweir    print "symlink: $from, to: $to\n" if $is_debug;
355cdf0e10cSrcweir
356cdf0e10cSrcweir    return unless $has_symlinks;
357cdf0e10cSrcweir
358cdf0e10cSrcweir    if ( $opt_check ) {
359cdf0e10cSrcweir        if ( $opt_delete ) {
360cdf0e10cSrcweir            print "REMOVE: $to\n";
361cdf0e10cSrcweir        }
362cdf0e10cSrcweir        else {
363cdf0e10cSrcweir            print "SYMLINK $from -> $to\n";
364cdf0e10cSrcweir        }
365cdf0e10cSrcweir    }
366cdf0e10cSrcweir    else {
367cdf0e10cSrcweir        print "REMOVE: $to\n" if $opt_verbose;
368cdf0e10cSrcweir        unlink $to;
369cdf0e10cSrcweir        if ( $opt_delete ) {
370cdf0e10cSrcweir            push_on_ziplist($to) if $opt_zip;
371cdf0e10cSrcweir            return;
372cdf0e10cSrcweir        }
373cdf0e10cSrcweir        return unless -e $fullfrom;
374cdf0e10cSrcweir        print "SYMLIB: $from -> $to\n" if $opt_verbose;
375cdf0e10cSrcweir        if ( !symlink("$from", "$to") ) {
376cdf0e10cSrcweir            print_error("can't symlink $from -> $to: $!",0);
377cdf0e10cSrcweir        }
378cdf0e10cSrcweir        else {
379cdf0e10cSrcweir            push_on_ziplist($to) if $opt_zip;
380cdf0e10cSrcweir            push_on_loglist("LINK", "$from", "$to") if $opt_log;
381cdf0e10cSrcweir        }
382cdf0e10cSrcweir    }
383cdf0e10cSrcweir}
384cdf0e10cSrcweir
385cdf0e10cSrcweirsub do_touch
386cdf0e10cSrcweir{
387cdf0e10cSrcweir    my ($from, $to);
388cdf0e10cSrcweir    my $line = shift;
389cdf0e10cSrcweir    my $touch = 1;
390cdf0e10cSrcweir
391cdf0e10cSrcweir    $line = expand_macros($line);
392cdf0e10cSrcweir    ($from, $to) = split(' ', $line);
393cdf0e10cSrcweir    print "touch: $from, to: $to\n" if $is_debug;
394cdf0e10cSrcweir    glob_and_copy($from, $to, $touch);
395cdf0e10cSrcweir}
396cdf0e10cSrcweir
397cdf0e10cSrcweir#### subroutines #####
398cdf0e10cSrcweir
399cdf0e10cSrcweirsub parse_options
400cdf0e10cSrcweir{
401cdf0e10cSrcweir    my $arg;
402cdf0e10cSrcweir    my $dontdeletecommon = 0;
403cdf0e10cSrcweir    $opt_silent = 1 if ( defined $ENV{VERBOSE} && $ENV{VERBOSE} eq 'FALSE');
404cdf0e10cSrcweir    $opt_verbose = 1 if ( defined $ENV{VERBOSE} && $ENV{VERBOSE} eq 'TRUE');
405cdf0e10cSrcweir    while ( $arg = shift @ARGV ) {
406cdf0e10cSrcweir        $arg =~ /^-force$/      and $opt_force  = 1  and next;
407cdf0e10cSrcweir        $arg =~ /^-check$/      and $opt_check  = 1  and $opt_verbose = 1 and next;
408cdf0e10cSrcweir        $arg =~ /^-quiet$/      and $opt_silent = 1  and next;
409cdf0e10cSrcweir        $arg =~ /^-verbose$/    and $opt_verbose = 1 and next;
410cdf0e10cSrcweir        $arg =~ /^-zip$/        and $opt_zip    = 1  and next;
411cdf0e10cSrcweir        $arg =~ /^-delete$/     and $opt_delete = 1  and next;
412cdf0e10cSrcweir        $arg =~ /^-dontdeletecommon$/ and $dontdeletecommon = 1 and next;
413cdf0e10cSrcweir        $arg =~ /^-help$/       and $opt_help   = 1  and $arg = '';
414cdf0e10cSrcweir        $arg =~ /^-link$/       and $ENV{GUI} ne 'WNT' and $opt_link = 1 and next;
415cdf0e10cSrcweir        $arg =~ /^-deloutput$/  and $opt_deloutput = 1 and next;
416cdf0e10cSrcweir        $arg =~ /^-debug$/      and $is_debug   = 1  and next;
417cdf0e10cSrcweir        $arg =~ /^-checkdlst$/  and $opt_checkdlst = 1 and next;
418cdf0e10cSrcweir        print_error("invalid option $arg") if ( $arg =~ /^-/ );
419cdf0e10cSrcweir        if ( $arg =~ /^-/ || $opt_help || $#ARGV > -1 ) {
420cdf0e10cSrcweir            usage(1);
421cdf0e10cSrcweir        }
422cdf0e10cSrcweir        $dest = $arg;
423cdf0e10cSrcweir    }
424cdf0e10cSrcweir    # $dest and $opt_zip or $opt_delete are mutually exclusive
425cdf0e10cSrcweir    if ( $dest and ($opt_zip || $opt_delete) ) {
426cdf0e10cSrcweir        usage(1);
427cdf0e10cSrcweir    }
428cdf0e10cSrcweir    # $opt_silent and $opt_check or $opt_verbose are mutually exclusive
429cdf0e10cSrcweir    if ( ($opt_check or $opt_verbose) and $opt_silent ) {
430cdf0e10cSrcweir        print STDERR "Error on command line: options '-check' and '-quiet' are mutually exclusive.\n";
431cdf0e10cSrcweir        usage(1);
432cdf0e10cSrcweir    }
433cdf0e10cSrcweir    if ($dontdeletecommon) {
434cdf0e10cSrcweir        if (!$opt_delete) {
435cdf0e10cSrcweir            usage(1);
436cdf0e10cSrcweir        }
437cdf0e10cSrcweir        $delete_common = 0;
438cdf0e10cSrcweir    };
439cdf0e10cSrcweir    # $opt_delete implies $opt_force
440cdf0e10cSrcweir    $opt_force = 1 if $opt_delete;
441cdf0e10cSrcweir}
442cdf0e10cSrcweir
443cdf0e10cSrcweirsub init_globals
444cdf0e10cSrcweir{
445cdf0e10cSrcweir    my $ext;
446cdf0e10cSrcweir    ($module, $repository, $base_dir, $dlst_file) =  get_base();
447cdf0e10cSrcweir
448cdf0e10cSrcweir    # for CWS:
449cdf0e10cSrcweir    $module =~ s/\.lnk$//;
450cdf0e10cSrcweir
451cdf0e10cSrcweir    print "Module=$module, Base_Dir=$base_dir, d.lst=$dlst_file\n" if $is_debug;
452cdf0e10cSrcweir
453cdf0e10cSrcweir    $umask = umask();
454cdf0e10cSrcweir    if ( !defined($umask) ) {
455cdf0e10cSrcweir        $umask = 22;
456cdf0e10cSrcweir    }
457cdf0e10cSrcweir
458cdf0e10cSrcweir    my $build_sosl    = $ENV{'BUILD_SOSL'};
459cdf0e10cSrcweir    my $common_outdir = $ENV{'COMMON_OUTDIR'};
460cdf0e10cSrcweir    my $inpath        = $ENV{'INPATH'};
461cdf0e10cSrcweir    my $solarversion  = $ENV{'SOLARVERSION'};
462cdf0e10cSrcweir    my $updater       = $ENV{'UPDATER'};
463cdf0e10cSrcweir    my $updminor      = $ENV{'UPDMINOR'};
464cdf0e10cSrcweir    my $updminorext   = $ENV{'UPDMINOREXT'};
465cdf0e10cSrcweir    my $work_stamp    = $ENV{'WORK_STAMP'};
466cdf0e10cSrcweir
467cdf0e10cSrcweir    # special security check for release engineers
468cdf0e10cSrcweir    if ( defined($updater) && !defined($build_sosl) && !$opt_force) {
469cdf0e10cSrcweir        my $path = getcwd();
470cdf0e10cSrcweir        if ( $path !~ /$work_stamp/io ) {
471cdf0e10cSrcweir            print_error("can't deliver from local directory to SOLARVERSION");
472cdf0e10cSrcweir            print STDERR "\nDANGER! Release Engineer:\n";
473cdf0e10cSrcweir            print STDERR "do you really want to deliver from $path to SOLARVERSION?\n";
474cdf0e10cSrcweir            print STDERR "If so, please use the -force switch\n\n";
475cdf0e10cSrcweir            exit(7);
476cdf0e10cSrcweir        }
477cdf0e10cSrcweir    }
478cdf0e10cSrcweir
479cdf0e10cSrcweir    # do we have a valid environment?
480cdf0e10cSrcweir    if ( !defined($inpath) ) {
481cdf0e10cSrcweir            print_error("no environment", 0);
482cdf0e10cSrcweir            exit(3);
483cdf0e10cSrcweir    }
484cdf0e10cSrcweir
485cdf0e10cSrcweir    $ext = "";
486cdf0e10cSrcweir    if ( ($updminor) && !$dest ) {
487cdf0e10cSrcweir        $ext = "$updminorext";
488cdf0e10cSrcweir    }
489cdf0e10cSrcweir
490cdf0e10cSrcweir    # Do we have common trees?
491cdf0e10cSrcweir    if ( defined($ENV{'common_build'}) && $ENV{'common_build'} eq 'TRUE' ) {
492cdf0e10cSrcweir        $common_build = 1;
493cdf0e10cSrcweir        if ((defined $common_outdir) && ($common_outdir ne "")) {
494cdf0e10cSrcweir            $common_outdir = $common_outdir . ".pro" if $inpath =~ /\.pro$/;
495cdf0e10cSrcweir            if ( $dest ) {
496cdf0e10cSrcweir                $common_dest = $dest;
497cdf0e10cSrcweir            } else {
498cdf0e10cSrcweir                $common_dest = "$solarversion/$common_outdir";
499cdf0e10cSrcweir                $dest = "$solarversion/$inpath";
500cdf0e10cSrcweir            }
501cdf0e10cSrcweir        } else {
502cdf0e10cSrcweir            print_error("common_build defined without common_outdir", 0);
503cdf0e10cSrcweir            exit(6);
504cdf0e10cSrcweir        }
505cdf0e10cSrcweir    } else {
506cdf0e10cSrcweir        $common_outdir = $inpath;
507cdf0e10cSrcweir        $dest = "$solarversion/$inpath" if ( !$dest );
508cdf0e10cSrcweir        $common_dest = $dest;
509cdf0e10cSrcweir    }
510cdf0e10cSrcweir    $dest =~ s#\\#/#g;
511cdf0e10cSrcweir    $common_dest =~ s#\\#/#g;
512cdf0e10cSrcweir
513cdf0e10cSrcweir    # the following macros are obsolete, will be flagged as error
514cdf0e10cSrcweir    # %__WORKSTAMP%
515cdf0e10cSrcweir    # %GUIBASE%
516cdf0e10cSrcweir    # %SDK%
517cdf0e10cSrcweir    # %SOLARVER%
518cdf0e10cSrcweir    # %__OFFENV%
519cdf0e10cSrcweir    # %DLLSUFFIX%'
520cdf0e10cSrcweir    # %OUTPATH%
521cdf0e10cSrcweir    # %L10N_FRAMEWORK%
522cdf0e10cSrcweir    # %UPD%
523cdf0e10cSrcweir
524cdf0e10cSrcweir    # valid macros
525cdf0e10cSrcweir    @macros = (
526cdf0e10cSrcweir                [ '%__PRJROOT%',        $base_dir       ],
527cdf0e10cSrcweir                [ '%__SRC%',            $inpath         ],
528cdf0e10cSrcweir                [ '%_DEST%',            $dest           ],
529cdf0e10cSrcweir                [ '%_EXT%',             $ext            ],
530cdf0e10cSrcweir                [ '%COMMON_OUTDIR%',    $common_outdir  ],
531cdf0e10cSrcweir                [ '%COMMON_DEST%',      $common_dest    ],
532cdf0e10cSrcweir                [ '%GUI%',              $gui            ]
533cdf0e10cSrcweir              );
534cdf0e10cSrcweir
535cdf0e10cSrcweir    # find out if the system supports symlinks
536cdf0e10cSrcweir    $has_symlinks = eval { symlink("",""); 1 };
537cdf0e10cSrcweir}
538cdf0e10cSrcweir
539cdf0e10cSrcweirsub get_base
540cdf0e10cSrcweir{
541cdf0e10cSrcweir    # a module base dir contains a subdir 'prj'
542cdf0e10cSrcweir    # which in turn contains a file 'd.lst'
543cdf0e10cSrcweir    my (@field, $repo, $base, $dlst);
544cdf0e10cSrcweir    my $path = getcwd();
545cdf0e10cSrcweir
546cdf0e10cSrcweir    @field = split(/\//, $path);
547cdf0e10cSrcweir
548cdf0e10cSrcweir    while ( $#field != -1 ) {
549cdf0e10cSrcweir        $base = join('/', @field);
550cdf0e10cSrcweir        $dlst = $base . '/prj/d.lst';
551cdf0e10cSrcweir        last if -e $dlst;
552cdf0e10cSrcweir        pop @field;
553cdf0e10cSrcweir    }
554cdf0e10cSrcweir
555cdf0e10cSrcweir    if ( $#field == -1 ) {
556cdf0e10cSrcweir        print_error("can't find d.lst");
557cdf0e10cSrcweir        exit(2);
558cdf0e10cSrcweir    }
559cdf0e10cSrcweir    else {
560cdf0e10cSrcweir        if ( defined $field[-2] ) {
561cdf0e10cSrcweir            $repo = $field[-2];
562cdf0e10cSrcweir        } else {
563cdf0e10cSrcweir            print_error("Internal error: cannot determine module's parent directory");
564cdf0e10cSrcweir        }
565cdf0e10cSrcweir        return ($field[-1], $repo, $base, $dlst);
566cdf0e10cSrcweir    }
567cdf0e10cSrcweir}
568cdf0e10cSrcweir
569cdf0e10cSrcweirsub parse_dlst
570cdf0e10cSrcweir{
571cdf0e10cSrcweir    my $line_cnt = 0;
572cdf0e10cSrcweir    open(DLST, "<$dlst_file") or die "can't open d.lst";
573cdf0e10cSrcweir    while(<DLST>) {
574cdf0e10cSrcweir        $line_cnt++;
575cdf0e10cSrcweir        tr/\r\n//d;
576cdf0e10cSrcweir        next if /^#/;
577cdf0e10cSrcweir        next if /^\s*$/;
578cdf0e10cSrcweir        if (!$delete_common && /%COMMON_DEST%/) {
579cdf0e10cSrcweir            # Just ignore all lines with %COMMON_DEST%
580cdf0e10cSrcweir            next;
581cdf0e10cSrcweir        };
582cdf0e10cSrcweir        if ( /^\s*(\w+?):\s+(.*)$/ ) {
583cdf0e10cSrcweir            if ( !exists $action_hash{$1} ) {
584cdf0e10cSrcweir                print_error("unknown action: \'$1\'", $line_cnt);
585cdf0e10cSrcweir                exit(4);
586cdf0e10cSrcweir            }
587cdf0e10cSrcweir            push(@action_data, [$1, $2]);
588cdf0e10cSrcweir        }
589cdf0e10cSrcweir        else {
590cdf0e10cSrcweir            if ( /^\s*%(COMMON)?_DEST%\\/ ) {
591cdf0e10cSrcweir                # only copy from source dir to solver, not from solver to solver
592cdf0e10cSrcweir                print_warning("illegal copy action, ignored: \'$_\'", $line_cnt);
593cdf0e10cSrcweir                next;
594cdf0e10cSrcweir            }
595cdf0e10cSrcweir            push(@action_data, ['copy', $_]);
596cdf0e10cSrcweir            # for each ressource file (.res) copy its image list (.ilst)
597cdf0e10cSrcweir            if ( /\.res\s/ ) {
598cdf0e10cSrcweir                my $imagelist = $_;
599cdf0e10cSrcweir                $imagelist =~ s/\.res/\.$ilst_ext/g;
600cdf0e10cSrcweir                $imagelist =~ s/\\bin%_EXT%\\/\\res%_EXT%\\img\\/;
601cdf0e10cSrcweir                push(@action_data, ['copy', $imagelist]);
602cdf0e10cSrcweir            }
603cdf0e10cSrcweir        }
604cdf0e10cSrcweir        # call expand_macros()just to find any undefined macros early
605cdf0e10cSrcweir        # real expansion is done later
606cdf0e10cSrcweir        expand_macros($_, $line_cnt);
607cdf0e10cSrcweir    }
608cdf0e10cSrcweir    close(DLST);
609cdf0e10cSrcweir}
610cdf0e10cSrcweir
611cdf0e10cSrcweirsub expand_macros
612cdf0e10cSrcweir{
613cdf0e10cSrcweir    # expand all macros and change backslashes to slashes
614cdf0e10cSrcweir    my $line        = shift;
615cdf0e10cSrcweir    my $line_cnt    = shift;
616cdf0e10cSrcweir    my $i;
617cdf0e10cSrcweir
618cdf0e10cSrcweir    for ($i=0; $i<=$#macros; $i++)  {
619cdf0e10cSrcweir        $line =~ s/$macros[$i][0]/$macros[$i][1]/gi
620cdf0e10cSrcweir    }
621cdf0e10cSrcweir    if ( $line =~ /(%\w+%)/ ) {
622cdf0e10cSrcweir        if ( $1 ne '%OS%' ) {   # %OS% looks like a macro but is not ...
623cdf0e10cSrcweir            print_error("unknown/obsolete macro: \'$1\'", $line_cnt);
624cdf0e10cSrcweir        }
625cdf0e10cSrcweir    }
626cdf0e10cSrcweir    $line =~ s#\\#/#g;
627cdf0e10cSrcweir    return $line;
628cdf0e10cSrcweir}
629cdf0e10cSrcweir
630cdf0e10cSrcweirsub walk_action_data
631cdf0e10cSrcweir{
632cdf0e10cSrcweir    # all actions have to be excuted relative to the prj directory
633cdf0e10cSrcweir    chdir("$base_dir/prj");
634cdf0e10cSrcweir    # dispatch depending on action type
635cdf0e10cSrcweir    for (my $i=0; $i <= $#action_data; $i++) {
636cdf0e10cSrcweir            &{"do_".$action_data[$i][0]}($action_data[$i][1]);
637cdf0e10cSrcweir            if ( $action_data[$i][0] eq 'mkdir' ) {
638cdf0e10cSrcweir                # fill array with (possibly) created directories in
639cdf0e10cSrcweir                # revers order for removal in 'cleanup'
640cdf0e10cSrcweir                unshift @dirlist, $action_data[$i][1];
641cdf0e10cSrcweir            }
642cdf0e10cSrcweir    }
643cdf0e10cSrcweir}
644cdf0e10cSrcweir
645cdf0e10cSrcweirsub glob_line
646cdf0e10cSrcweir{
647cdf0e10cSrcweir    my $from = shift;
648cdf0e10cSrcweir    my $to = shift;
649cdf0e10cSrcweir    my $to_dir = shift;
650cdf0e10cSrcweir    my $replace = 0;
651cdf0e10cSrcweir    my @globbed_files = ();
652cdf0e10cSrcweir
653cdf0e10cSrcweir    if ( ! ( $from && $to ) ) {
654cdf0e10cSrcweir        print_warning("Error in d.lst? source: '$from' destination: '$to'");
655cdf0e10cSrcweir        return \@globbed_files;
656cdf0e10cSrcweir    }
657cdf0e10cSrcweir
658cdf0e10cSrcweir    if ( $to =~ /[\*\?\[\]]/ ) {
659cdf0e10cSrcweir        my $to_fname;
660cdf0e10cSrcweir        ($to_fname, $to_dir) = fileparse($to);
661cdf0e10cSrcweir        $replace = 1;
662cdf0e10cSrcweir    }
663cdf0e10cSrcweir
664cdf0e10cSrcweir    if ( $from =~ /[\*\?\[\]]/ ) {
665cdf0e10cSrcweir        # globbing necessary, no renaming possible
666cdf0e10cSrcweir        my $file;
667cdf0e10cSrcweir        my @file_list = glob($from);
668cdf0e10cSrcweir
669cdf0e10cSrcweir        foreach $file ( @file_list ) {
670cdf0e10cSrcweir            next if ( -d $file); # we only copy files, not directories
671cdf0e10cSrcweir            my ($fname, $dir) = fileparse($file);
672cdf0e10cSrcweir            my $copy = ($replace) ? $to_dir . $fname : $to . '/' . $fname;
673cdf0e10cSrcweir            push(@globbed_files, [$file, $copy]);
674cdf0e10cSrcweir        }
675cdf0e10cSrcweir    }
676cdf0e10cSrcweir    else {
677cdf0e10cSrcweir        # no globbing but renaming possible
678cdf0e10cSrcweir        # #i89066#
679cdf0e10cSrcweir        if (-d $to && -f $from) {
680cdf0e10cSrcweir            my $filename = File::Basename::basename($from);
681cdf0e10cSrcweir            $to .= '/' if ($to !~ /[\\|\/]$/);
682cdf0e10cSrcweir            $to .= $filename;
683cdf0e10cSrcweir        };
684cdf0e10cSrcweir        push(@globbed_files, [$from, $to]);
685cdf0e10cSrcweir    }
686cdf0e10cSrcweir    if ( $opt_checkdlst ) {
687cdf0e10cSrcweir        my $outtree = expand_macros("%__SRC%");
688cdf0e10cSrcweir        my $commonouttree = expand_macros("%COMMON_OUTDIR%");
689cdf0e10cSrcweir        if (( $from !~ /\Q$outtree\E/ ) && ( $from !~ /\Q$commonouttree\E/ )) {
690cdf0e10cSrcweir            print_warning("'$from' does not match any file") if ( $#globbed_files == -1 );
691cdf0e10cSrcweir        }
692cdf0e10cSrcweir    }
693cdf0e10cSrcweir    return \@globbed_files;
694cdf0e10cSrcweir}
695cdf0e10cSrcweir
696cdf0e10cSrcweir
697cdf0e10cSrcweirsub glob_and_copy
698cdf0e10cSrcweir{
699cdf0e10cSrcweir    my $from = shift;
700cdf0e10cSrcweir    my $to = shift;
701cdf0e10cSrcweir    my $touch = shift;
702cdf0e10cSrcweir
703cdf0e10cSrcweir    my @copy_files = @{glob_line($from, $to)};
704cdf0e10cSrcweir
705cdf0e10cSrcweir    for (my $i = 0; $i <= $#copy_files; $i++) {
706cdf0e10cSrcweir        next if filter_out($copy_files[$i][0]); # apply copy filter
707cdf0e10cSrcweir        copy_if_newer($copy_files[$i][0], $copy_files[$i][1], $touch)
708cdf0e10cSrcweir                    ? $files_copied++ : $files_unchanged++;
709cdf0e10cSrcweir    }
710cdf0e10cSrcweir}
711cdf0e10cSrcweir
712cdf0e10cSrcweirsub is_unstripped {
713cdf0e10cSrcweir    my $file_name = shift;
714cdf0e10cSrcweir    my $nm_output;
715cdf0e10cSrcweir
716cdf0e10cSrcweir    if (-f $file_name.$maybedot) {
717cdf0e10cSrcweir        my $file_type = `file $file_name`;
718cdf0e10cSrcweir        # OS X file command doesn't know if a file is stripped or not
719cdf0e10cSrcweir        if (($file_type =~ /not stripped/o) || ($file_type =~ /Mach-O/o) ||
720cdf0e10cSrcweir            (($file_type =~ /PE/o) && ($ENV{GUI} eq 'WNT') &&
721cdf0e10cSrcweir             ($nm_output = `nm $file_name 2>&1`) && $nm_output &&
722cdf0e10cSrcweir             !($nm_output =~ /no symbols/i) && !($nm_output =~ /not recognized/i))) {
723cdf0e10cSrcweir            return '1' if ($file_name =~ /\.bin$/o);
724cdf0e10cSrcweir            return '1' if ($file_name =~ /\.so\.*/o);
725cdf0e10cSrcweir            return '1' if ($file_name =~ /\.dylib\.*/o);
726cdf0e10cSrcweir            return '1' if ($file_name =~ /\.com\.*/o);
727cdf0e10cSrcweir            return '1' if ($file_name =~ /\.dll\.*/o);
728cdf0e10cSrcweir            return '1' if ($file_name =~ /\.exe\.*/o);
729cdf0e10cSrcweir            return '1' if (basename($file_name) !~ /\./o);
730cdf0e10cSrcweir        }
731cdf0e10cSrcweir    };
732cdf0e10cSrcweir    return '';
733cdf0e10cSrcweir}
734cdf0e10cSrcweir
735cdf0e10cSrcweirsub initialize_strip {
736cdf0e10cSrcweir    if ((!defined $ENV{DISABLE_STRIP}) || ($ENV{DISABLE_STRIP} eq "")) {
737cdf0e10cSrcweir        $strip .= 'guw ' if ($^O eq 'cygwin');
738cdf0e10cSrcweir        $strip .= 'strip';
739cdf0e10cSrcweir	    $strip .= " -x" if ($ENV{OS} eq 'MACOSX');
740cdf0e10cSrcweir        $strip .= " -R '.comment' -s" if ($ENV{OS} eq 'LINUX');
741cdf0e10cSrcweir    };
742cdf0e10cSrcweir};
743cdf0e10cSrcweir
744cdf0e10cSrcweirsub is_jar {
745cdf0e10cSrcweir    my $file_name = shift;
746cdf0e10cSrcweir
747cdf0e10cSrcweir    if (-f $file_name && (( `file $file_name` ) =~ /Zip archive/o)) {
748cdf0e10cSrcweir        return '1' if ($file_name =~ /\.jar\.*/o);
749cdf0e10cSrcweir    };
750cdf0e10cSrcweir    return '';
751cdf0e10cSrcweir}
752cdf0e10cSrcweir
753cdf0e10cSrcweirsub execute_system {
754cdf0e10cSrcweir    my $command = shift;
755cdf0e10cSrcweir    if (system($command)) {
756cdf0e10cSrcweir        print_error("Failed to execute $command");
757cdf0e10cSrcweir        exit($?);
758cdf0e10cSrcweir    };
759cdf0e10cSrcweir};
760cdf0e10cSrcweir
761cdf0e10cSrcweirsub strip_target {
762cdf0e10cSrcweir    my $file = shift;
763cdf0e10cSrcweir    my $temp_file = shift;
764cdf0e10cSrcweir    $temp_file =~ s/\/{2,}/\//g;
765cdf0e10cSrcweir    my $rc = copy($file, $temp_file);
766cdf0e10cSrcweir    execute_system("$strip $temp_file");
767cdf0e10cSrcweir    return $rc;
768cdf0e10cSrcweir};
769cdf0e10cSrcweir
770cdf0e10cSrcweirsub copy_if_newer
771cdf0e10cSrcweir{
772cdf0e10cSrcweir    # return 0 if file is unchanged ( for whatever reason )
773cdf0e10cSrcweir    # return 1 if file has been copied
774cdf0e10cSrcweir    my $from = shift;
775cdf0e10cSrcweir    my $to = shift;
776cdf0e10cSrcweir    my $touch = shift;
777cdf0e10cSrcweir    my $from_stat_ref;
778cdf0e10cSrcweir    my $rc = 0;
779cdf0e10cSrcweir
780cdf0e10cSrcweir    print "testing $from, $to\n" if $is_debug;
781cdf0e10cSrcweir    push_on_ziplist($to) if $opt_zip;
782cdf0e10cSrcweir    push_on_loglist("COPY", "$from", "$to") if $opt_log;
783cdf0e10cSrcweir    return 0 unless ($from_stat_ref = is_newer($from, $to, $touch));
784cdf0e10cSrcweir
785cdf0e10cSrcweir    if ( $opt_delete ) {
786cdf0e10cSrcweir        print "REMOVE: $to\n" if $opt_verbose;
787cdf0e10cSrcweir        $rc = unlink($to) unless $opt_check;
788cdf0e10cSrcweir        return 1 if $opt_check;
789cdf0e10cSrcweir        return $rc;
790cdf0e10cSrcweir    }
791cdf0e10cSrcweir
792cdf0e10cSrcweir    if( !$opt_check && $opt_link ) {
793cdf0e10cSrcweir        # hard link if possible
794cdf0e10cSrcweir        if( link($from, $to) ){
795cdf0e10cSrcweir            print "LINK: $from -> $to\n" if $opt_verbose;
796cdf0e10cSrcweir            return 1;
797cdf0e10cSrcweir        }
798cdf0e10cSrcweir    }
799cdf0e10cSrcweir
800cdf0e10cSrcweir    if( $touch ) {
801cdf0e10cSrcweir       print "TOUCH: $from -> $to\n" if $opt_verbose;
802cdf0e10cSrcweir    }
803cdf0e10cSrcweir    else {
804cdf0e10cSrcweir       print "COPY: $from -> $to\n" if $opt_verbose;
805cdf0e10cSrcweir    }
806cdf0e10cSrcweir
807cdf0e10cSrcweir    return 1 if( $opt_check );
808cdf0e10cSrcweir
809cdf0e10cSrcweir    #
810cdf0e10cSrcweir    # copy to temporary file first and rename later
811cdf0e10cSrcweir    # to minimize the possibility for race conditions
812cdf0e10cSrcweir    local $temp_file = sprintf('%s.%d-%d', $to, $$, time());
813cdf0e10cSrcweir    $rc = '';
814cdf0e10cSrcweir    if (($strip ne '') && (defined $ENV{PROEXT}) && (is_unstripped($from))) {
815cdf0e10cSrcweir        $rc = strip_target($from, $temp_file);
816cdf0e10cSrcweir    } else {
817cdf0e10cSrcweir        $rc = copy($from, $temp_file);
818cdf0e10cSrcweir    };
819cdf0e10cSrcweir    if ( $rc) {
820cdf0e10cSrcweir        if ( is_newer($temp_file, $from, 0) ) {
821cdf0e10cSrcweir            $rc = utime($$from_stat_ref[9], $$from_stat_ref[9], $temp_file);
822cdf0e10cSrcweir            if ( !$rc ) {
823cdf0e10cSrcweir                print_warning("can't update temporary file modification time '$temp_file': $!\n
824cdf0e10cSrcweir                               Check file permissions of '$from'.",0);
825cdf0e10cSrcweir            }
826cdf0e10cSrcweir        }
827cdf0e10cSrcweir        fix_file_permissions($$from_stat_ref[2], $temp_file);
828cdf0e10cSrcweir        if ( $^O eq 'os2' )
829cdf0e10cSrcweir        {
830cdf0e10cSrcweir            $rc = unlink($to); # YD OS/2 can't rename if $to exists!
831cdf0e10cSrcweir        }
832cdf0e10cSrcweir        # Ugly hack: on windows file locking(?) sometimes prevents renaming.
833cdf0e10cSrcweir        # Until we've found and fixed the real reason try it repeatedly :-(
834cdf0e10cSrcweir        my $try = 0;
835cdf0e10cSrcweir        my $maxtries = 1;
836cdf0e10cSrcweir        $maxtries = 5 if ( $^O eq 'MSWin32' );
837cdf0e10cSrcweir        my $success = 0;
838cdf0e10cSrcweir        while ( $try < $maxtries && ! $success ) {
839cdf0e10cSrcweir            sleep $try;
840cdf0e10cSrcweir            $try ++;
841cdf0e10cSrcweir            $success = rename($temp_file, $to);
842cdf0e10cSrcweir            if ( $^O eq 'cygwin' && $to =~ /\.bin$/) {
843cdf0e10cSrcweir                # hack to survive automatically added .exe for executables renamed to
844cdf0e10cSrcweir                # *.bin - will break if there is intentionally a .bin _and_ .bin.exe file.
845cdf0e10cSrcweir                $success = rename( "$to.exe", $to ) if -f "$to.exe";
846cdf0e10cSrcweir            }
847cdf0e10cSrcweir        }
848cdf0e10cSrcweir        if ( $success ) {
849cdf0e10cSrcweir            # handle special packaging of *.dylib files for Mac OS X
850cdf0e10cSrcweir            if ( $^O eq 'darwin' )
851cdf0e10cSrcweir            {
852cdf0e10cSrcweir                system("macosx-create-bundle", "$to=$from.app") if ( -d "$from.app" );
853cdf0e10cSrcweir                system("ranlib", "$to" ) if ( $to =~ /\.a/ );
854cdf0e10cSrcweir            }
855cdf0e10cSrcweir            if ( $try > 1 ) {
856cdf0e10cSrcweir                print_warning("File '$to' temporarily locked. Dependency bug?");
857cdf0e10cSrcweir            }
858cdf0e10cSrcweir            return 1;
859cdf0e10cSrcweir        }
860cdf0e10cSrcweir        else {
861cdf0e10cSrcweir            print_error("can't rename temporary file to $to: $!",0);
862cdf0e10cSrcweir        }
863cdf0e10cSrcweir    }
864cdf0e10cSrcweir    else {
865cdf0e10cSrcweir        print_error("can't copy $from: $!",0);
866cdf0e10cSrcweir        my $destdir = dirname($to);
867cdf0e10cSrcweir        if ( ! -d $destdir ) {
868cdf0e10cSrcweir            print_error("directory '$destdir' does not exist", 0);
869cdf0e10cSrcweir        }
870cdf0e10cSrcweir    }
871cdf0e10cSrcweir    unlink($temp_file);
872cdf0e10cSrcweir    return 0;
873cdf0e10cSrcweir}
874cdf0e10cSrcweir
875cdf0e10cSrcweirsub is_newer
876cdf0e10cSrcweir{
877cdf0e10cSrcweir        # returns whole stat buffer if newer
878cdf0e10cSrcweir        my $from = shift;
879cdf0e10cSrcweir        my $to = shift;
880cdf0e10cSrcweir        my $touch = shift;
881cdf0e10cSrcweir        my (@from_stat, @to_stat);
882cdf0e10cSrcweir
883cdf0e10cSrcweir        @from_stat = stat($from.$maybedot);
884cdf0e10cSrcweir        if ( $opt_checkdlst ) {
885cdf0e10cSrcweir            my $outtree = expand_macros("%__SRC%");
886cdf0e10cSrcweir            my $commonouttree = expand_macros("%COMMON_OUTDIR%");
887cdf0e10cSrcweir            if ( $from !~ /$outtree/ ) {
888cdf0e10cSrcweir                if ( $from !~ /$commonouttree/ ) {
889cdf0e10cSrcweir                    print_warning("'$from' does not exist") unless -e _;
890cdf0e10cSrcweir                }
891cdf0e10cSrcweir            }
892cdf0e10cSrcweir        }
893cdf0e10cSrcweir        return 0 unless -f _;
894cdf0e10cSrcweir
895cdf0e10cSrcweir        if ( $touch ) {
896cdf0e10cSrcweir            $from_stat[9] = time();
897cdf0e10cSrcweir        }
898cdf0e10cSrcweir        # adjust timestamps to even seconds
899cdf0e10cSrcweir        # this is necessary since NT platforms have a
900cdf0e10cSrcweir        # 2s modified time granularity while the timestamps
901cdf0e10cSrcweir        # on Samba volumes have a 1s granularity
902cdf0e10cSrcweir
903cdf0e10cSrcweir        $from_stat[9]-- if $from_stat[9] % 2;
904cdf0e10cSrcweir
905cdf0e10cSrcweir        if ( $to =~ /^\Q$dest\E/ ) {
906cdf0e10cSrcweir            if ( $from_stat[9] > $logfiledate ) {
907cdf0e10cSrcweir                $logfiledate = $from_stat[9];
908cdf0e10cSrcweir            }
909cdf0e10cSrcweir        } elsif ( $common_build && ( $to =~ /^\Q$common_dest\E/ ) ) {
910cdf0e10cSrcweir            if ( $from_stat[9] > $commonlogfiledate ) {
911cdf0e10cSrcweir                $commonlogfiledate = $from_stat[9];
912cdf0e10cSrcweir            }
913cdf0e10cSrcweir        }
914cdf0e10cSrcweir
915cdf0e10cSrcweir        @to_stat = stat($to.$maybedot);
916cdf0e10cSrcweir        return \@from_stat unless -f _;
917cdf0e10cSrcweir
918cdf0e10cSrcweir        if ( $opt_force ) {
919cdf0e10cSrcweir            return \@from_stat;
920cdf0e10cSrcweir        }
921cdf0e10cSrcweir        else {
922cdf0e10cSrcweir            return ($from_stat[9] > $to_stat[9]) ? \@from_stat : 0;
923cdf0e10cSrcweir        }
924cdf0e10cSrcweir}
925cdf0e10cSrcweir
926cdf0e10cSrcweirsub filter_out
927cdf0e10cSrcweir{
928cdf0e10cSrcweir    my $file = shift;
929cdf0e10cSrcweir
930cdf0e10cSrcweir    foreach my $pattern ( @copy_filter_patterns ) {
931cdf0e10cSrcweir        if  ( $file =~ /$pattern/ ) {
932cdf0e10cSrcweir           print "filter out: $file\n" if $is_debug;
933cdf0e10cSrcweir           return 1;
934cdf0e10cSrcweir        }
935cdf0e10cSrcweir    }
936cdf0e10cSrcweir
937cdf0e10cSrcweir    return 0;
938cdf0e10cSrcweir}
939cdf0e10cSrcweir
940cdf0e10cSrcweirsub fix_file_permissions
941cdf0e10cSrcweir{
942cdf0e10cSrcweir    my $mode = shift;
943cdf0e10cSrcweir    my $file = shift;
944cdf0e10cSrcweir
945cdf0e10cSrcweir    if ( ($mode >> 6) % 2 == 1 ) {
946cdf0e10cSrcweir        $mode = 0777 & ~$umask;
947cdf0e10cSrcweir    }
948cdf0e10cSrcweir    else {
949cdf0e10cSrcweir        $mode = 0666 & ~$umask;
950cdf0e10cSrcweir    }
951cdf0e10cSrcweir    chmod($mode, $file);
952cdf0e10cSrcweir}
953cdf0e10cSrcweir
954cdf0e10cSrcweirsub get_latest_patchlevel
955cdf0e10cSrcweir{
956cdf0e10cSrcweir    # note: feed only well formed library names to this function
957cdf0e10cSrcweir    # of the form libfoo.so.x.y.z with x,y,z numbers
958cdf0e10cSrcweir
959cdf0e10cSrcweir    my @sorted_files = sort by_rev @_;
960cdf0e10cSrcweir    return $sorted_files[-1];
961cdf0e10cSrcweir
962cdf0e10cSrcweir    sub by_rev {
963cdf0e10cSrcweir    # comparison function for sorting
964cdf0e10cSrcweir        my (@field_a, @field_b, $i);
965cdf0e10cSrcweir
966cdf0e10cSrcweir        $a =~ /^(lib[\w-]+(\.so|\.dylib))\.(\d+)\.(\d+)\.(\d+)$/;
967cdf0e10cSrcweir        @field_a = ($3, $4, $5);
968cdf0e10cSrcweir        $b =~ /^(lib[\w-]+(\.so|\.dylib))\.(\d+)\.(\d+)\.(\d+)$/;
969cdf0e10cSrcweir        @field_b = ($3, $4, $5);
970cdf0e10cSrcweir
971cdf0e10cSrcweir        for ($i = 0; $i < 3; $i++)
972cdf0e10cSrcweir          {
973cdf0e10cSrcweir              if ( ($field_a[$i] < $field_b[$i]) ) {
974cdf0e10cSrcweir                  return -1;
975cdf0e10cSrcweir              }
976cdf0e10cSrcweir              if ( ($field_a[$i] > $field_b[$i]) ) {
977cdf0e10cSrcweir                  return 1;
978cdf0e10cSrcweir              }
979cdf0e10cSrcweir          }
980cdf0e10cSrcweir
981cdf0e10cSrcweir        # can't happen
982cdf0e10cSrcweir        return 0;
983cdf0e10cSrcweir    }
984cdf0e10cSrcweir
985cdf0e10cSrcweir}
986cdf0e10cSrcweir
987cdf0e10cSrcweirsub push_default_actions
988cdf0e10cSrcweir{
989cdf0e10cSrcweir    # any default action (that is an action which must be done even without
990cdf0e10cSrcweir    # a corresponding d.lst entry) should be pushed here on the
991cdf0e10cSrcweir    # @action_data list.
992cdf0e10cSrcweir    my $subdir;
993cdf0e10cSrcweir    my @subdirs = (
994cdf0e10cSrcweir                    'bin',
995cdf0e10cSrcweir                    'doc',
996cdf0e10cSrcweir                    'inc',
997cdf0e10cSrcweir                    'lib',
998cdf0e10cSrcweir                    'par',
999cdf0e10cSrcweir                    'pck',
1000cdf0e10cSrcweir                    'rdb',
1001cdf0e10cSrcweir                    'res',
1002cdf0e10cSrcweir                    'xml'
1003cdf0e10cSrcweir                );
1004cdf0e10cSrcweir    push(@subdirs, 'zip') if $opt_zip;
1005cdf0e10cSrcweir    push(@subdirs, 'idl') if ! $common_build;
1006cdf0e10cSrcweir    push(@subdirs, 'pus') if ! $common_build;
1007cdf0e10cSrcweir    my @common_subdirs = (
1008cdf0e10cSrcweir                    'bin',
1009cdf0e10cSrcweir                    'idl',
1010cdf0e10cSrcweir                    'inc',
1011cdf0e10cSrcweir                    'pck',
1012cdf0e10cSrcweir                    'pus',
1013cdf0e10cSrcweir                    'res'
1014cdf0e10cSrcweir                );
1015cdf0e10cSrcweir    push(@common_subdirs, 'zip') if $opt_zip;
1016cdf0e10cSrcweir
1017cdf0e10cSrcweir    if ( ! $opt_delete ) {
1018cdf0e10cSrcweir        # create all the subdirectories on solver
1019cdf0e10cSrcweir        foreach $subdir (@subdirs) {
1020cdf0e10cSrcweir            push(@action_data, ['mkdir', "%_DEST%/$subdir%_EXT%"]);
1021cdf0e10cSrcweir        }
1022cdf0e10cSrcweir        if ( $common_build ) {
1023cdf0e10cSrcweir            foreach $subdir (@common_subdirs) {
1024cdf0e10cSrcweir                push(@action_data, ['mkdir', "%COMMON_DEST%/$subdir%_EXT%"]);
1025cdf0e10cSrcweir            }
1026cdf0e10cSrcweir        }
1027cdf0e10cSrcweir    }
1028cdf0e10cSrcweir    push(@action_data, ['mkdir', "%_DEST%/inc%_EXT%/$module"]);
1029cdf0e10cSrcweir    if ( $common_build ) {
1030cdf0e10cSrcweir        push(@action_data, ['mkdir', "%COMMON_DEST%/inc%_EXT%/$module"]);
1031cdf0e10cSrcweir        push(@action_data, ['mkdir', "%COMMON_DEST%/res%_EXT%/img"]);
1032cdf0e10cSrcweir    } else {
1033cdf0e10cSrcweir        push(@action_data, ['mkdir', "%_DEST%/res%_EXT%/img"]);
1034cdf0e10cSrcweir    }
1035cdf0e10cSrcweir
1036cdf0e10cSrcweir    # deliver build.lst to $dest/inc/$module
1037cdf0e10cSrcweir    push(@action_data, ['copy', "build.lst %_DEST%/inc%_EXT%/$module/build.lst"]);
1038cdf0e10cSrcweir    if ( $common_build ) {
1039cdf0e10cSrcweir        # ... and to $common_dest/inc/$module
1040cdf0e10cSrcweir        push(@action_data, ['copy', "build.lst %COMMON_DEST%/inc%_EXT%/$module/build.lst"]);
1041cdf0e10cSrcweir    }
1042cdf0e10cSrcweir
1043cdf0e10cSrcweir    # need to copy libstaticmxp.dylib for Mac OS X
1044cdf0e10cSrcweir    if ( $^O eq 'darwin' )
1045cdf0e10cSrcweir    {
1046cdf0e10cSrcweir        push(@action_data, ['copy', "../%__SRC%/lib/lib*static*.dylib %_DEST%/lib%_EXT%/lib*static*.dylib"]);
1047cdf0e10cSrcweir    }
1048cdf0e10cSrcweir}
1049cdf0e10cSrcweir
1050cdf0e10cSrcweirsub walk_addincpath_list
1051cdf0e10cSrcweir{
1052cdf0e10cSrcweir    my (@addincpath_headers);
1053cdf0e10cSrcweir    return if $#addincpath_list == -1;
1054cdf0e10cSrcweir
1055cdf0e10cSrcweir    # create hash with all addincpath header names
1056cdf0e10cSrcweir    for (my $i = 0; $i <= $#addincpath_list; $i++) {
1057cdf0e10cSrcweir        my @field = split('/', $addincpath_list[$i][0]);
1058cdf0e10cSrcweir        push (@addincpath_headers, $field[-1]);
1059cdf0e10cSrcweir    }
1060cdf0e10cSrcweir
1061cdf0e10cSrcweir    # now stream all addincpath headers through addincpath filter
1062cdf0e10cSrcweir    for (my $i = 0; $i <= $#addincpath_list; $i++) {
1063cdf0e10cSrcweir        add_incpath_if_newer($addincpath_list[$i][0], $addincpath_list[$i][1], \@addincpath_headers)
1064cdf0e10cSrcweir                ? $files_copied++ : $files_unchanged++;
1065cdf0e10cSrcweir    }
1066cdf0e10cSrcweir}
1067cdf0e10cSrcweir
1068cdf0e10cSrcweirsub add_incpath_if_newer
1069cdf0e10cSrcweir{
1070cdf0e10cSrcweir    my $from = shift;
1071cdf0e10cSrcweir    my $to = shift;
1072cdf0e10cSrcweir    my $modify_headers_ref = shift;
1073cdf0e10cSrcweir    my ($from_stat_ref, $header);
1074cdf0e10cSrcweir
1075cdf0e10cSrcweir    push_on_ziplist($to) if $opt_zip;
1076cdf0e10cSrcweir    push_on_loglist("ADDINCPATH", "$from", "$to") if $opt_log;
1077cdf0e10cSrcweir
1078cdf0e10cSrcweir    if ( $opt_delete ) {
1079cdf0e10cSrcweir        print "REMOVE: $to\n" if $opt_verbose;
1080cdf0e10cSrcweir        my $rc = unlink($to);
1081cdf0e10cSrcweir        return 1 if $rc;
1082cdf0e10cSrcweir        return 0;
1083cdf0e10cSrcweir    }
1084cdf0e10cSrcweir
1085cdf0e10cSrcweir    if ( $from_stat_ref = is_newer($from, $to) ) {
1086cdf0e10cSrcweir        print "ADDINCPATH: $from -> $to\n" if $opt_verbose;
1087cdf0e10cSrcweir
1088cdf0e10cSrcweir        return 1 if $opt_check;
1089cdf0e10cSrcweir
1090cdf0e10cSrcweir        my $save = $/;
1091cdf0e10cSrcweir        undef $/;
1092cdf0e10cSrcweir        open(FROM, "<$from");
1093cdf0e10cSrcweir        # slurp whole file in one big string
1094cdf0e10cSrcweir        my $content = <FROM>;
1095cdf0e10cSrcweir        close(FROM);
1096cdf0e10cSrcweir        $/ = $save;
1097cdf0e10cSrcweir
1098cdf0e10cSrcweir        foreach $header (@$modify_headers_ref) {
1099cdf0e10cSrcweir            $content =~ s/#include [<"]$header[>"]/#include <$module\/$header>/g;
1100cdf0e10cSrcweir        }
1101cdf0e10cSrcweir
1102cdf0e10cSrcweir        open(TO, ">$to");
1103cdf0e10cSrcweir        print TO $content;
1104cdf0e10cSrcweir        close(TO);
1105cdf0e10cSrcweir
1106cdf0e10cSrcweir        utime($$from_stat_ref[9], $$from_stat_ref[9], $to);
1107cdf0e10cSrcweir        fix_file_permissions($$from_stat_ref[2], $to);
1108cdf0e10cSrcweir        return 1;
1109cdf0e10cSrcweir    }
1110cdf0e10cSrcweir    return 0;
1111cdf0e10cSrcweir}
1112cdf0e10cSrcweir
1113cdf0e10cSrcweirsub push_on_ziplist
1114cdf0e10cSrcweir{
1115cdf0e10cSrcweir    my $file = shift;
1116cdf0e10cSrcweir    return if ( $opt_check );
1117cdf0e10cSrcweir    # strip $dest from path since we don't want to record it in zip file
1118cdf0e10cSrcweir    if ( $file =~ s#^\Q$dest\E/##o ) {
1119cdf0e10cSrcweir        if ( $updminor ){
1120cdf0e10cSrcweir            # strip minor from path
1121cdf0e10cSrcweir            my $ext = "%_EXT%";
1122cdf0e10cSrcweir            $ext = expand_macros($ext);
1123cdf0e10cSrcweir            $file =~ s#^$ext##o;
1124cdf0e10cSrcweir        }
1125cdf0e10cSrcweir        push(@zip_list, $file);
1126cdf0e10cSrcweir    } elsif ( $file =~ s#^\Q$common_dest\E/##o ) {
1127cdf0e10cSrcweir        if ( $updminor ){
1128cdf0e10cSrcweir            # strip minor from path
1129cdf0e10cSrcweir            my $ext = "%_EXT%";
1130cdf0e10cSrcweir            $ext = expand_macros($ext);
1131cdf0e10cSrcweir            $file =~ s#^$ext##o;
1132cdf0e10cSrcweir        }
1133cdf0e10cSrcweir        push(@common_zip_list, $file);
1134cdf0e10cSrcweir    }
1135cdf0e10cSrcweir}
1136cdf0e10cSrcweir
1137cdf0e10cSrcweirsub push_on_loglist
1138cdf0e10cSrcweir{
1139cdf0e10cSrcweir    my @entry = @_;
1140cdf0e10cSrcweir    return 0 if ( $opt_check );
1141cdf0e10cSrcweir    return -1 if ( $#entry != 2 );
1142cdf0e10cSrcweir    if (( $entry[0] eq "COPY" ) || ( $entry[0] eq "ADDINCPATH" )) {
1143cdf0e10cSrcweir        return 0 if ( ! -e $entry[1].$maybedot );
1144cdf0e10cSrcweir        # make 'from' relative to source root
1145cdf0e10cSrcweir        $entry[1] = $repository ."/" . $module . "/prj/" . $entry[1];
1146cdf0e10cSrcweir        $entry[1] =~ s/$module\/prj\/\.\./$module/;
1147cdf0e10cSrcweir    }
1148cdf0e10cSrcweir    # platform or common tree?
1149cdf0e10cSrcweir    my $common;
1150cdf0e10cSrcweir    if ( $entry[2] =~ /^\Q$dest\E/ ) {
1151cdf0e10cSrcweir        $common = 0;
1152cdf0e10cSrcweir    } elsif ( $common_build && ( $entry[2] =~ /^\Q$common_dest\E/ )) {
1153cdf0e10cSrcweir        $common = 1;
1154cdf0e10cSrcweir    } else {
1155cdf0e10cSrcweir        warn "Neither common nor platform tree?";
1156cdf0e10cSrcweir        return;
1157cdf0e10cSrcweir    }
1158cdf0e10cSrcweir    # make 'to' relative to SOLARVERSION
1159cdf0e10cSrcweir    my $solarversion  = $ENV{'SOLARVERSION'};
1160cdf0e10cSrcweir    $solarversion =~ s#\\#/#g;
1161cdf0e10cSrcweir    $entry[2] =~ s/^\Q$solarversion\E\///;
1162cdf0e10cSrcweir    # strip minor from 'to'
1163cdf0e10cSrcweir    my $ext = "%_EXT%";
1164cdf0e10cSrcweir    $ext = expand_macros($ext);
1165cdf0e10cSrcweir    $entry[2] =~ s#$ext([\\\/])#$1#o;
1166cdf0e10cSrcweir
1167cdf0e10cSrcweir    if ( $common ) {
1168cdf0e10cSrcweir        push @common_log_list, [@entry];
1169cdf0e10cSrcweir    } else {
1170cdf0e10cSrcweir        push @log_list, [@entry];
1171cdf0e10cSrcweir    }
1172cdf0e10cSrcweir    return 1;
1173cdf0e10cSrcweir}
1174cdf0e10cSrcweir
1175cdf0e10cSrcweirsub zip_files
1176cdf0e10cSrcweir{
1177cdf0e10cSrcweir    my $zipexe = 'zip';
1178cdf0e10cSrcweir    $zipexe .= ' -y' unless  $^O eq 'MSWin32';
1179cdf0e10cSrcweir
1180cdf0e10cSrcweir    my ($platform_zip_file, $common_zip_file);
1181cdf0e10cSrcweir    $platform_zip_file = "%_DEST%/zip%_EXT%/$module.zip";
1182cdf0e10cSrcweir    $platform_zip_file = expand_macros($platform_zip_file);
1183cdf0e10cSrcweir    my (%dest_dir, %list_ref);
1184cdf0e10cSrcweir    $dest_dir{$platform_zip_file} = $dest;
1185cdf0e10cSrcweir    $list_ref{$platform_zip_file} = \@zip_list;
1186cdf0e10cSrcweir    if ( $common_build ) {
1187cdf0e10cSrcweir        $common_zip_file = "%COMMON_DEST%/zip%_EXT%/$module.zip";
1188cdf0e10cSrcweir        $common_zip_file = expand_macros($common_zip_file);
1189cdf0e10cSrcweir        $dest_dir{$common_zip_file}   = $common_dest;
1190cdf0e10cSrcweir        $list_ref{$common_zip_file}   = \@common_zip_list;
1191cdf0e10cSrcweir    }
1192cdf0e10cSrcweir
1193cdf0e10cSrcweir    my $ext = "%_EXT%";
1194cdf0e10cSrcweir    $ext = expand_macros($ext);
1195cdf0e10cSrcweir
1196cdf0e10cSrcweir    my @zipfiles;
1197cdf0e10cSrcweir    $zipfiles[0] = $platform_zip_file;
1198cdf0e10cSrcweir    if ( $common_build ) {
1199cdf0e10cSrcweir        push @zipfiles, ($common_zip_file);
1200cdf0e10cSrcweir    }
1201cdf0e10cSrcweir    foreach my $zip_file ( @zipfiles ) {
1202cdf0e10cSrcweir        print "ZIP: updating $zip_file\n" if $opt_verbose;
1203cdf0e10cSrcweir        next if ( $opt_check );
1204cdf0e10cSrcweir
1205cdf0e10cSrcweir        if ( $opt_delete ) {
1206cdf0e10cSrcweir            if ( -e $zip_file ) {
1207cdf0e10cSrcweir                unlink $zip_file or die "Error: can't remove file '$zip_file': $!";
1208cdf0e10cSrcweir            }
1209cdf0e10cSrcweir            next;
1210cdf0e10cSrcweir        }
1211cdf0e10cSrcweir
1212cdf0e10cSrcweir        local $work_file = "";
1213cdf0e10cSrcweir        if ( $zip_file eq $common_zip_file) {
1214cdf0e10cSrcweir            # Zip file in common tree: work on uniq copy to avoid collisions
1215cdf0e10cSrcweir            $work_file = $zip_file;
1216cdf0e10cSrcweir            $work_file =~ s/\.zip$//;
1217cdf0e10cSrcweir            $work_file .= (sprintf('.%d-%d', $$, time())) . ".zip";
1218cdf0e10cSrcweir            die "Error: temp file $work_file already exists" if ( -e $work_file);
1219cdf0e10cSrcweir            if ( -e $zip_file ) {
1220cdf0e10cSrcweir                if ( -z $zip_file) {
1221cdf0e10cSrcweir                    # sometimes there are files of 0 byte size - remove them
1222cdf0e10cSrcweir                    unlink $zip_file or print_error("can't remove empty file '$zip_file': $!",0);
1223cdf0e10cSrcweir                } else {
1224cdf0e10cSrcweir                    if ( ! copy($zip_file, $work_file)) {
1225cdf0e10cSrcweir                        # give a warning, not an error:
1226cdf0e10cSrcweir                        # we can zip from scratch instead of just updating the old zip file
1227cdf0e10cSrcweir                        print_warning("can't copy'$zip_file' into '$work_file': $!", 0);
1228cdf0e10cSrcweir                        unlink $work_file;
1229cdf0e10cSrcweir                    }
1230cdf0e10cSrcweir                }
1231cdf0e10cSrcweir            }
1232cdf0e10cSrcweir        } else {
1233cdf0e10cSrcweir            # No pre processing necessary, working directly on solver.
1234cdf0e10cSrcweir            $work_file = $zip_file;
1235cdf0e10cSrcweir        }
1236cdf0e10cSrcweir
1237cdf0e10cSrcweir        # zip content has to be relative to $dest_dir
1238cdf0e10cSrcweir        chdir($dest_dir{$zip_file}) or die "Error: cannot chdir into $dest_dir{$zip_file}";
1239cdf0e10cSrcweir        my $this_ref = $list_ref{$zip_file};
1240cdf0e10cSrcweir        open(ZIP, "| $zipexe -q -o -u -@ $work_file") or die "error opening zip file";
1241cdf0e10cSrcweir        foreach $file ( @$this_ref ) {
1242cdf0e10cSrcweir            print "ZIP: adding $file to $zip_file\n" if $is_debug;
1243cdf0e10cSrcweir            print ZIP "$file\n";
1244cdf0e10cSrcweir        }
1245cdf0e10cSrcweir        close(ZIP);
1246cdf0e10cSrcweir        fix_broken_cygwin_created_zips($work_file) if $^O eq "cygwin";
1247cdf0e10cSrcweir
1248cdf0e10cSrcweir        if ( $zip_file eq $common_zip_file) {
1249cdf0e10cSrcweir            # rename work file back
1250cdf0e10cSrcweir            if ( -e $work_file ) {
1251cdf0e10cSrcweir                if ( -e $zip_file) {
1252cdf0e10cSrcweir                    # do some tricks to be fast. otherwise we may disturb other platforms
1253cdf0e10cSrcweir                    # by unlinking a file which just gets copied -> stale file handle.
1254cdf0e10cSrcweir                    my $buffer_file=$work_file . '_rm';
1255cdf0e10cSrcweir                    rename($zip_file, $buffer_file) or warn "Warning: can't rename old zip file '$zip_file': $!";
1256cdf0e10cSrcweir                    if (! rename($work_file, $zip_file)) {
1257cdf0e10cSrcweir                        print_error("can't rename temporary file to $zip_file: $!",0);
1258cdf0e10cSrcweir                        unlink $work_file;
1259cdf0e10cSrcweir                    }
1260cdf0e10cSrcweir                    unlink $buffer_file;
1261cdf0e10cSrcweir                } else {
1262cdf0e10cSrcweir                    if (! rename($work_file, $zip_file)) {
1263cdf0e10cSrcweir                        print_error("can't rename temporary file to $zip_file: $!",0);
1264cdf0e10cSrcweir                        unlink $work_file;
1265cdf0e10cSrcweir                    }
1266cdf0e10cSrcweir                }
1267cdf0e10cSrcweir            }
1268cdf0e10cSrcweir        }
1269cdf0e10cSrcweir    }
1270cdf0e10cSrcweir}
1271cdf0e10cSrcweir
1272cdf0e10cSrcweirsub fix_broken_cygwin_created_zips
1273cdf0e10cSrcweir# add given extension to or strip it from stored path
1274cdf0e10cSrcweir{
1275cdf0e10cSrcweir    require Archive::Zip; import Archive::Zip;
1276cdf0e10cSrcweir    my $zip_file = shift;
1277cdf0e10cSrcweir
1278cdf0e10cSrcweir    $zip = Archive::Zip->new();
1279cdf0e10cSrcweir    unless ( $zip->read($work_file) == AZ_OK ) {
1280cdf0e10cSrcweir        die "Error: can't open zip file '$zip_file' to fix broken cygwin file permissions";
1281cdf0e10cSrcweir    }
1282cdf0e10cSrcweir    my $latest_member_mod_time = 0;
1283cdf0e10cSrcweir    foreach $member ( $zip->members() ) {
1284cdf0e10cSrcweir        my $attributes = $member->unixFileAttributes();
1285cdf0e10cSrcweir        $attributes &= ~0xFE00;
1286cdf0e10cSrcweir        print $member->fileName() . ": " . sprintf("%lo", $attributes) if $is_debug;
1287cdf0e10cSrcweir        $attributes |= 0x10; # add group write permission
1288cdf0e10cSrcweir        print "-> " . sprintf("%lo", $attributes) . "\n" if $is_debug;
1289cdf0e10cSrcweir        $member->unixFileAttributes($attributes);
1290cdf0e10cSrcweir        if ( $latest_member_mod_time < $member->lastModTime() ) {
1291cdf0e10cSrcweir            $latest_member_mod_time = $member->lastModTime();
1292cdf0e10cSrcweir        }
1293cdf0e10cSrcweir    }
1294cdf0e10cSrcweir    die "Error: can't overwrite zip file '$zip_file' for fixing permissions" unless $zip->overwrite() == AZ_OK;
1295cdf0e10cSrcweir    utime($latest_member_mod_time, $latest_member_mod_time, $zip_file);
1296cdf0e10cSrcweir}
1297cdf0e10cSrcweir
1298cdf0e10cSrcweirsub get_tempfilename
1299cdf0e10cSrcweir{
1300cdf0e10cSrcweir    my $temp_dir = shift;
1301cdf0e10cSrcweir    $temp_dir = ( -d '/tmp' ? '/tmp' : $ENV{TMPDIR} || $ENV{TEMP} || '.' )
1302cdf0e10cSrcweir            unless defined($temp_dir);
1303cdf0e10cSrcweir 	if ( ! -d $temp_dir ) {
1304cdf0e10cSrcweir        die "no temp directory $temp_dir\n";
1305cdf0e10cSrcweir    }
1306cdf0e10cSrcweir    my $base_name = sprintf( "%d-%di-%d", $$, time(), $tempcounter++ );
1307cdf0e10cSrcweir    return "$temp_dir/$base_name";
1308cdf0e10cSrcweir}
1309cdf0e10cSrcweir
1310cdf0e10cSrcweirsub write_log
1311cdf0e10cSrcweir{
1312cdf0e10cSrcweir    my (%log_file, %file_date);
1313cdf0e10cSrcweir    $log_file{\@log_list} = "%_DEST%/inc%_EXT%/$module/deliver.log";
1314cdf0e10cSrcweir    $log_file{\@common_log_list} = "%COMMON_DEST%/inc%_EXT%/$module/deliver.log";
1315cdf0e10cSrcweir    $file_date{\@log_list} = $logfiledate;
1316cdf0e10cSrcweir    $file_date{\@common_log_list} = $commonlogfiledate;
1317cdf0e10cSrcweir
1318cdf0e10cSrcweir    my @logs = ( \@log_list );
1319cdf0e10cSrcweir    push @logs, ( \@common_log_list ) if ( $common_build );
1320cdf0e10cSrcweir    foreach my $log ( @logs ) {
1321cdf0e10cSrcweir        $log_file{$log} = expand_macros( $log_file{$log} );
1322cdf0e10cSrcweir        if ( $opt_delete ) {
1323cdf0e10cSrcweir            print "LOG: removing $log_file{$log}\n" if $opt_verbose;
1324cdf0e10cSrcweir            next if ( $opt_check );
1325cdf0e10cSrcweir            unlink $log_file{$log};
1326cdf0e10cSrcweir        } else {
1327cdf0e10cSrcweir            print "LOG: writing $log_file{$log}\n" if $opt_verbose;
1328cdf0e10cSrcweir            next if ( $opt_check );
1329cdf0e10cSrcweir            open( LOGFILE, "> $log_file{$log}" ) or warn "Error: could not open log file.";
1330cdf0e10cSrcweir            foreach my $item ( @$log ) {
1331cdf0e10cSrcweir                print LOGFILE "@$item\n";
1332cdf0e10cSrcweir            }
1333cdf0e10cSrcweir            close( LOGFILE );
1334cdf0e10cSrcweir            utime($file_date{$log}, $file_date{$log}, $log_file{$log});
1335cdf0e10cSrcweir        }
1336cdf0e10cSrcweir        push_on_ziplist( $log_file{$log} ) if $opt_zip;
1337cdf0e10cSrcweir    }
1338cdf0e10cSrcweir    return;
1339cdf0e10cSrcweir}
1340cdf0e10cSrcweir
1341cdf0e10cSrcweirsub check_dlst
1342cdf0e10cSrcweir{
1343cdf0e10cSrcweir    my %createddir;
1344cdf0e10cSrcweir    my %destdir;
1345cdf0e10cSrcweir    my %destfile;
1346cdf0e10cSrcweir    # get all checkable actions to perform
1347cdf0e10cSrcweir    foreach my $action ( @action_data ) {
1348cdf0e10cSrcweir        my $path = expand_macros( $$action[1] );
1349cdf0e10cSrcweir        if ( $$action[0] eq 'mkdir' ) {
1350cdf0e10cSrcweir            $createddir{$path} ++;
1351cdf0e10cSrcweir        } elsif (( $$action[0] eq 'copy' ) || ( $$action[0] eq 'addincpath' )) {
1352cdf0e10cSrcweir            my ($from, $to) = split(' ', $path);
1353cdf0e10cSrcweir            my ($to_fname, $to_dir);
1354cdf0e10cSrcweir            my $withwildcard = 0;
1355cdf0e10cSrcweir            if ( $from =~ /[\*\?\[\]]/ ) {
1356cdf0e10cSrcweir                $withwildcard = 1;
1357cdf0e10cSrcweir            }
1358cdf0e10cSrcweir            ($to_fname, $to_dir) = fileparse($to);
1359cdf0e10cSrcweir            if ( $withwildcard ) {
1360cdf0e10cSrcweir                if ( $to !~ /[\*\?\[\]]/ ) {
1361cdf0e10cSrcweir                    $to_dir = $to;
1362cdf0e10cSrcweir                    $to_fname ='';
1363cdf0e10cSrcweir                }
1364cdf0e10cSrcweir            }
1365cdf0e10cSrcweir            $to_dir =~ s/[\\\/\s]$//;
1366cdf0e10cSrcweir            $destdir{$to_dir} ++;
1367cdf0e10cSrcweir            # Check: copy into non existing directory?
1368cdf0e10cSrcweir            if ( ! $createddir{$to_dir} ) {
1369cdf0e10cSrcweir                # unfortunately it is not so easy: it's OK if a subdirectory of $to_dir
1370cdf0e10cSrcweir                # gets created, because mkpath creates the whole tree
1371cdf0e10cSrcweir                foreach my $directory ( keys %createddir ) {
1372cdf0e10cSrcweir                    if ( $directory =~ /^\Q$to_dir\E[\\\/]/ ) {
1373cdf0e10cSrcweir                        $createddir{$to_dir} ++;
1374cdf0e10cSrcweir                        last;
1375cdf0e10cSrcweir                    }
1376cdf0e10cSrcweir                }
1377cdf0e10cSrcweir                print_warning("Possibly copying into directory without creating in before: '$to_dir'")
1378cdf0e10cSrcweir                    unless $createddir{$to_dir};
1379cdf0e10cSrcweir            }
1380cdf0e10cSrcweir            # Check: overwrite file?
1381cdf0e10cSrcweir            if ( ! $to ) {
1382cdf0e10cSrcweir                if ( $destfile{$to} ) {
1383cdf0e10cSrcweir                    print_warning("Multiple entries copying to '$to'");
1384cdf0e10cSrcweir                }
1385cdf0e10cSrcweir                $destfile{$to} ++;
1386cdf0e10cSrcweir            }
1387cdf0e10cSrcweir        }
1388cdf0e10cSrcweir    }
1389cdf0e10cSrcweir}
1390cdf0e10cSrcweir
1391cdf0e10cSrcweirsub cleanup
1392cdf0e10cSrcweir{
1393cdf0e10cSrcweir    # remove empty directories
1394cdf0e10cSrcweir    foreach my $path ( @dirlist ) {
1395cdf0e10cSrcweir        $path = expand_macros($path);
1396cdf0e10cSrcweir        if ( $opt_check ) {
1397cdf0e10cSrcweir            print "RMDIR: $path\n" if $opt_verbose;
1398cdf0e10cSrcweir        } else {
1399cdf0e10cSrcweir            rmdir $path;
1400cdf0e10cSrcweir        }
1401cdf0e10cSrcweir    }
1402cdf0e10cSrcweir}
1403cdf0e10cSrcweir
1404cdf0e10cSrcweirsub delete_output
1405cdf0e10cSrcweir{
1406cdf0e10cSrcweir    my $output_path = expand_macros("../%__SRC%");
1407cdf0e10cSrcweir    if ( "$output_path" ne "../" ) {
1408cdf0e10cSrcweir        if ( rmtree([$output_path], 0, 1) ) {
1409cdf0e10cSrcweir            print "Deleted output tree.\n" if $opt_verbose;
1410cdf0e10cSrcweir        }
1411cdf0e10cSrcweir        else {
1412cdf0e10cSrcweir            print_error("Error deleting output tree $output_path: $!",0);
1413cdf0e10cSrcweir        }
1414cdf0e10cSrcweir    }
1415cdf0e10cSrcweir    else {
1416cdf0e10cSrcweir        print_error("Output not deleted - INPATH is not set");
1417cdf0e10cSrcweir    }
1418cdf0e10cSrcweir}
1419cdf0e10cSrcweir
1420cdf0e10cSrcweirsub print_warning
1421cdf0e10cSrcweir{
1422cdf0e10cSrcweir    my $message = shift;
1423cdf0e10cSrcweir    my $line = shift;
1424cdf0e10cSrcweir
1425cdf0e10cSrcweir    print STDERR "$script_name: ";
1426cdf0e10cSrcweir    if ( $dlst_file ) {
1427cdf0e10cSrcweir        print STDERR "$dlst_file: ";
1428cdf0e10cSrcweir    }
1429cdf0e10cSrcweir    if ( $line ) {
1430cdf0e10cSrcweir        print STDERR "line $line: ";
1431cdf0e10cSrcweir    }
1432cdf0e10cSrcweir    print STDERR "WARNING: $message\n";
1433cdf0e10cSrcweir}
1434cdf0e10cSrcweir
1435cdf0e10cSrcweirsub print_error
1436cdf0e10cSrcweir{
1437cdf0e10cSrcweir    my $message = shift;
1438cdf0e10cSrcweir    my $line = shift;
1439cdf0e10cSrcweir
1440cdf0e10cSrcweir    print STDERR "$script_name: ";
1441cdf0e10cSrcweir    if ( $dlst_file ) {
1442cdf0e10cSrcweir        print STDERR "$dlst_file: ";
1443cdf0e10cSrcweir    }
1444cdf0e10cSrcweir    if ( $line ) {
1445cdf0e10cSrcweir        print STDERR "line $line: ";
1446cdf0e10cSrcweir    }
1447cdf0e10cSrcweir    print STDERR "ERROR: $message\n";
1448cdf0e10cSrcweir    $error ++;
1449cdf0e10cSrcweir}
1450cdf0e10cSrcweir
1451cdf0e10cSrcweirsub print_stats
1452cdf0e10cSrcweir{
1453cdf0e10cSrcweir    print "Module '$module' delivered ";
1454cdf0e10cSrcweir    if ( $error ) {
1455cdf0e10cSrcweir        print "with errors\n";
1456cdf0e10cSrcweir    } else {
1457cdf0e10cSrcweir        print "successfully.";
1458cdf0e10cSrcweir        if ( $opt_delete ) {
1459cdf0e10cSrcweir            print " $files_copied files removed,";
1460cdf0e10cSrcweir        }
1461cdf0e10cSrcweir        else {
1462cdf0e10cSrcweir            print " $files_copied files copied,";
1463cdf0e10cSrcweir        }
1464cdf0e10cSrcweir        print " $files_unchanged files unchanged\n";
1465cdf0e10cSrcweir    }
1466cdf0e10cSrcweir}
1467cdf0e10cSrcweir
1468cdf0e10cSrcweirsub cleanup_and_die
1469cdf0e10cSrcweir{
1470cdf0e10cSrcweir    # clean up on unexpected termination
1471cdf0e10cSrcweir    my $sig = shift;
1472cdf0e10cSrcweir    if ( defined($temp_file) && -e $temp_file ) {
1473cdf0e10cSrcweir        unlink($temp_file);
1474cdf0e10cSrcweir    }
1475cdf0e10cSrcweir    if ( defined($work_file) && -e $work_file ) {
1476cdf0e10cSrcweir        unlink($work_file);
1477cdf0e10cSrcweir        print STDERR "$work_file removed\n";
1478cdf0e10cSrcweir    }
1479cdf0e10cSrcweir
1480cdf0e10cSrcweir    die "caught unexpected signal $sig, terminating ...";
1481cdf0e10cSrcweir}
1482cdf0e10cSrcweir
1483cdf0e10cSrcweirsub usage
1484cdf0e10cSrcweir{
1485cdf0e10cSrcweir    my $exit_code = shift;
1486cdf0e10cSrcweir    print STDERR "Usage:\ndeliver [OPTIONS] [DESTINATION-PATH]\n";
1487cdf0e10cSrcweir    print STDERR "Options:\n";
1488cdf0e10cSrcweir    print STDERR "  -check       just print what would happen, no actual copying of files\n";
1489cdf0e10cSrcweir    print STDERR "  -checkdlst   be verbose about (possible) d.lst bugs\n";
1490cdf0e10cSrcweir    print STDERR "  -delete      delete files (undeliver), use with care\n";
1491cdf0e10cSrcweir    print STDERR "  -deloutput   remove the output tree after copying\n";
1492cdf0e10cSrcweir    print STDERR "  -dontdeletecommon do not delete common files (for -delete option)\n";
1493cdf0e10cSrcweir    print STDERR "  -force       copy even if not newer\n";
1494cdf0e10cSrcweir    print STDERR "  -help        print this message\n";
1495cdf0e10cSrcweir    if ( !defined($ENV{GUI}) || $ENV{GUI} ne 'WNT' ) {
1496cdf0e10cSrcweir        print STDERR "  -link        hard link files into the solver to save disk space\n";
1497cdf0e10cSrcweir    }
1498cdf0e10cSrcweir    print STDERR "  -quiet       be quiet, only report errors\n";
1499cdf0e10cSrcweir    print STDERR "  -verbose     be verbose\n";
1500cdf0e10cSrcweir    print STDERR "  -zip         additionally create zip files of delivered content\n";
1501cdf0e10cSrcweir    print STDERR "Options '-zip' and a destination-path are mutually exclusive.\n";
1502cdf0e10cSrcweir    print STDERR "Options '-check' and '-quiet' are mutually exclusive.\n";
1503cdf0e10cSrcweir    exit($exit_code);
1504cdf0e10cSrcweir}
1505cdf0e10cSrcweir
1506cdf0e10cSrcweir# vim: set ts=4 shiftwidth=4 expandtab syntax=perl:
1507