| OLD | NEW |
| 1 # Copyright (c) 2015 The Chromium Authors. All rights reserved. | 1 # Copyright (c) 2015 The Chromium Authors. All rights reserved. |
| 2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
| 4 | 4 |
| 5 """Contains the parsing system of the Chromium Buildbot Annotator.""" | 5 """Contains the parsing system of the Chromium Buildbot Annotator.""" |
| 6 | 6 |
| 7 import os | 7 import os |
| 8 import sys | 8 import sys |
| 9 import time |
| 9 import traceback | 10 import traceback |
| 10 | 11 |
| 11 # These are maps of annotation key -> number of expected arguments. | 12 # These are maps of annotation key -> number of expected arguments. |
| 12 STEP_ANNOTATIONS = { | 13 STEP_ANNOTATIONS = { |
| 13 'SET_BUILD_PROPERTY': 2, | 14 'SET_BUILD_PROPERTY': 2, |
| 14 'STEP_CLEAR': 0, | 15 'STEP_CLEAR': 0, |
| 15 'STEP_EXCEPTION': 0, | 16 'STEP_EXCEPTION': 0, |
| 16 'STEP_FAILURE': 0, | 17 'STEP_FAILURE': 0, |
| 17 'STEP_LINK': 2, | 18 'STEP_LINK': 2, |
| 18 'STEP_LOG_END': 1, | 19 'STEP_LOG_END': 1, |
| 19 'STEP_LOG_END_PERF': 2, | 20 'STEP_LOG_END_PERF': 2, |
| 20 'STEP_LOG_LINE': 2, | 21 'STEP_LOG_LINE': 2, |
| 21 'STEP_SUMMARY_CLEAR': 0, | 22 'STEP_SUMMARY_CLEAR': 0, |
| 22 'STEP_SUMMARY_TEXT': 1, | 23 'STEP_SUMMARY_TEXT': 1, |
| 23 'STEP_TEXT': 1, | 24 'STEP_TEXT': 1, |
| 24 'STEP_TRIGGER': 1, | 25 'STEP_TRIGGER': 1, |
| 25 'STEP_WARNINGS': 0, | 26 'STEP_WARNINGS': 0, |
| 26 'STEP_NEST_LEVEL': 1, | 27 'STEP_NEST_LEVEL': 1, |
| 27 } | 28 } |
| 28 | 29 |
| 29 CONTROL_ANNOTATIONS = { | 30 CONTROL_ANNOTATIONS = { |
| 30 'STEP_CLOSED': 0, | 31 'STEP_CLOSED': 0, |
| 31 'STEP_STARTED': 0, | 32 'STEP_STARTED': 0, |
| 32 } | 33 } |
| 33 | 34 |
| 34 STREAM_ANNOTATIONS = { | 35 STREAM_ANNOTATIONS = { |
| 36 # CURRENT_TIMESTAMP has one parameter, current Unix timestamp, which in |
| 37 # practice specifies timestamp of the following annotation. |
| 38 # The following annotation MUST be emitted immediately, |
| 39 # however there is no requirement for the annotation after the next one |
| 40 # to be emitted immediately. Annotation parsers must not consider |
| 41 # CURRENT_TIMESTAMP for annotations that follow the annotation which is next |
| 42 # after the CURRENT_TIMESTAMP. |
| 43 'CURRENT_TIMESTAMP': 1, |
| 35 'HALT_ON_FAILURE': 0, | 44 'HALT_ON_FAILURE': 0, |
| 36 'HONOR_ZERO_RETURN_CODE': 0, | 45 'HONOR_ZERO_RETURN_CODE': 0, |
| 37 'SEED_STEP': 1, | 46 'SEED_STEP': 1, |
| 38 'SEED_STEP_TEXT': 2, | 47 'SEED_STEP_TEXT': 2, |
| 39 'STEP_CURSOR': 1, | 48 'STEP_CURSOR': 1, |
| 40 } | 49 } |
| 41 | 50 |
| 42 DEPRECATED_ANNOTATIONS = { | 51 DEPRECATED_ANNOTATIONS = { |
| 43 'BUILD_STEP': 1, | 52 'BUILD_STEP': 1, |
| 44 } | 53 } |
| (...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 190 | 199 |
| 191 class StructuredAnnotationStep(StepCommands, StepControlCommands): | 200 class StructuredAnnotationStep(StepCommands, StepControlCommands): |
| 192 """Helper class to provide context for a step.""" | 201 """Helper class to provide context for a step.""" |
| 193 | 202 |
| 194 def __init__(self, annotation_stream, *args, **kwargs): | 203 def __init__(self, annotation_stream, *args, **kwargs): |
| 195 self.annotation_stream = annotation_stream | 204 self.annotation_stream = annotation_stream |
| 196 super(StructuredAnnotationStep, self).__init__(*args, **kwargs) | 205 super(StructuredAnnotationStep, self).__init__(*args, **kwargs) |
| 197 self.control = StepControlCommands(self.stream, self.flush_before) | 206 self.control = StepControlCommands(self.stream, self.flush_before) |
| 198 self.emitted_logs = set() | 207 self.emitted_logs = set() |
| 199 | 208 |
| 200 | |
| 201 def __enter__(self): | 209 def __enter__(self): |
| 202 return self.step_started() | 210 return self.step_started() |
| 203 | 211 |
| 204 def step_started(self): | 212 def step_started(self): |
| 213 self.annotation_stream.emit_current_timestamp() |
| 205 self.control.step_started() | 214 self.control.step_started() |
| 206 return self | 215 return self |
| 207 | 216 |
| 208 def __exit__(self, exc_type, exc_value, tb): | 217 def __exit__(self, exc_type, exc_value, tb): |
| 209 self.annotation_stream.step_cursor(self.annotation_stream.current_step) | 218 self.annotation_stream.step_cursor(self.annotation_stream.current_step) |
| 210 #TODO(martinis) combine this and step_ended | 219 #TODO(martinis) combine this and step_ended |
| 211 if exc_type: | 220 if exc_type: |
| 212 self.step_exception_occured(exc_type, exc_value, tb) | 221 self.step_exception_occured(exc_type, exc_value, tb) |
| 213 | 222 |
| 223 self.annotation_stream.emit_current_timestamp() |
| 214 self.control.step_closed() | 224 self.control.step_closed() |
| 215 self.annotation_stream.current_step = '' | 225 self.annotation_stream.current_step = '' |
| 216 return not exc_type | 226 return not exc_type |
| 217 | 227 |
| 218 def step_exception_occured(self, exc_type, exc_value, tb): | 228 def step_exception_occured(self, exc_type, exc_value, tb): |
| 219 trace = traceback.format_exception(exc_type, exc_value, tb) | 229 trace = traceback.format_exception(exc_type, exc_value, tb) |
| 220 trace_lines = ''.join(trace).split('\n') | 230 trace_lines = ''.join(trace).split('\n') |
| 221 self.write_log_lines('exception', filter(None, trace_lines)) | 231 self.write_log_lines('exception', filter(None, trace_lines)) |
| 222 self.step_exception() | 232 self.step_exception() |
| 223 | 233 |
| 224 def step_ended(self): | 234 def step_ended(self): |
| 225 self.annotation_stream.step_cursor(self.annotation_stream.current_step) | 235 self.annotation_stream.step_cursor(self.annotation_stream.current_step) |
| 236 self.annotation_stream.emit_current_timestamp() |
| 226 self.control.step_closed() | 237 self.control.step_closed() |
| 227 self.annotation_stream.current_step = '' | 238 self.annotation_stream.current_step = '' |
| 228 | 239 |
| 229 return True | 240 return True |
| 230 | 241 |
| 231 | 242 |
| 232 class StructuredAnnotationStream(AnnotationPrinter): | 243 class StructuredAnnotationStream(AnnotationPrinter): |
| 233 """Provides an interface to handle an annotated build. | 244 """Provides an interface to handle an annotated build. |
| 234 | 245 |
| 235 StructuredAnnotationStream handles most of the step setup and closure calls | 246 StructuredAnnotationStream handles most of the step setup and closure calls |
| (...skipping 10 matching lines...) Expand all Loading... |
| 246 s.step_failure() | 257 s.step_failure() |
| 247 with stream.step('test') as s: | 258 with stream.step('test') as s: |
| 248 # do something | 259 # do something |
| 249 if warnings: | 260 if warnings: |
| 250 s.step_warnings() | 261 s.step_warnings() |
| 251 """ | 262 """ |
| 252 ANNOTATIONS = STREAM_ANNOTATIONS | 263 ANNOTATIONS = STREAM_ANNOTATIONS |
| 253 | 264 |
| 254 def __init__(self, stream=sys.stdout, | 265 def __init__(self, stream=sys.stdout, |
| 255 flush_before=sys.stderr, | 266 flush_before=sys.stderr, |
| 256 seed_steps=None): # pylint: disable=W0613 | 267 seed_steps=None, # pylint: disable=W0613 |
| 268 time_fn=None): |
| 257 super(StructuredAnnotationStream, self).__init__(stream=stream, | 269 super(StructuredAnnotationStream, self).__init__(stream=stream, |
| 258 flush_before=flush_before) | 270 flush_before=flush_before) |
| 259 self.current_step = '' | 271 self.current_step = '' |
| 272 self.time_fn = time_fn or time.time |
| 273 |
| 274 def emit_current_timestamp(self): |
| 275 self.current_timestamp(self.time_fn()) |
| 260 | 276 |
| 261 def step(self, name): | 277 def step(self, name): |
| 262 """Provide a context with which to execute a step.""" | 278 """Provide a context with which to execute a step.""" |
| 263 if self.current_step: | 279 if self.current_step: |
| 264 raise Exception('Can\'t start step %s while in step %s.' % ( | 280 raise Exception('Can\'t start step %s while in step %s.' % ( |
| 265 name, self.current_step)) | 281 name, self.current_step)) |
| 266 | 282 |
| 267 self.seed_step(name) | 283 self.seed_step(name) |
| 268 self.step_cursor(name) | 284 self.step_cursor(name) |
| 269 self.current_step = name | 285 self.current_step = name |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 339 # This prevents functions from showing up as: | 355 # This prevents functions from showing up as: |
| 340 # '<function foo at 0x7f523ec7a410>' | 356 # '<function foo at 0x7f523ec7a410>' |
| 341 # which is tricky to test. | 357 # which is tricky to test. |
| 342 value = value.__name__+'(...)' | 358 value = value.__name__+'(...)' |
| 343 step_info_lines.append(' %s: %s' % (key, value)) | 359 step_info_lines.append(' %s: %s' % (key, value)) |
| 344 step_info_lines.append('full environment:') | 360 step_info_lines.append('full environment:') |
| 345 for key, value in sorted(env.items()): | 361 for key, value in sorted(env.items()): |
| 346 step_info_lines.append(' %s: %s' % (key, value)) | 362 step_info_lines.append(' %s: %s' % (key, value)) |
| 347 step_info_lines.append('') | 363 step_info_lines.append('') |
| 348 stream.emit('\n'.join(step_info_lines)) | 364 stream.emit('\n'.join(step_info_lines)) |
| OLD | NEW |