OLD | NEW |
---|---|
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # Copyright 2013 The Chromium Authors. All rights reserved. | 2 # Copyright 2013 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 """Extracts a Windows VS2013 toolchain from various downloadable pieces.""" | 6 """Extracts a Windows VS2013 toolchain from various downloadable pieces.""" |
7 | 7 |
8 | 8 |
9 import ctypes | 9 import ctypes |
10 import optparse | 10 import optparse |
11 import os | 11 import os |
12 import shutil | 12 import shutil |
13 import subprocess | 13 import subprocess |
14 import sys | 14 import sys |
15 import tempfile | 15 import tempfile |
16 import urllib2 | 16 import urllib2 |
17 | 17 |
18 | 18 |
19 BASEDIR = os.path.dirname(os.path.abspath(__file__)) | 19 BASEDIR = os.path.dirname(os.path.abspath(__file__)) |
20 WDK_ISO_URL = ( | |
21 'http://download.microsoft.com/download/' | |
22 '4/A/2/4A25C7D5-EFBE-4182-B6A9-AE6850409A78/GRMWDK_EN_7600_1.ISO') | |
20 g_temp_dirs = [] | 23 g_temp_dirs = [] |
21 | 24 |
22 | 25 |
23 sys.path.append(os.path.join(BASEDIR, '..')) | 26 sys.path.append(os.path.join(BASEDIR, '..')) |
24 import download_from_google_storage | 27 import download_from_google_storage |
25 | 28 |
26 | 29 |
27 def GetLongPathName(path): | 30 def GetLongPathName(path): |
28 """Converts any 8dot3 names in the path to the full name.""" | 31 """Converts any 8dot3 names in the path to the full name.""" |
29 buf = ctypes.create_unicode_buffer(260) | 32 buf = ctypes.create_unicode_buffer(260) |
(...skipping 20 matching lines...) Expand all Loading... | |
50 """Removes all temporary directories created by |TempDir()|.""" | 53 """Removes all temporary directories created by |TempDir()|.""" |
51 global g_temp_dirs | 54 global g_temp_dirs |
52 if g_temp_dirs: | 55 if g_temp_dirs: |
53 sys.stdout.write('Cleaning up temporaries...\n') | 56 sys.stdout.write('Cleaning up temporaries...\n') |
54 for temp in g_temp_dirs: | 57 for temp in g_temp_dirs: |
55 # shutil.rmtree errors out on read only attributes. | 58 # shutil.rmtree errors out on read only attributes. |
56 RunOrDie('rmdir /s/q "%s"' % temp) | 59 RunOrDie('rmdir /s/q "%s"' % temp) |
57 g_temp_dirs = [] | 60 g_temp_dirs = [] |
58 | 61 |
59 | 62 |
60 def GetIsoUrl(pro): | 63 def GetMainIsoUrl(pro): |
61 """Gets the .iso URL. | 64 """Gets the main .iso URL. |
62 | 65 |
63 If |pro| is False, downloads the Express edition. If |CHROME_HEADLESS| is | 66 If |pro| is False, downloads the Express edition. If |CHROME_HEADLESS| is |
64 set in the environment, then we assume we're on an internal bot, and download | 67 set in the environment, then we assume we're on an internal bot, and download |
65 from internal google storage instead. | 68 from internal google storage instead. |
66 """ | 69 """ |
67 prefix = 'http://download.microsoft.com/download/' | 70 prefix = 'http://download.microsoft.com/download/' |
68 if pro: | 71 if pro: |
69 return (prefix + | 72 return (prefix + |
70 'A/F/1/AF128362-A6A8-4DB3-A39A-C348086472CC/VS2013_RTM_PRO_ENU.iso') | 73 'A/F/1/AF128362-A6A8-4DB3-A39A-C348086472CC/VS2013_RTM_PRO_ENU.iso') |
71 else: | 74 else: |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
144 Download( | 147 Download( |
145 ('http://download.microsoft.com/download/' | 148 ('http://download.microsoft.com/download/' |
146 'F/1/3/F1300C9C-A120-4341-90DF-8A52509B23AC/standalonesdk/sdksetup.exe'), | 149 'F/1/3/F1300C9C-A120-4341-90DF-8A52509B23AC/standalonesdk/sdksetup.exe'), |
147 target_path) | 150 target_path) |
148 sys.stdout.write( | 151 sys.stdout.write( |
149 'Running sdksetup.exe to download Win8 SDK (may request elevation)...\n') | 152 'Running sdksetup.exe to download Win8 SDK (may request elevation)...\n') |
150 count = 0 | 153 count = 0 |
151 while count < 5: | 154 while count < 5: |
152 rc = os.system(target_path + ' /quiet ' | 155 rc = os.system(target_path + ' /quiet ' |
153 '/features OptionId.WindowsDesktopDebuggers ' | 156 '/features OptionId.WindowsDesktopDebuggers ' |
157 'OptionId.WindowsDesktopSoftwareDevelopmentKit ' | |
154 '/layout ' + standalone_path) | 158 '/layout ' + standalone_path) |
155 if rc == 0: | 159 if rc == 0: |
156 return standalone_path | 160 return standalone_path |
157 count += 1 | 161 count += 1 |
158 sys.stdout.write('Windows 8 SDK failed to download, retrying.\n') | 162 sys.stdout.write('Windows 8 SDK failed to download, retrying.\n') |
159 sys.exit('After multiple retries, couldn\'t download Win8 SDK') | 163 sys.exit('After multiple retries, couldn\'t download Win8 SDK') |
160 | 164 |
161 | 165 |
166 def DownloadWDKIso(): | |
167 wdk_temp_dir = TempDir() | |
168 target_path = os.path.join(wdk_temp_dir, 'GRMWDK_EN_7600_1.ISO') | |
169 Download(WDK_ISO_URL, target_path) | |
170 return target_path | |
171 | |
172 | |
162 def DownloadUsingGsutil(filename): | 173 def DownloadUsingGsutil(filename): |
163 """Downloads the given file from Google Storage chrome-wintoolchain bucket.""" | 174 """Downloads the given file from Google Storage chrome-wintoolchain bucket.""" |
164 temp_dir = TempDir() | 175 temp_dir = TempDir() |
165 assert os.path.basename(filename) == filename | 176 assert os.path.basename(filename) == filename |
166 target_path = os.path.join(temp_dir, filename) | 177 target_path = os.path.join(temp_dir, filename) |
167 gsutil = download_from_google_storage.Gsutil( | 178 gsutil = download_from_google_storage.Gsutil( |
168 download_from_google_storage.GSUTIL_DEFAULT_PATH, boto_path=None) | 179 download_from_google_storage.GSUTIL_DEFAULT_PATH, boto_path=None) |
169 code = gsutil.call('cp', 'gs://chrome-wintoolchain/' + filename, target_path) | 180 code = gsutil.call('cp', 'gs://chrome-wintoolchain/' + filename, target_path) |
170 if code != 0: | 181 if code != 0: |
171 sys.exit('gsutil failed') | 182 sys.exit('gsutil failed') |
172 return target_path | 183 return target_path |
173 | 184 |
174 | 185 |
175 def GetVSInternal(): | 186 def GetVSInternal(): |
176 """Uses gsutil to pull the toolchain from internal Google Storage bucket.""" | 187 """Uses gsutil to pull the toolchain from internal Google Storage bucket.""" |
177 return DownloadUsingGsutil('VS2013_RTM_PRO_ENU.iso') | 188 return DownloadUsingGsutil('VS2013_RTM_PRO_ENU.iso') |
178 | 189 |
179 | 190 |
180 def GetSDKInternal(): | 191 def GetSDKInternal(): |
181 """Downloads a zipped copy of the SDK from internal Google Storage bucket, | 192 """Downloads a zipped copy of the SDK from internal Google Storage bucket, |
182 and extracts it.""" | 193 and extracts it.""" |
183 zip_file = DownloadUsingGsutil('Standalone.zip') | 194 zip_file = DownloadUsingGsutil('Standalone.zip') |
184 return ExtractIso(zip_file) | 195 return ExtractIso(zip_file) |
185 | 196 |
186 | 197 |
187 class SourceImages(object): | 198 class SourceImages(object): |
188 def __init__(self, vs_path, sdk8_path): | 199 """Local paths for components. |wdk_path| may be None if it's unnecessary for |
200 the given configuration.""" | |
201 def __init__(self, vs_path, sdk8_path, wdk_path): | |
189 self.vs_path = vs_path | 202 self.vs_path = vs_path |
190 self.sdk8_path = sdk8_path | 203 self.sdk8_path = sdk8_path |
204 self.wdk_path = wdk_path | |
191 | 205 |
192 | 206 |
193 def GetSourceImages(local_dir, pro): | 207 def GetSourceImages(local_dir, pro): |
194 url = GetIsoUrl(pro) | 208 """Downloads the various sources that we need. |
209 | |
210 Of note: Because Express does not include ATL, there's an additional download | |
211 of the 7.1 WDK which is the latest publically accessible source for ATL. When | |
212 |pro| this is not necessary (and CHROME_HEADLESS always implies Pro). | |
213 """ | |
214 url = GetMainIsoUrl(pro) | |
195 if os.environ.get('CHROME_HEADLESS'): | 215 if os.environ.get('CHROME_HEADLESS'): |
M-A Ruel
2014/02/03 23:10:52
I'd prefer an option --bot-mode with default=bool(
scottmg
2014/02/03 23:22:12
Done.
| |
196 return SourceImages(GetVSInternal(), GetSDKInternal()) | 216 return SourceImages(GetVSInternal(), GetSDKInternal(), wdk_path=None) |
197 elif local_dir: | 217 elif local_dir: |
218 wdk_path = (os.path.join(local_dir, os.path.basename(WDK_ISO_URL)) | |
219 if not pro else None) | |
198 return SourceImages(os.path.join(local_dir, os.path.basename(url)), | 220 return SourceImages(os.path.join(local_dir, os.path.basename(url)), |
199 os.path.join(local_dir, 'Standalone')) | 221 os.path.join(local_dir, 'Standalone'), |
222 wdk_path=wdk_path) | |
200 else: | 223 else: |
201 # Note that we do the SDK first, as it might cause an elevation prompt. | 224 # Note that we do the SDK first, as it might cause an elevation prompt. |
202 sdk8_path = DownloadSDK8() | 225 sdk8_path = DownloadSDK8() |
203 vs_path = DownloadMainIso(url) | 226 vs_path = DownloadMainIso(url) |
204 return SourceImages(vs_path, sdk8_path) | 227 wdk_path = DownloadWDKIso() if not pro else None |
228 return SourceImages(vs_path, sdk8_path, wdk_path=wdk_path) | |
205 | 229 |
206 | 230 |
207 def ExtractMsiList(root_dir, packages): | 231 def ExtractMsiList(root_dir, packages): |
208 """Extracts the contents of a list of .msi files from an already extracted | 232 """Extracts the contents of a list of .msi files from an already extracted |
209 .iso file. | 233 .iso file. |
210 | 234 |
211 |packages| is a list of pairs (msi, required). If required is not True, the | 235 |packages| is a list of pairs (msi, required). If required is not True, the |
212 msi is optional (this is set for packages that are in Pro but not Express). | 236 msi is optional (this is set for packages that are in Pro but not Express). |
213 """ | 237 """ |
214 results = [] | 238 results = [] |
(...skipping 16 matching lines...) Expand all Loading... | |
231 (r'vc_compilerCore86\vc_compilerCore86.msi', True), | 255 (r'vc_compilerCore86\vc_compilerCore86.msi', True), |
232 (r'vc_compilerCore86res\vc_compilerCore86res.msi', True), | 256 (r'vc_compilerCore86res\vc_compilerCore86res.msi', True), |
233 (r'vc_compilerx64nat\vc_compilerx64nat.msi', False), | 257 (r'vc_compilerx64nat\vc_compilerx64nat.msi', False), |
234 (r'vc_compilerx64natres\vc_compilerx64natres.msi', False), | 258 (r'vc_compilerx64natres\vc_compilerx64natres.msi', False), |
235 (r'vc_compilerx64x86\vc_compilerx64x86.msi', False), | 259 (r'vc_compilerx64x86\vc_compilerx64x86.msi', False), |
236 (r'vc_compilerx64x86res\vc_compilerx64x86res.msi', False), | 260 (r'vc_compilerx64x86res\vc_compilerx64x86res.msi', False), |
237 (r'vc_librarycore86\vc_librarycore86.msi', True), | 261 (r'vc_librarycore86\vc_librarycore86.msi', True), |
238 (r'vc_libraryDesktop\x64\vc_LibraryDesktopX64.msi', True), | 262 (r'vc_libraryDesktop\x64\vc_LibraryDesktopX64.msi', True), |
239 (r'vc_libraryDesktop\x86\vc_LibraryDesktopX86.msi', True), | 263 (r'vc_libraryDesktop\x86\vc_LibraryDesktopX86.msi', True), |
240 (r'vc_libraryextended\vc_libraryextended.msi', False), | 264 (r'vc_libraryextended\vc_libraryextended.msi', False), |
241 (r'Windows_SDK\Windows Software Development Kit-x86_en-us.msi', True), | |
242 ('Windows_SDK\\' | |
243 r'Windows Software Development Kit for Metro style Apps-x86_en-us.msi', | |
244 True), | |
245 ] | 265 ] |
246 extracted_iso = ExtractIso(image.vs_path) | 266 extracted_iso = ExtractIso(image.vs_path) |
247 result = ExtractMsiList(os.path.join(extracted_iso, 'packages'), vs_packages) | 267 result = ExtractMsiList(os.path.join(extracted_iso, 'packages'), vs_packages) |
248 | 268 |
249 sdk_packages = [ | 269 sdk_packages = [ |
250 (r'X86 Debuggers And Tools-x86_en-us.msi', True), | 270 (r'X86 Debuggers And Tools-x86_en-us.msi', True), |
251 (r'X64 Debuggers And Tools-x64_en-us.msi', True), | 271 (r'X64 Debuggers And Tools-x64_en-us.msi', True), |
252 (r'SDK Debuggers-x86_en-us.msi', True), | 272 (r'SDK Debuggers-x86_en-us.msi', True), |
273 (r'Windows Software Development Kit-x86_en-us.msi', True), | |
274 (r'Windows Software Development Kit for Metro style Apps-x86_en-us.msi', | |
275 True), | |
253 ] | 276 ] |
254 result.extend(ExtractMsiList(os.path.join(image.sdk8_path, 'Installers'), | 277 result.extend(ExtractMsiList(os.path.join(image.sdk8_path, 'Installers'), |
255 sdk_packages)) | 278 sdk_packages)) |
256 | 279 |
280 if image.wdk_path: | |
281 # This image will only be set when using Express, when we need the WDK | |
282 # headers and libs to supplement Express with ATL. | |
283 wdk_packages = [ | |
284 (r'headers.msi', True), | |
285 (r'libs_x86fre.msi', True), | |
286 (r'libs_x64fre.msi', True), | |
287 ] | |
288 extracted_iso = ExtractIso(image.wdk_path) | |
289 result.extend(ExtractMsiList(os.path.join(extracted_iso, 'WDK'), | |
290 wdk_packages)) | |
291 | |
257 return result | 292 return result |
258 | 293 |
259 | 294 |
260 def CopyToFinalLocation(extracted_dirs, target_dir): | 295 def CopyToFinalLocation(extracted_dirs, target_dir): |
261 sys.stdout.write('Copying to final location...\n') | 296 sys.stdout.write('Copying to final location...\n') |
262 mappings = { | 297 mappings = { |
263 'Program Files\\Microsoft Visual Studio 12.0\\': '.\\', | 298 'Program Files\\Microsoft Visual Studio 12.0\\': '.\\', |
264 'System64\\': 'sys64\\', | 299 'System64\\': 'sys64\\', |
265 'System\\': 'sys32\\', | 300 'System\\': 'sys32\\', |
266 'Windows Kits\\8.0\\': 'win8sdk\\', | 301 'Windows Kits\\8.0\\': 'win8sdk\\', |
302 'WinDDK\\7600.16385.win7_wdk.100208-1538\\': 'wdk\\', | |
267 } | 303 } |
268 matches = [] | 304 matches = [] |
269 for extracted_dir in extracted_dirs: | 305 for extracted_dir in extracted_dirs: |
270 for root, _, filenames in os.walk(extracted_dir): | 306 for root, _, filenames in os.walk(extracted_dir): |
271 for filename in filenames: | 307 for filename in filenames: |
272 matches.append((extracted_dir, os.path.join(root, filename))) | 308 matches.append((extracted_dir, os.path.join(root, filename))) |
273 | 309 |
274 copies = [] | 310 copies = [] |
275 for prefix, full_path in matches: | 311 for prefix, full_path in matches: |
276 # +1 for trailing \. | 312 # +1 for trailing \. |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
320 '%~dp0..\\..\\VC\\atlmfc\\lib\n' | 356 '%~dp0..\\..\\VC\\atlmfc\\lib\n' |
321 'goto :EOF\n') | 357 'goto :EOF\n') |
322 | 358 |
323 # Express does not include a native 64 bit compiler, so we have to use | 359 # Express does not include a native 64 bit compiler, so we have to use |
324 # the x86->x64 cross. | 360 # the x86->x64 cross. |
325 if not pro: | 361 if not pro: |
326 # x86->x64 cross. | 362 # x86->x64 cross. |
327 f.write(':x64\n' | 363 f.write(':x64\n' |
328 'set PATH=%~dp0..\\..\\win8sdk\\bin\\x64;' | 364 'set PATH=%~dp0..\\..\\win8sdk\\bin\\x64;' |
329 '%~dp0..\\..\\VC\\bin\\x86_amd64;' | 365 '%~dp0..\\..\\VC\\bin\\x86_amd64;' |
366 # Needed for mspdb120.dll. Must be after above though, so | |
367 # that cl.exe is the x86_amd64 one. | |
368 '%~dp0..\\..\\VC\\bin;' | |
330 '%PATH%\n') | 369 '%PATH%\n') |
331 else: | 370 else: |
332 # x64 native. | 371 # x64 native. |
333 f.write(':x64\n' | 372 f.write(':x64\n' |
334 'set PATH=%~dp0..\\..\\win8sdk\\bin\\x64;' | 373 'set PATH=%~dp0..\\..\\win8sdk\\bin\\x64;' |
335 '%~dp0..\\..\\VC\\bin\\amd64;' | 374 '%~dp0..\\..\\VC\\bin\\amd64;' |
336 '%PATH%\n') | 375 '%PATH%\n') |
337 f.write('set LIB=%~dp0..\\..\\VC\\lib\\amd64;' | 376 f.write('set LIB=%~dp0..\\..\\VC\\lib\\amd64;' |
338 '%~dp0..\\..\\win8sdk\\Lib\\win8\\um\\x64;' | 377 '%~dp0..\\..\\win8sdk\\Lib\\win8\\um\\x64;' |
339 '%~dp0..\\..\\VC\\atlmfc\\lib\\amd64\n') | 378 '%~dp0..\\..\\VC\\atlmfc\\lib\\amd64\n') |
(...skipping 20 matching lines...) Expand all Loading... | |
360 target_dir) | 399 target_dir) |
361 # Set the working directory to 7z subdirectory. 7-zip doesn't find its | 400 # Set the working directory to 7z subdirectory. 7-zip doesn't find its |
362 # codec dll very well, so this is the simplest way to make sure it runs | 401 # codec dll very well, so this is the simplest way to make sure it runs |
363 # correctly, as we don't otherwise care about working directory. | 402 # correctly, as we don't otherwise care about working directory. |
364 os.chdir(os.path.join(BASEDIR, '7z')) | 403 os.chdir(os.path.join(BASEDIR, '7z')) |
365 images = GetSourceImages(options.local, not options.express) | 404 images = GetSourceImages(options.local, not options.express) |
366 extracted = ExtractComponents(images) | 405 extracted = ExtractComponents(images) |
367 CopyToFinalLocation(extracted, target_dir) | 406 CopyToFinalLocation(extracted, target_dir) |
368 | 407 |
369 GenerateSetEnvCmd(target_dir, not options.express) | 408 GenerateSetEnvCmd(target_dir, not options.express) |
409 with open(os.path.join(target_dir, '.version'), 'w') as f: | |
410 f.write('express' if options.express else 'pro') | |
370 finally: | 411 finally: |
371 if options.clean: | 412 if options.clean: |
372 DeleteAllTempDirs() | 413 DeleteAllTempDirs() |
373 | 414 |
374 | 415 |
375 if __name__ == '__main__': | 416 if __name__ == '__main__': |
376 sys.exit(main()) | 417 sys.exit(main()) |
OLD | NEW |