Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 #!/usr/bin/env python | |
|
scottmg
2015/10/03 05:04:25
This used to pull together a toolchain from a bunc
| |
| 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 | |
| 4 # found in the LICENSE file. | |
| 5 | |
| 6 """Extracts a Windows VS2013 toolchain from various downloadable pieces.""" | |
| 7 | |
| 8 | |
| 9 import ctypes | |
| 10 import json | |
| 11 import optparse | |
| 12 import os | |
| 13 import shutil | |
| 14 import subprocess | |
| 15 import sys | |
| 16 import tempfile | |
| 17 import urllib2 | |
| 18 | |
| 19 | |
| 20 BASEDIR = os.path.dirname(os.path.abspath(__file__)) | |
| 21 WDK_ISO_URL = ( | |
| 22 'http://download.microsoft.com/download/' | |
| 23 '4/A/2/4A25C7D5-EFBE-4182-B6A9-AE6850409A78/GRMWDK_EN_7600_1.ISO') | |
| 24 g_temp_dirs = [] | |
| 25 | |
| 26 | |
| 27 sys.path.append(os.path.join(BASEDIR, '..')) | |
| 28 import download_from_google_storage | |
| 29 | |
| 30 | |
| 31 def GetLongPathName(path): | |
| 32 """Converts any 8dot3 names in the path to the full name.""" | |
| 33 buf = ctypes.create_unicode_buffer(260) | |
| 34 size = ctypes.windll.kernel32.GetLongPathNameW(unicode(path), buf, 260) | |
| 35 if (size > 260): | |
| 36 sys.exit('Long form of path longer than 260 chars: %s' % path) | |
| 37 return buf.value | |
| 38 | |
| 39 | |
| 40 def RunOrDie(command): | |
| 41 subprocess.check_call(command, shell=True) | |
| 42 | |
| 43 | |
| 44 class ScopedSubstTempDir(object): | |
| 45 """Creates a |TempDir()| and subst's a drive to the path. | |
| 46 | |
| 47 This is done to avoid exceedingly long names in some .msi packages which | |
| 48 fail to extract because they exceed _MAX_PATH. Only the "subst" part of this | |
| 49 is scoped, not the temp dir, which is left for use and cleanup by the | |
| 50 caller. | |
| 51 """ | |
| 52 DefineDosDevice = ctypes.windll.kernel32.DefineDosDeviceW | |
| 53 DefineDosDevice.argtypes = [ctypes.c_int, ctypes.c_wchar_p, ctypes.c_wchar_p] | |
| 54 DDD_NO_BROADCAST_SYSTEM = 0x08 | |
| 55 DDD_REMOVE_DEFINITION = 0x02 | |
| 56 | |
| 57 def __init__(self): | |
| 58 self.real_path = TempDir() | |
| 59 self.subst_drive = None | |
| 60 | |
| 61 def __enter__(self): | |
| 62 """Tries to find a subst that we can use for the temporary directory, and | |
| 63 aborts on failure.""" | |
| 64 for drive in range(ord('Z'), ord('A') - 1, -1): | |
| 65 candidate = '%c:' % drive | |
| 66 if self.DefineDosDevice( | |
| 67 self.DDD_NO_BROADCAST_SYSTEM, candidate, self.real_path) != 0: | |
| 68 self.subst_drive = candidate | |
| 69 return self | |
| 70 raise RuntimeError('Unable to find a subst path') | |
| 71 | |
| 72 def __exit__(self, typ, value, traceback): | |
| 73 if self.subst_drive: | |
| 74 if self.DefineDosDevice(int(self.DDD_REMOVE_DEFINITION), | |
| 75 self.subst_drive, | |
| 76 self.real_path) == 0: | |
| 77 raise RuntimeError('Unable to remove subst') | |
| 78 | |
| 79 def ShortenedPath(self): | |
| 80 return self.subst_drive + '\\' | |
| 81 | |
| 82 def RealPath(self): | |
| 83 return self.real_path | |
| 84 | |
| 85 | |
| 86 def TempDir(): | |
| 87 """Generates a temporary directory (for downloading or extracting to) and keep | |
| 88 track of the directory that's created for cleaning up later. | |
| 89 """ | |
| 90 temp = tempfile.mkdtemp() | |
| 91 g_temp_dirs.append(temp) | |
| 92 return temp | |
| 93 | |
| 94 | |
| 95 def DeleteAllTempDirs(): | |
| 96 """Removes all temporary directories created by |TempDir()|.""" | |
| 97 global g_temp_dirs | |
| 98 if g_temp_dirs: | |
| 99 sys.stdout.write('Cleaning up temporaries...\n') | |
| 100 for temp in g_temp_dirs: | |
| 101 # shutil.rmtree errors out on read only attributes. | |
| 102 RunOrDie('rmdir /s/q "%s"' % temp) | |
| 103 g_temp_dirs = [] | |
| 104 | |
| 105 | |
| 106 def GetMainIsoUrl(pro): | |
| 107 """Gets the main .iso URL. | |
| 108 | |
| 109 If |pro| is False, downloads the Express edition. | |
| 110 """ | |
| 111 prefix = 'http://download.microsoft.com/download/' | |
| 112 if pro: | |
| 113 return (prefix + | |
| 114 'A/F/1/AF128362-A6A8-4DB3-A39A-C348086472CC/VS2013_RTM_PRO_ENU.iso') | |
| 115 else: | |
| 116 return (prefix + | |
| 117 '7/2/E/72E0F986-D247-4289-B9DC-C4FB07374894/VS2013_RTM_DskExp_ENU.iso') | |
| 118 | |
| 119 | |
| 120 def Download(url, local_path): | |
| 121 """Downloads a large-ish binary file and print some status information while | |
| 122 doing so. | |
| 123 """ | |
| 124 sys.stdout.write('Downloading %s...\n' % url) | |
| 125 req = urllib2.urlopen(url) | |
| 126 content_length = int(req.headers.get('Content-Length', 0)) | |
| 127 bytes_read = 0L | |
| 128 terminator = '\r' if sys.stdout.isatty() else '\n' | |
| 129 with open(local_path, 'wb') as file_handle: | |
| 130 while True: | |
| 131 chunk = req.read(1024 * 1024) | |
| 132 if not chunk: | |
| 133 break | |
| 134 bytes_read += len(chunk) | |
| 135 file_handle.write(chunk) | |
| 136 sys.stdout.write('... %d/%d%s' % (bytes_read, content_length, terminator)) | |
| 137 sys.stdout.flush() | |
| 138 sys.stdout.write('\n') | |
| 139 if content_length and content_length != bytes_read: | |
| 140 sys.exit('Got incorrect number of bytes downloading %s' % url) | |
| 141 | |
| 142 | |
| 143 def ExtractIso(iso_path): | |
| 144 """Uses 7zip to extract the contents of the given .iso (or self-extracting | |
| 145 .exe). | |
| 146 """ | |
| 147 target_path = TempDir() | |
| 148 sys.stdout.write('Extracting %s...\n' % iso_path) | |
| 149 sys.stdout.flush() | |
| 150 # TODO(scottmg): Do this (and exe) manually with python code. | |
| 151 # Note that at the beginning of main() we set the working directory to 7z's | |
| 152 # location so that 7z can find its codec dll. | |
| 153 RunOrDie('7z x "%s" -y "-o%s"' % (iso_path, target_path)) | |
| 154 return target_path | |
| 155 | |
| 156 | |
| 157 def ExtractMsi(msi_path): | |
| 158 """Uses msiexec to extract the contents of the given .msi file.""" | |
| 159 sys.stdout.write('Extracting %s...\n' % msi_path) | |
| 160 with ScopedSubstTempDir() as temp_dir: | |
| 161 RunOrDie('msiexec /a "%s" /qn TARGETDIR="%s"' % ( | |
| 162 msi_path, temp_dir.ShortenedPath())) | |
| 163 return temp_dir.RealPath() | |
| 164 | |
| 165 | |
| 166 def DownloadMainIso(url): | |
| 167 temp_dir = TempDir() | |
| 168 target_path = os.path.join(temp_dir, os.path.basename(url)) | |
| 169 Download(url, target_path) | |
| 170 return target_path | |
| 171 | |
| 172 | |
| 173 def DownloadSDK8(): | |
| 174 """Downloads the Win8 SDK. | |
| 175 | |
| 176 This one is slightly different than the simpler direct downloads. There is | |
| 177 no .ISO distribution for the Windows 8 SDK. Rather, a tool is provided that | |
| 178 is a download manager. This is used to download the various .msi files to a | |
| 179 target location. Unfortunately, this tool requires elevation for no obvious | |
| 180 reason even when only downloading, so this function will trigger a UAC | |
| 181 elevation if the script is not run from an elevated prompt. This is mostly | |
| 182 grabbed for windbg and cdb (See http://crbug.com/321187) as most of the SDK | |
| 183 is in VS2013, however we need a couple D3D related things from the SDK. | |
| 184 """ | |
| 185 # Use the long path name here because because 8dot3 names don't seem to work. | |
| 186 sdk_temp_dir = GetLongPathName(TempDir()) | |
| 187 target_path = os.path.join(sdk_temp_dir, 'sdksetup.exe') | |
| 188 standalone_path = os.path.join(sdk_temp_dir, 'Standalone') | |
| 189 Download( | |
| 190 ('http://download.microsoft.com/download/' | |
| 191 'F/1/3/F1300C9C-A120-4341-90DF-8A52509B23AC/standalonesdk/sdksetup.exe'), | |
| 192 target_path) | |
| 193 sys.stdout.write( | |
| 194 'Running sdksetup.exe to download Win8 SDK (may request elevation)...\n') | |
| 195 count = 0 | |
| 196 while count < 5: | |
| 197 rc = subprocess.call([target_path, | |
| 198 '/quiet', | |
| 199 '/features', 'OptionId.WindowsDesktopDebuggers', | |
| 200 'OptionId.WindowsDesktopSoftwareDevelopmentKit', | |
| 201 '/layout', standalone_path]) | |
| 202 if rc == 0: | |
| 203 return standalone_path | |
| 204 count += 1 | |
| 205 sys.stdout.write('Windows 8 SDK failed to download, retrying.\n') | |
| 206 sys.exit('After multiple retries, couldn\'t download Win8 SDK') | |
| 207 | |
| 208 | |
| 209 def DownloadWDKIso(): | |
| 210 wdk_temp_dir = TempDir() | |
| 211 target_path = os.path.join(wdk_temp_dir, 'GRMWDK_EN_7600_1.ISO') | |
| 212 Download(WDK_ISO_URL, target_path) | |
| 213 return target_path | |
| 214 | |
| 215 | |
| 216 def DownloadUsingGsutil(filename): | |
| 217 """Downloads the given file from Google Storage chrome-wintoolchain bucket.""" | |
| 218 temp_dir = TempDir() | |
| 219 assert os.path.basename(filename) == filename | |
| 220 target_path = os.path.join(temp_dir, filename) | |
| 221 gsutil = download_from_google_storage.Gsutil( | |
| 222 download_from_google_storage.GSUTIL_DEFAULT_PATH, boto_path=None) | |
| 223 code = gsutil.call('cp', 'gs://chrome-wintoolchain/' + filename, target_path) | |
| 224 if code != 0: | |
| 225 sys.exit('gsutil failed') | |
| 226 return target_path | |
| 227 | |
| 228 | |
| 229 def GetVSInternal(): | |
| 230 """Uses gsutil to pull the toolchain from internal Google Storage bucket.""" | |
| 231 return DownloadUsingGsutil('VS2013_RTM_PRO_ENU.iso') | |
| 232 | |
| 233 | |
| 234 def GetSDKInternal(): | |
| 235 """Downloads a zipped copy of the SDK from internal Google Storage bucket, | |
| 236 and extracts it.""" | |
| 237 zip_file = DownloadUsingGsutil('Standalone.zip') | |
| 238 return ExtractIso(zip_file) | |
| 239 | |
| 240 | |
| 241 class SourceImages(object): | |
| 242 """Local paths for components. |wdk_path| may be None if it's unnecessary for | |
| 243 the given configuration.""" | |
| 244 def __init__(self, vs_path, sdk8_path, wdk_path): | |
| 245 self.vs_path = vs_path | |
| 246 self.sdk8_path = sdk8_path | |
| 247 self.wdk_path = wdk_path | |
| 248 | |
| 249 | |
| 250 def GetSourceImages(local_dir, pro): | |
| 251 """Downloads the various sources that we need. | |
| 252 | |
| 253 Of note: Because Express does not include ATL, there's an additional download | |
| 254 of the 7.1 WDK which is the latest publically accessible source for ATL. When | |
| 255 |pro| this is not necessary (and CHROME_HEADLESS always implies Pro). | |
| 256 """ | |
| 257 if pro and not local_dir: | |
| 258 sys.exit('Non-Express must be used with --local') | |
| 259 url = GetMainIsoUrl(pro) | |
| 260 if local_dir: | |
| 261 wdk_path = (os.path.join(local_dir, os.path.basename(WDK_ISO_URL)) | |
| 262 if not pro else None) | |
| 263 return SourceImages(os.path.join(local_dir, os.path.basename(url)), | |
| 264 os.path.join(local_dir, 'Standalone'), | |
| 265 wdk_path=wdk_path) | |
| 266 else: | |
| 267 # Note that we do the SDK first, as it might cause an elevation prompt. | |
| 268 sdk8_path = DownloadSDK8() | |
| 269 vs_path = DownloadMainIso(url) | |
| 270 wdk_path = DownloadWDKIso() if not pro else None | |
| 271 return SourceImages(vs_path, sdk8_path, wdk_path=wdk_path) | |
| 272 | |
| 273 | |
| 274 def ExtractMsiList(root_dir, packages): | |
| 275 """Extracts the contents of a list of .msi files from an already extracted | |
| 276 .iso file. | |
| 277 | |
| 278 |packages| is a list of pairs (msi, required). If required is not True, the | |
| 279 msi is optional (this is set for packages that are in Pro but not Express). | |
| 280 """ | |
| 281 results = [] | |
| 282 for (package, required) in packages: | |
| 283 path_to_package = os.path.join(root_dir, package) | |
| 284 if not os.path.exists(path_to_package) and not required: | |
| 285 continue | |
| 286 results.append(ExtractMsi(path_to_package)) | |
| 287 return results | |
| 288 | |
| 289 | |
| 290 def ExtractComponents(image): | |
| 291 vs_packages = [ | |
| 292 (r'vcRuntimeAdditional_amd64\vc_runtimeAdditional_x64.msi', True), | |
| 293 (r'vcRuntimeAdditional_x86\vc_runtimeAdditional_x86.msi', True), | |
| 294 (r'vcRuntimeDebug_amd64\vc_runtimeDebug_x64.msi', True), | |
| 295 (r'vcRuntimeDebug_x86\vc_runtimeDebug_x86.msi', True), | |
| 296 (r'vcRuntimeMinimum_amd64\vc_runtimeMinimum_x64.msi', True), | |
| 297 (r'vcRuntimeMinimum_x86\vc_runtimeMinimum_x86.msi', True), | |
| 298 (r'vc_compilerCore86\vc_compilerCore86.msi', True), | |
| 299 (r'vc_compilerCore86res\vc_compilerCore86res.msi', True), | |
| 300 (r'vc_compilerx64nat\vc_compilerx64nat.msi', False), | |
| 301 (r'vc_compilerx64natres\vc_compilerx64natres.msi', False), | |
| 302 (r'vc_compilerx64x86\vc_compilerx64x86.msi', False), | |
| 303 (r'vc_compilerx64x86res\vc_compilerx64x86res.msi', False), | |
| 304 (r'vc_librarycore86\vc_librarycore86.msi', True), | |
| 305 (r'vc_libraryDesktop\x64\vc_LibraryDesktopX64.msi', True), | |
| 306 (r'vc_libraryDesktop\x86\vc_LibraryDesktopX86.msi', True), | |
| 307 (r'vc_libraryextended\vc_libraryextended.msi', False), | |
| 308 (r'professionalcore\Setup\vs_professionalcore.msi', False), | |
| 309 (r'vc_libraryselectablemfc\vc_libraryselectablemfc.msi', False), | |
| 310 ] | |
| 311 extracted_iso = ExtractIso(image.vs_path) | |
| 312 result = ExtractMsiList(os.path.join(extracted_iso, 'packages'), vs_packages) | |
| 313 | |
| 314 sdk_packages = [ | |
| 315 (r'X86 Debuggers And Tools-x86_en-us.msi', True), | |
| 316 (r'X64 Debuggers And Tools-x64_en-us.msi', True), | |
| 317 (r'SDK Debuggers-x86_en-us.msi', True), | |
| 318 (r'Windows Software Development Kit-x86_en-us.msi', True), | |
| 319 (r'Windows Software Development Kit for Metro style Apps-x86_en-us.msi', | |
| 320 True), | |
| 321 ] | |
| 322 result.extend(ExtractMsiList(os.path.join(image.sdk8_path, 'Installers'), | |
| 323 sdk_packages)) | |
| 324 | |
| 325 if image.wdk_path: | |
| 326 # This image will only be set when using Express, when we need the WDK | |
| 327 # headers and libs to supplement Express with ATL. | |
| 328 wdk_packages = [ | |
| 329 (r'headers.msi', True), | |
| 330 (r'libs_x86fre.msi', True), | |
| 331 (r'libs_x64fre.msi', True), | |
| 332 ] | |
| 333 extracted_iso = ExtractIso(image.wdk_path) | |
| 334 result.extend(ExtractMsiList(os.path.join(extracted_iso, 'WDK'), | |
| 335 wdk_packages)) | |
| 336 | |
| 337 return result | |
| 338 | |
| 339 | |
| 340 def CopyToFinalLocation(extracted_dirs, target_dir): | |
| 341 sys.stdout.write('Copying to final location...\n') | |
| 342 mappings = { | |
| 343 'Program Files\\Microsoft Visual Studio 12.0\\VC\\': 'VC\\', | |
| 344 'Program Files\\Microsoft Visual Studio 12.0\\DIA SDK\\': 'DIA SDK\\', | |
| 345 'System64\\': 'sys64\\', | |
| 346 'System\\': 'sys32\\', | |
| 347 'Windows Kits\\8.1\\': 'win8sdk\\', | |
| 348 'WinDDK\\7600.16385.win7_wdk.100208-1538\\': 'wdk\\', | |
| 349 } | |
| 350 matches = [] | |
| 351 for extracted_dir in extracted_dirs: | |
| 352 for root, _, filenames in os.walk(extracted_dir): | |
| 353 for filename in filenames: | |
| 354 matches.append((extracted_dir, os.path.join(root, filename))) | |
| 355 | |
| 356 copies = [] | |
| 357 for prefix, full_path in matches: | |
| 358 # +1 for trailing \. | |
| 359 partial_path = full_path[len(prefix) + 1:] | |
| 360 for map_from, map_to in mappings.iteritems(): | |
| 361 if partial_path.startswith(map_from): | |
| 362 target_path = os.path.join(map_to, partial_path[len(map_from):]) | |
| 363 copies.append((full_path, os.path.join(target_dir, target_path))) | |
| 364 | |
| 365 for full_source, full_target in copies: | |
| 366 target_dir = os.path.dirname(full_target) | |
| 367 if not os.path.isdir(target_dir): | |
| 368 os.makedirs(target_dir) | |
| 369 shutil.copy2(full_source, full_target) | |
| 370 | |
| 371 | |
| 372 def GenerateSetEnvCmd(target_dir, pro): | |
| 373 """Generate a batch file that gyp expects to exist to set up the compiler | |
| 374 environment. | |
| 375 | |
| 376 This is normally generated by a full install of the SDK, but we | |
| 377 do it here manually since we do not do a full install.""" | |
| 378 with open(os.path.join( | |
| 379 target_dir, r'win8sdk\bin\SetEnv.cmd'), 'w') as f: | |
| 380 f.write('@echo off\n' | |
| 381 ':: Generated by win_toolchain\\toolchain2013.py.\n' | |
| 382 # Common to x86 and x64 | |
| 383 'set PATH=%~dp0..\\..\\Common7\\IDE;%PATH%\n' | |
| 384 'set INCLUDE=%~dp0..\\..\\win8sdk\\Include\\um;' | |
| 385 '%~dp0..\\..\\win8sdk\\Include\\shared;' | |
| 386 '%~dp0..\\..\\VC\\include;' | |
| 387 '%~dp0..\\..\\VC\\atlmfc\\include\n' | |
| 388 'if "%1"=="/x64" goto x64\n') | |
| 389 | |
| 390 # x86. If we're Pro, then use the amd64_x86 cross (we don't support x86 | |
| 391 # host at all). | |
| 392 if pro: | |
| 393 f.write('set PATH=%~dp0..\\..\\win8sdk\\bin\\x86;' | |
| 394 '%~dp0..\\..\\VC\\bin\\amd64_x86;' | |
| 395 '%~dp0..\\..\\VC\\bin\\amd64;' # Needed for mspdb120.dll. | |
| 396 '%PATH%\n') | |
| 397 else: | |
| 398 f.write('set PATH=%~dp0..\\..\\win8sdk\\bin\\x86;' | |
| 399 '%~dp0..\\..\\VC\\bin;%PATH%\n') | |
| 400 f.write('set LIB=%~dp0..\\..\\VC\\lib;' | |
| 401 '%~dp0..\\..\\win8sdk\\Lib\\winv6.3\\um\\x86;' | |
| 402 '%~dp0..\\..\\VC\\atlmfc\\lib\n' | |
| 403 'goto :EOF\n') | |
| 404 | |
| 405 # Express does not include a native 64 bit compiler, so we have to use | |
| 406 # the x86->x64 cross. | |
| 407 if not pro: | |
| 408 # x86->x64 cross. | |
| 409 f.write(':x64\n' | |
| 410 'set PATH=%~dp0..\\..\\win8sdk\\bin\\x64;' | |
| 411 '%~dp0..\\..\\VC\\bin\\x86_amd64;' | |
| 412 # Needed for mspdb120.dll. Must be after above though, so | |
| 413 # that cl.exe is the x86_amd64 one. | |
| 414 '%~dp0..\\..\\VC\\bin;' | |
| 415 '%PATH%\n') | |
| 416 else: | |
| 417 # x64 native. | |
| 418 f.write(':x64\n' | |
| 419 'set PATH=%~dp0..\\..\\win8sdk\\bin\\x64;' | |
| 420 '%~dp0..\\..\\VC\\bin\\amd64;' | |
| 421 '%PATH%\n') | |
| 422 f.write('set LIB=%~dp0..\\..\\VC\\lib\\amd64;' | |
| 423 '%~dp0..\\..\\win8sdk\\Lib\\winv6.3\\um\\x64;' | |
| 424 '%~dp0..\\..\\VC\\atlmfc\\lib\\amd64\n') | |
| 425 | |
| 426 | |
| 427 def DoTreeMirror(target_dir, tree_sha1): | |
| 428 """In order to save temporary space on bots that do not have enough space to | |
| 429 download ISOs, unpack them, and copy to the target location, the whole tree | |
| 430 is uploaded as a zip to internal storage, and then mirrored here.""" | |
| 431 local_zip = DownloadUsingGsutil(tree_sha1 + '.zip') | |
| 432 sys.stdout.write('Extracting %s...\n' % local_zip) | |
| 433 sys.stdout.flush() | |
| 434 RunOrDie('7z x "%s" -y "-o%s"' % (local_zip, target_dir)) | |
| 435 | |
| 436 | |
| 437 def main(): | |
| 438 parser = optparse.OptionParser(description=sys.modules[__name__].__doc__) | |
| 439 parser.add_option('--targetdir', metavar='DIR', | |
| 440 help='put toolchain into DIR', | |
| 441 default=os.path.join(BASEDIR, 'win_toolchain_2013')) | |
| 442 parser.add_option('--noclean', action='store_false', dest='clean', | |
| 443 help='do not remove temp files', | |
| 444 default=True) | |
| 445 parser.add_option('--local', metavar='DIR', | |
| 446 help='use downloaded files from DIR') | |
| 447 parser.add_option('--express', | |
| 448 help='use VS Express instead of Pro', action='store_true') | |
| 449 parser.add_option('--sha1', | |
| 450 help='tree sha1 that can be used to mirror an internal ' | |
| 451 'copy (used if --use-gs)') | |
| 452 parser.add_option('--use-gs', | |
| 453 help='Use internal servers to pull isos', | |
| 454 default=bool(int(os.environ.get('CHROME_HEADLESS', 0))), | |
| 455 action='store_true') | |
| 456 options, _ = parser.parse_args() | |
| 457 try: | |
| 458 target_dir = os.path.abspath(options.targetdir) | |
| 459 if os.path.exists(target_dir): | |
| 460 parser.error('%s already exists. Please [re]move it or use ' | |
| 461 '--targetdir to select a different target.\n' % | |
| 462 target_dir) | |
| 463 # Set the working directory to 7z subdirectory. 7-zip doesn't find its | |
| 464 # codec dll very well, so this is the simplest way to make sure it runs | |
| 465 # correctly, as we don't otherwise care about working directory. | |
| 466 os.chdir(os.path.join(BASEDIR, '7z')) | |
| 467 if options.use_gs and options.sha1: | |
| 468 options.express = False | |
| 469 DoTreeMirror(target_dir, options.sha1) | |
| 470 else: | |
| 471 images = GetSourceImages(options.local, not options.express) | |
| 472 extracted = ExtractComponents(images) | |
| 473 CopyToFinalLocation(extracted, target_dir) | |
| 474 GenerateSetEnvCmd(target_dir, not options.express) | |
| 475 | |
| 476 data = { | |
| 477 'path': target_dir, | |
| 478 'version': '2013e' if options.express else '2013', | |
| 479 'win8sdk': os.path.join(target_dir, 'win8sdk'), | |
| 480 'wdk': os.path.join(target_dir, 'wdk'), | |
| 481 'runtime_dirs': [ | |
| 482 os.path.join(target_dir, 'sys64'), | |
| 483 os.path.join(target_dir, 'sys32'), | |
| 484 ], | |
| 485 } | |
| 486 with open(os.path.join(target_dir, '..', 'data.json'), 'w') as f: | |
| 487 json.dump(data, f) | |
| 488 finally: | |
| 489 if options.clean: | |
| 490 DeleteAllTempDirs() | |
| 491 | |
| 492 | |
| 493 if __name__ == '__main__': | |
| 494 sys.exit(main()) | |
| OLD | NEW |