[M120 Migration][Gamepad]Add gamepad event latency Test code
[platform/framework/web/chromium-efl.git] / build / mac_toolchain.py
1 #!/usr/bin/env python3
2
3 # Copyright 2018 The Chromium Authors
4 # Use of this source code is governed by a BSD-style license that can be
5 # found in the LICENSE file.
6
7 """
8 If should_use_hermetic_xcode.py emits "1", and the current toolchain is out of
9 date:
10   * Downloads the hermetic mac toolchain
11     * Requires CIPD authentication. Run `cipd auth-login`, use Google account.
12   * Accepts the license.
13     * If xcode-select and xcodebuild are not passwordless in sudoers, requires
14       user interaction.
15   * Downloads standalone binaries from [a possibly different version of Xcode].
16
17 The toolchain version can be overridden by setting MAC_TOOLCHAIN_REVISION with
18 the full revision, e.g. 9A235.
19 """
20
21 import argparse
22 import os
23 import platform
24 import plistlib
25 import shutil
26 import subprocess
27 import sys
28
29
30 def LoadPList(path):
31   """Loads Plist at |path| and returns it as a dictionary."""
32   with open(path, 'rb') as f:
33     return plistlib.load(f)
34
35
36 # This contains binaries from Xcode 15.0 15A240d along with the macOS 14.0 SDK
37 # (14.0 23A334). To build these packages, see comments in
38 # build/xcode_binaries.yaml
39 # To update the version numbers, open Xcode's "About Xcode" for the first number
40 # and run `xcrun --show-sdk-build-version` for the second.
41 # To update the _TAG, use the output of the `cipd create` command mentioned in
42 # xcode_binaries.yaml.
43
44 MAC_BINARIES_LABEL = 'infra_internal/ios/xcode/xcode_binaries/mac-amd64'
45 MAC_BINARIES_TAG = 'dC_BLs9U850OLk8m4V7yxysPhP-ixJ2b5c7hVm8B7tIC'
46
47 # The toolchain will not be downloaded if the minimum OS version is not met. 19
48 # is the major version number for macOS 10.15. Xcode 15.0 only runs on macOS
49 # 13.5 and newer, but some bots are still running older OS versions. macOS
50 # 10.15.4, the OS minimum through Xcode 12.4, still seems to work.
51 MAC_MINIMUM_OS_VERSION = [19, 4]
52
53 BASE_DIR = os.path.abspath(os.path.dirname(__file__))
54 TOOLCHAIN_ROOT = os.path.join(BASE_DIR, 'mac_files')
55 TOOLCHAIN_BUILD_DIR = os.path.join(TOOLCHAIN_ROOT, 'Xcode.app')
56
57 # Always integrity-check the entire SDK. Mac SDK packages are complex and often
58 # hit edge cases in cipd (eg https://crbug.com/1033987,
59 # https://crbug.com/915278), and generally when this happens it requires manual
60 # intervention to fix.
61 # Note the trailing \n!
62 PARANOID_MODE = '$ParanoidMode CheckIntegrity\n'
63
64
65 def PlatformMeetsHermeticXcodeRequirements():
66   if sys.platform != 'darwin':
67     return True
68   needed = MAC_MINIMUM_OS_VERSION
69   major_version = [int(v) for v in platform.release().split('.')[:len(needed)]]
70   return major_version >= needed
71
72
73 def _UseHermeticToolchain():
74   current_dir = os.path.dirname(os.path.realpath(__file__))
75   script_path = os.path.join(current_dir, 'mac/should_use_hermetic_xcode.py')
76   proc = subprocess.Popen([script_path, 'mac'], stdout=subprocess.PIPE)
77   return '1' in proc.stdout.readline().decode()
78
79
80 def RequestCipdAuthentication():
81   """Requests that the user authenticate to access Xcode CIPD packages."""
82
83   print('Access to Xcode CIPD package requires authentication.')
84   print('-----------------------------------------------------------------')
85   print()
86   print('You appear to be a Googler.')
87   print()
88   print('I\'m sorry for the hassle, but you may need to do a one-time manual')
89   print('authentication. Please run:')
90   print()
91   print('    cipd auth-login')
92   print()
93   print('and follow the instructions.')
94   print()
95   print('NOTE: Use your google.com credentials, not chromium.org.')
96   print()
97   print('-----------------------------------------------------------------')
98   print()
99   sys.stdout.flush()
100
101
102 def PrintError(message):
103   # Flush buffers to ensure correct output ordering.
104   sys.stdout.flush()
105   sys.stderr.write(message + '\n')
106   sys.stderr.flush()
107
108
109 def InstallXcodeBinaries():
110   """Installs the Xcode binaries needed to build Chrome and accepts the license.
111
112   This is the replacement for InstallXcode that installs a trimmed down version
113   of Xcode that is OS-version agnostic.
114   """
115   # First make sure the directory exists. It will serve as the cipd root. This
116   # also ensures that there will be no conflicts of cipd root.
117   binaries_root = os.path.join(TOOLCHAIN_ROOT, 'xcode_binaries')
118   if not os.path.exists(binaries_root):
119     os.makedirs(binaries_root)
120
121   # 'cipd ensure' is idempotent.
122   args = ['cipd', 'ensure', '-root', binaries_root, '-ensure-file', '-']
123
124   p = subprocess.Popen(args,
125                        universal_newlines=True,
126                        stdin=subprocess.PIPE,
127                        stdout=subprocess.PIPE,
128                        stderr=subprocess.PIPE)
129   stdout, stderr = p.communicate(input=PARANOID_MODE + MAC_BINARIES_LABEL +
130                                  ' ' + MAC_BINARIES_TAG)
131   if p.returncode != 0:
132     print(stdout)
133     print(stderr)
134     RequestCipdAuthentication()
135     return 1
136
137   if sys.platform != 'darwin':
138     return 0
139
140   # Accept the license for this version of Xcode if it's newer than the
141   # currently accepted version.
142   cipd_xcode_version_plist_path = os.path.join(binaries_root,
143                                                'Contents/version.plist')
144   cipd_xcode_version_plist = LoadPList(cipd_xcode_version_plist_path)
145   cipd_xcode_version = cipd_xcode_version_plist['CFBundleShortVersionString']
146
147   cipd_license_path = os.path.join(binaries_root,
148                                    'Contents/Resources/LicenseInfo.plist')
149   cipd_license_plist = LoadPList(cipd_license_path)
150   cipd_license_version = cipd_license_plist['licenseID']
151
152   should_overwrite_license = True
153   current_license_path = '/Library/Preferences/com.apple.dt.Xcode.plist'
154   if os.path.exists(current_license_path):
155     current_license_plist = LoadPList(current_license_path)
156     xcode_version = current_license_plist.get(
157         'IDEXcodeVersionForAgreedToGMLicense')
158     if (xcode_version is not None
159         and xcode_version.split('.') >= cipd_xcode_version.split('.')):
160       should_overwrite_license = False
161
162   if not should_overwrite_license:
163     return 0
164
165   # Use puppet's sudoers script to accept the license if its available.
166   license_accept_script = '/usr/local/bin/xcode_accept_license.sh'
167   if os.path.exists(license_accept_script):
168     args = [
169         'sudo', license_accept_script, cipd_xcode_version, cipd_license_version
170     ]
171     subprocess.check_call(args)
172     return 0
173
174   # Otherwise manually accept the license. This will prompt for sudo.
175   print('Accepting new Xcode license. Requires sudo.')
176   sys.stdout.flush()
177   args = [
178       'sudo', 'defaults', 'write', current_license_path,
179       'IDEXcodeVersionForAgreedToGMLicense', cipd_xcode_version
180   ]
181   subprocess.check_call(args)
182   args = [
183       'sudo', 'defaults', 'write', current_license_path,
184       'IDELastGMLicenseAgreedTo', cipd_license_version
185   ]
186   subprocess.check_call(args)
187   args = ['sudo', 'plutil', '-convert', 'xml1', current_license_path]
188   subprocess.check_call(args)
189
190   return 0
191
192
193 def main():
194   if not _UseHermeticToolchain():
195     print('Skipping Mac toolchain installation for mac')
196     return 0
197
198   parser = argparse.ArgumentParser(description='Download hermetic Xcode.')
199   args = parser.parse_args()
200
201   if not PlatformMeetsHermeticXcodeRequirements():
202     print('OS version does not support toolchain.')
203     return 0
204
205   return InstallXcodeBinaries()
206
207
208 if __name__ == '__main__':
209   sys.exit(main())