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();