1#!/usr/bin/env python 2# Copyright (c) 2012 The Chromium Authors. All rights reserved. 3# Use of this source code is governed by a BSD-style license that can be 4# found in the LICENSE file. 5 6"""Shim script for the SDK updater, to allow automatic updating. 7 8The purpose of this script is to be a shim which automatically updates 9sdk_tools (the bundle containing the updater scripts) whenever this script is 10run. 11 12When the sdk_tools bundle has been updated to the most recent version, this 13script forwards its arguments to sdk_updater_main.py. 14""" 15 16import os 17import subprocess 18from sdk_update_common import RenameDir, RemoveDir, Error 19import sys 20import tempfile 21 22 23SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) 24SDK_UPDATE_MAIN = os.path.join(SCRIPT_DIR, 'sdk_update_main.py') 25SDK_ROOT_DIR = os.path.dirname(SCRIPT_DIR) 26NACLSDK_SHELL_SCRIPT = os.path.join(SDK_ROOT_DIR, 'naclsdk') 27if sys.platform.startswith('win'): 28 NACLSDK_SHELL_SCRIPT += '.bat' 29SDK_TOOLS_DIR = os.path.join(SDK_ROOT_DIR, 'sdk_tools') 30SDK_TOOLS_UPDATE_DIR = os.path.join(SDK_ROOT_DIR, 'sdk_tools_update') 31 32 33def MakeSdkUpdateMainCmd(args): 34 """Returns a list of command line arguments to run sdk_update_main. 35 36 Args: 37 args: A list of arguments to pass to sdk_update_main.py 38 Returns: 39 A new list that can be passed to subprocess.call, subprocess.Popen, etc. 40 """ 41 return [sys.executable, SDK_UPDATE_MAIN] + args 42 43 44def UpdateSDKTools(args): 45 """Run sdk_update_main to update sdk_tools bundle. Return True if it is 46 updated. 47 48 Args: 49 args: The arguments to pass to sdk_update_main.py. We need to keep this to 50 ensure sdk_update_main is called correctly; some parameters specify 51 URLS or directories to use. 52 Returns: 53 True if the sdk_tools bundle was updated. 54 """ 55 cmd = MakeSdkUpdateMainCmd(args + ['--update-sdk-tools']) 56 process = subprocess.Popen(cmd, stdout=subprocess.PIPE) 57 stdout, _ = process.communicate() 58 if process.returncode == 0: 59 return stdout.find('Updating bundle sdk_tools to version') != -1 60 else: 61 # Updating sdk_tools could fail for any number of reasons. Regardless, it 62 # should be safe to try to run the user's command. 63 return False 64 65 66def RenameSdkToolsDirectory(): 67 """Rename sdk_tools_update to sdk_tools.""" 68 # If there is no update directory, bail. 69 if not os.path.isdir(SDK_TOOLS_UPDATE_DIR): 70 return False 71 72 try: 73 tempdir = tempfile.mkdtemp() 74 temp_sdktools = os.path.join(tempdir, 'sdk_tools') 75 try: 76 RenameDir(SDK_TOOLS_DIR, temp_sdktools) 77 except Error: 78 # The user is probably on Windows, and the directory is locked. 79 sys.stderr.write('Cannot rename directory "%s". Make sure no programs are' 80 ' viewing or accessing this directory and try again.\n' % ( 81 SDK_TOOLS_DIR,)) 82 sys.exit(1) 83 84 try: 85 RenameDir(SDK_TOOLS_UPDATE_DIR, SDK_TOOLS_DIR) 86 except Error: 87 # Failed for some reason, move the old dir back. 88 try: 89 RenameDir(temp_sdktools, SDK_TOOLS_DIR) 90 except Error: 91 # Not much to do here. sdk_tools won't exist, but sdk_tools_update 92 # should. Hopefully running the batch script again will move 93 # sdk_tools_update -> sdk_tools and it will work this time... 94 sys.stderr.write('Unable to restore directory "%s" while auto-updating.' 95 'Make sure no programs are viewing or accessing this directory and' 96 'try again.\n' % (SDK_TOOLS_DIR,)) 97 sys.exit(1) 98 finally: 99 RemoveDir(tempdir) 100 101 return True 102 103 104def CheckRuntimeRequirements(): 105 if sys.platform.startswith('linux'): 106 if not os.path.exists('/lib/ld-linux.so.2'): 107 sys.stderr.write("""32-bit runtime environment was not found on this 108system. Specifically the 32-bit dynamic loader which is needed by the NaCl 109compilers was not found ('/lib/ld-linux.so.2'). On modern debian/ubuntu 110systems this is included in the 'libc6:i386' package.\n""") 111 sys.exit(1) 112 113 114def main(): 115 args = sys.argv[1:] 116 CheckRuntimeRequirements() 117 if UpdateSDKTools(args) and RenameSdkToolsDirectory(): 118 # Call the shell script, just in case this script was updated in the next 119 # version of sdk_tools 120 return subprocess.call([NACLSDK_SHELL_SCRIPT] + args) 121 else: 122 return subprocess.call(MakeSdkUpdateMainCmd(args)) 123 124 125if __name__ == '__main__': 126 try: 127 sys.exit(main()) 128 except KeyboardInterrupt: 129 sys.exit(1) 130