blob: 87ed2568124ac59034f8746e503166bad09f0c5b [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
Elly Fong-Jones69989872019-03-06 18:34:1128MAC_TOOLCHAIN_VERSION = '9E501'
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.
Elly Fong-Jones69989872019-03-06 18:34:1131# 17 is the major version number for macOS 10.13.
32# 9E145 (Xcode 9.3) only runs on 10.13.2 and newer.
33MAC_MINIMUM_OS_VERSION = 17
Erik Chena537a9052018-11-13 01:44:4334
Sergey Berezin5654182d2018-04-30 21:24:4935MAC_TOOLCHAIN_INSTALLER = 'mac_toolchain'
justincohenabbd93dc2016-11-30 20:11:2836
37# Absolute path to src/ directory.
38REPO_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
39
40# Absolute path to a file with gclient solutions.
41GCLIENT_CONFIG = os.path.join(os.path.dirname(REPO_ROOT), '.gclient')
justincohen6a03a3d2016-03-26 21:44:3842
43BASE_DIR = os.path.abspath(os.path.dirname(__file__))
Sergey Berezin5654182d2018-04-30 21:24:4944TOOLCHAIN_ROOT = os.path.join(BASE_DIR, 'mac_files')
45TOOLCHAIN_BUILD_DIR = os.path.join(TOOLCHAIN_ROOT, 'Xcode.app')
46STAMP_FILE = os.path.join(TOOLCHAIN_ROOT, 'toolchain_build_revision')
justincohen6a03a3d2016-03-26 21:44:3847
erikchend5dfcdb02017-06-29 00:22:5348
Sergey Berezin5654182d2018-04-30 21:24:4949def PlatformMeetsHermeticXcodeRequirements():
Erik Chena537a9052018-11-13 01:44:4350 major_version = int(platform.release().split('.')[0])
Elly Fong-Jones69989872019-03-06 18:34:1151 return major_version >= MAC_MINIMUM_OS_VERSION
erikchend5dfcdb02017-06-29 00:22:5352
53
Sergey Berezin5654182d2018-04-30 21:24:4954def _UseHermeticToolchain():
erikchenda016262016-11-09 04:32:1355 current_dir = os.path.dirname(os.path.realpath(__file__))
56 script_path = os.path.join(current_dir, 'mac/should_use_hermetic_xcode.py')
Sergey Berezin5654182d2018-04-30 21:24:4957 proc = subprocess.Popen([script_path, 'mac'], stdout=subprocess.PIPE)
erikchenda016262016-11-09 04:32:1358 return '1' in proc.stdout.readline()
justincohen6a03a3d2016-03-26 21:44:3859
erikchenda016262016-11-09 04:32:1360
Sergey Berezin5654182d2018-04-30 21:24:4961def RequestCipdAuthentication():
62 """Requests that the user authenticate to access Xcode CIPD packages."""
63
64 print 'Access to Xcode CIPD package requires authentication.'
erikchenda016262016-11-09 04:32:1365 print '-----------------------------------------------------------------'
66 print
67 print 'You appear to be a Googler.'
68 print
Sergey Berezin5654182d2018-04-30 21:24:4969 print 'I\'m sorry for the hassle, but you may need to do a one-time manual'
erikchenda016262016-11-09 04:32:1370 print 'authentication. Please run:'
71 print
Sergey Berezin5654182d2018-04-30 21:24:4972 print ' cipd auth-login'
erikchenda016262016-11-09 04:32:1373 print
74 print 'and follow the instructions.'
75 print
Sergey Berezin5654182d2018-04-30 21:24:4976 print 'NOTE: Use your google.com credentials, not chromium.org.'
erikchenda016262016-11-09 04:32:1377 print
78 print '-----------------------------------------------------------------'
79 print
80 sys.stdout.flush()
justincohen6a03a3d2016-03-26 21:44:3881
82
Sergey Berezin5654182d2018-04-30 21:24:4983def PrintError(message):
84 # Flush buffers to ensure correct output ordering.
85 sys.stdout.flush()
86 sys.stderr.write(message + '\n')
87 sys.stderr.flush()
justincohen6a03a3d2016-03-26 21:44:3888
justincohen6a03a3d2016-03-26 21:44:3889
Sergey Berezin5654182d2018-04-30 21:24:4990def InstallXcode(xcode_build_version, installer_cmd, xcode_app_path):
91 """Installs the requested Xcode build version.
justincohen6a03a3d2016-03-26 21:44:3892
Sergey Berezin5654182d2018-04-30 21:24:4993 Args:
94 xcode_build_version: (string) Xcode build version to install.
95 installer_cmd: (string) Path to mac_toolchain command to install Xcode.
96 See https://chromium.googlesource.com/infra/infra/+/master/go/src/infra/cmd/mac_toolchain/
97 xcode_app_path: (string) Path to install the contents of Xcode.app.
justincohen6a03a3d2016-03-26 21:44:3898
Sergey Berezin5654182d2018-04-30 21:24:4999 Returns:
100 True if installation was successful. False otherwise.
101 """
102 args = [
103 installer_cmd, 'install',
104 '-kind', 'mac',
105 '-xcode-version', xcode_build_version.lower(),
106 '-output-dir', xcode_app_path,
107 ]
justincohen6a03a3d2016-03-26 21:44:38108
Sergey Berezin5654182d2018-04-30 21:24:49109 # Buildbot slaves need to use explicit credentials. LUCI bots should NOT set
110 # this variable.
111 creds = os.environ.get('MAC_TOOLCHAIN_CREDS')
112 if creds:
113 args.extend(['--service-account-json', creds])
114
justincohen6a03a3d2016-03-26 21:44:38115 try:
Sergey Berezin5654182d2018-04-30 21:24:49116 subprocess.check_call(args)
117 except subprocess.CalledProcessError as e:
118 PrintError('Xcode build version %s failed to install: %s\n' % (
119 xcode_build_version, e))
120 RequestCipdAuthentication()
121 return False
122 except OSError as e:
123 PrintError(('Xcode installer "%s" failed to execute'
124 ' (not on PATH or not installed).') % installer_cmd)
125 return False
justincohen6a03a3d2016-03-26 21:44:38126
Sergey Berezin5654182d2018-04-30 21:24:49127 return True
justincohen6a03a3d2016-03-26 21:44:38128
sdefresneaacc28452017-01-12 10:33:37129
130def main():
131 if sys.platform != 'darwin':
132 return 0
133
Sergey Berezin5654182d2018-04-30 21:24:49134 if not _UseHermeticToolchain():
135 print 'Skipping Mac toolchain installation for mac'
136 return 0
erikchend5dfcdb02017-06-29 00:22:53137
Sergey Berezin5654182d2018-04-30 21:24:49138 if not PlatformMeetsHermeticXcodeRequirements():
139 print 'OS version does not support toolchain.'
140 return 0
sdefresneaacc28452017-01-12 10:33:37141
Sergey Berezin5654182d2018-04-30 21:24:49142 toolchain_version = os.environ.get('MAC_TOOLCHAIN_REVISION',
143 MAC_TOOLCHAIN_VERSION)
144
145 # On developer machines, mac_toolchain tool is provided by
146 # depot_tools. On the bots, the recipe is responsible for installing
147 # it and providing the path to the executable.
148 installer_cmd = os.environ.get('MAC_TOOLCHAIN_INSTALLER',
149 MAC_TOOLCHAIN_INSTALLER)
150
151 toolchain_root = TOOLCHAIN_ROOT
152 xcode_app_path = TOOLCHAIN_BUILD_DIR
153 stamp_file = STAMP_FILE
154
155 # Delete the old "hermetic" installation if detected.
156 # TODO(crbug.com/797051): remove this once the old "hermetic" solution is no
157 # longer in use.
158 if os.path.exists(stamp_file):
159 print 'Detected old hermetic installation at %s. Deleting.' % (
160 toolchain_root)
161 shutil.rmtree(toolchain_root)
162
163 success = InstallXcode(toolchain_version, installer_cmd, xcode_app_path)
164 if not success:
165 return 1
sdefresneaacc28452017-01-12 10:33:37166
167 return 0
168
169
justincohen6a03a3d2016-03-26 21:44:38170if __name__ == '__main__':
171 sys.exit(main())