patch_tool.pl (9f91b7e3) patch_tool.pl (d575d58f)
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

--- 241 unchanged lines hidden (view full) ---

250 # Make sure that the downloadable installation set (.exe) is present in ext_sources/.
251 my $filename = File::Spec->catfile($ext_sources_path, $basename);
252 if ( -f $filename)
253 {
254 PrintInfo("%s is already present in ext_sources/. Nothing to do\n", $basename);
255 }
256 else
257 {
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

--- 241 unchanged lines hidden (view full) ---

250 # Make sure that the downloadable installation set (.exe) is present in ext_sources/.
251 my $filename = File::Spec->catfile($ext_sources_path, $basename);
252 if ( -f $filename)
253 {
254 PrintInfo("%s is already present in ext_sources/. Nothing to do\n", $basename);
255 }
256 else
257 {
258 return 0 if ! installer::patch::Download($language, $release_data, $location, $basename, $filename);
258 return 0 if ! installer::patch::InstallationSet::Download(
259 $language,
260 $release_data,
261 $filename);
259 return 0 if ! -f $filename;
260 }
261
262 # Unpack the installation set.
263 if ( -d $unpacked_path)
264 {
265 # Take the existence of the destination path as proof that the
266 # installation set was successfully unpacked before.

--- 849 unchanged lines hidden (view full) ---

1116 "Value", $uuid_string
1117 );
1118 $installer::logger::Info->printf("created new PatchGUID %s\n", $uuid_string);
1119
1120 # Prevent sequence table from being generated.
1121 $table->SetRow(
1122 "*Name", "SEQUENCE_DATA_GENERATION_DISABLED",
1123 "Value", 1);
262 return 0 if ! -f $filename;
263 }
264
265 # Unpack the installation set.
266 if ( -d $unpacked_path)
267 {
268 # Take the existence of the destination path as proof that the
269 # installation set was successfully unpacked before.

--- 849 unchanged lines hidden (view full) ---

1119 "Value", $uuid_string
1120 );
1121 $installer::logger::Info->printf("created new PatchGUID %s\n", $uuid_string);
1122
1123 # Prevent sequence table from being generated.
1124 $table->SetRow(
1125 "*Name", "SEQUENCE_DATA_GENERATION_DISABLED",
1126 "Value", 1);
1127
1128 # We don't provide file size and hash values.
1129 # This value is set to make this fact explicit (0 should be the default).
1130 $table->SetRow(
1131 "*Name", "TrustMsi",
1132 "Value", 0);
1124}
1125
1126
1127
1128
1129sub SetupImageFamiliesTable ($)
1130{
1131 my ($pcp) = @_;

--- 220 unchanged lines hidden (view full) ---

1352
1353 # Show the log file that was created by the msimsp.exe command.
1354 ShowLog($log_path, $log_filename, $log_basename, "msp creation");
1355 ShowLog($log_path, $performance_log_filename, $performance_log_basename, "msp creation perf");
1356}
1357
1358
1359
1133}
1134
1135
1136
1137
1138sub SetupImageFamiliesTable ($)
1139{
1140 my ($pcp) = @_;

--- 220 unchanged lines hidden (view full) ---

1361
1362 # Show the log file that was created by the msimsp.exe command.
1363 ShowLog($log_path, $log_filename, $log_basename, "msp creation");
1364 ShowLog($log_path, $performance_log_filename, $performance_log_basename, "msp creation perf");
1365}
1366
1367
1368
1369
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.
1378 4. Create the PCP driver file.
1379 5. Create the MSP patch file.
1380
1381=cut
1360sub CreatePatch ($$)
1361{
1362 my ($context, $variables) = @_;
1363
1364 $installer::logger::Info->printf("patch will update product %s from %s to %s\n",
1365 $context->{'product-name'},
1366 $context->{'source-version'},
1367 $context->{'target-version'});

--- 4 unchanged lines hidden (view full) ---

1372 {
1373 exit(1);
1374 }
1375
1376 my $release_data = installer::patch::ReleasesList::Instance()
1377 ->{$context->{'source-version'}}
1378 ->{$context->{'package-format'}};
1379
1382sub CreatePatch ($$)
1383{
1384 my ($context, $variables) = @_;
1385
1386 $installer::logger::Info->printf("patch will update product %s from %s to %s\n",
1387 $context->{'product-name'},
1388 $context->{'source-version'},
1389 $context->{'target-version'});

--- 4 unchanged lines hidden (view full) ---

1394 {
1395 exit(1);
1396 }
1397
1398 my $release_data = installer::patch::ReleasesList::Instance()
1399 ->{$context->{'source-version'}}
1400 ->{$context->{'package-format'}};
1401
1380 # Create a patch for each language.
1402 # 1. Determine the set of languages for which we can create patches.
1381 my @requested_languages = GetLanguages();
1382 my @valid_languages = FindValidLanguages($context, $release_data, \@requested_languages);
1383 $installer::logger::Info->printf("of the requested languages '%s' are valid: '%s'\n",
1384 join("', '", @requested_languages),
1385 join("', '", @valid_languages));
1386 foreach my $language (@valid_languages)
1387 {
1388 $installer::logger::Info->printf("processing language '%s'\n", $language);
1389 $installer::logger::Info->increase_indentation();
1390
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)
1409 {
1410 $installer::logger::Info->printf("processing language '%s'\n", $language);
1411 $installer::logger::Info->increase_indentation();
1412
1391 # Provide .msi and .cab files and unpacke .cab for the source release.
1413 # 2a. Provide .msi and .cab files and unpacke .cab for the source release.
1392 $installer::logger::Info->printf("locating source package (%s)\n", $context->{'source-version'});
1393 $installer::logger::Info->increase_indentation();
1394 if ( ! installer::patch::InstallationSet::ProvideUnpackedCab(
1395 $context->{'source-version'},
1396 0,
1397 $language,
1398 "msi",
1399 $context->{'product-name'}))

--- 4 unchanged lines hidden (view full) ---

1404 $context->{'source-version'},
1405 0,
1406 $language,
1407 $context->{'product-name'});
1408 die unless $source_msi->IsValid();
1409
1410 $installer::logger::Info->decrease_indentation();
1411
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'}))

--- 4 unchanged lines hidden (view full) ---

1426 $context->{'source-version'},
1427 0,
1428 $language,
1429 $context->{'product-name'});
1430 die unless $source_msi->IsValid();
1431
1432 $installer::logger::Info->decrease_indentation();
1433
1412 # Provide .msi and .cab files and unpacke .cab for the target release.
1434 # 2b. Provide .msi and .cab files and unpacke .cab for the target release.
1413 $installer::logger::Info->printf("locating target package (%s)\n", $context->{'target-version'});
1414 $installer::logger::Info->increase_indentation();
1415 if ( ! installer::patch::InstallationSet::ProvideUnpackedCab(
1416 $context->{'target-version'},
1417 1,
1418 $language,
1419 "msi",
1420 $context->{'product-name'}))

--- 12 unchanged lines hidden (view full) ---

1433 # Trigger reading of tables.
1434 foreach my $table_name (("File", "Component", "Registry"))
1435 {
1436 $source_msi->GetTable($table_name);
1437 $target_msi->GetTable($table_name);
1438 $installer::logger::Info->printf("read %s table (source and target\n", $table_name);
1439 }
1440
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'}))

--- 12 unchanged lines hidden (view full) ---

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
1441 # Check if the source and target msis fullfil all necessary requirements.
1463 # 3. Check if the source and target msis fullfil all necessary requirements.
1442 if ( ! Check($source_msi, $target_msi, $variables, $context->{'product-name'}))
1443 {
1444 $installer::logger::Info->printf("Error: Source and target releases are not compatible.\n");
1445 $installer::logger::Info->printf(" => Can not create patch.\n");
1446 $installer::logger::Info->printf(" Did you create the target installation set with 'release=t' ?\n");
1447 exit(1);
1448 }
1449 else

--- 12 unchanged lines hidden (view full) ---

1462 $source_msi->{'version'})),
1463 installer::patch::Version::ArrayToDirectoryName(
1464 installer::patch::Version::StringToNumberArray(
1465 $target_msi->{'version'}))),
1466 $language
1467 );
1468 File::Path::make_path($msp_path) unless -d $msp_path;
1469
1464 if ( ! Check($source_msi, $target_msi, $variables, $context->{'product-name'}))
1465 {
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 }
1471 else

--- 12 unchanged lines hidden (view full) ---

1484 $source_msi->{'version'})),
1485 installer::patch::Version::ArrayToDirectoryName(
1486 installer::patch::Version::StringToNumberArray(
1487 $target_msi->{'version'}))),
1488 $language
1489 );
1490 File::Path::make_path($msp_path) unless -d $msp_path;
1491
1470 # Create the .pcp file that drives the msimsp.exe command.
1492 # 4. Create the .pcp file that drives the msimsp.exe command.
1471 my $pcp = CreatePcp(
1472 $source_msi,
1473 $target_msi,
1474 $language,
1475 $context,
1476 $msp_path,
1477 $pcp_schema_filename,
1493 my $pcp = CreatePcp(
1494 $source_msi,
1495 $target_msi,
1496 $language,
1497 $context,
1498 $msp_path,
1499 $pcp_schema_filename,
1478 "Properties/Name:DontRemoveTempFolderWhenFinished" => "Value:1",
1479 "Properties/Name:SEQUENCE_DATA_GENERATION_DISABLED" => "Value:1",
1480 "Properties/Name:TrustMsi" => "Value:0",
1481 "Properties/Name:ProductName" => "Value:OOO341");
1500 "Properties/Name:DontRemoveTempFolderWhenFinished" => "Value:1");
1482
1501
1483 # Finally create the msp.
1502 # 5. Finally create the msp.
1484 CreateMsp($pcp);
1485
1486 $installer::logger::Info->decrease_indentation();
1487 }
1488}
1489
1490
1491
1503 CreateMsp($pcp);
1504
1505 $installer::logger::Info->decrease_indentation();
1506 }
1507}
1508
1509
1510
1511=cut ApplyPatch ($context, $variables)
1492
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
1493sub ApplyPatch ($$)
1494{
1495 my ($context, $variables) = @_;
1496
1497 $installer::logger::Info->printf("will apply patches that update product %s from %s to %s\n",
1498 $context->{'product-name'},
1499 $context->{'source-version'},
1500 $context->{'target-version'});

--- 41 unchanged lines hidden (view full) ---

1542
1543 ShowLog($log_path, $log_filename, $log_basename, "msp application");
1544 }
1545}
1546
1547
1548
1549
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'});

--- 41 unchanged lines hidden (view full) ---

1566
1567 ShowLog($log_path, $log_filename, $log_basename, "msp application");
1568 }
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
1577 setup the $release_data structure that is used by InstallationSet::Download().
1578
1579=cut
1580sub DownloadFile ($)
1581{
1582 my ($url) = shift;
1583
1584 my $agent = LWP::UserAgent->new();
1585 $agent->timeout(120);
1586 $agent->show_progress(0);
1587
1588 my $file_content = "";
1589 my $last_was_redirect = 0;
1590 my $bytes_read = 0;
1591 $agent->add_handler('response_redirect'
1592 => sub{
1593 $last_was_redirect = 1;
1594 return;
1595 });
1596 $agent->add_handler('response_data'
1597 => sub{
1598 if ($last_was_redirect)
1599 {
1600 $last_was_redirect = 0;
1601 # Throw away the data we got so far.
1602 $file_content = "";
1603 }
1604 my($response,$agent,$h,$data)=@_;
1605 $file_content .= $data;
1606 });
1607 $agent->get($url);
1608
1609 return $file_content;
1610}
1611
1612
1613
1614
1615sub CreateReleaseItem ($$$)
1616{
1617 my ($language, $exe_filename, $msi) = @_;
1618
1619 die "can not open installation set at ".$exe_filename unless -f $exe_filename;
1620
1621 open my $in, "<", $exe_filename;
1622 my $sha256_checksum = new Digest("SHA-256")->addfile($in)->hexdigest();
1623 close $in;
1624
1625 my $filesize = -s $exe_filename;
1626
1627 # Get the product code property from the msi and strip the enclosing braces.
1628 my $product_code = $msi->GetTable("Property")->GetValue("Property", "ProductCode", "Value");
1629 $product_code =~ s/(^{|}$)//g;
1630 my $upgrade_code = $msi->GetTable("Property")->GetValue("Property", "UpgradeCode", "Value");
1631 $upgrade_code =~ s/(^{|}$)//g;
1632 my $build_id = $msi->GetTable("Property")->GetValue("Property", "PRODUCTBUILDID", "Value");
1633
1634 return {
1635 'language' => $language,
1636 'checksum-type' => "sha256",
1637 'checksum-value' => $sha256_checksum,
1638 'file-size' => $filesize,
1639 'product-code' => $product_code,
1640 'upgrade-code' => $upgrade_code,
1641 'build-id' => $build_id
1642 };
1643}
1644
1645
1646
1647
1648sub GetReleaseItemForCurrentBuild ($$$)
1649{
1650 my ($context, $language, $exe_basename) = @_;
1651
1652 # Target version is the current version.
1653 # Search instsetoo_native for the installation set.
1654 my $filename = File::Spec->catfile(
1655 $context->{'output-path'},
1656 $context->{'product-name'},
1657 $context->{'package-format'},
1658 "install",
1659 $language."_download",
1660 $exe_basename);
1661
1662 printf(" current : %s\n", $filename);
1663 if ( ! -f $filename)
1664 {
1665 printf("ERROR: can not find %s\n", $filename);
1666 return undef;
1667 }
1668 else
1669 {
1670 my $msi = installer::patch::Msi->FindAndCreate(
1671 $context->{'target-version'},
1672 1,
1673 $language,
1674 $context->{'product-name'});
1675 return CreateReleaseItem($language, $filename, $msi);
1676 }
1677}
1678
1679
1680
1681sub GetReleaseItemForOldBuild ($$$$)
1682{
1683 my ($context, $language, $exe_basename, $url_template) = @_;
1684
1685 # Use ext_sources/ as local cache for archive.apache.org
1686 # and search these for the installation set.
1687
1688 my $version = $context->{'target-version'};
1689 my $package_format = $context->{'package-format'};
1690 my $releases_list = installer::patch::ReleasesList::Instance();
1691
1692 my $url = $url_template;
1693 $url =~ s/%L/$language/g;
1694 $releases_list->{$version}->{$package_format}->{$language}->{'URL'} = $url;
1695
1696 if ( ! installer::patch::InstallationSet::ProvideUnpackedExe(
1697 $version,
1698 0,
1699 $language,
1700 $package_format,
1701 $context->{'product-name'}))
1702 {
1703 # Can not provide unpacked EXE.
1704 return undef;
1705 }
1706 else
1707 {
1708 my $exe_filename = File::Spec->catfile(
1709 $ENV{'TARFILE_LOCATION'},
1710 $exe_basename);
1711 my $msi = installer::patch::Msi->FindAndCreate(
1712 $version,
1713 0,
1714 $language,
1715 $context->{'product-name'});
1716 return CreateReleaseItem($language, $exe_filename, $msi);
1717 }
1718}
1719
1720
1721
1722
1723sub UpdateReleasesXML($$)
1724{
1725 my ($context, $variables) = @_;
1726
1727 my $releases_list = installer::patch::ReleasesList::Instance();
1728 my $output_filename = File::Spec->catfile(
1729 $context->{'output-path'},
1730 "misc",
1731 "releases.xml");
1732
1733 my $target_version = $context->{'target-version'};
1734 my %version_hash = map {$_=>1} @{$releases_list->{'releases'}};
1735 my $item_hash = undef;
1736 if ( ! defined $version_hash{$context->{'target-version'}})
1737 {
1738 # Target version is not yet present. Add it and print message that asks caller to check order.
1739 push @{$releases_list->{'releases'}}, $target_version;
1740 printf("adding data for new version %s to list of released versions.\n", $target_version);
1741 printf("please check order of releases in $output_filename\n");
1742 $item_hash = {};
1743 }
1744 else
1745 {
1746 printf("adding data for existing version %s to releases.xml\n", $target_version);
1747 $item_hash = $releases_list->{$target_version}->{$context->{'package-format'}};
1748 }
1749 $releases_list->{$target_version} = {$context->{'package-format'} => $item_hash};
1750
1751 my @languages = GetLanguages();
1752 my %language_items = ();
1753 foreach my $language (@languages)
1754 {
1755 # There are three different sources where to find the downloadable installation sets.
1756 # 1. archive.apache.org for previously released versions.
1757 # 2. A local cache or repository directory that conceptually is a local copy of archive.apache.org
1758 # 3. The downloadable installation sets built in instsetoo_native/.
1759
1760 my $exe_basename = sprintf(
1761 "%s_%s_Win_x86_install_%s.exe",
1762 $context->{'product-name'},
1763 $target_version,
1764 $language);
1765 my $url_template = sprintf(
1766 "http://archive.apache.org/dist/openoffice/%s/binaries/%%L/%s_%s_Win_x86_install_%%L.exe",
1767 $target_version,
1768 $context->{'product-name'},
1769 $target_version);
1770
1771 my $item = undef;
1772 if ($target_version eq $variables->{PRODUCTVERSION})
1773 {
1774 $item = GetReleaseItemForCurrentBuild($context, $language, $exe_basename);
1775 }
1776 else
1777 {
1778 $item = GetReleaseItemForOldBuild($context, $language, $exe_basename, $url_template);
1779 }
1780
1781 next unless defined $item;
1782
1783 $language_items{$language} = $item;
1784 $item_hash->{$language} = $item;
1785 $item_hash->{'upgrade-code'} = $item->{'upgrade-code'};
1786 $item_hash->{'build-id'} = $item->{'build-id'};
1787 $item_hash->{'url-template'} = $url_template;
1788 }
1789
1790 my @valid_languages = sort keys %language_items;
1791 $item_hash->{'languages'} = \@valid_languages;
1792
1793 $releases_list->Write($output_filename);
1794
1795 printf("\n\n");
1796 printf("please copy '%s' to main/instsetoo_native/data\n", $output_filename);
1797 printf("and check in the modified file to the version control system\n");
1798}
1799
1800
1801
1802
1550sub main ()
1551{
1552 installer::logger::SetupSimpleLogging(undef);
1553 my $context = ProcessCommandline();
1803sub main ()
1804{
1805 installer::logger::SetupSimpleLogging(undef);
1806 my $context = ProcessCommandline();
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'};
1811
1554 my ($variables, undef, undef) = installer::ziplist::read_openoffice_lst_file(
1555 $context->{'lst-file'},
1556 $context->{'product-name'},
1557 undef);
1558 DetermineVersions($context, $variables);
1559
1560 if ($context->{'command'} eq "create")
1561 {
1562 CreatePatch($context, $variables);
1563 }
1564 elsif ($context->{'command'} eq "apply")
1565 {
1566 ApplyPatch($context, $variables);
1567 }
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
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 }
1568}
1569
1570
1571main();
1830}
1831
1832
1833main();