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

Side by Side Diff: scripts/common/annotator.py

Issue 17635005: Make blink_trybot recipe work on windows (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/build
Patch Set: Address comments Created 7 years, 6 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 | Annotate | Revision Log
« no previous file with comments | « no previous file | scripts/common/unittests/annotator_test.py » ('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 (c) 2013 The Chromium Authors. All rights reserved. 2 # Copyright (c) 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 """Contains generating and parsing systems of the Chromium Buildbot Annotator. 6 """Contains generating and parsing systems of the Chromium Buildbot Annotator.
7 7
8 When executed as a script, this reads step name / command pairs from a file and 8 When executed as a script, this reads step name / command pairs from a file and
9 executes those lines while annotating the output. The input is json: 9 executes those lines while annotating the output. The input is json:
10 10
11 [{"name": "step_name", "cmd": ["command", "arg1", "arg2"]}, 11 [{"name": "step_name", "cmd": ["command", "arg1", "arg2"]},
12 {"name": "step_name2", "cmd": ["command2", "arg1"]}] 12 {"name": "step_name2", "cmd": ["command2", "arg1"]}]
13 13
14 """ 14 """
15 15
16 import itertools
16 import json 17 import json
17 import optparse 18 import optparse
18 import os 19 import os
19 import re 20 import re
21 import subprocess
20 import sys 22 import sys
23 import threading
21 import traceback 24 import traceback
22 25
23 from common import chromium_utils
24
25 26
26 def emit(line, stream, flush_before=None): 27 def emit(line, stream, flush_before=None):
27 if flush_before: 28 if flush_before:
28 flush_before.flush() 29 flush_before.flush()
29 print >> stream, '\n' + line 30 print >> stream
31 # WinDOS can only handle 64kb of output to the console at a time, per process.
32 if sys.platform.startswith('win'):
33 lim = 2**15
34 while line:
35 to_print, line = line[:lim], line[lim:]
36 stream.write(to_print)
37 else:
38 print >> stream, line
30 stream.flush() 39 stream.flush()
31 40
32 41
33 class StepCommands(object): 42 class StepCommands(object):
34 """Class holding step commands. Intended to be subclassed.""" 43 """Class holding step commands. Intended to be subclassed."""
35 def __init__(self, stream, flush_before): 44 def __init__(self, stream, flush_before):
36 self.stream = stream 45 self.stream = stream
37 self.flush_before = flush_before 46 self.flush_before = flush_before
38 47
39 def emit(self, line): 48 def emit(self, line):
(...skipping 366 matching lines...) Expand 10 before | Expand all | Expand 10 after
406 415
407 # For error reporting. 416 # For error reporting.
408 step_dict = locals().copy() 417 step_dict = locals().copy()
409 step_dict.pop('kwargs') 418 step_dict.pop('kwargs')
410 step_dict.pop('stream') 419 step_dict.pop('stream')
411 step_dict.update(kwargs) 420 step_dict.update(kwargs)
412 421
413 for step_name in (seed_steps or []): 422 for step_name in (seed_steps or []):
414 stream.seed_step(step_name) 423 stream.seed_step(step_name)
415 424
416 filter_obj = None
417 if not allow_subannotations:
418 class AnnotationFilter(chromium_utils.RunCommandFilter):
419 # Missing __init__
420 # Method could be a function (but not really since it's an override)
421 # pylint: disable=W0232,R0201
422 def FilterLine(self, line):
423 return line.replace('@@@', '###')
424 filter_obj = AnnotationFilter()
425
426 ret = None 425 ret = None
427 with stream.step(name) as s: 426 with stream.step(name) as s:
428 print_step(step_dict) 427 print_step(step_dict)
429 try: 428 try:
430 ret = chromium_utils.RunCommand(command=cmd, 429 proc = subprocess.Popen(
431 cwd=cwd, 430 cmd,
432 env=_merge_envs(os.environ, env), 431 env=_merge_envs(os.environ, env),
433 filter_obj=filter_obj, 432 cwd=cwd,
434 print_cmd=False) 433 stdout=subprocess.PIPE,
434 stderr=subprocess.PIPE)
435
436 outlock = threading.Lock()
437 def filter_lines(lock, allow_subannotations, inhandle, outhandle):
438 while True:
439 line = inhandle.readline()
440 if not line:
441 break
442 lock.acquire()
443 try:
444 if not allow_subannotations:
445 outhandle.write('!')
446 outhandle.write(line)
447 outhandle.flush()
448 finally:
449 lock.release()
450
451 outthread = threading.Thread(
452 target=filter_lines,
453 args=(outlock, allow_subannotations, proc.stdout, sys.stdout))
454 errthread = threading.Thread(
455 target=filter_lines,
456 args=(outlock, allow_subannotations, proc.stderr, sys.stderr))
457 outthread.start()
458 errthread.start()
459 proc.wait()
460 outthread.join()
461 errthread.join()
462 ret = proc.returncode
435 except OSError: 463 except OSError:
436 # File wasn't found, error will be reported to stream when the exception 464 # File wasn't found, error will be reported to stream when the exception
437 # crosses the context manager. 465 # crosses the context manager.
438 ret = -1 466 ret = -1
439 raise 467 raise
440 if ret > 0: 468 if ret > 0:
441 stream.step_cursor(stream.current_step) 469 stream.step_cursor(stream.current_step)
442 print 'step returned non-zero exit code: %d' % ret 470 print 'step returned non-zero exit code: %d' % ret
443 s.step_failure() 471 s.step_failure()
444 if followup_fn: 472 if followup_fn:
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
482 usage = '%s <command list file or - for stdin>' % sys.argv[0] 510 usage = '%s <command list file or - for stdin>' % sys.argv[0]
483 parser = optparse.OptionParser(usage=usage) 511 parser = optparse.OptionParser(usage=usage)
484 _, args = parser.parse_args() 512 _, args = parser.parse_args()
485 if not args: 513 if not args:
486 parser.error('Must specify an input filename.') 514 parser.error('Must specify an input filename.')
487 if len(args) > 1: 515 if len(args) > 1:
488 parser.error('Too many arguments specified.') 516 parser.error('Too many arguments specified.')
489 517
490 steps = [] 518 steps = []
491 519
520 def force_list_str(lst):
521 ret = []
522 for v in lst:
523 if isinstance(v, basestring):
524 v = str(v)
525 elif isinstance(v, list):
526 v = force_list_str(v)
agable 2013/06/25 21:26:35 you want elif isinstance(v, dict) up here too, for
527 ret.append(v)
528 return ret
529
530 def force_dict_strs(obj):
531 ret = {}
532 for k, v in obj.iteritems():
533 if isinstance(v, basestring):
534 v = str(v)
535 elif isinstance(v, list):
536 v = force_list_str(v)
537 elif isinstance(v, dict):
538 v = force_dict_strs(v)
539 ret[str(k)] = v
540 return ret
541
492 if args[0] == '-': 542 if args[0] == '-':
493 steps.extend(json.load(sys.stdin)) 543 steps.extend(json.load(sys.stdin, object_hook=force_dict_strs))
494 else: 544 else:
495 with open(args[0], 'rb') as f: 545 with open(args[0], 'rb') as f:
496 steps.extend(json.load(f)) 546 steps.extend(json.load(f, object_hook=force_dict_strs))
497 547
498 return 1 if run_steps(steps, False)[0] else 0 548 return 1 if run_steps(steps, False)[0] else 0
499 549
500 550
501 if __name__ == '__main__': 551 if __name__ == '__main__':
502 sys.exit(main()) 552 sys.exit(main())
OLDNEW
« no previous file with comments | « no previous file | scripts/common/unittests/annotator_test.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698