xref: /aoo42x/main/solenv/bin/build_release.pl (revision c667dd47)
1*c667dd47SPedro Giffuni#!/usr/bin/env perl
2f219747dSAndre Fischer#**************************************************************
3f219747dSAndre Fischer#
4f219747dSAndre Fischer#  Licensed to the Apache Software Foundation (ASF) under one
5f219747dSAndre Fischer#  or more contributor license agreements.  See the NOTICE file
6f219747dSAndre Fischer#  distributed with this work for additional information
7f219747dSAndre Fischer#  regarding copyright ownership.  The ASF licenses this file
8f219747dSAndre Fischer#  to you under the Apache License, Version 2.0 (the
9f219747dSAndre Fischer#  "License"); you may not use this file except in compliance
10f219747dSAndre Fischer#  with the License.  You may obtain a copy of the License at
11f219747dSAndre Fischer#
12f219747dSAndre Fischer#    http://www.apache.org/licenses/LICENSE-2.0
13f219747dSAndre Fischer#
14f219747dSAndre Fischer#  Unless required by applicable law or agreed to in writing,
15f219747dSAndre Fischer#  software distributed under the License is distributed on an
16f219747dSAndre Fischer#  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17f219747dSAndre Fischer#  KIND, either express or implied.  See the License for the
18f219747dSAndre Fischer#  specific language governing permissions and limitations
19f219747dSAndre Fischer#  under the License.
20f219747dSAndre Fischer#
21f219747dSAndre Fischer#**************************************************************
22f219747dSAndre Fischer
23f219747dSAndre Fischeruse strict;
241108b05eSAndre Fischeruse warnings;
25f219747dSAndre Fischeruse XML::LibXML;
26f219747dSAndre Fischeruse open OUT => ":utf8";
27f219747dSAndre Fischeruse LWP::Simple;
28f219747dSAndre Fischeruse Digest;
29f219747dSAndre Fischeruse Digest::MD5;
30f219747dSAndre Fischeruse Digest::SHA;
319dd622cdSAndre Fischeruse File::Temp;
329dd622cdSAndre Fischeruse File::Path;
33f219747dSAndre Fischer
34f219747dSAndre Fischeruse Carp::always;
35f219747dSAndre Fischer
36f219747dSAndre Fischer=head1 NAME
37f219747dSAndre Fischer
38f219747dSAndre Fischer    build_release.pl - Tool for batch release builds and uploads and the creation of wiki pages that list install sets.
39f219747dSAndre Fischer
40f219747dSAndre Fischer=head1 SYNOPSIS
41f219747dSAndre Fischer
42f219747dSAndre Fischer    build_release.pl <command> {option} <release-description.xml>
43f219747dSAndre Fischer
44f219747dSAndre Fischer    comands:
45f219747dSAndre Fischer        build      builds all install sets as requested by the XML file and supported by the platform.
469dd622cdSAndre Fischer        build-missing
479dd622cdSAndre Fischer                   build only those install sets that have not been built earlier.
48f219747dSAndre Fischer        upload     upload install sets to a local or remote (via ssh with public/private key)
49f219747dSAndre Fischer                   directory structure.  Uploads install sets that where build on other platforms.
50f219747dSAndre Fischer        wiki       create a wiki (MediaWiki syntax) snippet that references all install sets at the upload
51f219747dSAndre Fischer                   location.  Includes install sets that where built and/or uploaded from other
52f219747dSAndre Fischer                   platforms and machines.
53f219747dSAndre Fischer    options:
54f219747dSAndre Fischer        -j <count>    maximum number of build processes
55f219747dSAndre Fischer        -k            keep going if there are recoverable errors
56f219747dSAndre Fischer        -u <path>     upload destination
57f219747dSAndre Fischer        -l            check links on wiki page, write broken links as plain text
58f219747dSAndre Fischer        -ld           check links on wiki page, mark broken links
59f219747dSAndre Fischer        -o <filename> filename of the output (wiki: wiki page, build: makefile)
609dd622cdSAndre Fischer        -n <number>   maximal number of upload tries, defaults to 5.
619dd622cdSAndre Fischer        -d            dry-run
62f219747dSAndre Fischer
639dd622cdSAndre Fischer    Typical calls are:
649dd622cdSAndre Fischer       build_release.pl build -j4 instsetoo_native/util/aoo-410-release.xml
659dd622cdSAndre Fischer           for building the installation sets, language packs and patches for the 4.1 release.
669dd622cdSAndre Fischer
679dd622cdSAndre Fischer       build_release.pl upload -u me@server:path -n 3 instsetoo_native/util/aoo-410-release.xml
689dd622cdSAndre Fischer           to upload the previously built installation sets etc.
699dd622cdSAndre Fischer
709dd622cdSAndre Fischer       build_release.pl wiki -o /tmp/wiki.txt instsetoo_native/util/aoo-410-release.xml
719dd622cdSAndre Fischer           to create an updated wiki page with installation sets etc built at several
729dd622cdSAndre Fischer           places and uploaded to several locations.
739dd622cdSAndre Fischer
749dd622cdSAndre Fischer
75f219747dSAndre Fischer=head1 XML file format
76f219747dSAndre Fischer
779dd622cdSAndre FischerThe release description could look like this:
789dd622cdSAndre Fischer
79f219747dSAndre Fischer<release
80f219747dSAndre Fischer    name="snapshot"
81f219747dSAndre Fischer    version="4.1.0">
82f219747dSAndre Fischer
83f219747dSAndre Fischer    <language
84f219747dSAndre Fischer        id="ast"                            # As specified by 'configure --with-lang'
85f219747dSAndre Fischer        english-name="Asturian"
86f219747dSAndre Fischer        local-name="Asturianu"
87f219747dSAndre Fischer        />
88f219747dSAndre Fischer    ... more languages
89f219747dSAndre Fischer
90f219747dSAndre Fischer    <platform
91f219747dSAndre Fischer        id="wntmsci12.pro"
92f219747dSAndre Fischer        display-name="Windows"
93f219747dSAndre Fischer        archive-platform="Win_x86"
94f219747dSAndre Fischer        word-size="32"
959dd622cdSAndre Fischer        package-types="msi"
969dd622cdSAndre Fischer        extension="exe"
97f219747dSAndre Fischer        />
98f219747dSAndre Fischer    ... more platforms
99f219747dSAndre Fischer
1009dd622cdSAndre Fischer    <download
1019dd622cdSAndre Fischer        platform-id="wntmsci12.pro"
1029dd622cdSAndre Fischer        base-url="http://people.apache.org/~somebody/developer-snapshots/snapshot/win32"
1039dd622cdSAndre Fischer        />
104f219747dSAndre Fischer
105f219747dSAndre Fischer    <package
1069dd622cdSAndre Fischer        id="openoffice"
1079dd622cdSAndre Fischer        target="openoffice"
108f219747dSAndre Fischer        display-name="Full Install"
1099dd622cdSAndre Fischer        archive-name="Apache_OpenOffice_%V_%P_install%T_%L.%E"
1109dd622cdSAndre Fischer        />
1119dd622cdSAndre Fischer
1129dd622cdSAndre Fischer    <build
1139dd622cdSAndre Fischer        package-id="openoffice"
1149dd622cdSAndre Fischer        platform-list="all"
1159dd622cdSAndre Fischer        language-list="all"
1169dd622cdSAndre Fischer        />
1179dd622cdSAndre Fischer    ... more build entries
1189dd622cdSAndre Fischer
1199dd622cdSAndre Fischer  <wiki>
1209dd622cdSAndre Fischer    <package-ref
1219dd622cdSAndre Fischer        package-id="openoffice"
122f219747dSAndre Fischer        language-list="all"
123f219747dSAndre Fischer        platform-list="all"
124f219747dSAndre Fischer        table="main"
125f219747dSAndre Fischer        />
126f219747dSAndre Fischer    ... more packages
127f219747dSAndre Fischer  </wiki>
128f219747dSAndre Fischer
129f219747dSAndre Fischer</release>
1309dd622cdSAndre Fischer
1319dd622cdSAndre FischerA single <release> tag contains any number of
1329dd622cdSAndre Fischer
1339dd622cdSAndre Fischer<language>  id
1349dd622cdSAndre Fischer                The language id used internally by the build process, eg de, en-US
1359dd622cdSAndre Fischer            english-name
1369dd622cdSAndre Fischer                The english name of the language, eg german
1379dd622cdSAndre Fischer            local-name
1389dd622cdSAndre Fischer                The language name in that language, eg Deutsch
1399dd622cdSAndre Fischer
1409dd622cdSAndre Fischer    Each listed language is expected to have been passed to configure via --with-lang
1419dd622cdSAndre Fischer    The set of languages defines for which languages to
1429dd622cdSAndre Fischer          build installation sets, language packs etc. (build command)
1439dd622cdSAndre Fischer          upload installation sets, etc (upload command)
1449dd622cdSAndre Fischer          add rows in the wiki page (wiki command)
1459dd622cdSAndre Fischer
1469dd622cdSAndre Fischer<platform>  id
1479dd622cdSAndre Fischer                The platform id that is used internally by the build process, eg wntmsci12.pro
1489dd622cdSAndre Fischer                Note that <p>.pro and <p> are treated as two different platforms.
1499dd622cdSAndre Fischer            display-name
1509dd622cdSAndre Fischer                Name which is printed in the wiki table.
1519dd622cdSAndre Fischer            archive-platform
1529dd622cdSAndre Fischer                Platform name as used in the name of the installation set, eg Win_x86
1539dd622cdSAndre Fischer            word-size
1549dd622cdSAndre Fischer                Bit size of the installation sets, etc, typically either 32 or 64
1559dd622cdSAndre Fischer            package-types
1569dd622cdSAndre Fischer                Semicolon separated list of package types, eg "msi" or "deb;rpm"
1579dd622cdSAndre Fischer            add-package-type-to-archive-name
1589dd622cdSAndre Fischer                For deb and rpm archives it is necessary to add the package type to the archive name.
1599dd622cdSAndre Fischer            extension
1609dd622cdSAndre Fischer                Extension of the archive name, eg "exe" or "tar.gz"
1619dd622cdSAndre Fischer
1629dd622cdSAndre Fischer    For the build command only those <platform> elements are used that match the platform on which this
1639dd622cdSAndre Fischer    script is run.
1649dd622cdSAndre Fischer
1659dd622cdSAndre Fischer<download>
1669dd622cdSAndre Fischer            platform-id
1679dd622cdSAndre Fischer                Reference to one of the <platform> elements and has to match the id attribute of that platform.
1689dd622cdSAndre Fischer            base-url
1699dd622cdSAndre Fischer                URL head to which the name of the downloadable installation set etc. is appended.
1709dd622cdSAndre Fischer                Eg. http://people.apache.org/~somebody/developer-snapshots/snapshot/win32
1719dd622cdSAndre Fischer
1729dd622cdSAndre Fischer    Defines one download source that is referenced in the wiki page.  Multiple <download> elements
1739dd622cdSAndre Fischer    per platform are possible.  Earlier entires are preferred over later ones.
1749dd622cdSAndre Fischer
1759dd622cdSAndre Fischer<package>
1769dd622cdSAndre Fischer            id
1779dd622cdSAndre Fischer                Internal name that is used to reference the package.
1789dd622cdSAndre Fischer            target
1799dd622cdSAndre Fischer                Target name recognized by instsetoo_native/util/makefile.mk, eg openoffice or oolanguagepack.
1809dd622cdSAndre Fischer            display-name
1819dd622cdSAndre Fischer                Name of the package that is shown in the wiki page, eg "Full Install" or "Langpack".
1829dd622cdSAndre Fischer            archive-name
1839dd622cdSAndre Fischer                Template of the archive name.
1849dd622cdSAndre Fischer                %V version
1859dd622cdSAndre Fischer                %P archive package name
1869dd622cdSAndre Fischer                %T package type
1879dd622cdSAndre Fischer                %L language
1889dd622cdSAndre Fischer                %E extension.
1899dd622cdSAndre Fischer
1909dd622cdSAndre Fischer    Defines a downloadable and distributable package, eg openoffice for the binary OpenOffice installation set.
191f219747dSAndre Fischer
1929dd622cdSAndre Fischer<build>     target
1939dd622cdSAndre Fischer            platform-list
1949dd622cdSAndre Fischer                Semicolon separated list of platforms for which to build the target.
1959dd622cdSAndre Fischer                Ignores all platforms that don't match the  platform on which this script is executed.
1969dd622cdSAndre Fischer                The special value 'all' is a shortcut for all platforms listed by <platform> elements.
1979dd622cdSAndre Fischer            language-list
1989dd622cdSAndre Fischer                Semicolon separated list of languages for which the build the target.
1999dd622cdSAndre Fischer                The special value 'all' is a shortcut for all languages listed by <language> elements.
2009dd622cdSAndre Fischer
2019dd622cdSAndre Fischer    Defines the sets of targets, plaforms and languages which are to be built.
2029dd622cdSAndre Fischer
2039dd622cdSAndre Fischer<wiki>
2049dd622cdSAndre Fischer    <package-ref>
2059dd622cdSAndre Fischer            package-id
2069dd622cdSAndre Fischer                The id of the referenced package.
2079dd622cdSAndre Fischer            platform-list
2089dd622cdSAndre Fischer                See <build> tag for explanation.
2099dd622cdSAndre Fischer            language-list
2109dd622cdSAndre Fischer                See <build> tag for explanation.
2119dd622cdSAndre Fischer            table
2129dd622cdSAndre Fischer                Specifies the wiki table into which to add the package lines.  Can be "main" or "secondary".
2139dd622cdSAndre Fischer
214f219747dSAndre Fischer=cut
215f219747dSAndre Fischer
216f219747dSAndre Fischer
217f219747dSAndre Fischer
218f219747dSAndre Fischermy %EnUSBasedLanguages = (
219f219747dSAndre Fischer    'ast' => 1
220f219747dSAndre Fischer    );
221f219747dSAndre Fischer
222f219747dSAndre Fischer
2231108b05eSAndre Fischersub ProcessCommandline (@);
2241108b05eSAndre Fischersub PrintUsageAndExit ();
2251108b05eSAndre Fischersub Trim ($);
2261108b05eSAndre Fischersub ReadReleaseDescription ($$);
2271108b05eSAndre Fischersub ProcessBuildDescription ($$$);
2281108b05eSAndre Fischersub ProcessPlatformDescription ($$);
2291108b05eSAndre Fischersub ProcessDownloadDescription ($$);
2301108b05eSAndre Fischersub ProcessPackageDescription ($$);
2311108b05eSAndre Fischersub ProcessWikiPackageDescription ($$$);
2321108b05eSAndre Fischersub ProcessLanguageDescription ($$);
2331108b05eSAndre Fischersub PostprocessLanguageList ($$);
2341108b05eSAndre Fischersub PostprocessPlatformList ($$);
2351108b05eSAndre Fischersub CheckLanguageSet ($@);
2361108b05eSAndre Fischersub WriteMakefile ($$);
2371108b05eSAndre Fischersub Upload ($$);
2381108b05eSAndre Fischersub PrepareUploadArea ($@);
2391108b05eSAndre Fischersub UploadFilesViaRsync ($$@);
2401108b05eSAndre Fischersub CollectDownloadSets ($);
2411108b05eSAndre Fischersub ProvideChecksums ($@);
2421108b05eSAndre Fischersub IsOlderThan ($$);
2431108b05eSAndre Fischersub GetInstallationPackageName ($$$$);
2441108b05eSAndre Fischersub ResolveTemplate ($$$$$);
2451108b05eSAndre Fischersub GetCurrentPlatformDescriptor ($);
2461108b05eSAndre Fischersub Wiki ($$);
2471108b05eSAndre Fischersub GetTableList ($);
2481108b05eSAndre Fischersub GetPackagesForTable ($$);
2491108b05eSAndre Fischersub GetLanguagesForTable ($@);
2501108b05eSAndre Fischersub GetPlatformsForTable ($@);
2511108b05eSAndre Fischersub WriteDownloadLinks ($$$$$$$);
2521108b05eSAndre Fischersub FindDownload ($$$$$);
2531108b05eSAndre Fischersub CreateLink ($$$);
2541108b05eSAndre Fischersub CheckLink ($);
2551108b05eSAndre Fischersub SignFile ($$);
256f219747dSAndre Fischer
257f219747dSAndre Fischersub ProcessCommandline (@)
258f219747dSAndre Fischer{
259f219747dSAndre Fischer    my @arguments = @_;
260f219747dSAndre Fischer
261f219747dSAndre Fischer    my $command = undef;
262f219747dSAndre Fischer    my $description_filename = undef;
263f219747dSAndre Fischer    my $max_process_count = 1;
264f219747dSAndre Fischer    my $keep_going = 0;
265f219747dSAndre Fischer    my $upload_destination = undef;
266f219747dSAndre Fischer    my $check_links = 0;
267f219747dSAndre Fischer    my $mark_broken_links = 0;
268f219747dSAndre Fischer    my $output_filename = undef;
2699dd622cdSAndre Fischer    my $max_upload_count = 5;
2709dd622cdSAndre Fischer    my $build_only_missing = 0;
2719dd622cdSAndre Fischer    my $dry_run = 0;
272f219747dSAndre Fischer
273f219747dSAndre Fischer    my $error = 0;
274f219747dSAndre Fischer    while (scalar @arguments > 0)
275f219747dSAndre Fischer    {
276f219747dSAndre Fischer        my $argument = shift @arguments;
277f219747dSAndre Fischer        if ($argument =~ /^-/)
278f219747dSAndre Fischer        {
279f219747dSAndre Fischer            if ($argument eq "-j")
280f219747dSAndre Fischer            {
281f219747dSAndre Fischer                $max_process_count = shift @arguments;
282f219747dSAndre Fischer            }
283f219747dSAndre Fischer            elsif ($argument eq "-u")
284f219747dSAndre Fischer            {
285f219747dSAndre Fischer                $upload_destination = shift @arguments;
286f219747dSAndre Fischer                $upload_destination =~ s/(\\|\/)$//;
287f219747dSAndre Fischer            }
288f219747dSAndre Fischer            elsif ($argument eq "-k")
289f219747dSAndre Fischer            {
290f219747dSAndre Fischer                $keep_going = 1;
291f219747dSAndre Fischer            }
292f219747dSAndre Fischer            elsif ($argument eq "-l")
293f219747dSAndre Fischer            {
294f219747dSAndre Fischer                $check_links = 1;
295f219747dSAndre Fischer            }
296f219747dSAndre Fischer            elsif ($argument eq "-ld")
297f219747dSAndre Fischer            {
298f219747dSAndre Fischer                $check_links = 1;
299f219747dSAndre Fischer                $mark_broken_links = 1;
300f219747dSAndre Fischer            }
301f219747dSAndre Fischer            elsif ($argument eq "-o")
302f219747dSAndre Fischer            {
303f219747dSAndre Fischer                $output_filename = shift @arguments;
304f219747dSAndre Fischer            }
3059dd622cdSAndre Fischer            elsif ($argument eq "-n")
3069dd622cdSAndre Fischer            {
3079dd622cdSAndre Fischer                $max_upload_count = shift @arguments;
3089dd622cdSAndre Fischer            }
3099dd622cdSAndre Fischer            elsif ($argument eq "-d")
3109dd622cdSAndre Fischer            {
3119dd622cdSAndre Fischer                $dry_run = 1;
3129dd622cdSAndre Fischer            }
313f219747dSAndre Fischer            else
314f219747dSAndre Fischer            {
315f219747dSAndre Fischer                printf STDERR "unknown option $argument %s\n", $argument;
316f219747dSAndre Fischer                $error = 1;
317f219747dSAndre Fischer            }
318f219747dSAndre Fischer        }
319f219747dSAndre Fischer        elsif ( ! defined $command)
320f219747dSAndre Fischer        {
321f219747dSAndre Fischer            $command = $argument;
3221108b05eSAndre Fischer            if ($command eq "build-missing")
3231108b05eSAndre Fischer            {
3241108b05eSAndre Fischer                $command = "build";
3251108b05eSAndre Fischer                $build_only_missing = 1;
3261108b05eSAndre Fischer            }
3279dd622cdSAndre Fischer            elsif ($command !~ /^(build|build-missing|upload|wiki)$/)
328f219747dSAndre Fischer            {
329f219747dSAndre Fischer                printf STDERR "unknown command '%s'\n", $command;
330f219747dSAndre Fischer                $error = 1;
331f219747dSAndre Fischer            }
332f219747dSAndre Fischer        }
333f219747dSAndre Fischer        else
334f219747dSAndre Fischer        {
335f219747dSAndre Fischer            $description_filename = $argument;
336f219747dSAndre Fischer            if ( ! -f $description_filename)
337f219747dSAndre Fischer            {
338f219747dSAndre Fischer                print STDERR "can not open release description '%s'\n", $description_filename;
339f219747dSAndre Fischer                $error = 1;
340f219747dSAndre Fischer            }
341f219747dSAndre Fischer        }
342f219747dSAndre Fischer    }
343f219747dSAndre Fischer
344f219747dSAndre Fischer    if ( ! defined $description_filename)
345f219747dSAndre Fischer    {
346f219747dSAndre Fischer        $error = 1;
347f219747dSAndre Fischer    }
3481108b05eSAndre Fischer    if (! defined $command)
3491108b05eSAndre Fischer    {
3501108b05eSAndre Fischer        printf STDERR "ERROR: no command\n";
3511108b05eSAndre Fischer        $error = 1;
3521108b05eSAndre Fischer    }
3531108b05eSAndre Fischer    elsif ($command =~ /^(wiki)$/)
354f219747dSAndre Fischer    {
355f219747dSAndre Fischer        if ( ! defined $output_filename)
356f219747dSAndre Fischer        {
357f219747dSAndre Fischer            printf STDERR "ERROR: no output filename\n",
358f219747dSAndre Fischer            $error = 1;
359f219747dSAndre Fischer        }
360f219747dSAndre Fischer    }
361f219747dSAndre Fischer
362f219747dSAndre Fischer    if ($error)
363f219747dSAndre Fischer    {
364f219747dSAndre Fischer        PrintUsageAndExit();
365f219747dSAndre Fischer    }
366f219747dSAndre Fischer
367f219747dSAndre Fischer    return {
368f219747dSAndre Fischer        'command' => $command,
369f219747dSAndre Fischer        'filename' => $description_filename,
370f219747dSAndre Fischer        'max-process-count' => $max_process_count,
371f219747dSAndre Fischer        'keep-going' => $keep_going,
372f219747dSAndre Fischer        'upload-destination' => $upload_destination,
373f219747dSAndre Fischer        'check-links' => $check_links,
374f219747dSAndre Fischer        'mark-broken-links' => $mark_broken_links,
3759dd622cdSAndre Fischer        'output-filename' => $output_filename,
3769dd622cdSAndre Fischer        'max-upload-count' => $max_upload_count,
3779dd622cdSAndre Fischer        'build-only-missing' => $build_only_missing,
3789dd622cdSAndre Fischer        'dry-run' => $dry_run
379f219747dSAndre Fischer    };
380f219747dSAndre Fischer}
381f219747dSAndre Fischer
382f219747dSAndre Fischer
383f219747dSAndre Fischer
384f219747dSAndre Fischer
385f219747dSAndre Fischersub PrintUsageAndExit ()
386f219747dSAndre Fischer{
387f219747dSAndre Fischer    print STDERR "usage: $0 <command> {option} <release-description.xml>\n";
388f219747dSAndre Fischer    print STDERR "    comands:\n";
389f219747dSAndre Fischer    print STDERR "        build\n";
3909dd622cdSAndre Fischer    print STDERR "        build-missing\n";
391f219747dSAndre Fischer    print STDERR "        upload\n";
392f219747dSAndre Fischer    print STDERR "        wiki     create a download page in MediaWiki syntax\n";
393f219747dSAndre Fischer    print STDERR "    options:\n";
394f219747dSAndre Fischer    print STDERR "    -j <count>    maximum number of build processes\n";
395f219747dSAndre Fischer    print STDERR "    -k            keep going if there are recoverable errors\n";
396f219747dSAndre Fischer    print STDERR "    -u <path>     upload destination\n";
397f219747dSAndre Fischer    print STDERR "    -l            check links on wiki page, write broken links as plain text\n";
398f219747dSAndre Fischer    print STDERR "    -ld           check links on wiki page, mark broken links\n";
399f219747dSAndre Fischer    print STDERR "    -o <filename> filename of the output (wiki: wiki page, build: makefile)\n";
4009dd622cdSAndre Fischer    print STDERR "    -n <number>   maximal number of upload tries, defaults to 5.\n";
4019dd622cdSAndre Fischer    print STDERR "    -d            dry run\n";
402f219747dSAndre Fischer    exit(1);
403f219747dSAndre Fischer}
404f219747dSAndre Fischer
405f219747dSAndre Fischer
406f219747dSAndre Fischer
407f219747dSAndre Fischer
4089dd622cdSAndre Fischer=head2 Trim ($text)
4099dd622cdSAndre Fischer
4109dd622cdSAndre Fischer    Remove leading and trailing space from the given string.
4119dd622cdSAndre Fischer
4129dd622cdSAndre Fischer=cut
413f219747dSAndre Fischersub Trim ($)
414f219747dSAndre Fischer{
415f219747dSAndre Fischer    my ($text) = @_;
416f219747dSAndre Fischer    $text =~ s/^\s+|\s+$//g;
417f219747dSAndre Fischer    return $text;
418f219747dSAndre Fischer}
419f219747dSAndre Fischer
420f219747dSAndre Fischer
421f219747dSAndre Fischer
422f219747dSAndre Fischer
4239dd622cdSAndre Fischer=head2 ReadReleaseDescription ($$)
4249dd622cdSAndre Fischer
4259dd622cdSAndre Fischer    Read the release description from $filename.
4269dd622cdSAndre Fischer
4279dd622cdSAndre Fischer=cut
428f219747dSAndre Fischersub ReadReleaseDescription ($$)
429f219747dSAndre Fischer{
430f219747dSAndre Fischer    my ($filename, $context) = @_;
431f219747dSAndre Fischer
432f219747dSAndre Fischer    my $document = XML::LibXML->load_xml('location' => $filename);
433f219747dSAndre Fischer    my $root = $document->documentElement();
434f219747dSAndre Fischer
435f219747dSAndre Fischer    # Initialize the release description.
436f219747dSAndre Fischer    my $release = {
437f219747dSAndre Fischer        'name' => $root->getAttribute("name"),
438f219747dSAndre Fischer        'version' => $root->getAttribute("version"),
4391108b05eSAndre Fischer        'previous-version' => $root->getAttribute("previous-version"),
440f219747dSAndre Fischer        'builds' => [],
441f219747dSAndre Fischer        'languages' => {},
442f219747dSAndre Fischer        'language-ids' => [],
443f219747dSAndre Fischer        'platforms' => {},
4449dd622cdSAndre Fischer        'downloads' => [],
4459dd622cdSAndre Fischer        'packages' => {},
446f219747dSAndre Fischer        'platform-ids' => [],
4479dd622cdSAndre Fischer        'wiki-packages' => []
448f219747dSAndre Fischer    };
449f219747dSAndre Fischer
450f219747dSAndre Fischer    # Process the language descriptions.
451f219747dSAndre Fischer    for my $language_element ($root->getChildrenByTagName("language"))
452f219747dSAndre Fischer    {
453f219747dSAndre Fischer        my $language_descriptor = ProcessLanguageDescription($language_element, $context);
454f219747dSAndre Fischer        $release->{'languages'}->{$language_descriptor->{'id'}} = $language_descriptor;
455f219747dSAndre Fischer        push @{$release->{'language-ids'}}, $language_descriptor->{'id'};
456f219747dSAndre Fischer    }
457f219747dSAndre Fischer    printf "%d languages\n", scalar keys %{$release->{'languages'}};
458f219747dSAndre Fischer
459f219747dSAndre Fischer    # Process the platform descriptions.
460f219747dSAndre Fischer    for my $platform_element ($root->getChildrenByTagName("platform"))
461f219747dSAndre Fischer    {
4629dd622cdSAndre Fischer        my $platform_descriptor = ProcessPlatformDescription($platform_element, $context);
4639dd622cdSAndre Fischer        $release->{'platforms'}->{$platform_descriptor->{'id'}} = $platform_descriptor;
4649dd622cdSAndre Fischer        push @{$release->{'platform-ids'}}, $platform_descriptor->{'id'};
465f219747dSAndre Fischer    }
466f219747dSAndre Fischer    printf "%d platforms\n", scalar keys %{$release->{'platforms'}};
467f219747dSAndre Fischer
4689dd622cdSAndre Fischer    # Process the package descriptions.
4699dd622cdSAndre Fischer    for my $package_element ($root->getChildrenByTagName("package"))
4709dd622cdSAndre Fischer    {
4719dd622cdSAndre Fischer        my $package_descriptor = ProcessPackageDescription($package_element, $context);
4729dd622cdSAndre Fischer        $release->{'packages'}->{$package_descriptor->{'id'}} = $package_descriptor;
4739dd622cdSAndre Fischer    }
4749dd622cdSAndre Fischer    printf "%d packages\n", scalar keys %{$release->{'packages'}};
4759dd622cdSAndre Fischer
4761108b05eSAndre Fischer    # Platform specific the package descriptions.
4771108b05eSAndre Fischer    for my $package_element ($root->getChildrenByTagName("platform-package"))
4781108b05eSAndre Fischer    {
4791108b05eSAndre Fischer        my $package_descriptor = ProcessPlatformPackageDescription($package_element, $context);
4801108b05eSAndre Fischer        my $key = $package_descriptor->{'platform-id'} . "/" . $package_descriptor->{'package-id'};
4811108b05eSAndre Fischer        $release->{'platform-packages'}->{$key} = $package_descriptor;
4821108b05eSAndre Fischer    }
4831108b05eSAndre Fischer    printf "%d platform packages\n", scalar keys %{$release->{'platform-packages'}};
4841108b05eSAndre Fischer
4859dd622cdSAndre Fischer    # Process the download descriptions.
4869dd622cdSAndre Fischer    for my $download_element ($root->getChildrenByTagName("download"))
4879dd622cdSAndre Fischer    {
4889dd622cdSAndre Fischer        my $download_descriptor = ProcessDownloadDescription($download_element, $context);
4899dd622cdSAndre Fischer        push @{$release->{'downloads'}}, $download_descriptor;
4909dd622cdSAndre Fischer    }
4919dd622cdSAndre Fischer    printf "%d downloads\n", scalar @{$release->{'downloads'}};
4929dd622cdSAndre Fischer
493f219747dSAndre Fischer    if ($context->{'command'} =~ /^(build|upload)$/)
494f219747dSAndre Fischer    {
495f219747dSAndre Fischer        # Process the build descriptions.
496f219747dSAndre Fischer        for my $build_element ($root->getChildrenByTagName("build"))
497f219747dSAndre Fischer        {
498f219747dSAndre Fischer            push @{$release->{'builds'}}, ProcessBuildDescription($build_element, $context, $release);
499f219747dSAndre Fischer        }
500f219747dSAndre Fischer        printf "%d build targets\n", scalar @{$release->{'builds'}};
501f219747dSAndre Fischer    }
502f219747dSAndre Fischer
503f219747dSAndre Fischer    if ($context->{'command'} eq "wiki")
504f219747dSAndre Fischer    {
505f219747dSAndre Fischer        for my $wiki_element ($root->getChildrenByTagName("wiki"))
506f219747dSAndre Fischer        {
5079dd622cdSAndre Fischer            for my $wiki_package_element ($wiki_element->getChildrenByTagName("package-ref"))
508f219747dSAndre Fischer            {
509f219747dSAndre Fischer                my $wiki_package = ProcessWikiPackageDescription(
510f219747dSAndre Fischer                    $wiki_package_element,
511f219747dSAndre Fischer                    $context,
512f219747dSAndre Fischer                    $release);
513f219747dSAndre Fischer                push @{$release->{'wiki-packages'}}, $wiki_package;
514f219747dSAndre Fischer            }
515f219747dSAndre Fischer        }
516f219747dSAndre Fischer        printf "%d wiki packages\n", scalar @{$release->{'wiki-packages'}};
517f219747dSAndre Fischer    }
518f219747dSAndre Fischer
519f219747dSAndre Fischer    return $release;
520f219747dSAndre Fischer}
521f219747dSAndre Fischer
522f219747dSAndre Fischer
523f219747dSAndre Fischer
524f219747dSAndre Fischer
5259dd622cdSAndre Fischer=head ProcessBuildDescription ($build_element, $context, $release_descriptor)
5269dd622cdSAndre Fischer
5279dd622cdSAndre Fischer    Process one <build> element.
5289dd622cdSAndre Fischer
5299dd622cdSAndre Fischer    If its platform-list does not match the current platform then the <build> element is ignored.
5309dd622cdSAndre Fischer
5319dd622cdSAndre Fischer=cut
532f219747dSAndre Fischersub ProcessBuildDescription ($$$)
533f219747dSAndre Fischer{
534f219747dSAndre Fischer    my ($build_element, $context, $release_descriptor) = @_;
535f219747dSAndre Fischer
5369dd622cdSAndre Fischer    my $package_id = $build_element->getAttribute("package-id");
537f219747dSAndre Fischer    my $languages = PostprocessLanguageList($build_element->getAttribute("language-list"), $release_descriptor);
538f219747dSAndre Fischer    my $platforms = PostprocessPlatformList($build_element->getAttribute("platform-list"), $release_descriptor);
539f219747dSAndre Fischer
540f219747dSAndre Fischer    # Check if the platform matches any for which the product shall be built.
541f219747dSAndre Fischer    my $current_platform = $ENV{'INPATH'};
542f219747dSAndre Fischer    my $is_platform_match = 0;
543f219747dSAndre Fischer    foreach my $platform_id (@$platforms)
544f219747dSAndre Fischer    {
545f219747dSAndre Fischer        if ($platform_id eq $current_platform)
546f219747dSAndre Fischer        {
547f219747dSAndre Fischer            $is_platform_match=1;
548f219747dSAndre Fischer            last;
549f219747dSAndre Fischer        }
550f219747dSAndre Fischer    }
551f219747dSAndre Fischer    if ($is_platform_match)
552f219747dSAndre Fischer    {
5539dd622cdSAndre Fischer        printf "including build %s\n", $package_id;
554f219747dSAndre Fischer    }
555f219747dSAndre Fischer    else
556f219747dSAndre Fischer    {
5579dd622cdSAndre Fischer        printf "skipping build %s: no platform match\n", $package_id;
558f219747dSAndre Fischer        printf "none of the platforms %s matches %s\n",
5599dd622cdSAndre Fischer        join(", ", keys %{$release_descriptor->{'platforms'}}),
5609dd622cdSAndre Fischer        $current_platform;
561f219747dSAndre Fischer        return;
562f219747dSAndre Fischer    }
563f219747dSAndre Fischer
564f219747dSAndre Fischer    my @languages = CheckLanguageSet($context, @$languages);
565f219747dSAndre Fischer
566f219747dSAndre Fischer    return {
5679dd622cdSAndre Fischer        'package-id' => $package_id,
5689dd622cdSAndre Fischer        'platform-list' => $platforms,
569f219747dSAndre Fischer        'language-list' => \@languages
570f219747dSAndre Fischer    };
571f219747dSAndre Fischer}
572f219747dSAndre Fischer
573f219747dSAndre Fischer
574f219747dSAndre Fischer
575f219747dSAndre Fischer
5769dd622cdSAndre Fischer
5779dd622cdSAndre Fischer=head2 ProcessPlatformDescription ($element, $context)
5789dd622cdSAndre Fischer
5799dd622cdSAndre Fischer    Process one <platform> element.
5809dd622cdSAndre Fischer
5819dd622cdSAndre Fischer    The corresponding platform descriptor is returned as a hash.
5829dd622cdSAndre Fischer
5839dd622cdSAndre Fischer=cut
584f219747dSAndre Fischersub ProcessPlatformDescription ($$)
585f219747dSAndre Fischer{
586f219747dSAndre Fischer    my ($element, $context) = @_;
587f219747dSAndre Fischer
588f219747dSAndre Fischer    my $descriptor = {};
589f219747dSAndre Fischer    # Mandatory tags.
5909dd622cdSAndre Fischer    foreach my $id ("id", "display-name", "archive-platform", "word-size", "package-types")
591f219747dSAndre Fischer    {
592f219747dSAndre Fischer        $descriptor->{$id} = $element->getAttribute($id);
5939dd622cdSAndre Fischer        die "release/platform has no attribute $id" unless defined $descriptor->{$id};
594f219747dSAndre Fischer    }
5959dd622cdSAndre Fischer    # Optional tags.
5969dd622cdSAndre Fischer    foreach my $id ("extension", "add-package-type-to-archive-name")
5979dd622cdSAndre Fischer    {
5981108b05eSAndre Fischer        my $value = $element->getAttribute($id);
5991108b05eSAndre Fischer        $descriptor->{$id} = $value if defined $value;
6009dd622cdSAndre Fischer    }
6019dd622cdSAndre Fischer
6021108b05eSAndre Fischer    $descriptor->{'add-package-type-to-archive-name'} = 0
6031108b05eSAndre Fischer        unless defined $descriptor->{'add-package-type-to-archive-name'};
6049dd622cdSAndre Fischer    $descriptor->{'package-types'} = [split(/;/, $descriptor->{'package-types'})];
6059dd622cdSAndre Fischer
6069dd622cdSAndre Fischer    return $descriptor;
6079dd622cdSAndre Fischer}
6089dd622cdSAndre Fischer
6099dd622cdSAndre Fischer
6109dd622cdSAndre Fischer
6119dd622cdSAndre Fischer
6129dd622cdSAndre Fischer=head2 ProcessDownloadDescription ($element, $context)
6139dd622cdSAndre Fischer
6149dd622cdSAndre Fischer    Process one <download> element.
6159dd622cdSAndre Fischer
6169dd622cdSAndre Fischer    The corresponding download descriptor is returned as a hash.
6179dd622cdSAndre Fischer
6189dd622cdSAndre Fischer=cut
6199dd622cdSAndre Fischersub ProcessDownloadDescription ($$)
6209dd622cdSAndre Fischer{
6219dd622cdSAndre Fischer    my ($element, $context) = @_;
622f219747dSAndre Fischer
6239dd622cdSAndre Fischer    my $descriptor = {};
6249dd622cdSAndre Fischer
6259dd622cdSAndre Fischer    # Mandatory tags.
6269dd622cdSAndre Fischer    foreach my $id ("platform-id", "base-url")
627f219747dSAndre Fischer    {
6289dd622cdSAndre Fischer        $descriptor->{$id} = $element->getAttribute($id);
6299dd622cdSAndre Fischer        die "release/download has no attribute $id" unless defined $descriptor->{$id};
630f219747dSAndre Fischer    }
631f219747dSAndre Fischer
6329dd622cdSAndre Fischer    return $descriptor;
633f219747dSAndre Fischer}
634f219747dSAndre Fischer
635f219747dSAndre Fischer
636f219747dSAndre Fischer
637f219747dSAndre Fischer
6389dd622cdSAndre Fischer=head2 ProcessPackageDescription ($element, $context)
6399dd622cdSAndre Fischer
6409dd622cdSAndre Fischer    Process one <package> element.
6419dd622cdSAndre Fischer
6429dd622cdSAndre Fischer    The corresponding package descriptor is returned as a hash.
6439dd622cdSAndre Fischer
6449dd622cdSAndre Fischer=cut
6451108b05eSAndre Fischersub ProcessPackageDescription ($$)
646f219747dSAndre Fischer{
6471108b05eSAndre Fischer    my ($element, $context) = @_;
648f219747dSAndre Fischer
649f219747dSAndre Fischer    my $descriptor = {};
6509dd622cdSAndre Fischer
651f219747dSAndre Fischer    # Mandatory tags.
6521108b05eSAndre Fischer    foreach my $id ("id", "target", "archive-path", "archive-name", "display-name")
653f219747dSAndre Fischer    {
654f219747dSAndre Fischer        $descriptor->{$id} = $element->getAttribute($id);
6559dd622cdSAndre Fischer        die "release/package has no attribute $id" unless defined $descriptor->{$id};
6569dd622cdSAndre Fischer        die "release/package attribute $id is empty" unless $descriptor->{$id} !~ /^\s*$/;
657f219747dSAndre Fischer    }
658f219747dSAndre Fischer    # Optional tags.
6599dd622cdSAndre Fischer    foreach my $id ("link-tooltip", "link-URL", "download-extension")
6601108b05eSAndre Fischer    {
6611108b05eSAndre Fischer        my $value = $element->getAttribute($id);
6621108b05eSAndre Fischer        $descriptor->{$id} = $value if defined $value;
6631108b05eSAndre Fischer    }
6641108b05eSAndre Fischer
6651108b05eSAndre Fischer    return $descriptor;
6661108b05eSAndre Fischer}
6671108b05eSAndre Fischer
6681108b05eSAndre Fischer
6691108b05eSAndre Fischer
6701108b05eSAndre Fischer
6711108b05eSAndre Fischer=head2 ProcessPlatformPackageDescription ($element, $context)
6721108b05eSAndre Fischer
6731108b05eSAndre Fischer    Process one <platform-package> element.
6741108b05eSAndre Fischer
6751108b05eSAndre Fischer    The corresponding package descriptor is returned as a hash.
6761108b05eSAndre Fischer
6771108b05eSAndre Fischer=cut
6781108b05eSAndre Fischersub ProcessPlatformPackageDescription ($$)
6791108b05eSAndre Fischer{
6801108b05eSAndre Fischer    my ($element, $context) = @_;
6811108b05eSAndre Fischer
6821108b05eSAndre Fischer    my $descriptor = {};
6831108b05eSAndre Fischer
6841108b05eSAndre Fischer    # Mandatory tags.
6851108b05eSAndre Fischer    foreach my $id ("platform-id", "package-id")
6869dd622cdSAndre Fischer    {
6879dd622cdSAndre Fischer        $descriptor->{$id} = $element->getAttribute($id);
6881108b05eSAndre Fischer        die "release/package has no attribute $id" unless defined $descriptor->{$id};
6891108b05eSAndre Fischer        die "release/package attribute $id is empty" unless $descriptor->{$id} !~ /^\s*$/;
6901108b05eSAndre Fischer    }
6911108b05eSAndre Fischer    # Optional tags.
6921108b05eSAndre Fischer    foreach my $id ("extension", "package-types")
6931108b05eSAndre Fischer    {
6941108b05eSAndre Fischer        my $value = $element->getAttribute($id);
6951108b05eSAndre Fischer        $descriptor->{$id} = $value if defined $value;
6961108b05eSAndre Fischer    }
6971108b05eSAndre Fischer    if (defined $descriptor->{'package-types'})
6981108b05eSAndre Fischer    {
6991108b05eSAndre Fischer        $descriptor->{'package-types'} = [split(/;/, $descriptor->{'package-types'})];
7009dd622cdSAndre Fischer    }
7019dd622cdSAndre Fischer
7029dd622cdSAndre Fischer    return $descriptor;
7039dd622cdSAndre Fischer}
7049dd622cdSAndre Fischer
7059dd622cdSAndre Fischer
7069dd622cdSAndre Fischer
7079dd622cdSAndre Fischer
7089dd622cdSAndre Fischer=head2 ProcessWikiPackageDescription ($element, $context)
7099dd622cdSAndre Fischer
7109dd622cdSAndre Fischer    Process one <wiki><package-ref> element.
7119dd622cdSAndre Fischer
7129dd622cdSAndre Fischer    The corresponding descriptor is returned as a hash.
7139dd622cdSAndre Fischer
7149dd622cdSAndre Fischer=cut
7159dd622cdSAndre Fischersub ProcessWikiPackageDescription ($$$)
7169dd622cdSAndre Fischer{
7179dd622cdSAndre Fischer    my ($element, $context, $release_descriptor) = @_;
7189dd622cdSAndre Fischer
7199dd622cdSAndre Fischer    my $descriptor = {};
7209dd622cdSAndre Fischer    # Mandatory tags.
7219dd622cdSAndre Fischer    foreach my $id ("package-id", "table")
722f219747dSAndre Fischer    {
723f219747dSAndre Fischer        $descriptor->{$id} = $element->getAttribute($id);
7249dd622cdSAndre Fischer        die "wiki/package-ref has no attribute $id" unless defined $descriptor->{$id};
7259dd622cdSAndre Fischer        die "wiki/package-ref attribute $id is empty" unless $descriptor->{$id} !~ /^\s*$/;
726f219747dSAndre Fischer    }
727f219747dSAndre Fischer
728f219747dSAndre Fischer    $descriptor->{'language-list'} = PostprocessLanguageList(
729f219747dSAndre Fischer        $element->getAttribute("language-list"),
730f219747dSAndre Fischer        $release_descriptor);
731f219747dSAndre Fischer    $descriptor->{'platform-list'} = PostprocessPlatformList(
732f219747dSAndre Fischer        $element->getAttribute("platform-list"),
733f219747dSAndre Fischer        $release_descriptor);
734f219747dSAndre Fischer
735f219747dSAndre Fischer    $descriptor->{'languages'} = {map{$_=>1} @{$descriptor->{'language-list'}}};
736f219747dSAndre Fischer    $descriptor->{'platforms'} = {map{$_=>1} @{$descriptor->{'platform-list'}}};
737f219747dSAndre Fischer
738f219747dSAndre Fischer    return $descriptor;
739f219747dSAndre Fischer}
740f219747dSAndre Fischer
741f219747dSAndre Fischer
742f219747dSAndre Fischer
743f219747dSAndre Fischer
7449dd622cdSAndre Fischer=head2 ProcessLanguageDescription ($element, $context)
7459dd622cdSAndre Fischer
7469dd622cdSAndre Fischer    Process one <language> element.
7479dd622cdSAndre Fischer
7489dd622cdSAndre Fischer    The corresponding language descriptor is returned as a hash.
7499dd622cdSAndre Fischer
7509dd622cdSAndre Fischer=cut
751f219747dSAndre Fischersub ProcessLanguageDescription ($$)
752f219747dSAndre Fischer{
753f219747dSAndre Fischer    my ($element, $context) = @_;
754f219747dSAndre Fischer
755f219747dSAndre Fischer    my $descriptor = {};
756f219747dSAndre Fischer    foreach my $id ("id", "english-name", "local-name")
757f219747dSAndre Fischer    {
758f219747dSAndre Fischer        $descriptor->{$id} = $element->getAttribute($id);
759f219747dSAndre Fischer        die "wiki/language has no attribute $id" unless defined $descriptor->{$id};
760f219747dSAndre Fischer    }
761f219747dSAndre Fischer
762f219747dSAndre Fischer    return $descriptor;
763f219747dSAndre Fischer}
764f219747dSAndre Fischer
765f219747dSAndre Fischer
766f219747dSAndre Fischer
767f219747dSAndre Fischer
7689dd622cdSAndre Fischer=head2 PostprocessLanguageList ($language_list, $release_descriptor)
7699dd622cdSAndre Fischer
7709dd622cdSAndre Fischer    Process a language list that is given as 'language-list' attribute to some tags.
7719dd622cdSAndre Fischer
7729dd622cdSAndre Fischer    If the attribute is missing, ie $language_list is undef, or its value is "all",
7739dd622cdSAndre Fischer    then the returned list of languages is set to all languages defined via <language> elements.
7749dd622cdSAndre Fischer
7759dd622cdSAndre Fischer=cut
776f219747dSAndre Fischersub PostprocessLanguageList ($$)
777f219747dSAndre Fischer{
778f219747dSAndre Fischer    my ($language_list, $release_descriptor) = @_;
779f219747dSAndre Fischer
780f219747dSAndre Fischer    my @matching_languages = ();
781f219747dSAndre Fischer    if ( ! defined $language_list
782f219747dSAndre Fischer        || $language_list eq "all")
783f219747dSAndre Fischer    {
784f219747dSAndre Fischer        @matching_languages = sort keys %{$release_descriptor->{'languages'}};
785f219747dSAndre Fischer    }
786f219747dSAndre Fischer    else
787f219747dSAndre Fischer    {
788f219747dSAndre Fischer        @matching_languages = split(/;/, $language_list);
789f219747dSAndre Fischer    }
790f219747dSAndre Fischer
791f219747dSAndre Fischer    return \@matching_languages;
792f219747dSAndre Fischer}
793f219747dSAndre Fischer
794f219747dSAndre Fischer
795f219747dSAndre Fischer
796f219747dSAndre Fischer
7979dd622cdSAndre Fischer=head2 PostprocessPlatformList ($platform_list, $release_descriptor)
7989dd622cdSAndre Fischer
7999dd622cdSAndre Fischer    Process a platform list that is given as 'platform-list' attribute to some tags.
8009dd622cdSAndre Fischer
8019dd622cdSAndre Fischer    If the attribute is missing, ie $platform_list is undef, or its value is "all",
8029dd622cdSAndre Fischer    then the returned list of platforms is set to all platforms defined via <platform> elements.
8039dd622cdSAndre Fischer
8049dd622cdSAndre Fischer=cut
805f219747dSAndre Fischersub PostprocessPlatformList ($$)
806f219747dSAndre Fischer{
807f219747dSAndre Fischer    my ($platform_list, $release_descriptor) = @_;
808f219747dSAndre Fischer
809f219747dSAndre Fischer    my @matching_platforms = ();
810f219747dSAndre Fischer    if ( ! defined $platform_list
811f219747dSAndre Fischer        || $platform_list eq "all")
812f219747dSAndre Fischer    {
813f219747dSAndre Fischer        @matching_platforms = sort keys %{$release_descriptor->{'platforms'}};
814f219747dSAndre Fischer    }
815f219747dSAndre Fischer    else
816f219747dSAndre Fischer    {
817f219747dSAndre Fischer        @matching_platforms = split(/;/, $platform_list);
818f219747dSAndre Fischer    }
819f219747dSAndre Fischer
820f219747dSAndre Fischer    return \@matching_platforms;
821f219747dSAndre Fischer}
822f219747dSAndre Fischer
823f219747dSAndre Fischer
824f219747dSAndre Fischer
825f219747dSAndre Fischer
8269dd622cdSAndre Fischer=head2 CheckLanguageSet ($context, @languages)
8279dd622cdSAndre Fischer
8289dd622cdSAndre Fischer    Compare the given list of languages with the one defined by the 'WITH_LANG' environment variable.
8299dd622cdSAndre Fischer
8309dd622cdSAndre Fischer    This is to ensure that configure --with-lang was called with the same set of languages that are
8319dd622cdSAndre Fischer    listed by the <language> elements.
8329dd622cdSAndre Fischer
8339dd622cdSAndre Fischer=cut
834f219747dSAndre Fischersub CheckLanguageSet ($@)
835f219747dSAndre Fischer{
836f219747dSAndre Fischer    my ($context, @languages) = @_;
837f219747dSAndre Fischer    my %configured_languages = map{$_=>1} split(/\s+/, $ENV{'WITH_LANG'});
838f219747dSAndre Fischer
839f219747dSAndre Fischer    my @missing_languages = ();
840f219747dSAndre Fischer    my @present_languages = ();
841f219747dSAndre Fischer    for my $language (@languages)
842f219747dSAndre Fischer    {
843f219747dSAndre Fischer        if (defined $configured_languages{$language})
844f219747dSAndre Fischer        {
845f219747dSAndre Fischer            push @present_languages, $language;
846f219747dSAndre Fischer        }
847f219747dSAndre Fischer        else
848f219747dSAndre Fischer        {
849f219747dSAndre Fischer            push @missing_languages, $language;
850f219747dSAndre Fischer        }
851f219747dSAndre Fischer    }
852f219747dSAndre Fischer
853f219747dSAndre Fischer    if (scalar @missing_languages > 0)
854f219747dSAndre Fischer    {
8559dd622cdSAndre Fischer        my $message_head = $context->{'keep-going'} ? "WARNING" : "ERROR";
8569dd622cdSAndre Fischer        printf STDERR "%s: there are languages that where not configured via --with-lang:\n", $message_head;
8579dd622cdSAndre Fischer        printf STDERR "%s:     %s\n", $message_head, join(", ", @missing_languages);
858f219747dSAndre Fischer        if ($context->{'keep-going'})
859f219747dSAndre Fischer        {
860f219747dSAndre Fischer            printf "    available languages:\n";
861f219747dSAndre Fischer            printf "        %s\n", join(", ", @present_languages);
862f219747dSAndre Fischer        }
863f219747dSAndre Fischer        else
864f219747dSAndre Fischer        {
8659dd622cdSAndre Fischer            printf STDERR "ERROR: please rerun configure with --with-lang=\"%s\"\n", join(" ", @languages);
8669dd622cdSAndre Fischer            exit(1);
867f219747dSAndre Fischer        }
868f219747dSAndre Fischer    }
869f219747dSAndre Fischer
870f219747dSAndre Fischer    return @present_languages;
871f219747dSAndre Fischer}
872f219747dSAndre Fischer
873f219747dSAndre Fischer
874f219747dSAndre Fischer
875f219747dSAndre Fischer
8761108b05eSAndre Fischer=head2 WriteMakefile ($release_descriptor, $context)
8779dd622cdSAndre Fischer
8789dd622cdSAndre Fischer    Write a makefile with all targets that match the <build> elements.
8799dd622cdSAndre Fischer
8809dd622cdSAndre Fischer    The use of a makefile allows us to use make to handle concurrent building.
8819dd622cdSAndre Fischer
8829dd622cdSAndre Fischer    When an output file was specified on the command line (option -o) then the
8839dd622cdSAndre Fischer    makefile is written to that file but make is not run.
8849dd622cdSAndre Fischer
8859dd622cdSAndre Fischer    When no output file was specified then the makefile is written to a temporary
8869dd622cdSAndre Fischer    file.  Then make is run for this makefile.
8879dd622cdSAndre Fischer
8889dd622cdSAndre Fischer=cut
889f219747dSAndre Fischersub WriteMakefile ($$)
890f219747dSAndre Fischer{
8911108b05eSAndre Fischer    my ($release_descriptor, $context) = @_;
892f219747dSAndre Fischer
8939dd622cdSAndre Fischer    my $filename = $context->{'output-filename'};
8949dd622cdSAndre Fischer    if ( ! defined $filename)
8959dd622cdSAndre Fischer    {
8969dd622cdSAndre Fischer        $filename = File::Temp->new();
8979dd622cdSAndre Fischer    }
898f219747dSAndre Fischer
8999dd622cdSAndre Fischer    # Collect the targets to make.
9009dd622cdSAndre Fischer    my @targets = ();
9011108b05eSAndre Fischer    foreach my $build (@{$release_descriptor->{'builds'}})
902f219747dSAndre Fischer    {
9031108b05eSAndre Fischer        my $platform_descriptor = GetCurrentPlatformDescriptor($release_descriptor);
9041108b05eSAndre Fischer        my $package_descriptor = $release_descriptor->{'packages'}->{$build->{'package-id'}};
9051108b05eSAndre Fischer        my $platform_package_descriptor = GetPlatformPackage(
9061108b05eSAndre Fischer            $release_descriptor,
9071108b05eSAndre Fischer            $platform_descriptor,
9081108b05eSAndre Fischer            $package_descriptor);
9091108b05eSAndre Fischer
9109dd622cdSAndre Fischer        foreach my $language_id (@{$build->{'language-list'}})
911f219747dSAndre Fischer        {
9121108b05eSAndre Fischer            foreach my $package_format (@{$platform_package_descriptor->{'package-types'}})
9139dd622cdSAndre Fischer            {
9149dd622cdSAndre Fischer                my $full_target = sprintf("%s_%s.%s",
9159dd622cdSAndre Fischer                    $package_descriptor->{'target'},
9169dd622cdSAndre Fischer                    $language_id,
9179dd622cdSAndre Fischer                    $package_format);
9189dd622cdSAndre Fischer                if ($context->{'build-only-missing'})
9199dd622cdSAndre Fischer                {
9201108b05eSAndre Fischer                    my ($archive_path, $archive_name) = GetInstallationPackageName(
9211108b05eSAndre Fischer                        $release_descriptor,
9221108b05eSAndre Fischer                        $platform_package_descriptor,
9239dd622cdSAndre Fischer                        $package_format,
9249dd622cdSAndre Fischer                        $language_id);
9251108b05eSAndre Fischer                    my $candidate = $archive_path . "/" . $archive_name;
9269dd622cdSAndre Fischer                    if (-f $candidate)
9279dd622cdSAndre Fischer                    {
9289dd622cdSAndre Fischer                        printf "download set for %s already exists, skipping\n", $full_target;
9299dd622cdSAndre Fischer                        next;
9309dd622cdSAndre Fischer                    }
9311108b05eSAndre Fischer                    else
9321108b05eSAndre Fischer                    {
9331108b05eSAndre Fischer                        printf "%s  %s\n", $archive_path, $archive_name;
9341108b05eSAndre Fischer                    }
9359dd622cdSAndre Fischer                }
9369dd622cdSAndre Fischer                push @targets, $full_target;
9379dd622cdSAndre Fischer            }
938f219747dSAndre Fischer        }
939f219747dSAndre Fischer    }
9409dd622cdSAndre Fischer
9419dd622cdSAndre Fischer    # Write the makefile.
9429dd622cdSAndre Fischer    open my $make, ">", $filename;
9439dd622cdSAndre Fischer
9449dd622cdSAndre Fischer    # Write dependencies of 'all' on the products in all languages.
9459dd622cdSAndre Fischer    print $make "all .PHONY : \\\n    ";
9469dd622cdSAndre Fischer    printf $make "%s\n", join(" \\\n    ", @targets);
947f219747dSAndre Fischer    printf $make "\n\n";
948f219747dSAndre Fischer
9499dd622cdSAndre Fischer    if ($context->{'dry-run'})
9509dd622cdSAndre Fischer    {
9519dd622cdSAndre Fischer        printf ("adding make fules for\n    %s\n", join("\n    ", @targets));
9529dd622cdSAndre Fischer    }
9539dd622cdSAndre Fischer
954f219747dSAndre Fischer    # Write rules that chain dmake in instsetoo_native/util.
9559dd622cdSAndre Fischer    foreach my $target (@targets)
9569dd622cdSAndre Fischer    {
9579dd622cdSAndre Fischer        printf $make "%s :\n", $target;
9589dd622cdSAndre Fischer        printf $make "\tdmake \$@ release=t\n";
9599dd622cdSAndre Fischer    }
9609dd622cdSAndre Fischer    close $make;
9619dd622cdSAndre Fischer
9629dd622cdSAndre Fischer
9639dd622cdSAndre Fischer    if ( ! defined $context->{'output-filename'})
964f219747dSAndre Fischer    {
9659dd622cdSAndre Fischer        # Caller wants us to run make.
9669dd622cdSAndre Fischer        my $path = $ENV{'SRC_ROOT'} . "/instsetoo_native/util";
9679dd622cdSAndre Fischer        my $command = sprintf("make -f \"%s\" -C \"%s\" -j%d",
9689dd622cdSAndre Fischer            $filename,
9699dd622cdSAndre Fischer            $path,
9709dd622cdSAndre Fischer            $context->{'max-process-count'});
9719dd622cdSAndre Fischer        if ($context->{'dry-run'})
972f219747dSAndre Fischer        {
9739dd622cdSAndre Fischer            printf "would run %s\n", $command;
9749dd622cdSAndre Fischer        }
9759dd622cdSAndre Fischer        else
9769dd622cdSAndre Fischer        {
9779dd622cdSAndre Fischer            printf "running %s\n", $command;
9789dd622cdSAndre Fischer            system($command);
979f219747dSAndre Fischer        }
980f219747dSAndre Fischer    }
981f219747dSAndre Fischer}
982f219747dSAndre Fischer
983f219747dSAndre Fischer
984f219747dSAndre Fischer
985f219747dSAndre Fischer
986f219747dSAndre Fischersub Upload ($$)
987f219747dSAndre Fischer{
9881108b05eSAndre Fischer    my ($release_descriptor, $context) = @_;
989f219747dSAndre Fischer
990f219747dSAndre Fischer    if ( ! defined $context->{'upload-destination'})
991f219747dSAndre Fischer    {
992f219747dSAndre Fischer        printf STDERR "ERROR: upload destination is missing\n";
993f219747dSAndre Fischer        PrintUsageAndExit();
994f219747dSAndre Fischer    }
995f219747dSAndre Fischer
9961108b05eSAndre Fischer    my @download_sets = CollectDownloadSets($release_descriptor);
9979dd622cdSAndre Fischer
9989dd622cdSAndre Fischer    ProvideChecksums($context, @download_sets);
9999dd622cdSAndre Fischer    my $source_path = PrepareUploadArea($context, @download_sets);
10009dd622cdSAndre Fischer    if ( ! defined $source_path)
10019dd622cdSAndre Fischer    {
10029dd622cdSAndre Fischer        exit(1);
10039dd622cdSAndre Fischer    }
10049dd622cdSAndre Fischer    if ( ! UploadFilesViaRsync($context, $source_path, @download_sets))
10059dd622cdSAndre Fischer    {
10069dd622cdSAndre Fischer        exit(1);
10079dd622cdSAndre Fischer    }
10089dd622cdSAndre Fischer}
10099dd622cdSAndre Fischer
10109dd622cdSAndre Fischer
10119dd622cdSAndre Fischer
10129dd622cdSAndre Fischer
10139dd622cdSAndre Fischer=head2 PrepareUploadArea ($context, @download_sets)
10149dd622cdSAndre Fischer
10159dd622cdSAndre Fischer    Create a temporary directory with the same sub directory strcuture that is requested in the upload location.
10169dd622cdSAndre Fischer    The files that are to be uploaded are not copied but linked into this temporary directory tree.
10179dd622cdSAndre Fischer
10189dd622cdSAndre Fischer    Returns the name of the temporary directory.
10199dd622cdSAndre Fischer
10209dd622cdSAndre Fischer=cut
10219dd622cdSAndre Fischersub PrepareUploadArea ($@)
10229dd622cdSAndre Fischer{
10239dd622cdSAndre Fischer    my ($context, @download_sets) = @_;
10249dd622cdSAndre Fischer
10259dd622cdSAndre Fischer    my $tmpdir = File::Temp->newdir();
10269dd622cdSAndre Fischer    foreach my $download_set (@download_sets)
1027f219747dSAndre Fischer    {
10289dd622cdSAndre Fischer        foreach my $extension ("", ".md5", ".sha256", ".asc")
1029f219747dSAndre Fischer        {
10309dd622cdSAndre Fischer            my $basename = sprintf("%s%s", $download_set->{'archive-name'}, $extension);
10311108b05eSAndre Fischer            my $source_path = $download_set->{'source-path'};
10321108b05eSAndre Fischer            my $source = sprintf("%s/%s", $source_path, $basename);
10331108b05eSAndre Fischer            my $target_path = sprintf("%s/%s", $tmpdir, $download_set->{'destination-path'});
10349dd622cdSAndre Fischer            my $target = sprintf("%s/%s", $target_path, $basename);
10359dd622cdSAndre Fischer            if ($context->{'dry-run'})
1036f219747dSAndre Fischer            {
10379dd622cdSAndre Fischer                printf "would create link for %s\n", $basename;
10381108b05eSAndre Fischer                printf "    %s\n", $source_path;
10391108b05eSAndre Fischer                printf " to %s\n", $target_path;
1040f219747dSAndre Fischer            }
10419dd622cdSAndre Fischer            else
1042f219747dSAndre Fischer            {
10439dd622cdSAndre Fischer                mkpath($target_path);
10449dd622cdSAndre Fischer                unlink $target if ( -f $target);
10459dd622cdSAndre Fischer                my $result = symlink($source, $target);
10469dd622cdSAndre Fischer                if ($result != 1)
1047f219747dSAndre Fischer                {
10489dd622cdSAndre Fischer                    printf "ERROR: can not created symbolic link to %s\n", $basename;
10499dd622cdSAndre Fischer                    printf "       %s\n", $source;
10509dd622cdSAndre Fischer                    printf "    -> %s\n", $target;
10519dd622cdSAndre Fischer                    return undef;
1052f219747dSAndre Fischer                }
1053f219747dSAndre Fischer            }
10549dd622cdSAndre Fischer        }
10559dd622cdSAndre Fischer    }
1056f219747dSAndre Fischer
10579dd622cdSAndre Fischer    return $tmpdir;
10589dd622cdSAndre Fischer}
1059f219747dSAndre Fischer
10609dd622cdSAndre Fischer
10619dd622cdSAndre Fischer
10629dd622cdSAndre Fischer
10639dd622cdSAndre Fischersub UploadFilesViaRsync ($$@)
10649dd622cdSAndre Fischer{
10659dd622cdSAndre Fischer    my ($context, $source_path, @download_sets) = @_;
10669dd622cdSAndre Fischer
10679dd622cdSAndre Fischer
10689dd622cdSAndre Fischer    # Collect the rsync flags.
10699dd622cdSAndre Fischer    my @rsync_options = (
10709dd622cdSAndre Fischer        "-L",         # Copy linked files
10719dd622cdSAndre Fischer        "-a",         # Transfer the local attributes and modification times.
10729dd622cdSAndre Fischer        "-c",         # Use checksums to compare source and destination files.
10739dd622cdSAndre Fischer        "--progress", # Show a progress indicator
10749dd622cdSAndre Fischer        "--partial",  # Try to resume a previously failed upload
10759dd622cdSAndre Fischer        );
10769dd622cdSAndre Fischer
10779dd622cdSAndre Fischer    # (Optional) Add flags for upload to ssh server
10789dd622cdSAndre Fischer    my $upload_destination = $context->{'upload-destination'};
10799dd622cdSAndre Fischer    if ($upload_destination =~ /@/)
10809dd622cdSAndre Fischer    {
10819dd622cdSAndre Fischer        push @rsync_options, ("-e", "ssh");
10829dd622cdSAndre Fischer    }
10839dd622cdSAndre Fischer
10849dd622cdSAndre Fischer    # Set up the rsync command.
10859dd622cdSAndre Fischer    my $command = sprintf("rsync %s \"%s/\" \"%s\"",
10869dd622cdSAndre Fischer        join(" ", @rsync_options),
10879dd622cdSAndre Fischer        $source_path,
10889dd622cdSAndre Fischer        $upload_destination);
10899dd622cdSAndre Fischer    printf "%s\n", $command;
10909dd622cdSAndre Fischer
10919dd622cdSAndre Fischer    if ($context->{'dry-run'})
10929dd622cdSAndre Fischer    {
10939dd622cdSAndre Fischer        printf "would run %s up to %d times\n", $command, $context->{'max-upload-count'};
10949dd622cdSAndre Fischer    }
10959dd622cdSAndre Fischer    else
10969dd622cdSAndre Fischer    {
10979dd622cdSAndre Fischer        # Run the command.  If it fails, repeat a number of times.
10989dd622cdSAndre Fischer        my $max_run_count = $context->{'max-upload-count'};
10999dd622cdSAndre Fischer        for (my $run_index=1; $run_index<=$max_run_count && scalar @download_sets>0; ++$run_index)
11009dd622cdSAndre Fischer        {
11019dd622cdSAndre Fischer            my $result = system($command);
11029dd622cdSAndre Fischer            printf "%d %d\n", $result, $?;
11039dd622cdSAndre Fischer            return 1 if $result == 0;
1104f219747dSAndre Fischer        }
11059dd622cdSAndre Fischer        printf "ERROR: could not upload all files without error in %d runs\n", $max_run_count;
11069dd622cdSAndre Fischer        return 0;
1107f219747dSAndre Fischer    }
1108f219747dSAndre Fischer}
1109f219747dSAndre Fischer
1110f219747dSAndre Fischer
1111f219747dSAndre Fischer
1112f219747dSAndre Fischer
1113f219747dSAndre Fischersub CollectDownloadSets ($)
1114f219747dSAndre Fischer{
11151108b05eSAndre Fischer    my ($release_descriptor) = @_;
1116f219747dSAndre Fischer
1117f219747dSAndre Fischer    my @download_sets = ();
1118f219747dSAndre Fischer
11191108b05eSAndre Fischer    foreach my $platform_descriptor (values %{$release_descriptor->{'platforms'}})
1120f219747dSAndre Fischer    {
11219dd622cdSAndre Fischer        my $platform_path = sprintf("%s/instsetoo_native/%s",
11229dd622cdSAndre Fischer            $ENV{'SOLARSRC'},
11239dd622cdSAndre Fischer            $platform_descriptor->{'id'});
11249dd622cdSAndre Fischer        if ( ! -d $platform_path)
11259dd622cdSAndre Fischer        {
11269dd622cdSAndre Fischer            printf "ignoring missing %s\n", $platform_path;
11279dd622cdSAndre Fischer            next;
11289dd622cdSAndre Fischer        }
11291108b05eSAndre Fischer        for my $package_descriptor (values %{$release_descriptor->{'packages'}})
1130f219747dSAndre Fischer        {
11311108b05eSAndre Fischer            my $platform_package_descriptor = GetPlatformPackage(
11321108b05eSAndre Fischer                $release_descriptor,
11331108b05eSAndre Fischer                $platform_descriptor,
11341108b05eSAndre Fischer                $package_descriptor);
11359dd622cdSAndre Fischer            my @package_formats = @{$platform_descriptor->{'package-types'}};
11369dd622cdSAndre Fischer            for my $package_format (@package_formats)
1137f219747dSAndre Fischer            {
11381108b05eSAndre Fischer                for my $language_id (@{$release_descriptor->{'language-ids'}})
1139f219747dSAndre Fischer                {
11401108b05eSAndre Fischer                    my ($archive_path, $archive_name) = GetInstallationPackageName(
11411108b05eSAndre Fischer                        $release_descriptor,
11421108b05eSAndre Fischer                        $platform_package_descriptor,
11439dd622cdSAndre Fischer                        $package_format,
11449dd622cdSAndre Fischer                        $language_id);
11451108b05eSAndre Fischer                    my $candidate = $archive_path."/".$archive_name;
11469dd622cdSAndre Fischer                    if ( ! -f $candidate)
11479dd622cdSAndre Fischer                    {
11489dd622cdSAndre Fischer#                        printf STDERR "ERROR: can not find download set '%s'\n", $candidate;
11499dd622cdSAndre Fischer                        next;
11509dd622cdSAndre Fischer                    }
11519dd622cdSAndre Fischer                    printf "adding %s\n", $archive_name;
11521108b05eSAndre Fischer                    my $download_set = {
11531108b05eSAndre Fischer                        'source-path' => $archive_path,
11549dd622cdSAndre Fischer                        'archive-name' => $archive_name,
11551108b05eSAndre Fischer                        'platform' => $platform_descriptor->{'archive-platform'},
11569dd622cdSAndre Fischer                        'destination-path' => sprintf("developer-snapshots/%s/%s",
11571108b05eSAndre Fischer                            $release_descriptor->{'name'},
11581108b05eSAndre Fischer                            $platform_descriptor->{'archive-platform'})
11599dd622cdSAndre Fischer                    };
11601108b05eSAndre Fischer                    printf "    %s\n", $download_set->{'destination-path'};
11611108b05eSAndre Fischer                    push @download_sets, $download_set;
1162f219747dSAndre Fischer                }
1163f219747dSAndre Fischer            }
1164f219747dSAndre Fischer        }
1165f219747dSAndre Fischer    }
1166f219747dSAndre Fischer
1167f219747dSAndre Fischer    return @download_sets;
1168f219747dSAndre Fischer}
1169f219747dSAndre Fischer
1170f219747dSAndre Fischer
1171f219747dSAndre Fischer
1172f219747dSAndre Fischer
11739dd622cdSAndre Fischer=head2 ProvideChecksums ($context, @download_sets)
11749dd622cdSAndre Fischer
11759dd622cdSAndre Fischer    Create checksums in MD5 and SHA256 format and a gpg signature for the given download set.
11769dd622cdSAndre Fischer    The checksums are not created when they already exists and are not older than the download set.
11779dd622cdSAndre Fischer
11789dd622cdSAndre Fischer=cut
11799dd622cdSAndre Fischersub ProvideChecksums ($@)
1180f219747dSAndre Fischer{
11819dd622cdSAndre Fischer    my ($context, @download_sets) = @_;
11829dd622cdSAndre Fischer
11839dd622cdSAndre Fischer    my @asc_requests = ();
11849dd622cdSAndre Fischer    foreach my $download_set (@download_sets)
11859dd622cdSAndre Fischer    {
11869dd622cdSAndre Fischer        printf "%s\n", $download_set->{'archive-name'};
11879dd622cdSAndre Fischer        my $full_archive_name = $download_set->{'source-path'} . "/" . $download_set->{'archive-name'};
11889dd622cdSAndre Fischer        $full_archive_name = Trim(qx(cygpath -u "$full_archive_name"));
1189f219747dSAndre Fischer
11909dd622cdSAndre Fischer        my $md5_filename = $full_archive_name . ".md5";
11919dd622cdSAndre Fischer        if ( ! -f $md5_filename || IsOlderThan($md5_filename, $full_archive_name))
11929dd622cdSAndre Fischer        {
11939dd622cdSAndre Fischer            if ($context->{'dry-run'})
11949dd622cdSAndre Fischer            {
11959dd622cdSAndre Fischer                printf "    would create MD5\n";
11969dd622cdSAndre Fischer            }
11979dd622cdSAndre Fischer            else
11989dd622cdSAndre Fischer            {
11999dd622cdSAndre Fischer                my $digest = Digest::MD5->new();
12001108b05eSAndre Fischer                open my ($in), $full_archive_name;
12019dd622cdSAndre Fischer                $digest->addfile($in);
12029dd622cdSAndre Fischer                my $checksum = $digest->hexdigest();
12039dd622cdSAndre Fischer                close $in;
1204f219747dSAndre Fischer
12051108b05eSAndre Fischer                open my ($out), ">", $md5_filename;
12069dd622cdSAndre Fischer                printf $out "%s *%s", $checksum, $download_set->{'archive-name'};
12079dd622cdSAndre Fischer                close $out;
1208f219747dSAndre Fischer
12099dd622cdSAndre Fischer                printf "    created MD5\n";
12109dd622cdSAndre Fischer            }
12119dd622cdSAndre Fischer        }
12129dd622cdSAndre Fischer        else
12139dd622cdSAndre Fischer        {
12149dd622cdSAndre Fischer            printf "    MD5 already exists\n";
12159dd622cdSAndre Fischer        }
1216f219747dSAndre Fischer
12179dd622cdSAndre Fischer        my $sha256_filename = $full_archive_name . ".sha256";
12189dd622cdSAndre Fischer        if ( ! -f $sha256_filename || IsOlderThan($sha256_filename, $full_archive_name))
12199dd622cdSAndre Fischer        {
12209dd622cdSAndre Fischer            if ($context->{'dry-run'})
12219dd622cdSAndre Fischer            {
12229dd622cdSAndre Fischer                printf "    would create SHA256\n";
12239dd622cdSAndre Fischer            }
12249dd622cdSAndre Fischer            else
12259dd622cdSAndre Fischer            {
12269dd622cdSAndre Fischer                my $digest = Digest::SHA->new("sha256");
12271108b05eSAndre Fischer                open my ($in), $full_archive_name;
12289dd622cdSAndre Fischer                $digest->addfile($in);
12299dd622cdSAndre Fischer                my $checksum = $digest->hexdigest();
12309dd622cdSAndre Fischer                close $in;
1231f219747dSAndre Fischer
12321108b05eSAndre Fischer                open my ($out), ">", $sha256_filename;
12339dd622cdSAndre Fischer                printf $out "%s *%s", $checksum, $download_set->{'archive-name'};
12349dd622cdSAndre Fischer                close $out;
1235f219747dSAndre Fischer
12369dd622cdSAndre Fischer                printf "    created SHA256\n";
12379dd622cdSAndre Fischer            }
12389dd622cdSAndre Fischer        }
12399dd622cdSAndre Fischer        else
12409dd622cdSAndre Fischer        {
12419dd622cdSAndre Fischer            printf "    SHA256 already exists\n";
12429dd622cdSAndre Fischer        }
1243f219747dSAndre Fischer
12449dd622cdSAndre Fischer        my $asc_filename = $full_archive_name . ".asc";
12459dd622cdSAndre Fischer        if ( ! -f $asc_filename || IsOlderThan($asc_filename, $full_archive_name))
12469dd622cdSAndre Fischer        {
12479dd622cdSAndre Fischer            if ($context->{'dry-run'})
12489dd622cdSAndre Fischer            {
12499dd622cdSAndre Fischer                printf "    would create ASC\n";
12509dd622cdSAndre Fischer            }
12519dd622cdSAndre Fischer            else
12529dd622cdSAndre Fischer            {
12539dd622cdSAndre Fischer                # gpg seems not to be able to sign more than one file at a time.
12549dd622cdSAndre Fischer                # Password has to be provided every time.
12559dd622cdSAndre Fischer                my $command = sprintf("gpg --armor --detach-sig \"%s\"", $full_archive_name);
12569dd622cdSAndre Fischer                print $command;
12579dd622cdSAndre Fischer                my $result = system($command);
12589dd622cdSAndre Fischer                printf "    created ASC\n";
12599dd622cdSAndre Fischer            }
12609dd622cdSAndre Fischer        }
12619dd622cdSAndre Fischer        else
12629dd622cdSAndre Fischer        {
12639dd622cdSAndre Fischer            printf "    ASC already exists\n";
12649dd622cdSAndre Fischer        }
1265f219747dSAndre Fischer    }
1266f219747dSAndre Fischer}
1267f219747dSAndre Fischer
1268f219747dSAndre Fischer
1269f219747dSAndre Fischer
1270f219747dSAndre Fischer
12719dd622cdSAndre Fischer=head2 IsOlderThan ($filename1, $filename2)
12729dd622cdSAndre Fischer
12739dd622cdSAndre Fischer    Return true (1) if the last modification date of $filename1 is older than (<) that of $filename2.
12749dd622cdSAndre Fischer
12759dd622cdSAndre Fischer=cut
12769dd622cdSAndre Fischersub IsOlderThan ($$)
1277f219747dSAndre Fischer{
12789dd622cdSAndre Fischer    my ($filename1, $filename2) = @_;
12799dd622cdSAndre Fischer
12809dd622cdSAndre Fischer    my @stat1 = stat $filename1;
12819dd622cdSAndre Fischer    my @stat2 = stat $filename2;
12829dd622cdSAndre Fischer
12839dd622cdSAndre Fischer    return $stat1[9] < $stat2[9];
1284f219747dSAndre Fischer}
1285f219747dSAndre Fischer
1286f219747dSAndre Fischer
1287f219747dSAndre Fischer
1288f219747dSAndre Fischer
12891108b05eSAndre Fischersub GetInstallationPackageName ($$$$)
1290f219747dSAndre Fischer{
12911108b05eSAndre Fischer    my ($release_descriptor, $platform_package_descriptor, $package_format, $language) = @_;
12929dd622cdSAndre Fischer
12931108b05eSAndre Fischer    my $path = ResolveTemplate(
12941108b05eSAndre Fischer        $platform_package_descriptor->{'archive-path'},
12951108b05eSAndre Fischer        $release_descriptor,
12961108b05eSAndre Fischer        $platform_package_descriptor,
12971108b05eSAndre Fischer        $package_format,
12981108b05eSAndre Fischer        $language);
12991108b05eSAndre Fischer    my $name = ResolveTemplate(
13001108b05eSAndre Fischer        $platform_package_descriptor->{'archive-name'},
13011108b05eSAndre Fischer        $release_descriptor,
13021108b05eSAndre Fischer        $platform_package_descriptor,
13031108b05eSAndre Fischer        $package_format,
13041108b05eSAndre Fischer        $language);
13059dd622cdSAndre Fischer
13061108b05eSAndre Fischer    return ($path, $name);
13079dd622cdSAndre Fischer}
13089dd622cdSAndre Fischer
13099dd622cdSAndre Fischer
13109dd622cdSAndre Fischer
13119dd622cdSAndre Fischer
13121108b05eSAndre Fischersub ResolveTemplate ($$$$$)
13139dd622cdSAndre Fischer{
13141108b05eSAndre Fischer    my ($template, $release_descriptor, $platform_package_descriptor, $package_format, $language) = @_;
13151108b05eSAndre Fischer
13161108b05eSAndre Fischer    my $archive_package_type = "";
13171108b05eSAndre Fischer    if ($platform_package_descriptor->{'add-package-type-to-archive-name'} =~ /^(1|true|yes)$/i)
13181108b05eSAndre Fischer    {
13191108b05eSAndre Fischer        $archive_package_type = "-".$package_format;
13201108b05eSAndre Fischer    }
13219dd622cdSAndre Fischer    my $full_language = $language;
13229dd622cdSAndre Fischer    if ($EnUSBasedLanguages{$language})
1323f219747dSAndre Fischer    {
13249dd622cdSAndre Fischer        $full_language = "en-US_".$language;
1325f219747dSAndre Fischer    }
13261108b05eSAndre Fischer    my $extension = $platform_package_descriptor->{'download-extension'};
13271108b05eSAndre Fischer    if ( ! defined $extension)
13281108b05eSAndre Fischer    {
13291108b05eSAndre Fischer        $extension = $platform_package_descriptor->{'extension'};
13301108b05eSAndre Fischer    }
13311108b05eSAndre Fischer
13321108b05eSAndre Fischer    my $old_to_new_version_dash = sprintf(
13331108b05eSAndre Fischer        "v-%s_v-%s",
13341108b05eSAndre Fischer        $release_descriptor->{'previous-version'},
13351108b05eSAndre Fischer        $release_descriptor->{'version'});
13361108b05eSAndre Fischer    $old_to_new_version_dash =~ s/\./-/g;
13371108b05eSAndre Fischer    my $old_to_new_version_dots = sprintf(
13381108b05eSAndre Fischer        "%s-%s",
13391108b05eSAndre Fischer        $release_descriptor->{'previous-version'},
13401108b05eSAndre Fischer        $release_descriptor->{'version'});
13419dd622cdSAndre Fischer
13421108b05eSAndre Fischer
13431108b05eSAndre Fischer    my $name = $template;
13441108b05eSAndre Fischer
134586e1cf34SPedro Giffuni    # Resolve %? template parameters.
13461108b05eSAndre Fischer    $name =~ s/%V/$release_descriptor->{'version'}/g;
13471108b05eSAndre Fischer    $name =~ s/%W/$old_to_new_version_dash/g;
13481108b05eSAndre Fischer    $name =~ s/%w/$old_to_new_version_dots/g;
13491108b05eSAndre Fischer    $name =~ s/%P/$platform_package_descriptor->{'archive-platform'}/g;
13501108b05eSAndre Fischer    $name =~ s/%t/$archive_package_type/g;
13511108b05eSAndre Fischer    $name =~ s/%T/$package_format/g;
13521108b05eSAndre Fischer    $name =~ s/%l/$full_language/g;
13531108b05eSAndre Fischer    $name =~ s/%L/$language/g;
13541108b05eSAndre Fischer    $name =~ s/%E/$extension/g;
13551108b05eSAndre Fischer
13561108b05eSAndre Fischer    # Resolve $name environment references.
13571108b05eSAndre Fischer    while ($name =~ /^(.*?)\$([a-zA-Z0-9_]+)(.*)$/)
13581108b05eSAndre Fischer    {
13591108b05eSAndre Fischer        $name = $1 . $ENV{$2} . $3;
13601108b05eSAndre Fischer    }
13611108b05eSAndre Fischer
13621108b05eSAndre Fischer    return $name;
1363f219747dSAndre Fischer}
1364f219747dSAndre Fischer
1365f219747dSAndre Fischer
1366f219747dSAndre Fischer
1367f219747dSAndre Fischer
13689dd622cdSAndre Fischersub GetCurrentPlatformDescriptor ($)
1369f219747dSAndre Fischer{
13701108b05eSAndre Fischer    my ($release_descriptor) = @_;
13719dd622cdSAndre Fischer
13721108b05eSAndre Fischer    my $platform_descriptor = $release_descriptor->{'platforms'}->{$ENV{'INPATH'}};
13739dd622cdSAndre Fischer    if ( ! defined $platform_descriptor)
1374f219747dSAndre Fischer    {
13759dd622cdSAndre Fischer        printf STDERR "ERROR: platform '%s' is not supported\n", $ENV{'INPATH'};
1376f219747dSAndre Fischer    }
13779dd622cdSAndre Fischer    return $platform_descriptor;
1378f219747dSAndre Fischer}
1379f219747dSAndre Fischer
1380f219747dSAndre Fischer
1381f219747dSAndre Fischer
1382f219747dSAndre Fischer
13831108b05eSAndre Fischersub GetPlatformPackage ($$$)
13841108b05eSAndre Fischer{
13851108b05eSAndre Fischer    my ($release_descriptor, $platform_descriptor, $package_descriptor) = @_;
13861108b05eSAndre Fischer    my $key = sprintf("%s/%s", $platform_descriptor->{'id'}, $package_descriptor->{'id'});
13871108b05eSAndre Fischer
13881108b05eSAndre Fischer    my $platform_package = $release_descriptor->{'platform-packages'}->{$key};
13891108b05eSAndre Fischer    $platform_package = {}
13901108b05eSAndre Fischer        unless defined $platform_package;
13911108b05eSAndre Fischer
13921108b05eSAndre Fischer    my $joined_descriptor = {
13931108b05eSAndre Fischer        %$platform_descriptor,
13941108b05eSAndre Fischer        %$package_descriptor,
13951108b05eSAndre Fischer        %$platform_package,
13961108b05eSAndre Fischer        'id' => $key,
13971108b05eSAndre Fischer        'platform-id' => $platform_descriptor->{'id'},
13981108b05eSAndre Fischer        'package-id' => $package_descriptor->{'id'}
13991108b05eSAndre Fischer    };
14001108b05eSAndre Fischer    return $joined_descriptor;
14011108b05eSAndre Fischer}
14021108b05eSAndre Fischer
14031108b05eSAndre Fischer
14041108b05eSAndre Fischer
14051108b05eSAndre Fischer
1406f219747dSAndre Fischersub Wiki ($$)
1407f219747dSAndre Fischer{
1408f219747dSAndre Fischer    my ($release_descriptor, $context) = @_;
1409f219747dSAndre Fischer
1410f219747dSAndre Fischer    open my $out, ">", $context->{'output-filename'};
1411f219747dSAndre Fischer
1412f219747dSAndre Fischer    my @table_list = GetTableList($release_descriptor);
1413f219747dSAndre Fischer    foreach my $table_name (@table_list)
1414f219747dSAndre Fischer    {
1415f219747dSAndre Fischer        my @table_packages = GetPackagesForTable($release_descriptor, $table_name);
1416f219747dSAndre Fischer        my @table_languages = GetLanguagesForTable($release_descriptor, @table_packages);
1417f219747dSAndre Fischer        my @table_platforms = GetPlatformsForTable($release_descriptor, @table_packages);
1418f219747dSAndre Fischer
14199dd622cdSAndre Fischer        printf "packages: %s\n", join(", ", map {$_->{'package'}->{'display-name'}} @table_packages);
1420f219747dSAndre Fischer        printf "languages: %s\n", join(", ", map {$_->{'english-name'}} @table_languages);
1421f219747dSAndre Fischer        printf "platforms: %s\n", join(", ", map {$_->{'id'}} @table_platforms);
1422f219747dSAndre Fischer
1423f219747dSAndre Fischer        print $out "{| class=\"wikitable\"\n";
14249dd622cdSAndre Fischer
14259dd622cdSAndre Fischer        # Write the table head.
1426f219747dSAndre Fischer        print $out "|-\n";
1427f219747dSAndre Fischer        print $out "! colspan=\"2\" | Language<br>The names do not refer to countries\n";
1428f219747dSAndre Fischer        print $out "! Type\n";
1429f219747dSAndre Fischer        foreach my $platform_descriptor (@table_platforms)
1430f219747dSAndre Fischer        {
14319dd622cdSAndre Fischer            foreach my $package_type (@{$platform_descriptor->{'package-types'}})
14329dd622cdSAndre Fischer            {
14339dd622cdSAndre Fischer                printf $out "! %s<br>%s bit<br>%s\n",
1434f219747dSAndre Fischer                $platform_descriptor->{'display-name'},
1435f219747dSAndre Fischer                $platform_descriptor->{'word-size'},
14369dd622cdSAndre Fischer                uc($package_type);
14379dd622cdSAndre Fischer            }
1438f219747dSAndre Fischer        }
1439f219747dSAndre Fischer
1440f219747dSAndre Fischer        foreach my $language_descriptor (@table_languages)
1441f219747dSAndre Fischer        {
1442f219747dSAndre Fischer            if ($context->{'check-links'})
1443f219747dSAndre Fischer            {
1444f219747dSAndre Fischer                $| = 1;
14451108b05eSAndre Fischer                printf "%-5s: ", $language_descriptor->{'id'};
1446f219747dSAndre Fischer            }
1447f219747dSAndre Fischer
1448f219747dSAndre Fischer            print $out "|-\n";
1449f219747dSAndre Fischer            printf $out "| rowspan=\"%d\" | %s\n", scalar @table_packages, $language_descriptor->{'english-name'};
1450f219747dSAndre Fischer            printf $out "| rowspan=\"%d\" | %s\n", scalar @table_packages, $language_descriptor->{'local-name'};
1451f219747dSAndre Fischer
1452f219747dSAndre Fischer            my $is_first = 1;
14539dd622cdSAndre Fischer            foreach my $wiki_package_descriptor (@table_packages)
1454f219747dSAndre Fischer            {
14559dd622cdSAndre Fischer                my $package_descriptor = $wiki_package_descriptor->{'package'};
14569dd622cdSAndre Fischer
1457f219747dSAndre Fischer                if ($is_first)
1458f219747dSAndre Fischer                {
1459f219747dSAndre Fischer                    $is_first = 0;
1460f219747dSAndre Fischer                }
1461f219747dSAndre Fischer                else
1462f219747dSAndre Fischer                {
1463f219747dSAndre Fischer                    printf $out "|-\n";
1464f219747dSAndre Fischer                }
1465f219747dSAndre Fischer
1466f219747dSAndre Fischer                # Write the name of the package, e.g. Full Install or Langpack.
1467f219747dSAndre Fischer                if (defined $package_descriptor->{'link-URL'})
1468f219747dSAndre Fischer                {
1469f219747dSAndre Fischer                    printf $out "| [%s %s]\n",
1470f219747dSAndre Fischer                    $package_descriptor->{'link-URL'},
1471f219747dSAndre Fischer                    $package_descriptor->{'display-name'};
1472f219747dSAndre Fischer                }
1473f219747dSAndre Fischer                else
1474f219747dSAndre Fischer                {
1475f219747dSAndre Fischer                    printf $out "| %s\n", $package_descriptor->{'display-name'};
1476f219747dSAndre Fischer                }
1477f219747dSAndre Fischer
1478f219747dSAndre Fischer                foreach my $platform_descriptor (@table_platforms)
1479f219747dSAndre Fischer                {
14801108b05eSAndre Fischer                    my $platform_package_descriptor = GetPlatformPackage(
14811108b05eSAndre Fischer                        $release_descriptor,
14821108b05eSAndre Fischer                        $platform_descriptor,
14831108b05eSAndre Fischer                        $package_descriptor);
14841108b05eSAndre Fischer
14851108b05eSAndre Fischer                    foreach my $package_type (@{$platform_package_descriptor->{'package-types'}})
14869dd622cdSAndre Fischer                    {
14879dd622cdSAndre Fischer                        WriteDownloadLinks(
14889dd622cdSAndre Fischer                            $out,
14899dd622cdSAndre Fischer                            $release_descriptor,
14909dd622cdSAndre Fischer                            $context,
14919dd622cdSAndre Fischer                            $language_descriptor,
14929dd622cdSAndre Fischer                            $wiki_package_descriptor,
14931108b05eSAndre Fischer                            $platform_package_descriptor,
14949dd622cdSAndre Fischer                            $package_type);
14959dd622cdSAndre Fischer                    }
1496f219747dSAndre Fischer                }
1497f219747dSAndre Fischer            }
1498f219747dSAndre Fischer
1499f219747dSAndre Fischer            if ($context->{'check-links'})
1500f219747dSAndre Fischer            {
1501f219747dSAndre Fischer                printf "\n";
1502f219747dSAndre Fischer            }
1503f219747dSAndre Fischer        }
1504f219747dSAndre Fischer
1505f219747dSAndre Fischer        print $out "|}\n";
1506f219747dSAndre Fischer    }
1507f219747dSAndre Fischer    close $out;
1508f219747dSAndre Fischer}
1509f219747dSAndre Fischer
1510f219747dSAndre Fischer
1511f219747dSAndre Fischer
1512f219747dSAndre Fischer
1513f219747dSAndre Fischersub GetTableList ($)
1514f219747dSAndre Fischer{
1515f219747dSAndre Fischer    my ($release_descriptor) = @_;
1516f219747dSAndre Fischer
1517f219747dSAndre Fischer    my %seen_table_names = ();
1518f219747dSAndre Fischer    my @table_names = ();
15199dd622cdSAndre Fischer    foreach my $wiki_package_descriptor (@{$release_descriptor->{'wiki-packages'}})
1520f219747dSAndre Fischer    {
15219dd622cdSAndre Fischer        my $table_name = $wiki_package_descriptor->{'table'};
1522f219747dSAndre Fischer        if ( ! $seen_table_names{$table_name})
1523f219747dSAndre Fischer        {
1524f219747dSAndre Fischer            push @table_names, $table_name;
1525f219747dSAndre Fischer            $seen_table_names{$table_name} = 1;
1526f219747dSAndre Fischer        }
1527f219747dSAndre Fischer    }
1528f219747dSAndre Fischer    return @table_names;
1529f219747dSAndre Fischer}
1530f219747dSAndre Fischer
1531f219747dSAndre Fischer
1532f219747dSAndre Fischer
1533f219747dSAndre Fischer
1534f219747dSAndre Fischersub GetPackagesForTable ($$)
1535f219747dSAndre Fischer{
1536f219747dSAndre Fischer    my ($release_descriptor, $table_name) = @_;
1537f219747dSAndre Fischer
1538f219747dSAndre Fischer    my @packages = ();
15399dd622cdSAndre Fischer    foreach my $wiki_package_descriptor (@{$release_descriptor->{'wiki-packages'}})
1540f219747dSAndre Fischer    {
15419dd622cdSAndre Fischer        if ($wiki_package_descriptor->{'table'} eq $table_name)
1542f219747dSAndre Fischer        {
15439dd622cdSAndre Fischer            my $package_descriptor = $release_descriptor->{'packages'}->{
15449dd622cdSAndre Fischer                $wiki_package_descriptor->{'package-id'}};
15459dd622cdSAndre Fischer            $wiki_package_descriptor->{'package'} = $package_descriptor;
15469dd622cdSAndre Fischer            push @packages, $wiki_package_descriptor;
1547f219747dSAndre Fischer        }
1548f219747dSAndre Fischer    }
1549f219747dSAndre Fischer    return @packages;
1550f219747dSAndre Fischer}
1551f219747dSAndre Fischer
1552f219747dSAndre Fischer
1553f219747dSAndre Fischer
1554f219747dSAndre Fischer
1555f219747dSAndre Fischersub GetLanguagesForTable ($@)
1556f219747dSAndre Fischer{
1557f219747dSAndre Fischer    my ($release_descriptor, @packages) = @_;
1558f219747dSAndre Fischer
1559f219747dSAndre Fischer    # Find the languages that are reference by at least one package.
1560f219747dSAndre Fischer    my %matching_languages = ();
1561f219747dSAndre Fischer    foreach my $package_descriptor (@packages)
1562f219747dSAndre Fischer    {
1563f219747dSAndre Fischer        foreach my $language_id (@{$package_descriptor->{'language-list'}})
1564f219747dSAndre Fischer        {
1565f219747dSAndre Fischer            $matching_languages{$language_id} = 1;
1566f219747dSAndre Fischer        }
1567f219747dSAndre Fischer    }
1568f219747dSAndre Fischer
1569f219747dSAndre Fischer    # Retrieve the language descriptors for the language ids.
1570f219747dSAndre Fischer    my @matching_language_descriptors = ();
1571f219747dSAndre Fischer    foreach my $language_id (@{$release_descriptor->{'language-ids'}})
1572f219747dSAndre Fischer    {
1573f219747dSAndre Fischer        if (defined $matching_languages{$language_id})
1574f219747dSAndre Fischer        {
1575f219747dSAndre Fischer            my $language_descriptor = $release_descriptor->{'languages'}->{$language_id};
1576f219747dSAndre Fischer            if (defined $language_descriptor)
1577f219747dSAndre Fischer            {
1578f219747dSAndre Fischer                push @matching_language_descriptors, $language_descriptor;
1579f219747dSAndre Fischer            }
1580f219747dSAndre Fischer        }
1581f219747dSAndre Fischer    }
1582f219747dSAndre Fischer
1583f219747dSAndre Fischer    return @matching_language_descriptors;
1584f219747dSAndre Fischer}
1585f219747dSAndre Fischer
1586f219747dSAndre Fischer
1587f219747dSAndre Fischer
1588f219747dSAndre Fischer
1589f219747dSAndre Fischersub GetPlatformsForTable ($@)
1590f219747dSAndre Fischer{
1591f219747dSAndre Fischer    my ($release_descriptor, @packages) = @_;
1592f219747dSAndre Fischer
1593f219747dSAndre Fischer    # Find the platforms that are reference by at least one package.
1594f219747dSAndre Fischer    my %matching_platform_ids = ();
1595f219747dSAndre Fischer    foreach my $package_descriptor (@packages)
1596f219747dSAndre Fischer    {
1597f219747dSAndre Fischer        foreach my $platform_id (@{$package_descriptor->{'platform-list'}})
1598f219747dSAndre Fischer        {
1599f219747dSAndre Fischer            $matching_platform_ids{$platform_id} = 1;
1600f219747dSAndre Fischer        }
1601f219747dSAndre Fischer    }
1602f219747dSAndre Fischer
1603f219747dSAndre Fischer    # Retrieve the platform descriptors for the plaform ids.
1604f219747dSAndre Fischer    my @matching_platform_descriptors = ();
1605f219747dSAndre Fischer    foreach my $platform_id (@{$release_descriptor->{'platform-ids'}})
1606f219747dSAndre Fischer    {
1607f219747dSAndre Fischer        if ($matching_platform_ids{$platform_id})
1608f219747dSAndre Fischer        {
16099dd622cdSAndre Fischer	    print $platform_id."\n";
1610f219747dSAndre Fischer            push @matching_platform_descriptors, $release_descriptor->{'platforms'}->{$platform_id};
1611f219747dSAndre Fischer        }
1612f219747dSAndre Fischer    }
1613f219747dSAndre Fischer
1614f219747dSAndre Fischer    return @matching_platform_descriptors;
1615f219747dSAndre Fischer}
1616f219747dSAndre Fischer
1617f219747dSAndre Fischer
1618f219747dSAndre Fischer
1619f219747dSAndre Fischer
1620f219747dSAndre Fischermy $bold_text_start = "<b>";
1621f219747dSAndre Fischermy $bold_text_end = "</b>";
1622f219747dSAndre Fischermy $small_text_start = "<span style=\"font-size:80%\">";
1623f219747dSAndre Fischermy $small_text_end = "</span>";
1624f219747dSAndre Fischermy $broken_link_start = "<span style=\"color:#FF0000\">";
1625f219747dSAndre Fischermy $broken_link_end = "</span>";
1626f219747dSAndre Fischer
1627f219747dSAndre Fischer
16289dd622cdSAndre Fischersub WriteDownloadLinks ($$$$$$$)
1629f219747dSAndre Fischer{
1630f219747dSAndre Fischer    my ($out,
16319dd622cdSAndre Fischer        $release_descriptor,
1632f219747dSAndre Fischer        $context,
1633f219747dSAndre Fischer        $language_descriptor,
16349dd622cdSAndre Fischer        $wiki_package_descriptor,
16351108b05eSAndre Fischer        $platform_package_descriptor,
16369dd622cdSAndre Fischer        $package_type) = @_;
16379dd622cdSAndre Fischer
1638f219747dSAndre Fischer    # Check if the current language and platform match the package.
16391108b05eSAndre Fischer    my $platform_id = $platform_package_descriptor->{'platform-id'};
16401108b05eSAndre Fischer    if (defined $wiki_package_descriptor->{'platforms'}->{$platform_id}
16419dd622cdSAndre Fischer        && defined $wiki_package_descriptor->{'languages'}->{$language_descriptor->{'id'}})
1642f219747dSAndre Fischer    {
1643f219747dSAndre Fischer        my $archive_package_name = "";
1644f219747dSAndre Fischer        my $extension = $package_type;
16451108b05eSAndre Fischer        if (defined $platform_package_descriptor->{'extension'})
1646f219747dSAndre Fischer        {
16471108b05eSAndre Fischer            $extension = $platform_package_descriptor->{'extension'};
1648f219747dSAndre Fischer        }
16491108b05eSAndre Fischer        if (defined $platform_package_descriptor->{'download-extension'})
1650f219747dSAndre Fischer        {
16511108b05eSAndre Fischer            $extension = $platform_package_descriptor->{'download-extension'};
1652f219747dSAndre Fischer        }
1653f219747dSAndre Fischer        $archive_package_name = "-".$package_type if ($package_type =~ /deb|rpm/);
16549dd622cdSAndre Fischer
16551108b05eSAndre Fischer        my ($archive_path, $archive_name) = GetInstallationPackageName(
16569dd622cdSAndre Fischer            $release_descriptor,
16571108b05eSAndre Fischer            $platform_package_descriptor,
16589dd622cdSAndre Fischer            $package_type,
16599dd622cdSAndre Fischer            $language_descriptor->{'id'});
16609dd622cdSAndre Fischer
16619dd622cdSAndre Fischer        printf $out "| align=\"center\" | ";
16629dd622cdSAndre Fischer        my $download = FindDownload(
16639dd622cdSAndre Fischer            $context,
16649dd622cdSAndre Fischer            $release_descriptor,
16651108b05eSAndre Fischer            $platform_package_descriptor,
16669dd622cdSAndre Fischer            $package_type,
16679dd622cdSAndre Fischer            $archive_name);
16689dd622cdSAndre Fischer        if (defined $download)
16699dd622cdSAndre Fischer        {
16709dd622cdSAndre Fischer            my $url = $download->{'base-url'} . "/". $archive_name;
16719dd622cdSAndre Fischer            printf $out "%s%s%s<br><br>%s%s %s<br>%s%s",
1672f219747dSAndre Fischer            $bold_text_start,
1673f219747dSAndre Fischer            CreateLink($url, $extension, $context),
1674f219747dSAndre Fischer            $bold_text_end,
1675f219747dSAndre Fischer            $small_text_start,
1676f219747dSAndre Fischer            CreateLink($url.".asc", "ASC", $context),
1677f219747dSAndre Fischer            CreateLink($url.".md5", "MD5", $context),
1678f219747dSAndre Fischer            CreateLink($url.".sha256", "SHA256", $context),
1679f219747dSAndre Fischer            $small_text_end;
16809dd622cdSAndre Fischer        }
16819dd622cdSAndre Fischer        printf $out "\n";
1682f219747dSAndre Fischer    }
1683f219747dSAndre Fischer    else
1684f219747dSAndre Fischer    {
1685f219747dSAndre Fischer        printf $out "|\n";
1686f219747dSAndre Fischer    }
1687f219747dSAndre Fischer}
1688f219747dSAndre Fischer
1689f219747dSAndre Fischer
1690f219747dSAndre Fischer
1691f219747dSAndre Fischer
16929dd622cdSAndre Fischersub FindDownload ($$$$$)
16939dd622cdSAndre Fischer{
16949dd622cdSAndre Fischer    my ($context,
16951108b05eSAndre Fischer        $release_descriptor,
16961108b05eSAndre Fischer        $platform_package_descriptor,
16971108b05eSAndre Fischer        $package_type,
16989dd622cdSAndre Fischer        $archive_name) = @_;
16999dd622cdSAndre Fischer
17009dd622cdSAndre Fischer    foreach my $download (@{$release_descriptor->{'downloads'}})
17019dd622cdSAndre Fischer    {
17021108b05eSAndre Fischer        if ($download->{'platform-id'} eq $platform_package_descriptor->{'platform-id'})
17039dd622cdSAndre Fischer        {
17049dd622cdSAndre Fischer            my $url = $download->{'base-url'} . "/". $archive_name;
17059dd622cdSAndre Fischer            if ($context->{'check-links'})
17069dd622cdSAndre Fischer            {
17079dd622cdSAndre Fischer                if (CheckLink($url))
17089dd622cdSAndre Fischer                {
17099dd622cdSAndre Fischer                    # URL points to an existing file.
17109dd622cdSAndre Fischer                    printf "+";
17119dd622cdSAndre Fischer                    return $download;
17129dd622cdSAndre Fischer                }
17139dd622cdSAndre Fischer                else
17149dd622cdSAndre Fischer                {
17159dd622cdSAndre Fischer                    # URL is broken.
17169dd622cdSAndre Fischer                    # Try the next download area for the platform.
17179dd622cdSAndre Fischer                    next;
17189dd622cdSAndre Fischer                }
17199dd622cdSAndre Fischer            }
17209dd622cdSAndre Fischer            else
17219dd622cdSAndre Fischer            {
17229dd622cdSAndre Fischer                # Use the URL unchecked.  If there is more than one download area for the platform then only
17239dd622cdSAndre Fischer                # the first is ever used.
17249dd622cdSAndre Fischer                printf ".";
17259dd622cdSAndre Fischer                return $download;
17269dd622cdSAndre Fischer            }
17279dd622cdSAndre Fischer        }
17289dd622cdSAndre Fischer    }
17299dd622cdSAndre Fischer
17309dd622cdSAndre Fischer    if ($context->{'check-links'})
17319dd622cdSAndre Fischer    {
17329dd622cdSAndre Fischer        printf "-";
17339dd622cdSAndre Fischer    }
17349dd622cdSAndre Fischer
17359dd622cdSAndre Fischer    return undef;
17369dd622cdSAndre Fischer}
17379dd622cdSAndre Fischer
17389dd622cdSAndre Fischer
17399dd622cdSAndre Fischer
17409dd622cdSAndre Fischer
1741f219747dSAndre Fischersub CreateLink ($$$)
1742f219747dSAndre Fischer{
1743f219747dSAndre Fischer    my ($url, $text, $context) = @_;
1744f219747dSAndre Fischer
1745f219747dSAndre Fischer    my $is_link_broken = 0;
1746f219747dSAndre Fischer    if ($context->{'check-links'})
1747f219747dSAndre Fischer    {
17489dd622cdSAndre Fischer        if (CheckLink($url))
17499dd622cdSAndre Fischer        {
17509dd622cdSAndre Fischer            $is_link_broken = 0;
17519dd622cdSAndre Fischer            printf "+";
17529dd622cdSAndre Fischer        }
17539dd622cdSAndre Fischer        else
17549dd622cdSAndre Fischer        {
17559dd622cdSAndre Fischer            $is_link_broken = 1;
17569dd622cdSAndre Fischer            printf "-";
17579dd622cdSAndre Fischer        }
17589dd622cdSAndre Fischer    }
17599dd622cdSAndre Fischer    else
17609dd622cdSAndre Fischer    {
1761f219747dSAndre Fischer        printf ".";
1762f219747dSAndre Fischer    }
1763f219747dSAndre Fischer
1764f219747dSAndre Fischer    if ( ! $is_link_broken)
1765f219747dSAndre Fischer    {
1766f219747dSAndre Fischer        return sprintf ("[%s %s]", $url, $text);
1767f219747dSAndre Fischer    }
1768f219747dSAndre Fischer    elsif ($context->{'mark-broken-links'})
1769f219747dSAndre Fischer    {
1770f219747dSAndre Fischer        return sprintf ("%sbroken%s[%s %s]", $broken_link_start, $broken_link_end, $url, $text);
1771f219747dSAndre Fischer    }
1772f219747dSAndre Fischer    else
1773f219747dSAndre Fischer    {
1774f219747dSAndre Fischer        return sprintf ("%s", $text);
1775f219747dSAndre Fischer    }
1776f219747dSAndre Fischer}
1777f219747dSAndre Fischer
1778f219747dSAndre Fischer
1779f219747dSAndre Fischer
1780f219747dSAndre Fischer
17819dd622cdSAndre Fischer=head2 CheckLink ($url)
17829dd622cdSAndre Fischer
17839dd622cdSAndre Fischer    Check if the file referenced by $url can be downloaded.
17849dd622cdSAndre Fischer    This is determined by downloading only the header.
17859dd622cdSAndre Fischer
17869dd622cdSAndre Fischer=cut
17871108b05eSAndre Fischermy $LastCheckedURL = "";
17889dd622cdSAndre Fischermy $LastCheckedResult = undef;
17899dd622cdSAndre Fischersub CheckLink ($)
17909dd622cdSAndre Fischer{
17919dd622cdSAndre Fischer    my ($url) = @_;
17929dd622cdSAndre Fischer
17939dd622cdSAndre Fischer    if ($url ne $LastCheckedURL)
17949dd622cdSAndre Fischer    {
17959dd622cdSAndre Fischer        my $head = LWP::Simple::head($url);
17969dd622cdSAndre Fischer        $LastCheckedURL = $url;
17979dd622cdSAndre Fischer        $LastCheckedResult = !!$head;
17989dd622cdSAndre Fischer    }
17999dd622cdSAndre Fischer
18009dd622cdSAndre Fischer    return $LastCheckedResult;
18019dd622cdSAndre Fischer}
18029dd622cdSAndre Fischer
18039dd622cdSAndre Fischer
18049dd622cdSAndre Fischer
18059dd622cdSAndre Fischer
18069dd622cdSAndre Fischersub SignFile ($$)
18079dd622cdSAndre Fischer{
18089dd622cdSAndre Fischer    my ($signature, $filename) = @_;
18099dd622cdSAndre Fischer
18109dd622cdSAndre Fischer    my $command = sprintf(
18119dd622cdSAndre Fischer        "gpg --armor --output %s.asc --detach-sig %s",
18129dd622cdSAndre Fischer        $filename,
18139dd622cdSAndre Fischer        $filename);
18149dd622cdSAndre Fischer}
18159dd622cdSAndre Fischer
18169dd622cdSAndre Fischer
18179dd622cdSAndre Fischer
18189dd622cdSAndre Fischer
1819f219747dSAndre Fischermy $context = ProcessCommandline(@ARGV);
18201108b05eSAndre Fischermy $release_descriptor = ReadReleaseDescription($context->{'filename'}, $context);
1821f219747dSAndre Fischerif ($context->{'command'} eq "build")
1822f219747dSAndre Fischer{
18231108b05eSAndre Fischer    WriteMakefile($release_descriptor, $context);
1824f219747dSAndre Fischer}
1825f219747dSAndre Fischerelsif ($context->{'command'} eq "upload")
1826f219747dSAndre Fischer{
18271108b05eSAndre Fischer    Upload($release_descriptor, $context);
1828f219747dSAndre Fischer}
1829f219747dSAndre Fischerelsif ($context->{'command'} eq "wiki")
1830f219747dSAndre Fischer{
18311108b05eSAndre Fischer    Wiki($release_descriptor, $context);
1832f219747dSAndre Fischer}
1833