patch_tool.pl (d575d58f) | patch_tool.pl (677600b0) |
---|---|
1#!/usr/bin/perl -w 2 3#************************************************************** 4# 5# Licensed to the Apache Software Foundation (ASF) under one 6# or more contributor license agreements. See the NOTICE file 7# distributed with this work for additional information 8# regarding copyright ownership. The ASF licenses this file --- 24 unchanged lines hidden (view full) --- 33 34use installer::ziplist; 35use installer::logger; 36use installer::windows::msiglobal; 37use installer::patch::Msi; 38use installer::patch::ReleasesList; 39use installer::patch::Version; 40 | 1#!/usr/bin/perl -w 2 3#************************************************************** 4# 5# Licensed to the Apache Software Foundation (ASF) under one 6# or more contributor license agreements. See the NOTICE file 7# distributed with this work for additional information 8# regarding copyright ownership. The ASF licenses this file --- 24 unchanged lines hidden (view full) --- 33 34use installer::ziplist; 35use installer::logger; 36use installer::windows::msiglobal; 37use installer::patch::Msi; 38use installer::patch::ReleasesList; 39use installer::patch::Version; 40 |
41#use Carp::Always; 42 |
|
41use strict; 42 43 44=head1 NAME 45 46 patch_tool.pl - Create Windows MSI patches. 47 48=head1 SYNOPSIS --- 10 unchanged lines hidden (view full) --- 59 -o|--output-path <path> 60 Path to the instsetoo_native platform output tree 61 -d|--data-path <path> 62 Path to the data directory that is expected to be under version control. 63 --source-version <major>.<minor>.<micro> 64 The version that is to be patched. 65 --target-version <major>.<minor>.<micro> 66 The version after the patch has been applied. | 43use strict; 44 45 46=head1 NAME 47 48 patch_tool.pl - Create Windows MSI patches. 49 50=head1 SYNOPSIS --- 10 unchanged lines hidden (view full) --- 61 -o|--output-path <path> 62 Path to the instsetoo_native platform output tree 63 -d|--data-path <path> 64 Path to the data directory that is expected to be under version control. 65 --source-version <major>.<minor>.<micro> 66 The version that is to be patched. 67 --target-version <major>.<minor>.<micro> 68 The version after the patch has been applied. |
69 --language <language-code> 70 Language of the installation sets. 71 --package-format 72 Only the package format 'msi' is supported at the moment. |
|
67 68=head1 DESCRIPTION 69 70 Creates windows MSP patch files, one for each relevant language. 71 Patches convert an installed OpenOffice to the target version. 72 73 Required data are: 74 Installation sets of the source versions 75 Taken from ext_sources/ 76 Downloaded from archive.apache.org on demand 77 78 Installation set of the target version 79 This is expected to be the current version. 80 81=cut 82 | 73 74=head1 DESCRIPTION 75 76 Creates windows MSP patch files, one for each relevant language. 77 Patches convert an installed OpenOffice to the target version. 78 79 Required data are: 80 Installation sets of the source versions 81 Taken from ext_sources/ 82 Downloaded from archive.apache.org on demand 83 84 Installation set of the target version 85 This is expected to be the current version. 86 87=cut 88 |
83# my $ImageFamily = "MNPapps"; | |
84# The ImageFamily name has to have 1-8 alphanumeric characters. 85my $ImageFamily = "AOO"; 86my $SourceImageName = "Source"; 87my $TargetImageName = "Target"; 88 89 90 91sub ProcessCommandline () 92{ | 89# The ImageFamily name has to have 1-8 alphanumeric characters. 90my $ImageFamily = "AOO"; 91my $SourceImageName = "Source"; 92my $TargetImageName = "Target"; 93 94 95 96sub ProcessCommandline () 97{ |
93 my $arguments = { | 98 my $context = { |
94 'product-name' => undef, 95 'output-path' => undef, 96 'data-path' => undef, 97 'lst-file' => undef, 98 'source-version' => undef, | 99 'product-name' => undef, 100 'output-path' => undef, 101 'data-path' => undef, 102 'lst-file' => undef, 103 'source-version' => undef, |
99 'target-version' => undef}; | 104 'target-version' => undef, 105 'language' => undef, 106 'package-format' => undef 107 }; |
100 101 if ( ! GetOptions( | 108 109 if ( ! GetOptions( |
102 "product-name=s", \$arguments->{'product-name'}, 103 "output-path=s", \$arguments->{'output-path'}, 104 "data-path=s" => \$arguments->{'data-path'}, 105 "lst-file=s" => \$arguments->{'lst-file'}, 106 "source-version:s" => \$arguments->{'source-version'}, 107 "target-version:s" => \$arguments->{'target-version'} | 110 "product-name=s", \$context->{'product-name'}, 111 "output-path=s", \$context->{'output-path'}, 112 "data-path=s" => \$context->{'data-path'}, 113 "lst-file=s" => \$context->{'lst-file'}, 114 "source-version:s" => \$context->{'source-version'}, 115 "target-version:s" => \$context->{'target-version'}, 116 "language=s" => \$context->{'language'}, 117 "package-format=s" => \$context->{'package-format'} |
108 )) 109 { 110 pod2usage(2); 111 } 112 113 # Only the command should be left in @ARGV. 114 pod2usage(2) unless scalar @ARGV == 1; | 118 )) 119 { 120 pod2usage(2); 121 } 122 123 # Only the command should be left in @ARGV. 124 pod2usage(2) unless scalar @ARGV == 1; |
115 $arguments->{'command'} = shift @ARGV; 116 117 # At the moment we only support patches on windows. When this 118 # is extended in the future we need the package format as an 119 # argument. 120 $arguments->{'package-format'} = "msi"; | 125 $context->{'command'} = shift @ARGV; |
121 | 126 |
122 return $arguments; | 127 return $context; |
123} 124 125 126 127 128sub GetSourceMsiPath ($$) 129{ 130 my ($context, $language) = @_; --- 45 unchanged lines hidden (view full) --- 176 } 177 178 return 1; 179} 180 181 182 183 | 128} 129 130 131 132 133sub GetSourceMsiPath ($$) 134{ 135 my ($context, $language) = @_; --- 45 unchanged lines hidden (view full) --- 181 } 182 183 return 1; 184} 185 186 187 188 |
184sub GetLanguages () | 189sub IsLanguageValid ($$$) |
185{ | 190{ |
186 # The set of languages is taken from the WITH_LANG environment variable. 187 # If that is missing or is empty then the default 'en-US' is used instead. 188 my @languages = ("en-US"); 189 my $with_lang = $ENV{'WITH_LANG'}; 190 if (defined $with_lang && $with_lang ne "") 191 { 192 @languages = split(/\s+/, $with_lang); 193 } 194 return @languages; 195} | 191 my ($context, $release_data, $language) = @_; |
196 | 192 |
193 my $normalized_language = installer::languages::get_normalized_language($language); |
|
197 | 194 |
198 199 200sub FindValidLanguages ($$$) 201{ 202 my ($context, $release_data, $languages) = @_; 203 204 my @valid_languages = (); 205 foreach my $language (@$languages) | 195 if ( ! ProvideInstallationSets($context, $language)) |
206 { | 196 { |
207 if ( ! ProvideInstallationSets($context, $language)) 208 { 209 installer::logger::PrintError(" '%s' has no target installation set\n", $language); 210 } 211 elsif ( ! defined $release_data->{$language}) 212 { 213 installer::logger::PrintError(" '%s' is not a released language for version %s\n", 214 $language, 215 $context->{'source-version'}); 216 } 217 else 218 { 219 push @valid_languages, $language; 220 } | 197 installer::logger::PrintError(" '%s' has no target installation set\n", $language); 198 return 0; |
221 } | 199 } |
222 223 return @valid_languages; | 200 elsif ( ! defined $release_data->{$normalized_language}) 201 { 202 installer::logger::PrintError(" '%s' is not a released language for version %s\n", 203 $language, 204 $context->{'source-version'}); 205 return 0; 206 } 207 else 208 { 209 return 1; 210 } |
224} 225 226 227 228 229sub ProvideSourceInstallationSet ($$$) 230{ 231 my ($context, $language, $release_data) = @_; --- 90 unchanged lines hidden (view full) --- 322 my $last_release = undef; 323 foreach my $release (@{$releases->{'releases'}}) 324 { 325 last if ($release eq $context->{'target-version'}); 326 $last_release = $release; 327 } 328 $context->{'source-version'} = $last_release; 329 } | 211} 212 213 214 215 216sub ProvideSourceInstallationSet ($$$) 217{ 218 my ($context, $language, $release_data) = @_; --- 90 unchanged lines hidden (view full) --- 309 my $last_release = undef; 310 foreach my $release (@{$releases->{'releases'}}) 311 { 312 last if ($release eq $context->{'target-version'}); 313 $last_release = $release; 314 } 315 $context->{'source-version'} = $last_release; 316 } |
317 318 if (defined $context->{'source-version'}) 319 { 320 $context->{'source-version-dash'} = installer::patch::Version::ArrayToDirectoryName( 321 installer::patch::Version::StringToNumberArray( 322 $context->{'source-version'})); 323 } 324 if (defined $context->{'target-version'}) 325 { 326 $context->{'target-version-dash'} = installer::patch::Version::ArrayToDirectoryName( 327 installer::patch::Version::StringToNumberArray( 328 $context->{'target-version'})); 329 } |
|
330} 331 332 333 334 335=head2 CheckUpgradeCode($source_msi, $target_msi) 336 337 The 'UpgradeCode' values in the 'Property' table differs from source to target --- 9 unchanged lines hidden (view full) --- 347 if ($source_upgrade_code eq $target_upgrade_code) 348 { 349 $installer::logger::Info->printf("Error: The UpgradeCode properties have to differ but are both '%s'\n", 350 $source_upgrade_code); 351 return 0; 352 } 353 else 354 { | 330} 331 332 333 334 335=head2 CheckUpgradeCode($source_msi, $target_msi) 336 337 The 'UpgradeCode' values in the 'Property' table differs from source to target --- 9 unchanged lines hidden (view full) --- 347 if ($source_upgrade_code eq $target_upgrade_code) 348 { 349 $installer::logger::Info->printf("Error: The UpgradeCode properties have to differ but are both '%s'\n", 350 $source_upgrade_code); 351 return 0; 352 } 353 else 354 { |
355 $installer::logger::Info->printf("OK: UpgradeCode values are identical\n"); | 355 $installer::logger::Info->printf("OK: UpgradeCode values are different\n"); |
356 return 1; 357 } 358} 359 360 361 362 363=head2 CheckProductCode($source_msi, $target_msi) --- 13 unchanged lines hidden (view full) --- 377 $installer::logger::Info->printf("Error: The ProductCode properties have to remain the same but are\n"); 378 $installer::logger::Info->printf(" '%s' and '%s'\n", 379 $source_product_code, 380 $target_product_code); 381 return 0; 382 } 383 else 384 { | 356 return 1; 357 } 358} 359 360 361 362 363=head2 CheckProductCode($source_msi, $target_msi) --- 13 unchanged lines hidden (view full) --- 377 $installer::logger::Info->printf("Error: The ProductCode properties have to remain the same but are\n"); 378 $installer::logger::Info->printf(" '%s' and '%s'\n", 379 $source_product_code, 380 $target_product_code); 381 return 0; 382 } 383 else 384 { |
385 $installer::logger::Info->printf("OK: ProductCode properties differ\n"); | 385 $installer::logger::Info->printf("OK: ProductCodes are identical\n"); |
386 return 1; 387 } 388} 389 390 391 392 393=head2 CheckBuildIdCode($source_msi, $target_msi) --- 102 unchanged lines hidden (view full) --- 496 my ($source_msi, $target_msi) = @_; 497 498 # Get the 'File' tables. 499 my $source_file_table = $source_msi->GetTable("File"); 500 my $target_file_table = $target_msi->GetTable("File"); 501 502 # Create data structures for fast lookup. 503 my %source_file_map = map {$_->GetValue("File") => $_} @{$source_file_table->GetAllRows()}; | 386 return 1; 387 } 388} 389 390 391 392 393=head2 CheckBuildIdCode($source_msi, $target_msi) --- 102 unchanged lines hidden (view full) --- 496 my ($source_msi, $target_msi) = @_; 497 498 # Get the 'File' tables. 499 my $source_file_table = $source_msi->GetTable("File"); 500 my $target_file_table = $target_msi->GetTable("File"); 501 502 # Create data structures for fast lookup. 503 my %source_file_map = map {$_->GetValue("File") => $_} @{$source_file_table->GetAllRows()}; |
504 my @target_files = map {$_->GetValue("File")} @{$target_file_table->GetAllRows()}; | 504 my %target_files_map = map {$_->GetValue("File") => $_} @{$target_file_table->GetAllRows()}; |
505 506 # Search for added files (files in target that where not in source). | 505 506 # Search for added files (files in target that where not in source). |
507 my $added_file_count = 0; 508 foreach my $uniquename (@target_files) | 507 my @added_files = (); 508 foreach my $uniquename (keys %target_files_map) |
509 { 510 if ( ! defined $source_file_map{$uniquename}) 511 { | 509 { 510 if ( ! defined $source_file_map{$uniquename}) 511 { |
512 ++$added_file_count; | 512 push @added_files, $target_files_map{$uniquename}; |
513 } 514 } 515 | 513 } 514 } 515 |
516 if ($added_file_count > 0) | 516 if (scalar @added_files > 0) |
517 { | 517 { |
518 $installer::logger::Info->printf("Warning: %d files have been added\n", $added_file_count); | 518 $installer::logger::Info->printf("Warning: %d files have been added\n", scalar @added_files); |
519 | 519 |
520 $installer::logger::Info->printf("Check for new files being part of new components is not yet implemented\n"); 521 522 return 1; | 520 # Prepare component tables and hashes. 521 my $source_component_table = $source_msi->GetTable("Component"); 522 my $target_component_table = $target_msi->GetTable("Component"); 523 die unless defined $source_component_table && defined $target_component_table; 524 my %source_component_map = map {$_->GetValue('Component') => $_} @{$source_component_table->GetAllRows()}; 525 my %target_component_map = map {$_->GetValue('Component') => $_} @{$target_component_table->GetAllRows()}; 526 527 my @new_files_with_existing_components = (); 528 foreach my $target_file_row (@added_files) 529 { 530 $installer::logger::Info->printf(" %s (%s)\n", 531 $target_file_row->GetValue("FileName"), 532 $target_file_row->GetValue("File")); 533 534 # Get target component for target file. 535 my $target_component = $target_file_row->GetValue('Component_'); 536 537 # Check that the component is not part of the source components. 538 if (defined $source_component_map{$target_component}) 539 { 540 push @new_files_with_existing_components, $target_file_row; 541 } 542 } 543 544 if (scalar @new_files_with_existing_components > 0) 545 { 546 $installer::logger::Info->printf( 547 "Error: %d new files have existing components (which must also be new)\n", 548 scalar @new_files_with_existing_components); 549 return 0; 550 } 551 else 552 { 553 $installer::logger::Info->printf( 554 "OK: all %d new files also have new components\n", 555 scalar @added_files); 556 return 1; 557 } |
523 } 524 else 525 { 526 $installer::logger::Info->printf("OK: no files have been added\n"); 527 return 1; 528 } 529} 530 531 532 533 | 558 } 559 else 560 { 561 $installer::logger::Info->printf("OK: no files have been added\n"); 562 return 1; 563 } 564} 565 566 567 568 |
534=head2 CheckComponentSets($source_msi, $target_msi) | 569=head2 CheckFeatureSets($source_msi, $target_msi) |
535 | 570 |
571 Features must not be removed but can be added. 572 Parent features of new features also have to be new. 573 574=cut 575sub CheckFeatureSets($$) 576{ 577 my ($source_msi, $target_msi) = @_; 578 579 # Get the 'Feature' tables. 580 my $source_feature_table = $source_msi->GetTable("Feature"); 581 my $target_feature_table = $target_msi->GetTable("Feature"); 582 583 # Create data structures for fast lookup. 584 my %source_feature_map = map {$_->GetValue("Feature") => $_} @{$source_feature_table->GetAllRows()}; 585 my %target_feature_map = map {$_->GetValue("Feature") => $_} @{$target_feature_table->GetAllRows()}; 586 587 # Check that no feature has been removed. 588 my @removed_features = (); 589 foreach my $feature_name (keys %source_feature_map) 590 { 591 if ( ! defined $target_feature_map{$feature_name}) 592 { 593 push @removed_features, $feature_name; 594 } 595 } 596 if (scalar @removed_features > 0) 597 { 598 # There are removed features. 599 $installer::logger::Info->printf( 600 "Error: %d features have been removed:\n", 601 scalar @removed_features); 602 $installer::logger::Info->printf(" %s\n", join(", ", @removed_features)); 603 return 0; 604 } 605 606 # Check that added features belong to new parent features. 607 my @added_features = (); 608 foreach my $feature_name (keys %target_feature_map) 609 { 610 if ( ! defined $source_feature_map{$feature_name}) 611 { 612 push @added_features, $feature_name; 613 } 614 } 615 616 if (scalar @added_features > 0) 617 { 618 $installer::logger::Info->printf("Warning: %d features have been addded\n", scalar @added_features); 619 620 my @new_features_with_existing_parents = (); 621 foreach my $new_feature (@added_features) 622 { 623 my $target_feature = $target_feature_map{$new_feature}; 624 if (defined $source_feature_map{$target_feature->{'Feature_Parent'}}) 625 { 626 push @new_features_with_existing_parents, $target_feature; 627 } 628 } 629 630 if (scalar @new_features_with_existing_parents > 0) 631 { 632 $installer::logger::Info->printf( 633 "Error: %d new features have existing parents (which also must be new)\n", 634 scalar @new_features_with_existing_parents); 635 return 0; 636 } 637 else 638 { 639 $installer::logger::Info->printf( 640 "OK: parents of all new features are also new\n"); 641 return 1; 642 } 643 } 644 645 $installer::logger::Info->printf("OK: feature sets in source and target are compatible\n"); 646 return 1; 647} 648 649 650 651 652=head2 CheckRemovedComponents($source_msi, $target_msi) 653 |
|
536 Components must not be removed but can be added. 537 Features of added components have also to be new. 538 539=cut | 654 Components must not be removed but can be added. 655 Features of added components have also to be new. 656 657=cut |
540sub CheckComponentSets($$) | 658sub CheckRemovedComponents ($$) |
541{ 542 my ($source_msi, $target_msi) = @_; 543 544 # Get the 'Component' tables. 545 my $source_component_table = $source_msi->GetTable("Component"); 546 my $target_component_table = $target_msi->GetTable("Component"); 547 548 # Create data structures for fast lookup. --- 4 unchanged lines hidden (view full) --- 553 my @removed_components = (); 554 foreach my $componentname (keys %source_component_map) 555 { 556 if ( ! defined $target_component_map{$componentname}) 557 { 558 push @removed_components, $componentname; 559 } 560 } | 659{ 660 my ($source_msi, $target_msi) = @_; 661 662 # Get the 'Component' tables. 663 my $source_component_table = $source_msi->GetTable("Component"); 664 my $target_component_table = $target_msi->GetTable("Component"); 665 666 # Create data structures for fast lookup. --- 4 unchanged lines hidden (view full) --- 671 my @removed_components = (); 672 foreach my $componentname (keys %source_component_map) 673 { 674 if ( ! defined $target_component_map{$componentname}) 675 { 676 push @removed_components, $componentname; 677 } 678 } |
561 if (scalar @removed_components > 0) | 679 if (scalar @removed_components == 0) |
562 { | 680 { |
681 $installer::logger::Info->printf("OK: no removed components\n"); 682 return 1; 683 } 684 else 685 { |
|
563 # There are removed components. 564 565 # Check if any of them is not a registry component. 566 my $is_file_component_removed = 0; 567 foreach my $componentname (@removed_components) 568 { 569 if ($componentname !~ /^registry/) 570 { --- 11 unchanged lines hidden (view full) --- 582 else 583 { 584 $installer::logger::Info->printf( 585 "Error: %d components have been removed, all of them are registry components:\n", 586 scalar @removed_components); 587 return 0; 588 } 589 } | 686 # There are removed components. 687 688 # Check if any of them is not a registry component. 689 my $is_file_component_removed = 0; 690 foreach my $componentname (@removed_components) 691 { 692 if ($componentname !~ /^registry/) 693 { --- 11 unchanged lines hidden (view full) --- 705 else 706 { 707 $installer::logger::Info->printf( 708 "Error: %d components have been removed, all of them are registry components:\n", 709 scalar @removed_components); 710 return 0; 711 } 712 } |
713} |
|
590 | 714 |
715 716 717 718sub GetTableAndMap ($$$) 719{ 720 my ($msi, $table_name, $index_column) = @_; 721 722 my $table = $msi->GetTable($table_name); 723 my %map = map {$_->GetValue($index_column) => $_} @{$table->GetAllRows()}; 724 725 return ($table, \%map); 726} 727 728 729=head2 CheckAddedComponents($source_msi, $target_msi) 730 731 Components can be added. 732 Features of added components have also to be new. 733 734=cut 735sub CheckAddedComponents ($$) 736{ 737 my ($source_msi, $target_msi) = @_; 738 739 # Get the 'Component' tables and maps. 740 my ($source_component_table, $source_component_map) 741 = GetTableAndMap($source_msi, "Component", "Component"); 742 my ($target_component_table, $target_component_map) 743 = GetTableAndMap($target_msi, "Component", "Component"); 744 |
|
591 # Check that added components belong to new features. 592 my @added_components = (); | 745 # Check that added components belong to new features. 746 my @added_components = (); |
593 foreach my $componentname (keys %target_component_map) | 747 foreach my $componentname (keys %$target_component_map) |
594 { | 748 { |
595 if ( ! defined $source_component_map{$componentname}) | 749 if ( ! defined $source_component_map->{$componentname}) |
596 { 597 push @added_components, $componentname; 598 } 599 } 600 | 750 { 751 push @added_components, $componentname; 752 } 753 } 754 |
601 if (scalar @added_components > 0) | 755 if (scalar @added_components == 0) |
602 { | 756 { |
603 # Check if any of them is not a registry component. 604 my $is_file_component_removed = 0; 605 foreach my $componentname (@removed_components) 606 { 607 if ($componentname !~ /^registry/) 608 { 609 $is_file_component_removed = 1; 610 } 611 } | 757 $installer::logger::Info->printf("OK: no new components\n"); 758 return 1; 759 } 760 else 761 { 762 $installer::logger::Info->printf( 763 "Warning: %d components have been addded\n", 764 scalar @added_components); |
612 | 765 |
613 if ($is_file_component_removed) | 766 # Check that the referencing features are also new. 767 my $target_feature_component_table = $target_msi->GetTable("FeatureComponents"); 768 769 my $error = 0; 770 foreach my $component_name (@added_components) |
614 { | 771 { |
615 $installer::logger::Info->printf( 616 "Warning: %d components have been addded\n", 617 scalar @added_components); 618 $installer::logger::Info->printf( 619 "Test for new components belonging to new features has not yet been implemented\n"); 620 return 0; 621 } 622 else 623 { 624 $installer::logger::Info->printf( 625 "Warning: %d components have been addded, all of them registry components\n", 626 scalar @added_components); 627 } 628 } | 772 my @feature_names = (); 773 foreach my $feature_component_row (@{$target_feature_component_table->GetAllRows()}) 774 { 775 if ($feature_component_row->GetValue("Component_") eq $component_name) 776 { 777 my $feature_name = $feature_component_row->GetValue("Feature_"); 778 push @feature_names, $feature_name; 779 } 780 } 781 if (scalar @feature_names == 0) 782 { 783 $installer::logger::Info->printf("Error: no feature found for component '%s'\n", $component_name); 784 $error = 1; 785 } 786 else 787 { 788 # Check that the referenced features are new and have new parents (if they have parents). 789 my ($source_feature_table, $source_feature_map) 790 = GetTableAndMap($source_msi, "Feature", "Feature"); 791 my ($target_feature_table, $target_feature_map) 792 = GetTableAndMap($target_msi, "Feature", "Feature"); 793 foreach my $feature_name (@feature_names) 794 { 795 $installer::logger::Info->printf(" component '%s' -> feature '%s'\n", 796 $component_name, 797 $feature_name); 798 my $source_feature_row = $source_feature_map->{$feature_name}; 799 if (defined $source_feature_row) 800 { 801 $installer::logger::Info->printf("Warning(Error?): feature of new component is not new\n"); 802 $error = 1; 803 } 804 else 805 { 806 # Feature is new. Check that the parent feature is also new. 807 my $target_feature_row = $target_feature_map->{$feature_name}; 808 my $parent_feature_name = $target_feature_row->GetValue("Feature_Parent"); 809 if ($parent_feature_name ne "" && defined $source_feature_map->{$parent_feature_name}) 810 { 811 $installer::logger::Info->printf("Warning(Error?): parent feature of new component is not new\n"); 812 $error = 1; 813 } 814 } 815 } 816 } 817 } |
629 | 818 |
630 $installer::logger::Info->printf("OK: component sets in source and target are compatible\n"); 631 return 1; | 819# return !$error; 820 return 1; 821 } |
632} 633 634 635 636 637=head2 CheckComponent($source_msi, $target_msi) 638 639 In the 'Component' table the 'ComponentId' and 'Component' values --- 317 unchanged lines hidden (view full) --- 957 "OK: no mismatches in the 'KeyPath' column of the 'Component' table\n"); 958 return 1; 959 } 960} 961 962 963 964 | 822} 823 824 825 826 827=head2 CheckComponent($source_msi, $target_msi) 828 829 In the 'Component' table the 'ComponentId' and 'Component' values --- 317 unchanged lines hidden (view full) --- 1147 "OK: no mismatches in the 'KeyPath' column of the 'Component' table\n"); 1148 return 1; 1149 } 1150} 1151 1152 1153 1154 |
1155sub GetMissingReferences ($$$$$) 1156{ 1157 my ($table, $key, $map, $what, $report_key) = @_; 1158 1159 my @missing_references = (); 1160 1161 foreach my $row (@{$table->GetAllRows()}) 1162 { 1163 my $value = $row->GetValue($key); 1164 if ($value ne "" && ! defined $map->{$value}) 1165 { 1166 push @missing_references, [$what, $row->GetValue($report_key), $value]; 1167 } 1168 } 1169 1170 return @missing_references; 1171} 1172 1173 1174 1175 1176=head CheckAllReferences ($msi) 1177 1178 Check references from files and registry entries to components, 1179 from components to features, and between features. 1180 1181=cut 1182 1183sub CheckAllReferences ($) 1184{ 1185 my ($msi) = @_; 1186 1187 # Set up tables and maps for easy iteration and fast lookups. 1188 1189 my $feature_table = $msi->GetTable("Feature"); 1190 my $component_table = $msi->GetTable("Component"); 1191 my $feature_component_table = $msi->GetTable("FeatureComponents"); 1192 my $file_table = $msi->GetTable("File"); 1193 my $registry_table = $msi->GetTable("Registry"); 1194 my $directory_table = $msi->GetTable("Directory"); 1195 1196 my %feature_map = map {$_->GetValue("Feature") => $_} @{$feature_table->GetAllRows()}; 1197 my %component_map = map {$_->GetValue("Component") => $_} @{$component_table->GetAllRows()}; 1198 my %directory_map = map {$_->GetValue("Directory") => $_} @{$directory_table->GetAllRows()}; 1199 1200 my @missing_references = (); 1201 1202 # Check references from files and registry entries to components. 1203 push @missing_references, GetMissingReferences( 1204 $file_table, 1205 "Component_", 1206 \%component_map, 1207 "file->component", 1208 "File"); 1209 push @missing_references, GetMissingReferences( 1210 $registry_table, 1211 "Component_", 1212 \%component_map, 1213 "registry->component", 1214 "Registry"); 1215 1216 # Check references between features and components. 1217 push @missing_references, GetMissingReferences( 1218 $feature_component_table, 1219 "Feature_", 1220 \%feature_map, 1221 "component->feature", 1222 "Component_"); 1223 push @missing_references, GetMissingReferences( 1224 $feature_component_table, 1225 "Component_", 1226 \%component_map, 1227 "feature->component", 1228 "Feature_"); 1229 1230 # Check references between features. 1231 push @missing_references, GetMissingReferences( 1232 $feature_table, 1233 'Feature_Parent', 1234 \%feature_map, 1235 "feature->feature", 1236 'Feature'); 1237 1238 # Check references between directories. 1239 push @missing_references, GetMissingReferences( 1240 $directory_table, 1241 'Directory_Parent', 1242 \%directory_map, 1243 "directory->directory", 1244 'Directory'); 1245 1246 # Check references from components to directories. 1247 push @missing_references, GetMissingReferences( 1248 $component_table, 1249 'Directory_', 1250 \%directory_map, 1251 "component->directory", 1252 'Component'); 1253 1254 # Check references from components to files (via the . 1255 1256 # Report the result. 1257 if (scalar @missing_references > 0) 1258 { 1259 $installer::logger::Info->printf("Error: there are %d missing references\n", scalar @missing_references); 1260 foreach my $reference (@missing_references) 1261 { 1262 $installer::logger::Info->printf(" %s : %s -> %s\n", 1263 $reference->[0], 1264 $reference->[1], 1265 $reference->[2]); 1266 } 1267 return 0; 1268 } 1269 else 1270 { 1271 $installer::logger::Info->printf("OK: all references are OK\n"); 1272 return 1; 1273 1274 } 1275} 1276 1277 1278 1279 |
|
965sub Check ($$$$) 966{ 967 my ($source_msi, $target_msi, $variables, $product_name) = @_; 968 969 $installer::logger::Info->printf("checking if source and target releases are compatable\n"); 970 $installer::logger::Info->increase_indentation(); 971 972 my $result = 1; 973 | 1280sub Check ($$$$) 1281{ 1282 my ($source_msi, $target_msi, $variables, $product_name) = @_; 1283 1284 $installer::logger::Info->printf("checking if source and target releases are compatable\n"); 1285 $installer::logger::Info->increase_indentation(); 1286 1287 my $result = 1; 1288 |
974 $result &&= CheckUpgradeCode($source_msi, $target_msi); 975 $result &&= CheckProductCode($source_msi, $target_msi); 976 $result &&= CheckBuildIdCode($source_msi, $target_msi); 977 $result &&= CheckProductName($source_msi, $target_msi); 978 $result &&= CheckRemovedFiles($source_msi, $target_msi); 979 $result &&= CheckNewFiles($source_msi, $target_msi); 980 $result &&= CheckComponentSets($source_msi, $target_msi); 981 $result &&= CheckComponentValues($source_msi, $target_msi, $variables); 982 $result &&= CheckFileSequence($source_msi, $target_msi); 983 $result &&= CheckFileSequenceUnique($source_msi, $target_msi); 984 $result &&= CheckFileSequenceHoles($source_msi, $target_msi); 985 $result &&= CheckRegistryItems($source_msi, $target_msi, $product_name); 986 $result &&= CheckComponentKeyPath($source_msi, $target_msi); | 1289 # Using &= below to avoid lazy evaluation. Even if there are errors, all checks shall be run. 1290 $result &= CheckUpgradeCode($source_msi, $target_msi); 1291 $result &= CheckProductCode($source_msi, $target_msi); 1292 $result &= CheckBuildIdCode($source_msi, $target_msi); 1293 $result &= CheckProductName($source_msi, $target_msi); 1294 $result &= CheckRemovedFiles($source_msi, $target_msi); 1295 $result &= CheckNewFiles($source_msi, $target_msi); 1296 $result &= CheckFeatureSets($source_msi, $target_msi); 1297 $result &= CheckRemovedComponents($source_msi, $target_msi); 1298 $result &= CheckAddedComponents($source_msi, $target_msi); 1299 $result &= CheckComponentValues($source_msi, $target_msi, $variables); 1300 $result &= CheckFileSequence($source_msi, $target_msi); 1301 $result &= CheckFileSequenceUnique($source_msi, $target_msi); 1302 $result &= CheckFileSequenceHoles($source_msi, $target_msi); 1303 $result &= CheckRegistryItems($source_msi, $target_msi, $product_name); 1304 $result &= CheckComponentKeyPath($source_msi, $target_msi); 1305 $result &= CheckAllReferences($target_msi); |
987 988 $installer::logger::Info->decrease_indentation(); 989 | 1306 1307 $installer::logger::Info->decrease_indentation(); 1308 |
1309 if ($result) 1310 { 1311 $installer::logger::Info->printf("OK: Source and target releases are compatible.\n"); 1312 } 1313 else 1314 { 1315 $installer::logger::Info->printf("Error: Source and target releases are not compatible.\n"); 1316 $installer::logger::Info->printf(" => Can not create patch.\n"); 1317 $installer::logger::Info->printf(" Did you create the target installation set with 'release=t' ?\n"); 1318 } 1319 |
|
990 return $result; 991} 992 993 994 995 996=head2 FindPcpTemplate () 997 --- 229 unchanged lines hidden (view full) --- 1227 { 1228 $installer::logger::Info->printf("Error: could not create openoffice.pcp as copy of pcp schema\n"); 1229 $installer::logger::Info->printf(" %s\n", $pcp_schema_filename); 1230 $installer::logger::Info->printf(" %s\n", $pcp_filename); 1231 return undef; 1232 } 1233 my $pcp = installer::patch::Msi->new( 1234 $pcp_filename, | 1320 return $result; 1321} 1322 1323 1324 1325 1326=head2 FindPcpTemplate () 1327 --- 229 unchanged lines hidden (view full) --- 1557 { 1558 $installer::logger::Info->printf("Error: could not create openoffice.pcp as copy of pcp schema\n"); 1559 $installer::logger::Info->printf(" %s\n", $pcp_schema_filename); 1560 $installer::logger::Info->printf(" %s\n", $pcp_filename); 1561 return undef; 1562 } 1563 my $pcp = installer::patch::Msi->new( 1564 $pcp_filename, |
1235 undef, 1236 undef, | 1565 $target_msi->{'version'}, 1566 $target_msi->{'is_current_version'}, |
1237 $language, 1238 $context->{'product-name'}); 1239 1240 # Store some values in the pcp for easy reference in the msp creation. 1241 $pcp->{'msp_filename'} = $msp_filename; 1242 1243 SetupPcpPatchMetadataTable($pcp, $source_msi, $target_msi); 1244 SetupPropertiesTable($pcp, $msp_filename); --- 31 unchanged lines hidden (view full) --- 1276 File::Path::make_path($destination_path) if ! -d $destination_path; 1277 my $command = join(" ", 1278 "wilogutl.exe", 1279 "/q", 1280 "/l", "'".installer::patch::Tools::ToWindowsPath($log_filename)."'", 1281 "/o", "'".installer::patch::Tools::ToWindowsPath($destination_path)."'"); 1282 printf("running command $command\n"); 1283 my $response = qx($command); | 1567 $language, 1568 $context->{'product-name'}); 1569 1570 # Store some values in the pcp for easy reference in the msp creation. 1571 $pcp->{'msp_filename'} = $msp_filename; 1572 1573 SetupPcpPatchMetadataTable($pcp, $source_msi, $target_msi); 1574 SetupPropertiesTable($pcp, $msp_filename); --- 31 unchanged lines hidden (view full) --- 1606 File::Path::make_path($destination_path) if ! -d $destination_path; 1607 my $command = join(" ", 1608 "wilogutl.exe", 1609 "/q", 1610 "/l", "'".installer::patch::Tools::ToWindowsPath($log_filename)."'", 1611 "/o", "'".installer::patch::Tools::ToWindowsPath($destination_path)."'"); 1612 printf("running command $command\n"); 1613 my $response = qx($command); |
1284 printf("response is '%s'\n", $response); | |
1285 my @candidates = glob($destination_path . "/Details*"); 1286 foreach my $candidate (@candidates) 1287 { 1288 next unless -f $candidate; 1289 my $new_name = $candidate; 1290 $new_name =~ s/Details.*$/$log_basename.html/; 1291 1292 # Rename the top-level html file and replace the title. --- 8 unchanged lines hidden (view full) --- 1301 else 1302 { 1303 print $out $_; 1304 } 1305 } 1306 close $in; 1307 close $out; 1308 | 1614 my @candidates = glob($destination_path . "/Details*"); 1615 foreach my $candidate (@candidates) 1616 { 1617 next unless -f $candidate; 1618 my $new_name = $candidate; 1619 $new_name =~ s/Details.*$/$log_basename.html/; 1620 1621 # Rename the top-level html file and replace the title. --- 8 unchanged lines hidden (view full) --- 1630 else 1631 { 1632 print $out $_; 1633 } 1634 } 1635 close $in; 1636 close $out; 1637 |
1309 my $URL = $new_name; 1310 $URL =~ s/\/c\//c|\//; | 1638 my $URL = File::Spec->rel2abs($new_name); 1639 $URL =~ s/\/cygdrive\/(.)\//$1|\//; |
1311 $URL =~ s/^(.):/$1|/; 1312 $URL = "file:///". $URL; 1313 $installer::logger::Info->printf("open %s in your browser to see the log messages\n", $URL); 1314 } 1315 } 1316 else 1317 { 1318 $installer::logger::Info->printf("Error: log file not found at %s\n", $log_filename); --- 20 unchanged lines hidden (view full) --- 1339 # Create the .msp patch file. 1340 my $temporary_msimsp_path = File::Spec->catfile($pcp->{'path'}, "tmp"); 1341 if ( ! -d $temporary_msimsp_path) 1342 { 1343 File::Path::make_path($temporary_msimsp_path) 1344 || die ("can not create temporary path ".$temporary_msimsp_path); 1345 } 1346 $installer::logger::Info->printf("running msimsp.exe, that will take a while\n"); | 1640 $URL =~ s/^(.):/$1|/; 1641 $URL = "file:///". $URL; 1642 $installer::logger::Info->printf("open %s in your browser to see the log messages\n", $URL); 1643 } 1644 } 1645 else 1646 { 1647 $installer::logger::Info->printf("Error: log file not found at %s\n", $log_filename); --- 20 unchanged lines hidden (view full) --- 1668 # Create the .msp patch file. 1669 my $temporary_msimsp_path = File::Spec->catfile($pcp->{'path'}, "tmp"); 1670 if ( ! -d $temporary_msimsp_path) 1671 { 1672 File::Path::make_path($temporary_msimsp_path) 1673 || die ("can not create temporary path ".$temporary_msimsp_path); 1674 } 1675 $installer::logger::Info->printf("running msimsp.exe, that will take a while\n"); |
1676 my $create_performance_log = 0; |
|
1347 my $command = join(" ", 1348 "msimsp.exe", 1349 "-s", "'".installer::patch::Tools::ToWindowsPath($pcp->{'filename'})."'", 1350 "-p", "'".installer::patch::Tools::ToWindowsPath($pcp->{'msp_filename'})."'", 1351 "-l", "'".installer::patch::Tools::ToWindowsPath($log_filename)."'", 1352 "-f", "'".installer::patch::Tools::ToWindowsPath($temporary_msimsp_path)."'"); | 1677 my $command = join(" ", 1678 "msimsp.exe", 1679 "-s", "'".installer::patch::Tools::ToWindowsPath($pcp->{'filename'})."'", 1680 "-p", "'".installer::patch::Tools::ToWindowsPath($pcp->{'msp_filename'})."'", 1681 "-l", "'".installer::patch::Tools::ToWindowsPath($log_filename)."'", 1682 "-f", "'".installer::patch::Tools::ToWindowsPath($temporary_msimsp_path)."'"); |
1353# "-lp", MsiTools::ToEscapedWindowsPath($performance_log_filename), | 1683 if ($create_performance_log) 1684 { 1685 $command .= " -lp " . MsiTools::ToEscapedWindowsPath($performance_log_filename); 1686 } |
1354 $installer::logger::Info->printf("running command %s\n", $command); 1355 my $response = qx($command); 1356 $installer::logger::Info->printf("response of msimsp is %s\n", $response); 1357 if ( ! -d $temporary_msimsp_path) 1358 { 1359 die("msimsp failed and deleted temporary path ".$temporary_msimsp_path); 1360 } 1361 1362 # Show the log file that was created by the msimsp.exe command. 1363 ShowLog($log_path, $log_filename, $log_basename, "msp creation"); | 1687 $installer::logger::Info->printf("running command %s\n", $command); 1688 my $response = qx($command); 1689 $installer::logger::Info->printf("response of msimsp is %s\n", $response); 1690 if ( ! -d $temporary_msimsp_path) 1691 { 1692 die("msimsp failed and deleted temporary path ".$temporary_msimsp_path); 1693 } 1694 1695 # Show the log file that was created by the msimsp.exe command. 1696 ShowLog($log_path, $log_filename, $log_basename, "msp creation"); |
1364 ShowLog($log_path, $performance_log_filename, $performance_log_basename, "msp creation perf"); | 1697 if ($create_performance_log) 1698 { 1699 ShowLog($log_path, $performance_log_filename, $performance_log_basename, "msp creation perf"); 1700 } |
1365} 1366 1367 | 1701} 1702 1703 |
1704sub ProvideMsis ($$$) 1705{ 1706 my ($context, $variables, $language) = @_; |
|
1368 | 1707 |
1708 # 2a. Provide .msi and .cab files and unpack .cab for the source release. 1709 $installer::logger::Info->printf("locating source package (%s)\n", $context->{'source-version'}); 1710 $installer::logger::Info->increase_indentation(); 1711 if ( ! installer::patch::InstallationSet::ProvideUnpackedCab( 1712 $context->{'source-version'}, 1713 0, 1714 $language, 1715 "msi", 1716 $context->{'product-name'})) 1717 { 1718 die "could not provide unpacked .cab file"; 1719 } 1720 my $source_msi = installer::patch::Msi->FindAndCreate( 1721 $context->{'source-version'}, 1722 0, 1723 $language, 1724 $context->{'product-name'}); 1725 die unless defined $source_msi; 1726 die unless $source_msi->IsValid(); 1727 $installer::logger::Info->decrease_indentation(); |
|
1369 | 1728 |
1729 # 2b. Provide .msi and .cab files and unpacked .cab for the target release. 1730 $installer::logger::Info->printf("locating target package (%s)\n", $context->{'target-version'}); 1731 $installer::logger::Info->increase_indentation(); 1732 if ( ! installer::patch::InstallationSet::ProvideUnpackedCab( 1733 $context->{'target-version'}, 1734 1, 1735 $language, 1736 "msi", 1737 $context->{'product-name'})) 1738 { 1739 die; 1740 } 1741 my $target_msi = installer::patch::Msi->FindAndCreate( 1742 $context->{'target-version'}, 1743 0, 1744 $language, 1745 $context->{'product-name'}); 1746 die unless defined $target_msi; 1747 die unless $target_msi->IsValid(); 1748 $installer::logger::Info->decrease_indentation(); 1749 1750 return ($source_msi, $target_msi); 1751} 1752 1753 1754 1755 |
|
1370=head CreatePatch($context, $variables) 1371 1372 Create MSP patch files for all relevant languages. 1373 The different steps are: 1374 1. Determine the set of languages for which both the source and target installation sets are present. 1375 Per language: 1376 2. Unpack CAB files (for source and target). 1377 3. Check if source and target releases are compatible. --- 17 unchanged lines hidden (view full) --- 1395 exit(1); 1396 } 1397 1398 my $release_data = installer::patch::ReleasesList::Instance() 1399 ->{$context->{'source-version'}} 1400 ->{$context->{'package-format'}}; 1401 1402 # 1. Determine the set of languages for which we can create patches. | 1756=head CreatePatch($context, $variables) 1757 1758 Create MSP patch files for all relevant languages. 1759 The different steps are: 1760 1. Determine the set of languages for which both the source and target installation sets are present. 1761 Per language: 1762 2. Unpack CAB files (for source and target). 1763 3. Check if source and target releases are compatible. --- 17 unchanged lines hidden (view full) --- 1781 exit(1); 1782 } 1783 1784 my $release_data = installer::patch::ReleasesList::Instance() 1785 ->{$context->{'source-version'}} 1786 ->{$context->{'package-format'}}; 1787 1788 # 1. Determine the set of languages for which we can create patches. |
1403 my @requested_languages = GetLanguages(); 1404 my @valid_languages = FindValidLanguages($context, $release_data, \@requested_languages); 1405 $installer::logger::Info->printf("of the requested languages '%s' are valid: '%s'\n", 1406 join("', '", @requested_languages), 1407 join("', '", @valid_languages)); 1408 foreach my $language (@valid_languages) | 1789 my $language = $context->{'language'}; 1790 my %no_ms_lang_locale_map = map {$_=>1} @installer::globals::noMSLocaleLangs; 1791 if (defined $no_ms_lang_locale_map{$language}) |
1409 { | 1792 { |
1793 $language = "en-US_".$language; 1794 } 1795 1796 if ( ! IsLanguageValid($context, $release_data, $language)) 1797 { 1798 $installer::logger::Info->printf("can not create patch for language '%s'\n", $language); 1799 } 1800 else 1801 { |
|
1410 $installer::logger::Info->printf("processing language '%s'\n", $language); 1411 $installer::logger::Info->increase_indentation(); 1412 | 1802 $installer::logger::Info->printf("processing language '%s'\n", $language); 1803 $installer::logger::Info->increase_indentation(); 1804 |
1413 # 2a. Provide .msi and .cab files and unpacke .cab for the source release. 1414 $installer::logger::Info->printf("locating source package (%s)\n", $context->{'source-version'}); 1415 $installer::logger::Info->increase_indentation(); 1416 if ( ! installer::patch::InstallationSet::ProvideUnpackedCab( 1417 $context->{'source-version'}, 1418 0, 1419 $language, 1420 "msi", 1421 $context->{'product-name'})) 1422 { 1423 die "could not provide unpacked .cab file"; 1424 } 1425 my $source_msi = installer::patch::Msi->FindAndCreate( 1426 $context->{'source-version'}, 1427 0, 1428 $language, 1429 $context->{'product-name'}); 1430 die unless $source_msi->IsValid(); | 1805 my ($source_msi, $target_msi) = ProvideMsis($context, $variables, $language); |
1431 | 1806 |
1432 $installer::logger::Info->decrease_indentation(); 1433 1434 # 2b. Provide .msi and .cab files and unpacke .cab for the target release. 1435 $installer::logger::Info->printf("locating target package (%s)\n", $context->{'target-version'}); 1436 $installer::logger::Info->increase_indentation(); 1437 if ( ! installer::patch::InstallationSet::ProvideUnpackedCab( 1438 $context->{'target-version'}, 1439 1, 1440 $language, 1441 "msi", 1442 $context->{'product-name'})) 1443 { 1444 die; 1445 } 1446 my $target_msi = installer::patch::Msi->FindAndCreate( 1447 $context->{'target-version'}, 1448 0, 1449 $language, 1450 $context->{'product-name'}); 1451 die unless defined $target_msi; 1452 die unless $target_msi->IsValid(); 1453 $installer::logger::Info->decrease_indentation(); 1454 | |
1455 # Trigger reading of tables. 1456 foreach my $table_name (("File", "Component", "Registry")) 1457 { 1458 $source_msi->GetTable($table_name); 1459 $target_msi->GetTable($table_name); 1460 $installer::logger::Info->printf("read %s table (source and target\n", $table_name); 1461 } 1462 1463 # 3. Check if the source and target msis fullfil all necessary requirements. 1464 if ( ! Check($source_msi, $target_msi, $variables, $context->{'product-name'})) 1465 { | 1807 # Trigger reading of tables. 1808 foreach my $table_name (("File", "Component", "Registry")) 1809 { 1810 $source_msi->GetTable($table_name); 1811 $target_msi->GetTable($table_name); 1812 $installer::logger::Info->printf("read %s table (source and target\n", $table_name); 1813 } 1814 1815 # 3. Check if the source and target msis fullfil all necessary requirements. 1816 if ( ! Check($source_msi, $target_msi, $variables, $context->{'product-name'})) 1817 { |
1466 $installer::logger::Info->printf("Error: Source and target releases are not compatible.\n"); 1467 $installer::logger::Info->printf(" => Can not create patch.\n"); 1468 $installer::logger::Info->printf(" Did you create the target installation set with 'release=t' ?\n"); | |
1469 exit(1); 1470 } | 1818 exit(1); 1819 } |
1471 else 1472 { 1473 $installer::logger::Info->printf("OK: Source and target releases are compatible.\n"); 1474 } | |
1475 1476 # Provide the base path for creating .pcp and .mcp file. 1477 my $msp_path = File::Spec->catfile( 1478 $context->{'output-path'}, 1479 $context->{'product-name'}, 1480 "msp", 1481 sprintf("%s_%s", | 1820 1821 # Provide the base path for creating .pcp and .mcp file. 1822 my $msp_path = File::Spec->catfile( 1823 $context->{'output-path'}, 1824 $context->{'product-name'}, 1825 "msp", 1826 sprintf("%s_%s", |
1482 installer::patch::Version::ArrayToDirectoryName( 1483 installer::patch::Version::StringToNumberArray( 1484 $source_msi->{'version'})), 1485 installer::patch::Version::ArrayToDirectoryName( 1486 installer::patch::Version::StringToNumberArray( 1487 $target_msi->{'version'}))), | 1827 installer::patch::Version::ArrayToDirectoryName( 1828 installer::patch::Version::StringToNumberArray( 1829 $source_msi->{'version'})), 1830 installer::patch::Version::ArrayToDirectoryName( 1831 installer::patch::Version::StringToNumberArray( 1832 $target_msi->{'version'}))), |
1488 $language 1489 ); 1490 File::Path::make_path($msp_path) unless -d $msp_path; 1491 1492 # 4. Create the .pcp file that drives the msimsp.exe command. 1493 my $pcp = CreatePcp( 1494 $source_msi, 1495 $target_msi, --- 7 unchanged lines hidden (view full) --- 1503 CreateMsp($pcp); 1504 1505 $installer::logger::Info->decrease_indentation(); 1506 } 1507} 1508 1509 1510 | 1833 $language 1834 ); 1835 File::Path::make_path($msp_path) unless -d $msp_path; 1836 1837 # 4. Create the .pcp file that drives the msimsp.exe command. 1838 my $pcp = CreatePcp( 1839 $source_msi, 1840 $target_msi, --- 7 unchanged lines hidden (view full) --- 1848 CreateMsp($pcp); 1849 1850 $installer::logger::Info->decrease_indentation(); 1851 } 1852} 1853 1854 1855 |
1856 1857sub CheckPatchCompatability ($$) 1858{ 1859 my ($context, $variables) = @_; 1860 1861 $installer::logger::Info->printf("patch will update product %s from %s to %s\n", 1862 $context->{'product-name'}, 1863 $context->{'source-version'}, 1864 $context->{'target-version'}); 1865 1866 my $release_data = installer::patch::ReleasesList::Instance() 1867 ->{$context->{'source-version'}} 1868 ->{$context->{'package-format'}}; 1869 1870 # 1. Determine the set of languages for which we can create patches. 1871 my $language = $context->{'language'}; 1872 my %no_ms_lang_locale_map = map {$_=>1} @installer::globals::noMSLocaleLangs; 1873 if (defined $no_ms_lang_locale_map{$language}) 1874 { 1875 $language = "en-US_".$language; 1876 } 1877 1878 if ( ! IsLanguageValid($context, $release_data, $language)) 1879 { 1880 $installer::logger::Info->printf("can not create patch for language '%s'\n", $language); 1881 } 1882 else 1883 { 1884 $installer::logger::Info->printf("processing language '%s'\n", $language); 1885 $installer::logger::Info->increase_indentation(); 1886 1887 my ($source_msi, $target_msi) = ProvideMsis($context, $variables, $language); 1888 1889 # Trigger reading of tables. 1890 foreach my $table_name (("File", "Component", "Registry")) 1891 { 1892 $source_msi->GetTable($table_name); 1893 $target_msi->GetTable($table_name); 1894 $installer::logger::Info->printf("read %s table (source and target\n", $table_name); 1895 } 1896 1897 # 3. Check if the source and target msis fullfil all necessary requirements. 1898 if ( ! Check($source_msi, $target_msi, $variables, $context->{'product-name'})) 1899 { 1900 exit(1); 1901 } 1902 } 1903} 1904 1905 1906 1907 |
|
1511=cut ApplyPatch ($context, $variables) 1512 1513 This is for testing only. 1514 The patch is applied and (extensive) log information is created and transformed into HTML format. 1515 1516=cut 1517sub ApplyPatch ($$) 1518{ 1519 my ($context, $variables) = @_; 1520 1521 $installer::logger::Info->printf("will apply patches that update product %s from %s to %s\n", 1522 $context->{'product-name'}, 1523 $context->{'source-version'}, 1524 $context->{'target-version'}); | 1908=cut ApplyPatch ($context, $variables) 1909 1910 This is for testing only. 1911 The patch is applied and (extensive) log information is created and transformed into HTML format. 1912 1913=cut 1914sub ApplyPatch ($$) 1915{ 1916 my ($context, $variables) = @_; 1917 1918 $installer::logger::Info->printf("will apply patches that update product %s from %s to %s\n", 1919 $context->{'product-name'}, 1920 $context->{'source-version'}, 1921 $context->{'target-version'}); |
1525 my @languages = GetLanguages(); | |
1526 1527 my $source_version_dirname = installer::patch::Version::ArrayToDirectoryName( 1528 installer::patch::Version::StringToNumberArray( 1529 $context->{'source-version'})); 1530 my $target_version_dirname = installer::patch::Version::ArrayToDirectoryName( 1531 installer::patch::Version::StringToNumberArray( 1532 $context->{'target-version'})); 1533 | 1922 1923 my $source_version_dirname = installer::patch::Version::ArrayToDirectoryName( 1924 installer::patch::Version::StringToNumberArray( 1925 $context->{'source-version'})); 1926 my $target_version_dirname = installer::patch::Version::ArrayToDirectoryName( 1927 installer::patch::Version::StringToNumberArray( 1928 $context->{'target-version'})); 1929 |
1534 foreach my $language (@languages) | 1930 my $language = $context->{'language'}; 1931 my %no_ms_lang_locale_map = map {$_=>1} @installer::globals::noMSLocaleLangs; 1932 if (defined $no_ms_lang_locale_map{$language}) |
1535 { | 1933 { |
1536 my $msp_filename = File::Spec->catfile( 1537 $context->{'output-path'}, 1538 $context->{'product-name'}, 1539 "msp", 1540 $source_version_dirname . "_" . $target_version_dirname, 1541 $language, 1542 "openoffice.msp"); 1543 if ( ! -f $msp_filename) 1544 { 1545 $installer::logger::Info->printf("%s does not point to a valid file\n", $msp_filename); 1546 next; 1547 } | 1934 $language = "en-US_".$language; 1935 } 1936 1937 my $msp_filename = File::Spec->catfile( 1938 $context->{'output-path'}, 1939 $context->{'product-name'}, 1940 "msp", 1941 $source_version_dirname . "_" . $target_version_dirname, 1942 $language, 1943 "openoffice.msp"); 1944 if ( ! -f $msp_filename) 1945 { 1946 $installer::logger::Info->printf("%s does not point to a valid file\n", $msp_filename); 1947 next; 1948 } |
1548 | 1949 |
1549 my $log_path = File::Spec->catfile(dirname($msp_filename), "log"); 1550 my $log_basename = "apply-msp"; 1551 my $log_filename = File::Spec->catfile($log_path, $log_basename.".log"); 1552 1553 my $command = join(" ", 1554 "msiexec.exe", 1555 "/update", "'".installer::patch::Tools::ToWindowsPath($msp_filename)."'", 1556 "/L*xv!", "'".installer::patch::Tools::ToWindowsPath($log_filename)."'", 1557 "REINSTALL=ALL", | 1950 my $log_path = File::Spec->catfile(dirname($msp_filename), "log"); 1951 my $log_basename = "apply-msp"; 1952 my $log_filename = File::Spec->catfile($log_path, $log_basename.".log"); 1953 1954 my $command = join(" ", 1955 "msiexec.exe", 1956 "/update", "'".installer::patch::Tools::ToWindowsPath($msp_filename)."'", 1957 "/L*xv!", "'".installer::patch::Tools::ToWindowsPath($log_filename)."'", 1958 "REINSTALL=ALL", |
1558# "REINSTALLMODE=vomus", | 1959# "REINSTALLMODE=vomus", |
1559 "REINSTALLMODE=omus", 1560 "MSIENFORCEUPGRADECOMPONENTRULES=1"); | 1960 "REINSTALLMODE=omus", 1961 "MSIENFORCEUPGRADECOMPONENTRULES=1"); |
1561 | 1962 |
1562 printf("executing command %s\n", $command); 1563 my $response = qx($command); 1564 Encode::from_to($response, "UTF16LE", "UTF8"); 1565 printf("response was '%s'\n", $response); | 1963 printf("executing command %s\n", $command); 1964 my $response = qx($command); 1965 Encode::from_to($response, "UTF16LE", "UTF8"); 1966 printf("response was '%s'\n", $response); |
1566 | 1967 |
1567 ShowLog($log_path, $log_filename, $log_basename, "msp application"); 1568 } | 1968 ShowLog($log_path, $log_filename, $log_basename, "msp application"); |
1569} 1570 1571 1572 1573 1574=head2 DownloadFile ($url) 1575 1576 A simpler version of InstallationSet::Download(). It is simple because it is used to --- 220 unchanged lines hidden (view full) --- 1797 printf("and check in the modified file to the version control system\n"); 1798} 1799 1800 1801 1802 1803sub main () 1804{ | 1969} 1970 1971 1972 1973 1974=head2 DownloadFile ($url) 1975 1976 A simpler version of InstallationSet::Download(). It is simple because it is used to --- 220 unchanged lines hidden (view full) --- 2197 printf("and check in the modified file to the version control system\n"); 2198} 2199 2200 2201 2202 2203sub main () 2204{ |
1805 installer::logger::SetupSimpleLogging(undef); | |
1806 my $context = ProcessCommandline(); | 2205 my $context = ProcessCommandline(); |
2206 installer::logger::starttime(); 2207 $installer::logger::Global->add_timestamp("starting logging"); 2208# installer::logger::SetupSimpleLogging(undef); 2209 |
|
1807 die "ERROR: list file is not defined, please use --lst-file option" 1808 unless defined $context->{'lst-file'}; 1809 die "ERROR: product name is not defined, please use --product-name option" 1810 unless defined $context->{'product-name'}; | 2210 die "ERROR: list file is not defined, please use --lst-file option" 2211 unless defined $context->{'lst-file'}; 2212 die "ERROR: product name is not defined, please use --product-name option" 2213 unless defined $context->{'product-name'}; |
2214 die sprintf("ERROR: package format %s is not supported", $context->{'package-format'}) 2215 unless defined $context->{'package-format'} ne "msi"; |
|
1811 1812 my ($variables, undef, undef) = installer::ziplist::read_openoffice_lst_file( 1813 $context->{'lst-file'}, 1814 $context->{'product-name'}, 1815 undef); 1816 DetermineVersions($context, $variables); 1817 | 2216 2217 my ($variables, undef, undef) = installer::ziplist::read_openoffice_lst_file( 2218 $context->{'lst-file'}, 2219 $context->{'product-name'}, 2220 undef); 2221 DetermineVersions($context, $variables); 2222 |
2223 if ($context->{'command'} =~ /create|check/) 2224 { 2225 $installer::logger::Lang->set_filename( 2226 File::Spec->catfile( 2227 $context->{'output-path'}, 2228 $context->{'product-name'}, 2229 "msp", 2230 $context->{'source-version-dash'} . "_" . $context->{'target-version-dash'}, 2231 $context->{'language'}, 2232 "log", 2233 "patch-creation.log")); 2234 $installer::logger::Lang->copy_lines_from($installer::logger::Global); 2235 $installer::logger::Lang->set_forward(undef); 2236 $installer::logger::Info->set_forward($installer::logger::Lang); 2237 } 2238 |
|
1818 if ($context->{'command'} eq "create") 1819 { 1820 CreatePatch($context, $variables); 1821 } 1822 elsif ($context->{'command'} eq "apply") 1823 { 1824 ApplyPatch($context, $variables); 1825 } 1826 elsif ($context->{'command'} eq "update-releases-xml") 1827 { 1828 UpdateReleasesXML($context, $variables); 1829 } | 2239 if ($context->{'command'} eq "create") 2240 { 2241 CreatePatch($context, $variables); 2242 } 2243 elsif ($context->{'command'} eq "apply") 2244 { 2245 ApplyPatch($context, $variables); 2246 } 2247 elsif ($context->{'command'} eq "update-releases-xml") 2248 { 2249 UpdateReleasesXML($context, $variables); 2250 } |
2251 elsif ($context->{'command'} eq "check") 2252 { 2253 CheckPatchCompatability($context, $variables); 2254 } |
|
1830} 1831 1832 1833main(); | 2255} 2256 2257 2258main(); |