chromium/native_client_sdk/src/build_tools/sdk_tools/sdk_update.py

#!/usr/bin/env python
# Copyright 2012 The Chromium Authors
# 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)