Msi.pm (60b96b8d) | Msi.pm (677600b0) |
---|---|
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 --- 62 unchanged lines hidden (view full) --- 71 72 Create a new object of the Msi class. The values of $version, $language, and $product_name define 73 where to look for the msi file. 74 75 If construction fails then IsValid() will return false. 76 77=cut 78 | 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 --- 62 unchanged lines hidden (view full) --- 71 72 Create a new object of the Msi class. The values of $version, $language, and $product_name define 73 where to look for the msi file. 74 75 If construction fails then IsValid() will return false. 76 77=cut 78 |
79sub new ($$$$$$) | 79sub new ($$;$$$$) |
80{ 81 my ($class, $filename, $version, $is_current_version, $language, $product_name) = @_; 82 83 if ( ! -f $filename) 84 { 85 installer::logger::PrintError("can not find the .msi file for version %s and language %s at '%s'\n", 86 $version, 87 $language, --- 9 unchanged lines hidden (view full) --- 97 'language' => $language, 98 'package_format' => "msi", 99 'product_name' => $product_name, 100 'tmpdir' => File::Temp->newdir(CLEANUP => 1), 101 'is_valid' => -f $filename 102 }; 103 bless($self, $class); 104 | 80{ 81 my ($class, $filename, $version, $is_current_version, $language, $product_name) = @_; 82 83 if ( ! -f $filename) 84 { 85 installer::logger::PrintError("can not find the .msi file for version %s and language %s at '%s'\n", 86 $version, 87 $language, --- 9 unchanged lines hidden (view full) --- 97 'language' => $language, 98 'package_format' => "msi", 99 'product_name' => $product_name, 100 'tmpdir' => File::Temp->newdir(CLEANUP => 1), 101 'is_valid' => -f $filename 102 }; 103 bless($self, $class); 104 |
105 # Fill in some missing values from the 'Properties' table. 106 if ( ! (defined $version && defined $language && defined $product_name)) 107 { 108 my $property_table = $self->GetTable("Property"); 109 110 $self->{'version'} = $property_table->GetValue("Property", "DEFINEDVERSION", "Value") 111 unless defined $self->{'version'}; 112 $self->{'product_name'} = $property_table->GetValue("Property", "DEFINEDPRODUCT", "Value") 113 unless defined $self->{'product_name'}; 114 115 my $language = $property_table->GetValue("Property", "ProductLanguage", "Value"); 116 # TODO: Convert numerical language id to language name. 117 $self->{'language'} = $language 118 unless defined $self->{'language'}; 119 } 120 |
|
105 return $self; 106} 107 108 109 110 111sub IsValid ($) 112{ --- 63 unchanged lines hidden (view full) --- 176 # Extract table from database to text file on disk. 177 my $truncated_table_name = length($table_name)>8 ? substr($table_name,0,8) : $table_name; 178 my $command = join(" ", 179 "msidb.exe", 180 "-d", installer::patch::Tools::ToEscapedWindowsPath($self->{'filename'}), 181 "-f", installer::patch::Tools::ToEscapedWindowsPath($self->{'tmpdir'}), 182 "-e", $table_name); 183 my $result = qx($command); | 121 return $self; 122} 123 124 125 126 127sub IsValid ($) 128{ --- 63 unchanged lines hidden (view full) --- 192 # Extract table from database to text file on disk. 193 my $truncated_table_name = length($table_name)>8 ? substr($table_name,0,8) : $table_name; 194 my $command = join(" ", 195 "msidb.exe", 196 "-d", installer::patch::Tools::ToEscapedWindowsPath($self->{'filename'}), 197 "-f", installer::patch::Tools::ToEscapedWindowsPath($self->{'tmpdir'}), 198 "-e", $table_name); 199 my $result = qx($command); |
184 print $result; | |
185 } 186 187 # Read table into memory. 188 $table = new installer::patch::MsiTable($table_filename, $table_name); 189 $self->{'tables'}->{$table_name} = $table; 190 } 191 192 return $table; --- 125 unchanged lines hidden (view full) --- 318 else 319 { 320 my ($long,$short) = installer::patch::Msi::SplitLongShortName($name); 321 return ($long,$short,$long,$short); 322 } 323} 324 325 | 200 } 201 202 # Read table into memory. 203 $table = new installer::patch::MsiTable($table_filename, $table_name); 204 $self->{'tables'}->{$table_name} = $table; 205 } 206 207 return $table; --- 125 unchanged lines hidden (view full) --- 333 else 334 { 335 my ($long,$short) = installer::patch::Msi::SplitLongShortName($name); 336 return ($long,$short,$long,$short); 337 } 338} 339 340 |
341 342 343sub SetupFullNames ($$); 344sub SetupFullNames ($$) 345{ 346 my ($item, $directory_map) = @_; 347 348 # Don't process any item twice. 349 return if defined $item->{'full_source_name'}; 350 351 my $parent = $item->{'parent'}; 352 if (defined $parent) 353 { 354 # Process the parent first. 355 if ( ! defined $parent->{'full_source_long_name'}) 356 { 357 SetupFullNames($parent, $directory_map); 358 } 359 360 # Prepend the full names of the parent to our names. 361 $item->{'full_source_long_name'} 362 = $parent->{'full_source_long_name'} . "/" . $item->{'source_long_name'}; 363 $item->{'full_source_short_name'} 364 = $parent->{'full_source_short_name'} . "/" . $item->{'source_short_name'}; 365 $item->{'full_target_long_name'} 366 = $parent->{'full_target_long_name'} . "/" . $item->{'target_long_name'}; 367 $item->{'full_target_short_name'} 368 = $parent->{'full_target_short_name'} . "/" . $item->{'target_short_name'}; 369 } 370 else 371 { 372 # Directory has no parent => full names are the same as the name. 373 $item->{'full_source_long_name'} = $item->{'source_long_name'}; 374 $item->{'full_source_short_name'} = $item->{'source_short_name'}; 375 $item->{'full_target_long_name'} = $item->{'target_long_name'}; 376 $item->{'full_target_short_name'} = $item->{'target_short_name'}; 377 } 378} 379 380 381 382 |
|
326=head2 GetDirectoryMap($self) 327 328 Return a map that maps directory unique names (column 'Directory' in table 'Directory') 329 to hashes that contains short and long source and target names. 330 331=cut 332 333sub GetDirectoryMap ($) 334{ 335 my ($self) = @_; 336 337 if (defined $self->{'DirectoryMap'}) 338 { 339 return $self->{'DirectoryMap'}; 340 } 341 | 383=head2 GetDirectoryMap($self) 384 385 Return a map that maps directory unique names (column 'Directory' in table 'Directory') 386 to hashes that contains short and long source and target names. 387 388=cut 389 390sub GetDirectoryMap ($) 391{ 392 my ($self) = @_; 393 394 if (defined $self->{'DirectoryMap'}) 395 { 396 return $self->{'DirectoryMap'}; 397 } 398 |
399 # Initialize the directory map. |
|
342 my $directory_table = $self->GetTable("Directory"); | 400 my $directory_table = $self->GetTable("Directory"); |
343 my %dir_map = (); | 401 my $directory_map = (); |
344 foreach my $row (@{$directory_table->GetAllRows()}) 345 { 346 my ($target_long_name, $target_short_name, $source_long_name, $source_short_name) 347 = installer::patch::Msi::SplitTargetSourceLongShortName($row->GetValue("DefaultDir")); 348 my $unique_name = $row->GetValue("Directory"); | 402 foreach my $row (@{$directory_table->GetAllRows()}) 403 { 404 my ($target_long_name, $target_short_name, $source_long_name, $source_short_name) 405 = installer::patch::Msi::SplitTargetSourceLongShortName($row->GetValue("DefaultDir")); 406 my $unique_name = $row->GetValue("Directory"); |
349 $dir_map{$unique_name} = | 407 $directory_map->{$unique_name} = |
350 { 351 'unique_name' => $unique_name, | 408 { 409 'unique_name' => $unique_name, |
352 'parent' => $row->GetValue("Directory_Parent"), | 410 'parent_name' => $row->GetValue("Directory_Parent"), |
353 'default_dir' => $row->GetValue("DefaultDir"), 354 'source_long_name' => $source_long_name, 355 'source_short_name' => $source_short_name, 356 'target_long_name' => $target_long_name, 357 'target_short_name' => $target_short_name 358 }; 359 } 360 | 411 'default_dir' => $row->GetValue("DefaultDir"), 412 'source_long_name' => $source_long_name, 413 'source_short_name' => $source_short_name, 414 'target_long_name' => $target_long_name, 415 'target_short_name' => $target_short_name 416 }; 417 } 418 |
361 # Set up full names for all directories. 362 my @todo = map {$_} (keys %dir_map); 363 while (scalar @todo > 0) | 419 # Add references to parent directories. 420 foreach my $item (values %$directory_map) |
364 { | 421 { |
365 my $key = shift @todo; 366 my $item = $dir_map{$key}; 367 next if defined $item->{'full_source_name'}; | 422 $item->{'parent'} = $directory_map->{$item->{'parent_name'}}; 423 } |
368 | 424 |
369 if ($item->{'parent'} eq "") 370 { 371 # Directory has no parent => full names are the same as the name. 372 $item->{'full_source_long_name'} = $item->{'source_long_name'}; 373 $item->{'full_source_short_name'} = $item->{'source_short_name'}; 374 $item->{'full_target_long_name'} = $item->{'target_long_name'}; 375 $item->{'full_target_short_name'} = $item->{'target_short_name'}; 376 } 377 else 378 { 379 my $parent = $dir_map{$item->{'parent'}}; 380 if ( defined $parent->{'full_source_long_name'}) 381 { 382 # Parent aleady has full names => we can create the full name of the current item. 383 $item->{'full_source_long_name'} 384 = $parent->{'full_source_long_name'} . "/" . $item->{'source_long_name'}; 385 $item->{'full_source_short_name'} 386 = $parent->{'full_source_short_name'} . "/" . $item->{'source_short_name'}; 387 $item->{'full_target_long_name'} 388 = $parent->{'full_target_long_name'} . "/" . $item->{'target_long_name'}; 389 $item->{'full_target_short_name'} 390 = $parent->{'full_target_short_name'} . "/" . $item->{'target_short_name'}; 391 } 392 else 393 { 394 # Parent has to be processed before the current item can be processed. 395 # Push both to the head of the list. 396 unshift @todo, $key; 397 unshift @todo, $item->{'parent'}; 398 } 399 } | 425 # Set up full names for all directories. 426 foreach my $item (values %$directory_map) 427 { 428 SetupFullNames($item, $directory_map); |
400 } 401 | 429 } 430 |
402 # Postprocess the path names for cleanup. 403 foreach my $item (values %dir_map) | 431 # Cleanup the names. 432 foreach my $item (values %$directory_map) |
404 { 405 foreach my $id ( 406 'full_source_long_name', 407 'full_source_short_name', 408 'full_target_long_name', 409 'full_target_short_name') 410 { 411 $item->{$id} =~ s/\/(\.\/)+/\//g; 412 $item->{$id} =~ s/^SourceDir\///; 413 $item->{$id} =~ s/^\.$//; 414 } 415 } 416 | 433 { 434 foreach my $id ( 435 'full_source_long_name', 436 'full_source_short_name', 437 'full_target_long_name', 438 'full_target_short_name') 439 { 440 $item->{$id} =~ s/\/(\.\/)+/\//g; 441 $item->{$id} =~ s/^SourceDir\///; 442 $item->{$id} =~ s/^\.$//; 443 } 444 } 445 |
417 $self->{'DirectoryMap'} = \%dir_map; | 446 $self->{'DirectoryMap'} = $directory_map; |
418 return $self->{'DirectoryMap'}; 419} 420 421 422 423 424=head2 GetFileMap ($) 425 --- 24 unchanged lines hidden (view full) --- 450 map 451 {$_->GetValue('Component') => $_->GetValue('Directory_')} 452 @{$component_table->GetAllRows()}; 453 454 # Finally, create the map from files to directories. 455 my $file_map = {}; 456 my $file_component_index = $file_table->GetColumnIndex("Component_"); 457 my $file_file_index = $file_table->GetColumnIndex("File"); | 447 return $self->{'DirectoryMap'}; 448} 449 450 451 452 453=head2 GetFileMap ($) 454 --- 24 unchanged lines hidden (view full) --- 479 map 480 {$_->GetValue('Component') => $_->GetValue('Directory_')} 481 @{$component_table->GetAllRows()}; 482 483 # Finally, create the map from files to directories. 484 my $file_map = {}; 485 my $file_component_index = $file_table->GetColumnIndex("Component_"); 486 my $file_file_index = $file_table->GetColumnIndex("File"); |
487 my $file_filename_index = $file_table->GetColumnIndex("FileName"); |
|
458 foreach my $file_row (@{$file_table->GetAllRows()}) 459 { 460 my $component_name = $file_row->GetValue($file_component_index); 461 my $directory_name = $component_to_directory_map{$component_name}; 462 my $unique_name = $file_row->GetValue($file_file_index); | 488 foreach my $file_row (@{$file_table->GetAllRows()}) 489 { 490 my $component_name = $file_row->GetValue($file_component_index); 491 my $directory_name = $component_to_directory_map{$component_name}; 492 my $unique_name = $file_row->GetValue($file_file_index); |
493 my $file_name = $file_row->GetValue($file_filename_index); 494 my ($long_name, $short_name) = SplitLongShortName($file_name); |
|
463 $file_map->{$unique_name} = { 464 'directory' => $dir_map->{$directory_name}, | 495 $file_map->{$unique_name} = { 496 'directory' => $dir_map->{$directory_name}, |
465 'component_name' => $component_name | 497 'component_name' => $component_name, 498 'file_name' => $file_name, 499 'long_name' => $long_name, 500 'short_name' => $short_name |
466 }; 467 } 468 469 $self->{'FileMap'} = $file_map; 470 return $file_map; 471} 472 473 4741; | 501 }; 502 } 503 504 $self->{'FileMap'} = $file_map; 505 return $file_map; 506} 507 508 5091; |