1*c6dedb65SAndre Fischer#**************************************************************
2*c6dedb65SAndre Fischer#
3*c6dedb65SAndre Fischer#  Licensed to the Apache Software Foundation (ASF) under one
4*c6dedb65SAndre Fischer#  or more contributor license agreements.  See the NOTICE file
5*c6dedb65SAndre Fischer#  distributed with this work for additional information
6*c6dedb65SAndre Fischer#  regarding copyright ownership.  The ASF licenses this file
7*c6dedb65SAndre Fischer#  to you under the Apache License, Version 2.0 (the
8*c6dedb65SAndre Fischer#  "License"); you may not use this file except in compliance
9*c6dedb65SAndre Fischer#  with the License.  You may obtain a copy of the License at
10*c6dedb65SAndre Fischer#
11*c6dedb65SAndre Fischer#    http://www.apache.org/licenses/LICENSE-2.0
12*c6dedb65SAndre Fischer#
13*c6dedb65SAndre Fischer#  Unless required by applicable law or agreed to in writing,
14*c6dedb65SAndre Fischer#  software distributed under the License is distributed on an
15*c6dedb65SAndre Fischer#  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16*c6dedb65SAndre Fischer#  KIND, either express or implied.  See the License for the
17*c6dedb65SAndre Fischer#  specific language governing permissions and limitations
18*c6dedb65SAndre Fischer#  under the License.
19*c6dedb65SAndre Fischer#
20*c6dedb65SAndre Fischer#**************************************************************
21*c6dedb65SAndre Fischer
22*c6dedb65SAndre Fischerpackage ExtensionsLst;
23*c6dedb65SAndre Fischer
24*c6dedb65SAndre Fischeruse File::Spec;
25*c6dedb65SAndre Fischeruse LWP::UserAgent;
26*c6dedb65SAndre Fischeruse Digest::MD5;
27*c6dedb65SAndre Fischer
28*c6dedb65SAndre Fischeruse base 'Exporter';
29*c6dedb65SAndre Fischerour @EXPORT = qw(DownloadExtensions GetExtensionList);
30*c6dedb65SAndre Fischer
31*c6dedb65SAndre Fischer
32*c6dedb65SAndre Fischer=head1 NAME
33*c6dedb65SAndre Fischer
34*c6dedb65SAndre Fischer    ExtensionLst.pm - Functionality for the interpretation of the main/extensions.lst file.
35*c6dedb65SAndre Fischer
36*c6dedb65SAndre Fischer=head1 SYNOPSIS
37*c6dedb65SAndre Fischer
38*c6dedb65SAndre Fischer    For downloading extensions during build setup:
39*c6dedb65SAndre Fischer
40*c6dedb65SAndre Fischer    use ExtensionsLst;
41*c6dedb65SAndre Fischer    ExtensionsLst::DownloadExtensions();
42*c6dedb65SAndre Fischer
43*c6dedb65SAndre Fischer    For including extensions into the pack set:
44*c6dedb65SAndre Fischer
45*c6dedb65SAndre Fischer    use ExtensionsLst;
46*c6dedb65SAndre Fischer    ExtensionsLst::GetExtensionList(@language_list);
47*c6dedb65SAndre Fischer
48*c6dedb65SAndre Fischer=head1 DESCRIPTION
49*c6dedb65SAndre Fischer
50*c6dedb65SAndre Fischer    The contents of the extensions.lst file are used at two times in
51*c6dedb65SAndre Fischer    the process of building pack sets.
52*c6dedb65SAndre Fischer
53*c6dedb65SAndre Fischer    Once at the beginning right after configure is run the
54*c6dedb65SAndre Fischer    DownloadExtensions() function determines the list of extensions
55*c6dedb65SAndre Fischer    that are not present locally and downloads them.
56*c6dedb65SAndre Fischer
57*c6dedb65SAndre Fischer    The second time is after all modules are built (and the locally
58*c6dedb65SAndre Fischer    built extensions are present) and the pack sets are created.  For
59*c6dedb65SAndre Fischer    every language (or sets of lanugages) a set of extensions is
60*c6dedb65SAndre Fischer    collected and included into the pack set.
61*c6dedb65SAndre Fischer
62*c6dedb65SAndre Fischer    The content of the extensions.lst file is ignored when the --with-extensions option is given to configure.
63*c6dedb65SAndre Fischer
64*c6dedb65SAndre Fischer=cut
65*c6dedb65SAndre Fischer
66*c6dedb65SAndre Fischer
67*c6dedb65SAndre Fischer# Number of the line in extensions.lst that is currently being processed.
68*c6dedb65SAndre Fischermy $LineNo = 0;
69*c6dedb65SAndre Fischer
70*c6dedb65SAndre Fischer
71*c6dedb65SAndre Fischer=head3 Prepare
72*c6dedb65SAndre Fischer    Check that some environment variables are properly set and then return the file name
73*c6dedb65SAndre Fischer    of the 'extensions.lst' file, typically located in main/ beside 'ooo.lst'.
74*c6dedb65SAndre Fischer=cut
75*c6dedb65SAndre Fischersub Prepare ()
76*c6dedb65SAndre Fischer{
77*c6dedb65SAndre Fischer    die "can not access environment varianle SRC_ROOT" if ! defined $ENV{'SRC_ROOT'};
78*c6dedb65SAndre Fischer    die "can not determine the platform: INPATH is not set" if ! defined $ENV{'INPATH'};
79*c6dedb65SAndre Fischer    die "can not determine solver directory: OUTDIR is not set" if ! defined $ENV{'OUTDIR'};
80*c6dedb65SAndre Fischer    die "can not determine download directory: TARFILE_LOCATION is not set" if ! defined $ENV{'TARFILE_LOCATION'};
81*c6dedb65SAndre Fischer
82*c6dedb65SAndre Fischer    my $candidate = File::Spec->catfile($ENV{SRC_ROOT}, "extensions.lst");
83*c6dedb65SAndre Fischer    die "can not read file $candidate" if ! -r $candidate;
84*c6dedb65SAndre Fischer    return $candidate;
85*c6dedb65SAndre Fischer}
86*c6dedb65SAndre Fischer
87*c6dedb65SAndre Fischer
88*c6dedb65SAndre Fischer
89*c6dedb65SAndre Fischer=head 3 EvaluateOperator
90*c6dedb65SAndre Fischer    Evaluate a single test statement like 'language = en.*'.
91*c6dedb65SAndre Fischer    Special handling for operators '=', '==', and 'eq' which are all mapped to '=~'.
92*c6dedb65SAndre Fischer    Therefore the right hand side may be a perl regexp.  It is prefixed with '^'.
93*c6dedb65SAndre Fischer
94*c6dedb65SAndre Fischer    Other operators are at the moment only supported in the way that they are evaluated via eval().
95*c6dedb65SAndre Fischer=cut
96*c6dedb65SAndre Fischersub EvaluateOperator ($$$)
97*c6dedb65SAndre Fischer{
98*c6dedb65SAndre Fischer    my ($left,$operator,$right) = @_;
99*c6dedb65SAndre Fischer
100*c6dedb65SAndre Fischer    my $result;
101*c6dedb65SAndre Fischer
102*c6dedb65SAndre Fischer    if ($operator =~ /^(=|==|eq)$/)
103*c6dedb65SAndre Fischer    {
104*c6dedb65SAndre Fischer        if ($left =~ /^$right$/)
105*c6dedb65SAndre Fischer        {
106*c6dedb65SAndre Fischer            $result = 1;
107*c6dedb65SAndre Fischer        }
108*c6dedb65SAndre Fischer        else
109*c6dedb65SAndre Fischer        {
110*c6dedb65SAndre Fischer            $result = 0;
111*c6dedb65SAndre Fischer        }
112*c6dedb65SAndre Fischer    }
113*c6dedb65SAndre Fischer    elsif (eval($left.$operator.$right))
114*c6dedb65SAndre Fischer    {
115*c6dedb65SAndre Fischer        $result = 1;
116*c6dedb65SAndre Fischer    }
117*c6dedb65SAndre Fischer    else
118*c6dedb65SAndre Fischer    {
119*c6dedb65SAndre Fischer        $result = 0;
120*c6dedb65SAndre Fischer    }
121*c6dedb65SAndre Fischer
122*c6dedb65SAndre Fischer    return $result;
123*c6dedb65SAndre Fischer}
124*c6dedb65SAndre Fischer
125*c6dedb65SAndre Fischer
126*c6dedb65SAndre Fischer
127*c6dedb65SAndre Fischer
128*c6dedb65SAndre Fischer=head EvaluateTerm
129*c6dedb65SAndre Fischer    Evaluate a string that contains a simple test term of the form
130*c6dedb65SAndre Fischer    left operator right
131*c6dedb65SAndre Fischer    with arbitrary spacing allowed around and between the three parts.
132*c6dedb65SAndre Fischer
133*c6dedb65SAndre Fischer    The left hand side is specially handled:
134*c6dedb65SAndre Fischer
135*c6dedb65SAndre Fischer    - When the left hand side is 'language' then it is replaced by
136*c6dedb65SAndre Fischer    any of the given languages in turn.  When the term evaluates to true for any of the languages then
137*c6dedb65SAndre Fischer    true is returned.  False is returned only when none of the given languages matches.
138*c6dedb65SAndre Fischer
139*c6dedb65SAndre Fischer    - When the left hand side consists only of upper case letters, digits, and '_' then it is
140*c6dedb65SAndre Fischer    interpreted as the name of a environment variable.  It is replaced by its value before the term
141*c6dedb65SAndre Fischer    is evaluated.
142*c6dedb65SAndre Fischer
143*c6dedb65SAndre Fischer    - Any other left hand side is an error (at the moment.)
144*c6dedb65SAndre Fischer=cut
145*c6dedb65SAndre Fischersub EvaluateTerm ($$)
146*c6dedb65SAndre Fischer{
147*c6dedb65SAndre Fischer    my $term = shift;
148*c6dedb65SAndre Fischer    my $languages = shift;
149*c6dedb65SAndre Fischer
150*c6dedb65SAndre Fischer    my $result;
151*c6dedb65SAndre Fischer
152*c6dedb65SAndre Fischer    if ($term =~ /^\s*(\w+)\s*(\W+)\s*(.*?)\s*$/)
153*c6dedb65SAndre Fischer    {
154*c6dedb65SAndre Fischer        my ($left,$operator,$right) = ($1,$2,$3);
155*c6dedb65SAndre Fischer
156*c6dedb65SAndre Fischer        if ($operator !~ /^=|==|eq$/)
157*c6dedb65SAndre Fischer        {
158*c6dedb65SAndre Fischer            die "unsupported operator $operator on line $LineNo";
159*c6dedb65SAndre Fischer        }
160*c6dedb65SAndre Fischer
161*c6dedb65SAndre Fischer        die "no right side in condition on line $LineNo ($term)" if ! defined $right;
162*c6dedb65SAndre Fischer
163*c6dedb65SAndre Fischer        if ($left =~ /^[A-Z_0-9]+$/)
164*c6dedb65SAndre Fischer        {
165*c6dedb65SAndre Fischer            # Uppercase words are interpreted as environment variables.
166*c6dedb65SAndre Fischer            my $left_value = $ENV{$left};
167*c6dedb65SAndre Fischer            $left_value = "" if ! defined $left_value;
168*c6dedb65SAndre Fischer
169*c6dedb65SAndre Fischer            # We can check whether the condition is fullfilled right now.
170*c6dedb65SAndre Fischer            $result = EvaluateOperator($left_value, $operator, $right);
171*c6dedb65SAndre Fischer        }
172*c6dedb65SAndre Fischer        elsif ($left eq "language")
173*c6dedb65SAndre Fischer        {
174*c6dedb65SAndre Fischer            if ($right eq "all")
175*c6dedb65SAndre Fischer            {
176*c6dedb65SAndre Fischer                $result = 1;
177*c6dedb65SAndre Fischer            }
178*c6dedb65SAndre Fischer            elsif ($#$languages>=0)
179*c6dedb65SAndre Fischer            {
180*c6dedb65SAndre Fischer                $result = 0;
181*c6dedb65SAndre Fischer                for my $language (@$languages)
182*c6dedb65SAndre Fischer                {
183*c6dedb65SAndre Fischer                    # Unify naming schemes.
184*c6dedb65SAndre Fischer                    $language =~ s/_/-/g;
185*c6dedb65SAndre Fischer                    $right =~ s/_/-/g;
186*c6dedb65SAndre Fischer
187*c6dedb65SAndre Fischer                    # Evaluate language regexp.
188*c6dedb65SAndre Fischer                    $result = EvaluateOperator($language, $operator, $right) ? 1 : 0;
189*c6dedb65SAndre Fischer                    last if $result;
190*c6dedb65SAndre Fischer                }
191*c6dedb65SAndre Fischer            }
192*c6dedb65SAndre Fischer            else
193*c6dedb65SAndre Fischer            {
194*c6dedb65SAndre Fischer                # The set of languages is not yet known.  Return true
195*c6dedb65SAndre Fischer                # to include the following entries.
196*c6dedb65SAndre Fischer                $result = 1;
197*c6dedb65SAndre Fischer            }
198*c6dedb65SAndre Fischer        }
199*c6dedb65SAndre Fischer        elsif ($left eq "platform")
200*c6dedb65SAndre Fischer        {
201*c6dedb65SAndre Fischer            if ($right eq "all")
202*c6dedb65SAndre Fischer            {
203*c6dedb65SAndre Fischer                $result = 1;
204*c6dedb65SAndre Fischer            }
205*c6dedb65SAndre Fischer            else
206*c6dedb65SAndre Fischer            {
207*c6dedb65SAndre Fischer                # Evaluate platform regexp.
208*c6dedb65SAndre Fischer                $result = EvaluateOperator($ENV{'INPATH'}, $operator, $right) ? 1 : 0;
209*c6dedb65SAndre Fischer            }
210*c6dedb65SAndre Fischer        }
211*c6dedb65SAndre Fischer        else
212*c6dedb65SAndre Fischer        {
213*c6dedb65SAndre Fischer            die "can not handle left hand side $left on line $LineNo";
214*c6dedb65SAndre Fischer        }
215*c6dedb65SAndre Fischer    }
216*c6dedb65SAndre Fischer    else
217*c6dedb65SAndre Fischer    {
218*c6dedb65SAndre Fischer        die "syntax error in expression on line $LineNo";
219*c6dedb65SAndre Fischer    }
220*c6dedb65SAndre Fischer
221*c6dedb65SAndre Fischer    return $result;
222*c6dedb65SAndre Fischer}
223*c6dedb65SAndre Fischer
224*c6dedb65SAndre Fischer
225*c6dedb65SAndre Fischer
226*c6dedb65SAndre Fischer
227*c6dedb65SAndre Fischer=head3 EvaluateSelector
228*c6dedb65SAndre Fischer    Evaluate the given expression that is expected to be list of terms of the form
229*c6dedb65SAndre Fischer        left-hand-side operator right-hand-side
230*c6dedb65SAndre Fischer    that are separated by logical operators
231*c6dedb65SAndre Fischer        && ||
232*c6dedb65SAndre Fischer    The expression is lazy evaluated left to right.
233*c6dedb65SAndre Fischer=cut
234*c6dedb65SAndre Fischersub EvaluateSelector($$);
235*c6dedb65SAndre Fischersub EvaluateSelector($$)
236*c6dedb65SAndre Fischer{
237*c6dedb65SAndre Fischer    my $expression = shift;
238*c6dedb65SAndre Fischer    my $languages = shift;
239*c6dedb65SAndre Fischer
240*c6dedb65SAndre Fischer    my $result = "";
241*c6dedb65SAndre Fischer
242*c6dedb65SAndre Fischer    if ($expression =~ /^\s*$/)
243*c6dedb65SAndre Fischer    {
244*c6dedb65SAndre Fischer        # Empty selector is always true.
245*c6dedb65SAndre Fischer        return 1;
246*c6dedb65SAndre Fischer    }
247*c6dedb65SAndre Fischer    elsif ($expression =~ /^\s*(.*?)(&&|\|\|)\s*(.*)$/)
248*c6dedb65SAndre Fischer    {
249*c6dedb65SAndre Fischer        my ($term, $operator) = ($1,$2);
250*c6dedb65SAndre Fischer        $expression = $3;
251*c6dedb65SAndre Fischer
252*c6dedb65SAndre Fischer        my $left_result = EvaluateTerm($term, $languages);
253*c6dedb65SAndre Fischer        # Lazy evaluation of &&
254*c6dedb65SAndre Fischer        return 0 if ($operator eq "&&" && !$left_result);
255*c6dedb65SAndre Fischer        # Lazy evaluation of ||
256*c6dedb65SAndre Fischer        return 1 if ($operator eq "||" && $left_result);
257*c6dedb65SAndre Fischer        my $right_result = EvaluateSelector($expression, $languages);
258*c6dedb65SAndre Fischer
259*c6dedb65SAndre Fischer        if ($operator eq "&&")
260*c6dedb65SAndre Fischer        {
261*c6dedb65SAndre Fischer            return $left_result && $right_result;
262*c6dedb65SAndre Fischer        }
263*c6dedb65SAndre Fischer        else
264*c6dedb65SAndre Fischer        {
265*c6dedb65SAndre Fischer            return $left_result || $right_result;
266*c6dedb65SAndre Fischer        }
267*c6dedb65SAndre Fischer    }
268*c6dedb65SAndre Fischer    elsif ($expression =~ /^\s*(.+?)\s$/)
269*c6dedb65SAndre Fischer    {
270*c6dedb65SAndre Fischer        return EvaluateTerm($1, $languages);
271*c6dedb65SAndre Fischer    }
272*c6dedb65SAndre Fischer    else
273*c6dedb65SAndre Fischer    {
274*c6dedb65SAndre Fischer        die "invalid expression syntax on line $LineNo ($expression)";
275*c6dedb65SAndre Fischer    }
276*c6dedb65SAndre Fischer}
277*c6dedb65SAndre Fischer
278*c6dedb65SAndre Fischer
279*c6dedb65SAndre Fischer
280*c6dedb65SAndre Fischer
281*c6dedb65SAndre Fischer=head3 ProcessURL
282*c6dedb65SAndre Fischer    Check that the given line contains an optional MD5 sum followed by
283*c6dedb65SAndre Fischer    a URL for one of the protocols file, http, https
284*c6dedb65SAndre Fischer    Return an array that contains the protocol, the name, the original
285*c6dedb65SAndre Fischer    URL, and the MD5 sum from the beginning of the line.
286*c6dedb65SAndre Fischer    The name of the URL depends on its protocol:
287*c6dedb65SAndre Fischer    - for http(s) the part of the URL after the last '/'.
288*c6dedb65SAndre Fischer    - for file URLS it is everything after the protocol://
289*c6dedb65SAndre Fischer=cut
290*c6dedb65SAndre Fischersub ProcessURL ($)
291*c6dedb65SAndre Fischer{
292*c6dedb65SAndre Fischer    my $line = shift;
293*c6dedb65SAndre Fischer
294*c6dedb65SAndre Fischer    # Check that we are looking at a valid URL.
295*c6dedb65SAndre Fischer    if ($line =~ /^\s*(\w{32}\s+)?([a-zA-Z]+)(:\/\/.*?\/)([^\/ \t]+)\s*$/)
296*c6dedb65SAndre Fischer    {
297*c6dedb65SAndre Fischer        my ($md5, $protocol, $name) = ($1,$2,$4);
298*c6dedb65SAndre Fischer        my $URL = $2.$3.$4;
299*c6dedb65SAndre Fischer
300*c6dedb65SAndre Fischer        die "invalid URL protocol on line $LineNo:\n$line\n" if $protocol !~ /(file|http|https)/;
301*c6dedb65SAndre Fischer
302*c6dedb65SAndre Fischer        # For file URLs we use everything after :// as name.
303*c6dedb65SAndre Fischer        if ($protocol eq "file")
304*c6dedb65SAndre Fischer        {
305*c6dedb65SAndre Fischer            $URL =~ /:\/\/(.*)$/;
306*c6dedb65SAndre Fischer            $name = $1;
307*c6dedb65SAndre Fischer        }
308*c6dedb65SAndre Fischer
309*c6dedb65SAndre Fischer        return [$protocol, $name, $URL, $md5];
310*c6dedb65SAndre Fischer    }
311*c6dedb65SAndre Fischer    else
312*c6dedb65SAndre Fischer    {
313*c6dedb65SAndre Fischer        die "invalid URL at line $LineNo:\n$line\n";
314*c6dedb65SAndre Fischer    }
315*c6dedb65SAndre Fischer}
316*c6dedb65SAndre Fischer
317*c6dedb65SAndre Fischer
318*c6dedb65SAndre Fischer
319*c6dedb65SAndre Fischer
320*c6dedb65SAndre Fischer=head3 ParseExtensionsLst
321*c6dedb65SAndre Fischer    Parse the extensions.lst file.
322*c6dedb65SAndre Fischer
323*c6dedb65SAndre Fischer    Lines that contain only spaces or comments or are empty are
324*c6dedb65SAndre Fischer    ignored.
325*c6dedb65SAndre Fischer
326*c6dedb65SAndre Fischer    Lines that contain a selector, ie a test enclosed in brackets, are
327*c6dedb65SAndre Fischer    evaluated.  The following lines, until the next selector, are
328*c6dedb65SAndre Fischer    ignored when the selector evaluates to false.  When an empty list
329*c6dedb65SAndre Fischer    of languages is given then any 'language=...' test is evaluated as
330*c6dedb65SAndre Fischer    true.
331*c6dedb65SAndre Fischer
332*c6dedb65SAndre Fischer    All other lines are expected to contain a URL optionally preceded
333*c6dedb65SAndre Fischer    by an MD5 sum.
334*c6dedb65SAndre Fischer=cut
335*c6dedb65SAndre Fischersub ParseExtensionsLst ($$)
336*c6dedb65SAndre Fischer{
337*c6dedb65SAndre Fischer    my $file_name = shift;
338*c6dedb65SAndre Fischer    my $languages = shift;
339*c6dedb65SAndre Fischer
340*c6dedb65SAndre Fischer    open my $in, "$file_name";
341*c6dedb65SAndre Fischer
342*c6dedb65SAndre Fischer    my $current_selector_value = 1;
343*c6dedb65SAndre Fischer    my @URLs = ();
344*c6dedb65SAndre Fischer
345*c6dedb65SAndre Fischer    while (<$in>)
346*c6dedb65SAndre Fischer    {
347*c6dedb65SAndre Fischer        my $line = $_;
348*c6dedb65SAndre Fischer        $line =~ s/[\r\n]+//g;
349*c6dedb65SAndre Fischer        ++$LineNo;
350*c6dedb65SAndre Fischer
351*c6dedb65SAndre Fischer        # Strip away comments.
352*c6dedb65SAndre Fischer        next if $line =~ /^\s*#/;
353*c6dedb65SAndre Fischer
354*c6dedb65SAndre Fischer        # Ignore empty lines.
355*c6dedb65SAndre Fischer        next if $line =~ /^\s*$/;
356*c6dedb65SAndre Fischer
357*c6dedb65SAndre Fischer        # Process selectors
358*c6dedb65SAndre Fischer        if ($line =~ /^\s*\[\s*(.*)\s*\]\s*$/)
359*c6dedb65SAndre Fischer        {
360*c6dedb65SAndre Fischer            $current_selector_value = EvaluateSelector($1, $languages);
361*c6dedb65SAndre Fischer        }
362*c6dedb65SAndre Fischer        else
363*c6dedb65SAndre Fischer        {
364*c6dedb65SAndre Fischer            if ($current_selector_value)
365*c6dedb65SAndre Fischer            {
366*c6dedb65SAndre Fischer                push @URLs, ProcessURL($line);
367*c6dedb65SAndre Fischer            }
368*c6dedb65SAndre Fischer        }
369*c6dedb65SAndre Fischer    }
370*c6dedb65SAndre Fischer
371*c6dedb65SAndre Fischer    close $in;
372*c6dedb65SAndre Fischer
373*c6dedb65SAndre Fischer    return @URLs;
374*c6dedb65SAndre Fischer}
375*c6dedb65SAndre Fischer
376*c6dedb65SAndre Fischer
377*c6dedb65SAndre Fischer
378*c6dedb65SAndre Fischer
379*c6dedb65SAndre Fischer=head3 Download
380*c6dedb65SAndre Fischer    Download a set of files that are specified via URLs.
381*c6dedb65SAndre Fischer
382*c6dedb65SAndre Fischer    File URLs are ignored here because they point to extensions that have not yet been built.
383*c6dedb65SAndre Fischer
384*c6dedb65SAndre Fischer    For http URLs there may be an optional MD5 checksum.  If it is present then downloaded
385*c6dedb65SAndre Fischer    files that do not match that checksum are an error and lead to abortion of the current process.
386*c6dedb65SAndre Fischer    Files that have already been downloaded are not downloaded again.
387*c6dedb65SAndre Fischer=cut
388*c6dedb65SAndre Fischersub Download (@)
389*c6dedb65SAndre Fischer{
390*c6dedb65SAndre Fischer    my @urls = @_;
391*c6dedb65SAndre Fischer
392*c6dedb65SAndre Fischer    my @missing = ();
393*c6dedb65SAndre Fischer    my $download_path = $ENV{'TARFILE_LOCATION'};
394*c6dedb65SAndre Fischer
395*c6dedb65SAndre Fischer    # First check which (if any) extensions have already been downloaded.
396*c6dedb65SAndre Fischer    for my $entry (@urls)
397*c6dedb65SAndre Fischer    {
398*c6dedb65SAndre Fischer        my ($protocol, $name, $URL, $md5sum) = @{$entry};
399*c6dedb65SAndre Fischer
400*c6dedb65SAndre Fischer        # We can not check the existence of file URLs because they point to extensions that
401*c6dedb65SAndre Fischer        # have yet to be built.
402*c6dedb65SAndre Fischer
403*c6dedb65SAndre Fischer        next if $protocol ne "http";
404*c6dedb65SAndre Fischer        my $candidate = File::Spec->catfile($download_path, $name);
405*c6dedb65SAndre Fischer        if ( ! -f $candidate)
406*c6dedb65SAndre Fischer        {
407*c6dedb65SAndre Fischer            push @missing, $entry;
408*c6dedb65SAndre Fischer        }
409*c6dedb65SAndre Fischer    }
410*c6dedb65SAndre Fischer    if ($#missing >= 0)
411*c6dedb65SAndre Fischer    {
412*c6dedb65SAndre Fischer        printf "downloading %d missing extension%s\n", $#missing+1, $#missing>0 ? "s" : "";
413*c6dedb65SAndre Fischer        if ( ! -d $download_path)
414*c6dedb65SAndre Fischer        {
415*c6dedb65SAndre Fischer            mkdir File::Spec->catpath($download_path, "tmp")
416*c6dedb65SAndre Fischer                || die "can not create tmp subdirectory of $download_path";
417*c6dedb65SAndre Fischer        }
418*c6dedb65SAndre Fischer    }
419*c6dedb65SAndre Fischer    else
420*c6dedb65SAndre Fischer    {
421*c6dedb65SAndre Fischer        print "all downloadable extensions present\n";
422*c6dedb65SAndre Fischer        return;
423*c6dedb65SAndre Fischer    }
424*c6dedb65SAndre Fischer
425*c6dedb65SAndre Fischer    # Download the missing files.
426*c6dedb65SAndre Fischer    for my $entry (@missing)
427*c6dedb65SAndre Fischer    {
428*c6dedb65SAndre Fischer        my ($protocol, $name, $URL, $md5sum) = @{$entry};
429*c6dedb65SAndre Fischer
430*c6dedb65SAndre Fischer        # Open a .part file for writing.
431*c6dedb65SAndre Fischer        my $filename = File::Spec->catfile($download_path, $name);
432*c6dedb65SAndre Fischer        my $temporary_filename = $filename . ".part";
433*c6dedb65SAndre Fischer        open my $out, ">$temporary_filename";
434*c6dedb65SAndre Fischer        binmode($out);
435*c6dedb65SAndre Fischer
436*c6dedb65SAndre Fischer        # Prepare md5
437*c6dedb65SAndre Fischer        my $md5 = Digest::MD5->new();
438*c6dedb65SAndre Fischer
439*c6dedb65SAndre Fischer        # Download the extension.
440*c6dedb65SAndre Fischer        my $agent = LWP::UserAgent->new();
441*c6dedb65SAndre Fischer        $agent->timeout(10);
442*c6dedb65SAndre Fischer        $agent->show_progress(1);
443*c6dedb65SAndre Fischer        $agent->add_handler('response_data'
444*c6dedb65SAndre Fischer                            => sub{
445*c6dedb65SAndre Fischer                                my($response,$agent,$h,$data)=@_;
446*c6dedb65SAndre Fischer                                print $out $data;
447*c6dedb65SAndre Fischer                                $md5->add($data);
448*c6dedb65SAndre Fischer                            });
449*c6dedb65SAndre Fischer        my $response = $agent->get($URL);
450*c6dedb65SAndre Fischer        close $out;
451*c6dedb65SAndre Fischer
452*c6dedb65SAndre Fischer        # When download was successfull then check the md5 checksum and rename the .part file
453*c6dedb65SAndre Fischer        # into the actual extension name.
454*c6dedb65SAndre Fischer        if ($response->is_success())
455*c6dedb65SAndre Fischer        {
456*c6dedb65SAndre Fischer            if (defined $md5sum && length($md5sum)==32)
457*c6dedb65SAndre Fischer            {
458*c6dedb65SAndre Fischer                if ($md5sum eq $md5->digest())
459*c6dedb65SAndre Fischer                {
460*c6dedb65SAndre Fischer                    print "md5 is OK\n";
461*c6dedb65SAndre Fischer                }
462*c6dedb65SAndre Fischer                else
463*c6dedb65SAndre Fischer                {
464*c6dedb65SAndre Fischer                    unlink($temporary_filename);
465*c6dedb65SAndre Fischer                    die "downloaded file has the wrong md5 checksum";
466*c6dedb65SAndre Fischer                }
467*c6dedb65SAndre Fischer            }
468*c6dedb65SAndre Fischer
469*c6dedb65SAndre Fischer            rename($temporary_filename, $filename) || die "can not rename $temporary_filename to $filename";
470*c6dedb65SAndre Fischer        }
471*c6dedb65SAndre Fischer        else
472*c6dedb65SAndre Fischer        {
473*c6dedb65SAndre Fischer            die "failed to download $URL";
474*c6dedb65SAndre Fischer        }
475*c6dedb65SAndre Fischer    }
476*c6dedb65SAndre Fischer}
477*c6dedb65SAndre Fischer
478*c6dedb65SAndre Fischer
479*c6dedb65SAndre Fischer
480*c6dedb65SAndre Fischer
481*c6dedb65SAndre Fischer=head3 DownloadExtensions
482*c6dedb65SAndre Fischer    This function is intended to be called during bootstrapping.  It extracts the set of extensions
483*c6dedb65SAndre Fischer    that will be used later, when the installation sets are built.
484*c6dedb65SAndre Fischer=cut
485*c6dedb65SAndre Fischersub DownloadExtensions ()
486*c6dedb65SAndre Fischer{
487*c6dedb65SAndre Fischer    my $full_file_name = Prepare();
488*c6dedb65SAndre Fischer    my @urls = ParseExtensionsLst($full_file_name, []);
489*c6dedb65SAndre Fischer    Download(@urls);
490*c6dedb65SAndre Fischer}
491*c6dedb65SAndre Fischer
492*c6dedb65SAndre Fischer
493*c6dedb65SAndre Fischer
494*c6dedb65SAndre Fischer
495*c6dedb65SAndre Fischer=head3 GetExtensionList
496*c6dedb65SAndre Fischer    This function is intended to be called when installation sets are built.
497*c6dedb65SAndre Fischer    It expects two arguments:
498*c6dedb65SAndre Fischer        - A protocol selector.  Http URLs reference remotely located
499*c6dedb65SAndre Fischer          extensions that will be bundled as-is into the installation
500*c6dedb65SAndre Fischer          sets due to legal reasons. They are installed on first start
501*c6dedb65SAndre Fischer          of the office.
502*c6dedb65SAndre Fischer          File URLs reference extensions whose source code is part of
503*c6dedb65SAndre Fischer          the repository.  They are pre-registered when installation
504*c6dedb65SAndre Fischer          sets are created.  Their installation is finished when the
505*c6dedb65SAndre Fischer          office is first started.
506*c6dedb65SAndre Fischer        - A set of languages.  This set determines which extensions
507*c6dedb65SAndre Fischer          are returned and then included in an installation set.
508*c6dedb65SAndre Fischer=cut
509*c6dedb65SAndre Fischersub GetExtensionList ($@)
510*c6dedb65SAndre Fischer{
511*c6dedb65SAndre Fischer    my $protocol_selector = shift;
512*c6dedb65SAndre Fischer    my @language_list = @_;
513*c6dedb65SAndre Fischer
514*c6dedb65SAndre Fischer    my $full_file_name = Prepare();
515*c6dedb65SAndre Fischer    my @urls = ParseExtensionsLst($full_file_name, \@language_list);
516*c6dedb65SAndre Fischer
517*c6dedb65SAndre Fischer    my @result = ();
518*c6dedb65SAndre Fischer    for my $entry (@urls)
519*c6dedb65SAndre Fischer    {
520*c6dedb65SAndre Fischer        my ($protocol, $name, $URL, $md5sum) = @{$entry};
521*c6dedb65SAndre Fischer        if ($protocol =~ /^$protocol_selector$/)
522*c6dedb65SAndre Fischer        {
523*c6dedb65SAndre Fischer            push @result, $name;
524*c6dedb65SAndre Fischer        }
525*c6dedb65SAndre Fischer    }
526*c6dedb65SAndre Fischer
527*c6dedb65SAndre Fischer    return @result;
528*c6dedb65SAndre Fischer}
529*c6dedb65SAndre Fischer
530*c6dedb65SAndre Fischer
531*c6dedb65SAndre Fischer1;
532