blob: 9f9d2745f2c949a91aa0aaf84b955f8d8256136e [file] [log] [blame]
justincohen6a03a3d2016-03-26 21:44:381#!/usr/bin/env python
Sergey Berezin5654182d2018-04-30 21:24:492# Copyright 2018 The Chromium Authors. All rights reserved.
justincohen6a03a3d2016-03-26 21:44:383# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
erikchenda016262016-11-09 04:32:136"""
7If should_use_hermetic_xcode.py emits "1", and the current toolchain is out of
8date:
9 * Downloads the hermetic mac toolchain
Sergey Berezin5654182d2018-04-30 21:24:4910 * Requires CIPD authentication. Run `cipd auth-login`, use Google account.
erikchenda016262016-11-09 04:32:1311 * Accepts the license.
12 * If xcode-select and xcodebuild are not passwordless in sudoers, requires
13 user interaction.
Justin Cohen170c409b72017-09-13 02:37:0214
Sergey Berezin5654182d2018-04-30 21:24:4915The toolchain version can be overridden by setting MAC_TOOLCHAIN_REVISION with
16the full revision, e.g. 9A235.
justincohen6a03a3d2016-03-26 21:44:3817"""
18
19import os
erikchend5dfcdb02017-06-29 00:22:5320import platform
justincohen6a03a3d2016-03-26 21:44:3821import shutil
22import subprocess
23import sys
justincohen6a03a3d2016-03-26 21:44:3824
Sergey Berezin5654182d2018-04-30 21:24:4925
26# This can be changed after running:
27# mac_toolchain upload -xcode-path path/to/Xcode.app
erikchend5dfcdb02017-06-29 00:22:5328MAC_TOOLCHAIN_VERSION = '8E2002'
Sergey Berezin5654182d2018-04-30 21:24:4929
erikchend5dfcdb02017-06-29 00:22:5330# The toolchain will not be downloaded if the minimum OS version is not met.
31# 16 is the major version number for macOS 10.12.
32MAC_MINIMUM_OS_VERSION = 16
33
Erik Chena537a9052018-11-13 01:44:4334# The toolchain will not be downloaded if the maximum OS version is exceeded.
35# 17 is the major version number for macOS 10.13. Xcode 8 does not run on macOS
36# 10.14.
37# TODO(https://crbug.com/780980): Once we build with 10.13 SDK, Xcode 9, we
38# should be able to remove this upper bound.
39MAC_MAXIMUM_OS_VERSION = 17
40
Sergey Berezin5654182d2018-04-30 21:24:4941MAC_TOOLCHAIN_INSTALLER = 'mac_toolchain'
justincohenabbd93dc2016-11-30 20:11:2842
43# Absolute path to src/ directory.
44REPO_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
45
46# Absolute path to a file with gclient solutions.
47GCLIENT_CONFIG = os.path.join(os.path.dirname(REPO_ROOT), '.gclient')
justincohen6a03a3d2016-03-26 21:44:3848
49BASE_DIR = os.path.abspath(os.path.dirname(__file__))
Sergey Berezin5654182d2018-04-30 21:24:4950TOOLCHAIN_ROOT = os.path.join(BASE_DIR, 'mac_files')
51TOOLCHAIN_BUILD_DIR = os.path.join(TOOLCHAIN_ROOT, 'Xcode.app')
52STAMP_FILE = os.path.join(TOOLCHAIN_ROOT, 'toolchain_build_revision')
justincohen6a03a3d2016-03-26 21:44:3853
erikchend5dfcdb02017-06-29 00:22:5354
Sergey Berezin5654182d2018-04-30 21:24:4955def PlatformMeetsHermeticXcodeRequirements():
Erik Chena537a9052018-11-13 01:44:4356 major_version = int(platform.release().split('.')[0])
57 return (major_version >= MAC_MINIMUM_OS_VERSION and
58 major_version <= MAC_MAXIMUM_OS_VERSION)
erikchend5dfcdb02017-06-29 00:22:5359
60
Sergey Berezin5654182d2018-04-30 21:24:4961def _UseHermeticToolchain():
erikchenda016262016-11-09 04:32:1362 current_dir = os.path.dirname(os.path.realpath(__file__))
63 script_path = os.path.join(current_dir, 'mac/should_use_hermetic_xcode.py')
Sergey Berezin5654182d2018-04-30 21:24:4964 proc = subprocess.Popen([script_path, 'mac'], stdout=subprocess.PIPE)
erikchenda016262016-11-09 04:32:1365 return '1' in proc.stdout.readline()
justincohen6a03a3d2016-03-26 21:44:3866
erikchenda016262016-11-09 04:32:1367
Sergey Berezin5654182d2018-04-30 21:24:4968def RequestCipdAuthentication():
69 """Requests that the user authenticate to access Xcode CIPD packages."""
70
71 print 'Access to Xcode CIPD package requires authentication.'
erikchenda016262016-11-09 04:32:1372 print '-----------------------------------------------------------------'
73 print
74 print 'You appear to be a Googler.'
75 print
Sergey Berezin5654182d2018-04-30 21:24:4976 print 'I\'m sorry for the hassle, but you may need to do a one-time manual'
erikchenda016262016-11-09 04:32:1377 print 'authentication. Please run:'
78 print
Sergey Berezin5654182d2018-04-30 21:24:4979 print ' cipd auth-login'
erikchenda016262016-11-09 04:32:1380 print
81 print 'and follow the instructions.'
82 print
Sergey Berezin5654182d2018-04-30 21:24:4983 print 'NOTE: Use your google.com credentials, not chromium.org.'
erikchenda016262016-11-09 04:32:1384 print
85 print '-----------------------------------------------------------------'
86 print
87 sys.stdout.flush()
justincohen6a03a3d2016-03-26 21:44:3888
89
Sergey Berezin5654182d2018-04-30 21:24:4990def PrintError(message):
91 # Flush buffers to ensure correct output ordering.
92 sys.stdout.flush()
93 sys.stderr.write(message + '\n')
94 sys.stderr.flush()
justincohen6a03a3d2016-03-26 21:44:3895
justincohen6a03a3d2016-03-26 21:44:3896
Sergey Berezin5654182d2018-04-30 21:24:4997def InstallXcode(xcode_build_version, installer_cmd, xcode_app_path):
98 """Installs the requested Xcode build version.
justincohen6a03a3d2016-03-26 21:44:3899
Sergey Berezin5654182d2018-04-30 21:24:49100 Args:
101 xcode_build_version: (string) Xcode build version to install.
102 installer_cmd: (string) Path to mac_toolchain command to install Xcode.
103 See https://chromium.googlesource.com/infra/infra/+/master/go/src/infra/cmd/mac_toolchain/
104 xcode_app_path: (string) Path to install the contents of Xcode.app.
justincohen6a03a3d2016-03-26 21:44:38105
Sergey Berezin5654182d2018-04-30 21:24:49106 Returns:
107 True if installation was successful. False otherwise.
108 """
109 args = [
110 installer_cmd, 'install',
111 '-kind', 'mac',
112 '-xcode-version', xcode_build_version.lower(),
113 '-output-dir', xcode_app_path,
114 ]
justincohen6a03a3d2016-03-26 21:44:38115
Sergey Berezin5654182d2018-04-30 21:24:49116 # Buildbot slaves need to use explicit credentials. LUCI bots should NOT set
117 # this variable.
118 creds = os.environ.get('MAC_TOOLCHAIN_CREDS')
119 if creds:
120 args.extend(['--service-account-json', creds])
121
justincohen6a03a3d2016-03-26 21:44:38122 try:
Sergey Berezin5654182d2018-04-30 21:24:49123 subprocess.check_call(args)
124 except subprocess.CalledProcessError as e:
125 PrintError('Xcode build version %s failed to install: %s\n' % (
126 xcode_build_version, e))
127 RequestCipdAuthentication()
128 return False
129 except OSError as e:
130 PrintError(('Xcode installer "%s" failed to execute'
131 ' (not on PATH or not installed).') % installer_cmd)
132 return False
justincohen6a03a3d2016-03-26 21:44:38133
Sergey Berezin5654182d2018-04-30 21:24:49134 return True
justincohen6a03a3d2016-03-26 21:44:38135
sdefresneaacc28452017-01-12 10:33:37136
137def main():
138 if sys.platform != 'darwin':
139 return 0
140
Sergey Berezin5654182d2018-04-30 21:24:49141 if not _UseHermeticToolchain():
142 print 'Skipping Mac toolchain installation for mac'
143 return 0
erikchend5dfcdb02017-06-29 00:22:53144
Sergey Berezin5654182d2018-04-30 21:24:49145 if not PlatformMeetsHermeticXcodeRequirements():
146 print 'OS version does not support toolchain.'
147 return 0
sdefresneaacc28452017-01-12 10:33:37148
Sergey Berezin5654182d2018-04-30 21:24:49149 toolchain_version = os.environ.get('MAC_TOOLCHAIN_REVISION',
150 MAC_TOOLCHAIN_VERSION)
151
152 # On developer machines, mac_toolchain tool is provided by
153 # depot_tools. On the bots, the recipe is responsible for installing
154 # it and providing the path to the executable.
155 installer_cmd = os.environ.get('MAC_TOOLCHAIN_INSTALLER',
156 MAC_TOOLCHAIN_INSTALLER)
157
158 toolchain_root = TOOLCHAIN_ROOT
159 xcode_app_path = TOOLCHAIN_BUILD_DIR
160 stamp_file = STAMP_FILE
161
162 # Delete the old "hermetic" installation if detected.
163 # TODO(crbug.com/797051): remove this once the old "hermetic" solution is no
164 # longer in use.
165 if os.path.exists(stamp_file):
166 print 'Detected old hermetic installation at %s. Deleting.' % (
167 toolchain_root)
168 shutil.rmtree(toolchain_root)
169
170 success = InstallXcode(toolchain_version, installer_cmd, xcode_app_path)
171 if not success:
172 return 1
sdefresneaacc28452017-01-12 10:33:37173
174 return 0
175
176
justincohen6a03a3d2016-03-26 21:44:38177if __name__ == '__main__':
178 sys.exit(main())