1#!/usr/bin/perl 2#************************************************************** 3# 4# Licensed to the Apache Software Foundation (ASF) under one 5# or more contributor license agreements. See the NOTICE file 6# distributed with this work for additional information 7# regarding copyright ownership. The ASF licenses this file 8# to you under the Apache License, Version 2.0 (the 9# "License"); you may not use this file except in compliance 10# with the License. You may obtain a copy of the License at 11# 12# http://www.apache.org/licenses/LICENSE-2.0 13# 14# Unless required by applicable law or agreed to in writing, 15# software distributed under the License is distributed on an 16# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17# KIND, either express or implied. See the License for the 18# specific language governing permissions and limitations 19# under the License. 20# 21#************************************************************** 22 23use strict; 24use XML::LibXML; 25use open OUT => ":utf8"; 26use LWP::Simple; 27use Digest; 28use Digest::MD5; 29use Digest::SHA; 30 31use Carp::always; 32 33=head1 NAME 34 35 build_release.pl - Tool for batch release builds and uploads and the creation of wiki pages that list install sets. 36 37=head1 SYNOPSIS 38 39 build_release.pl <command> {option} <release-description.xml> 40 41 comands: 42 build builds all install sets as requested by the XML file and supported by the platform. 43 upload upload install sets to a local or remote (via ssh with public/private key) 44 directory structure. Uploads install sets that where build on other platforms. 45 wiki create a wiki (MediaWiki syntax) snippet that references all install sets at the upload 46 location. Includes install sets that where built and/or uploaded from other 47 platforms and machines. 48 options: 49 -j <count> maximum number of build processes 50 -k keep going if there are recoverable errors 51 -u <path> upload destination 52 -l check links on wiki page, write broken links as plain text 53 -ld check links on wiki page, mark broken links 54 -o <filename> filename of the output (wiki: wiki page, build: makefile) 55 56=head1 XML file format 57 58<release 59 name="snapshot" 60 version="4.1.0"> 61 62 <language 63 id="ast" # As specified by 'configure --with-lang' 64 english-name="Asturian" 65 local-name="Asturianu" 66 /> 67 ... more languages 68 69 <platform 70 id="wntmsci12.pro" 71 display-name="Windows" 72 base-url="http://people.apache.org/~hdu/developer-snapshots/snapshot/win32" 73 archive-platform="Win_x86" 74 word-size="32" 75 package-types="exe" 76 /> 77 ... more platforms 78 79 <build 80 target="openoffice" 81 platform-list="all" 82 language-list="all"> 83 </build> 84 ... more build entries 85 86 <wiki> 87 88 # Each wiki package will generate one row per language. 89 # For each language there will be one package block. 90 <package 91 display-name="Full Install" 92 archive-name1="" 93 archive-name2="install" 94 language-list="all" 95 platform-list="all" 96 table="main" 97 /> 98 ... more packages 99 </wiki> 100 101</release> 102 103=cut 104 105 106 107my %PlatformDescriptors = ( 108 "wntmsci12" => { 109 'name' => "windows", 110 'extension' => "exe", 111 'pack-platform' => "Win_x86", 112 'package-formats' => ["msi"] 113 }, 114 "unxmaccxi" => { 115 'name' => "unxmaccx_x86-64", 116 'extension' => "dmg", 117 'pack-platform' => "MacOS_x86", 118 'package-formats' => ["dmg"] 119 }, 120 "unxlngi6" => { 121 'name' => "Linux_x86", 122 'extension' => "tar.gz", 123 'pack-platform' => "Linux_x86", 124 'package-formats' => ["deb", "rpm"] 125 }, 126 "unxlngx6" => { 127 'name' => "Linux_x86-64", 128 'extension' => "tar.gz", 129 'pack-platform' => "Linux_x86-64", 130 'package-formats' => ["deb", "rpm"] 131 } 132); 133my %ProductDescriptors = ( 134 "openoffice" => { 135 'pack-name' => "install", 136 'product-name-tail' => "" 137 }, 138 "oolanguagepack" => { 139 'pack-name' => "langpack", 140 'product-name-tail' => "_languagepack" 141 } 142); 143my %EnUSBasedLanguages = ( 144 'ast' => 1 145 ); 146 147 148 149sub ProcessCommandline (@) 150{ 151 my @arguments = @_; 152 153 my $command = undef; 154 my $description_filename = undef; 155 my $max_process_count = 1; 156 my $keep_going = 0; 157 my $upload_destination = undef; 158 my $check_links = 0; 159 my $mark_broken_links = 0; 160 my $output_filename = undef; 161 162 my $error = 0; 163 while (scalar @arguments > 0) 164 { 165 my $argument = shift @arguments; 166 if ($argument =~ /^-/) 167 { 168 if ($argument eq "-j") 169 { 170 $max_process_count = shift @arguments; 171 } 172 elsif ($argument eq "-u") 173 { 174 $upload_destination = shift @arguments; 175 $upload_destination =~ s/(\\|\/)$//; 176 } 177 elsif ($argument eq "-k") 178 { 179 $keep_going = 1; 180 } 181 elsif ($argument eq "-l") 182 { 183 $check_links = 1; 184 } 185 elsif ($argument eq "-ld") 186 { 187 $check_links = 1; 188 $mark_broken_links = 1; 189 } 190 elsif ($argument eq "-o") 191 { 192 $output_filename = shift @arguments; 193 } 194 else 195 { 196 printf STDERR "unknown option $argument %s\n", $argument; 197 $error = 1; 198 } 199 } 200 elsif ( ! defined $command) 201 { 202 $command = $argument; 203 if ($command !~ /^(build|upload|wiki)$/) 204 { 205 printf STDERR "unknown command '%s'\n", $command; 206 $error = 1; 207 } 208 } 209 else 210 { 211 $description_filename = $argument; 212 if ( ! -f $description_filename) 213 { 214 print STDERR "can not open release description '%s'\n", $description_filename; 215 $error = 1; 216 } 217 } 218 } 219 220 if ( ! defined $description_filename) 221 { 222 $error = 1; 223 } 224 if ($command =~ /^(build|wiki)$/) 225 { 226 if ( ! defined $output_filename) 227 { 228 printf STDERR "ERROR: no output filename\n", 229 $error = 1; 230 } 231 } 232 233 if ($error) 234 { 235 PrintUsageAndExit(); 236 } 237 238 return { 239 'command' => $command, 240 'filename' => $description_filename, 241 'max-process-count' => $max_process_count, 242 'keep-going' => $keep_going, 243 'upload-destination' => $upload_destination, 244 'check-links' => $check_links, 245 'mark-broken-links' => $mark_broken_links, 246 'output-filename' => $output_filename 247 }; 248} 249 250 251 252 253sub PrintUsageAndExit () 254{ 255 print STDERR "usage: $0 <command> {option} <release-description.xml>\n"; 256 print STDERR " comands:\n"; 257 print STDERR " build\n"; 258 print STDERR " upload\n"; 259 print STDERR " wiki create a download page in MediaWiki syntax\n"; 260 print STDERR " options:\n"; 261 print STDERR " -j <count> maximum number of build processes\n"; 262 print STDERR " -k keep going if there are recoverable errors\n"; 263 print STDERR " -u <path> upload destination\n"; 264 print STDERR " -l check links on wiki page, write broken links as plain text\n"; 265 print STDERR " -ld check links on wiki page, mark broken links\n"; 266 print STDERR " -o <filename> filename of the output (wiki: wiki page, build: makefile)\n"; 267 exit(1); 268} 269 270 271 272 273sub Trim ($) 274{ 275 my ($text) = @_; 276 $text =~ s/^\s+|\s+$//g; 277 return $text; 278} 279 280 281 282 283sub ReadReleaseDescription ($$) 284{ 285 my ($filename, $context) = @_; 286 287 my $document = XML::LibXML->load_xml('location' => $filename); 288 my $root = $document->documentElement(); 289 290 # Initialize the release description. 291 my $release = { 292 'name' => $root->getAttribute("name"), 293 'version' => $root->getAttribute("version"), 294 'builds' => [], 295 'languages' => {}, 296 'language-ids' => [], 297 'platforms' => {}, 298 'platform-ids' => [], 299 'wiki-packages' => [], 300 }; 301 302 # Process the language descriptions. 303 for my $language_element ($root->getChildrenByTagName("language")) 304 { 305 my $language_descriptor = ProcessLanguageDescription($language_element, $context); 306 $release->{'languages'}->{$language_descriptor->{'id'}} = $language_descriptor; 307 push @{$release->{'language-ids'}}, $language_descriptor->{'id'}; 308 } 309 printf "%d languages\n", scalar keys %{$release->{'languages'}}; 310 311 # Process the platform descriptions. 312 for my $platform_element ($root->getChildrenByTagName("platform")) 313 { 314 foreach my $platform_descriptor (ProcessPlatformDescription($platform_element, $context)) 315 { 316 $release->{'platforms'}->{$platform_descriptor->{'id'}} = $platform_descriptor; 317 push @{$release->{'platform-ids'}}, $platform_descriptor->{'id'}; 318 } 319 } 320 printf "%d platforms\n", scalar keys %{$release->{'platforms'}}; 321 322 if ($context->{'command'} =~ /^(build|upload)$/) 323 { 324 # Process the build descriptions. 325 for my $build_element ($root->getChildrenByTagName("build")) 326 { 327 push @{$release->{'builds'}}, ProcessBuildDescription($build_element, $context, $release); 328 } 329 printf "%d build targets\n", scalar @{$release->{'builds'}}; 330 } 331 332 if ($context->{'command'} eq "wiki") 333 { 334 for my $wiki_element ($root->getChildrenByTagName("wiki")) 335 { 336 for my $wiki_package_element ($wiki_element->getChildrenByTagName("package")) 337 { 338 my $wiki_package = ProcessWikiPackageDescription( 339 $wiki_package_element, 340 $context, 341 $release); 342 push @{$release->{'wiki-packages'}}, $wiki_package; 343 } 344 } 345 printf "%d wiki packages\n", scalar @{$release->{'wiki-packages'}}; 346 } 347 348 return $release; 349} 350 351 352 353 354sub ProcessBuildDescription ($$$) 355{ 356 my ($build_element, $context, $release_descriptor) = @_; 357 358 my $target_name = $build_element->getAttribute("target"); 359 my $languages = PostprocessLanguageList($build_element->getAttribute("language-list"), $release_descriptor); 360 my $platforms = PostprocessPlatformList($build_element->getAttribute("platform-list"), $release_descriptor); 361 362 # Check if the platform matches any for which the product shall be built. 363 my $current_platform = $ENV{'INPATH'}; 364 my $is_platform_match = 0; 365 foreach my $platform_id (@$platforms) 366 { 367 if ($platform_id eq $current_platform) 368 { 369 $is_platform_match=1; 370 last; 371 } 372 } 373 if ($is_platform_match) 374 { 375 printf "including build %s\n", $target_name; 376 } 377 else 378 { 379 printf "skipping build %s: no platform match\n", $target_name; 380 printf "none of the platforms %s matches %s\n", 381 join(", ", keys %{$release_descriptor->{'platforms'}}), 382 $current_platform; 383 return; 384 } 385 386 my @languages = CheckLanguageSet($context, @$languages); 387 388 return { 389 'target' => $target_name, 390 'language-list' => \@languages 391 }; 392} 393 394 395 396 397sub ProcessPlatformDescription ($$) 398{ 399 my ($element, $context) = @_; 400 401 my $descriptor = {}; 402 # Mandatory tags. 403 foreach my $id ("id", "display-name", "base-url", "archive-platform", "word-size", "package-types") 404 { 405 $descriptor->{$id} = $element->getAttribute($id); 406 die "wiki/platform has no attribute $id" unless defined $descriptor->{$id}; 407 } 408 $descriptor->{"extension"} = $element->getAttribute("extension"); 409 410 # Split package-types at ';' into single package-type entries. 411 my @descriptors = (); 412 foreach my $package_type (split(/;/, $descriptor->{'package-types'})) 413 { 414 push @descriptors, { 415 %$descriptor, 416 'package-type' => $package_type 417 }; 418 } 419 420 return @descriptors; 421} 422 423 424 425 426sub ProcessWikiPackageDescription ($$$) 427{ 428 my ($element, $context, $release_descriptor) = @_; 429 430 my $descriptor = {}; 431 # Mandatory tags. 432 foreach my $id ("archive-name2", "display-name", "table") 433 { 434 $descriptor->{$id} = $element->getAttribute($id); 435 die "wiki/package has no attribute $id" unless defined $descriptor->{$id}; 436 die "wiki/package attribute $id is empty" unless $descriptor->{$id} !~ /^\s*$/; 437 } 438 # Optional tags. 439 foreach my $id ("archive-name1", "link-tooltip", "link-URL", "download-extension") 440 { 441 $descriptor->{$id} = $element->getAttribute($id); 442 } 443 444 $descriptor->{'language-list'} = PostprocessLanguageList( 445 $element->getAttribute("language-list"), 446 $release_descriptor); 447 $descriptor->{'platform-list'} = PostprocessPlatformList( 448 $element->getAttribute("platform-list"), 449 $release_descriptor); 450 451 $descriptor->{'languages'} = {map{$_=>1} @{$descriptor->{'language-list'}}}; 452 $descriptor->{'platforms'} = {map{$_=>1} @{$descriptor->{'platform-list'}}}; 453 454 return $descriptor; 455} 456 457 458 459 460sub ProcessLanguageDescription ($$) 461{ 462 my ($element, $context) = @_; 463 464 my $descriptor = {}; 465 foreach my $id ("id", "english-name", "local-name") 466 { 467 $descriptor->{$id} = $element->getAttribute($id); 468 die "wiki/language has no attribute $id" unless defined $descriptor->{$id}; 469 } 470 471 return $descriptor; 472} 473 474 475 476 477sub PostprocessLanguageList ($$) 478{ 479 my ($language_list, $release_descriptor) = @_; 480 481 my @matching_languages = (); 482 if ( ! defined $language_list 483 || $language_list eq "all") 484 { 485 @matching_languages = sort keys %{$release_descriptor->{'languages'}}; 486 } 487 else 488 { 489 @matching_languages = split(/;/, $language_list); 490 } 491 492 return \@matching_languages; 493} 494 495 496 497 498sub PostprocessPlatformList ($$) 499{ 500 my ($platform_list, $release_descriptor) = @_; 501 502 my @matching_platforms = (); 503 if ( ! defined $platform_list 504 || $platform_list eq "all") 505 { 506 @matching_platforms = sort keys %{$release_descriptor->{'platforms'}}; 507 } 508 else 509 { 510 @matching_platforms = split(/;/, $platform_list); 511 } 512 513 return \@matching_platforms; 514} 515 516 517 518 519sub CheckLanguageSet ($@) 520{ 521 my ($context, @languages) = @_; 522 my %configured_languages = map{$_=>1} split(/\s+/, $ENV{'WITH_LANG'}); 523 524 my @missing_languages = (); 525 my @present_languages = (); 526 for my $language (@languages) 527 { 528 if (defined $configured_languages{$language}) 529 { 530 push @present_languages, $language; 531 } 532 else 533 { 534 push @missing_languages, $language; 535 } 536 } 537 538 if (scalar @missing_languages > 0) 539 { 540 printf STDERR " there are languages that where not configured via --with-lang:\n"; 541 printf STDERR " %s\n", join(", ", @missing_languages); 542 if ($context->{'keep-going'}) 543 { 544 printf " available languages:\n"; 545 printf " %s\n", join(", ", @present_languages); 546 } 547 else 548 { 549 die; 550 } 551 } 552 553 return @present_languages; 554} 555 556 557 558 559sub WriteMakefile ($$) 560{ 561 my ($release_description, $output_filename) = @_; 562 563 my $path = $ENV{'SRC_ROOT'} . "/instsetoo_native/util"; 564 open my $make, ">", $output_filename; 565 566 # Write dependencies of 'all' on the products in all languages. 567 print $make "all .PHONY : \\\n"; 568 for my $build (@{$release_description->{'builds'}}) 569 { 570 for my $language_id (@{$build->{'language-list'}}) 571 { 572 printf $make " %s_%s \\\n", $build->{'target'}, $language_id; 573 } 574 } 575 printf $make "\n\n"; 576 577 # Write rules that chain dmake in instsetoo_native/util. 578 for my $build (@{$release_description->{'builds'}}) 579 { 580 for my $language_id (@{$build->{'language-list'}}) 581 { 582 printf $make "%s_%s :\n", $build->{'target'}, $language_id; 583 printf $make "\tdmake \$@ release=t\n"; 584 } 585 } 586 587 close $make; 588} 589 590 591 592 593sub Upload ($$) 594{ 595 my ($release_description, $context) = @_; 596 597 if ( ! defined $context->{'upload-destination'}) 598 { 599 printf STDERR "ERROR: upload destination is missing\n"; 600 PrintUsageAndExit(); 601 } 602 603 my @download_sets = CollectDownloadSets($release_description); 604 my @actions = GetCopyActions($release_description, @download_sets); 605 foreach my $action (@actions) 606 { 607 printf "uploading %s to %s/%s\n", 608 $action->{'basename'}, 609 $context->{'upload-destination'}, 610 $action->{'to'}; 611 612 613 ProvideChecksums($action); 614 if ($context->{'upload-destination'} =~ /@/) 615 { 616 my $destination = $action->{'to'}; 617 my $server = $context->{'upload-destination'}; 618 if ($server =~ /^(.*):(.*)$/) 619 { 620 $server = $1; 621 $destination = $2 . "/" . $destination; 622 } 623 624 my @path_parts = split(/\//, $destination); 625 my @paths = (); 626 my $path = undef; 627 foreach my $part (@path_parts) 628 { 629 if (defined $path) 630 { 631 $path .= "/" . $part; 632 } 633 else 634 { 635 $path = $part; 636 } 637 push @paths, $path; 638 } 639 my $command = sprintf("ssh %s mkdir \"%s\"", 640 $server, 641 join("\" \"", @paths)); 642 printf "running command '%s'\n", $command; 643 system($command); 644 645 my $command = sprintf("scp %s %s/%s/", 646 qx(cygpath -u \"$action->{'from'}\"), 647 $context->{'upload-destination'}, 648 $action->{'to'}); 649 printf "running command '%s'\n", $command; 650 system($command); 651 652 my $command = sprintf("ssh %s md5 \"%s/%s\"", 653 $server, 654 $destination, 655 $action->{'basename'}); 656 printf "running command '%s'\n", $command; 657 system($command); 658 } 659 } 660} 661 662 663 664 665sub CollectDownloadSets ($) 666{ 667 my ($release_description) = @_; 668 669 my @download_sets = (); 670 my $platform_descriptor = GetPlatformDescriptor(); 671 672 for my $build (@{$release_description->{'builds'}}) 673 { 674 my $product_descriptor = GetProductDescriptor($build->{'target'}); 675 print $build->{'target'}."\n"; 676 my @package_formats = @{$platform_descriptor->{'package-formats'}}; 677 for my $package_format (@package_formats) 678 { 679 for my $language (@{$build->{'language-list'}}) 680 { 681 my $full_language = $language; 682 if ($EnUSBasedLanguages{$language}) 683 { 684 $full_language = "en-US_".$language; 685 } 686 my $archive_name = GetInstallationPackageName($build, $language); 687 688 my $source_path = sprintf("%s/instsetoo_native/%s/Apache_OpenOffice%s/%s/install/%s_download", 689 $ENV{'SOLARSRC'}, 690 $ENV{'INPATH'}, 691 $product_descriptor->{'product-name-tail'}, 692 $package_format, 693 $full_language); 694 if ( ! -f $source_path."/".$archive_name) 695 { 696 printf STDERR "ERROR: can not find download set '%s'\n", $source_path; 697 next; 698 } 699 push @download_sets, { 700 'source-path' => $source_path, 701 'archive-name' => $archive_name, 702 'platform' => $platform_descriptor->{'pack-platform'} 703 }; 704 } 705 } 706 } 707 708 return @download_sets; 709} 710 711 712 713 714sub ProvideChecksums ($) 715{ 716 my ($action) = @_; 717 718 printf "creating checksums for %s\n", $action->{'basename'}; 719 my $full_archive_name = $action->{'from'} . "/" . $action->{'basename'}; 720 721 my $digest = Digest::MD5->new(); 722 open my $in, $full_archive_name; 723 $digest->addfile($in); 724 $action->{"MD5"} = $digest->hexdigest(); 725 close $in; 726 727 my $digest = Digest::SHA->new("sha256"); 728 open my $in, $full_archive_name; 729 $digest->addfile($in); 730 $action->{"SHA256"} = $digest->hexdigest(); 731 close $in; 732} 733 734 735 736 737sub GetCopyActions ($@) 738{ 739 my ($release_description, @download_sets) = @_; 740 741 my $platform_descriptor = GetPlatformDescriptor(); 742 743 my @actions = (); 744 745 for my $download_set (@download_sets) 746 { 747 my $destination_path = sprintf("developer-snapshots/%s/%s", 748 $release_description->{'name'}, 749 $platform_descriptor->{'pack-platform'}); 750 751 push @actions, { 752 'action'=>'copy', 753 'from' => $download_set->{'source-path'}, 754 'to' => $destination_path, 755 'basename' => $download_set->{'archive-name'} 756 }; 757 } 758 759 return @actions; 760} 761 762 763 764 765sub GetInstallationPackageName ($$) 766{ 767 my ($build, $language) = @_; 768 769 my $platform_descriptor = GetPlatformDescriptor(); 770 my $build_descriptor = GetProductDescriptor($build->{'target'}); 771 my $name = sprintf ("Apache_OpenOffice_%s_%s_%s_%s.%s", 772 "4.1.0", 773 $platform_descriptor->{'pack-platform'}, 774 $build_descriptor->{'pack-name'}, 775 $language, 776 $platform_descriptor->{'extension'}); 777 return $name; 778} 779 780 781 782 783sub GetPlatformDescriptor () 784{ 785 if ( ! defined $ENV{'OUTPATH'}) 786 { 787 printf STDERR "ERROR: solar environment not loaded or broken (OUTPATH not defined)\n"; 788 die; 789 } 790 my $descriptor = $PlatformDescriptors{$ENV{'OUTPATH'}}; 791 if ( ! defined $descriptor) 792 { 793 printf STDERR "ERROR: platform '%s' is not yet supported\n", $ENV{'OUTPATH'}; 794 die; 795 } 796 return $descriptor; 797} 798 799 800 801 802sub GetProductDescriptor ($) 803{ 804 my ($product_name) = @_; 805 my $descriptor = $ProductDescriptors{$product_name}; 806 if ( ! defined $descriptor) 807 { 808 printf STDERR "ERROR: product '%s' is not supported\n", $product_name; 809 } 810 return $descriptor; 811} 812 813 814 815 816sub Wiki ($$) 817{ 818 my ($release_descriptor, $context) = @_; 819 820 open my $out, ">", $context->{'output-filename'}; 821 822 my @table_list = GetTableList($release_descriptor); 823 foreach my $table_name (@table_list) 824 { 825 my @table_packages = GetPackagesForTable($release_descriptor, $table_name); 826 my @table_languages = GetLanguagesForTable($release_descriptor, @table_packages); 827 my @table_platforms = GetPlatformsForTable($release_descriptor, @table_packages); 828 829 printf "packages: %s\n", join(", ", map {$_->{'display-name'}} @table_packages); 830 printf "languages: %s\n", join(", ", map {$_->{'english-name'}} @table_languages); 831 printf "platforms: %s\n", join(", ", map {$_->{'id'}} @table_platforms); 832 833 print $out "{| class=\"wikitable\"\n"; 834 print $out "|-\n"; 835 print $out "! colspan=\"2\" | Language<br>The names do not refer to countries\n"; 836 print $out "! Type\n"; 837 foreach my $platform_descriptor (@table_platforms) 838 { 839 printf $out "! %s<br>%s bit<br>%s\n", 840 $platform_descriptor->{'display-name'}, 841 $platform_descriptor->{'word-size'}, 842 uc($platform_descriptor->{'package-type'}); 843 } 844 845 foreach my $language_descriptor (@table_languages) 846 { 847 if ($context->{'check-links'}) 848 { 849 $| = 1; 850 printf "%s: ", $language_descriptor->{'id'}; 851 } 852 853 print $out "|-\n"; 854 printf $out "| rowspan=\"%d\" | %s\n", scalar @table_packages, $language_descriptor->{'english-name'}; 855 printf $out "| rowspan=\"%d\" | %s\n", scalar @table_packages, $language_descriptor->{'local-name'}; 856 857 my $is_first = 1; 858 foreach my $package_descriptor (@table_packages) 859 { 860 if ($is_first) 861 { 862 $is_first = 0; 863 } 864 else 865 { 866 printf $out "|-\n"; 867 } 868 869 # Write the name of the package, e.g. Full Install or Langpack. 870 if (defined $package_descriptor->{'link-URL'}) 871 { 872 printf $out "| [%s %s]\n", 873 $package_descriptor->{'link-URL'}, 874 $package_descriptor->{'display-name'}; 875 } 876 else 877 { 878 printf $out "| %s\n", $package_descriptor->{'display-name'}; 879 } 880 881 foreach my $platform_descriptor (@table_platforms) 882 { 883 WriteDownloadLinks( 884 $out, 885 $context, 886 $release_descriptor, 887 $language_descriptor, 888 $package_descriptor, 889 $platform_descriptor); 890 } 891 } 892 893 if ($context->{'check-links'}) 894 { 895 printf "\n"; 896 } 897 } 898 899 print $out "|}\n"; 900 } 901 close $out; 902} 903 904 905 906 907sub GetTableList ($) 908{ 909 my ($release_descriptor) = @_; 910 911 my %seen_table_names = (); 912 my @table_names = (); 913 foreach my $package_descriptor (@{$release_descriptor->{'wiki-packages'}}) 914 { 915 my $table_name = $package_descriptor->{'table'}; 916 if ( ! $seen_table_names{$table_name}) 917 { 918 push @table_names, $table_name; 919 $seen_table_names{$table_name} = 1; 920 } 921 } 922 return @table_names; 923} 924 925 926 927 928sub GetPackagesForTable ($$) 929{ 930 my ($release_descriptor, $table_name) = @_; 931 932 my @packages = (); 933 foreach my $package_descriptor (@{$release_descriptor->{'wiki-packages'}}) 934 { 935 if ($package_descriptor->{'table'} eq $table_name) 936 { 937 push @packages, $package_descriptor; 938 } 939 } 940 return @packages; 941} 942 943 944 945 946sub GetLanguagesForTable ($@) 947{ 948 my ($release_descriptor, @packages) = @_; 949 950 # Find the languages that are reference by at least one package. 951 my %matching_languages = (); 952 foreach my $package_descriptor (@packages) 953 { 954 foreach my $language_id (@{$package_descriptor->{'language-list'}}) 955 { 956 $matching_languages{$language_id} = 1; 957 } 958 } 959 960 # Retrieve the language descriptors for the language ids. 961 my @matching_language_descriptors = (); 962 foreach my $language_id (@{$release_descriptor->{'language-ids'}}) 963 { 964 if (defined $matching_languages{$language_id}) 965 { 966 my $language_descriptor = $release_descriptor->{'languages'}->{$language_id}; 967 if (defined $language_descriptor) 968 { 969 push @matching_language_descriptors, $language_descriptor; 970 } 971 } 972 } 973 974 return @matching_language_descriptors; 975} 976 977 978 979 980sub GetPlatformsForTable ($@) 981{ 982 my ($release_descriptor, @packages) = @_; 983 984 # Find the platforms that are reference by at least one package. 985 my %matching_platform_ids = (); 986 foreach my $package_descriptor (@packages) 987 { 988 foreach my $platform_id (@{$package_descriptor->{'platform-list'}}) 989 { 990 $matching_platform_ids{$platform_id} = 1; 991 } 992 } 993 994 # Retrieve the platform descriptors for the plaform ids. 995 my @matching_platform_descriptors = (); 996 foreach my $platform_id (@{$release_descriptor->{'platform-ids'}}) 997 { 998 if ($matching_platform_ids{$platform_id}) 999 { 1000 push @matching_platform_descriptors, $release_descriptor->{'platforms'}->{$platform_id}; 1001 } 1002 } 1003 1004 return @matching_platform_descriptors; 1005} 1006 1007 1008 1009 1010my $bold_text_start = "<b>"; 1011my $bold_text_end = "</b>"; 1012my $small_text_start = "<span style=\"font-size:80%\">"; 1013my $small_text_end = "</span>"; 1014my $broken_link_start = "<span style=\"color:#FF0000\">"; 1015my $broken_link_end = "</span>"; 1016 1017 1018sub WriteDownloadLinks ($$$$$) 1019{ 1020 my ($out, 1021 $context, 1022 $release_descriptor, 1023 $language_descriptor, 1024 $package_descriptor, 1025 $platform_descriptor) = @_; 1026 1027 # Check if the current language and platform match the package. 1028 if (defined $package_descriptor->{'platforms'}->{$platform_descriptor->{'id'}} 1029 && defined $package_descriptor->{'languages'}->{$language_descriptor->{'id'}}) 1030 { 1031 my $archive_package_name = ""; 1032 my $package_type = $platform_descriptor->{'package-type'}; 1033 my $extension = $package_type; 1034 if (defined $platform_descriptor->{'extension'}) 1035 { 1036 $extension = $platform_descriptor->{'extension'}; 1037 } 1038 if (defined $package_descriptor->{'download-extension'}) 1039 { 1040 $extension = $package_descriptor->{'download-extension'}; 1041 } 1042 $archive_package_name = "-".$package_type if ($package_type =~ /deb|rpm/); 1043 my $archive_name = sprintf("Apache_OpenOffice%s_%s_%s_%s%s_%s.%s", 1044 $package_descriptor->{'archive-name1'}, 1045 $release_descriptor->{'version'}, 1046 $platform_descriptor->{'archive-platform'}, 1047 $package_descriptor->{'archive-name2'}, 1048 $archive_package_name, 1049 $language_descriptor->{'id'}, 1050 $extension); 1051 1052 my $url = $platform_descriptor->{'base-url'} . "/". $archive_name; 1053 printf $out 1054 "| align=\"center\" | %s%s%s<br><br>%s%s %s<br>%s%s\n", 1055 $bold_text_start, 1056 CreateLink($url, $extension, $context), 1057 $bold_text_end, 1058 $small_text_start, 1059 CreateLink($url.".asc", "ASC", $context), 1060 CreateLink($url.".md5", "MD5", $context), 1061 CreateLink($url.".sha256", "SHA256", $context), 1062 $small_text_end; 1063 } 1064 else 1065 { 1066 printf $out "|\n"; 1067 } 1068} 1069 1070 1071 1072 1073sub CreateLink ($$$) 1074{ 1075 my ($url, $text, $context) = @_; 1076 1077 my $is_link_broken = 0; 1078 if ($context->{'check-links'}) 1079 { 1080 my $head = LWP::Simple::head($url); 1081 $is_link_broken = ! $head; 1082 printf "."; 1083 } 1084 1085 if ( ! $is_link_broken) 1086 { 1087 return sprintf ("[%s %s]", $url, $text); 1088 } 1089 elsif ($context->{'mark-broken-links'}) 1090 { 1091 return sprintf ("%sbroken%s[%s %s]", $broken_link_start, $broken_link_end, $url, $text); 1092 } 1093 else 1094 { 1095 return sprintf ("%s", $text); 1096 } 1097} 1098 1099 1100 1101 1102my $context = ProcessCommandline(@ARGV); 1103my $release_description = ReadReleaseDescription($context->{'filename'}, $context); 1104if ($context->{'command'} eq "build") 1105{ 1106 WriteMakefile($release_description, $context->{'output-filename'}); 1107# open my $make, "|-", sprintf("make -C \"%s\" -j%d -f -", $path, $max_process_count); 1108} 1109elsif ($context->{'command'} eq "upload") 1110{ 1111 Upload($release_description, $context); 1112} 1113elsif ($context->{'command'} eq "wiki") 1114{ 1115 Wiki($release_description, $context); 1116} 1117