1*489cdf4fSarielch#!/usr/bin/env perl 26a22bca6SAndre Fischer 396dbeebcSAndre Fischer#************************************************************** 496dbeebcSAndre Fischer# 596dbeebcSAndre Fischer# Licensed to the Apache Software Foundation (ASF) under one 696dbeebcSAndre Fischer# or more contributor license agreements. See the NOTICE file 796dbeebcSAndre Fischer# distributed with this work for additional information 896dbeebcSAndre Fischer# regarding copyright ownership. The ASF licenses this file 996dbeebcSAndre Fischer# to you under the Apache License, Version 2.0 (the 1096dbeebcSAndre Fischer# "License"); you may not use this file except in compliance 1196dbeebcSAndre Fischer# with the License. You may obtain a copy of the License at 1296dbeebcSAndre Fischer# 1396dbeebcSAndre Fischer# http://www.apache.org/licenses/LICENSE-2.0 1496dbeebcSAndre Fischer# 1596dbeebcSAndre Fischer# Unless required by applicable law or agreed to in writing, 1696dbeebcSAndre Fischer# software distributed under the License is distributed on an 1796dbeebcSAndre Fischer# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 1896dbeebcSAndre Fischer# KIND, either express or implied. See the License for the 1996dbeebcSAndre Fischer# specific language governing permissions and limitations 2096dbeebcSAndre Fischer# under the License. 2196dbeebcSAndre Fischer# 2296dbeebcSAndre Fischer#************************************************************** 2396dbeebcSAndre Fischer 246a22bca6SAndre Fischer=head1 NAME 256a22bca6SAndre Fischer 266a22bca6SAndre Fischer download_external_libraries.pl - Load missing tarballs specified in main/external_libs.lst. 276a22bca6SAndre Fischer 286a22bca6SAndre Fischer=head1 SYNOPSIS 296a22bca6SAndre Fischer 306a22bca6SAndre Fischer For downloading external libraries (typically from the main/bootstrap script): 316a22bca6SAndre Fischer 326a22bca6SAndre Fischer download_external_libraries(<data-file-name>); 336a22bca6SAndre Fischer 346a22bca6SAndre Fischer=head1 DESCRIPTION 356a22bca6SAndre Fischer 366a22bca6SAndre Fischer The contents of the main/external_libs.lst file are used to determine the 376a22bca6SAndre Fischer external library tarballs that are missing from ext_sources/. 386a22bca6SAndre Fischer 396a22bca6SAndre Fischer Individual libraries can be ignored depending on the values of environment variables. 406a22bca6SAndre Fischer 416a22bca6SAndre Fischer Format of the main/external_libs.lst file: 426a22bca6SAndre Fischer 436a22bca6SAndre Fischer The file is line based. 446a22bca6SAndre Fischer Comments start with a # and go to the end of the line and are ignored. 456a22bca6SAndre Fischer Lines that are empty or contain only spaces and/or comments are ignored. 466a22bca6SAndre Fischer 476a22bca6SAndre Fischer All other lines can have one of two forms: 486a22bca6SAndre Fischer - A variable definition of the form <name>=<value>. 496a22bca6SAndre Fischer - A conditional block start in the form "if (<expression>)" 506a22bca6SAndre Fischer 516a22bca6SAndre Fischer Variables defined in a conditional block are only visible in this block and 526a22bca6SAndre Fischer replace the definition of global variables and variables earlier in the same 536a22bca6SAndre Fischer block. 546a22bca6SAndre Fischer Some variables have special names: 5510e20387SAndre Fischer - MD5 is the expected MD5 checksum of the library tarball. 5610e20387SAndre Fischer - SHA1 is the expected SHA1 checksum of the library tarball. 576a22bca6SAndre Fischer - URL1 to URL9 specify from where to download the tarball. The urls are tried in order. 5810e20387SAndre Fischer The first successful download (download completed and checksum match) stops the iteration. 596a22bca6SAndre Fischer 606a22bca6SAndre Fischer Expressions are explained below in the comment of EvaluateExpression(). 616a22bca6SAndre Fischer 626a22bca6SAndre Fischer A library is only regarded if its conditional expression evaluates to 1. 636a22bca6SAndre Fischer 646a22bca6SAndre Fischer Example: 656a22bca6SAndre Fischer 666a22bca6SAndre Fischer DefaultSite=http://some-internet-site.org 676a22bca6SAndre Fischer if ( true ) 686a22bca6SAndre Fischer MD5 = 0123456789abcdef0123456789abcdef 696a22bca6SAndre Fischer name = library-1.0.tar.gz 706a22bca6SAndre Fischer URL1 = http://some-other-internet-site.org/another-name.tgz 716a22bca6SAndre Fischer URL2 = $(DefaultSite)$(MD5)-$(name) 726a22bca6SAndre Fischer 736a22bca6SAndre Fischer This tries to load a library first from some-other-internet-site.org and if 746a22bca6SAndre Fischer that fails from some-internet-site.org. The library is stored as $(MD5)-$(name) 756a22bca6SAndre Fischer even when it is loaded as another-name.tgz. 766a22bca6SAndre Fischer 776a22bca6SAndre Fischer=cut 786a22bca6SAndre Fischer 796a22bca6SAndre Fischer 806a22bca6SAndre Fischeruse strict; 816a22bca6SAndre Fischer 826a22bca6SAndre Fischeruse File::Spec; 836a22bca6SAndre Fischeruse File::Path; 846a22bca6SAndre Fischeruse File::Basename; 856a22bca6SAndre Fischeruse Digest::MD5; 8610e20387SAndre Fischeruse Digest::SHA; 876a22bca6SAndre Fischeruse URI; 88f253223cSAndre Fischeruse LWP::UserAgent; 896a22bca6SAndre Fischer 906a22bca6SAndre Fischermy $Debug = 1; 916a22bca6SAndre Fischer 926a22bca6SAndre Fischermy $LocalEnvironment = undef; 936a22bca6SAndre Fischermy $GlobalEnvironment = {}; 946a22bca6SAndre Fischermy @Missing = (); 956a22bca6SAndre Fischer 966a22bca6SAndre Fischer 976a22bca6SAndre Fischer 986a22bca6SAndre Fischer 996a22bca6SAndre Fischer=head3 ProcessDataFile 1006a22bca6SAndre Fischer 1016a22bca6SAndre Fischer Read the data file, typically named main/external_libs.lst, find the external 1026a22bca6SAndre Fischer library tarballs that are not yet present in ext_sources/ and download them. 1036a22bca6SAndre Fischer 1046a22bca6SAndre Fischer=cut 1056a22bca6SAndre Fischersub ProcessDataFile ($) 1066a22bca6SAndre Fischer{ 1076a22bca6SAndre Fischer my $filename = shift; 1086a22bca6SAndre Fischer 1096a22bca6SAndre Fischer my $destination = $ENV{'TARFILE_LOCATION'}; 1106a22bca6SAndre Fischer 1116a22bca6SAndre Fischer die "can not open data file $filename" if ! -e $filename; 1126a22bca6SAndre Fischer 1136a22bca6SAndre Fischer my $current_selector_value = 1; 1146a22bca6SAndre Fischer my @URLHeads = (); 1156a22bca6SAndre Fischer my @download_requests = (); 1166a22bca6SAndre Fischer 1176a22bca6SAndre Fischer open my $in, $filename; 1186a22bca6SAndre Fischer while (my $line = <$in>) 1196a22bca6SAndre Fischer { 1206a22bca6SAndre Fischer # Remove leading and trailing space and comments 1216a22bca6SAndre Fischer $line =~ s/^\s+//; 1226a22bca6SAndre Fischer $line =~ s/\s+$//; 1236a22bca6SAndre Fischer $line =~ s/\s*#.*$//; 1246a22bca6SAndre Fischer 1256a22bca6SAndre Fischer # Ignore empty lines. 1266a22bca6SAndre Fischer next if $line eq ""; 1276a22bca6SAndre Fischer 1286a22bca6SAndre Fischer # An "if" statement starts a new block. 1296a22bca6SAndre Fischer if ($line =~ /^\s*if\s*\(\s*(.*?)\s*\)\s*$/) 1306a22bca6SAndre Fischer { 1316a22bca6SAndre Fischer ProcessLastBlock(); 1326a22bca6SAndre Fischer 1336a22bca6SAndre Fischer $LocalEnvironment = { 'selector' => $1 }; 1346a22bca6SAndre Fischer } 1356a22bca6SAndre Fischer 1366a22bca6SAndre Fischer # Lines of the form name = value define a local variable. 1376a22bca6SAndre Fischer elsif ($line =~ /^\s*(\S+)\s*=\s*(.*?)\s*$/) 1386a22bca6SAndre Fischer { 1396a22bca6SAndre Fischer if (defined $LocalEnvironment) 1406a22bca6SAndre Fischer { 1416a22bca6SAndre Fischer $LocalEnvironment->{$1} = $2; 1426a22bca6SAndre Fischer } 1436a22bca6SAndre Fischer else 1446a22bca6SAndre Fischer { 1456a22bca6SAndre Fischer $GlobalEnvironment->{$1} = $2; 1466a22bca6SAndre Fischer } 1476a22bca6SAndre Fischer } 1486a22bca6SAndre Fischer else 1496a22bca6SAndre Fischer { 1506a22bca6SAndre Fischer die "can not parse line $line\n"; 1516a22bca6SAndre Fischer } 1526a22bca6SAndre Fischer } 1536a22bca6SAndre Fischer 1546a22bca6SAndre Fischer ProcessLastBlock(); 1556a22bca6SAndre Fischer 1566a22bca6SAndre Fischer Download(\@download_requests, \@URLHeads); 1576a22bca6SAndre Fischer} 1586a22bca6SAndre Fischer 1596a22bca6SAndre Fischer 1606a22bca6SAndre Fischer 1616a22bca6SAndre Fischer 1626a22bca6SAndre Fischer=head3 ProcessLastBlock 1636a22bca6SAndre Fischer 1646a22bca6SAndre Fischer Process the last definition of an external library. 1656a22bca6SAndre Fischer If there is not last block, true for the first "if" statement, then the call is ignored. 1666a22bca6SAndre Fischer 1676a22bca6SAndre Fischer=cut 1686a22bca6SAndre Fischersub ProcessLastBlock () 1696a22bca6SAndre Fischer{ 1706a22bca6SAndre Fischer # Return if no block is defined. 1716a22bca6SAndre Fischer return if ! defined $LocalEnvironment; 1726a22bca6SAndre Fischer 1736a22bca6SAndre Fischer # Ignore the block if the selector does not match. 1746a22bca6SAndre Fischer if ( ! EvaluateExpression(SubstituteVariables($LocalEnvironment->{'selector'}))) 1756a22bca6SAndre Fischer { 1766a22bca6SAndre Fischer printf("ignoring %s because its prerequisites are not fulfilled\n", GetValue('name')); 1776a22bca6SAndre Fischer } 1786a22bca6SAndre Fischer else 1796a22bca6SAndre Fischer { 1806a22bca6SAndre Fischer my $name = GetValue('name'); 18110e20387SAndre Fischer my $checksum = GetChecksum(); 1826a22bca6SAndre Fischer 1830aabba3aSAndre Fischer if ( ! IsPresent($name, $checksum)) 18410e20387SAndre Fischer { 18510e20387SAndre Fischer AddDownloadRequest($name, $checksum); 1866a22bca6SAndre Fischer } 1876a22bca6SAndre Fischer } 1886a22bca6SAndre Fischer} 1896a22bca6SAndre Fischer 1906a22bca6SAndre Fischer 1916a22bca6SAndre Fischer 1926a22bca6SAndre Fischer 19310e20387SAndre Fischer=head3 AddDownloadRequest($name, $checksum) 1946a22bca6SAndre Fischer 1956a22bca6SAndre Fischer Add a request for downloading the library $name to @Missing. 1966a22bca6SAndre Fischer Collect all available URL[1-9] variables as source URLs. 1976a22bca6SAndre Fischer 1986a22bca6SAndre Fischer=cut 19910e20387SAndre Fischersub AddDownloadRequest ($$) 2006a22bca6SAndre Fischer{ 20110e20387SAndre Fischer my ($name, $checksum) = @_; 2026a22bca6SAndre Fischer 2036a22bca6SAndre Fischer print "adding download request for $name\n"; 2046a22bca6SAndre Fischer 2056a22bca6SAndre Fischer my $urls = []; 2066a22bca6SAndre Fischer my $url = GetValue('URL'); 2076a22bca6SAndre Fischer push @$urls, SubstituteVariables($url) if (defined $url); 2086a22bca6SAndre Fischer for (my $i=1; $i<10; ++$i) 2096a22bca6SAndre Fischer { 2106a22bca6SAndre Fischer $url = GetValue('URL'.$i); 2116a22bca6SAndre Fischer next if ! defined $url; 2126a22bca6SAndre Fischer push @$urls, SubstituteVariables($url); 2136a22bca6SAndre Fischer } 2146a22bca6SAndre Fischer 21510e20387SAndre Fischer push @Missing, [$name, $checksum, $urls]; 21610e20387SAndre Fischer} 21710e20387SAndre Fischer 21810e20387SAndre Fischer 21910e20387SAndre Fischer 22010e20387SAndre Fischer 22110e20387SAndre Fischer=head3 GetChecksum() 22210e20387SAndre Fischer 22310e20387SAndre Fischer When either MD5 or SHA1 are variables in the current scope then return 22410e20387SAndre Fischer a reference to a hash with two entries: 22510e20387SAndre Fischer 'type' is either 'MD5' or 'SHA1', the type or algorithm of the checksum, 22610e20387SAndre Fischer 'value' is the actual checksum 22710e20387SAndre Fischer Otherwise undef is returned. 22810e20387SAndre Fischer 22910e20387SAndre Fischer=cut 23010e20387SAndre Fischersub GetChecksum() 23110e20387SAndre Fischer{ 23210e20387SAndre Fischer my $checksum = GetValue("MD5"); 23310e20387SAndre Fischer if (defined $checksum && $checksum ne "") 23410e20387SAndre Fischer { 23510e20387SAndre Fischer return { 'type' => 'MD5', 'value' => $checksum }; 23610e20387SAndre Fischer } 23710e20387SAndre Fischer elsif (defined ($checksum=GetValue("SHA1")) && $checksum ne "") 23810e20387SAndre Fischer { 23910e20387SAndre Fischer return { 'type' => 'SHA1', 'value' => $checksum }; 24010e20387SAndre Fischer } 24110e20387SAndre Fischer else 24210e20387SAndre Fischer { 24310e20387SAndre Fischer return undef; 24410e20387SAndre Fischer } 2456a22bca6SAndre Fischer} 2466a22bca6SAndre Fischer 2476a22bca6SAndre Fischer 2486a22bca6SAndre Fischer 2496a22bca6SAndre Fischer 2506a22bca6SAndre Fischer=head3 GetValue($variable_name) 2516a22bca6SAndre Fischer 2526a22bca6SAndre Fischer Return the value of the variable with name $variable_name from the local 2536a22bca6SAndre Fischer environment or, if not defined there, the global environment. 2546a22bca6SAndre Fischer 2556a22bca6SAndre Fischer=cut 2566a22bca6SAndre Fischersub GetValue ($) 2576a22bca6SAndre Fischer{ 2586a22bca6SAndre Fischer my $variable_name = shift; 2596a22bca6SAndre Fischer 2606a22bca6SAndre Fischer my $candidate = $LocalEnvironment->{$variable_name}; 2616a22bca6SAndre Fischer return $candidate if defined $candidate; 2626a22bca6SAndre Fischer 2636a22bca6SAndre Fischer return $GlobalEnvironment->{$variable_name}; 2646a22bca6SAndre Fischer} 2656a22bca6SAndre Fischer 2666a22bca6SAndre Fischer 2676a22bca6SAndre Fischer 2686a22bca6SAndre Fischer=head3 SubstituteVariables($text) 2696a22bca6SAndre Fischer 2706a22bca6SAndre Fischer Replace all references to variables in $text with the respective variable values. 2716a22bca6SAndre Fischer This is done repeatedly until no variable reference remains. 2726a22bca6SAndre Fischer 2736a22bca6SAndre Fischer=cut 2746a22bca6SAndre Fischersub SubstituteVariables ($) 2756a22bca6SAndre Fischer{ 2766a22bca6SAndre Fischer my $text = shift; 2776a22bca6SAndre Fischer 2786a22bca6SAndre Fischer my $infinite_recursion_guard = 100; 2796a22bca6SAndre Fischer while ($text =~ /^(.*?)\$\(([^)]+)\)(.*)$/) 2806a22bca6SAndre Fischer { 2816a22bca6SAndre Fischer my ($head,$name,$tail) = ($1,$2,$3); 2826a22bca6SAndre Fischer my $value = GetValue($name); 2830aabba3aSAndre Fischer die "can not evaluate variable $name" if ! defined $value; 2846a22bca6SAndre Fischer $text = $head.$value.$tail; 2856a22bca6SAndre Fischer 2866a22bca6SAndre Fischer die "(probably) detected an infinite recursion in variable definitions" if --$infinite_recursion_guard<=0; 2876a22bca6SAndre Fischer } 2886a22bca6SAndre Fischer 2896a22bca6SAndre Fischer return $text; 2906a22bca6SAndre Fischer} 2916a22bca6SAndre Fischer 2926a22bca6SAndre Fischer 2936a22bca6SAndre Fischer 2946a22bca6SAndre Fischer 2956a22bca6SAndre Fischer=head3 EvaluateExpression($expression) 2966a22bca6SAndre Fischer 2976a22bca6SAndre Fischer Evaluate the $expression of an "if" statement to either 0 or 1. It can 2986a22bca6SAndre Fischer be a single term (see EvaluateTerm for a description), or several terms 2996a22bca6SAndre Fischer separated by either all ||s or &&s. A term can also be an expression 3006a22bca6SAndre Fischer enclosed in parantheses. 3016a22bca6SAndre Fischer 3026a22bca6SAndre Fischer=cut 3036a22bca6SAndre Fischersub EvaluateExpression ($) 3046a22bca6SAndre Fischer{ 3056a22bca6SAndre Fischer my $expression = shift; 3066a22bca6SAndre Fischer 3076a22bca6SAndre Fischer # Evaluate sub expressions enclosed in parantheses. 3086a22bca6SAndre Fischer while ($expression =~ /^(.*)\(([^\(\)]+)\)(.*)$/) 3096a22bca6SAndre Fischer { 3106a22bca6SAndre Fischer $expression = $1 . (EvaluateExpression($2) ? " true " : " false ") . $3; 3116a22bca6SAndre Fischer } 3126a22bca6SAndre Fischer 3136a22bca6SAndre Fischer if ($expression =~ /&&/ && $expression =~ /\|\|/) 3146a22bca6SAndre Fischer { 3156a22bca6SAndre Fischer die "expression can contain either && or || but not both at the same time"; 3166a22bca6SAndre Fischer } 3176a22bca6SAndre Fischer elsif ($expression =~ /&&/) 3186a22bca6SAndre Fischer { 3196a22bca6SAndre Fischer foreach my $term (split (/\s*&&\s*/,$expression)) 3206a22bca6SAndre Fischer { 3216a22bca6SAndre Fischer return 0 if ! EvaluateTerm($term); 3226a22bca6SAndre Fischer } 3236a22bca6SAndre Fischer return 1; 3246a22bca6SAndre Fischer } 3256a22bca6SAndre Fischer elsif ($expression =~ /\|\|/) 3266a22bca6SAndre Fischer { 3276a22bca6SAndre Fischer foreach my $term (split (/\s*\|\|\s*/,$expression)) 3286a22bca6SAndre Fischer { 3296a22bca6SAndre Fischer return 1 if EvaluateTerm($term); 3306a22bca6SAndre Fischer } 3316a22bca6SAndre Fischer return 0; 3326a22bca6SAndre Fischer } 3336a22bca6SAndre Fischer else 3346a22bca6SAndre Fischer { 3356a22bca6SAndre Fischer return EvaluateTerm($expression); 3366a22bca6SAndre Fischer } 3376a22bca6SAndre Fischer} 3386a22bca6SAndre Fischer 3396a22bca6SAndre Fischer 3406a22bca6SAndre Fischer 3416a22bca6SAndre Fischer 3426a22bca6SAndre Fischer=head3 EvaluateTerm($term) 3436a22bca6SAndre Fischer 3446a22bca6SAndre Fischer Evaluate the $term to either 0 or 1. 3456a22bca6SAndre Fischer A term is either the literal "true", which evaluates to 1, or an expression 3466a22bca6SAndre Fischer of the form NAME=VALUE or NAME!=VALUE. NAME is the name of an environment 3476a22bca6SAndre Fischer variable and VALUE any string. VALUE may be empty. 3486a22bca6SAndre Fischer 3496a22bca6SAndre Fischer=cut 3506a22bca6SAndre Fischersub EvaluateTerm ($) 3516a22bca6SAndre Fischer{ 3526a22bca6SAndre Fischer my $term = shift; 3536a22bca6SAndre Fischer 3546a22bca6SAndre Fischer if ($term =~ /^\s*([a-zA-Z_0-9]+)\s*(==|!=)\s*(.*)\s*$/) 3556a22bca6SAndre Fischer { 3566a22bca6SAndre Fischer my ($variable_name, $operator, $given_value) = ($1,$2,$3); 3576a22bca6SAndre Fischer my $variable_value = $ENV{$variable_name}; 3586a22bca6SAndre Fischer $variable_value = "" if ! defined $variable_value; 3596a22bca6SAndre Fischer 3606a22bca6SAndre Fischer if ($operator eq "==") 3616a22bca6SAndre Fischer { 3626a22bca6SAndre Fischer return $variable_value eq $given_value; 3636a22bca6SAndre Fischer } 3646a22bca6SAndre Fischer elsif ($operator eq "!=") 3656a22bca6SAndre Fischer { 3666a22bca6SAndre Fischer return $variable_value ne $given_value; 3676a22bca6SAndre Fischer } 3686a22bca6SAndre Fischer else 3696a22bca6SAndre Fischer { 3706a22bca6SAndre Fischer die "unknown operator in term $term"; 3716a22bca6SAndre Fischer } 3726a22bca6SAndre Fischer } 3736a22bca6SAndre Fischer elsif ($term =~ /^\s*true\s*$/i) 3746a22bca6SAndre Fischer { 3756a22bca6SAndre Fischer return 1; 3766a22bca6SAndre Fischer } 3776a22bca6SAndre Fischer elsif ($term =~ /^\s*false\s*$/i) 3786a22bca6SAndre Fischer { 3796a22bca6SAndre Fischer return 0; 3806a22bca6SAndre Fischer } 3816a22bca6SAndre Fischer else 3826a22bca6SAndre Fischer { 3836a22bca6SAndre Fischer die "term $term is not of the form <environment-variable> (=|==) <value>"; 3846a22bca6SAndre Fischer } 3856a22bca6SAndre Fischer} 3866a22bca6SAndre Fischer 3876a22bca6SAndre Fischer 3886a22bca6SAndre Fischer 3896a22bca6SAndre Fischer 39010e20387SAndre Fischer=head IsPresent($name, $given_checksum) 3916a22bca6SAndre Fischer 3926a22bca6SAndre Fischer Check if an external library tar ball with the basename $name already 3936a22bca6SAndre Fischer exists in the target directory TARFILE_LOCATION. The basename is 39410e20387SAndre Fischer prefixed with the MD5 or SHA1 checksum. 39510e20387SAndre Fischer If the file exists then its checksum is compared to the given one. 3966a22bca6SAndre Fischer 3976a22bca6SAndre Fischer=cut 3986a22bca6SAndre Fischersub IsPresent ($$) 3996a22bca6SAndre Fischer{ 40010e20387SAndre Fischer my ($name, $given_checksum) = @_; 4016a22bca6SAndre Fischer 40210e20387SAndre Fischer my $filename = File::Spec->catfile($ENV{'TARFILE_LOCATION'}, $given_checksum->{'value'}."-".$name); 40310e20387SAndre Fischer return 0 unless -f $filename; 4046a22bca6SAndre Fischer 40510e20387SAndre Fischer # File exists. Check if its checksum is correct. 40610e20387SAndre Fischer my $checksum; 4070aabba3aSAndre Fischer if ( ! defined $given_checksum) 4080aabba3aSAndre Fischer { 4090aabba3aSAndre Fischer print "no checksum given, can not verify\n"; 4100aabba3aSAndre Fischer return 1; 4110aabba3aSAndre Fischer } 4120aabba3aSAndre Fischer elsif ($given_checksum->{'type'} eq "MD5") 41310e20387SAndre Fischer { 4146a22bca6SAndre Fischer my $md5 = Digest::MD5->new(); 4156a22bca6SAndre Fischer open my $in, $filename; 4166a22bca6SAndre Fischer $md5->addfile($in); 41710e20387SAndre Fischer $checksum = $md5->hexdigest(); 41810e20387SAndre Fischer } 41910e20387SAndre Fischer elsif ($given_checksum->{'type'} eq "SHA1") 4206a22bca6SAndre Fischer { 42110e20387SAndre Fischer my $sha1 = Digest::SHA->new("1"); 42210e20387SAndre Fischer open my $in, $filename; 42310e20387SAndre Fischer $sha1->addfile($in); 42410e20387SAndre Fischer $checksum = $sha1->hexdigest(); 42510e20387SAndre Fischer } 42610e20387SAndre Fischer else 42710e20387SAndre Fischer { 42810e20387SAndre Fischer die "unsupported checksum type (not MD5 or SHA1)"; 42910e20387SAndre Fischer } 43010e20387SAndre Fischer 43110e20387SAndre Fischer if ($given_checksum->{'value'} ne $checksum) 43210e20387SAndre Fischer { 43310e20387SAndre Fischer # Checksum does not match. Delete the file. 43410e20387SAndre Fischer print "$name exists, but checksum does not match => deleting\n"; 4350aabba3aSAndre Fischer unlink($filename); 4366a22bca6SAndre Fischer return 0; 4376a22bca6SAndre Fischer } 4386a22bca6SAndre Fischer else 4396a22bca6SAndre Fischer { 44010e20387SAndre Fischer printf("%s exists, %s checksum is OK\n", $name, $given_checksum->{'type'}); 4416a22bca6SAndre Fischer return 1; 4426a22bca6SAndre Fischer } 4436a22bca6SAndre Fischer} 4446a22bca6SAndre Fischer 4456a22bca6SAndre Fischer 4466a22bca6SAndre Fischer 4476a22bca6SAndre Fischer 4486a22bca6SAndre Fischer=head3 Download 4496a22bca6SAndre Fischer 4506a22bca6SAndre Fischer Download a set of files specified by @Missing. 4516a22bca6SAndre Fischer 45210e20387SAndre Fischer For http URLs there may be an optional checksum. If it is present then downloaded 45310e20387SAndre Fischer files that do not match that checksum lead to abortion of the current process. 4546a22bca6SAndre Fischer Files that have already been downloaded are not downloaded again. 4556a22bca6SAndre Fischer 4566a22bca6SAndre Fischer=cut 4576a22bca6SAndre Fischersub Download () 4586a22bca6SAndre Fischer{ 4596a22bca6SAndre Fischer my $download_path = $ENV{'TARFILE_LOCATION'}; 4606a22bca6SAndre Fischer 4616a22bca6SAndre Fischer if (scalar @Missing > 0) 4626a22bca6SAndre Fischer { 4636a22bca6SAndre Fischer printf("downloading %d missing tar ball%s to %s\n", 4646a22bca6SAndre Fischer scalar @Missing, scalar @Missing>0 ? "s" : "", 4656a22bca6SAndre Fischer $download_path); 4666a22bca6SAndre Fischer } 4676a22bca6SAndre Fischer else 4686a22bca6SAndre Fischer { 4696a22bca6SAndre Fischer print "all external libraries present\n"; 4706a22bca6SAndre Fischer return; 4716a22bca6SAndre Fischer } 4726a22bca6SAndre Fischer 4736a22bca6SAndre Fischer # Download the missing files. 474*489cdf4fSarielch my $all_downloaded = 1; 4756a22bca6SAndre Fischer for my $item (@Missing) 4766a22bca6SAndre Fischer { 47710e20387SAndre Fischer my ($name, $checksum, $urls) = @$item; 4786a22bca6SAndre Fischer 479*489cdf4fSarielch my $downloaded = 0; 4806a22bca6SAndre Fischer foreach my $url (@$urls) 4816a22bca6SAndre Fischer { 482*489cdf4fSarielch $downloaded = DownloadFile( 4830aabba3aSAndre Fischer defined $checksum 4840aabba3aSAndre Fischer ? $checksum->{'value'}."-".$name 4850aabba3aSAndre Fischer : $name, 4860aabba3aSAndre Fischer $url, 4870aabba3aSAndre Fischer $checksum); 488*489cdf4fSarielch last if $downloaded 4896a22bca6SAndre Fischer } 490*489cdf4fSarielch $all_downloaded &&= $downloaded; 4916a22bca6SAndre Fischer } 492*489cdf4fSarielch die "some needed files could not be downloaded!" if !$all_downloaded; 4936a22bca6SAndre Fischer} 4946a22bca6SAndre Fischer 4956a22bca6SAndre Fischer 4966a22bca6SAndre Fischer 4976a22bca6SAndre Fischer 49810e20387SAndre Fischer=head3 DownloadFile($name,$URL,$checksum) 4996a22bca6SAndre Fischer 5006a22bca6SAndre Fischer Download a single external library tarball. It origin is given by $URL. 50110e20387SAndre Fischer Its destination is $(TARFILE_LOCATION)/$checksum-$name. 5026a22bca6SAndre Fischer 5036a22bca6SAndre Fischer=cut 5046a22bca6SAndre Fischersub DownloadFile ($$$) 5056a22bca6SAndre Fischer{ 5066a22bca6SAndre Fischer my $name = shift; 5076a22bca6SAndre Fischer my $URL = shift; 50810e20387SAndre Fischer my $checksum = shift; 5096a22bca6SAndre Fischer 5106a22bca6SAndre Fischer my $filename = File::Spec->catfile($ENV{'TARFILE_LOCATION'}, $name); 5116a22bca6SAndre Fischer 5126a22bca6SAndre Fischer my $temporary_filename = $filename . ".part"; 5136a22bca6SAndre Fischer 5146a22bca6SAndre Fischer print "downloading to $temporary_filename\n"; 5150aabba3aSAndre Fischer my $out; 5160aabba3aSAndre Fischer open $out, ">$temporary_filename"; 5176a22bca6SAndre Fischer binmode($out); 5186a22bca6SAndre Fischer 51910e20387SAndre Fischer # Prepare checksum 52010e20387SAndre Fischer my $digest; 52110e20387SAndre Fischer if (defined $checksum && $checksum->{'type'} eq "SHA1") 52210e20387SAndre Fischer { 52310e20387SAndre Fischer # Use SHA1 only when explicitly requested (by the presence of a "SHA1=..." line.) 52410e20387SAndre Fischer $digest = Digest::SHA->new("1"); 52510e20387SAndre Fischer } 52610e20387SAndre Fischer elsif ( ! defined $checksum || $checksum->{'type'} eq "MD5") 52710e20387SAndre Fischer { 52810e20387SAndre Fischer # Use MD5 when explicitly requested or when no checksum type is given. 52910e20387SAndre Fischer $digest = Digest::MD5->new(); 53010e20387SAndre Fischer } 53110e20387SAndre Fischer else 53210e20387SAndre Fischer { 53310e20387SAndre Fischer die "checksum type ".$checksum->{'type'}." is not supported"; 53410e20387SAndre Fischer } 5356a22bca6SAndre Fischer 5366a22bca6SAndre Fischer # Download the extension. 537f253223cSAndre Fischer my $success = 0; 538*489cdf4fSarielch 539*489cdf4fSarielch my $agent = LWP::UserAgent->new(); 540*489cdf4fSarielch $agent->env_proxy; 541*489cdf4fSarielch my $response = $agent->get($URL); 542*489cdf4fSarielch 543*489cdf4fSarielch $success = $response->is_success; 544f253223cSAndre Fischer if ($success) 545f253223cSAndre Fischer { 546*489cdf4fSarielch my $content = $response->content; 547f253223cSAndre Fischer open $out, ">$temporary_filename"; 548f253223cSAndre Fischer binmode($out); 549f253223cSAndre Fischer print $out $content; 550f253223cSAndre Fischer $digest->add($content); 551f253223cSAndre Fischer } 552f253223cSAndre Fischer else 553f253223cSAndre Fischer { 554*489cdf4fSarielch print "download from $URL failed (" . $response->status_line . ")\n"; 555f253223cSAndre Fischer } 556*489cdf4fSarielch close($out); 5576a22bca6SAndre Fischer 558*489cdf4fSarielch # When download was successful then check the checksum and rename the .part file 5596a22bca6SAndre Fischer # into the actual extension name. 560f253223cSAndre Fischer if ($success) 5616a22bca6SAndre Fischer { 56210e20387SAndre Fischer my $file_checksum = $digest->hexdigest(); 56310e20387SAndre Fischer if (defined $checksum) 5646a22bca6SAndre Fischer { 56510e20387SAndre Fischer if ($checksum->{'value'} eq $file_checksum) 5666a22bca6SAndre Fischer { 56710e20387SAndre Fischer printf("%s checksum is OK\n", $checksum->{'type'}); 5686a22bca6SAndre Fischer } 5696a22bca6SAndre Fischer else 5706a22bca6SAndre Fischer { 5716a22bca6SAndre Fischer unlink($temporary_filename); 57210e20387SAndre Fischer printf(" %s checksum does not match (%s instead of %s)\n", 573a90d3987SAndrea Pescetti $checksum->{'type'}, 57410e20387SAndre Fischer $file_checksum, 575a90d3987SAndrea Pescetti $checksum->{'value'}); 5766a22bca6SAndre Fischer return 0; 5776a22bca6SAndre Fischer } 5786a22bca6SAndre Fischer } 5796a22bca6SAndre Fischer else 5806a22bca6SAndre Fischer { 58110e20387SAndre Fischer # The datafile does not contain a checksum to match against. 58210e20387SAndre Fischer # Display the one that was calculated for the downloaded file so that 58310e20387SAndre Fischer # it can be integrated manually into the data file. 58410e20387SAndre Fischer printf("checksum not given, md5 of file is %s\n", $file_checksum); 58510e20387SAndre Fischer $filename = File::Spec->catfile($ENV{'TARFILE_LOCATION'}, $file_checksum . "-" . $name); 5866a22bca6SAndre Fischer } 5876a22bca6SAndre Fischer 5886a22bca6SAndre Fischer rename($temporary_filename, $filename) || die "can not rename $temporary_filename to $filename"; 5896a22bca6SAndre Fischer return 1; 5906a22bca6SAndre Fischer } 5916a22bca6SAndre Fischer else 5926a22bca6SAndre Fischer { 5936a22bca6SAndre Fischer unlink($temporary_filename); 5946a22bca6SAndre Fischer print " download failed\n"; 5956a22bca6SAndre Fischer return 0; 5966a22bca6SAndre Fischer } 5976a22bca6SAndre Fischer} 5986a22bca6SAndre Fischer 5996a22bca6SAndre Fischer 6006a22bca6SAndre Fischer 6016a22bca6SAndre Fischer 6026a22bca6SAndre Fischer=head3 CheckDownloadDestination () 6036a22bca6SAndre Fischer 6046a22bca6SAndre Fischer Make sure that the download destination $TARFILE_LOCATION does exist. If 6056a22bca6SAndre Fischer not, then the directory is created. 6066a22bca6SAndre Fischer 6076a22bca6SAndre Fischer=cut 6086a22bca6SAndre Fischersub CheckDownloadDestination () 6096a22bca6SAndre Fischer{ 6106a22bca6SAndre Fischer my $destination = $ENV{'TARFILE_LOCATION'}; 6116a22bca6SAndre Fischer die "ERROR: no destination defined! please set TARFILE_LOCATION!" if ($destination eq ""); 6126a22bca6SAndre Fischer 6136a22bca6SAndre Fischer if ( ! -d $destination) 6146a22bca6SAndre Fischer { 6156a22bca6SAndre Fischer File::Path::make_path($destination); 6166a22bca6SAndre Fischer die "ERROR: can't create \$TARFILE_LOCATION" if ! -d $destination; 6176a22bca6SAndre Fischer } 6186a22bca6SAndre Fischer} 6196a22bca6SAndre Fischer 6206a22bca6SAndre Fischer 6216a22bca6SAndre Fischer 6226a22bca6SAndre Fischer 6236a22bca6SAndre Fischer=head3 ProvideSpecialTarball ($url,$name,$name_converter) 6246a22bca6SAndre Fischer 6256a22bca6SAndre Fischer A few tarballs need special handling. That is done here. 6266a22bca6SAndre Fischer 6276a22bca6SAndre Fischer=cut 6286a22bca6SAndre Fischersub ProvideSpecialTarball ($$$) 6296a22bca6SAndre Fischer{ 6306a22bca6SAndre Fischer my $url = shift; 6316a22bca6SAndre Fischer my $name = shift; 6326a22bca6SAndre Fischer my $name_converter = shift; 6336a22bca6SAndre Fischer 6346a22bca6SAndre Fischer return unless defined $url && $url ne ""; 6356a22bca6SAndre Fischer 6366a22bca6SAndre Fischer # See if we can find the executable. 6376a22bca6SAndre Fischer my ($SOLARENV,$OUTPATH,$EXEEXT) = ($ENV{'SOLARENV'},$ENV{'OUTPATH'},$ENV{'EXEEXT'}); 6386a22bca6SAndre Fischer $SOLARENV = "" unless defined $SOLARENV; 6396a22bca6SAndre Fischer $OUTPATH = "" unless defined $OUTPATH; 6406a22bca6SAndre Fischer $EXEEXT = "" unless defined $EXEEXT; 6416a22bca6SAndre Fischer if (-x File::Spec->catfile($SOLARENV, $OUTPATH, "bin", $name.$EXEEXT)) 6426a22bca6SAndre Fischer { 6436a22bca6SAndre Fischer print "found $name executable\n"; 6446a22bca6SAndre Fischer return; 6456a22bca6SAndre Fischer } 6466a22bca6SAndre Fischer 6476a22bca6SAndre Fischer # Download the source from the URL. 6486a22bca6SAndre Fischer my $basename = basename(URI->new($url)->path()); 6496a22bca6SAndre Fischer die unless defined $basename; 6506a22bca6SAndre Fischer 6516a22bca6SAndre Fischer if (defined $name_converter) 6526a22bca6SAndre Fischer { 6536a22bca6SAndre Fischer $basename = &{$name_converter}($basename); 6546a22bca6SAndre Fischer } 6556a22bca6SAndre Fischer 6566a22bca6SAndre Fischer # Has the source tar ball already been downloaded? 6576a22bca6SAndre Fischer my @candidates = glob(File::Spec->catfile($ENV{'TARFILE_LOCATION'}, "*-" . $basename)); 6586a22bca6SAndre Fischer if (scalar @candidates > 0) 6596a22bca6SAndre Fischer { 6606a22bca6SAndre Fischer # Yes. 6616a22bca6SAndre Fischer print "$basename exists\n"; 6626a22bca6SAndre Fischer return; 6636a22bca6SAndre Fischer } 6646a22bca6SAndre Fischer else 6656a22bca6SAndre Fischer { 6666a22bca6SAndre Fischer # No, download it. 6676a22bca6SAndre Fischer print "downloading $basename\n"; 6686a22bca6SAndre Fischer DownloadFile($basename, $url, undef); 6696a22bca6SAndre Fischer } 6706a22bca6SAndre Fischer} 6716a22bca6SAndre Fischer 6726a22bca6SAndre Fischer 6736a22bca6SAndre Fischer 6746a22bca6SAndre Fischer 6756a22bca6SAndre Fischer 6766a22bca6SAndre Fischer# The main() functionality. 6776a22bca6SAndre Fischer 6786a22bca6SAndre Fischerdie "usage: $0 <data-file-name>" if scalar @ARGV != 1; 6796a22bca6SAndre Fischermy $data_file = $ARGV[0]; 6806a22bca6SAndre FischerCheckDownloadDestination(); 6816a22bca6SAndre FischerProcessDataFile($data_file); 6826a22bca6SAndre FischerProvideSpecialTarball($ENV{'DMAKE_URL'}, "dmake", undef); 6836a22bca6SAndre FischerProvideSpecialTarball( 6846a22bca6SAndre Fischer $ENV{'EPM_URL'}, 6856a22bca6SAndre Fischer "epm", 6866a22bca6SAndre Fischer sub{$_[0]=~s/-source//; return $_[0]}); 687