xref: /trunk/main/solenv/bin/modules/installer/simplepackage.pm (revision be094486c5534336663aa1ddadd1cdda20a9ddd0)
1#**************************************************************
2#
3#  Licensed to the Apache Software Foundation (ASF) under one
4#  or more contributor license agreements.  See the NOTICE file
5#  distributed with this work for additional information
6#  regarding copyright ownership.  The ASF licenses this file
7#  to you under the Apache License, Version 2.0 (the
8#  "License"); you may not use this file except in compliance
9#  with the License.  You may obtain a copy of the License at
10#
11#    http://www.apache.org/licenses/LICENSE-2.0
12#
13#  Unless required by applicable law or agreed to in writing,
14#  software distributed under the License is distributed on an
15#  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16#  KIND, either express or implied.  See the License for the
17#  specific language governing permissions and limitations
18#  under the License.
19#
20#**************************************************************
21
22
23
24package installer::simplepackage;
25
26# use Archive::Zip qw( :ERROR_CODES :CONSTANTS );
27use Cwd;
28use File::Copy;
29use installer::download;
30use installer::exiter;
31use installer::globals;
32use installer::logger;
33use installer::strip;
34use installer::systemactions;
35use installer::worker;
36
37sub shell_quote
38{
39    my ( $value ) = @_;
40    $value =~ s/'/'"'"'/g;
41    return "'$value'";
42}
43
44####################################################
45# Checking if the simple packager is required.
46# This can be achieved by setting the global
47# variable SIMPLE_PACKAGE in *.lst file or by
48# setting the environment variable SIMPLE_PACKAGE.
49####################################################
50
51sub check_simple_packager_project
52{
53    my ( $allvariables ) = @_;
54
55    if (( $installer::globals::packageformat eq "installed" ) ||
56        ( $installer::globals::packageformat eq "archive" ))
57    {
58        $installer::globals::is_simple_packager_project = 1;
59        $installer::globals::patch_user_dir = 1;
60    }
61    elsif( $installer::globals::packageformat eq "dmg" )
62    {
63        $installer::globals::is_simple_packager_project = 1;
64    }
65}
66
67####################################################
68# Detecting the directory with extensions
69####################################################
70
71sub get_extensions_dir
72{
73    my ( $subfolderdir ) = @_;
74
75    my $extensiondir = $subfolderdir . $installer::globals::separator;
76    if ( $installer::globals::officedirhostname ne "" ) { $extensiondir = $extensiondir . $installer::globals::officedirhostname . $installer::globals::separator; }
77    my $extensionsdir = $extensiondir . "share" . $installer::globals::separator . "extensions";
78    my $preregdir = $extensiondir . "share" . $installer::globals::separator . "prereg" . $installer::globals::separator . "bundled";
79
80    return ( $extensionsdir, $preregdir );
81}
82
83####################################################
84# Registering extensions
85####################################################
86
87sub register_extensions
88{
89    my ($officedir, $languagestringref, $preregdir) = @_;
90
91    my $infoline = "";
92
93    if ( $preregdir eq "" )
94    {
95        $infoline = "ERROR: Failed to determine directory \"prereg\" for extension registration! Please check your installation set.\n";
96        $installer::logger::Lang->print($infoline);
97        installer::exiter::exit_program($infoline, "register_extensions");
98    }
99
100    my $programdir = $officedir . $installer::globals::separator;
101    if ( $installer::globals::officedirhostname ne "" ) { $programdir = $programdir . $installer::globals::officedirhostname . $installer::globals::separator; }
102    $programdir = $programdir . "program";
103
104    my $from = cwd();
105    chdir($programdir);
106
107    my $unopkgfile = $installer::globals::unopkgfile;
108
109    my $unopkgexists = 1;
110    if (( $installer::globals::languagepack ) && ( ! -f $unopkgfile ))
111    {
112        $unopkgexists = 0;
113        $infoline = "Language packs do not contain unopkg!\n";
114        $installer::logger::Lang->print($infoline);
115    }
116
117    if ( ! -f $unopkgfile )
118    {
119        $unopkgexists = 0;
120        $infoline = "Info: File $unopkgfile does not exist! Extensions cannot be registered.\n";
121        $installer::logger::Lang->print($infoline);
122    }
123
124    if ( $unopkgexists )
125    {
126        my $currentdir = cwd();
127        $installer::logger::Info->printf("... current dir: %s ...\n", $currentdir);
128        $infoline = "Current dir: $currentdir\n";
129        $installer::logger::Lang->print($infoline);
130
131        if ( ! -f $unopkgfile ) { installer::exiter::exit_program("ERROR: $unopkgfile not found!", "register_extensions"); }
132
133        my $systemcall = $programdir . $installer::globals::separator . $unopkgfile . " sync --verbose" . " -env:UNO_JAVA_JFW_ENV_JREHOME=true 2\>\&1 |";
134
135        $installer::logger::Info->printf("... %s ...\n", $systemcall);
136
137        $infoline = "Systemcall: $systemcall\n";
138        $installer::logger::Lang->print($infoline);
139
140        my @unopkgoutput = ();
141
142        open (UNOPKG, $systemcall);
143        while (<UNOPKG>)
144        {
145            my $lastline = $_;
146            push(@unopkgoutput, $lastline);
147        }
148        close (UNOPKG);
149
150        my $returnvalue = $?;   # $? contains the return value of the systemcall
151
152        if ($returnvalue)
153        {
154            # Writing content of @unopkgoutput only in the error case into the log file. Sometimes it
155            # contains strings like "Error" even in the case of success. This causes a packaging error
156            # when the log file is analyzed at the end, even if there is no real error.
157            foreach my $line (@unopkgoutput)
158            {
159                $installer::logger::Lang->printf($line);
160            }
161
162            $infoline = "ERROR: Could not execute \"$systemcall\"!\nExitcode: '$returnvalue'\n";
163            $installer::logger::Lang->print($infoline);
164            installer::exiter::exit_program("ERROR: $systemcall failed!", "register_extensions");
165        }
166        else
167        {
168            $infoline = "Success: Executed \"$systemcall\" successfully!\n";
169            $installer::logger::Lang->print($infoline);
170        }
171    }
172
173    chdir($from);
174}
175
176########################################################################
177# Getting the translation file for the Mac Language Pack installer
178########################################################################
179
180sub get_mac_translation_file
181{
182    my $translationfilename = $installer::globals::maclangpackfilename;
183    if ( ! -f $translationfilename ) { installer::exiter::exit_program("ERROR: Could not find language file $translationfilename!", "get_mac_translation_file"); }
184    my $translationfile = installer::files::read_file($translationfilename);
185
186    my $infoline = "Reading translation file: $translationfilename\n";
187    $installer::logger::Lang->print($infoline);
188
189    return $translationfile;
190}
191
192##################################################################
193# Collecting all identifier from ulf file
194##################################################################
195
196sub get_identifier
197{
198    my ( $translationfile ) = @_;
199
200    my @identifier = ();
201
202    for ( my $i = 0; $i <= $#{$translationfile}; $i++ )
203    {
204        my $oneline = ${$translationfile}[$i];
205
206        if ( $oneline =~ /^\s*\[(.+)\]\s*$/ )
207        {
208            my $identifier = $1;
209            push(@identifier, $identifier);
210        }
211    }
212
213    return \@identifier;
214}
215
216##############################################################
217# Returning the complete block in all languages
218# for a specified string
219##############################################################
220
221sub get_language_block_from_language_file
222{
223    my ($searchstring, $languagefile) = @_;
224
225    my @language_block = ();
226
227    for ( my $i = 0; $i <= $#{$languagefile}; $i++ )
228    {
229        if ( ${$languagefile}[$i] =~ /^\s*\[\s*$searchstring\s*\]\s*$/ )
230        {
231            my $counter = $i;
232
233            push(@language_block, ${$languagefile}[$counter]);
234            $counter++;
235
236            while (( $counter <= $#{$languagefile} ) && (!( ${$languagefile}[$counter] =~ /^\s*\[/ )))
237            {
238                push(@language_block, ${$languagefile}[$counter]);
239                $counter++;
240            }
241
242            last;
243        }
244    }
245
246    return \@language_block;
247}
248
249##############################################################
250# Returning a specific language string from the block
251# of all translations
252##############################################################
253
254sub get_language_string_from_language_block
255{
256    my ($language_block, $language) = @_;
257
258    my $newstring = "";
259
260    for ( my $i = 0; $i <= $#{$language_block}; $i++ )
261    {
262        if ( ${$language_block}[$i] =~ /^\s*$language\s*\=\s*\"(.*)\"\s*$/ )
263        {
264            $newstring = $1;
265            last;
266        }
267    }
268
269    if ( $newstring eq "" )
270    {
271        $language = "en-US";    # defaulting to english
272
273        for ( my $i = 0; $i <= $#{$language_block}; $i++ )
274        {
275            if ( ${$language_block}[$i] =~ /^\s*$language\s*\=\s*\"(.*)\"\s*$/ )
276            {
277                $newstring = $1;
278                last;
279            }
280        }
281    }
282
283    return $newstring;
284}
285
286########################################################################
287# Localizing the script for the Mac Language Pack installer
288########################################################################
289
290sub localize_scriptfile
291{
292    my ($scriptfile, $translationfile, $languagestringref) = @_;
293
294    # my $translationfile = get_mac_translation_file();
295
296    my $onelanguage = $$languagestringref;
297    if ( $onelanguage =~ /^\s*(.*?)_/ ) { $onelanguage = $1; }
298
299    # Analyzing the ulf file, collecting all Identifier
300    my $allidentifier = get_identifier($translationfile);
301
302    for ( my $i = 0; $i <= $#{$allidentifier}; $i++ )
303    {
304        my $identifier = ${$allidentifier}[$i];
305        my $language_block = get_language_block_from_language_file($identifier, $translationfile);
306        my $newstring = get_language_string_from_language_block($language_block, $onelanguage);
307
308        # removing mask
309        $newstring =~ s/\\\'/\'/g;
310
311        replace_one_variable_in_shellscript($scriptfile, $newstring, $identifier);
312    }
313}
314
315#################################################################################
316# Replacing one variable in Mac shell script
317#################################################################################
318
319sub replace_one_variable_in_shellscript
320{
321    my ($scriptfile, $variable, $searchstring) = @_;
322
323    for ( my $i = 0; $i <= $#{$scriptfile}; $i++ )
324    {
325        ${$scriptfile}[$i] =~ s/\[$searchstring\]/$variable/g;
326    }
327}
328
329#############################################
330# Replacing variables in Mac shell script
331#############################################
332
333sub replace_variables_in_scriptfile
334{
335    my ($scriptfile, $volume_name, $volume_name_app, $allvariables) = @_;
336
337    replace_one_variable_in_shellscript($scriptfile, $volume_name, "FULLPRODUCTNAME" );
338    replace_one_variable_in_shellscript($scriptfile, $volume_name_app, "FULLAPPPRODUCTNAME" );
339    replace_one_variable_in_shellscript($scriptfile, $allvariables->{'PRODUCTNAME'}, "PRODUCTNAME" );
340    replace_one_variable_in_shellscript($scriptfile, $allvariables->{'PRODUCTVERSION'}, "PRODUCTVERSION" );
341
342    my $scriptname = lc($allvariables->{'PRODUCTNAME'}) . "\.script";
343    if ( $allvariables->{'PRODUCTNAME'} eq "OpenOffice" )
344    {
345        $scriptname = "org.openoffice.script";
346    }
347
348    replace_one_variable_in_shellscript($scriptfile, $scriptname, "SEARCHSCRIPTNAME" );
349}
350
351#############################################
352# Creating the "simple" package.
353# "zip" for Windows
354# "tar.gz" for all other platforms
355# additionally "dmg" on Mac OS X
356#############################################
357
358sub create_package
359{
360    my ( $installdir, $archivedir, $packagename, $allvariables, $includepatharrayref, $languagestringref, $format ) = @_;
361
362    $installer::logger::Info->printf("... creating %s file ...\n", $installer::globals::packageformat);
363    installer::logger::include_header_into_logfile("Creating $installer::globals::packageformat file:");
364
365    # moving dir into temporary directory
366    my $pid = $$; # process id
367    my $tempdir = $installdir . "_temp" . "." . $pid;
368    my $systemcall = "";
369    my $from = "";
370    my $makesystemcall = 1;
371    my $return_to_start = 0;
372    installer::systemactions::rename_directory($installdir, $tempdir);
373
374    # creating new directory with original name
375    installer::systemactions::create_directory($archivedir);
376
377    my $archive = $archivedir . $installer::globals::separator . $packagename . $format;
378
379    if ( $archive =~ /zip$/ )
380    {
381        $from = cwd();
382        $return_to_start = 1;
383        chdir($tempdir);
384        if ( $^O =~ /os2/i )
385        {
386            my $zip = Cwd::realpath($archive);
387            $systemcall = "$installer::globals::zippath -qr $zip .";
388        }
389        else
390        {
391            $systemcall = "$installer::globals::zippath -qr $archive .";
392        }
393
394        # Using Archive::Zip fails because of very long path names below "share/uno_packages/cache"
395        # my $packzip = Archive::Zip->new();
396        # $packzip->addTree(".");   # after changing into $tempdir
397        # $packzip->writeToFileNamed($archive);
398        # $makesystemcall = 0;
399    }
400    elsif ( $archive =~ /dmg$/ )
401    {
402        my $folder = (( -l "$tempdir/$packagename/Applications" ) or ( -l "$tempdir/$packagename/opt" )) ? $packagename : "\.";
403
404        if ( $allvariables->{'PACK_INSTALLED'} ) {
405            $folder = $packagename;
406        }
407
408        # my $volume_name = $allvariables->{'PRODUCTNAME'} . ' ' . $allvariables->{'PRODUCTVERSION'}; # Adding PRODUCTVERSION makes this difficult to maintain!
409        my $volume_name = $allvariables->{'PRODUCTNAME'};
410        my $volume_name_classic = $allvariables->{'PRODUCTNAME'} . ' ' . $allvariables->{'PRODUCTVERSION'};
411        my $volume_name_classic_app = $volume_name;  # "app" should not contain version number
412        # $volume_name = $volume_name . ' ' . $allvariables->{'PRODUCTEXTENSION'} if $allvariables->{'PRODUCTEXTENSION'}; # Adding PRODUCTEXTENSION makes this difficult to maintain!
413        $volume_name_classic = $volume_name_classic . ' ' . $allvariables->{'PRODUCTEXTENSION'} if $allvariables->{'PRODUCTEXTENSION'};
414        $volume_name_classic_app = $volume_name_classic_app . ' ' . $allvariables->{'PRODUCTEXTENSION'} if $allvariables->{'PRODUCTEXTENSION'};
415        if ( $allvariables->{'DMG_VOLUMEEXTENSION'} ) {
416            $volume_name = $volume_name . ' ' . $allvariables->{'DMG_VOLUMEEXTENSION'};
417            $volume_name_classic = $volume_name_classic . ' ' . $allvariables->{'DMG_VOLUMEEXTENSION'};
418            $volume_name_classic_app = $volume_name_classic_app . ' ' . $allvariables->{'DMG_VOLUMEEXTENSION'};
419        }
420
421        my $sla = 'sla.r';
422        my $ref = "";
423
424        if ( ! $allvariables->{'HIDELICENSEDIALOG'} )
425        {
426            $ref = installer::scriptitems::get_sourcepath_from_filename_and_includepath( \$sla, $includepatharrayref, 0);
427        }
428
429        my $localtempdir = $tempdir;
430
431        if (( $installer::globals::languagepack ) || ( $installer::globals::patch ))
432        {
433            $localtempdir = "$tempdir/$packagename";
434            if ( $installer::globals::languagepack )
435            {
436                $volume_name = "$volume_name Language Pack";
437                $volume_name_classic = "$volume_name_classic Language Pack";
438                $volume_name_classic_app = "$volume_name_classic_app Language Pack";
439            }
440            if ( $installer::globals::patch )
441            {
442                $volume_name = "$volume_name Patch";
443                $volume_name_classic = "$volume_name_classic Patch";
444                $volume_name_classic_app = "$volume_name_classic_app Patch";
445            }
446
447            # Create tar ball named tarball.tar.bz2
448            # my $appfolder = $localtempdir . "/" . $volume_name . "\.app";
449            my $appfolder = $localtempdir . "/" . $volume_name_classic_app . "\.app";
450            my $contentsfolder = $appfolder . "/Contents";
451            my $tarballname = "tarball.tar.bz2";
452
453            my $localfrom = cwd();
454            chdir $appfolder;
455
456            $systemcall = "tar -cjf $tarballname Contents/";
457
458            $installer::logger::Info->printf("... %s ...\n", $systemcall);
459            my $localreturnvalue = system($systemcall);
460            $infoline = "Systemcall: $systemcall\n";
461            $installer::logger::Lang->print($infoline);
462
463            if ($localreturnvalue)
464            {
465                $infoline = "ERROR: Could not execute \"$systemcall\"!\n";
466                $installer::logger::Lang->print($infoline);
467            }
468            else
469            {
470                $infoline = "Success: Executed \"$systemcall\" successfully!\n";
471                $installer::logger::Lang->print($infoline);
472            }
473
474            # codesign treats loose files in Contents as unsigned nested code.
475            my $resourcesfolder = $contentsfolder . "/Resources";
476            my $sourcefile = $appfolder . "/" . $tarballname;
477            my $destfile = $resourcesfolder . "/" . $tarballname;
478
479            installer::systemactions::remove_complete_directory($contentsfolder);
480            installer::systemactions::create_directory($contentsfolder);
481            installer::systemactions::create_directory($resourcesfolder);
482
483            installer::systemactions::copy_one_file($sourcefile, $destfile);
484            unlink($sourcefile);
485
486            # Copy two files into installation set next to the tar ball
487            # 1. "osx_install.applescript"
488            # 2 "OpenOffice.org Languagepack"
489
490            my $scriptrealfilename = "osx_install.applescript";
491            my $scriptfilename = "";
492            if ( $installer::globals::languagepack ) { $scriptfilename = "osx_install_languagepack.applescript"; }
493            if ( $installer::globals::patch ) { $scriptfilename = "osx_install_patch.applescript"; }
494            my $scripthelpersolverfilename = "mac_install.script";
495            # my $scripthelperrealfilename = $volume_name;
496            my $scripthelperrealfilename = $volume_name_classic_app;
497            my $translationfilename = $installer::globals::macinstallfilename;
498
499            # Finding both files in solver
500
501            my $scriptref = installer::scriptitems::get_sourcepath_from_filename_and_includepath( \$scriptfilename, $includepatharrayref, 0);
502            if ($$scriptref eq "") { installer::exiter::exit_program("ERROR: Could not find Apple script $scriptfilename!", "create_package"); }
503            my $scripthelperref = installer::scriptitems::get_sourcepath_from_filename_and_includepath( \$scripthelpersolverfilename, $includepatharrayref, 0);
504            if ($$scripthelperref eq "") { installer::exiter::exit_program("ERROR: Could not find Apple script $scripthelpersolverfilename!", "create_package"); }
505            my $translationfileref = installer::scriptitems::get_sourcepath_from_filename_and_includepath( \$translationfilename, $includepatharrayref, 0);
506            if ($$translationfileref eq "") { installer::exiter::exit_program("ERROR: Could not find Apple script translation file $translationfilename!", "create_package"); }
507
508            $scriptfilename = $resourcesfolder . "/" . $scriptrealfilename;
509            my $macosfolder = $contentsfolder . "/MacOS";
510            installer::systemactions::create_directory($macosfolder);
511            $scripthelperrealfilename = $macosfolder . "/" . $scripthelperrealfilename;
512
513            installer::systemactions::copy_one_file($$scriptref, $scriptfilename);
514            installer::systemactions::copy_one_file($$scripthelperref, $scripthelperrealfilename);
515
516            # Replacing variables in script $scriptfilename
517            # Localizing script $scriptfilename
518            my $scriptfilecontent = installer::files::read_file($scriptfilename);
519            my $translationfilecontent = installer::files::read_file($$translationfileref);
520            localize_scriptfile($scriptfilecontent, $translationfilecontent, $languagestringref);
521            # replace_variables_in_scriptfile($scriptfilecontent, $volume_name, $allvariables);
522            replace_variables_in_scriptfile($scriptfilecontent, $volume_name_classic, $volume_name_classic_app, $allvariables);
523            installer::files::save_file($scriptfilename, $scriptfilecontent);
524
525            $systemcall = "chmod 775 " . "\"" . $scriptfilename . "\"";
526            system($systemcall);
527            $systemcall = "chmod 775 " . "\"" . $scripthelperrealfilename . "\"";
528            system($systemcall);
529
530            # Copy also Info.plist and icon file
531            # Finding both files in solver
532            my $iconfile = "ooo3_installer.icns";
533            my $iconfileref = installer::scriptitems::get_sourcepath_from_filename_and_includepath( \$iconfile, $includepatharrayref, 0);
534            if ($$iconfileref eq "") { installer::exiter::exit_program("ERROR: Could not find Apple script icon file $iconfile!", "create_package"); }
535            $destfile = $resourcesfolder . "/" . $iconfile;
536            installer::systemactions::copy_one_file($$iconfileref, $destfile);
537
538            my $infoplistfile = "Info.plist.langpack";
539            my $installname = "Info.plist";
540            my $infoplistfileref = installer::scriptitems::get_sourcepath_from_filename_and_includepath( \$infoplistfile, $includepatharrayref, 0);
541            if ($$infoplistfileref eq "") { installer::exiter::exit_program("ERROR: Could not find Apple script Info.plist: $infoplistfile!", "create_package"); }
542            $destfile = $contentsfolder . "/" . $installname;
543            installer::systemactions::copy_one_file($$infoplistfileref, $destfile);
544
545            # Replacing variables in Info.plist
546            $scriptfilecontent = installer::files::read_file($destfile);
547            # replace_one_variable_in_shellscript($scriptfilecontent, $volume_name, "FULLPRODUCTNAME" );
548            replace_one_variable_in_shellscript($scriptfilecontent, $volume_name_classic_app, "FULLAPPPRODUCTNAME" ); # OpenOffice.org Language Pack
549            installer::files::save_file($destfile, $scriptfilecontent);
550
551            chdir $localfrom;
552        }
553
554        # A build-time load path left in a shipped Mach-O breaks at runtime, signed or not.
555        # The language-pack app is only scripts and a plist, so it has no Mach-O to check.
556        foreach my $appdir ( $installer::globals::languagepack ? () : glob("$localtempdir/$folder/*.app") )
557        {
558            my $checkreturn = system($ENV{'SOLARENV'} . "/bin/macosx-check-load-commands.sh", $appdir);
559            if ( $checkreturn ) { installer::exiter::exit_program("ERROR: Unrelocated Mach-O load commands in $appdir!", "create_package"); }
560        }
561
562        # Code-sign the .app before it is sealed into the .dmg. Opt-in: without
563        # MACOSX_CODESIGNING_IDENTITY the installation set is left as it was.
564        if ( $ENV{'MACOSX_CODESIGNING_IDENTITY'} )
565        {
566            my $signscript = $ENV{'SOLARENV'} . "/bin/macosx-codesign.sh";
567            foreach my $appdir ( glob("$localtempdir/$folder/*.app") )
568            {
569                my @signcall = ($signscript, "-i", $ENV{'MACOSX_CODESIGNING_IDENTITY'});
570                push(@signcall, "-k", $ENV{'MACOSX_CODESIGNING_KEYCHAIN'}) if $ENV{'MACOSX_CODESIGNING_KEYCHAIN'};
571                push(@signcall, "--notarize", $ENV{'MACOSX_NOTARY_PROFILE'}) if $ENV{'MACOSX_NOTARY_PROFILE'};
572                push(@signcall, $appdir);
573                my $signreturn = system(@signcall);
574                if ( $signreturn ) { installer::exiter::exit_program("ERROR: Could not code-sign $appdir!", "create_package"); }
575                $installer::logger::Lang->print("Success: Code-signed $appdir\n");
576            }
577        }
578
579        # "hdiutil makehybrid -hfs" stamps an (empty) com.apple.FinderInfo onto
580        # every file in the image, which makes "codesign --verify --strict"
581        # reject the signed application inside the .dmg and would fail
582        # notarization. "hdiutil create -srcfolder" copies the files as they
583        # are. (The -hfs-openfolder auto-open it also did is not supported on
584        # Apple Silicon any more: bless refuses it.)
585        # "-fs HFS+" is not optional: left to itself "hdiutil create" makes an
586        # APFS image on recent macOS, which will not mount before 10.12.
587        # "makehybrid -hfs" always produced HFS+.
588        $systemcall = "cd " . shell_quote($localtempdir) .
589            " && hdiutil create -srcfolder " . shell_quote($folder) .
590            " -volname " . shell_quote($volume_name) .
591            " -fs HFS+ -format UDZO -ov " . shell_quote($archive);
592        if (( $ref ne "" ) && ( $$ref ne "" )) {
593            $systemcall .= " && hdiutil unflatten " . shell_quote($archive) .
594                " && Rez -a " . shell_quote($$ref) . " -o " . shell_quote($archive) .
595                " && hdiutil flatten " . shell_quote($archive);
596        }
597    }
598    else
599    {
600        # getting the path of the getuid.so (Solaris) or fakeroot (Linux)
601        my $getuidlibrary = "";
602        my $ldpreloadstring = "";
603        if ( $installer::globals::issolarisbuild )
604        {
605            $getuidlibrary = installer::download::get_path_for_library($includepatharrayref);
606            if ( $getuidlibrary ne "" ) { $ldpreloadstring = "LD_PRELOAD=" . $getuidlibrary; }
607        }
608        elsif ( $installer::globals::islinuxbuild )
609        {
610            $ldpreloadstring = $ENV{'FAKEROOT'};
611        }
612
613        $systemcall = "cd $tempdir; $ldpreloadstring tar -cf - . | gzip > $archive";
614    }
615
616    if ( $makesystemcall )
617    {
618        $installer::logger::Info->printf("... %s ...\n", $systemcall);
619        my $returnvalue = system($systemcall);
620        my $infoline = "Systemcall: $systemcall\n";
621        $installer::logger::Lang->print($infoline);
622
623        if ($returnvalue)
624        {
625            $infoline = "ERROR: Could not execute \"$systemcall\"!\n";
626            $installer::logger::Lang->print($infoline);
627        }
628        else
629        {
630            $infoline = "Success: Executed \"$systemcall\" successfully!\n";
631            $installer::logger::Lang->print($infoline);
632            # Sign the finished disk image. This completes the chain: the .app
633            # inside was signed before the image was built, and the image itself
634            # is signed here. It has to happen at this point rather than earlier -
635            # the Rez step above rewrites the image to attach the license
636            # resource, and that would invalidate a signature applied before it.
637            #
638            # Skipped for an ad-hoc identity: an ad-hoc signed .dmg buys nothing
639            # (Gatekeeper rejects it either way) and macosx-codesign.sh refuses
640            # it outright, which would turn a working ad-hoc build into an error.
641            if (( $archive =~ /dmg$/ ) &&
642                ( $ENV{'MACOSX_CODESIGNING_IDENTITY'} ) &&
643                ( $ENV{'MACOSX_CODESIGNING_IDENTITY'} ne "-" ))
644            {
645                my $signscript = $ENV{'SOLARENV'} . "/bin/macosx-codesign.sh";
646                my @signcall = ($signscript, "-i", $ENV{'MACOSX_CODESIGNING_IDENTITY'});
647                push(@signcall, "-k", $ENV{'MACOSX_CODESIGNING_KEYCHAIN'}) if $ENV{'MACOSX_CODESIGNING_KEYCHAIN'};
648                push(@signcall, "--notarize", $ENV{'MACOSX_NOTARY_PROFILE'}) if $ENV{'MACOSX_NOTARY_PROFILE'};
649                push(@signcall, $archive);
650                my $signreturn = system(@signcall);
651                if ( $signreturn ) { installer::exiter::exit_program("ERROR: Could not code-sign $archive!", "create_package"); }
652                $installer::logger::Lang->print("Success: Code-signed $archive\n");
653            }
654        }
655    }
656
657    if ( $return_to_start ) { chdir($from); }
658
659    $installer::logger::Info->printf("... removing %s ...\n", $tempdir);
660    installer::systemactions::remove_complete_directory($tempdir);
661}
662
663####################################################
664# Main method for creating the simple package
665# installation sets
666####################################################
667
668sub create_simple_package
669{
670    my ( $filesref, $dirsref, $scpactionsref, $linksref, $unixlinksref, $loggingdir, $languagestringref, $shipinstalldir, $allsettingsarrayref, $allvariables, $includepatharrayref ) = @_;
671
672    # Creating directories
673
674    my $current_install_number = "";
675    my $infoline = "";
676
677    $installer::logger::Info->print( "... creating installation directory ...\n" );
678    installer::logger::include_header_into_logfile("Creating installation directory");
679
680    $installer::globals::csp_installdir = installer::worker::create_installation_directory($shipinstalldir, $languagestringref, \$current_install_number);
681    $installer::globals::csp_installlogdir = installer::systemactions::create_directory_next_to_directory($installer::globals::csp_installdir, "log");
682
683    my $installdir = $installer::globals::csp_installdir;
684    my $installlogdir = $installer::globals::csp_installlogdir;
685
686    # Setting package name (similar to the download name)
687    my $packagename = "";
688
689    if ( $installer::globals::packageformat eq "archive"  ||
690        $installer::globals::packageformat eq "dmg" )
691    {
692        $installer::globals::csp_languagestring = $$languagestringref;
693
694        my $locallanguage = $installer::globals::csp_languagestring;
695
696        if ( $allvariables->{'AOODOWNLOADNAME'} )
697        {
698            $packagename = installer::download::set_download_filename(\$locallanguage, $allvariables);
699        }
700        else
701        {
702            $downloadname = installer::ziplist::getinfofromziplist($allsettingsarrayref, "downloadname");
703            if ( $installer::globals::languagepack ) { $downloadname = installer::ziplist::getinfofromziplist($allsettingsarrayref, "langpackdownloadname"); }
704            if ( $installer::globals::patch ) { $downloadname = installer::ziplist::getinfofromziplist($allsettingsarrayref, "patchdownloadname"); }
705            $packagename = installer::download::resolve_variables_in_downloadname($allvariables, $$downloadname, \$locallanguage);
706        }
707    }
708
709    # Work around Windows problems with long pathnames (see issue 50885) by
710    # putting the to-be-archived installation tree into the temp directory
711    # instead of the module output tree (unless LOCALINSTALLDIR dictates
712    # otherwise, anyway); can be removed once issue 50885 is fixed:
713    my $tempinstalldir = $installdir;
714    if ( $installer::globals::iswindowsbuild &&
715         $installer::globals::packageformat eq "archive" &&
716         !$installer::globals::localinstalldirset )
717    {
718        $tempinstalldir = File::Temp::tempdir;
719    }
720
721    # Creating subfolder in installdir, which shall become the root of package or zip file
722    my $subfolderdir = "";
723    if ( $packagename ne "" ) { $subfolderdir = $tempinstalldir . $installer::globals::separator . $packagename; }
724    else { $subfolderdir = $tempinstalldir; }
725
726    if ( ! -d $subfolderdir ) { installer::systemactions::create_directory($subfolderdir); }
727
728    # Create directories, copy files and ScpActions
729
730    $installer::logger::Info->print("... creating directories ...\n");
731    installer::logger::include_header_into_logfile("Creating directories:");
732
733    for ( my $i = 0; $i <= $#{$dirsref}; $i++ )
734    {
735        my $onedir = ${$dirsref}[$i];
736
737        if ( $onedir->{'HostName'} )
738        {
739            my $destdir = $subfolderdir . $installer::globals::separator . $onedir->{'HostName'};
740
741            if ( ! -d $destdir )
742            {
743                if ( $^O =~ /cygwin/i || $^O =~ /os2/i ) # Cygwin performance check
744                {
745                    $installer::logger::Lang->printf("Try to create directory %s\n", $destdir);
746                    # Directories in $dirsref are sorted and all parents were added -> "mkdir" works without parent creation!
747                    if ( ! ( -d $destdir )) { mkdir($destdir, 0775); }
748                }
749                else
750                {
751                    installer::systemactions::create_directory_structure($destdir);
752                }
753            }
754        }
755    }
756
757    # stripping files ?!
758    if (( $installer::globals::strip ) && ( ! $installer::globals::iswindowsbuild ) && ( ! $installer::globals::isos2 )) { installer::strip::strip_libraries($filesref, $languagestringref); }
759
760    # copy Files
761    $installer::logger::Info->print("... copying files ...\n");
762    installer::logger::include_header_into_logfile("Copying files:");
763
764    for ( my $i = 0; $i <= $#{$filesref}; $i++ )
765    {
766        my $onefile = ${$filesref}[$i];
767
768        if (( $onefile->{'Styles'} ) && ( $onefile->{'Styles'} =~ /\bBINARYTABLE_ONLY\b/ )) { next; }
769        if (( $installer::globals::patch ) && ( $onefile->{'Styles'} ) && ( ! ( $onefile->{'Styles'} =~ /\bPATCH\b/ ))) { next; }
770        if (( $installer::globals::patch ) && ( $installer::globals::packageformat eq "dmg" )) { push(@installer::globals::patchfilecollector, "$onefile->{'destination'}\n"); }
771
772        my $source = $onefile->{'sourcepath'};
773        my $destination = $onefile->{'destination'};
774        $destination = $subfolderdir . $installer::globals::separator . $destination;
775
776        # Replacing $$ by $ is necessary to install files with $ in its name (back-masquerading)
777        # Otherwise, the following shell command does not work and the file list is not correct
778        $source =~ s/\$\$/\$/;
779        $destination =~ s/\$\$/\$/;
780
781        if ( $^O =~ /cygwin/i || $^O =~ /os2/i )    # Cygwin performance, do not use copy_one_file. "chmod -R" at the end
782        {
783            my $copyreturn = copy($source, $destination);
784
785            if ($copyreturn)
786            {
787                $installer::logger::Lang->printf("Copy: $source to %s\n", $destination);
788                $returnvalue = 1;
789            }
790            else
791            {
792                $installer::logger::Lang->printf("ERROR: Could not copy %s to %s\n", $source, $destination);
793                $returnvalue = 0;
794            }
795        }
796        else
797        {
798            installer::systemactions::copy_one_file($source, $destination);
799
800            if ( ! $installer::globals::iswindowsbuild )
801            {
802                # see issue 102274
803                my $unixrights = "";
804                if ( $onefile->{'UnixRights'} )
805                {
806                    $unixrights = $onefile->{'UnixRights'};
807
808                    my $localcall = "$installer::globals::wrapcmd chmod $unixrights \'$destination\' \>\/dev\/null 2\>\&1";
809                    system($localcall);
810                }
811            }
812        }
813    }
814
815    # creating Links
816
817    $installer::logger::Info->print("... creating links ...\n");
818    installer::logger::include_header_into_logfile("Creating links:");
819
820    for ( my $i = 0; $i <= $#{$linksref}; $i++ )
821    {
822        my $onelink = ${$linksref}[$i];
823
824        if (( $installer::globals::patch ) && ( $onelink->{'Styles'} ) && ( ! ( $onelink->{'Styles'} =~ /\bPATCH\b/ ))) { next; }
825
826        my $destination = $onelink->{'destination'};
827        $destination = $subfolderdir . $installer::globals::separator . $destination;
828        my $destinationfile = $onelink->{'destinationfile'};
829
830        my $localcall = "ln -sf \'$destinationfile\' \'$destination\' \>\/dev\/null 2\>\&1";
831        system($localcall);
832
833        $installer::logger::Lang->printf("Creating link: \"ln -sf %s %s\"\n",
834            $destinationfile,
835            $destination);
836    }
837
838    for ( my $i = 0; $i <= $#{$unixlinksref}; $i++ )
839    {
840        my $onelink = ${$unixlinksref}[$i];
841
842        if (( $installer::globals::patch ) && ( $onelink->{'Styles'} ) && ( ! ( $onelink->{'Styles'} =~ /\bPATCH\b/ ))) { next; }
843
844        my $target = $onelink->{'Target'};
845        my $destination = $subfolderdir . $installer::globals::separator . $onelink->{'destination'};
846
847        my $localcall = "ln -sf \'$target\' \'$destination\' \>\/dev\/null 2\>\&1";
848        system($localcall);
849
850        $installer::logger::Lang->printf("Creating Unix link: \"ln -sf %s %s\"\n",
851            $target,
852            $destination);
853    }
854
855    # Setting privileges for cygwin globally
856
857    if ( $^O =~ /cygwin/i )
858    {
859        $installer::logger::Lang->print( "... changing privileges in $subfolderdir ...\n" );
860        installer::logger::include_header_into_logfile("Changing privileges in $subfolderdir:");
861
862        my $localcall = "chmod -R 755 " . "\"" . $subfolderdir . "\"";
863        system($localcall);
864    }
865
866    $installer::logger::Lang->print( "... removing superfluous directories ...\n" );
867    installer::logger::include_header_into_logfile("Removing superfluous directories:");
868
869    my ( $extensionfolder, $preregdir ) = get_extensions_dir($subfolderdir);
870    installer::systemactions::remove_empty_dirs_in_folder($extensionfolder);
871
872    # Registering the extensions
873
874    $installer::logger::Lang->print( "... registering extensions ...\n" );
875    installer::logger::include_header_into_logfile("Registering extensions:");
876    register_extensions($subfolderdir, $languagestringref, $preregdir);
877
878    if ( $installer::globals::compiler =~ /^unxmac/ )
879    {
880        installer::worker::put_scpactions_into_installset("$installdir/$packagename");
881    }
882
883    # Creating archive file
884    if ( $installer::globals::packageformat eq "archive" )
885    {
886        create_package($tempinstalldir, $installdir, $packagename, $allvariables, $includepatharrayref, $languagestringref, $installer::globals::archiveformat);
887    }
888    elsif ( $installer::globals::packageformat eq "dmg" )
889    {
890        create_package($installdir, $installdir, $packagename, $allvariables, $includepatharrayref, $languagestringref, ".dmg");
891    }
892
893    # Analyzing the log file
894
895    installer::worker::clean_output_tree(); # removing directories created in the output tree
896    installer::worker::analyze_and_save_logfile($loggingdir, $installdir, $installlogdir, $allsettingsarrayref, $languagestringref, $current_install_number);
897}
898
8991;
900