2 # This file is part of the LibreOffice project.
4 # This Source Code Form is subject to the terms of the Mozilla Public
5 # License, v. 2.0. If a copy of the MPL was not distributed with this
6 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 # This file incorporates work covered by the following license notice:
10 # Licensed to the Apache Software Foundation (ASF) under one or more
11 # contributor license agreements. See the NOTICE file distributed
12 # with this work for additional information regarding copyright
13 # ownership. The ASF licenses this file to you under the Apache
14 # License, Version 2.0 (the "License"); you may not use this file
15 # except in compliance with the License. You may obtain a copy of
16 # the License at http://www.apache.org/licenses/LICENSE-2.0 .
19 package installer
::packagelist
;
21 use installer
::converter
;
22 use installer
::exiter
;
23 use installer
::globals
;
24 use installer
::remover
;
25 use installer
::scriptitems
;
27 ########################################
28 # Check existence of module
29 ########################################
31 sub check_module_existence
33 my ($onegid, $moduleslist) = @_;
37 for ( my $i = 0; $i <= $#{$moduleslist}; $i++ )
39 my $gid = ${$moduleslist}[$i]->{'gid'};
41 if ( $gid eq $onegid )
51 ###################################################
52 # Analyzing the gids, defined in the packagelist
53 ###################################################
57 my ($packagelist, $moduleslist) = @_;
61 my $moduleshash = get_module_hash
($moduleslist);
63 for ( my $i = 0; $i <= $#{$packagelist}; $i++ )
65 my $onepackage = ${$packagelist}[$i];
67 my $onegid = $onepackage->{'module'};
69 installer
::remover
::remove_leading_and_ending_whitespaces
(\
$onegid);
71 my $moduleexists = check_module_existence
($onegid, $moduleslist);
73 if ( ! $moduleexists ) { next; }
77 push(@allmodules, $onegid);
79 get_children_with_hash
($moduleshash, $onegid, \
@allmodules);
81 $onepackage->{'allmodules'} = \
@allmodules;
83 push(@allpackages, $onepackage);
89 ###################################################
90 # Creating a hash, that contains the module gids
91 # as keys and the parentids as values
92 ###################################################
96 my ($moduleslist) = @_;
100 for ( my $i = 0; $i <= $#{$moduleslist}; $i++ )
102 my $gid = ${$moduleslist}[$i]->{'gid'};
103 # Containing only modules with parent. Root modules can be ignored.
104 if ( ${$moduleslist}[$i]->{'ParentID'} ) { $modulehash{$gid} = ${$moduleslist}[$i]->{'ParentID'}; }
110 ########################################################
111 # Recursively defined procedure to order
112 # modules and directories
113 ########################################################
115 sub get_children_with_hash
117 my ($modulehash, $parentgid, $newitemorder) = @_;
119 foreach my $gid ( keys %{$modulehash} )
121 my $parent = $modulehash->{$gid};
123 if ( $parent eq $parentgid )
125 push(@
{$newitemorder}, $gid);
127 get_children_with_hash
($modulehash, $parent, $newitemorder); # recursive!
132 ########################################################
133 # Recursively defined procedure to order
134 # modules and directories
135 ########################################################
139 my ($allitems, $startparent, $newitemorder) = @_;
141 for ( my $i = 0; $i <= $#{$allitems}; $i++ )
143 my $gid = ${$allitems}[$i]->{'gid'};
145 if ( ${$allitems}[$i]->{'ParentID'} ) { $parent = ${$allitems}[$i]->{'ParentID'}; }
147 if ( $parent eq $startparent )
149 push(@
{$newitemorder}, $gid);
151 get_children
($allitems, $parent, $newitemorder); # recursive!
156 #####################################################################
157 # All modules below a defined gid_Module_A are collected now for
158 # each modules defined in the packagelist. Now the modules have
159 # to be removed, that are part of more than one package.
160 #####################################################################
162 sub remove_multiple_modules_packages
164 my ($allpackagemodules) = @_;
166 # iterating over all packages
168 for ( my $i = 0; $i <= $#{$allpackagemodules}; $i++ )
170 my $onepackage = ${$allpackagemodules}[$i];
171 my $allmodules = $onepackage->{'allmodules'};
173 # Comparing each package, with all following packages. If a
174 # gid for the module is part of more than one package, it is
175 # removed if the number of modules in the package is greater
176 # in the current package than in the compare package.
178 # Taking all modules from package $i
180 my $packagecount = $#{$allmodules};
182 my @optimizedpackage = ();
184 # iterating over all modules of this package
186 for ( my $j = 0; $j <= $#{$allmodules}; $j++ )
188 my $onemodule = ${$allmodules}[$j]; # this is the module, that shall be removed or not
190 my $put_module_into_new_package = 1;
192 # iterating over all other packages
194 for ( my $k = 0; $k <= $#{$allpackagemodules}; $k++ )
196 if ( $k == $i ) { next; } # not comparing equal module
198 if (! $put_module_into_new_package) { next; } # do not compare, if already found
200 my $comparepackage = ${$allpackagemodules}[$k];
201 my $allcomparemodules = $comparepackage->{'allmodules'};
203 my $comparepackagecount = $#{$allcomparemodules};
205 # modules will only be removed from packages, that have more modules
206 # than the compare package
208 if ( $packagecount < $comparepackagecount ) { next; } # nothing to do, take next package
210 # iterating over all modules of this package
212 for ( my $m = 0; $m <= $#{$allcomparemodules}; $m++ )
214 my $onecomparemodule = ${$allcomparemodules}[$m];
216 if ( $onemodule eq $onecomparemodule ) # this $onemodule has to be removed
218 $put_module_into_new_package = 0;
223 if ( $put_module_into_new_package )
225 push(@optimizedpackage, $onemodule)
229 $onepackage->{'allmodules'} = \
@optimizedpackage;
233 #####################################################################
234 # Analyzing all files if they belong to a special package.
235 # A package is described by a list of modules.
236 #####################################################################
238 sub find_files_for_package
240 my ($filelist, $onepackage) = @_;
242 my @newfilelist = ();
244 for ( my $i = 0; $i <= $#{$filelist}; $i++ )
246 my $onefile = ${$filelist}[$i];
247 my $modulesstring = $onefile->{'modules'}; # comma separated modules list
248 my $moduleslist = installer
::converter
::convert_stringlist_into_array
(\
$modulesstring, ",");
252 # iterating over all modules of this file
254 for ( my $j = 0; $j <= $#{$moduleslist}; $j++ )
256 if ( $includefile ) { next; }
257 my $filemodule = ${$moduleslist}[$j];
258 installer
::remover
::remove_leading_and_ending_whitespaces
(\
$filemodule);
260 # iterating over all modules of the package
262 my $packagemodules = $onepackage->{'allmodules'};
264 for ( my $k = 0; $k <= $#{$packagemodules}; $k++ )
266 if ( $includefile ) { next; }
267 my $packagemodule = ${$packagemodules}[$k];
269 if ( $filemodule eq $packagemodule )
279 push(@newfilelist, $onefile);
283 return \
@newfilelist;
286 #####################################################################
287 # Analyzing all links if they belong to a special package.
288 # A package is described by a list of modules.
289 # A link is inserted into the package, if the corresponding
290 # file is also inserted.
291 #####################################################################
293 sub find_links_for_package
295 my ($linklist, $filelist) = @_;
297 # First looking for all links with a FileID.
298 # Then looking for all links with a ShortcutID.
300 my @newlinklist = ();
302 for ( my $i = 0; $i <= $#{$linklist}; $i++ )
306 my $onelink = ${$linklist}[$i];
309 if ( $onelink->{'FileID'} ) { $fileid = $onelink->{'FileID'}; }
311 if ( $fileid eq "" ) { next; } # A link with a ShortcutID
313 for ( my $j = 0; $j <= $#{$filelist}; $j++ ) # iterating over file list
315 my $onefile = ${$filelist}[$j];
316 my $gid = $onefile->{'gid'};
318 if ( $gid eq $fileid )
327 push(@newlinklist, $onelink);
331 # iterating over the new list, because of all links with a ShortcutID
333 for ( my $i = 0; $i <= $#{$linklist}; $i++ )
337 my $onelink = ${$linklist}[$i];
340 if ( $onelink->{'ShortcutID'} ) { $shortcutid = $onelink->{'ShortcutID'}; }
342 if ( $shortcutid eq "" ) { next; } # A link with a ShortcutID
344 for ( my $j = 0; $j <= $#newlinklist; $j++ ) # iterating over newly created link list
346 my $onefilelink = $newlinklist[$j];
347 my $gid = $onefilelink->{'gid'};
349 if ( $gid eq $shortcutid )
358 push(@newlinklist, $onelink);
362 return \
@newlinklist;
365 #####################################################################
366 # Analyzing all directories if they belong to a special package.
367 # A package is described by a list of modules.
368 # Directories are included into the package, if they are needed
369 # by a file or a link included into the package.
370 # Attention: A directory with the flag CREATE, is only included
371 # into the root module:
372 # ($packagename eq $installer::globals::rootmodulegid)
373 #####################################################################
375 sub find_dirs_for_package
377 my ($dirlist, $onepackage) = @_;
381 for ( my $i = 0; $i <= $#{$dirlist}; $i++ )
383 my $onedir = ${$dirlist}[$i];
384 my $modulesstring = $onedir->{'modules'}; # comma separated modules list
385 my $moduleslist = installer
::converter
::convert_stringlist_into_array
(\
$modulesstring, ",");
389 # iterating over all modules of this dir
391 for ( my $j = 0; $j <= $#{$moduleslist}; $j++ )
393 if ( $includedir ) { last; }
394 my $dirmodule = ${$moduleslist}[$j];
395 installer
::remover
::remove_leading_and_ending_whitespaces
(\
$dirmodule);
397 # iterating over all modules of the package
399 my $packagemodules = $onepackage->{'allmodules'};
401 for ( my $k = 0; $k <= $#{$packagemodules}; $k++ )
403 my $packagemodule = ${$packagemodules}[$k];
405 if ( $dirmodule eq $packagemodule )
415 push(@newdirlist, $onedir);
422 #####################################################################
423 # Resolving all variables in the packagename.
424 #####################################################################
426 sub resolve_packagevariables
428 my ($packagenameref, $variableshashref, $make_lowercase) = @_;
432 # Special handling for dictionaries
433 if ( $$packagenameref =~ /-dict-/ )
435 if (exists($variableshashref->{'DICTIONARYUNIXPRODUCTNAME'}) ) { $$packagenameref =~ s/\%UNIXPRODUCTNAME/$variableshashref->{'DICTIONARYUNIXPRODUCTNAME'}/g; }
436 if (exists($variableshashref->{'DICTIONARYBRANDPACKAGEVERSION'}) ) { $$packagenameref =~ s/\%BRANDPACKAGEVERSION/$variableshashref->{'DICTIONARYBRANDPACKAGEVERSION'}/g; }
439 foreach $key (keys %{$variableshashref})
441 my $value = $variableshashref->{$key};
442 if ( $make_lowercase ) { $value = lc($value); }
443 $$packagenameref =~ s/\%$key/$value/g;
447 #####################################################################
448 # Resolving all variables in the packagename.
449 #####################################################################
451 sub resolve_packagevariables2
453 my ($packagenameref, $variableshashref, $make_lowercase, $isdict ) = @_;
457 # Special handling for dictionaries
460 if (exists($variableshashref->{'DICTIONARYUNIXPRODUCTNAME'}) ) { $$packagenameref =~ s/\%UNIXPRODUCTNAME/$variableshashref->{'DICTIONARYUNIXPRODUCTNAME'}/g; }
461 if (exists($variableshashref->{'DICTIONARYBRANDPACKAGEVERSION'}) ) { $$packagenameref =~ s/\%BRANDPACKAGEVERSION/$variableshashref->{'DICTIONARYBRANDPACKAGEVERSION'}/g; }
464 foreach $key (keys %{$variableshashref})
466 my $value = $variableshashref->{$key};
467 if ( $make_lowercase ) { $value = lc($value); }
468 $$packagenameref =~ s/\%$key/$value/g;
472 #####################################################################
473 # New packages system.
474 #####################################################################
476 ##################################################################
477 # Controlling the content of the packagelist
478 # 1. Items in @installer::globals::packagelistitems must exist
479 # 2. If a shellscript file is defined, it must exist
480 ##################################################################
482 sub check_packagelist
486 if ( ! ( $#{$packages} > -1 )) { installer::exiter::exit_program("ERROR: No packages defined!", "check_packagelist"); }
488 for ( my $i = 0; $i <= $#{$packages}; $i++ )
490 my $onepackage = ${$packages}[$i];
494 # checking all items that must be defined
496 foreach $element (@installer::globals
::packagelistitems
)
498 if ( ! exists($onepackage->{$element}) )
500 installer
::exiter
::exit_program
("ERROR in package list: No value for $element !", "check_packagelist");
504 # checking the existence of the script file, if defined
506 if ( $onepackage->{'script'} )
508 my $scriptfile = $onepackage->{'script'};
509 my $gid = $onepackage->{'module'};
510 my $fileref = installer
::scriptitems
::get_sourcepath_from_filename_and_includepath
(\
$scriptfile, "" , 0);
512 if ( $$fileref eq "" ) { installer
::exiter
::exit_program
("ERROR: Could not find script file $scriptfile for module $gid!", "check_packagelist"); }
514 my $infoline = "$gid: Using script file: \"$$fileref\"!\n";
515 push( @installer::globals
::logfileinfo
, $infoline);
517 $onepackage->{'script'} = $$fileref;
522 #####################################################################
523 # Reading pack info for one module from packinfo file.
524 #####################################################################
528 my ($gid, $filename, $packages, $onelanguage, $islanguagemodule) = @_;
530 my $packagelist = installer
::files
::read_file
($filename);
532 my @allpackages = ();
534 for ( my $i = 0; $i <= $#{$packagelist}; $i++ )
536 my $line = ${$packagelist}[$i];
538 if ( $line =~ /^\s*\#/ ) { next; } # this is a comment line
540 if ( $line =~ /^\s*Start\s*$/i ) # a new package definition
544 my $counter = $i + 1;
546 while (!( ${$packagelist}[$counter] =~ /^\s*End\s*$/i ))
548 if ( ${$packagelist}[$counter] =~ /^\s*(\S+)\s*\=\s*\"(.*)\"/ )
552 $onepackage{$key} = $value;
558 $onepackage{'islanguagemodule'} = $islanguagemodule;
559 if ( $islanguagemodule )
561 $saveonelanguage = $onelanguage;
562 $saveonelanguage =~ s/_/-/g;
563 $onepackage{'language'} = $saveonelanguage;
566 push(@allpackages, \
%onepackage);
570 # looking for the packinfo with the correct gid
574 foreach $onepackage (@allpackages)
576 # Adding the language to the module gid for LanguagePacks !
577 # Making the module gid language specific: gid_Module_Root -> gir_Module_Root_pt_BR (as defined in scp2)
578 if ( $onelanguage ne "" ) { $onepackage->{'module'} = $onepackage->{'module'} . "_$onelanguage"; }
580 if ( $onepackage->{'module'} eq $gid )
582 # Resolving the language identifier
584 foreach $onekey ( keys %{$onepackage} )
586 # Some keys require "-" instead of "_" for example in "en-US". All package names do not use underlines.
587 my $locallang = $onelanguage;
588 if (( $onekey eq "solarispackagename" ) ||
589 ( $onekey eq "solarisrequires" ) ||
590 ( $onekey eq "packagename" ) ||
591 ( $onekey eq "requires" )) { $locallang =~ s/_/-/g; } # avoiding illegal package abbreviation
592 $onepackage->{$onekey} =~ s/\%LANGUAGESTRING/$locallang/g;
595 # Saving the language for the package
596 my $lang = $onelanguage;
598 $onepackage->{'specificlanguage'} = $lang;
600 push(@
{$packages}, $onepackage);
608 installer
::exiter
::exit_program
("ERROR: Could not find package info for module $gid in file \"$filename\"!", "get_packinfo");
612 #####################################################################
613 # Collecting all packages from scp project.
614 #####################################################################
618 my ( $allmodules, $languagesarrayref ) = @_;
620 installer
::logger
::include_header_into_logfile
("Collecting packages:");
623 my %gid_analyzed = ();
626 foreach $onemodule ( @
{$allmodules} )
628 if ( $onemodule->{'PackageInfo'} ) # this is a package module!
630 my $modulegid = $onemodule->{'gid'};
633 if ( $onemodule->{'Styles'} ) { $styles = $onemodule->{'Styles'}; }
635 # checking modules with style LANGUAGEMODULE
636 my $islanguagemodule = 0;
637 my $onelanguage = "";
638 if ( $styles =~ /\bLANGUAGEMODULE\b/ )
640 $islanguagemodule = 1;
641 $onelanguage = $onemodule->{'Language'}; # already checked, that it is set.
642 $onelanguage =~ s/-/_/g; # pt-BR -> pt_BR in scp
645 # Modules in different languages are listed more than once in multilingual installation sets
646 if ( exists($gid_analyzed{$modulegid}) ) { next; }
647 $gid_analyzed{$modulegid} = 1;
649 my $packinfofile = $onemodule->{'PackageInfo'};
651 # The file with package information has to be found in path list
652 my $fileref = installer
::scriptitems
::get_sourcepath_from_filename_and_includepath
(\
$packinfofile, "" , 0);
654 if ( $$fileref eq "" ) { installer
::exiter
::exit_program
("ERROR: Could not find file $packinfofile for module $modulegid!", "collectpackages"); }
656 my $infoline = "$modulegid: Using packinfo: \"$$fileref\"!\n";
657 push( @installer::globals
::logfileinfo
, $infoline);
659 get_packinfo
($modulegid, $$fileref, \
@packages, $onelanguage, $islanguagemodule);
666 #####################################################################
667 # Printing packages content for debugging purposes
668 #####################################################################
670 sub log_packages_content
674 if ( ! ( $#{$packages} > -1 )) { installer::exiter::exit_program("ERROR: No packages defined!", "print_content"); }
676 installer
::logger
::include_header_into_logfile
("Logging packages content:");
680 for ( my $i = 0; $i <= $#{$packages}; $i++ )
682 my $onepackage = ${$packages}[$i];
684 # checking all items that must be defined
686 $infoline = "Package $onepackage->{'module'}\n";
687 push(@installer::globals
::logfileinfo
, $infoline);
690 foreach $key (sort keys %{$onepackage})
692 if ( $key =~ /^\s*\;/ ) { next; }
694 if ( $key eq "allmodules" )
696 $infoline = "\t$key:\n";
697 push(@installer::globals
::logfileinfo
, $infoline);
699 foreach $onemodule ( @
{$onepackage->{$key}} )
701 $infoline = "\t\t$onemodule\n";
702 push(@installer::globals
::logfileinfo
, $infoline);
707 $infoline = "\t$key: $onepackage->{$key}\n";
708 push(@installer::globals
::logfileinfo
, $infoline);
713 push(@installer::globals
::logfileinfo
, $infoline);
718 #####################################################################
719 # Creating assignments from modules to destination paths.
720 # This is required for logging in fileinfo file. Otherwise
721 # the complete destination file would not be known in file list.
722 # Saved in %installer::globals::moduledestination
723 #####################################################################
725 sub create_module_destination_hash
727 my ($packages, $allvariables) = @_;
729 for ( my $i = 0; $i <= $#{$packages}; $i++ )
731 my $onepackage = ${$packages}[$i];
733 my $defaultdestination = $onepackage->{'destpath'};
734 resolve_packagevariables
(\
$defaultdestination, $allvariables, 1);
735 if ( $^O
=~ /darwin/i ) { $defaultdestination =~ s/\/opt\//\/Applications\
//; }
737 foreach my $onemodule ( @
{$onepackage->{'allmodules'}} )
739 $installer::globals
::moduledestination
{$onemodule} = $defaultdestination;
744 #####################################################################
745 # Adding the default paths into the files collector for Unixes.
746 # This is necessary to know the complete destination path in
748 #####################################################################
750 sub add_defaultpaths_into_filescollector
754 for ( my $i = 0; $i <= $#{$allfiles}; $i++ )
756 my $onefile = ${$allfiles}[$i];
758 if ( ! $onefile->{'destination'} ) { installer
::exiter
::exit_program
("ERROR: No destination found at file $onefile->{'gid'}!", "add_defaultpaths_into_filescollector"); }
759 my $destination = $onefile->{'destination'};
761 if ( ! $onefile->{'modules'} ) { installer
::exiter
::exit_program
("ERROR: No modules found at file $onefile->{'gid'}!", "add_defaultpaths_into_filescollector"); }
762 my $module = $onefile->{'modules'};
763 # If modules contains a list of modules, only taking the first one.
764 if ( $module =~ /^\s*(.*?)\,/ ) { $module = $1; }
766 if ( ! exists($installer::globals
::moduledestination
{$module}) ) { installer
::exiter
::exit_program
("ERROR: No default destination path found for module $module!", "add_defaultpaths_into_filescollector"); }
767 my $defaultpath = $installer::globals
::moduledestination
{$module};
768 $defaultpath =~ s/\/\s*$//; # removing ending slashes
769 my $fulldestpath = $defaultpath . $installer::globals
::separator
. $destination;
771 $onefile->{'fulldestpath'} = $fulldestpath;
775 #####################################################################
776 # Creating list of cabinet files from packages
777 #####################################################################
779 sub prepare_cabinet_files
781 my ($packages, $allvariables) = @_;
783 if ( ! ( $#{$packages} > -1 )) { installer::exiter::exit_program("ERROR: No packages defined!", "print_content"); }
785 installer
::logger
::include_header_into_logfile
("Preparing cabinet files:");
789 for ( my $i = 0; $i <= $#{$packages}; $i++ )
791 my $onepackage = ${$packages}[$i];
793 my $cabinetfile = "$onepackage->{'packagename'}\.cab";
795 resolve_packagevariables
(\
$cabinetfile, $allvariables, 0);
797 $installer::globals
::allcabinets
{$cabinetfile} = 1;
799 # checking all items that must be defined
801 $infoline = "Package $onepackage->{'module'}\n";
802 push(@installer::globals
::logfileinfo
, $infoline);
804 # Assigning the cab file to the module and also to all corresponding sub modules
807 foreach $onemodule ( @
{$onepackage->{'allmodules'}} )
809 if ( ! exists($installer::globals
::allcabinetassigns
{$onemodule}) )
811 $installer::globals
::allcabinetassigns
{$onemodule} = $cabinetfile;
815 my $infoline = "Warning: Already existing assignment: $onemodule : $installer::globals::allcabinetassigns{$onemodule}\n";
816 push(@installer::globals
::logfileinfo
, $infoline);
817 $infoline = "Ignoring further assignment: $onemodule : $cabinetfile\n";
818 push(@installer::globals
::logfileinfo
, $infoline);
824 #####################################################################
825 # Logging assignments of cabinet files
826 #####################################################################
828 sub log_cabinet_assignments
830 installer
::logger
::include_header_into_logfile
("Logging cabinet files:");
832 my $infoline = "List of cabinet files:\n";
833 push(@installer::globals
::logfileinfo
, $infoline);
836 foreach $key ( sort keys %installer::globals
::allcabinets
) { push(@installer::globals
::logfileinfo
, "\t$key\n"); }
838 $infoline = "\nList of assignments from modules to cabinet files:\n";
839 push(@installer::globals
::logfileinfo
, $infoline);
841 foreach $key ( sort keys %installer::globals
::allcabinetassigns
) { push(@installer::globals
::logfileinfo
, "\t$key : $installer::globals::allcabinetassigns{$key}\n"); }