Index: build/mac_toolchain.py |
diff --git a/build/mac_toolchain.py b/build/mac_toolchain.py |
new file mode 100755 |
index 0000000000000000000000000000000000000000..64d07169e80eaae489053ec8997a10de33b8c499 |
--- /dev/null |
+++ b/build/mac_toolchain.py |
@@ -0,0 +1,154 @@ |
+#!/usr/bin/env python |
+# Copyright 2016 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. |
+ |
+"""Download necessary mac toolchain files under certain conditions. If |
+xcode-select is already set and points to an external folder |
+(e.g. /Application/Xcode.app), this script only runs if the GYP_DEFINE |
+|force_mac_toolchain| is set. To override the values in |
+|TOOLCHAIN_REVISION|-|TOOLCHAIN_SUB_REVISION| below, GYP_DEFINE |
+mac_toolchain_revision can be used instead. |
+ |
+This script will only run on machines if /usr/bin/xcodebuild has been added to |
+the sudoers list so the license can be accepted. |
+ |
+Otherwise, user input would be required to complete the script. Perhaps future |
+versions can be modified to allow for user input on developer machines. |
+""" |
+ |
+import os |
+import shutil |
+import subprocess |
+import sys |
+import tarfile |
+import time |
+import tempfile |
+import urllib2 |
+ |
+# This can be changed after running /build/package_mac_toolchain.py. |
+TOOLCHAIN_REVISION = '5B1008' |
+TOOLCHAIN_SUB_REVISION = 2 |
+TOOLCHAIN_VERSION = '%s-%s' % (TOOLCHAIN_REVISION, TOOLCHAIN_SUB_REVISION) |
+ |
+BASE_DIR = os.path.abspath(os.path.dirname(__file__)) |
+TOOLCHAIN_BUILD_DIR = os.path.join(BASE_DIR, 'mac_files', 'Xcode.app') |
+STAMP_FILE = os.path.join(BASE_DIR, 'mac_files', 'toolchain_build_revision') |
+TOOLCHAIN_URL = 'gs://chrome-mac-sdk/' |
+ |
+ |
+def GetToolchainDirectory(): |
+ if sys.platform == 'darwin' and not UseLocalMacSDK(): |
+ return TOOLCHAIN_BUILD_DIR |
+ |
+ |
+def ReadStampFile(): |
+ """Return the contents of the stamp file, or '' if it doesn't exist.""" |
+ try: |
+ with open(STAMP_FILE, 'r') as f: |
+ return f.read().rstrip() |
+ except IOError: |
+ return '' |
+ |
+ |
+def WriteStampFile(s): |
+ """Write s to the stamp file.""" |
+ EnsureDirExists(os.path.dirname(STAMP_FILE)) |
+ with open(STAMP_FILE, 'w') as f: |
+ f.write(s) |
+ f.write('\n') |
+ |
+ |
+def EnsureDirExists(path): |
+ if not os.path.exists(path): |
+ os.makedirs(path) |
+ |
+ |
+def DownloadAndUnpack(url, output_dir): |
+ """Decompresses |url| into a cleared |output_dir|.""" |
+ temp_name = tempfile.mktemp(prefix='mac_toolchain') |
+ try: |
+ print 'Downloading new toolchain.' |
+ subprocess.check_call(['gsutil.py', 'cp', url, temp_name]) |
+ if os.path.exists(output_dir): |
+ print 'Deleting old toolchain.' |
+ shutil.rmtree(output_dir) |
+ EnsureDirExists(output_dir) |
+ print 'Unpacking new toolchain.' |
+ tarfile.open(mode='r:gz', name=temp_name).extractall(path=output_dir) |
+ finally: |
+ if os.path.exists(temp_name): |
+ os.unlink(temp_name) |
+ |
+ |
+def CanAccessToolchainBucket(): |
+ """Checks whether the user has access to |TOOLCHAIN_URL|.""" |
+ proc = subprocess.Popen(['gsutil.py', 'ls', TOOLCHAIN_URL], |
+ stdout=subprocess.PIPE) |
+ proc.communicate() |
+ return proc.returncode == 0 |
+ |
+ |
+def AcceptLicense(directory): |
+ """Use xcodebuild to accept new toolchain license. This only |
+ works if xcodebuild is in sudoers.""" |
+ xcodebuild = os.path.join(TOOLCHAIN_BUILD_DIR, |
+ 'Contents/Developer/usr/bin/xcodebuild') |
+ subprocess.check_call(['sudo', xcodebuild, '-license', 'accept']) |
+ |
+ |
+def UseLocalMacSDK(): |
+ force_pull = os.environ.has_key('FORCE_MAC_TOOLCHAIN') |
+ |
+ # Don't update the toolchain if there's already one installed outside of the |
+ # expected location for a Chromium mac toolchain, unless |force_pull| is set. |
+ proc = subprocess.Popen(['xcode-select', '-p'], stdout=subprocess.PIPE) |
+ xcode_select_dir = proc.communicate()[0] |
+ rc = proc.returncode |
+ return (not force_pull and rc == 0 and |
+ TOOLCHAIN_BUILD_DIR not in xcode_select_dir) |
+ |
+ |
+def main(): |
+ if sys.platform != 'darwin': |
+ return 0 |
+ |
+ # TODO(justincohen): Add support for GN per crbug.com/570091 |
+ if UseLocalMacSDK(): |
+ print 'Using local toolchain.' |
+ return 0 |
+ |
+ toolchain_revision = os.environ.get('MAC_TOOLCHAIN_REVISION', |
+ TOOLCHAIN_VERSION) |
+ if ReadStampFile() == toolchain_revision: |
+ print 'Toolchain (%s) is already up to date.' % toolchain_revision |
+ AcceptLicense(TOOLCHAIN_BUILD_DIR) |
+ return 0 |
+ |
+ if not CanAccessToolchainBucket(): |
+ print 'Cannot access toolchain bucket.' |
+ return 0 |
+ |
+ # Reset the stamp file in case the build is unsuccessful. |
+ WriteStampFile('') |
+ |
+ toolchain_file = '%s.tgz' % toolchain_revision |
+ toolchain_full_url = TOOLCHAIN_URL + toolchain_file |
+ |
+ print 'Updating toolchain to %s...' % toolchain_revision |
+ try: |
+ toolchain_file = 'toolchain-%s.tgz' % toolchain_revision |
+ toolchain_full_url = TOOLCHAIN_URL + toolchain_file |
+ DownloadAndUnpack(toolchain_full_url, TOOLCHAIN_BUILD_DIR) |
+ AcceptLicense(TOOLCHAIN_BUILD_DIR) |
+ |
+ print 'Toolchain %s unpacked.' % toolchain_revision |
+ WriteStampFile(toolchain_revision) |
+ return 0 |
+ except: |
+ print 'Failed to download toolchain %s.' % toolchain_file |
+ print 'Exiting.' |
+ return 1 |
+ |
+if __name__ == '__main__': |
+ sys.exit(main()) |