1*b1cdbd2cSJim Jagielski#************************************************************** 2*b1cdbd2cSJim Jagielski# 3*b1cdbd2cSJim Jagielski# Licensed to the Apache Software Foundation (ASF) under one 4*b1cdbd2cSJim Jagielski# or more contributor license agreements. See the NOTICE file 5*b1cdbd2cSJim Jagielski# distributed with this work for additional information 6*b1cdbd2cSJim Jagielski# regarding copyright ownership. The ASF licenses this file 7*b1cdbd2cSJim Jagielski# to you under the Apache License, Version 2.0 (the 8*b1cdbd2cSJim Jagielski# "License"); you may not use this file except in compliance 9*b1cdbd2cSJim Jagielski# with the License. You may obtain a copy of the License at 10*b1cdbd2cSJim Jagielski# 11*b1cdbd2cSJim Jagielski# http://www.apache.org/licenses/LICENSE-2.0 12*b1cdbd2cSJim Jagielski# 13*b1cdbd2cSJim Jagielski# Unless required by applicable law or agreed to in writing, 14*b1cdbd2cSJim Jagielski# software distributed under the License is distributed on an 15*b1cdbd2cSJim Jagielski# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16*b1cdbd2cSJim Jagielski# KIND, either express or implied. See the License for the 17*b1cdbd2cSJim Jagielski# specific language governing permissions and limitations 18*b1cdbd2cSJim Jagielski# under the License. 19*b1cdbd2cSJim Jagielski# 20*b1cdbd2cSJim Jagielski#************************************************************** 21*b1cdbd2cSJim Jagielski 22*b1cdbd2cSJim Jagielskipackage installer::patch::InstallationSet; 23*b1cdbd2cSJim Jagielski 24*b1cdbd2cSJim Jagielskiuse installer::patch::Tools; 25*b1cdbd2cSJim Jagielskiuse installer::patch::Version; 26*b1cdbd2cSJim Jagielskiuse installer::logger; 27*b1cdbd2cSJim Jagielski 28*b1cdbd2cSJim Jagielskiuse strict; 29*b1cdbd2cSJim Jagielski 30*b1cdbd2cSJim Jagielski# Call Get7Zip() to get access to the filename of the 7z executable. 31*b1cdbd2cSJim Jagielskimy $SevenZip = undef; 32*b1cdbd2cSJim Jagielski 33*b1cdbd2cSJim Jagielski 34*b1cdbd2cSJim Jagielski=head1 NAME 35*b1cdbd2cSJim Jagielski 36*b1cdbd2cSJim Jagielski package installer::patch::InstallationSet - Functions for handling installation sets 37*b1cdbd2cSJim Jagielski 38*b1cdbd2cSJim Jagielski=head1 DESCRIPTION 39*b1cdbd2cSJim Jagielski 40*b1cdbd2cSJim Jagielski This package contains functions for unpacking the .exe files that 41*b1cdbd2cSJim Jagielski are created by the NSIS installer creator and the .cab files in 42*b1cdbd2cSJim Jagielski the installation sets. 43*b1cdbd2cSJim Jagielski 44*b1cdbd2cSJim Jagielski=cut 45*b1cdbd2cSJim Jagielski 46*b1cdbd2cSJim Jagielski 47*b1cdbd2cSJim Jagielski 48*b1cdbd2cSJim Jagielski 49*b1cdbd2cSJim Jagielski=head2 Detect7ZipOnWindows () 50*b1cdbd2cSJim Jagielski 51*b1cdbd2cSJim Jagielski 7Zip seems to be the only program able to unpack an NSIS installer. 52*b1cdbd2cSJim Jagielski Search for it. 53*b1cdbd2cSJim Jagielski 54*b1cdbd2cSJim Jagielski=cut 55*b1cdbd2cSJim Jagielski 56*b1cdbd2cSJim Jagielskisub Detect7ZipOnWindows () 57*b1cdbd2cSJim Jagielski{ 58*b1cdbd2cSJim Jagielski # Use 'reg query' to read registry entry from Windows registry. 59*b1cdbd2cSJim Jagielski my $registry_key = "HKEY_CURRENT_USER\\\\Software\\\\7-Zip"; 60*b1cdbd2cSJim Jagielski my $registry_value_name = "Path"; 61*b1cdbd2cSJim Jagielski my $command = sprintf("reg query %s /v %s", $registry_key, $registry_value_name); 62*b1cdbd2cSJim Jagielski my $response = qx($command); 63*b1cdbd2cSJim Jagielski 64*b1cdbd2cSJim Jagielski # Process the response. 65*b1cdbd2cSJim Jagielski my $path_to_7zip = undef; 66*b1cdbd2cSJim Jagielski if ($response =~ /\s+REG_SZ\s+([^\r\n]*)/m) 67*b1cdbd2cSJim Jagielski { 68*b1cdbd2cSJim Jagielski $path_to_7zip = $1; 69*b1cdbd2cSJim Jagielski } 70*b1cdbd2cSJim Jagielski 71*b1cdbd2cSJim Jagielski # If that failed, then make an educated guess. 72*b1cdbd2cSJim Jagielski if ( ! defined $path_to_7zip) 73*b1cdbd2cSJim Jagielski { 74*b1cdbd2cSJim Jagielski $path_to_7zip = "c:\\Program Files\\7-Zip\\"; 75*b1cdbd2cSJim Jagielski } 76*b1cdbd2cSJim Jagielski 77*b1cdbd2cSJim Jagielski # Check if the executable exists and is, well, executable. 78*b1cdbd2cSJim Jagielski return undef unless -d $path_to_7zip; 79*b1cdbd2cSJim Jagielski my $fullname = File::Spec->catfile($path_to_7zip, "7z.exe"); 80*b1cdbd2cSJim Jagielski return undef unless -f $fullname; 81*b1cdbd2cSJim Jagielski return undef unless -x $fullname; 82*b1cdbd2cSJim Jagielski 83*b1cdbd2cSJim Jagielski return $fullname; 84*b1cdbd2cSJim Jagielski} 85*b1cdbd2cSJim Jagielski 86*b1cdbd2cSJim Jagielski 87*b1cdbd2cSJim Jagielski 88*b1cdbd2cSJim Jagielski 89*b1cdbd2cSJim Jagielskisub Get7Zip () 90*b1cdbd2cSJim Jagielski{ 91*b1cdbd2cSJim Jagielski if ( ! defined $SevenZip) 92*b1cdbd2cSJim Jagielski { 93*b1cdbd2cSJim Jagielski if ($ENV{'OS'} eq "WNT") 94*b1cdbd2cSJim Jagielski { 95*b1cdbd2cSJim Jagielski $SevenZip = Detect7ZipOnWindows(); 96*b1cdbd2cSJim Jagielski } 97*b1cdbd2cSJim Jagielski if ( ! defined $SevenZip) 98*b1cdbd2cSJim Jagielski { 99*b1cdbd2cSJim Jagielski # Use an empty string to avoid repeated (and failing) detections of a missing 7z. 100*b1cdbd2cSJim Jagielski $SevenZip = ""; 101*b1cdbd2cSJim Jagielski } 102*b1cdbd2cSJim Jagielski } 103*b1cdbd2cSJim Jagielski 104*b1cdbd2cSJim Jagielski return $SevenZip eq "" ? undef : $SevenZip; 105*b1cdbd2cSJim Jagielski} 106*b1cdbd2cSJim Jagielski 107*b1cdbd2cSJim Jagielski 108*b1cdbd2cSJim Jagielski 109*b1cdbd2cSJim Jagielski 110*b1cdbd2cSJim Jagielskisub UnpackExe ($$) 111*b1cdbd2cSJim Jagielski{ 112*b1cdbd2cSJim Jagielski my ($filename, $destination_path) = @_; 113*b1cdbd2cSJim Jagielski 114*b1cdbd2cSJim Jagielski $installer::logger::Info->printf("unpacking installation set to '%s'\n", $destination_path); 115*b1cdbd2cSJim Jagielski 116*b1cdbd2cSJim Jagielski # Unpack to a temporary path and change its name to the destination path 117*b1cdbd2cSJim Jagielski # only when the unpacking has completed successfully. 118*b1cdbd2cSJim Jagielski File::Path::make_path($destination_path); 119*b1cdbd2cSJim Jagielski 120*b1cdbd2cSJim Jagielski my $windows_filename = installer::patch::Tools::ToEscapedWindowsPath($filename); 121*b1cdbd2cSJim Jagielski my $windows_destination_path = installer::patch::Tools::ToEscapedWindowsPath($destination_path); 122*b1cdbd2cSJim Jagielski my $command = join(" ", 123*b1cdbd2cSJim Jagielski "\"".Get7Zip()."\"", 124*b1cdbd2cSJim Jagielski "x", 125*b1cdbd2cSJim Jagielski "-y", 126*b1cdbd2cSJim Jagielski "-o".$windows_destination_path, 127*b1cdbd2cSJim Jagielski $windows_filename); 128*b1cdbd2cSJim Jagielski my $result = qx($command); 129*b1cdbd2cSJim Jagielski if ( ! $result) 130*b1cdbd2cSJim Jagielski { 131*b1cdbd2cSJim Jagielski installer::exiter::exit_program( 132*b1cdbd2cSJim Jagielski "ERROR: can not unpack downloadable installation set: ".$!, 133*b1cdbd2cSJim Jagielski "installer::patch::InstallationSet::UnpackExe"); 134*b1cdbd2cSJim Jagielski } 135*b1cdbd2cSJim Jagielski 136*b1cdbd2cSJim Jagielski # Check the existence of the .cab files. 137*b1cdbd2cSJim Jagielski my $cab_filename = File::Spec->catfile($destination_path, "openoffice1.cab"); 138*b1cdbd2cSJim Jagielski if ( ! -f $cab_filename) 139*b1cdbd2cSJim Jagielski { 140*b1cdbd2cSJim Jagielski installer::logger::PrintError("cab file '%s' was not extracted from installation set\n", $cab_filename); 141*b1cdbd2cSJim Jagielski return 0; 142*b1cdbd2cSJim Jagielski } 143*b1cdbd2cSJim Jagielski return 1; 144*b1cdbd2cSJim Jagielski} 145*b1cdbd2cSJim Jagielski 146*b1cdbd2cSJim Jagielski 147*b1cdbd2cSJim Jagielski 148*b1cdbd2cSJim Jagielski 149*b1cdbd2cSJim Jagielski=head2 UnpackCab($cab_filename, $destination_path) 150*b1cdbd2cSJim Jagielski 151*b1cdbd2cSJim Jagielski Unpacking the cabinet file inside an .exe installation set is a 152*b1cdbd2cSJim Jagielski three step process because there is no directory information stored 153*b1cdbd2cSJim Jagielski inside the cab file. This has to be taken from the 'File' and 154*b1cdbd2cSJim Jagielski 'Directory' tables in the .msi file. 155*b1cdbd2cSJim Jagielski 156*b1cdbd2cSJim Jagielski 1. Setup the directory structure of all files in the cab from the 'File' and 'Directory' tables in the msi. 157*b1cdbd2cSJim Jagielski 158*b1cdbd2cSJim Jagielski 2. Unpack the cab file. 159*b1cdbd2cSJim Jagielski 160*b1cdbd2cSJim Jagielski 3. Move the files to their destination directories. 161*b1cdbd2cSJim Jagielski 162*b1cdbd2cSJim Jagielski=cut 163*b1cdbd2cSJim Jagielskisub UnpackCab ($$$) 164*b1cdbd2cSJim Jagielski{ 165*b1cdbd2cSJim Jagielski my ($cab_filename, $msi, $destination_path) = @_; 166*b1cdbd2cSJim Jagielski 167*b1cdbd2cSJim Jagielski # Step 1 168*b1cdbd2cSJim Jagielski # Extract the directory structure from the 'File' and 'Directory' tables in the given msi. 169*b1cdbd2cSJim Jagielski $installer::logger::Info->printf("setting up directory tree\n"); 170*b1cdbd2cSJim Jagielski my $file_table = $msi->GetTable("File"); 171*b1cdbd2cSJim Jagielski my $file_map = $msi->GetFileMap(); 172*b1cdbd2cSJim Jagielski 173*b1cdbd2cSJim Jagielski # Step 2 174*b1cdbd2cSJim Jagielski # Unpack the .cab file to a temporary path. 175*b1cdbd2cSJim Jagielski my $temporary_destination_path = $destination_path . ".tmp"; 176*b1cdbd2cSJim Jagielski if ( -d $temporary_destination_path) 177*b1cdbd2cSJim Jagielski { 178*b1cdbd2cSJim Jagielski # Temporary directory already exists => cab file has already been unpacked (flat), nothing to do. 179*b1cdbd2cSJim Jagielski printf("%s exists\n", $temporary_destination_path); 180*b1cdbd2cSJim Jagielski $installer::logger::Info->printf("cab file has already been unpacked to flat structure\n"); 181*b1cdbd2cSJim Jagielski } 182*b1cdbd2cSJim Jagielski else 183*b1cdbd2cSJim Jagielski { 184*b1cdbd2cSJim Jagielski UnpackCabFlat($cab_filename, $temporary_destination_path, $file_table); 185*b1cdbd2cSJim Jagielski } 186*b1cdbd2cSJim Jagielski 187*b1cdbd2cSJim Jagielski # Step 3 188*b1cdbd2cSJim Jagielski # Move the files to their destinations. 189*b1cdbd2cSJim Jagielski File::Path::make_path($destination_path); 190*b1cdbd2cSJim Jagielski $installer::logger::Info->printf("moving files to their directories\n"); 191*b1cdbd2cSJim Jagielski my $directory_map = $msi->GetDirectoryMap(); 192*b1cdbd2cSJim Jagielski my $office_menu_folder_name = $directory_map->{'INSTALLLOCATION'}->{'target_long_name'}; 193*b1cdbd2cSJim Jagielski my $count = 0; 194*b1cdbd2cSJim Jagielski foreach my $file_row (@{$file_table->GetAllRows()}) 195*b1cdbd2cSJim Jagielski { 196*b1cdbd2cSJim Jagielski my $unique_name = $file_row->GetValue('File'); 197*b1cdbd2cSJim Jagielski my $file_item = $file_map->{$unique_name}; 198*b1cdbd2cSJim Jagielski my $directory_item = $file_item->{'directory'}; 199*b1cdbd2cSJim Jagielski my $long_file_name = $file_item->{'long_name'}; 200*b1cdbd2cSJim Jagielski my $full_name = $directory_item->{'full_source_long_name'}; 201*b1cdbd2cSJim Jagielski # Strip away the leading OfficeMenuFolder part. 202*b1cdbd2cSJim Jagielski $full_name =~ s/^$office_menu_folder_name\///; 203*b1cdbd2cSJim Jagielski my $flat_filename = File::Spec->catfile($temporary_destination_path, $unique_name); 204*b1cdbd2cSJim Jagielski my $dir_path = File::Spec->catfile($destination_path, $full_name); 205*b1cdbd2cSJim Jagielski my $dir_filename = File::Spec->catfile($dir_path, $long_file_name); 206*b1cdbd2cSJim Jagielski 207*b1cdbd2cSJim Jagielski if ( ! -d $dir_path) 208*b1cdbd2cSJim Jagielski { 209*b1cdbd2cSJim Jagielski File::Path::make_path($dir_path); 210*b1cdbd2cSJim Jagielski } 211*b1cdbd2cSJim Jagielski 212*b1cdbd2cSJim Jagielski $installer::logger::Lang->printf("moving %s to %s\n", $flat_filename, $dir_filename); 213*b1cdbd2cSJim Jagielski File::Copy::move($flat_filename, $dir_filename) 214*b1cdbd2cSJim Jagielski || die("can not move file ".$flat_filename.":".$!); 215*b1cdbd2cSJim Jagielski 216*b1cdbd2cSJim Jagielski ++$count; 217*b1cdbd2cSJim Jagielski } 218*b1cdbd2cSJim Jagielski 219*b1cdbd2cSJim Jagielski # Cleanup. Remove the temporary directory. It should be empty by now. 220*b1cdbd2cSJim Jagielski rmdir($temporary_destination_path); 221*b1cdbd2cSJim Jagielski} 222*b1cdbd2cSJim Jagielski 223*b1cdbd2cSJim Jagielski 224*b1cdbd2cSJim Jagielski 225*b1cdbd2cSJim Jagielski 226*b1cdbd2cSJim Jagielski=head2 UnpackCabFlat ($cab_filename, $destination_path, $file_table) 227*b1cdbd2cSJim Jagielski 228*b1cdbd2cSJim Jagielski Unpack the flat file structure of the $cab_filename to $destination_path. 229*b1cdbd2cSJim Jagielski 230*b1cdbd2cSJim Jagielski In order to detect and handle an incomplete (arborted) previous 231*b1cdbd2cSJim Jagielski extraction, the cab file is unpacked to a temprorary directory 232*b1cdbd2cSJim Jagielski that after successful extraction is renamed to $destination_path. 233*b1cdbd2cSJim Jagielski 234*b1cdbd2cSJim Jagielski=cut 235*b1cdbd2cSJim Jagielskisub UnpackCabFlat ($$$) 236*b1cdbd2cSJim Jagielski{ 237*b1cdbd2cSJim Jagielski my ($cab_filename, $destination_path, $file_table) = @_; 238*b1cdbd2cSJim Jagielski 239*b1cdbd2cSJim Jagielski # Unpack the .cab file to a temporary path (note that 240*b1cdbd2cSJim Jagielski # $destination_path may alreay bee a temporary path). Using a 241*b1cdbd2cSJim Jagielski # second one prevents the lengthy flat unpacking to be repeated 242*b1cdbd2cSJim Jagielski # when another step fails. 243*b1cdbd2cSJim Jagielski 244*b1cdbd2cSJim Jagielski $installer::logger::Info->printf("unpacking cab file\n"); 245*b1cdbd2cSJim Jagielski File::Path::make_path($destination_path); 246*b1cdbd2cSJim Jagielski my $windows_cab_filename = installer::patch::Tools::ToEscapedWindowsPath($cab_filename); 247*b1cdbd2cSJim Jagielski my $windows_destination_path = installer::patch::Tools::ToEscapedWindowsPath($destination_path); 248*b1cdbd2cSJim Jagielski my $command = join(" ", 249*b1cdbd2cSJim Jagielski "\"".Get7Zip()."\"", 250*b1cdbd2cSJim Jagielski "x", "-o".$windows_destination_path, 251*b1cdbd2cSJim Jagielski $windows_cab_filename, 252*b1cdbd2cSJim Jagielski "-y"); 253*b1cdbd2cSJim Jagielski open my $cmd, $command."|"; 254*b1cdbd2cSJim Jagielski my $extraction_count = 0; 255*b1cdbd2cSJim Jagielski my $file_count = $file_table->GetRowCount(); 256*b1cdbd2cSJim Jagielski while (<$cmd>) 257*b1cdbd2cSJim Jagielski { 258*b1cdbd2cSJim Jagielski my $message = $_; 259*b1cdbd2cSJim Jagielski chomp($message); 260*b1cdbd2cSJim Jagielski ++$extraction_count; 261*b1cdbd2cSJim Jagielski printf("%4d/%4d %3.2f%% \r", 262*b1cdbd2cSJim Jagielski $extraction_count, 263*b1cdbd2cSJim Jagielski $file_count, 264*b1cdbd2cSJim Jagielski $extraction_count*100/$file_count); 265*b1cdbd2cSJim Jagielski } 266*b1cdbd2cSJim Jagielski close $cmd; 267*b1cdbd2cSJim Jagielski} 268*b1cdbd2cSJim Jagielski 269*b1cdbd2cSJim Jagielski 270*b1cdbd2cSJim Jagielski 271*b1cdbd2cSJim Jagielski 272*b1cdbd2cSJim Jagielski=head GetUnpackedExePath ($version, $is_current_version, $language, $package_format, $product) 273*b1cdbd2cSJim Jagielski 274*b1cdbd2cSJim Jagielski Convenience function that returns where a downloadable installation set is extracted to. 275*b1cdbd2cSJim Jagielski 276*b1cdbd2cSJim Jagielski=cut 277*b1cdbd2cSJim Jagielskisub GetUnpackedExePath ($$$$$) 278*b1cdbd2cSJim Jagielski{ 279*b1cdbd2cSJim Jagielski my ($version, $is_current_version, $language, $package_format, $product) = @_; 280*b1cdbd2cSJim Jagielski 281*b1cdbd2cSJim Jagielski my $path = GetUnpackedPath($version, $is_current_version, $language, $package_format, $product); 282*b1cdbd2cSJim Jagielski return File::Spec->catfile($path, "unpacked"); 283*b1cdbd2cSJim Jagielski} 284*b1cdbd2cSJim Jagielski 285*b1cdbd2cSJim Jagielski 286*b1cdbd2cSJim Jagielski 287*b1cdbd2cSJim Jagielski 288*b1cdbd2cSJim Jagielski=head GetUnpackedCabPath ($version, $is_current_version, $language, $package_format, $product) 289*b1cdbd2cSJim Jagielski 290*b1cdbd2cSJim Jagielski Convenience function that returns where a cab file is extracted 291*b1cdbd2cSJim Jagielski (with injected directory structure from the msi file) to. 292*b1cdbd2cSJim Jagielski 293*b1cdbd2cSJim Jagielski=cut 294*b1cdbd2cSJim Jagielskisub GetUnpackedCabPath ($$$$$) 295*b1cdbd2cSJim Jagielski{ 296*b1cdbd2cSJim Jagielski my ($version, $is_current_version, $language, $package_format, $product) = @_; 297*b1cdbd2cSJim Jagielski 298*b1cdbd2cSJim Jagielski my $path = GetUnpackedPath($version, $is_current_version, $language, $package_format, $product); 299*b1cdbd2cSJim Jagielski return File::Spec->catfile($path, "unpacked"); 300*b1cdbd2cSJim Jagielski} 301*b1cdbd2cSJim Jagielski 302*b1cdbd2cSJim Jagielski 303*b1cdbd2cSJim Jagielski 304*b1cdbd2cSJim Jagielski 305*b1cdbd2cSJim Jagielski=head2 GetUnpackedPath($version, $is_current_version, $language, $package_format, $product) 306*b1cdbd2cSJim Jagielski 307*b1cdbd2cSJim Jagielski Internal function for creating paths to where archives are unpacked. 308*b1cdbd2cSJim Jagielski 309*b1cdbd2cSJim Jagielski=cut 310*b1cdbd2cSJim Jagielskisub GetUnpackedPath ($$$$$) 311*b1cdbd2cSJim Jagielski{ 312*b1cdbd2cSJim Jagielski my ($version, $is_current_version, $language, $package_format, $product) = @_; 313*b1cdbd2cSJim Jagielski 314*b1cdbd2cSJim Jagielski return File::Spec->catfile( 315*b1cdbd2cSJim Jagielski $ENV{'SRC_ROOT'}, 316*b1cdbd2cSJim Jagielski "instsetoo_native", 317*b1cdbd2cSJim Jagielski $ENV{'INPATH'}, 318*b1cdbd2cSJim Jagielski $product, 319*b1cdbd2cSJim Jagielski $package_format, 320*b1cdbd2cSJim Jagielski installer::patch::Version::ArrayToDirectoryName( 321*b1cdbd2cSJim Jagielski installer::patch::Version::StringToNumberArray($version)), 322*b1cdbd2cSJim Jagielski installer::languages::get_normalized_language($language)); 323*b1cdbd2cSJim Jagielski} 324*b1cdbd2cSJim Jagielski 325*b1cdbd2cSJim Jagielski 326*b1cdbd2cSJim Jagielski 327*b1cdbd2cSJim Jagielski 328*b1cdbd2cSJim Jagielskisub GetMsiFilename ($$) 329*b1cdbd2cSJim Jagielski{ 330*b1cdbd2cSJim Jagielski my ($path, $version) = @_; 331*b1cdbd2cSJim Jagielski 332*b1cdbd2cSJim Jagielski my $no_dot_version = installer::patch::Version::ArrayToNoDotName( 333*b1cdbd2cSJim Jagielski installer::patch::Version::StringToNumberArray( 334*b1cdbd2cSJim Jagielski $version)); 335*b1cdbd2cSJim Jagielski return File::Spec->catfile( 336*b1cdbd2cSJim Jagielski $path, 337*b1cdbd2cSJim Jagielski "openoffice" . $no_dot_version . ".msi"); 338*b1cdbd2cSJim Jagielski} 339*b1cdbd2cSJim Jagielski 340*b1cdbd2cSJim Jagielski 341*b1cdbd2cSJim Jagielski 342*b1cdbd2cSJim Jagielski 343*b1cdbd2cSJim Jagielskisub GetCabFilename ($$) 344*b1cdbd2cSJim Jagielski{ 345*b1cdbd2cSJim Jagielski my ($path, $version) = @_; 346*b1cdbd2cSJim Jagielski 347*b1cdbd2cSJim Jagielski return File::Spec->catfile( 348*b1cdbd2cSJim Jagielski $path, 349*b1cdbd2cSJim Jagielski "openoffice1.cab"); 350*b1cdbd2cSJim Jagielski} 351*b1cdbd2cSJim Jagielski 352*b1cdbd2cSJim Jagielski 353*b1cdbd2cSJim Jagielski 354*b1cdbd2cSJim Jagielski 355*b1cdbd2cSJim Jagielski=head2 Download($language, $release_data, $filename) 356*b1cdbd2cSJim Jagielski 357*b1cdbd2cSJim Jagielski Download an installation set to $filename. The URL for the 358*b1cdbd2cSJim Jagielski download is taken from $release_data, a snippet from the 359*b1cdbd2cSJim Jagielski instsetoo_native/data/releases.xml file. 360*b1cdbd2cSJim Jagielski 361*b1cdbd2cSJim Jagielski=cut 362*b1cdbd2cSJim Jagielskisub Download ($$$) 363*b1cdbd2cSJim Jagielski{ 364*b1cdbd2cSJim Jagielski my ($language, $release_data, $filename) = @_; 365*b1cdbd2cSJim Jagielski 366*b1cdbd2cSJim Jagielski my $url = $release_data->{'URL'}; 367*b1cdbd2cSJim Jagielski $release_data->{'URL'} =~ /^(.*)\/([^\/]+)$/; 368*b1cdbd2cSJim Jagielski my ($location, $basename) = ($1,$2); 369*b1cdbd2cSJim Jagielski 370*b1cdbd2cSJim Jagielski $installer::logger::Info->printf("downloading %s\n", $basename); 371*b1cdbd2cSJim Jagielski $installer::logger::Info->printf(" from '%s'\n", $location); 372*b1cdbd2cSJim Jagielski my $filesize = $release_data->{'file-size'}; 373*b1cdbd2cSJim Jagielski if (defined $filesize) 374*b1cdbd2cSJim Jagielski { 375*b1cdbd2cSJim Jagielski $installer::logger::Info->printf(" expected size is %d\n", $filesize); 376*b1cdbd2cSJim Jagielski } 377*b1cdbd2cSJim Jagielski else 378*b1cdbd2cSJim Jagielski { 379*b1cdbd2cSJim Jagielski $installer::logger::Info->printf(" file size is not yet known\n"); 380*b1cdbd2cSJim Jagielski } 381*b1cdbd2cSJim Jagielski my $temporary_filename = $filename . ".part"; 382*b1cdbd2cSJim Jagielski my $resume_size = 0; 383*b1cdbd2cSJim Jagielski 384*b1cdbd2cSJim Jagielski # Prepare checksum. 385*b1cdbd2cSJim Jagielski my $checksum = undef; 386*b1cdbd2cSJim Jagielski my $checksum_type = $release_data->{'checksum-type'}; 387*b1cdbd2cSJim Jagielski my $checksum_value = $release_data->{'checksum-value'}; 388*b1cdbd2cSJim Jagielski my $digest = undef; 389*b1cdbd2cSJim Jagielski if ( ! defined $checksum_value) 390*b1cdbd2cSJim Jagielski { 391*b1cdbd2cSJim Jagielski # No checksum available. Skip test. 392*b1cdbd2cSJim Jagielski } 393*b1cdbd2cSJim Jagielski elsif ($checksum_type eq "sha256") 394*b1cdbd2cSJim Jagielski { 395*b1cdbd2cSJim Jagielski $digest = Digest->new("SHA-256"); 396*b1cdbd2cSJim Jagielski } 397*b1cdbd2cSJim Jagielski elsif ($checksum_type eq "md5") 398*b1cdbd2cSJim Jagielski { 399*b1cdbd2cSJim Jagielski $digest = Digest->new("md5"); 400*b1cdbd2cSJim Jagielski } 401*b1cdbd2cSJim Jagielski else 402*b1cdbd2cSJim Jagielski { 403*b1cdbd2cSJim Jagielski installer::logger::PrintError( 404*b1cdbd2cSJim Jagielski "checksum type %s is not supported. Supported checksum types are: sha256,md5\n", 405*b1cdbd2cSJim Jagielski $checksum_type); 406*b1cdbd2cSJim Jagielski return 0; 407*b1cdbd2cSJim Jagielski } 408*b1cdbd2cSJim Jagielski 409*b1cdbd2cSJim Jagielski # Download the extension. 410*b1cdbd2cSJim Jagielski open my $out, ">$temporary_filename"; 411*b1cdbd2cSJim Jagielski binmode($out); 412*b1cdbd2cSJim Jagielski 413*b1cdbd2cSJim Jagielski my $mode = $|; 414*b1cdbd2cSJim Jagielski my $handle = select STDOUT; 415*b1cdbd2cSJim Jagielski $| = 1; 416*b1cdbd2cSJim Jagielski select $handle; 417*b1cdbd2cSJim Jagielski 418*b1cdbd2cSJim Jagielski my $agent = LWP::UserAgent->new(); 419*b1cdbd2cSJim Jagielski $agent->timeout(120); 420*b1cdbd2cSJim Jagielski $agent->show_progress(0); 421*b1cdbd2cSJim Jagielski my $last_was_redirect = 0; 422*b1cdbd2cSJim Jagielski my $bytes_read = 0; 423*b1cdbd2cSJim Jagielski $agent->add_handler('response_redirect' 424*b1cdbd2cSJim Jagielski => sub{ 425*b1cdbd2cSJim Jagielski $last_was_redirect = 1; 426*b1cdbd2cSJim Jagielski return; 427*b1cdbd2cSJim Jagielski }); 428*b1cdbd2cSJim Jagielski $agent->add_handler('response_data' 429*b1cdbd2cSJim Jagielski => sub{ 430*b1cdbd2cSJim Jagielski if ($last_was_redirect) 431*b1cdbd2cSJim Jagielski { 432*b1cdbd2cSJim Jagielski $last_was_redirect = 0; 433*b1cdbd2cSJim Jagielski # Throw away the data we got so far. 434*b1cdbd2cSJim Jagielski $digest->reset() if defined $digest; 435*b1cdbd2cSJim Jagielski close $out; 436*b1cdbd2cSJim Jagielski open $out, ">$temporary_filename"; 437*b1cdbd2cSJim Jagielski binmode($out); 438*b1cdbd2cSJim Jagielski } 439*b1cdbd2cSJim Jagielski my($response,$agent,$h,$data)=@_; 440*b1cdbd2cSJim Jagielski print $out $data; 441*b1cdbd2cSJim Jagielski $digest->add($data) if defined $digest; 442*b1cdbd2cSJim Jagielski $bytes_read += length($data); 443*b1cdbd2cSJim Jagielski if (defined $filesize) 444*b1cdbd2cSJim Jagielski { 445*b1cdbd2cSJim Jagielski printf("read %*d / %d %d%% \r", 446*b1cdbd2cSJim Jagielski length($filesize), 447*b1cdbd2cSJim Jagielski $bytes_read, 448*b1cdbd2cSJim Jagielski $filesize, 449*b1cdbd2cSJim Jagielski $bytes_read*100/$filesize); 450*b1cdbd2cSJim Jagielski } 451*b1cdbd2cSJim Jagielski else 452*b1cdbd2cSJim Jagielski { 453*b1cdbd2cSJim Jagielski printf("read %6.2f MB\r", $bytes_read/(1024.0*1024.0)); 454*b1cdbd2cSJim Jagielski } 455*b1cdbd2cSJim Jagielski }); 456*b1cdbd2cSJim Jagielski my $response; 457*b1cdbd2cSJim Jagielski if ($resume_size > 0) 458*b1cdbd2cSJim Jagielski { 459*b1cdbd2cSJim Jagielski $response = $agent->get($url, 'Range' => "bytes=$resume_size-"); 460*b1cdbd2cSJim Jagielski } 461*b1cdbd2cSJim Jagielski else 462*b1cdbd2cSJim Jagielski { 463*b1cdbd2cSJim Jagielski $response = $agent->get($url); 464*b1cdbd2cSJim Jagielski } 465*b1cdbd2cSJim Jagielski close $out; 466*b1cdbd2cSJim Jagielski 467*b1cdbd2cSJim Jagielski $handle = select STDOUT; 468*b1cdbd2cSJim Jagielski $| = $mode; 469*b1cdbd2cSJim Jagielski select $handle; 470*b1cdbd2cSJim Jagielski 471*b1cdbd2cSJim Jagielski $installer::logger::Info->print(" \r"); 472*b1cdbd2cSJim Jagielski 473*b1cdbd2cSJim Jagielski if ($response->is_success()) 474*b1cdbd2cSJim Jagielski { 475*b1cdbd2cSJim Jagielski if ( ! defined $digest 476*b1cdbd2cSJim Jagielski || $digest->hexdigest() eq $checksum_value) 477*b1cdbd2cSJim Jagielski { 478*b1cdbd2cSJim Jagielski $installer::logger::Info->print("download was successfull\n"); 479*b1cdbd2cSJim Jagielski if ( ! rename($temporary_filename, $filename)) 480*b1cdbd2cSJim Jagielski { 481*b1cdbd2cSJim Jagielski installer::logger::PrintError("can not rename '%s' to '%s'\n", $temporary_filename, $filename); 482*b1cdbd2cSJim Jagielski return 0; 483*b1cdbd2cSJim Jagielski } 484*b1cdbd2cSJim Jagielski else 485*b1cdbd2cSJim Jagielski { 486*b1cdbd2cSJim Jagielski return 1; 487*b1cdbd2cSJim Jagielski } 488*b1cdbd2cSJim Jagielski } 489*b1cdbd2cSJim Jagielski else 490*b1cdbd2cSJim Jagielski { 491*b1cdbd2cSJim Jagielski installer::logger::PrintError("%s checksum is wrong\n", $checksum_type); 492*b1cdbd2cSJim Jagielski return 0; 493*b1cdbd2cSJim Jagielski } 494*b1cdbd2cSJim Jagielski } 495*b1cdbd2cSJim Jagielski else 496*b1cdbd2cSJim Jagielski { 497*b1cdbd2cSJim Jagielski installer::logger::PrintError("there was a download error\n"); 498*b1cdbd2cSJim Jagielski return 0; 499*b1cdbd2cSJim Jagielski } 500*b1cdbd2cSJim Jagielski} 501*b1cdbd2cSJim Jagielski 502*b1cdbd2cSJim Jagielski 503*b1cdbd2cSJim Jagielski 504*b1cdbd2cSJim Jagielski 505*b1cdbd2cSJim Jagielski=head2 ProvideDownloadSet ($version, $language, $package_format) 506*b1cdbd2cSJim Jagielski 507*b1cdbd2cSJim Jagielski Download an installation set when it is not yet present to 508*b1cdbd2cSJim Jagielski $ENV{'TARFILE_LOCATION'}. Verify the downloaded file with the 509*b1cdbd2cSJim Jagielski checksum that is extracted from the 510*b1cdbd2cSJim Jagielski instsetoo_native/data/releases.xml file. 511*b1cdbd2cSJim Jagielski 512*b1cdbd2cSJim Jagielski=cut 513*b1cdbd2cSJim Jagielskisub ProvideDownloadSet ($$$) 514*b1cdbd2cSJim Jagielski{ 515*b1cdbd2cSJim Jagielski my ($version, $language, $package_format) = @_; 516*b1cdbd2cSJim Jagielski 517*b1cdbd2cSJim Jagielski my $release_item = installer::patch::ReleasesList::Instance()->{$version}->{$package_format}->{$language}; 518*b1cdbd2cSJim Jagielski return undef unless defined $release_item; 519*b1cdbd2cSJim Jagielski 520*b1cdbd2cSJim Jagielski # Get basename of installation set from URL. 521*b1cdbd2cSJim Jagielski $release_item->{'URL'} =~ /^(.*)\/([^\/]+)$/; 522*b1cdbd2cSJim Jagielski my ($location, $basename) = ($1,$2); 523*b1cdbd2cSJim Jagielski 524*b1cdbd2cSJim Jagielski # Is the installation set already present in ext_sources/ ? 525*b1cdbd2cSJim Jagielski my $need_download = 0; 526*b1cdbd2cSJim Jagielski my $ext_sources_filename = File::Spec->catfile( 527*b1cdbd2cSJim Jagielski $ENV{'TARFILE_LOCATION'}, 528*b1cdbd2cSJim Jagielski $basename); 529*b1cdbd2cSJim Jagielski if ( ! -f $ext_sources_filename) 530*b1cdbd2cSJim Jagielski { 531*b1cdbd2cSJim Jagielski $installer::logger::Info->printf("download set is not in ext_sources/ (%s)\n", $ext_sources_filename); 532*b1cdbd2cSJim Jagielski $need_download = 1; 533*b1cdbd2cSJim Jagielski } 534*b1cdbd2cSJim Jagielski else 535*b1cdbd2cSJim Jagielski { 536*b1cdbd2cSJim Jagielski $installer::logger::Info->printf("download set exists at '%s'\n", $ext_sources_filename); 537*b1cdbd2cSJim Jagielski if (defined $release_item->{'checksum-value'} 538*b1cdbd2cSJim Jagielski && $release_item->{'checksum-type'} eq 'sha256') 539*b1cdbd2cSJim Jagielski { 540*b1cdbd2cSJim Jagielski $installer::logger::Info->printf("checking SHA256 checksum\n"); 541*b1cdbd2cSJim Jagielski my $digest = Digest->new("SHA-256"); 542*b1cdbd2cSJim Jagielski open my $in, "<", $ext_sources_filename; 543*b1cdbd2cSJim Jagielski $digest->addfile($in); 544*b1cdbd2cSJim Jagielski close $in; 545*b1cdbd2cSJim Jagielski if ($digest->hexdigest() ne $release_item->{'checksum-value'}) 546*b1cdbd2cSJim Jagielski { 547*b1cdbd2cSJim Jagielski $installer::logger::Info->printf(" mismatch\n", $ext_sources_filename); 548*b1cdbd2cSJim Jagielski $need_download = 1; 549*b1cdbd2cSJim Jagielski } 550*b1cdbd2cSJim Jagielski else 551*b1cdbd2cSJim Jagielski { 552*b1cdbd2cSJim Jagielski $installer::logger::Info->printf(" match\n"); 553*b1cdbd2cSJim Jagielski } 554*b1cdbd2cSJim Jagielski } 555*b1cdbd2cSJim Jagielski } 556*b1cdbd2cSJim Jagielski 557*b1cdbd2cSJim Jagielski if ($need_download) 558*b1cdbd2cSJim Jagielski { 559*b1cdbd2cSJim Jagielski if ( ! installer::patch::InstallationSet::Download( 560*b1cdbd2cSJim Jagielski $language, 561*b1cdbd2cSJim Jagielski $release_item, 562*b1cdbd2cSJim Jagielski $ext_sources_filename)) 563*b1cdbd2cSJim Jagielski { 564*b1cdbd2cSJim Jagielski return 0; 565*b1cdbd2cSJim Jagielski } 566*b1cdbd2cSJim Jagielski if ( ! -f $ext_sources_filename) 567*b1cdbd2cSJim Jagielski { 568*b1cdbd2cSJim Jagielski $installer::logger::Info->printf("download set could not be downloaded\n"); 569*b1cdbd2cSJim Jagielski return 0; 570*b1cdbd2cSJim Jagielski } 571*b1cdbd2cSJim Jagielski } 572*b1cdbd2cSJim Jagielski 573*b1cdbd2cSJim Jagielski return $ext_sources_filename; 574*b1cdbd2cSJim Jagielski} 575*b1cdbd2cSJim Jagielski 576*b1cdbd2cSJim Jagielski 577*b1cdbd2cSJim Jagielski 578*b1cdbd2cSJim Jagielski 579*b1cdbd2cSJim Jagielskisub ProvideUnpackedExe ($$$$$) 580*b1cdbd2cSJim Jagielski{ 581*b1cdbd2cSJim Jagielski my ($version, $is_current_version, $language, $package_format, $product_name) = @_; 582*b1cdbd2cSJim Jagielski 583*b1cdbd2cSJim Jagielski # Check if the exe has already been unpacked. 584*b1cdbd2cSJim Jagielski my $unpacked_exe_path = installer::patch::InstallationSet::GetUnpackedExePath( 585*b1cdbd2cSJim Jagielski $version, 586*b1cdbd2cSJim Jagielski $is_current_version, 587*b1cdbd2cSJim Jagielski $language, 588*b1cdbd2cSJim Jagielski $package_format, 589*b1cdbd2cSJim Jagielski $product_name); 590*b1cdbd2cSJim Jagielski my $unpacked_exe_flag_filename = File::Spec->catfile($unpacked_exe_path, "__exe_is_unpacked"); 591*b1cdbd2cSJim Jagielski my $exe_is_unpacked = -f $unpacked_exe_flag_filename; 592*b1cdbd2cSJim Jagielski 593*b1cdbd2cSJim Jagielski if ($exe_is_unpacked) 594*b1cdbd2cSJim Jagielski { 595*b1cdbd2cSJim Jagielski # Yes, exe has already been unpacked. There is nothing more to do. 596*b1cdbd2cSJim Jagielski $installer::logger::Info->printf("downloadable installation set has already been unpacked to\n"); 597*b1cdbd2cSJim Jagielski $installer::logger::Info->printf(" %s\n", $unpacked_exe_path); 598*b1cdbd2cSJim Jagielski return 1; 599*b1cdbd2cSJim Jagielski } 600*b1cdbd2cSJim Jagielski elsif ($is_current_version) 601*b1cdbd2cSJim Jagielski { 602*b1cdbd2cSJim Jagielski # For the current version the exe is created from the unpacked 603*b1cdbd2cSJim Jagielski # content and both are expected to be already present. 604*b1cdbd2cSJim Jagielski 605*b1cdbd2cSJim Jagielski # In order to have the .cab and its unpacked content in one 606*b1cdbd2cSJim Jagielski # directory and don't interfere with the creation of regular 607*b1cdbd2cSJim Jagielski # installation sets, we copy the unpacked .exe into a separate 608*b1cdbd2cSJim Jagielski # directory. 609*b1cdbd2cSJim Jagielski 610*b1cdbd2cSJim Jagielski my $original_path = File::Spec->catfile( 611*b1cdbd2cSJim Jagielski $ENV{'SRC_ROOT'}, 612*b1cdbd2cSJim Jagielski "instsetoo_native", 613*b1cdbd2cSJim Jagielski $ENV{'INPATH'}, 614*b1cdbd2cSJim Jagielski $product_name, 615*b1cdbd2cSJim Jagielski $package_format, 616*b1cdbd2cSJim Jagielski "install", 617*b1cdbd2cSJim Jagielski $language); 618*b1cdbd2cSJim Jagielski $installer::logger::Info->printf("creating a copy\n"); 619*b1cdbd2cSJim Jagielski $installer::logger::Info->printf(" of %s\n", $original_path); 620*b1cdbd2cSJim Jagielski $installer::logger::Info->printf(" at %s\n", $unpacked_exe_path); 621*b1cdbd2cSJim Jagielski File::Path::make_path($unpacked_exe_path) unless -d $unpacked_exe_path; 622*b1cdbd2cSJim Jagielski my ($file_count,$directory_count) = CopyRecursive($original_path, $unpacked_exe_path); 623*b1cdbd2cSJim Jagielski return 0 if ( ! defined $file_count); 624*b1cdbd2cSJim Jagielski $installer::logger::Info->printf(" copied %d files in %d directories\n", 625*b1cdbd2cSJim Jagielski $file_count, 626*b1cdbd2cSJim Jagielski $directory_count); 627*b1cdbd2cSJim Jagielski 628*b1cdbd2cSJim Jagielski installer::patch::Tools::touch($unpacked_exe_flag_filename); 629*b1cdbd2cSJim Jagielski 630*b1cdbd2cSJim Jagielski return 1; 631*b1cdbd2cSJim Jagielski } 632*b1cdbd2cSJim Jagielski else 633*b1cdbd2cSJim Jagielski { 634*b1cdbd2cSJim Jagielski # No, we have to unpack the exe. 635*b1cdbd2cSJim Jagielski 636*b1cdbd2cSJim Jagielski # Provide the exe. 637*b1cdbd2cSJim Jagielski my $filename = installer::patch::InstallationSet::ProvideDownloadSet( 638*b1cdbd2cSJim Jagielski $version, 639*b1cdbd2cSJim Jagielski $language, 640*b1cdbd2cSJim Jagielski $package_format); 641*b1cdbd2cSJim Jagielski 642*b1cdbd2cSJim Jagielski # Unpack it. 643*b1cdbd2cSJim Jagielski if (defined $filename) 644*b1cdbd2cSJim Jagielski { 645*b1cdbd2cSJim Jagielski if (installer::patch::InstallationSet::UnpackExe($filename, $unpacked_exe_path)) 646*b1cdbd2cSJim Jagielski { 647*b1cdbd2cSJim Jagielski $installer::logger::Info->printf("downloadable installation set has been unpacked to\n"); 648*b1cdbd2cSJim Jagielski $installer::logger::Info->printf(" %s\n", $unpacked_exe_path); 649*b1cdbd2cSJim Jagielski 650*b1cdbd2cSJim Jagielski installer::patch::Tools::touch($unpacked_exe_flag_filename); 651*b1cdbd2cSJim Jagielski 652*b1cdbd2cSJim Jagielski return 1; 653*b1cdbd2cSJim Jagielski } 654*b1cdbd2cSJim Jagielski } 655*b1cdbd2cSJim Jagielski else 656*b1cdbd2cSJim Jagielski { 657*b1cdbd2cSJim Jagielski installer::logger::PrintError("could not provide .exe installation set at '%s'\n", $filename); 658*b1cdbd2cSJim Jagielski } 659*b1cdbd2cSJim Jagielski } 660*b1cdbd2cSJim Jagielski 661*b1cdbd2cSJim Jagielski return 0; 662*b1cdbd2cSJim Jagielski} 663*b1cdbd2cSJim Jagielski 664*b1cdbd2cSJim Jagielski 665*b1cdbd2cSJim Jagielski 666*b1cdbd2cSJim Jagielski 667*b1cdbd2cSJim Jagielskisub CopyRecursive ($$) 668*b1cdbd2cSJim Jagielski{ 669*b1cdbd2cSJim Jagielski my ($source_path, $destination_path) = @_; 670*b1cdbd2cSJim Jagielski 671*b1cdbd2cSJim Jagielski return (undef,undef) unless -d $source_path; 672*b1cdbd2cSJim Jagielski 673*b1cdbd2cSJim Jagielski my @todo = ([$source_path, $destination_path]); 674*b1cdbd2cSJim Jagielski my $file_count = 0; 675*b1cdbd2cSJim Jagielski my $directory_count = 0; 676*b1cdbd2cSJim Jagielski while (scalar @todo > 0) 677*b1cdbd2cSJim Jagielski { 678*b1cdbd2cSJim Jagielski my ($source,$destination) = @{shift @todo}; 679*b1cdbd2cSJim Jagielski 680*b1cdbd2cSJim Jagielski next if ! -d $source; 681*b1cdbd2cSJim Jagielski File::Path::make_path($destination); 682*b1cdbd2cSJim Jagielski ++$directory_count; 683*b1cdbd2cSJim Jagielski 684*b1cdbd2cSJim Jagielski # Read list of files in the current source directory. 685*b1cdbd2cSJim Jagielski opendir( my $dir, $source); 686*b1cdbd2cSJim Jagielski my @files = readdir $dir; 687*b1cdbd2cSJim Jagielski closedir $dir; 688*b1cdbd2cSJim Jagielski 689*b1cdbd2cSJim Jagielski # Copy all files and push all directories to @todo. 690*b1cdbd2cSJim Jagielski foreach my $file (@files) 691*b1cdbd2cSJim Jagielski { 692*b1cdbd2cSJim Jagielski next if $file =~ /^\.+$/; 693*b1cdbd2cSJim Jagielski 694*b1cdbd2cSJim Jagielski my $source_file = File::Spec->catfile($source, $file); 695*b1cdbd2cSJim Jagielski my $destination_file = File::Spec->catfile($destination, $file); 696*b1cdbd2cSJim Jagielski if ( -f $source_file) 697*b1cdbd2cSJim Jagielski { 698*b1cdbd2cSJim Jagielski File::Copy::copy($source_file, $destination_file); 699*b1cdbd2cSJim Jagielski ++$file_count; 700*b1cdbd2cSJim Jagielski } 701*b1cdbd2cSJim Jagielski elsif ( -d $source_file) 702*b1cdbd2cSJim Jagielski { 703*b1cdbd2cSJim Jagielski push @todo, [$source_file, $destination_file]; 704*b1cdbd2cSJim Jagielski } 705*b1cdbd2cSJim Jagielski } 706*b1cdbd2cSJim Jagielski } 707*b1cdbd2cSJim Jagielski 708*b1cdbd2cSJim Jagielski return ($file_count, $directory_count); 709*b1cdbd2cSJim Jagielski} 710*b1cdbd2cSJim Jagielski 711*b1cdbd2cSJim Jagielski 712*b1cdbd2cSJim Jagielski 713*b1cdbd2cSJim Jagielski 714*b1cdbd2cSJim Jagielskisub CheckLocalCopy ($$$$) 715*b1cdbd2cSJim Jagielski{ 716*b1cdbd2cSJim Jagielski my ($version, $language, $package_format, $product_name) = @_; 717*b1cdbd2cSJim Jagielski 718*b1cdbd2cSJim Jagielski # Compare creation times of the original .msi and its copy. 719*b1cdbd2cSJim Jagielski 720*b1cdbd2cSJim Jagielski my $original_path = File::Spec->catfile( 721*b1cdbd2cSJim Jagielski $ENV{'SRC_ROOT'}, 722*b1cdbd2cSJim Jagielski "instsetoo_native", 723*b1cdbd2cSJim Jagielski $ENV{'INPATH'}, 724*b1cdbd2cSJim Jagielski $product_name, 725*b1cdbd2cSJim Jagielski $package_format, 726*b1cdbd2cSJim Jagielski "install", 727*b1cdbd2cSJim Jagielski $language); 728*b1cdbd2cSJim Jagielski 729*b1cdbd2cSJim Jagielski my $copy_path = installer::patch::InstallationSet::GetUnpackedExePath( 730*b1cdbd2cSJim Jagielski $version, 731*b1cdbd2cSJim Jagielski 1, 732*b1cdbd2cSJim Jagielski $language, 733*b1cdbd2cSJim Jagielski $package_format, 734*b1cdbd2cSJim Jagielski $product_name); 735*b1cdbd2cSJim Jagielski 736*b1cdbd2cSJim Jagielski my $msi_basename = "openoffice" 737*b1cdbd2cSJim Jagielski . installer::patch::Version::ArrayToNoDotName( 738*b1cdbd2cSJim Jagielski installer::patch::Version::StringToNumberArray($version)) 739*b1cdbd2cSJim Jagielski . ".msi"; 740*b1cdbd2cSJim Jagielski 741*b1cdbd2cSJim Jagielski my $original_msi_filename = File::Spec->catfile($original_path, $msi_basename); 742*b1cdbd2cSJim Jagielski my $copied_msi_filename = File::Spec->catfile($copy_path, $msi_basename); 743*b1cdbd2cSJim Jagielski 744*b1cdbd2cSJim Jagielski my @original_msi_stats = stat($original_msi_filename); 745*b1cdbd2cSJim Jagielski my @copied_msi_stats = stat($copied_msi_filename); 746*b1cdbd2cSJim Jagielski my $original_msi_mtime = $original_msi_stats[9]; 747*b1cdbd2cSJim Jagielski my $copied_msi_mtime = $copied_msi_stats[9]; 748*b1cdbd2cSJim Jagielski 749*b1cdbd2cSJim Jagielski if (defined $original_msi_mtime 750*b1cdbd2cSJim Jagielski && defined $copied_msi_mtime 751*b1cdbd2cSJim Jagielski && $original_msi_mtime > $copied_msi_mtime) 752*b1cdbd2cSJim Jagielski { 753*b1cdbd2cSJim Jagielski # The installation set is newer than its copy. 754*b1cdbd2cSJim Jagielski # Remove the copy. 755*b1cdbd2cSJim Jagielski $installer::logger::Info->printf( 756*b1cdbd2cSJim Jagielski "removing copy of installation set (version %s) because it is out of date\n", 757*b1cdbd2cSJim Jagielski $version); 758*b1cdbd2cSJim Jagielski File::Path::remove_tree($copy_path); 759*b1cdbd2cSJim Jagielski } 760*b1cdbd2cSJim Jagielski} 761*b1cdbd2cSJim Jagielski 762*b1cdbd2cSJim Jagielski 763*b1cdbd2cSJim Jagielski 764*b1cdbd2cSJim Jagielski 765*b1cdbd2cSJim Jagielski=head2 ProvideUnpackedCab 766*b1cdbd2cSJim Jagielski 767*b1cdbd2cSJim Jagielski 1a. Make sure that a downloadable installation set is present. 768*b1cdbd2cSJim Jagielski 1b. or that a freshly built installation set (packed and unpacked is present) 769*b1cdbd2cSJim Jagielski 2. Unpack the downloadable installation set 770*b1cdbd2cSJim Jagielski 3. Unpack the .cab file. 771*b1cdbd2cSJim Jagielski 772*b1cdbd2cSJim Jagielski The 'Provide' in the function name means that any step that has 773*b1cdbd2cSJim Jagielski already been made is not made again. 774*b1cdbd2cSJim Jagielski 775*b1cdbd2cSJim Jagielski=cut 776*b1cdbd2cSJim Jagielskisub ProvideUnpackedCab ($$$$$) 777*b1cdbd2cSJim Jagielski{ 778*b1cdbd2cSJim Jagielski my ($version, $is_current_version, $language, $package_format, $product_name) = @_; 779*b1cdbd2cSJim Jagielski 780*b1cdbd2cSJim Jagielski if ($is_current_version) 781*b1cdbd2cSJim Jagielski { 782*b1cdbd2cSJim Jagielski # For creating patches we maintain a copy of the unpacked .exe. Make sure that that is updated when 783*b1cdbd2cSJim Jagielski # a new installation set has been built. 784*b1cdbd2cSJim Jagielski CheckLocalCopy($version, $language, $package_format, $product_name); 785*b1cdbd2cSJim Jagielski } 786*b1cdbd2cSJim Jagielski 787*b1cdbd2cSJim Jagielski # Check if the cab file has already been unpacked. 788*b1cdbd2cSJim Jagielski my $unpacked_cab_path = installer::patch::InstallationSet::GetUnpackedCabPath( 789*b1cdbd2cSJim Jagielski $version, 790*b1cdbd2cSJim Jagielski $is_current_version, 791*b1cdbd2cSJim Jagielski $language, 792*b1cdbd2cSJim Jagielski $package_format, 793*b1cdbd2cSJim Jagielski $product_name); 794*b1cdbd2cSJim Jagielski my $unpacked_cab_flag_filename = File::Spec->catfile($unpacked_cab_path, "__cab_is_unpacked"); 795*b1cdbd2cSJim Jagielski my $cab_is_unpacked = -f $unpacked_cab_flag_filename; 796*b1cdbd2cSJim Jagielski 797*b1cdbd2cSJim Jagielski if ($cab_is_unpacked) 798*b1cdbd2cSJim Jagielski { 799*b1cdbd2cSJim Jagielski # Yes. Cab was already unpacked. There is nothing more to do. 800*b1cdbd2cSJim Jagielski $installer::logger::Info->printf("cab has already been unpacked to\n"); 801*b1cdbd2cSJim Jagielski $installer::logger::Info->printf(" %s\n", $unpacked_cab_path); 802*b1cdbd2cSJim Jagielski 803*b1cdbd2cSJim Jagielski return 1; 804*b1cdbd2cSJim Jagielski } 805*b1cdbd2cSJim Jagielski else 806*b1cdbd2cSJim Jagielski { 807*b1cdbd2cSJim Jagielski # Make sure that the exe is unpacked and the cab file exists. 808*b1cdbd2cSJim Jagielski ProvideUnpackedExe($version, $is_current_version, $language, $package_format, $product_name); 809*b1cdbd2cSJim Jagielski 810*b1cdbd2cSJim Jagielski # Unpack the cab file. 811*b1cdbd2cSJim Jagielski my $unpacked_exe_path = installer::patch::InstallationSet::GetUnpackedExePath( 812*b1cdbd2cSJim Jagielski $version, 813*b1cdbd2cSJim Jagielski $is_current_version, 814*b1cdbd2cSJim Jagielski $language, 815*b1cdbd2cSJim Jagielski $package_format, 816*b1cdbd2cSJim Jagielski $product_name); 817*b1cdbd2cSJim Jagielski my $msi = new installer::patch::Msi( 818*b1cdbd2cSJim Jagielski installer::patch::InstallationSet::GetMsiFilename($unpacked_exe_path, $version), 819*b1cdbd2cSJim Jagielski $version, 820*b1cdbd2cSJim Jagielski $is_current_version, 821*b1cdbd2cSJim Jagielski $language, 822*b1cdbd2cSJim Jagielski $product_name); 823*b1cdbd2cSJim Jagielski 824*b1cdbd2cSJim Jagielski my $cab_filename = installer::patch::InstallationSet::GetCabFilename( 825*b1cdbd2cSJim Jagielski $unpacked_exe_path, 826*b1cdbd2cSJim Jagielski $version); 827*b1cdbd2cSJim Jagielski if ( ! -f $cab_filename) 828*b1cdbd2cSJim Jagielski { 829*b1cdbd2cSJim Jagielski # Cab file does not exist. 830*b1cdbd2cSJim Jagielski installer::logger::PrintError( 831*b1cdbd2cSJim Jagielski "could not find .cab file at '%s'. Extraction of .exe seems to have failed.\n", 832*b1cdbd2cSJim Jagielski $cab_filename); 833*b1cdbd2cSJim Jagielski return 0; 834*b1cdbd2cSJim Jagielski } 835*b1cdbd2cSJim Jagielski 836*b1cdbd2cSJim Jagielski if (installer::patch::InstallationSet::UnpackCab( 837*b1cdbd2cSJim Jagielski $cab_filename, 838*b1cdbd2cSJim Jagielski $msi, 839*b1cdbd2cSJim Jagielski $unpacked_cab_path)) 840*b1cdbd2cSJim Jagielski { 841*b1cdbd2cSJim Jagielski $installer::logger::Info->printf("unpacked cab file '%s'\n", $cab_filename); 842*b1cdbd2cSJim Jagielski $installer::logger::Info->printf(" to '%s'\n", $unpacked_cab_path); 843*b1cdbd2cSJim Jagielski 844*b1cdbd2cSJim Jagielski installer::patch::Tools::touch($unpacked_cab_flag_filename); 845*b1cdbd2cSJim Jagielski 846*b1cdbd2cSJim Jagielski return 1; 847*b1cdbd2cSJim Jagielski } 848*b1cdbd2cSJim Jagielski else 849*b1cdbd2cSJim Jagielski { 850*b1cdbd2cSJim Jagielski return 0; 851*b1cdbd2cSJim Jagielski } 852*b1cdbd2cSJim Jagielski } 853*b1cdbd2cSJim Jagielski} 854*b1cdbd2cSJim Jagielski1; 855