cid#1607171 Data race condition
[LibreOffice.git] / solenv / bin / modules / installer / windows / feature.pm
blob6dff3dead168f3dabec515a96ac5e64748d7f606
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::windows::feature;
21 use strict;
22 use warnings;
24 use installer::exiter;
25 use installer::files;
26 use installer::globals;
27 use installer::worker;
28 use installer::windows::idtglobal;
29 use installer::windows::language;
31 ##############################################################
32 # Returning the gid for a feature.
33 # Attention: Maximum length
34 ##############################################################
36 sub get_feature_gid
38 my ($onefeature) = @_;
40 my $gid = "";
42 if ( $onefeature->{'gid'} ) { $gid = $onefeature->{'gid'}; }
44 # Attention: Maximum feature length is 38!
45 installer::windows::idtglobal::shorten_feature_gid(\$gid);
47 return $gid
50 ##############################################################
51 # Returning the gid of the parent.
52 # Attention: Maximum length
53 ##############################################################
55 sub get_feature_parent
57 my ($onefeature) = @_;
59 my $parentgid = "";
61 if ( $onefeature->{'ParentID'} ) { $parentgid = $onefeature->{'ParentID'}; }
63 # The modules, hanging directly below the root, have to be root modules.
64 # Only then it is possible to make the "real" root module invisible by
65 # setting the display to "0".
67 if ( $parentgid eq $installer::globals::rootmodulegid ) { $parentgid = ""; }
69 # Attention: Maximum feature length is 38!
70 installer::windows::idtglobal::shorten_feature_gid(\$parentgid);
72 return $parentgid
75 ##############################################################
76 # Returning the display for a feature.
77 # 0: Feature is not shown
78 # odd: subfeatures are shown
79 # even: subfeatures are not shown
80 ##############################################################
82 sub get_feature_display
84 my ($onefeature) = @_;
86 my $display;
87 my $parentid = "";
89 if ( $onefeature->{'ParentID'} ) { $parentid = $onefeature->{'ParentID'}; }
91 if ( $parentid eq "" )
93 $display = "0"; # root module is not visible
95 elsif ( $onefeature->{'gid'} eq "gid_Module_Prg") # program module shows subfeatures
97 $display = "1"; # root module shows subfeatures
99 else
101 $display = "2"; # all other modules do not show subfeatures
104 # special case: Feature has flag "HIDDEN_ROOT" -> $display is 0
105 my $styles = "";
106 if ( $onefeature->{'Styles'} ) { $styles = $onefeature->{'Styles'}; }
107 if ( $styles =~ /\bHIDDEN_ROOT\b/ ) { $display = "0"; }
109 # Special handling for language modules. Only visible in multilingual installation set
110 if (( $styles =~ /\bSHOW_MULTILINGUAL_ONLY\b/ ) && ( ! $installer::globals::ismultilingual )) { $display = "0"; }
112 # No program module visible.
113 if ( $onefeature->{'gid'} eq "gid_Module_Prg" ) { $display = "0"; }
115 # making all feature invisible in Language packs and in Help packs!
116 if ( $installer::globals::languagepack || $installer::globals::helppack ) { $display = "0"; }
118 return $display
121 ##############################################################
122 # Returning the level for a feature.
123 ##############################################################
125 sub get_feature_level
127 my ($onefeature) = @_;
129 my $level = "20"; # the default
131 if ( $onefeature->{'Disabled'} )
133 if ( $onefeature->{'Disabled'} eq "YES" ) # Disabled = "YES"
135 $level = "0"; # disabled for installation at any INSTALLLEVEL
138 elsif ( $onefeature->{'Default'} )
140 if ( $onefeature->{'Default'} eq "NO" ) # explicitly set Default = "NO"
142 $level = "200"; # deselected in default installation, base is 100
146 return $level
149 ##############################################################
150 # Returning the directory for a feature.
151 ##############################################################
153 sub get_feature_directory
155 my ($onefeature) = @_;
157 my $directory;
159 $directory = "INSTALLLOCATION";
161 return $directory
164 ##############################################################
165 # Returning the directory for a feature.
166 ##############################################################
168 sub get_feature_attributes
170 my ($onefeature) = @_;
172 my $attributes;
174 # 2 = msidbFeatureAttributesFollowParent
175 # 8 = msidbFeatureAttributesDisallowAdvertise
176 # 16 = msidbFeatureAttributesUIDisallowAbsent
178 # No advertising of features and no leaving on network.
179 # Feature without parent must not have the "2"
181 my $parentgid = "";
182 if ( $onefeature->{'ParentID'} ) { $parentgid = $onefeature->{'ParentID'}; }
184 if (( $parentgid eq "" ) || ( $parentgid eq $installer::globals::rootmodulegid )) { $attributes = "8"; }
185 elsif ( $onefeature->{'Independent'} && ($onefeature->{'Independent'} eq "YES") ) { $attributes = "8"; }
186 elsif ( get_feature_display($onefeature) eq "0" ) { $attributes = "26"; } # fdo#33798
187 else { $attributes = "10"; }
189 return $attributes
192 #################################################################################
193 # Collecting the feature recursively.
194 #################################################################################
196 sub collect_modules_recursive
198 my ($modulesref, $parentid, $feature, $directaccess, $directgid, $directparent, $directsortkey, $sorted) = @_;
200 my @allchildren = ();
201 my $childrenexist = 0;
203 # Collecting children from Module $parentid
205 my $modulegid;
206 foreach $modulegid ( keys %{$directparent})
208 if ( $directparent->{$modulegid} eq $parentid )
210 push @allchildren, [ $directsortkey->{$modulegid}, $modulegid ];
211 $childrenexist = 1;
215 # Sorting children
217 if ( $childrenexist )
219 # Sort children
220 @allchildren = map { $_->[1] }
221 sort { $a->[0] <=> $b->[0] }
222 @allchildren;
224 # Adding children to new array
225 foreach my $gid ( @allchildren )
227 # Saving all lines, that have this 'gid'
229 my $unique;
230 foreach $unique ( keys %{$directgid} )
232 if ( $directgid->{$unique} eq $gid )
234 push(@{$feature}, ${$modulesref}[$directaccess->{$unique}]);
235 if ( $sorted->{$unique} == 1 ) { installer::exiter::exit_program("ERROR: Sorting feature failed! \"$unique\" already sorted.", "sort_feature"); }
236 $sorted->{$unique} = 1;
240 collect_modules_recursive($modulesref, $gid, $feature, $directaccess, $directgid, $directparent, $directsortkey, $sorted);
245 #################################################################################
246 # Sorting the feature in specified order. Evaluated is the key "Sortkey", that
247 # is set in scp2 projects.
248 # The display order of modules in Windows Installer is dependent from the order
249 # in the idt file. Therefore the order of the modules array has to be adapted
250 # to the Sortkey order, before the idt file is created.
251 #################################################################################
253 sub sort_feature
255 my ($modulesref) = @_;
257 my @feature = ();
259 my %directaccess = ();
260 my %directparent = ();
261 my %directgid = ();
262 my %directsortkey = ();
263 my %sorted = ();
265 for ( my $i = 0; $i <= $#{$modulesref}; $i++ )
267 my $onefeature = ${$modulesref}[$i];
269 my $uniquekey = $onefeature->{'uniquekey'};
270 my $modulegid = $onefeature->{'gid'};
272 $directaccess{$uniquekey} = $i;
274 $directgid{$uniquekey} = $onefeature->{'gid'};
276 # ParentID and Sortkey are not saved for the 'uniquekey', but only for the 'gid'
278 if ( $onefeature->{'ParentID'} ) { $directparent{$modulegid} = $onefeature->{'ParentID'}; }
279 else { $directparent{$modulegid} = ""; }
281 if ( $onefeature->{'Sortkey'} ) { $directsortkey{$modulegid} = $onefeature->{'Sortkey'}; }
282 else { $directsortkey{$modulegid} = "9999"; }
284 # Bookkeeping:
285 $sorted{$uniquekey} = 0;
288 # Searching all feature recursively, beginning with ParentID = ""
289 my $parentid = "";
290 collect_modules_recursive($modulesref, $parentid, \@feature, \%directaccess, \%directgid, \%directparent, \%directsortkey, \%sorted);
292 # Bookkeeping
293 my $modulekey;
294 foreach $modulekey ( keys %sorted )
296 if ( $sorted{$modulekey} == 0 )
298 my $infoline = "Warning: Module \"$modulekey\" could not be sorted. Added to the end of the module array.\n";
299 push(@installer::globals::logfileinfo, $infoline);
300 push(@feature, ${$modulesref}[$directaccess{$modulekey}]);
304 return \@feature;
307 #################################################################################
308 # Adding a unique key to the modules array. The gid is not unique for
309 # multilingual modules. Only the combination from gid and specific language
310 # is unique. Uniqueness is required for sorting mechanism.
311 #################################################################################
313 sub add_uniquekey
315 my ( $modulesref ) = @_;
317 for ( my $i = 0; $i <= $#{$modulesref}; $i++ )
319 my $uniquekey = ${$modulesref}[$i]->{'gid'};
320 if ( ${$modulesref}[$i]->{'specificlanguage'} ) { $uniquekey = $uniquekey . "_" . ${$modulesref}[$i]->{'specificlanguage'}; }
321 ${$modulesref}[$i]->{'uniquekey'} = $uniquekey;
325 #################################################################################
326 # Creating the file Feature.idt dynamically
327 # Content:
328 # Feature Feature_Parent Title Description Display Level Directory_ Attributes
329 #################################################################################
331 sub create_feature_table
333 my ($modulesref, $basedir, $languagesarrayref, $allvariableshashref) = @_;
335 for ( my $m = 0; $m <= $#{$languagesarrayref}; $m++ )
337 my $onelanguage = ${$languagesarrayref}[$m];
339 my $infoline;
341 my @featuretable = ();
343 installer::windows::idtglobal::write_idt_header(\@featuretable, "feature");
345 for ( my $i = 0; $i <= $#{$modulesref}; $i++ )
347 my $onefeature = ${$modulesref}[$i];
349 # Java and Ada only, if the correct settings are set
350 my $styles = "";
351 if ( $onefeature->{'Styles'} ) { $styles = $onefeature->{'Styles'}; }
353 # Controlling the language!
354 # Only language independent feature or feature with the correct language will be included into the table
355 # But help packs are different. They have en-US added as setup language.
357 if (! (!(( $onefeature->{'ismultilingual'} )) || ( $onefeature->{'specificlanguage'} eq $onelanguage ) || $installer::globals::helppack ) ) { next; }
359 my %feature = ();
361 $feature{'feature'} = get_feature_gid($onefeature);
362 $feature{'feature_parent'} = get_feature_parent($onefeature);
363 $feature{'Title'} = $onefeature->{'Name'} // "";
364 $feature{'Description'} = $onefeature->{'Description'} // "";
365 $feature{'Description'} =~ s/\\\"/\"/g; # no more masquerading of '"'
366 $feature{'Display'} = get_feature_display($onefeature);
367 $feature{'Level'} = get_feature_level($onefeature);
368 $feature{'Directory_'} = get_feature_directory($onefeature);
369 $feature{'Attributes'} = get_feature_attributes($onefeature);
371 my $oneline = $feature{'feature'} . "\t" . $feature{'feature_parent'} . "\t" . $feature{'Title'} . "\t"
372 . $feature{'Description'} . "\t" . $feature{'Display'} . "\t" . $feature{'Level'} . "\t"
373 . $feature{'Directory_'} . "\t" . $feature{'Attributes'} . "\n";
375 push(@featuretable, $oneline);
377 # collecting all feature in global feature collector (so that properties can be set in property table)
378 if ( ! grep {$_ eq $feature{'feature'}} @installer::globals::featurecollector )
380 push(@installer::globals::featurecollector, $feature{'feature'});
383 # collecting all language feature in feature collector for check of language selection
384 if (( $styles =~ /\bSHOW_MULTILINGUAL_ONLY\b/ ) && ( $onefeature->{'ParentID'} ne $installer::globals::rootmodulegid ))
386 $installer::globals::multilingual_only_modules{$feature{'feature'}} = 1;
389 # collecting all application feature in global feature collector for check of application selection
390 if ( $styles =~ /\bAPPLICATIONMODULE\b/ )
392 $installer::globals::application_modules{$feature{'feature'}} = 1;
396 # Saving the file
398 my $featuretablename = $basedir . $installer::globals::separator . "Feature.idt" . "." . $onelanguage;
399 installer::files::save_file($featuretablename ,\@featuretable);
400 $infoline = "Created idt file: $featuretablename\n";
401 push(@installer::globals::logfileinfo, $infoline);