blob: 2b640fa373e7fe5796245ccbc19d8ad07000b55e [file] [log] [blame]
thakis4f4b1372015-08-11 22:25:001#!/usr/bin/env python
[email protected]4e8a2472014-03-19 22:01:392# Copyright 2014 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
brucedawsond5273dd2016-02-09 04:27:526import glob
[email protected]4e8a2472014-03-19 22:01:397import json
8import os
9import pipes
brucedawsone7bd0342016-06-01 18:37:1810import platform
[email protected]4e8a2472014-03-19 22:01:3911import shutil
brucedawsone7bd0342016-06-01 18:37:1812import stat
[email protected]4e8a2472014-03-19 22:01:3913import subprocess
14import sys
[email protected]4e8a2472014-03-19 22:01:3915
16
17script_dir = os.path.dirname(os.path.realpath(__file__))
18chrome_src = os.path.abspath(os.path.join(script_dir, os.pardir))
19SRC_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
[email protected]4e8a2472014-03-19 22:01:3920sys.path.insert(0, os.path.join(chrome_src, 'tools', 'gyp', 'pylib'))
[email protected]c71d3282014-04-09 01:56:2021json_data_file = os.path.join(script_dir, 'win_toolchain.json')
[email protected]4e8a2472014-03-19 22:01:3922
23
24import gyp
25
26
brucedawson2b33e7e2016-03-11 19:55:2527# Use MSVS2015 as the default toolchain.
28CURRENT_DEFAULT_TOOLCHAIN_VERSION = '2015'
sebmarchande44b02e2016-01-15 22:29:5729
30
[email protected]c71d3282014-04-09 01:56:2031def SetEnvironmentAndGetRuntimeDllDirs():
32 """Sets up os.environ to use the depot_tools VS toolchain with gyp, and
33 returns the location of the VS runtime DLLs so they can be copied into
34 the output directory after gyp generation.
brucedawsone7bd0342016-06-01 18:37:1835
36 Return value is [x64path, x86path] or None
[email protected]4e8a2472014-03-19 22:01:3937 """
brucedawsonaaff8dc2015-11-21 02:21:5238 vs_runtime_dll_dirs = None
[email protected]4e8a2472014-03-19 22:01:3939 depot_tools_win_toolchain = \
40 bool(int(os.environ.get('DEPOT_TOOLS_WIN_TOOLCHAIN', '1')))
thakis4f4b1372015-08-11 22:25:0041 # When running on a non-Windows host, only do this if the SDK has explicitly
42 # been downloaded before (in which case json_data_file will exist).
scottmg05eac9c02015-08-25 23:03:3543 if ((sys.platform in ('win32', 'cygwin') or os.path.exists(json_data_file))
44 and depot_tools_win_toolchain):
sebmarchande44b02e2016-01-15 22:29:5745 if ShouldUpdateToolchain():
[email protected]9372bec2014-08-14 14:03:3046 Update()
[email protected]c71d3282014-04-09 01:56:2047 with open(json_data_file, 'r') as tempf:
[email protected]4e8a2472014-03-19 22:01:3948 toolchain_data = json.load(tempf)
[email protected]4e8a2472014-03-19 22:01:3949
50 toolchain = toolchain_data['path']
51 version = toolchain_data['version']
scottmg54e45062015-06-02 01:15:4452 win_sdk = toolchain_data.get('win_sdk')
53 if not win_sdk:
54 win_sdk = toolchain_data['win8sdk']
[email protected]4e8a2472014-03-19 22:01:3955 wdk = toolchain_data['wdk']
56 # TODO(scottmg): The order unfortunately matters in these. They should be
57 # split into separate keys for x86 and x64. (See CopyVsRuntimeDlls call
58 # below). http://crbug.com/345992
brucedawsonaaff8dc2015-11-21 02:21:5259 vs_runtime_dll_dirs = toolchain_data['runtime_dirs']
[email protected]4e8a2472014-03-19 22:01:3960
61 os.environ['GYP_MSVS_OVERRIDE_PATH'] = toolchain
62 os.environ['GYP_MSVS_VERSION'] = version
63 # We need to make sure windows_sdk_path is set to the automated
64 # toolchain values in GYP_DEFINES, but don't want to override any
65 # otheroptions.express
66 # values there.
67 gyp_defines_dict = gyp.NameValueListToDict(gyp.ShlexEnv('GYP_DEFINES'))
scottmg54e45062015-06-02 01:15:4468 gyp_defines_dict['windows_sdk_path'] = win_sdk
[email protected]4e8a2472014-03-19 22:01:3969 os.environ['GYP_DEFINES'] = ' '.join('%s=%s' % (k, pipes.quote(str(v)))
70 for k, v in gyp_defines_dict.iteritems())
scottmg54e45062015-06-02 01:15:4471 os.environ['WINDOWSSDKDIR'] = win_sdk
[email protected]4e8a2472014-03-19 22:01:3972 os.environ['WDK_DIR'] = wdk
73 # Include the VS runtime in the PATH in case it's not machine-installed.
thakis44a40f82016-02-15 18:18:0174 runtime_path = os.path.pathsep.join(vs_runtime_dll_dirs)
75 os.environ['PATH'] = runtime_path + os.path.pathsep + os.environ['PATH']
bratellc7af8792016-01-07 16:30:1276 elif sys.platform == 'win32' and not depot_tools_win_toolchain:
77 if not 'GYP_MSVS_OVERRIDE_PATH' in os.environ:
78 os.environ['GYP_MSVS_OVERRIDE_PATH'] = DetectVisualStudioPath()
lwchkg833a437f2016-01-19 00:39:0879 if not 'GYP_MSVS_VERSION' in os.environ:
80 os.environ['GYP_MSVS_VERSION'] = GetVisualStudioVersion()
bratellc7af8792016-01-07 16:30:1281
brucedawsone7bd0342016-06-01 18:37:1882 # When using an installed toolchain these files aren't needed in the output
83 # directory in order to run binaries locally, but they are needed in order
84 # to create isolates or the mini_installer. Copying them to the output
85 # directory ensures that they are available when needed.
86 bitness = platform.architecture()[0]
87 # When running 64-bit python the x64 DLLs will be in System32
88 x64_path = 'System32' if bitness == '64bit' else 'Sysnative'
89 x64_path = os.path.join(r'C:\Windows', x64_path)
90 vs_runtime_dll_dirs = [x64_path, r'C:\Windows\SysWOW64']
91
brucedawsonaaff8dc2015-11-21 02:21:5292 return vs_runtime_dll_dirs
[email protected]4e8a2472014-03-19 22:01:3993
94
bratellc7af8792016-01-07 16:30:1295def _RegistryGetValueUsingWinReg(key, value):
96 """Use the _winreg module to obtain the value of a registry key.
97
98 Args:
99 key: The registry key.
100 value: The particular registry value to read.
101 Return:
102 contents of the registry key's value, or None on failure. Throws
103 ImportError if _winreg is unavailable.
104 """
105 import _winreg
106 try:
107 root, subkey = key.split('\\', 1)
108 assert root == 'HKLM' # Only need HKLM for now.
109 with _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, subkey) as hkey:
110 return _winreg.QueryValueEx(hkey, value)[0]
111 except WindowsError:
112 return None
113
114
115def _RegistryGetValue(key, value):
116 try:
117 return _RegistryGetValueUsingWinReg(key, value)
118 except ImportError:
119 raise Exception('The python library _winreg not found.')
120
121
halton.huo815e1772016-01-13 02:23:30122def GetVisualStudioVersion():
sebmarchande44b02e2016-01-15 22:29:57123 """Return GYP_MSVS_VERSION of Visual Studio.
halton.huo815e1772016-01-13 02:23:30124 """
sebmarchande44b02e2016-01-15 22:29:57125 return os.environ.get('GYP_MSVS_VERSION', CURRENT_DEFAULT_TOOLCHAIN_VERSION)
halton.huo815e1772016-01-13 02:23:30126
127
bratellc7af8792016-01-07 16:30:12128def DetectVisualStudioPath():
129 """Return path to the GYP_MSVS_VERSION of Visual Studio.
130 """
131
132 # Note that this code is used from
133 # build/toolchain/win/setup_toolchain.py as well.
halton.huo815e1772016-01-13 02:23:30134 version_as_year = GetVisualStudioVersion()
bratellc7af8792016-01-07 16:30:12135 year_to_version = {
136 '2013': '12.0',
137 '2015': '14.0',
138 }
139 if version_as_year not in year_to_version:
140 raise Exception(('Visual Studio version %s (from GYP_MSVS_VERSION)'
141 ' not supported. Supported versions are: %s') % (
142 version_as_year, ', '.join(year_to_version.keys())))
143 version = year_to_version[version_as_year]
144 keys = [r'HKLM\Software\Microsoft\VisualStudio\%s' % version,
145 r'HKLM\Software\Wow6432Node\Microsoft\VisualStudio\%s' % version]
146 for key in keys:
147 path = _RegistryGetValue(key, 'InstallDir')
148 if not path:
149 continue
150 path = os.path.normpath(os.path.join(path, '..', '..'))
151 return path
152
153 raise Exception(('Visual Studio Version %s (from GYP_MSVS_VERSION)'
154 ' not found.') % (version_as_year))
155
156
scottmg54e45062015-06-02 01:15:44157def _VersionNumber():
158 """Gets the standard version number ('120', '140', etc.) based on
159 GYP_MSVS_VERSION."""
halton.huo815e1772016-01-13 02:23:30160 vs_version = GetVisualStudioVersion()
161 if vs_version == '2013':
scottmg54e45062015-06-02 01:15:44162 return '120'
halton.huo815e1772016-01-13 02:23:30163 elif vs_version == '2015':
scottmg54e45062015-06-02 01:15:44164 return '140'
165 else:
166 raise ValueError('Unexpected GYP_MSVS_VERSION')
167
168
brucedawsond5273dd2016-02-09 04:27:52169def _CopyRuntimeImpl(target, source, verbose=True):
gab381d9f172016-04-18 15:29:14170 """Copy |source| to |target| if it doesn't already exist or if it needs to be
171 updated (comparing last modified time as an approximate float match as for
172 some reason the values tend to differ by ~1e-07 despite being copies of the
173 same file... https://crbug.com/603603).
dpranke0b951952014-11-15 00:09:14174 """
175 if (os.path.isdir(os.path.dirname(target)) and
176 (not os.path.isfile(target) or
gab381d9f172016-04-18 15:29:14177 abs(os.stat(target).st_mtime - os.stat(source).st_mtime) >= 0.01)):
brucedawsond5273dd2016-02-09 04:27:52178 if verbose:
179 print 'Copying %s to %s...' % (source, target)
dpranke0b951952014-11-15 00:09:14180 if os.path.exists(target):
brucedawsone7bd0342016-06-01 18:37:18181 # Make the file writable so that we can delete it now.
182 os.chmod(target, stat.S_IWRITE)
dpranke0b951952014-11-15 00:09:14183 os.unlink(target)
184 shutil.copy2(source, target)
brucedawsone7bd0342016-06-01 18:37:18185 # Make the file writable so that we can overwrite or delete it later.
186 os.chmod(target, stat.S_IWRITE)
dpranke0b951952014-11-15 00:09:14187
188
scottmg54e45062015-06-02 01:15:44189def _CopyRuntime2013(target_dir, source_dir, dll_pattern):
190 """Copy both the msvcr and msvcp runtime DLLs, only if the target doesn't
191 exist, but the target directory does exist."""
192 for file_part in ('p', 'r'):
193 dll = dll_pattern % file_part
194 target = os.path.join(target_dir, dll)
195 source = os.path.join(source_dir, dll)
196 _CopyRuntimeImpl(target, source)
197
198
brucedawsonc6f6c692016-02-22 23:09:18199def _CopyRuntime2015(target_dir, source_dir, dll_pattern, suffix):
scottmg54e45062015-06-02 01:15:44200 """Copy both the msvcp and vccorlib runtime DLLs, only if the target doesn't
201 exist, but the target directory does exist."""
sebmarchand7cebe212015-12-17 20:44:35202 for file_part in ('msvcp', 'vccorlib', 'vcruntime'):
scottmg54e45062015-06-02 01:15:44203 dll = dll_pattern % file_part
204 target = os.path.join(target_dir, dll)
205 source = os.path.join(source_dir, dll)
206 _CopyRuntimeImpl(target, source)
brucedawsone7bd0342016-06-01 18:37:18207 # OS installs of Visual Studio (and all installs of Windows 10) put the
208 # universal CRT files in c:\Windows\System32\downlevel - look for them there
209 # to support DEPOT_TOOLS_WIN_TOOLCHAIN=0.
210 if os.path.exists(os.path.join(source_dir, 'downlevel')):
211 ucrt_src_glob = os.path.join(source_dir, 'downlevel', 'api-ms-win-*.dll')
212 else:
213 ucrt_src_glob = os.path.join(source_dir, 'api-ms-win-*.dll')
214 ucrt_files = glob.glob(ucrt_src_glob)
215 assert len(ucrt_files) > 0
216 for ucrt_src_file in ucrt_files:
brucedawsonc6f6c692016-02-22 23:09:18217 file_part = os.path.basename(ucrt_src_file)
218 ucrt_dst_file = os.path.join(target_dir, file_part)
219 _CopyRuntimeImpl(ucrt_dst_file, ucrt_src_file, False)
220 _CopyRuntimeImpl(os.path.join(target_dir, 'ucrtbase' + suffix),
221 os.path.join(source_dir, 'ucrtbase' + suffix))
dpranke0b951952014-11-15 00:09:14222
223
brucedawsonaaff8dc2015-11-21 02:21:52224def _CopyRuntime(target_dir, source_dir, target_cpu, debug):
225 """Copy the VS runtime DLLs, only if the target doesn't exist, but the target
226 directory does exist. Handles VS 2013 and VS 2015."""
227 suffix = "d.dll" if debug else ".dll"
halton.huo815e1772016-01-13 02:23:30228 if GetVisualStudioVersion() == '2015':
brucedawsonc6f6c692016-02-22 23:09:18229 _CopyRuntime2015(target_dir, source_dir, '%s140' + suffix, suffix)
brucedawsonaaff8dc2015-11-21 02:21:52230 else:
231 _CopyRuntime2013(target_dir, source_dir, 'msvc%s120' + suffix)
232
233 # Copy the PGO runtime library to the release directories.
234 if not debug and os.environ.get('GYP_MSVS_OVERRIDE_PATH'):
235 pgo_x86_runtime_dir = os.path.join(os.environ.get('GYP_MSVS_OVERRIDE_PATH'),
236 'VC', 'bin')
237 pgo_x64_runtime_dir = os.path.join(pgo_x86_runtime_dir, 'amd64')
238 pgo_runtime_dll = 'pgort' + _VersionNumber() + '.dll'
239 if target_cpu == "x86":
240 source_x86 = os.path.join(pgo_x86_runtime_dir, pgo_runtime_dll)
241 if os.path.exists(source_x86):
242 _CopyRuntimeImpl(os.path.join(target_dir, pgo_runtime_dll), source_x86)
243 elif target_cpu == "x64":
244 source_x64 = os.path.join(pgo_x64_runtime_dir, pgo_runtime_dll)
245 if os.path.exists(source_x64):
246 _CopyRuntimeImpl(os.path.join(target_dir, pgo_runtime_dll),
247 source_x64)
248 else:
249 raise NotImplementedError("Unexpected target_cpu value:" + target_cpu)
250
251
[email protected]4e8a2472014-03-19 22:01:39252def CopyVsRuntimeDlls(output_dir, runtime_dirs):
253 """Copies the VS runtime DLLs from the given |runtime_dirs| to the output
254 directory so that even if not system-installed, built binaries are likely to
255 be able to run.
256
257 This needs to be run after gyp has been run so that the expected target
258 output directories are already created.
brucedawsonaaff8dc2015-11-21 02:21:52259
260 This is used for the GYP build and gclient runhooks.
[email protected]4e8a2472014-03-19 22:01:39261 """
[email protected]4e8a2472014-03-19 22:01:39262 x86, x64 = runtime_dirs
263 out_debug = os.path.join(output_dir, 'Debug')
264 out_debug_nacl64 = os.path.join(output_dir, 'Debug', 'x64')
265 out_release = os.path.join(output_dir, 'Release')
266 out_release_nacl64 = os.path.join(output_dir, 'Release', 'x64')
267 out_debug_x64 = os.path.join(output_dir, 'Debug_x64')
268 out_release_x64 = os.path.join(output_dir, 'Release_x64')
269
270 if os.path.exists(out_debug) and not os.path.exists(out_debug_nacl64):
271 os.makedirs(out_debug_nacl64)
272 if os.path.exists(out_release) and not os.path.exists(out_release_nacl64):
273 os.makedirs(out_release_nacl64)
brucedawsonaaff8dc2015-11-21 02:21:52274 _CopyRuntime(out_debug, x86, "x86", debug=True)
275 _CopyRuntime(out_release, x86, "x86", debug=False)
276 _CopyRuntime(out_debug_x64, x64, "x64", debug=True)
277 _CopyRuntime(out_release_x64, x64, "x64", debug=False)
278 _CopyRuntime(out_debug_nacl64, x64, "x64", debug=True)
279 _CopyRuntime(out_release_nacl64, x64, "x64", debug=False)
dpranke0b951952014-11-15 00:09:14280
281
dpranke43276212015-02-20 02:55:19282def CopyDlls(target_dir, configuration, target_cpu):
dpranke0b951952014-11-15 00:09:14283 """Copy the VS runtime DLLs into the requested directory as needed.
284
285 configuration is one of 'Debug' or 'Release'.
dpranke43276212015-02-20 02:55:19286 target_cpu is one of 'x86' or 'x64'.
dpranke0b951952014-11-15 00:09:14287
288 The debug configuration gets both the debug and release DLLs; the
289 release config only the latter.
brucedawsonaaff8dc2015-11-21 02:21:52290
291 This is used for the GN build.
dpranke0b951952014-11-15 00:09:14292 """
brucedawsonaaff8dc2015-11-21 02:21:52293 vs_runtime_dll_dirs = SetEnvironmentAndGetRuntimeDllDirs()
294 if not vs_runtime_dll_dirs:
dpranke0b951952014-11-15 00:09:14295 return
296
brucedawsonaaff8dc2015-11-21 02:21:52297 x64_runtime, x86_runtime = vs_runtime_dll_dirs
dpranke43276212015-02-20 02:55:19298 runtime_dir = x64_runtime if target_cpu == 'x64' else x86_runtime
brucedawsonaaff8dc2015-11-21 02:21:52299 _CopyRuntime(target_dir, runtime_dir, target_cpu, debug=False)
dpranke0b951952014-11-15 00:09:14300 if configuration == 'Debug':
brucedawsonaaff8dc2015-11-21 02:21:52301 _CopyRuntime(target_dir, runtime_dir, target_cpu, debug=True)
[email protected]33222522014-07-22 00:18:32302
[email protected]4e8a2472014-03-19 22:01:39303
[email protected]c71d3282014-04-09 01:56:20304def _GetDesiredVsToolchainHashes():
305 """Load a list of SHA1s corresponding to the toolchains that we want installed
306 to build with."""
halton.huo815e1772016-01-13 02:23:30307 if GetVisualStudioVersion() == '2015':
brucedawsona80d80c2016-05-17 02:44:04308 if bool(int(os.environ.get('DEPOT_TOOLS_WIN_TOOLCHAIN_PRERELEASE', '0'))):
309 # Update 3 pre-release, May 16th.
310 return ['283cc362f57dbe240e0d21f48ae45f9d834a425a']
311 else:
312 # Update 2.
313 return ['95ddda401ec5678f15eeed01d2bee08fcbc5ee97']
scottmg54e45062015-06-02 01:15:44314 else:
brucedawsonb10de5ec2016-04-13 18:18:53315 return ['03a4e939cd325d6bc5216af41b92d02dda1366a6']
[email protected]c71d3282014-04-09 01:56:20316
317
sebmarchande44b02e2016-01-15 22:29:57318def ShouldUpdateToolchain():
319 """Check if the toolchain should be upgraded."""
320 if not os.path.exists(json_data_file):
321 return True
322 with open(json_data_file, 'r') as tempf:
323 toolchain_data = json.load(tempf)
324 version = toolchain_data['version']
325 env_version = GetVisualStudioVersion()
326 # If there's a mismatch between the version set in the environment and the one
327 # in the json file then the toolchain should be updated.
328 return version != env_version
329
330
thakis4f4b1372015-08-11 22:25:00331def Update(force=False):
[email protected]c71d3282014-04-09 01:56:20332 """Requests an update of the toolchain to the specific hashes we have at
333 this revision. The update outputs a .json of the various configuration
334 information required to pass to gyp which we use in |GetToolchainDir()|.
335 """
thakis4f4b1372015-08-11 22:25:00336 if force != False and force != '--force':
337 print >>sys.stderr, 'Unknown parameter "%s"' % force
338 return 1
339 if force == '--force' or os.path.exists(json_data_file):
340 force = True
341
[email protected]c71d3282014-04-09 01:56:20342 depot_tools_win_toolchain = \
343 bool(int(os.environ.get('DEPOT_TOOLS_WIN_TOOLCHAIN', '1')))
thakis4f4b1372015-08-11 22:25:00344 if ((sys.platform in ('win32', 'cygwin') or force) and
345 depot_tools_win_toolchain):
[email protected]c71d3282014-04-09 01:56:20346 import find_depot_tools
347 depot_tools_path = find_depot_tools.add_depot_tools_to_path()
brucedawson2b33e7e2016-03-11 19:55:25348 # Necessary so that get_toolchain_if_necessary.py will put the VS toolkit
349 # in the correct directory.
350 os.environ['GYP_MSVS_VERSION'] = GetVisualStudioVersion()
[email protected]c71d3282014-04-09 01:56:20351 get_toolchain_args = [
352 sys.executable,
353 os.path.join(depot_tools_path,
354 'win_toolchain',
355 'get_toolchain_if_necessary.py'),
356 '--output-json', json_data_file,
357 ] + _GetDesiredVsToolchainHashes()
thakis4f4b1372015-08-11 22:25:00358 if force:
359 get_toolchain_args.append('--force')
[email protected]c71d3282014-04-09 01:56:20360 subprocess.check_call(get_toolchain_args)
361
[email protected]4e8a2472014-03-19 22:01:39362 return 0
363
[email protected]ffe205622014-03-20 17:42:25364
brucedawson12bbca42016-03-23 00:58:06365def NormalizePath(path):
366 while path.endswith("\\"):
367 path = path[:-1]
368 return path
369
370
[email protected]c71d3282014-04-09 01:56:20371def GetToolchainDir():
372 """Gets location information about the current toolchain (must have been
[email protected]308a6cae2014-05-28 20:32:01373 previously updated by 'update'). This is used for the GN build."""
scottmg9bf8fb32014-11-19 19:33:28374 runtime_dll_dirs = SetEnvironmentAndGetRuntimeDllDirs()
ckocagilfc8d7f232014-09-30 19:31:43375
376 # If WINDOWSSDKDIR is not set, search the default SDK path and set it.
377 if not 'WINDOWSSDKDIR' in os.environ:
brucedawson953e3762016-01-21 23:35:35378 default_sdk_path = 'C:\\Program Files (x86)\\Windows Kits\\10'
ckocagilfc8d7f232014-09-30 19:31:43379 if os.path.isdir(default_sdk_path):
380 os.environ['WINDOWSSDKDIR'] = default_sdk_path
381
[email protected]308a6cae2014-05-28 20:32:01382 print '''vs_path = "%s"
383sdk_path = "%s"
384vs_version = "%s"
385wdk_dir = "%s"
scottmg9bf8fb32014-11-19 19:33:28386runtime_dirs = "%s"
[email protected]308a6cae2014-05-28 20:32:01387''' % (
brucedawson12bbca42016-03-23 00:58:06388 NormalizePath(os.environ['GYP_MSVS_OVERRIDE_PATH']),
389 NormalizePath(os.environ['WINDOWSSDKDIR']),
halton.huo815e1772016-01-13 02:23:30390 GetVisualStudioVersion(),
brucedawson12bbca42016-03-23 00:58:06391 NormalizePath(os.environ.get('WDK_DIR', '')),
thakis44a40f82016-02-15 18:18:01392 os.path.pathsep.join(runtime_dll_dirs or ['None']))
[email protected]c71d3282014-04-09 01:56:20393
394
395def main():
[email protected]c71d3282014-04-09 01:56:20396 commands = {
397 'update': Update,
398 'get_toolchain_dir': GetToolchainDir,
dpranke0b951952014-11-15 00:09:14399 'copy_dlls': CopyDlls,
[email protected]c71d3282014-04-09 01:56:20400 }
401 if len(sys.argv) < 2 or sys.argv[1] not in commands:
402 print >>sys.stderr, 'Expected one of: %s' % ', '.join(commands)
403 return 1
dpranke0b951952014-11-15 00:09:14404 return commands[sys.argv[1]](*sys.argv[2:])
[email protected]c71d3282014-04-09 01:56:20405
406
[email protected]4e8a2472014-03-19 22:01:39407if __name__ == '__main__':
408 sys.exit(main())