Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(231)

Side by Side Diff: build/mac_toolchain.py

Issue 2626063002: Allow using the same checkout to build both iOS and macOS. (Closed)
Patch Set: Address nitpick. Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « .gitignore ('k') | build/toolchain/toolchain.gni » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # Copyright 2016 The Chromium Authors. All rights reserved. 2 # Copyright 2016 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be 3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file. 4 # found in the LICENSE file.
5 5
6 """ 6 """
7 If should_use_hermetic_xcode.py emits "1", and the current toolchain is out of 7 If should_use_hermetic_xcode.py emits "1", and the current toolchain is out of
8 date: 8 date:
9 * Downloads the hermetic mac toolchain 9 * Downloads the hermetic mac toolchain
10 * Requires gsutil to be configured. 10 * Requires gsutil to be configured.
(...skipping 22 matching lines...) Expand all
33 IOS_TOOLCHAIN_VERSION = '%s-%s' % (IOS_TOOLCHAIN_VERSION, 33 IOS_TOOLCHAIN_VERSION = '%s-%s' % (IOS_TOOLCHAIN_VERSION,
34 IOS_TOOLCHAIN_SUB_REVISION) 34 IOS_TOOLCHAIN_SUB_REVISION)
35 35
36 # Absolute path to src/ directory. 36 # Absolute path to src/ directory.
37 REPO_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 37 REPO_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
38 38
39 # Absolute path to a file with gclient solutions. 39 # Absolute path to a file with gclient solutions.
40 GCLIENT_CONFIG = os.path.join(os.path.dirname(REPO_ROOT), '.gclient') 40 GCLIENT_CONFIG = os.path.join(os.path.dirname(REPO_ROOT), '.gclient')
41 41
42 BASE_DIR = os.path.abspath(os.path.dirname(__file__)) 42 BASE_DIR = os.path.abspath(os.path.dirname(__file__))
43 TOOLCHAIN_BUILD_DIR = os.path.join(BASE_DIR, 'mac_files', 'Xcode.app') 43 TOOLCHAIN_BUILD_DIR = os.path.join(BASE_DIR, '%s_files', 'Xcode.app')
44 STAMP_FILE = os.path.join(BASE_DIR, 'mac_files', 'toolchain_build_revision') 44 STAMP_FILE = os.path.join(BASE_DIR, '%s_files', 'toolchain_build_revision')
45 TOOLCHAIN_URL = 'gs://chrome-mac-sdk/' 45 TOOLCHAIN_URL = 'gs://chrome-mac-sdk/'
46 46
47 def IsIOSPlatform(): 47 def GetPlatforms():
48 default_target_os = ["mac"]
48 try: 49 try:
49 env = {} 50 env = {}
50 execfile(GCLIENT_CONFIG, env, env) 51 execfile(GCLIENT_CONFIG, env, env)
51 if 'ios' in env.get('target_os', []): 52 return env.get('target_os', default_target_os)
52 return True
53 except: 53 except:
54 pass 54 pass
55 return False 55 return default_target_os
56 56
57 57
58 def ReadStampFile(): 58 def ReadStampFile(target_os):
59 """Return the contents of the stamp file, or '' if it doesn't exist.""" 59 """Return the contents of the stamp file, or '' if it doesn't exist."""
60 try: 60 try:
61 with open(STAMP_FILE, 'r') as f: 61 with open(STAMP_FILE % target_os, 'r') as f:
62 return f.read().rstrip() 62 return f.read().rstrip()
63 except IOError: 63 except IOError:
64 return '' 64 return ''
65 65
66 66
67 def WriteStampFile(s): 67 def WriteStampFile(target_os, s):
68 """Write s to the stamp file.""" 68 """Write s to the stamp file."""
69 EnsureDirExists(os.path.dirname(STAMP_FILE)) 69 EnsureDirExists(os.path.dirname(STAMP_FILE % target_os))
70 with open(STAMP_FILE, 'w') as f: 70 with open(STAMP_FILE % target_os, 'w') as f:
71 f.write(s) 71 f.write(s)
72 f.write('\n') 72 f.write('\n')
73 73
74 74
75 def EnsureDirExists(path): 75 def EnsureDirExists(path):
76 if not os.path.exists(path): 76 if not os.path.exists(path):
77 os.makedirs(path) 77 os.makedirs(path)
78 78
79 79
80 def DownloadAndUnpack(url, output_dir): 80 def DownloadAndUnpack(url, output_dir):
(...skipping 13 matching lines...) Expand all
94 os.unlink(temp_name) 94 os.unlink(temp_name)
95 95
96 96
97 def CanAccessToolchainBucket(): 97 def CanAccessToolchainBucket():
98 """Checks whether the user has access to |TOOLCHAIN_URL|.""" 98 """Checks whether the user has access to |TOOLCHAIN_URL|."""
99 proc = subprocess.Popen(['gsutil.py', 'ls', TOOLCHAIN_URL], 99 proc = subprocess.Popen(['gsutil.py', 'ls', TOOLCHAIN_URL],
100 stdout=subprocess.PIPE) 100 stdout=subprocess.PIPE)
101 proc.communicate() 101 proc.communicate()
102 return proc.returncode == 0 102 return proc.returncode == 0
103 103
104
104 def LoadPlist(path): 105 def LoadPlist(path):
105 """Loads Plist at |path| and returns it as a dictionary.""" 106 """Loads Plist at |path| and returns it as a dictionary."""
106 fd, name = tempfile.mkstemp() 107 fd, name = tempfile.mkstemp()
107 try: 108 try:
108 subprocess.check_call(['plutil', '-convert', 'xml1', '-o', name, path]) 109 subprocess.check_call(['plutil', '-convert', 'xml1', '-o', name, path])
109 with os.fdopen(fd, 'r') as f: 110 with os.fdopen(fd, 'r') as f:
110 return plistlib.readPlist(f) 111 return plistlib.readPlist(f)
111 finally: 112 finally:
112 os.unlink(name) 113 os.unlink(name)
113 114
114 115
115 def AcceptLicense(): 116 def AcceptLicense(target_os):
116 """Use xcodebuild to accept new toolchain license if necessary. Don't accept 117 """Use xcodebuild to accept new toolchain license if necessary. Don't accept
117 the license if a newer license has already been accepted. This only works if 118 the license if a newer license has already been accepted. This only works if
118 xcodebuild and xcode-select are passwordless in sudoers.""" 119 xcodebuild and xcode-select are passwordless in sudoers."""
119 120
120 # Check old license 121 # Check old license
121 try: 122 try:
122 target_license_plist_path = \ 123 target_license_plist_path = \
123 os.path.join(TOOLCHAIN_BUILD_DIR, 124 os.path.join(TOOLCHAIN_BUILD_DIR % target_os,
124 *['Contents','Resources','LicenseInfo.plist']) 125 *['Contents','Resources','LicenseInfo.plist'])
125 target_license_plist = LoadPlist(target_license_plist_path) 126 target_license_plist = LoadPlist(target_license_plist_path)
126 build_type = target_license_plist['licenseType'] 127 build_type = target_license_plist['licenseType']
127 build_version = target_license_plist['licenseID'] 128 build_version = target_license_plist['licenseID']
128 129
129 accepted_license_plist = LoadPlist( 130 accepted_license_plist = LoadPlist(
130 '/Library/Preferences/com.apple.dt.Xcode.plist') 131 '/Library/Preferences/com.apple.dt.Xcode.plist')
131 agreed_to_key = 'IDELast%sLicenseAgreedTo' % build_type 132 agreed_to_key = 'IDELast%sLicenseAgreedTo' % build_type
132 last_license_agreed_to = accepted_license_plist[agreed_to_key] 133 last_license_agreed_to = accepted_license_plist[agreed_to_key]
133 134
134 # Historically all Xcode build numbers have been in the format of AANNNN, so 135 # Historically all Xcode build numbers have been in the format of AANNNN, so
135 # a simple string compare works. If Xcode's build numbers change this may 136 # a simple string compare works. If Xcode's build numbers change this may
136 # need a more complex compare. 137 # need a more complex compare.
137 if build_version <= last_license_agreed_to: 138 if build_version <= last_license_agreed_to:
138 # Don't accept the license of older toolchain builds, this will break the 139 # Don't accept the license of older toolchain builds, this will break the
139 # license of newer builds. 140 # license of newer builds.
140 return 141 return
141 except (subprocess.CalledProcessError, KeyError): 142 except (subprocess.CalledProcessError, KeyError):
142 # If there's never been a license of type |build_type| accepted, 143 # If there's never been a license of type |build_type| accepted,
143 # |target_license_plist_path| or |agreed_to_key| may not exist. 144 # |target_license_plist_path| or |agreed_to_key| may not exist.
144 pass 145 pass
145 146
146 print "Accepting license." 147 print "Accepting license."
147 old_path = subprocess.Popen(['/usr/bin/xcode-select', '-p'], 148 old_path = subprocess.Popen(['/usr/bin/xcode-select', '-p'],
148 stdout=subprocess.PIPE).communicate()[0].strip() 149 stdout=subprocess.PIPE).communicate()[0].strip()
149 try: 150 try:
150 build_dir = os.path.join(TOOLCHAIN_BUILD_DIR, 'Contents/Developer') 151 build_dir = os.path.join(
152 TOOLCHAIN_BUILD_DIR % target_os, 'Contents/Developer')
151 subprocess.check_call(['sudo', '/usr/bin/xcode-select', '-s', build_dir]) 153 subprocess.check_call(['sudo', '/usr/bin/xcode-select', '-s', build_dir])
152 subprocess.check_call(['sudo', '/usr/bin/xcodebuild', '-license', 'accept']) 154 subprocess.check_call(['sudo', '/usr/bin/xcodebuild', '-license', 'accept'])
153 finally: 155 finally:
154 subprocess.check_call(['sudo', '/usr/bin/xcode-select', '-s', old_path]) 156 subprocess.check_call(['sudo', '/usr/bin/xcode-select', '-s', old_path])
155 157
156 158
157 def _UseHermeticToolchain(): 159 def _UseHermeticToolchain(target_os):
158 current_dir = os.path.dirname(os.path.realpath(__file__)) 160 current_dir = os.path.dirname(os.path.realpath(__file__))
159 script_path = os.path.join(current_dir, 'mac/should_use_hermetic_xcode.py') 161 script_path = os.path.join(current_dir, 'mac/should_use_hermetic_xcode.py')
160 target_os = 'ios' if IsIOSPlatform() else 'mac'
161 proc = subprocess.Popen([script_path, target_os], stdout=subprocess.PIPE) 162 proc = subprocess.Popen([script_path, target_os], stdout=subprocess.PIPE)
162 return '1' in proc.stdout.readline() 163 return '1' in proc.stdout.readline()
163 164
164 165
165 def RequestGsAuthentication(): 166 def RequestGsAuthentication():
166 """Requests that the user authenticate to be able to access gs://. 167 """Requests that the user authenticate to be able to access gs://.
167 """ 168 """
168 print 'Access to ' + TOOLCHAIN_URL + ' not configured.' 169 print 'Access to ' + TOOLCHAIN_URL + ' not configured.'
169 print '-----------------------------------------------------------------' 170 print '-----------------------------------------------------------------'
170 print 171 print
171 print 'You appear to be a Googler.' 172 print 'You appear to be a Googler.'
172 print 173 print
173 print 'I\'m sorry for the hassle, but you need to do a one-time manual' 174 print 'I\'m sorry for the hassle, but you need to do a one-time manual'
174 print 'authentication. Please run:' 175 print 'authentication. Please run:'
175 print 176 print
176 print ' download_from_google_storage --config' 177 print ' download_from_google_storage --config'
177 print 178 print
178 print 'and follow the instructions.' 179 print 'and follow the instructions.'
179 print 180 print
180 print 'NOTE 1: Use your google.com credentials, not chromium.org.' 181 print 'NOTE 1: Use your google.com credentials, not chromium.org.'
181 print 'NOTE 2: Enter 0 when asked for a "project-id".' 182 print 'NOTE 2: Enter 0 when asked for a "project-id".'
182 print 183 print
183 print '-----------------------------------------------------------------' 184 print '-----------------------------------------------------------------'
184 print 185 print
185 sys.stdout.flush() 186 sys.stdout.flush()
186 sys.exit(1) 187 sys.exit(1)
187 188
188 189
189 def main(): 190 def DownloadHermeticBuild(target_os, default_version, toolchain_filename):
190 if sys.platform != 'darwin': 191 if not _UseHermeticToolchain(target_os):
192 print 'Using local toolchain for %s.' % target_os
191 return 0 193 return 0
192 194
193 if not _UseHermeticToolchain():
194 print 'Using local toolchain.'
195 return 0
196
197 if IsIOSPlatform():
198 default_version = IOS_TOOLCHAIN_VERSION
199 toolchain_filename = 'ios-toolchain-%s.tgz'
200 else:
201 default_version = MAC_TOOLCHAIN_VERSION
202 toolchain_filename = 'toolchain-%s.tgz'
203
204 toolchain_version = os.environ.get('MAC_TOOLCHAIN_REVISION', 195 toolchain_version = os.environ.get('MAC_TOOLCHAIN_REVISION',
205 default_version) 196 default_version)
206 197
207 if ReadStampFile() == toolchain_version: 198 if ReadStampFile(target_os) == toolchain_version:
208 print 'Toolchain (%s) is already up to date.' % toolchain_version 199 print 'Toolchain (%s) is already up to date.' % toolchain_version
209 AcceptLicense() 200 AcceptLicense(target_os)
210 return 0 201 return 0
211 202
212 if not CanAccessToolchainBucket(): 203 if not CanAccessToolchainBucket():
213 RequestGsAuthentication() 204 RequestGsAuthentication()
214 return 1 205 return 1
215 206
216 # Reset the stamp file in case the build is unsuccessful. 207 # Reset the stamp file in case the build is unsuccessful.
217 WriteStampFile('') 208 WriteStampFile(target_os, '')
218 209
219 toolchain_file = '%s.tgz' % toolchain_version 210 toolchain_file = '%s.tgz' % toolchain_version
220 toolchain_full_url = TOOLCHAIN_URL + toolchain_file 211 toolchain_full_url = TOOLCHAIN_URL + toolchain_file
221 212
222 print 'Updating toolchain to %s...' % toolchain_version 213 print 'Updating toolchain to %s...' % toolchain_version
223 try: 214 try:
224 toolchain_file = toolchain_filename % toolchain_version 215 toolchain_file = toolchain_filename % toolchain_version
225 toolchain_full_url = TOOLCHAIN_URL + toolchain_file 216 toolchain_full_url = TOOLCHAIN_URL + toolchain_file
226 DownloadAndUnpack(toolchain_full_url, TOOLCHAIN_BUILD_DIR) 217 DownloadAndUnpack(toolchain_full_url, TOOLCHAIN_BUILD_DIR % target_os)
227 AcceptLicense() 218 AcceptLicense(target_os)
228 219
229 print 'Toolchain %s unpacked.' % toolchain_version 220 print 'Toolchain %s unpacked.' % toolchain_version
230 WriteStampFile(toolchain_version) 221 WriteStampFile(target_os, toolchain_version)
231 return 0 222 return 0
232 except Exception as e: 223 except Exception as e:
233 print 'Failed to download toolchain %s.' % toolchain_file 224 print 'Failed to download toolchain %s.' % toolchain_file
234 print 'Exception %s' % e 225 print 'Exception %s' % e
235 print 'Exiting.' 226 print 'Exiting.'
236 return 1 227 return 1
237 228
229
230 def main():
231 if sys.platform != 'darwin':
232 return 0
233
234 for target_os in GetPlatforms():
235 if target_os == 'ios':
236 default_version = IOS_TOOLCHAIN_VERSION
237 toolchain_filename = 'ios-toolchain-%s.tgz'
238 else:
239 default_version = MAC_TOOLCHAIN_VERSION
240 toolchain_filename = 'toolchain-%s.tgz'
241
242 return_value = DownloadHermeticBuild(
243 target_os, default_version, toolchain_filename)
244 if return_value:
245 return return_value
246
247 return 0
248
249
238 if __name__ == '__main__': 250 if __name__ == '__main__':
239 sys.exit(main()) 251 sys.exit(main())
OLDNEW
« no previous file with comments | « .gitignore ('k') | build/toolchain/toolchain.gni » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698