blob: 866b5f85c2a7aab3f8226c5bab7e29dadac7df67 [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.
Erik Chenbc74094852019-07-17 21:47:0014 * Downloads standalone binaries from [a possibly different version of Xcode].
Justin Cohen170c409b72017-09-13 02:37:0215
Sergey Berezin5654182d2018-04-30 21:24:4916The toolchain version can be overridden by setting MAC_TOOLCHAIN_REVISION with
17the full revision, e.g. 9A235.
justincohen6a03a3d2016-03-26 21:44:3818"""
19
Raul Tambre9e24293b2019-05-12 06:11:0720from __future__ import print_function
21
justincohen6a03a3d2016-03-26 21:44:3822import os
Erik Chenbc74094852019-07-17 21:47:0023import pkg_resources
erikchend5dfcdb02017-06-29 00:22:5324import platform
Erik Chenbc74094852019-07-17 21:47:0025import plistlib
justincohen6a03a3d2016-03-26 21:44:3826import shutil
27import subprocess
28import sys
justincohen6a03a3d2016-03-26 21:44:3829
Sergey Berezin5654182d2018-04-30 21:24:4930
Elly Fong-Jones5fed7d82020-01-28 17:41:5431# This contains binaries from Xcode 11.2.1, along with the 10.15 SDKs (aka
32# 11B53). To build this package, see comments in build/xcode_binaries.yaml
Erik Chenbc74094852019-07-17 21:47:0033MAC_BINARIES_LABEL = 'infra_internal/ios/xcode/xcode_binaries/mac-amd64'
Elly Fong-Jones5fed7d82020-01-28 17:41:5434MAC_BINARIES_TAG = 'X5ZbqG_UKa-N64_XSBkAwShWPtzskeXhQRfpzc_1KUYC'
Erik Chenbc74094852019-07-17 21:47:0035
erikchend5dfcdb02017-06-29 00:22:5336# The toolchain will not be downloaded if the minimum OS version is not met.
Elly Fong-Jones69989872019-03-06 18:34:1137# 17 is the major version number for macOS 10.13.
38# 9E145 (Xcode 9.3) only runs on 10.13.2 and newer.
39MAC_MINIMUM_OS_VERSION = 17
Erik Chena537a9052018-11-13 01:44:4340
justincohen6a03a3d2016-03-26 21:44:3841BASE_DIR = os.path.abspath(os.path.dirname(__file__))
Sergey Berezin5654182d2018-04-30 21:24:4942TOOLCHAIN_ROOT = os.path.join(BASE_DIR, 'mac_files')
43TOOLCHAIN_BUILD_DIR = os.path.join(TOOLCHAIN_ROOT, 'Xcode.app')
justincohen6a03a3d2016-03-26 21:44:3844
Elly Fong-Jones33187c6e2019-12-13 20:50:1145# Always integrity-check the entire SDK. Mac SDK packages are complex and often
46# hit edge cases in cipd (eg https://crbug.com/1033987,
47# https://crbug.com/915278), and generally when this happens it requires manual
48# intervention to fix.
49# Note the trailing \n!
50PARANOID_MODE = '$ParanoidMode CheckIntegrity\n'
erikchend5dfcdb02017-06-29 00:22:5351
Sergey Berezin5654182d2018-04-30 21:24:4952def PlatformMeetsHermeticXcodeRequirements():
Erik Chena537a9052018-11-13 01:44:4353 major_version = int(platform.release().split('.')[0])
Elly Fong-Jones69989872019-03-06 18:34:1154 return major_version >= MAC_MINIMUM_OS_VERSION
erikchend5dfcdb02017-06-29 00:22:5355
56
Sergey Berezin5654182d2018-04-30 21:24:4957def _UseHermeticToolchain():
erikchenda016262016-11-09 04:32:1358 current_dir = os.path.dirname(os.path.realpath(__file__))
59 script_path = os.path.join(current_dir, 'mac/should_use_hermetic_xcode.py')
Sergey Berezin5654182d2018-04-30 21:24:4960 proc = subprocess.Popen([script_path, 'mac'], stdout=subprocess.PIPE)
erikchenda016262016-11-09 04:32:1361 return '1' in proc.stdout.readline()
justincohen6a03a3d2016-03-26 21:44:3862
erikchenda016262016-11-09 04:32:1363
Sergey Berezin5654182d2018-04-30 21:24:4964def RequestCipdAuthentication():
65 """Requests that the user authenticate to access Xcode CIPD packages."""
66
Raul Tambre9e24293b2019-05-12 06:11:0767 print('Access to Xcode CIPD package requires authentication.')
68 print('-----------------------------------------------------------------')
69 print()
70 print('You appear to be a Googler.')
71 print()
72 print('I\'m sorry for the hassle, but you may need to do a one-time manual')
73 print('authentication. Please run:')
74 print()
75 print(' cipd auth-login')
76 print()
77 print('and follow the instructions.')
78 print()
79 print('NOTE: Use your google.com credentials, not chromium.org.')
80 print()
81 print('-----------------------------------------------------------------')
82 print()
erikchenda016262016-11-09 04:32:1383 sys.stdout.flush()
justincohen6a03a3d2016-03-26 21:44:3884
85
Sergey Berezin5654182d2018-04-30 21:24:4986def PrintError(message):
87 # Flush buffers to ensure correct output ordering.
88 sys.stdout.flush()
89 sys.stderr.write(message + '\n')
90 sys.stderr.flush()
justincohen6a03a3d2016-03-26 21:44:3891
justincohen6a03a3d2016-03-26 21:44:3892
Erik Chenbc74094852019-07-17 21:47:0093def InstallXcodeBinaries():
94 """Installs the Xcode binaries needed to build Chrome and accepts the license.
95
96 This is the replacement for InstallXcode that installs a trimmed down version
97 of Xcode that is OS-version agnostic.
98 """
99 # First make sure the directory exists. It will serve as the cipd root. This
100 # also ensures that there will be no conflicts of cipd root.
101 binaries_root = os.path.join(TOOLCHAIN_ROOT, 'xcode_binaries')
102 if not os.path.exists(binaries_root):
Nico Webera3d706d2019-08-09 23:04:38103 os.makedirs(binaries_root)
Erik Chenbc74094852019-07-17 21:47:00104
105 # 'cipd ensure' is idempotent.
106 args = [
107 'cipd', 'ensure', '-root', binaries_root, '-ensure-file', '-'
108 ]
Erik Chendea651342019-07-23 05:02:47109
Erik Chen890362ea2019-07-22 22:43:48110 p = subprocess.Popen(
111 args, stdin=subprocess.PIPE, stdout=subprocess.PIPE,
112 stderr=subprocess.PIPE)
113 stdout, stderr = p.communicate(
Elly Fong-Jones33187c6e2019-12-13 20:50:11114 input=PARANOID_MODE + MAC_BINARIES_LABEL + ' ' + MAC_BINARIES_TAG)
Erik Chen890362ea2019-07-22 22:43:48115 if p.returncode != 0:
116 print(stdout)
117 print(stderr)
118 RequestCipdAuthentication()
119 return 1
Erik Chenbc74094852019-07-17 21:47:00120
121 # Accept the license for this version of Xcode if it's newer than the
122 # currently accepted version.
123 cipd_xcode_version_plist_path = os.path.join(
124 binaries_root, 'Contents/version.plist')
125 cipd_xcode_version_plist = plistlib.readPlist(cipd_xcode_version_plist_path)
126 cipd_xcode_version = cipd_xcode_version_plist['CFBundleShortVersionString']
127
128 cipd_license_path = os.path.join(
129 binaries_root, 'Contents/Resources/LicenseInfo.plist')
130 cipd_license_plist = plistlib.readPlist(cipd_license_path)
131 cipd_license_version = cipd_license_plist['licenseID']
132
133 should_overwrite_license = True
134 current_license_path = '/Library/Preferences/com.apple.dt.Xcode.plist'
135 if os.path.exists(current_license_path):
136 current_license_plist = plistlib.readPlist(current_license_path)
137 xcode_version = current_license_plist['IDEXcodeVersionForAgreedToGMLicense']
138 if (pkg_resources.parse_version(xcode_version) >=
139 pkg_resources.parse_version(cipd_xcode_version)):
140 should_overwrite_license = False
141
142 if not should_overwrite_license:
Erik Chen890362ea2019-07-22 22:43:48143 return 0
Erik Chenbc74094852019-07-17 21:47:00144
145 # Use puppet's sudoers script to accept the license if its available.
146 license_accept_script = '/usr/local/bin/xcode_accept_license.py'
147 if os.path.exists(license_accept_script):
Erik Chen687a9362019-07-23 03:47:06148 args = ['sudo', license_accept_script, '--xcode-version',
Erik Chenbc74094852019-07-17 21:47:00149 cipd_xcode_version, '--license-version', cipd_license_version]
Erik Chen687a9362019-07-23 03:47:06150 subprocess.check_call(args)
Erik Chen890362ea2019-07-22 22:43:48151 return 0
Erik Chenbc74094852019-07-17 21:47:00152
153 # Otherwise manually accept the license. This will prompt for sudo.
Erik Chenffc42752019-07-20 01:26:26154 print('Accepting new Xcode license. Requires sudo.')
155 sys.stdout.flush()
Erik Chenbc74094852019-07-17 21:47:00156 args = ['sudo', 'defaults', 'write', current_license_path,
157 'IDEXcodeVersionForAgreedToGMLicense', cipd_xcode_version]
Erik Chen687a9362019-07-23 03:47:06158 subprocess.check_call(args)
Erik Chenbc74094852019-07-17 21:47:00159 args = ['sudo', 'defaults', 'write', current_license_path,
160 'IDELastGMLicenseAgreedTo', cipd_license_version]
Erik Chen687a9362019-07-23 03:47:06161 subprocess.check_call(args)
Erik Chenbc74094852019-07-17 21:47:00162 args = ['sudo', 'plutil', '-convert', 'xml1', current_license_path]
Erik Chen687a9362019-07-23 03:47:06163 subprocess.check_call(args)
Erik Chenbc74094852019-07-17 21:47:00164
Erik Chen890362ea2019-07-22 22:43:48165 return 0
166
Erik Chenbc74094852019-07-17 21:47:00167
sdefresneaacc28452017-01-12 10:33:37168def main():
169 if sys.platform != 'darwin':
170 return 0
171
Sergey Berezin5654182d2018-04-30 21:24:49172 if not _UseHermeticToolchain():
Raul Tambre9e24293b2019-05-12 06:11:07173 print('Skipping Mac toolchain installation for mac')
Sergey Berezin5654182d2018-04-30 21:24:49174 return 0
erikchend5dfcdb02017-06-29 00:22:53175
Sergey Berezin5654182d2018-04-30 21:24:49176 if not PlatformMeetsHermeticXcodeRequirements():
Raul Tambre9e24293b2019-05-12 06:11:07177 print('OS version does not support toolchain.')
Sergey Berezin5654182d2018-04-30 21:24:49178 return 0
sdefresneaacc28452017-01-12 10:33:37179
Nico Weber6b9763fb2019-08-09 18:03:10180 # Delete obsolete hermetic full Xcode folder, the build now uses
181 # build/mac_files/xcode_binaries instead.
182 if os.path.exists(TOOLCHAIN_BUILD_DIR):
183 # TODO(thakis): Remove this after it's been here for a few months.
184 print('Deleting obsolete build/mac_files/Xcode.app...', end='')
185 sys.stdout.flush()
186 shutil.rmtree(TOOLCHAIN_BUILD_DIR)
187 print('done')
sdefresneaacc28452017-01-12 10:33:37188
Erik Chen890362ea2019-07-22 22:43:48189 return InstallXcodeBinaries()
sdefresneaacc28452017-01-12 10:33:37190
191
justincohen6a03a3d2016-03-26 21:44:38192if __name__ == '__main__':
193 sys.exit(main())