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

Side by Side Diff: scripts/slave/compile.py

Issue 2178193003: Move goma_teardown, goma_setup and determine_goma_jobs to goma_utils.py (Closed) Base URL: https://chromium.googlesource.com/chromium/tools/build.git@master
Patch Set: Move some code to goma_utils Created 4 years, 4 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 | « no previous file | scripts/slave/goma_utils.py » ('j') | scripts/slave/goma_utils.py » ('J')
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 (c) 2012 The Chromium Authors. All rights reserved. 2 # Copyright (c) 2012 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 """A tool to build chrome, executed by buildbot. 6 """A tool to build chrome, executed by buildbot.
7 7
8 When this is run, the current directory (cwd) should be the outer build 8 When this is run, the current directory (cwd) should be the outer build
9 directory (e.g., chrome-release/build/). 9 directory (e.g., chrome-release/build/).
10 10
11 For a list of command-line options, call this script with '--help'. 11 For a list of command-line options, call this script with '--help'.
12 """ 12 """
13 13
14 import multiprocessing
15 import optparse 14 import optparse
16 import os 15 import os
17 import re 16 import re
18 import subprocess
19 import sys 17 import sys
20 18
21 from common import chromium_utils 19 from common import chromium_utils
22 from slave import build_directory 20 from slave import build_directory
23 from slave import goma_utils 21 from slave import goma_utils
24 22
25 # Define a bunch of directory paths (same as bot_update.py)
26 CURRENT_DIR = os.path.abspath(os.getcwd())
27 BUILDER_DIR = os.path.dirname(CURRENT_DIR)
28 SLAVE_DIR = os.path.dirname(BUILDER_DIR)
29 # GOMA_CACHE_DIR used for caching long-term data.
30 DEFAULT_GOMA_CACHE_DIR = os.path.join(SLAVE_DIR, 'goma_cache')
31
32 # Path of the scripts/slave/ checkout on the slave, found by looking at the 23 # Path of the scripts/slave/ checkout on the slave, found by looking at the
33 # current compile.py script's path's dirname(). 24 # current compile.py script's path's dirname().
34 SLAVE_SCRIPTS_DIR = os.path.dirname(os.path.abspath(__file__)) 25 SLAVE_SCRIPTS_DIR = os.path.dirname(os.path.abspath(__file__))
35 # Path of the build/ checkout on the slave, found relative to the 26 # Path of the build/ checkout on the slave, found relative to the
36 # scripts/slave/ directory. 27 # scripts/slave/ directory.
37 BUILD_DIR = os.path.dirname(os.path.dirname(SLAVE_SCRIPTS_DIR)) 28 BUILD_DIR = os.path.dirname(os.path.dirname(SLAVE_SCRIPTS_DIR))
38 29
39 30
40 class EchoDict(dict): 31 class EchoDict(dict):
41 """Dict that remembers all modified values.""" 32 """Dict that remembers all modified values."""
(...skipping 23 matching lines...) Expand all
65 fh = sys.stdout 56 fh = sys.stdout
66 fh.write('Environment variables modified in compile.py:\n') 57 fh.write('Environment variables modified in compile.py:\n')
67 for k in sorted(list(self.overrides)): 58 for k in sorted(list(self.overrides)):
68 if k in self: 59 if k in self:
69 fh.write(' %s=%s\n' % (k, self[k])) 60 fh.write(' %s=%s\n' % (k, self[k]))
70 else: 61 else:
71 fh.write(' %s (removed)\n' % k) 62 fh.write(' %s (removed)\n' % k)
72 fh.write('\n') 63 fh.write('\n')
73 64
74 65
75 # TODO(tikuta): move to goma_utils.py
76 def goma_setup(options, env):
77 """Sets up goma if necessary.
78
79 If using the Goma compiler, first call goma_ctl to ensure the proxy is
80 available, and returns (True, instance of cloudtail subprocess).
81 If it failed to start up compiler_proxy, modify options.compiler and
82 options.goma_dir and returns (False, None)
83
84 """
85 if options.compiler not in ('goma', 'goma-clang'):
86 # Unset goma_dir to make sure we'll not use goma.
87 options.goma_dir = None
88 return False, None
89
90 hostname = goma_utils.GetShortHostname()
91 # HACK(shinyak, yyanagisawa, goma): Windows NO_NACL_GOMA (crbug.com/390764)
92 # Building NaCl untrusted code using goma brings large performance
93 # improvement but it sometimes cause build failure by race condition.
94 # Let me enable goma build on goma canary buildslaves to confirm the issue
95 # has been fixed by a workaround.
96 # vm*-m4 are trybots. build*-m1 and vm*-m1 are all goma canary bots.
97 if hostname in ['build28-m1', 'build58-m1', 'vm191-m1', 'vm480-m1',
98 'vm820-m1', 'vm821-m1', 'vm848-m1']:
99 env['NO_NACL_GOMA'] = 'false'
100
101 if options.goma_fail_fast:
102 # startup fails when initial ping failed.
103 env['GOMA_FAIL_FAST'] = 'true'
104 else:
105 # If a network error continues 30 minutes, compiler_proxy make the compile
106 # failed. When people use goma, they expect using goma is faster than
107 # compile locally. If goma cannot guarantee that, let it make compile
108 # as error.
109 env['GOMA_ALLOWED_NETWORK_ERROR_DURATION'] = '1800'
110
111 # HACK(yyanagisawa): reduce GOMA_BURST_MAX_PROCS crbug.com/592306
112 # Recently, I sometimes see buildbot slave time out, one possibility I come
113 # up with is burst mode use up resource.
114 # Let me temporary set small values to GOMA_BURST_MAX_PROCS to confirm
115 # the possibility is true or false.
116 max_subprocs = '3'
117 max_heavy_subprocs = '1'
118 number_of_processors = 0
119 try:
120 number_of_processors = multiprocessing.cpu_count()
121 except NotImplementedError:
122 print 'cpu_count() is not implemented, using default value.'
123 number_of_processors = 1
124 if number_of_processors > 3:
125 max_subprocs = str(number_of_processors - 1)
126 max_heavy_subprocs = str(number_of_processors / 2)
127 env['GOMA_BURST_MAX_SUBPROCS'] = max_subprocs
128 env['GOMA_BURST_MAX_SUBPROCS_LOW'] = max_subprocs
129 env['GOMA_BURST_MAX_SUBPROCS_HEAVY'] = max_heavy_subprocs
130
131 # Caches CRLs in GOMA_CACHE_DIR.
132 # Since downloading CRLs is usually slow, caching them may improves
133 # compiler_proxy start time.
134 if not os.path.exists(options.goma_cache_dir):
135 os.mkdir(options.goma_cache_dir, 0700)
136 env['GOMA_CACHE_DIR'] = options.goma_cache_dir
137
138 # Enable DepsCache. DepsCache caches the list of files to send goma server.
139 # This will greatly improve build speed when cache is warmed.
140 # The cache file is stored in the target output directory.
141 env['GOMA_DEPS_CACHE_DIR'] = (
142 options.goma_deps_cache_dir or options.target_output_dir)
143
144 if not env.get('GOMA_HERMETIC'):
145 env['GOMA_HERMETIC'] = options.goma_hermetic
146 if options.goma_enable_remote_link:
147 env['GOMA_ENABLE_REMOTE_LINK'] = options.goma_enable_remote_link
148 if options.goma_store_local_run_output:
149 env['GOMA_STORE_LOCAL_RUN_OUTPUT'] = options.goma_store_local_run_output
150 if options.goma_enable_compiler_info_cache:
151 # Will be stored in GOMA_CACHE_DIR.
152 env['GOMA_COMPILER_INFO_CACHE_FILE'] = 'goma-compiler-info.cache'
153
154 if options.build_data_dir:
155 env['GOMA_DUMP_STATS_FILE'] = os.path.join(options.build_data_dir,
156 'goma_stats_proto')
157
158 # goma is requested.
159 goma_key = os.path.join(options.goma_dir, 'goma.key')
160 if os.path.exists(goma_key):
161 env['GOMA_API_KEY_FILE'] = goma_key
162 if options.goma_service_account_json_file:
163 env['GOMA_SERVICE_ACCOUNT_JSON_FILE'] = \
164 options.goma_service_account_json_file
165 if chromium_utils.IsWindows():
166 env['GOMA_RPC_EXTRA_PARAMS'] = '?win'
167 goma_start_command = ['restart']
168 goma_ctl_cmd = [sys.executable,
169 os.path.join(options.goma_dir, 'goma_ctl.py')]
170 result = chromium_utils.RunCommand(goma_ctl_cmd + goma_start_command, env=env)
171 if not result:
172 # goma started sucessfully.
173 # Making cloudtail to upload the latest log.
174 # TODO(yyanagisawa): install cloudtail from CIPD.
175 cloudtail_path = '/opt/infra-tools/cloudtail'
176 if chromium_utils.IsWindows():
177 cloudtail_path = 'C:\\infra-tools\\cloudtail'
178 try:
179 cloudtail_proc = subprocess.Popen(
180 [cloudtail_path, 'tail', '--log-id', 'goma_compiler_proxy', '--path',
181 goma_utils.GetLatestGomaCompilerProxyInfo()])
182 except Exception as e:
183 print 'failed to invoke cloudtail: %s' % e
184 return True, None
185 return True, cloudtail_proc
186
187 if options.goma_jsonstatus:
188 chromium_utils.RunCommand(
189 goma_ctl_cmd + ['jsonstatus', options.goma_jsonstatus], env=env)
190 goma_utils.SendGomaTsMon(options.goma_jsonstatus, -1)
191
192 # Try to stop compiler_proxy so that it flushes logs and stores
193 # GomaStats.
194 if options.build_data_dir:
195 env['GOMACTL_CRASH_REPORT_ID_FILE'] = os.path.join(options.build_data_dir,
196 'crash_report_id_file')
197 chromium_utils.RunCommand(goma_ctl_cmd + ['stop'], env=env)
198
199 override_gsutil = None
200 if options.gsutil_py_path:
201 override_gsutil = [sys.executable, options.gsutil_py_path]
202
203 # Upload compiler_proxy.INFO to investigate the reason of compiler_proxy
204 # start-up failure.
205 goma_utils.UploadGomaCompilerProxyInfo(override_gsutil=override_gsutil)
206 # Upload GomaStats to make it monitored.
207 if env.get('GOMA_DUMP_STATS_FILE'):
208 goma_utils.SendGomaStats(env['GOMA_DUMP_STATS_FILE'],
209 env.get('GOMACTL_CRASH_REPORT_ID_FILE'),
210 options.build_data_dir)
211
212 if options.goma_disable_local_fallback:
213 print 'error: failed to start goma; fallback has been disabled'
214 raise Exception('failed to start goma')
215
216 print 'warning: failed to start goma. falling back to non-goma'
217 # Drop goma from options.compiler
218 options.compiler = options.compiler.replace('goma-', '')
219 if options.compiler == 'goma':
220 options.compiler = None
221 # Reset options.goma_dir.
222 options.goma_dir = None
223 env['GOMA_DISABLED'] = '1'
224 return False, None
225
226
227 # TODO(tikuta): move to goma_utils.py
228 def goma_teardown(options, env, exit_status, cloudtail_proc):
229 """Tears down goma if necessary. """
230 if (options.compiler in ('goma', 'goma-clang') and
231 options.goma_dir):
232 override_gsutil = None
233 if options.gsutil_py_path:
234 override_gsutil = [sys.executable, options.gsutil_py_path]
235
236 # If goma compiler_proxy crashes during the build, there could be crash
237 # dump.
238 if options.build_data_dir:
239 env['GOMACTL_CRASH_REPORT_ID_FILE'] = os.path.join(options.build_data_dir,
240 'crash_report_id_file')
241 goma_ctl_cmd = [sys.executable,
242 os.path.join(options.goma_dir, 'goma_ctl.py')]
243 if options.goma_jsonstatus:
244 chromium_utils.RunCommand(
245 goma_ctl_cmd + ['jsonstatus', options.goma_jsonstatus], env=env)
246 goma_utils.SendGomaTsMon(options.goma_jsonstatus, exit_status)
247 # Always stop the proxy for now to allow in-place update.
248 chromium_utils.RunCommand(goma_ctl_cmd + ['stop'], env=env)
249 goma_utils.UploadGomaCompilerProxyInfo(override_gsutil=override_gsutil)
250 if env.get('GOMA_DUMP_STATS_FILE'):
251 goma_utils.SendGomaStats(env['GOMA_DUMP_STATS_FILE'],
252 env.get('GOMACTL_CRASH_REPORT_ID_FILE'),
253 options.build_data_dir)
254 if cloudtail_proc:
255 cloudtail_proc.terminate()
256 cloudtail_proc.wait()
257
258
259 def maybe_set_official_build_envvars(options, env): 66 def maybe_set_official_build_envvars(options, env):
260 if options.mode == 'google_chrome' or options.mode == 'official': 67 if options.mode == 'google_chrome' or options.mode == 'official':
261 env['CHROMIUM_BUILD'] = '_google_chrome' 68 env['CHROMIUM_BUILD'] = '_google_chrome'
262 69
263 if options.mode == 'official': 70 if options.mode == 'official':
264 # Official builds are always Google Chrome. 71 # Official builds are always Google Chrome.
265 env['CHROME_BUILD_TYPE'] = '_official' 72 env['CHROME_BUILD_TYPE'] = '_official'
266 73
267 74
268 class EnsureUpToDateFilter(chromium_utils.RunCommandFilter): 75 class EnsureUpToDateFilter(chromium_utils.RunCommandFilter):
269 """Filter for RunCommand that checks whether the output contains ninja's 76 """Filter for RunCommand that checks whether the output contains ninja's
270 message for a no-op build.""" 77 message for a no-op build."""
271 def __init__(self): 78 def __init__(self):
272 self.was_up_to_date = False 79 self.was_up_to_date = False
273 80
274 def FilterLine(self, a_line): 81 def FilterLine(self, a_line):
275 if 'ninja: no work to do.' in a_line: 82 if 'ninja: no work to do.' in a_line:
276 self.was_up_to_date = True 83 self.was_up_to_date = True
277 return a_line 84 return a_line
278 85
279 86
280 def NeedEnvFileUpdateOnWin(env):
281 """Returns true if environment file need to be updated."""
282 # Following GOMA_* are applied to compiler_proxy not gomacc,
283 # you do not need to update environment files.
284 ignore_envs = (
285 'GOMA_API_KEY_FILE',
286 'GOMA_DEPS_CACHE_DIR',
287 'GOMA_HERMETIC',
288 'GOMA_RPC_EXTRA_PARAMS',
289 'GOMA_ALLOWED_NETWORK_ERROR_DURATION'
290 )
291 for key in env.overrides:
292 if key not in ignore_envs:
293 return True
294 return False
295
296
297 def UpdateWindowsEnvironment(envfile_dir, env): 87 def UpdateWindowsEnvironment(envfile_dir, env):
298 """Update windows environment in environment.{x86,x64}. 88 """Update windows environment in environment.{x86,x64}.
299 89
300 Args: 90 Args:
301 envfile_dir: a directory name environment.{x86,x64} are stored. 91 envfile_dir: a directory name environment.{x86,x64} are stored.
302 env: an instance of EchoDict that represents environment. 92 env: an instance of EchoDict that represents environment.
303 """ 93 """
304 # envvars_to_save come from _ExtractImportantEnvironment in 94 # envvars_to_save come from _ExtractImportantEnvironment in
305 # https://chromium.googlesource.com/external/gyp/+/\ 95 # https://chromium.googlesource.com/external/gyp/+/\
306 # master/pylib/gyp/msvs_emuation.py 96 # master/pylib/gyp/msvs_emuation.py
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
340 if not entry: 130 if not entry:
341 continue 131 continue
342 key, value = entry.split('=', 1) 132 key, value = entry.split('=', 1)
343 env_in_file[key] = value 133 env_in_file[key] = value
344 env_in_file.update(env_to_store) 134 env_in_file.update(env_to_store)
345 with open(path, 'wb') as f: 135 with open(path, 'wb') as f:
346 f.write(nul.join(['%s=%s' % (k, v) for k, v in env_in_file.iteritems()])) 136 f.write(nul.join(['%s=%s' % (k, v) for k, v in env_in_file.iteritems()]))
347 f.write(nul * 2) 137 f.write(nul * 2)
348 138
349 139
350 # TODO(tikuta): move to goma_utils
351 def determine_goma_jobs():
352 # We would like to speed up build on Windows a bit, since it is slowest.
353 number_of_processors = 0
354 try:
355 number_of_processors = multiprocessing.cpu_count()
356 except NotImplementedError:
357 print 'cpu_count() is not implemented, using default value 50.'
358 return 50
359
360 assert number_of_processors > 0
361
362 # When goma is used, 10 * number_of_processors is basically good in
363 # various situations according to our measurement. Build speed won't
364 # be improved if -j is larger than that.
365 #
366 # Since Mac had process number limitation before, we had to set
367 # the upper limit to 50. Now that the process number limitation is 2000,
368 # so we would be able to use 10 * number_of_processors.
369 # For the safety, we'd like to set the upper limit to 200.
370 #
371 # Note that currently most try-bot build slaves have 8 processors.
372 if chromium_utils.IsMac() or chromium_utils.IsWindows():
373 return min(10 * number_of_processors, 200)
374
375 # For Linux, we also would like to use 10 * cpu. However, not sure
376 # backend resource is enough, so let me set Linux and Linux x64 builder
377 # only for now.
378 hostname = goma_utils.GetShortHostname()
379 if hostname in (
380 ['build14-m1', 'build48-m1'] +
381 # Also increasing cpus for v8/blink trybots.
382 ['build%d-m4' % x for x in xrange(45, 48)] +
383 # Also increasing cpus for LTO buildbots.
384 ['slave%d-c1' % x for x in [20, 33] + range(78, 108)]):
385 return min(10 * number_of_processors, 200)
386
387 return 50
388
389
390 def main_ninja(options, args, env): 140 def main_ninja(options, args, env):
391 """This function calls ninja. 141 """This function calls ninja.
392 142
393 Args: 143 Args:
394 options (Option): options for ninja command. 144 options (Option): options for ninja command.
395 args (str): extra args for ninja command. 145 args (str): extra args for ninja command.
396 env (dict): Used when ninja command executes. 146 env (dict): Used when ninja command executes.
397 147
398 Returns: 148 Returns:
399 int: ninja command exit status. 149 int: ninja command exit status.
400 150
401 """ 151 """
402 152
403 exit_status = -1 153 exit_status = -1
404 154
405 try: 155 try:
406 print 'chdir to %s' % options.src_dir 156 print 'chdir to %s' % options.src_dir
407 os.chdir(options.src_dir) 157 os.chdir(options.src_dir)
408 158
409 command = [options.ninja_path, '-w', 'dupbuild=err', 159 command = [options.ninja_path, '-w', 'dupbuild=err',
410 '-C', options.target_output_dir] 160 '-C', options.target_output_dir]
411 161
412 # HACK(yyanagisawa): update environment files on |env| update.
413 # For compiling on Windows, environment in environment files are used.
414 # It means even if enviroment such as GOMA_DISABLED is updated in
415 # compile.py, the update will be ignored.
416 # We need to update environment files to reflect the update.
417 if chromium_utils.IsWindows() and NeedEnvFileUpdateOnWin(env):
418 print 'Updating environment.{x86,x64} files.'
419 UpdateWindowsEnvironment(options.target_output_dir, env)
420
421 if options.clobber: 162 if options.clobber:
422 print 'Removing %s' % options.target_output_dir 163 print 'Removing %s' % options.target_output_dir
423 # Deleting output_dir would also delete all the .ninja files necessary to 164 # Deleting output_dir would also delete all the .ninja files necessary to
424 # build. Clobbering should run before runhooks (which creates .ninja 165 # build. Clobbering should run before runhooks (which creates .ninja
425 # files). For now, only delete all non-.ninja files. 166 # files). For now, only delete all non-.ninja files.
426 # TODO(thakis): Make "clobber" a step that runs before "runhooks". 167 # TODO(thakis): Make "clobber" a step that runs before "runhooks".
427 # Once the master has been restarted, remove all clobber handling 168 # Once the master has been restarted, remove all clobber handling
428 # from compile.py, https://crbug.com/574557 169 # from compile.py, https://crbug.com/574557
429 build_directory.RmtreeExceptNinjaOrGomaFiles(options.target_output_dir) 170 build_directory.RmtreeExceptNinjaOrGomaFiles(options.target_output_dir)
430 171
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
503 if chromium_utils.IsLinux(): 244 if chromium_utils.IsLinux():
504 option_parser.add_option('--cros-board', action='store', 245 option_parser.add_option('--cros-board', action='store',
505 help='If building for the ChromeOS Simple Chrome ' 246 help='If building for the ChromeOS Simple Chrome '
506 'workflow, the name of the ChromeOS board.') 247 'workflow, the name of the ChromeOS board.')
507 option_parser.add_option('--out-dir', action='store', 248 option_parser.add_option('--out-dir', action='store',
508 help='Specify a custom output directory.') 249 help='Specify a custom output directory.')
509 option_parser.add_option('--goma-dir', 250 option_parser.add_option('--goma-dir',
510 default=os.path.join(BUILD_DIR, 'goma'), 251 default=os.path.join(BUILD_DIR, 'goma'),
511 help='specify goma directory') 252 help='specify goma directory')
512 option_parser.add_option('--goma-cache-dir', 253 option_parser.add_option('--goma-cache-dir',
513 default=DEFAULT_GOMA_CACHE_DIR, 254 default=goma_utils.DEFAULT_GOMA_CACHE_DIR,
514 help='specify goma cache directory') 255 help='specify goma cache directory')
515 option_parser.add_option('--goma-deps-cache-dir', 256 option_parser.add_option('--goma-deps-cache-dir',
516 help='specify goma deps cache directory') 257 help='specify goma deps cache directory')
517 option_parser.add_option('--goma-hermetic', default='error', 258 option_parser.add_option('--goma-hermetic', default='error',
518 help='Set goma hermetic mode') 259 help='Set goma hermetic mode')
519 option_parser.add_option('--goma-enable-remote-link', default=None, 260 option_parser.add_option('--goma-enable-remote-link', default=None,
520 help='Enable goma remote link.') 261 help='Enable goma remote link.')
521 option_parser.add_option('--goma-enable-compiler-info-cache', 262 option_parser.add_option('--goma-enable-compiler-info-cache',
522 action='store_true', 263 action='store_true',
523 help='Enable goma CompilerInfo cache') 264 help='Enable goma CompilerInfo cache')
(...skipping 29 matching lines...) Expand all
553 return options, args 294 return options, args
554 295
555 296
556 def real_main(): 297 def real_main():
557 options, args = get_parsed_options() 298 options, args = get_parsed_options()
558 299
559 # Prepare environment. 300 # Prepare environment.
560 env = EchoDict(os.environ) 301 env = EchoDict(os.environ)
561 302
562 # start goma 303 # start goma
563 goma_ready, goma_cloudtail = goma_setup(options, env) 304 goma_ready, goma_cloudtail = goma_utils.goma_setup(options, env)
564 305
565 if not goma_ready: 306 if goma_ready:
307 if options.goma_jobs is None:
308 options.goma_jobs = goma_utils.determine_goma_jobs()
309 else:
566 assert options.compiler not in ('goma', 'goma-clang') 310 assert options.compiler not in ('goma', 'goma-clang')
567 assert options.goma_dir is None 311 assert options.goma_dir is None
568 elif options.goma_jobs is None: 312 options.goma_jobs = goma_utils.determine_goma_jobs()
569 options.goma_jobs = determine_goma_jobs() 313
570 314
571 # build 315 # build
572 exit_status = main_ninja(options, args, env) 316 exit_status = main_ninja(options, args, env)
573 317
574 # stop goma 318 # stop goma
575 goma_teardown(options, env, exit_status, goma_cloudtail) 319 goma_utils.goma_teardown(options, env, exit_status, goma_cloudtail)
576 320
577 return exit_status 321 return exit_status
578 322
579 323
580 if '__main__' == __name__: 324 if '__main__' == __name__:
581 sys.exit(real_main()) 325 sys.exit(real_main())
OLDNEW
« no previous file with comments | « no previous file | scripts/slave/goma_utils.py » ('j') | scripts/slave/goma_utils.py » ('J')

Powered by Google App Engine
This is Rietveld 408576698