blob: ea62f28085c206ea161cc3520eba03c18a5ecabf [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
Erik Chen9a856e82019-07-27 01:40:2231# This contains binaries from Xcode 10.12.1, along with the 10.14 SDKs. To build
32# 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'
Erik Chen9a856e82019-07-27 01:40:2234MAC_BINARIES_TAG = 'hKD0dobc7nP5I5bX5OZ0v9GkUJXb7ADJO7SuK5070G8C'
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
erikchend5dfcdb02017-06-29 00:22:5345
Sergey Berezin5654182d2018-04-30 21:24:4946def PlatformMeetsHermeticXcodeRequirements():
Erik Chena537a9052018-11-13 01:44:4347 major_version = int(platform.release().split('.')[0])
Elly Fong-Jones69989872019-03-06 18:34:1148 return major_version >= MAC_MINIMUM_OS_VERSION
erikchend5dfcdb02017-06-29 00:22:5349
50
Sergey Berezin5654182d2018-04-30 21:24:4951def _UseHermeticToolchain():
erikchenda016262016-11-09 04:32:1352 current_dir = os.path.dirname(os.path.realpath(__file__))
53 script_path = os.path.join(current_dir, 'mac/should_use_hermetic_xcode.py')
Sergey Berezin5654182d2018-04-30 21:24:4954 proc = subprocess.Popen([script_path, 'mac'], stdout=subprocess.PIPE)
erikchenda016262016-11-09 04:32:1355 return '1' in proc.stdout.readline()
justincohen6a03a3d2016-03-26 21:44:3856
erikchenda016262016-11-09 04:32:1357
Sergey Berezin5654182d2018-04-30 21:24:4958def RequestCipdAuthentication():
59 """Requests that the user authenticate to access Xcode CIPD packages."""
60
Raul Tambre9e24293b2019-05-12 06:11:0761 print('Access to Xcode CIPD package requires authentication.')
62 print('-----------------------------------------------------------------')
63 print()
64 print('You appear to be a Googler.')
65 print()
66 print('I\'m sorry for the hassle, but you may need to do a one-time manual')
67 print('authentication. Please run:')
68 print()
69 print(' cipd auth-login')
70 print()
71 print('and follow the instructions.')
72 print()
73 print('NOTE: Use your google.com credentials, not chromium.org.')
74 print()
75 print('-----------------------------------------------------------------')
76 print()
erikchenda016262016-11-09 04:32:1377 sys.stdout.flush()
justincohen6a03a3d2016-03-26 21:44:3878
79
Sergey Berezin5654182d2018-04-30 21:24:4980def PrintError(message):
81 # Flush buffers to ensure correct output ordering.
82 sys.stdout.flush()
83 sys.stderr.write(message + '\n')
84 sys.stderr.flush()
justincohen6a03a3d2016-03-26 21:44:3885
justincohen6a03a3d2016-03-26 21:44:3886
Erik Chenbc74094852019-07-17 21:47:0087def InstallXcodeBinaries():
88 """Installs the Xcode binaries needed to build Chrome and accepts the license.
89
90 This is the replacement for InstallXcode that installs a trimmed down version
91 of Xcode that is OS-version agnostic.
92 """
93 # First make sure the directory exists. It will serve as the cipd root. This
94 # also ensures that there will be no conflicts of cipd root.
95 binaries_root = os.path.join(TOOLCHAIN_ROOT, 'xcode_binaries')
96 if not os.path.exists(binaries_root):
Nico Webera3d706d2019-08-09 23:04:3897 os.makedirs(binaries_root)
Erik Chenbc74094852019-07-17 21:47:0098
99 # 'cipd ensure' is idempotent.
100 args = [
101 'cipd', 'ensure', '-root', binaries_root, '-ensure-file', '-'
102 ]
Erik Chendea651342019-07-23 05:02:47103
104 # Buildbot slaves need to use explicit credentials. LUCI bots should NOT set
105 # this variable. This is temporary code used to make official Xcode bots
106 # happy. https://crbug.com/986488
107 creds = os.environ.get('MAC_TOOLCHAIN_CREDS')
108 if creds:
109 args.extend(['--service-account-json', creds])
110
Erik Chen890362ea2019-07-22 22:43:48111 p = subprocess.Popen(
112 args, stdin=subprocess.PIPE, stdout=subprocess.PIPE,
113 stderr=subprocess.PIPE)
114 stdout, stderr = p.communicate(
115 input=MAC_BINARIES_LABEL + ' ' + MAC_BINARIES_TAG)
116 if p.returncode != 0:
117 print(stdout)
118 print(stderr)
119 RequestCipdAuthentication()
120 return 1
Erik Chenbc74094852019-07-17 21:47:00121
122 # Accept the license for this version of Xcode if it's newer than the
123 # currently accepted version.
124 cipd_xcode_version_plist_path = os.path.join(
125 binaries_root, 'Contents/version.plist')
126 cipd_xcode_version_plist = plistlib.readPlist(cipd_xcode_version_plist_path)
127 cipd_xcode_version = cipd_xcode_version_plist['CFBundleShortVersionString']
128
129 cipd_license_path = os.path.join(
130 binaries_root, 'Contents/Resources/LicenseInfo.plist')
131 cipd_license_plist = plistlib.readPlist(cipd_license_path)
132 cipd_license_version = cipd_license_plist['licenseID']
133
134 should_overwrite_license = True
135 current_license_path = '/Library/Preferences/com.apple.dt.Xcode.plist'
136 if os.path.exists(current_license_path):
137 current_license_plist = plistlib.readPlist(current_license_path)
138 xcode_version = current_license_plist['IDEXcodeVersionForAgreedToGMLicense']
139 if (pkg_resources.parse_version(xcode_version) >=
140 pkg_resources.parse_version(cipd_xcode_version)):
141 should_overwrite_license = False
142
143 if not should_overwrite_license:
Erik Chen890362ea2019-07-22 22:43:48144 return 0
Erik Chenbc74094852019-07-17 21:47:00145
146 # Use puppet's sudoers script to accept the license if its available.
147 license_accept_script = '/usr/local/bin/xcode_accept_license.py'
148 if os.path.exists(license_accept_script):
Erik Chen687a9362019-07-23 03:47:06149 args = ['sudo', license_accept_script, '--xcode-version',
Erik Chenbc74094852019-07-17 21:47:00150 cipd_xcode_version, '--license-version', cipd_license_version]
Erik Chen687a9362019-07-23 03:47:06151 subprocess.check_call(args)
Erik Chen890362ea2019-07-22 22:43:48152 return 0
Erik Chenbc74094852019-07-17 21:47:00153
154 # Otherwise manually accept the license. This will prompt for sudo.
Erik Chenffc42752019-07-20 01:26:26155 print('Accepting new Xcode license. Requires sudo.')
156 sys.stdout.flush()
Erik Chenbc74094852019-07-17 21:47:00157 args = ['sudo', 'defaults', 'write', current_license_path,
158 'IDEXcodeVersionForAgreedToGMLicense', cipd_xcode_version]
Erik Chen687a9362019-07-23 03:47:06159 subprocess.check_call(args)
Erik Chenbc74094852019-07-17 21:47:00160 args = ['sudo', 'defaults', 'write', current_license_path,
161 'IDELastGMLicenseAgreedTo', cipd_license_version]
Erik Chen687a9362019-07-23 03:47:06162 subprocess.check_call(args)
Erik Chenbc74094852019-07-17 21:47:00163 args = ['sudo', 'plutil', '-convert', 'xml1', current_license_path]
Erik Chen687a9362019-07-23 03:47:06164 subprocess.check_call(args)
Erik Chenbc74094852019-07-17 21:47:00165
Erik Chen890362ea2019-07-22 22:43:48166 return 0
167
Erik Chenbc74094852019-07-17 21:47:00168
sdefresneaacc28452017-01-12 10:33:37169def main():
170 if sys.platform != 'darwin':
171 return 0
172
Sergey Berezin5654182d2018-04-30 21:24:49173 if not _UseHermeticToolchain():
Raul Tambre9e24293b2019-05-12 06:11:07174 print('Skipping Mac toolchain installation for mac')
Sergey Berezin5654182d2018-04-30 21:24:49175 return 0
erikchend5dfcdb02017-06-29 00:22:53176
Sergey Berezin5654182d2018-04-30 21:24:49177 if not PlatformMeetsHermeticXcodeRequirements():
Raul Tambre9e24293b2019-05-12 06:11:07178 print('OS version does not support toolchain.')
Sergey Berezin5654182d2018-04-30 21:24:49179 return 0
sdefresneaacc28452017-01-12 10:33:37180
Nico Weber6b9763fb2019-08-09 18:03:10181 # Delete obsolete hermetic full Xcode folder, the build now uses
182 # build/mac_files/xcode_binaries instead.
183 if os.path.exists(TOOLCHAIN_BUILD_DIR):
184 # TODO(thakis): Remove this after it's been here for a few months.
185 print('Deleting obsolete build/mac_files/Xcode.app...', end='')
186 sys.stdout.flush()
187 shutil.rmtree(TOOLCHAIN_BUILD_DIR)
188 print('done')
sdefresneaacc28452017-01-12 10:33:37189
Erik Chen890362ea2019-07-22 22:43:48190 return InstallXcodeBinaries()
sdefresneaacc28452017-01-12 10:33:37191
192
justincohen6a03a3d2016-03-26 21:44:38193if __name__ == '__main__':
194 sys.exit(main())