1 #!/usr/bin/perl -w 2 # Copyright (C) 2010 Google Inc. All rights reserved. 3 # 4 # Redistribution and use in source and binary forms, with or without 5 # modification, are permitted provided that the following conditions 6 # are met: 7 # 8 # 1. Redistributions of source code must retain the above copyright 9 # notice, this list of conditions and the following disclaimer. 10 # 2. Redistributions in binary form must reproduce the above copyright 11 # notice, this list of conditions and the following disclaimer in the 12 # documentation and/or other materials provided with the distribution. 13 # 3. Neither the name of Apple Inc. ("Apple") nor the names of 14 # its contributors may be used to endorse or promote products derived 15 # from this software without specific prior written permission. 16 # 17 # THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 18 # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 # DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28 use strict; 29 30 use File::Basename; 31 use File::Spec; 32 use File::Temp qw(tempdir); 33 use FindBin; 34 use Getopt::Long; 35 36 use lib $FindBin::Bin; 37 use webkitdirs; 38 use VCSUtils; 39 40 my $macPythonURL = "http://www.python.org/ftp/python/2.6.5/python-2.6.5-macosx10.3-2010-03-24.dmg"; 41 my $macPythonMD5 = "84489bba813fdbb6041b69d4310a86da"; 42 my $macPythonInstallerName = "Python.mpkg"; 43 44 # We could use a consistent download location, like the source or build directory. 45 my $tempDirectory = File::Temp::tempdir("WebKitPythonXXXX", TMPDIR => 1, CLEANUP => 1); 46 my $downloadDirectory = $tempDirectory; 47 my $mountPoint = File::Spec->join($tempDirectory, "mount"); 48 49 sub checkPythonVersion() 50 { 51 # Will exit 0 if Python is 2.5 or greater, non-zero otherwise. 52 `python -c "import sys;sys.exit(sys.version_info[:2] < (2,5))"`; 53 return exitStatus($?) == 0; 54 } 55 56 sub downloadFileToPath($$) 57 { 58 my ($remoteURL, $localPath) = @_; 59 print "Downloading $remoteURL to $localPath\n"; 60 my $exitCode = system("curl", "-o", $localPath, $remoteURL); 61 return exitStatus($exitCode) == 0; 62 } 63 64 sub checkMD5($$) 65 { 66 my ($path, $expectedMD5) = @_; 67 my $md5Output = `md5 -q "$path"`; 68 chomp($md5Output); 69 my $isValid = $md5Output eq $expectedMD5; 70 print "'$md5Output' does not match expected: '$expectedMD5'\n" unless $isValid; 71 return $isValid; 72 } 73 74 sub mountDMG($$) 75 { 76 my ($dmgPath, $mountPoint) = @_; 77 print "Mounting $dmgPath at $mountPoint\n"; 78 return system("hdiutil", "attach", "-mountpoint", $mountPoint, "-nobrowse", $dmgPath) == 0; 79 } 80 81 sub unmountDMG($) 82 { 83 my ($mountPoint) = @_; 84 print "Unmounting disk image from $mountPoint\n"; 85 my $exitCode = system("hdiutil", "detach", $mountPoint); 86 return exitStatus($exitCode) == 0; 87 } 88 89 sub runInstaller($) 90 { 91 my ($installerPackage) = @_; 92 print "sudo will now ask for your password to run the Python installer.\n"; 93 print "The installer will install Python in /Library/Frameworks/Python.framework\n"; 94 print "and add symlinks from /usr/local/bin.\n"; 95 return system("sudo", "installer", "-verbose", "-pkg", $installerPackage, "-target", "/") == 0; 96 } 97 98 sub downloadAndMountMacPythonDMG($$) 99 { 100 my ($pythonURL, $pythonMD5) = @_; 101 my $localFilename = basename($pythonURL); 102 my $localPath = File::Spec->join($downloadDirectory, $localFilename); 103 104 downloadFileToPath($pythonURL, $localPath) or die "Failed to download $pythonURL"; 105 checkMD5($localPath, $pythonMD5) or die "MD5 check failed on $localPath"; 106 return mountDMG($localPath, $mountPoint); 107 } 108 109 sub installMacPython() 110 { 111 downloadAndMountMacPythonDMG($macPythonURL, $macPythonMD5) or die "Failed to download and mount disk image."; 112 print "Mounted python install image at: $mountPoint\n"; 113 my $installerPackage = File::Spec->join($mountPoint, $macPythonInstallerName); 114 my $installSuccess = runInstaller($installerPackage); 115 unmountDMG($mountPoint) or die "Failed to unmount disk image from $mountPoint"; 116 return $installSuccess; 117 } 118 119 sub main() 120 { 121 my $checkOnly = 0; 122 my $showHelp = 0; 123 my $getOptionsResult = GetOptions( 124 'check-only!' => \$checkOnly, 125 'help|h' => \$showHelp, 126 ); 127 if (!$getOptionsResult || $showHelp) { 128 print STDERR <<HELP; 129 Usage: $0 [options] 130 --check-only Check python version only. 131 -h|--help Show this help message. 132 HELP 133 return 1; 134 } 135 # Congrats, your Python is fine. 136 return 0 if checkPythonVersion(); 137 138 return 1 if $checkOnly; 139 140 if (!isTiger()) { 141 print "Your Python version is insufficient to run WebKit's Python code. Please update.\n"; 142 print "See http://trac.webkit.org/wiki/PythonGuidelines for more info.\n"; 143 return 1; 144 } 145 146 installMacPython() or die "Failed to install Python."; 147 148 checkPythonVersion() or die "Final version check failed, must have failed to update Python"; 149 print "Successfully updated python.\n"; 150 } 151 152 exit(main()); 153