#!/usr/bin/env python # Copyright (c) 2012 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. """Shim script for the SDK updater, to allow automatic updating. The purpose of this script is to be a shim which automatically updates sdk_tools (the bundle containing the updater scripts) whenever this script is run. When the sdk_tools bundle has been updated to the most recent version, this script forwards its arguments to sdk_updater_main.py. """ import os import subprocess from sdk_update_common import RenameDir, RemoveDir, Error import sys import tempfile SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) SDK_UPDATE_MAIN = os.path.join(SCRIPT_DIR, 'sdk_update_main.py') SDK_ROOT_DIR = os.path.dirname(SCRIPT_DIR) NACLSDK_SHELL_SCRIPT = os.path.join(SDK_ROOT_DIR, 'naclsdk') if sys.platform.startswith('win'): NACLSDK_SHELL_SCRIPT += '.bat' SDK_TOOLS_DIR = os.path.join(SDK_ROOT_DIR, 'sdk_tools') SDK_TOOLS_UPDATE_DIR = os.path.join(SDK_ROOT_DIR, 'sdk_tools_update') def MakeSdkUpdateMainCmd(args): """Returns a list of command line arguments to run sdk_update_main. Args: args: A list of arguments to pass to sdk_update_main.py Returns: A new list that can be passed to subprocess.call, subprocess.Popen, etc. """ return [sys.executable, SDK_UPDATE_MAIN] + args def UpdateSDKTools(args): """Run sdk_update_main to update sdk_tools bundle. Return True if it is updated. Args: args: The arguments to pass to sdk_update_main.py. We need to keep this to ensure sdk_update_main is called correctly; some parameters specify URLS or directories to use. Returns: True if the sdk_tools bundle was updated. """ cmd = MakeSdkUpdateMainCmd(args + ['--update-sdk-tools']) process = subprocess.Popen(cmd, stdout=subprocess.PIPE) stdout, _ = process.communicate() if process.returncode == 0: return stdout.find('Updating bundle sdk_tools to version') != -1 else: # Updating sdk_tools could fail for any number of reasons. Regardless, it # should be safe to try to run the user's command. return False def RenameSdkToolsDirectory(): """Rename sdk_tools_update to sdk_tools.""" # If there is no update directory, bail. if not os.path.isdir(SDK_TOOLS_UPDATE_DIR): return False try: tempdir = tempfile.mkdtemp() temp_sdktools = os.path.join(tempdir, 'sdk_tools') try: RenameDir(SDK_TOOLS_DIR, temp_sdktools) except Error: # The user is probably on Windows, and the directory is locked. sys.stderr.write('Cannot rename directory "%s". Make sure no programs are' ' viewing or accessing this directory and try again.\n' % ( SDK_TOOLS_DIR,)) sys.exit(1) try: RenameDir(SDK_TOOLS_UPDATE_DIR, SDK_TOOLS_DIR) except Error: # Failed for some reason, move the old dir back. try: RenameDir(temp_sdktools, SDK_TOOLS_DIR) except Error: # Not much to do here. sdk_tools won't exist, but sdk_tools_update # should. Hopefully running the batch script again will move # sdk_tools_update -> sdk_tools and it will work this time... sys.stderr.write('Unable to restore directory "%s" while auto-updating.' 'Make sure no programs are viewing or accessing this directory and' 'try again.\n' % (SDK_TOOLS_DIR,)) sys.exit(1) finally: RemoveDir(tempdir) return True def CheckRuntimeRequirements(): if sys.platform.startswith('linux'): if not os.path.exists('/lib/ld-linux.so.2'): sys.stderr.write("""32-bit runtime environment was not found on this system. Specifically the 32-bit dynamic loader which is needed by the NaCl compilers was not found ('/lib/ld-linux.so.2'). On modern debian/ubuntu systems this is included in the 'libc6:i386' package.\n""") sys.exit(1) def main(): args = sys.argv[1:] CheckRuntimeRequirements() if UpdateSDKTools(args) and RenameSdkToolsDirectory(): # Call the shell script, just in case this script was updated in the next # version of sdk_tools return subprocess.call([NACLSDK_SHELL_SCRIPT] + args) else: return subprocess.call(MakeSdkUpdateMainCmd(args)) if __name__ == '__main__': try: sys.exit(main()) except KeyboardInterrupt: sys.exit(1)