xref: /aoo41x/main/solenv/bin/build_release.pl (revision f219747d)
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