blob: ea264a2f4c9d222d9fbf20c15be9577d249d15dc [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
Raul Tambre9e24293b2019-05-12 06:11:0719from __future__ import print_function
20
justincohen6a03a3d2016-03-26 21:44:3821import os
erikchend5dfcdb02017-06-29 00:22:5322import platform
justincohen6a03a3d2016-03-26 21:44:3823import shutil
24import subprocess
25import sys
justincohen6a03a3d2016-03-26 21:44:3826
Sergey Berezin5654182d2018-04-30 21:24:4927
28# This can be changed after running:
29# mac_toolchain upload -xcode-path path/to/Xcode.app
Elly Fong-Jones69989872019-03-06 18:34:1130MAC_TOOLCHAIN_VERSION = '9E501'
Sergey Berezin5654182d2018-04-30 21:24:4931
erikchend5dfcdb02017-06-29 00:22:5332# The toolchain will not be downloaded if the minimum OS version is not met.
Elly Fong-Jones69989872019-03-06 18:34:1133# 17 is the major version number for macOS 10.13.
34# 9E145 (Xcode 9.3) only runs on 10.13.2 and newer.
35MAC_MINIMUM_OS_VERSION = 17
Erik Chena537a9052018-11-13 01:44:4336
Sergey Berezin5654182d2018-04-30 21:24:4937MAC_TOOLCHAIN_INSTALLER = 'mac_toolchain'
justincohenabbd93dc2016-11-30 20:11:2838
39# Absolute path to src/ directory.
40REPO_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
41
42# Absolute path to a file with gclient solutions.
43GCLIENT_CONFIG = os.path.join(os.path.dirname(REPO_ROOT), '.gclient')
justincohen6a03a3d2016-03-26 21:44:3844
45BASE_DIR = os.path.abspath(os.path.dirname(__file__))
Sergey Berezin5654182d2018-04-30 21:24:4946TOOLCHAIN_ROOT = os.path.join(BASE_DIR, 'mac_files')
47TOOLCHAIN_BUILD_DIR = os.path.join(TOOLCHAIN_ROOT, 'Xcode.app')
48STAMP_FILE = os.path.join(TOOLCHAIN_ROOT, 'toolchain_build_revision')
justincohen6a03a3d2016-03-26 21:44:3849
erikchend5dfcdb02017-06-29 00:22:5350
Sergey Berezin5654182d2018-04-30 21:24:4951def PlatformMeetsHermeticXcodeRequirements():
Erik Chena537a9052018-11-13 01:44:4352 major_version = int(platform.release().split('.')[0])
Elly Fong-Jones69989872019-03-06 18:34:1153 return major_version >= MAC_MINIMUM_OS_VERSION
erikchend5dfcdb02017-06-29 00:22:5354
55
Sergey Berezin5654182d2018-04-30 21:24:4956def _UseHermeticToolchain():
erikchenda016262016-11-09 04:32:1357 current_dir = os.path.dirname(os.path.realpath(__file__))
58 script_path = os.path.join(current_dir, 'mac/should_use_hermetic_xcode.py')
Sergey Berezin5654182d2018-04-30 21:24:4959 proc = subprocess.Popen([script_path, 'mac'], stdout=subprocess.PIPE)
erikchenda016262016-11-09 04:32:1360 return '1' in proc.stdout.readline()
justincohen6a03a3d2016-03-26 21:44:3861
erikchenda016262016-11-09 04:32:1362
Sergey Berezin5654182d2018-04-30 21:24:4963def RequestCipdAuthentication():
64 """Requests that the user authenticate to access Xcode CIPD packages."""
65
Raul Tambre9e24293b2019-05-12 06:11:0766 print('Access to Xcode CIPD package requires authentication.')
67 print('-----------------------------------------------------------------')
68 print()
69 print('You appear to be a Googler.')
70 print()
71 print('I\'m sorry for the hassle, but you may need to do a one-time manual')
72 print('authentication. Please run:')
73 print()
74 print(' cipd auth-login')
75 print()
76 print('and follow the instructions.')
77 print()
78 print('NOTE: Use your google.com credentials, not chromium.org.')
79 print()
80 print('-----------------------------------------------------------------')
81 print()
erikchenda016262016-11-09 04:32:1382 sys.stdout.flush()
justincohen6a03a3d2016-03-26 21:44:3883
84
Sergey Berezin5654182d2018-04-30 21:24:4985def PrintError(message):
86 # Flush buffers to ensure correct output ordering.
87 sys.stdout.flush()
88 sys.stderr.write(message + '\n')
89 sys.stderr.flush()
justincohen6a03a3d2016-03-26 21:44:3890
justincohen6a03a3d2016-03-26 21:44:3891
Sergey Berezin5654182d2018-04-30 21:24:4992def InstallXcode(xcode_build_version, installer_cmd, xcode_app_path):
93 """Installs the requested Xcode build version.
justincohen6a03a3d2016-03-26 21:44:3894
Sergey Berezin5654182d2018-04-30 21:24:4995 Args:
96 xcode_build_version: (string) Xcode build version to install.
97 installer_cmd: (string) Path to mac_toolchain command to install Xcode.
98 See https://chromium.googlesource.com/infra/infra/+/master/go/src/infra/cmd/mac_toolchain/
99 xcode_app_path: (string) Path to install the contents of Xcode.app.
justincohen6a03a3d2016-03-26 21:44:38100
Sergey Berezin5654182d2018-04-30 21:24:49101 Returns:
102 True if installation was successful. False otherwise.
103 """
104 args = [
105 installer_cmd, 'install',
106 '-kind', 'mac',
107 '-xcode-version', xcode_build_version.lower(),
108 '-output-dir', xcode_app_path,
109 ]
justincohen6a03a3d2016-03-26 21:44:38110
Sergey Berezin5654182d2018-04-30 21:24:49111 # Buildbot slaves need to use explicit credentials. LUCI bots should NOT set
112 # this variable.
113 creds = os.environ.get('MAC_TOOLCHAIN_CREDS')
114 if creds:
115 args.extend(['--service-account-json', creds])
116
justincohen6a03a3d2016-03-26 21:44:38117 try:
Sergey Berezin5654182d2018-04-30 21:24:49118 subprocess.check_call(args)
119 except subprocess.CalledProcessError as e:
120 PrintError('Xcode build version %s failed to install: %s\n' % (
121 xcode_build_version, e))
122 RequestCipdAuthentication()
123 return False
124 except OSError as e:
125 PrintError(('Xcode installer "%s" failed to execute'
126 ' (not on PATH or not installed).') % installer_cmd)
127 return False
justincohen6a03a3d2016-03-26 21:44:38128
Sergey Berezin5654182d2018-04-30 21:24:49129 return True
justincohen6a03a3d2016-03-26 21:44:38130
sdefresneaacc28452017-01-12 10:33:37131
132def main():
133 if sys.platform != 'darwin':
134 return 0
135
Sergey Berezin5654182d2018-04-30 21:24:49136 if not _UseHermeticToolchain():
Raul Tambre9e24293b2019-05-12 06:11:07137 print('Skipping Mac toolchain installation for mac')
Sergey Berezin5654182d2018-04-30 21:24:49138 return 0
erikchend5dfcdb02017-06-29 00:22:53139
Sergey Berezin5654182d2018-04-30 21:24:49140 if not PlatformMeetsHermeticXcodeRequirements():
Raul Tambre9e24293b2019-05-12 06:11:07141 print('OS version does not support toolchain.')
Sergey Berezin5654182d2018-04-30 21:24:49142 return 0
sdefresneaacc28452017-01-12 10:33:37143
Sergey Berezin5654182d2018-04-30 21:24:49144 toolchain_version = os.environ.get('MAC_TOOLCHAIN_REVISION',
145 MAC_TOOLCHAIN_VERSION)
146
147 # On developer machines, mac_toolchain tool is provided by
148 # depot_tools. On the bots, the recipe is responsible for installing
149 # it and providing the path to the executable.
150 installer_cmd = os.environ.get('MAC_TOOLCHAIN_INSTALLER',
151 MAC_TOOLCHAIN_INSTALLER)
152
153 toolchain_root = TOOLCHAIN_ROOT
154 xcode_app_path = TOOLCHAIN_BUILD_DIR
155 stamp_file = STAMP_FILE
156
157 # Delete the old "hermetic" installation if detected.
158 # TODO(crbug.com/797051): remove this once the old "hermetic" solution is no
159 # longer in use.
160 if os.path.exists(stamp_file):
Raul Tambre9e24293b2019-05-12 06:11:07161 print(
162 'Detected old hermetic installation at %s. Deleting.' % toolchain_root)
Sergey Berezin5654182d2018-04-30 21:24:49163 shutil.rmtree(toolchain_root)
164
165 success = InstallXcode(toolchain_version, installer_cmd, xcode_app_path)
166 if not success:
167 return 1
sdefresneaacc28452017-01-12 10:33:37168
169 return 0
170
171
justincohen6a03a3d2016-03-26 21:44:38172if __name__ == '__main__':
173 sys.exit(main())