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

Side by Side Diff: recipe_engine/step_runner.py

Issue 2320223002: Revert of Track step nesting in StreamEngine. (Closed) Base URL: https://github.com/luci/recipes-py@emit-initial-properties
Patch Set: Created 4 years, 3 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 | « recipe_engine/simulation_test.py ('k') | recipe_engine/stream.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 # Copyright 2016 The LUCI Authors. All rights reserved. 1 # Copyright 2016 The LUCI Authors. All rights reserved.
2 # Use of this source code is governed under the Apache License, Version 2.0 2 # Use of this source code is governed under the Apache License, Version 2.0
3 # that can be found in the LICENSE file. 3 # that can be found in the LICENSE file.
4 4
5 import StringIO 5 import StringIO
6 import collections 6 import collections
7 import contextlib 7 import contextlib
8 import datetime 8 import datetime
9 import json 9 import json
10 import os 10 import os
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
90 """Constructs an OpenStep object which can be used to actually run a step. 90 """Constructs an OpenStep object which can be used to actually run a step.
91 91
92 step_dict parameters: 92 step_dict parameters:
93 name: name of the step, will appear in buildbots waterfall 93 name: name of the step, will appear in buildbots waterfall
94 cmd: command to run, list of one or more strings 94 cmd: command to run, list of one or more strings
95 cwd: absolute path to working directory for the command 95 cwd: absolute path to working directory for the command
96 env: dict with overrides for environment variables 96 env: dict with overrides for environment variables
97 allow_subannotations: if True, lets the step emit its own annotations 97 allow_subannotations: if True, lets the step emit its own annotations
98 trigger_specs: a list of trigger specifications, see also _trigger_builds. 98 trigger_specs: a list of trigger specifications, see also _trigger_builds.
99 stdout: Path to a file to put step stdout into. If used, stdout won't 99 stdout: Path to a file to put step stdout into. If used, stdout won't
100 appear in annotator's stdout (and |allow_subannotations| is 100 appear in annotator's stdout (and |allow_subannotations| is
101 ignored). 101 ignored).
102 stderr: Path to a file to put step stderr into. If used, stderr won't 102 stderr: Path to a file to put step stderr into. If used, stderr won't
103 appear in annotator's stderr. 103 appear in annotator's stderr.
104 stdin: Path to a file to read step stdin from. 104 stdin: Path to a file to read step stdin from.
105 step_nest_level: the step's nesting level.
106 105
107 Returns an OpenStep object. 106 Returns an OpenStep object.
108 """ 107 """
109 raise NotImplementedError() 108 raise NotImplementedError()
110 109
111 def run_recipe(self, universe, recipe, properties): 110 def run_recipe(self, universe, recipe, properties):
112 """Run the recipe named |recipe|. 111 """Run the recipe named |recipe|.
113 112
114 Args: 113 Args:
115 universe: The RecipeUniverse where the recipe lives. 114 universe: The RecipeUniverse where the recipe lives.
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
158 157
159 def __init__(self, stream_engine): 158 def __init__(self, stream_engine):
160 self._stream_engine = stream_engine 159 self._stream_engine = stream_engine
161 160
162 @property 161 @property
163 def stream_engine(self): 162 def stream_engine(self):
164 return self._stream_engine 163 return self._stream_engine
165 164
166 def open_step(self, step_dict): 165 def open_step(self, step_dict):
167 allow_subannotations = step_dict.get('allow_subannotations', False) 166 allow_subannotations = step_dict.get('allow_subannotations', False)
168 nest_level = step_dict.pop('step_nest_level', 0)
169
170 step_stream = self._stream_engine.new_step_stream( 167 step_stream = self._stream_engine.new_step_stream(
171 step_dict['name'], 168 step_dict['name'],
172 allow_subannotations=allow_subannotations, 169 allow_subannotations=allow_subannotations)
173 nest_level=nest_level)
174 if not step_dict.get('cmd'): 170 if not step_dict.get('cmd'):
175 class EmptyOpenStep(OpenStep): 171 class EmptyOpenStep(OpenStep):
176 def run(inner): 172 def run(inner):
177 if 'trigger_specs' in step_dict: 173 if 'trigger_specs' in step_dict:
178 self._trigger_builds(step_stream, step_dict['trigger_specs']) 174 self._trigger_builds(step_stream, step_dict['trigger_specs'])
179 return types.StepData(step_dict, 0) 175 return types.StepData(step_dict, 0)
180 176
181 def finalize(inner): 177 def finalize(inner):
182 step_stream.close() 178 step_stream.close()
183 179
184 @property 180 @property
185 def stream(inner): 181 def stream(inner):
186 return step_stream 182 return step_stream
187 183
188 return EmptyOpenStep() 184 return EmptyOpenStep()
189 185
190 step_dict, placeholders = render_step( 186 step_dict, placeholders = render_step(
191 step_dict, recipe_test_api.DisabledTestData()) 187 step_dict, recipe_test_api.DisabledTestData())
192 cmd = map(str, step_dict['cmd']) 188 cmd = map(str, step_dict['cmd'])
193 step_env = _merge_envs(os.environ, step_dict.get('env', {})) 189 step_env = _merge_envs(os.environ, step_dict.get('env', {}))
190 if 'nest_level' in step_dict:
191 step_stream.step_nest_level(step_dict['nest_level'])
194 self._print_step(step_stream, step_dict, step_env) 192 self._print_step(step_stream, step_dict, step_env)
195 193
196 class ReturnOpenStep(OpenStep): 194 class ReturnOpenStep(OpenStep):
197 def run(inner): 195 def run(inner):
198 try: 196 try:
199 # Open file handles for IO redirection based on file names in 197 # Open file handles for IO redirection based on file names in
200 # step_dict. 198 # step_dict.
201 handles = { 199 handles = {
202 'stdout': step_stream, 200 'stdout': step_stream,
203 'stderr': step_stream, 201 'stderr': step_stream,
(...skipping 190 matching lines...) Expand 10 before | Expand all | Expand 10 after
394 return change 392 return change
395 393
396 394
397 class SimulationStepRunner(StepRunner): 395 class SimulationStepRunner(StepRunner):
398 """Pretends to run steps, instead recording what would have been run. 396 """Pretends to run steps, instead recording what would have been run.
399 397
400 This is the main workhorse of recipes.py simulation_test. Returns the log of 398 This is the main workhorse of recipes.py simulation_test. Returns the log of
401 steps that would have been run in steps_ran. Uses test_data to mock return 399 steps that would have been run in steps_ran. Uses test_data to mock return
402 values. 400 values.
403 """ 401 """
404 def __init__(self, stream_engine, test_data, annotator): 402 def __init__(self, stream_engine, test_data):
405 self._test_data = test_data 403 self._test_data = test_data
406 self._stream_engine = stream_engine 404 self._stream_engine = stream_engine
407 self._annotator = annotator
408 self._step_history = collections.OrderedDict() 405 self._step_history = collections.OrderedDict()
409 406
410 @property 407 @property
411 def stream_engine(self): 408 def stream_engine(self):
412 return self._stream_engine 409 return self._stream_engine
413 410
414 def open_step(self, step_dict): 411 def open_step(self, step_dict):
415 # We modify step_dict. In particular, we add ~followup_annotations during 412 # We modify step_dict. In particular, we add ~followup_annotations during
416 # finalize, and depend on that side-effect being carried into what we 413 # finalize, and depend on that side-effect being carried into what we
417 # added to self._step_history, earlier. So copy it here so at least we 414 # added to self._step_history, earlier. So copy it here so at least we
418 # keep the modifications local. 415 # keep the modifications local.
419 step_dict = dict(step_dict) 416 step_dict = dict(step_dict)
420 nest_level = step_dict.pop('step_nest_level', 0)
421 417
422 test_data_fn = step_dict.pop('step_test_data', recipe_test_api.StepTestData) 418 test_data_fn = step_dict.pop('step_test_data', recipe_test_api.StepTestData)
423 step_test = self._test_data.pop_step_test_data( 419 step_test = self._test_data.pop_step_test_data(
424 step_dict['name'], test_data_fn) 420 step_dict['name'], test_data_fn)
425 step_dict, placeholders = render_step(step_dict, step_test) 421 step_dict, placeholders = render_step(step_dict, step_test)
422 outstream = StringIO.StringIO()
426 423
427 # Layer the simulation step on top of the given stream engine. 424 # Layer the simulation step on top of the given stream engine.
428 step_stream = self._stream_engine.new_step_stream( 425 step_stream = stream.ProductStreamEngine.StepStream(
429 step_dict['name'], 426 self._stream_engine.new_step_stream(step_dict['name']),
430 nest_level=nest_level) 427 stream.BareAnnotationStepStream(outstream))
431 428
432 class ReturnOpenStep(OpenStep): 429 class ReturnOpenStep(OpenStep):
433 def run(inner): 430 def run(inner):
434 timeout = step_dict.get('timeout') 431 timeout = step_dict.get('timeout')
435 if (timeout and step_test.times_out_after and 432 if (timeout and step_test.times_out_after and
436 step_test.times_out_after > timeout): 433 step_test.times_out_after > timeout):
437 raise recipe_api.StepTimeout(step_dict['name'], timeout) 434 raise recipe_api.StepTimeout(step_dict['name'], timeout)
438 435
439 self._step_history[step_dict['name']] = step_dict 436 self._step_history[step_dict['name']] = step_dict
440 return construct_step_result(step_dict, step_test.retcode, placeholders) 437 return construct_step_result(step_dict, step_test.retcode, placeholders)
441 438
442 def finalize(inner): 439 def finalize(inner):
443 # note that '~' sorts after 'z' so that this will be last on each 440 # note that '~' sorts after 'z' so that this will be last on each
444 # step. also use _step to get access to the mutable step 441 # step. also use _step to get access to the mutable step
445 # dictionary. 442 # dictionary.
446 buf = self._annotator.step_buffer(step_dict['name']) 443 lines = filter(None, outstream.getvalue()).splitlines()
447 lines = filter(None, buf.getvalue()).splitlines()
448 lines = [stream.encode_str(x) for x in lines] 444 lines = [stream.encode_str(x) for x in lines]
449 if lines: 445 if lines:
450 # This magically floats into step_history, which we have already 446 # This magically floats into step_history, which we have already
451 # added step_dict to. 447 # added step_dict to.
452 step_dict['~followup_annotations'] = lines 448 step_dict['~followup_annotations'] = lines
453 step_stream.close()
454 449
455 @property 450 @property
456 def stream(inner): 451 def stream(inner):
457 return step_stream 452 return step_stream
458 453
459 return ReturnOpenStep() 454 return ReturnOpenStep()
460 455
461 def run_recipe(self, universe, recipe, properties): 456 def run_recipe(self, universe, recipe, properties):
462 return self._test_data.depend_on_data.pop(types.freeze((recipe, properties), )) 457 return self._test_data.depend_on_data.pop(types.freeze((recipe, properties), ))
463 458
(...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after
661 supplied command, and only uses the |env| kwarg for modifying the environment 656 supplied command, and only uses the |env| kwarg for modifying the environment
662 of the child process. 657 of the child process.
663 """ 658 """
664 saved_path = os.environ['PATH'] 659 saved_path = os.environ['PATH']
665 try: 660 try:
666 if path is not None: 661 if path is not None:
667 os.environ['PATH'] = path 662 os.environ['PATH'] = path
668 yield 663 yield
669 finally: 664 finally:
670 os.environ['PATH'] = saved_path 665 os.environ['PATH'] = saved_path
OLDNEW
« no previous file with comments | « recipe_engine/simulation_test.py ('k') | recipe_engine/stream.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698