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

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 comments. 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 24 matching lines...) Expand all
105 """Loads Plist at |path| and returns it as a dictionary.""" 105 """Loads Plist at |path| and returns it as a dictionary."""
106 fd, name = tempfile.mkstemp() 106 fd, name = tempfile.mkstemp()
107 try: 107 try:
108 subprocess.check_call(['plutil', '-convert', 'xml1', '-o', name, path]) 108 subprocess.check_call(['plutil', '-convert', 'xml1', '-o', name, path])
109 with os.fdopen(fd, 'r') as f: 109 with os.fdopen(fd, 'r') as f:
110 return plistlib.readPlist(f) 110 return plistlib.readPlist(f)
111 finally: 111 finally:
112 os.unlink(name) 112 os.unlink(name)
113 113
114 114
115 def AcceptLicense(): 115 def AcceptLicense(target_os):
116 """Use xcodebuild to accept new toolchain license if necessary. Don't accept 116 """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 117 the license if a newer license has already been accepted. This only works if
118 xcodebuild and xcode-select are passwordless in sudoers.""" 118 xcodebuild and xcode-select are passwordless in sudoers."""
119 119
120 # Check old license 120 # Check old license
121 try: 121 try:
122 target_license_plist_path = \ 122 target_license_plist_path = \
123 os.path.join(TOOLCHAIN_BUILD_DIR, 123 os.path.join(TOOLCHAIN_BUILD_DIR % target_os,
124 *['Contents','Resources','LicenseInfo.plist']) 124 *['Contents','Resources','LicenseInfo.plist'])
125 target_license_plist = LoadPlist(target_license_plist_path) 125 target_license_plist = LoadPlist(target_license_plist_path)
126 build_type = target_license_plist['licenseType'] 126 build_type = target_license_plist['licenseType']
127 build_version = target_license_plist['licenseID'] 127 build_version = target_license_plist['licenseID']
128 128
129 accepted_license_plist = LoadPlist( 129 accepted_license_plist = LoadPlist(
130 '/Library/Preferences/com.apple.dt.Xcode.plist') 130 '/Library/Preferences/com.apple.dt.Xcode.plist')
131 agreed_to_key = 'IDELast%sLicenseAgreedTo' % build_type 131 agreed_to_key = 'IDELast%sLicenseAgreedTo' % build_type
132 last_license_agreed_to = accepted_license_plist[agreed_to_key] 132 last_license_agreed_to = accepted_license_plist[agreed_to_key]
133 133
134 # Historically all Xcode build numbers have been in the format of AANNNN, so 134 # 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 135 # a simple string compare works. If Xcode's build numbers change this may
136 # need a more complex compare. 136 # need a more complex compare.
137 if build_version <= last_license_agreed_to: 137 if build_version <= last_license_agreed_to:
138 # Don't accept the license of older toolchain builds, this will break the 138 # Don't accept the license of older toolchain builds, this will break the
139 # license of newer builds. 139 # license of newer builds.
140 return 140 return
141 except (subprocess.CalledProcessError, KeyError): 141 except (subprocess.CalledProcessError, KeyError):
142 # If there's never been a license of type |build_type| accepted, 142 # If there's never been a license of type |build_type| accepted,
143 # |target_license_plist_path| or |agreed_to_key| may not exist. 143 # |target_license_plist_path| or |agreed_to_key| may not exist.
144 pass 144 pass
145 145
146 print "Accepting license." 146 print "Accepting license."
147 old_path = subprocess.Popen(['/usr/bin/xcode-select', '-p'], 147 old_path = subprocess.Popen(['/usr/bin/xcode-select', '-p'],
148 stdout=subprocess.PIPE).communicate()[0].strip() 148 stdout=subprocess.PIPE).communicate()[0].strip()
149 try: 149 try:
150 build_dir = os.path.join(TOOLCHAIN_BUILD_DIR, 'Contents/Developer') 150 build_dir = os.path.join(
151 TOOLCHAIN_BUILD_DIR % target_os, 'Contents/Developer')
151 subprocess.check_call(['sudo', '/usr/bin/xcode-select', '-s', build_dir]) 152 subprocess.check_call(['sudo', '/usr/bin/xcode-select', '-s', build_dir])
152 subprocess.check_call(['sudo', '/usr/bin/xcodebuild', '-license', 'accept']) 153 subprocess.check_call(['sudo', '/usr/bin/xcodebuild', '-license', 'accept'])
153 finally: 154 finally:
154 subprocess.check_call(['sudo', '/usr/bin/xcode-select', '-s', old_path]) 155 subprocess.check_call(['sudo', '/usr/bin/xcode-select', '-s', old_path])
155 156
156 157
157 def _UseHermeticToolchain(): 158 def _UseHermeticToolchain(target_os):
158 current_dir = os.path.dirname(os.path.realpath(__file__)) 159 current_dir = os.path.dirname(os.path.realpath(__file__))
159 script_path = os.path.join(current_dir, 'mac/should_use_hermetic_xcode.py') 160 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) 161 proc = subprocess.Popen([script_path, target_os], stdout=subprocess.PIPE)
162 return '1' in proc.stdout.readline() 162 return '1' in proc.stdout.readline()
163 163
164 164
165 def RequestGsAuthentication(): 165 def RequestGsAuthentication():
166 """Requests that the user authenticate to be able to access gs://. 166 """Requests that the user authenticate to be able to access gs://.
167 """ 167 """
168 print 'Access to ' + TOOLCHAIN_URL + ' not configured.' 168 print 'Access to ' + TOOLCHAIN_URL + ' not configured.'
169 print '-----------------------------------------------------------------' 169 print '-----------------------------------------------------------------'
170 print 170 print
171 print 'You appear to be a Googler.' 171 print 'You appear to be a Googler.'
172 print 172 print
173 print 'I\'m sorry for the hassle, but you need to do a one-time manual' 173 print 'I\'m sorry for the hassle, but you need to do a one-time manual'
174 print 'authentication. Please run:' 174 print 'authentication. Please run:'
175 print 175 print
176 print ' download_from_google_storage --config' 176 print ' download_from_google_storage --config'
177 print 177 print
178 print 'and follow the instructions.' 178 print 'and follow the instructions.'
179 print 179 print
180 print 'NOTE 1: Use your google.com credentials, not chromium.org.' 180 print 'NOTE 1: Use your google.com credentials, not chromium.org.'
181 print 'NOTE 2: Enter 0 when asked for a "project-id".' 181 print 'NOTE 2: Enter 0 when asked for a "project-id".'
182 print 182 print
183 print '-----------------------------------------------------------------' 183 print '-----------------------------------------------------------------'
184 print 184 print
185 sys.stdout.flush() 185 sys.stdout.flush()
186 sys.exit(1) 186 sys.exit(1)
187 187
188 188
189 def main(): 189 def DownloadHermeticBuild(target_os, default_version, toolchain_filename):
190 if sys.platform != 'darwin': 190 if not _UseHermeticToolchain(target_os):
191 print 'Using local toolchain for %s.' % target_os
191 return 0 192 return 0
192 193
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', 194 toolchain_version = os.environ.get('MAC_TOOLCHAIN_REVISION',
205 default_version) 195 default_version)
206 196
207 if ReadStampFile() == toolchain_version: 197 if ReadStampFile(target_os) == toolchain_version:
208 print 'Toolchain (%s) is already up to date.' % toolchain_version 198 print 'Toolchain (%s) is already up to date.' % toolchain_version
209 AcceptLicense() 199 AcceptLicense(target_os)
210 return 0 200 return 0
211 201
212 if not CanAccessToolchainBucket(): 202 if not CanAccessToolchainBucket():
213 RequestGsAuthentication() 203 RequestGsAuthentication()
214 return 1 204 return 1
215 205
216 # Reset the stamp file in case the build is unsuccessful. 206 # Reset the stamp file in case the build is unsuccessful.
217 WriteStampFile('') 207 WriteStampFile(target_os, '')
218 208
219 toolchain_file = '%s.tgz' % toolchain_version 209 toolchain_file = '%s.tgz' % toolchain_version
220 toolchain_full_url = TOOLCHAIN_URL + toolchain_file 210 toolchain_full_url = TOOLCHAIN_URL + toolchain_file
221 211
222 print 'Updating toolchain to %s...' % toolchain_version 212 print 'Updating toolchain to %s...' % toolchain_version
223 try: 213 try:
224 toolchain_file = toolchain_filename % toolchain_version 214 toolchain_file = toolchain_filename % toolchain_version
225 toolchain_full_url = TOOLCHAIN_URL + toolchain_file 215 toolchain_full_url = TOOLCHAIN_URL + toolchain_file
226 DownloadAndUnpack(toolchain_full_url, TOOLCHAIN_BUILD_DIR) 216 DownloadAndUnpack(toolchain_full_url, TOOLCHAIN_BUILD_DIR % target_os)
227 AcceptLicense() 217 AcceptLicense(target_os)
228 218
229 print 'Toolchain %s unpacked.' % toolchain_version 219 print 'Toolchain %s unpacked.' % toolchain_version
230 WriteStampFile(toolchain_version) 220 WriteStampFile(target_os, toolchain_version)
231 return 0 221 return 0
232 except Exception as e: 222 except Exception as e:
233 print 'Failed to download toolchain %s.' % toolchain_file 223 print 'Failed to download toolchain %s.' % toolchain_file
234 print 'Exception %s' % e 224 print 'Exception %s' % e
235 print 'Exiting.' 225 print 'Exiting.'
236 return 1 226 return 1
237 227
228
229 def main():
230 if sys.platform != 'darwin':
231 return 0
232
233 for target_os in GetPlatforms():
234 if target_os == "ios":
235 default_version = IOS_TOOLCHAIN_VERSION
236 toolchain_filename = 'ios-toolchain-%s.tgz'
237 else:
238 default_version = MAC_TOOLCHAIN_VERSION
239 toolchain_filename = 'toolchain-%s.tgz'
240
241 return_value = DownloadHermeticBuild(
242 target_os, default_version, toolchain_filename)
243 if return_value != 0:
244 return_value
justincohen 2017/01/11 14:40:57 return return return value value value.
sdefresne 2017/01/11 14:44:44 My brain was convinced there were enough returns t
245
246 return 0
247
248
238 if __name__ == '__main__': 249 if __name__ == '__main__':
239 sys.exit(main()) 250 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