Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 # Copyright (c) 2013-2015 The Chromium Authors. All rights reserved. | 1 # Copyright (c) 2013-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 """Entry point for fully-annotated builds. | 5 """Entry point for fully-annotated builds. |
| 6 | 6 |
| 7 This script is part of the effort to move all builds to annotator-based | 7 This script is part of the effort to move all builds to annotator-based |
| 8 systems. Any builder configured to use the AnnotatorFactory.BaseFactory() | 8 systems. Any builder configured to use the AnnotatorFactory.BaseFactory() |
| 9 found in scripts/master/factory/annotator_factory.py executes a single | 9 found in scripts/master/factory/annotator_factory.py executes a single |
| 10 AddAnnotatedScript step. That step (found in annotator_commands.py) calls | 10 AddAnnotatedScript step. That step (found in annotator_commands.py) calls |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 65 | 65 |
| 66 import collections | 66 import collections |
| 67 import contextlib | 67 import contextlib |
| 68 import copy | 68 import copy |
| 69 import functools | 69 import functools |
| 70 import json | 70 import json |
| 71 import os | 71 import os |
| 72 import re | 72 import re |
| 73 import subprocess | 73 import subprocess |
| 74 import sys | 74 import sys |
| 75 import tempfile | |
| 75 import threading | 76 import threading |
| 76 import traceback | 77 import traceback |
| 77 | 78 |
| 78 import cStringIO | 79 import cStringIO |
| 79 | 80 |
| 80 | 81 |
| 81 from . import loader | 82 from . import loader |
| 82 from . import recipe_api | 83 from . import recipe_api |
| 83 from . import recipe_test_api | 84 from . import recipe_test_api |
| 85 from . import types | |
| 84 from . import util | 86 from . import util |
| 85 | 87 |
| 86 | 88 |
| 87 SCRIPT_PATH = os.path.dirname(os.path.abspath(__file__)) | 89 SCRIPT_PATH = os.path.dirname(os.path.abspath(__file__)) |
| 88 | 90 |
| 89 BUILDBOT_MAGIC_ENV = set([ | 91 BUILDBOT_MAGIC_ENV = set([ |
| 90 'BUILDBOT_BLAMELIST', | 92 'BUILDBOT_BLAMELIST', |
| 91 'BUILDBOT_BRANCH', | 93 'BUILDBOT_BRANCH', |
| 92 'BUILDBOT_BUILDBOTURL', | 94 'BUILDBOT_BUILDBOTURL', |
| 93 'BUILDBOT_BUILDERNAME', | 95 'BUILDBOT_BUILDERNAME', |
| (...skipping 332 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 426 properties.pop('root', None) | 428 properties.pop('root', None) |
| 427 | 429 |
| 428 # TODO(iannucci): A much better way to do this would be to dynamically | 430 # TODO(iannucci): A much better way to do this would be to dynamically |
| 429 # detect if the mirrors are actually available during the execution of the | 431 # detect if the mirrors are actually available during the execution of the |
| 430 # recipe. | 432 # recipe. |
| 431 if ('use_mirror' not in properties and ( | 433 if ('use_mirror' not in properties and ( |
| 432 'TESTING_MASTERNAME' in os.environ or | 434 'TESTING_MASTERNAME' in os.environ or |
| 433 'TESTING_SLAVENAME' in os.environ)): | 435 'TESTING_SLAVENAME' in os.environ)): |
| 434 properties['use_mirror'] = False | 436 properties['use_mirror'] = False |
| 435 | 437 |
| 436 engine = RecipeEngine(stream, properties, test_data) | 438 engine = RecipeEngine(stream, properties, test_data, universe) |
| 437 | 439 |
| 438 # Create all API modules and top level RunSteps function. It doesn't launch | 440 # Create all API modules and top level RunSteps function. It doesn't launch |
| 439 # any recipe code yet; RunSteps needs to be called. | 441 # any recipe code yet; RunSteps needs to be called. |
| 440 api = None | 442 api = None |
| 441 with stream.step('setup_build') as s: | 443 with stream.step('setup_build') as s: |
| 442 assert 'recipe' in properties | 444 assert 'recipe' in properties |
| 443 recipe = properties['recipe'] | 445 recipe = properties['recipe'] |
| 444 | 446 |
| 445 properties_to_print = properties.copy() | 447 properties_to_print = properties.copy() |
| 446 if 'use_mirror' in properties: | 448 if 'use_mirror' in properties: |
| (...skipping 296 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 743 Knows how to execute steps emitted by a recipe, holds global state such as | 745 Knows how to execute steps emitted by a recipe, holds global state such as |
| 744 step history and build properties. Each recipe module API has a reference to | 746 step history and build properties. Each recipe module API has a reference to |
| 745 this object. | 747 this object. |
| 746 | 748 |
| 747 Recipe modules that are aware of the engine: | 749 Recipe modules that are aware of the engine: |
| 748 * properties - uses engine.properties. | 750 * properties - uses engine.properties. |
| 749 * step_history - uses engine.step_history. | 751 * step_history - uses engine.step_history. |
| 750 * step - uses engine.create_step(...). | 752 * step - uses engine.create_step(...). |
| 751 | 753 |
| 752 """ | 754 """ |
| 753 def __init__(self, stream, properties, test_data): | 755 def __init__(self, stream, properties, test_data, universe): |
| 754 self._stream = stream | 756 self._stream = stream |
| 755 self._properties = properties | 757 self._properties = properties |
| 756 self._test_data = test_data | 758 self._test_data = test_data |
| 757 self._step_history = collections.OrderedDict() | 759 self._step_history = collections.OrderedDict() |
| 760 self._universe = universe | |
| 758 | 761 |
| 759 self._previous_step_annotation = None | 762 self._previous_step_annotation = None |
| 760 self._previous_step_result = None | 763 self._previous_step_result = None |
| 761 self._api = None | 764 self._api = None |
| 762 | 765 |
| 766 def clone(self, stream=None, properties=None, universe=None): | |
| 767 return RecipeEngine(stream or self._stream, properties or self._properties, | |
| 768 self._test_data, universe or self._universe) | |
|
luqui
2015/11/16 20:48:00
Hmm, isn't test_data mutable, in order for example
martiniss
2015/11/18 01:00:00
Deleted this method. Not needed anymore.
| |
| 769 | |
| 763 @property | 770 @property |
| 764 def properties(self): | 771 def properties(self): |
| 765 return self._properties | 772 return self._properties |
| 766 | 773 |
| 767 @property | 774 @property |
| 768 def previous_step_result(self): | 775 def previous_step_result(self): |
| 769 """Allows api.step to get the active result from any context.""" | 776 """Allows api.step to get the active result from any context.""" |
| 770 return self._previous_step_result | 777 return self._previous_step_result |
| 771 | 778 |
| 772 def _emit_results(self): | 779 def _emit_results(self): |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 854 exc = recipe_api.InfraFailure | 861 exc = recipe_api.InfraFailure |
| 855 | 862 |
| 856 step_result.presentation.status = state | 863 step_result.presentation.status = state |
| 857 if step_test.enabled: | 864 if step_test.enabled: |
| 858 # To avoid cluttering the expectations, don't emit this in testmode. | 865 # To avoid cluttering the expectations, don't emit this in testmode. |
| 859 self._previous_step_annotation.emit( | 866 self._previous_step_annotation.emit( |
| 860 'step returned non-zero exit code: %d' % step_result.retcode) | 867 'step returned non-zero exit code: %d' % step_result.retcode) |
| 861 | 868 |
| 862 raise exc(step['name'], step_result) | 869 raise exc(step['name'], step_result) |
| 863 | 870 |
| 864 | |
| 865 def run(self, recipe_script, api): | 871 def run(self, recipe_script, api): |
| 866 """Run a recipe represented by a recipe_script object. | 872 """Run a recipe represented by a recipe_script object. |
| 867 | 873 |
| 868 This function blocks until recipe finishes. | 874 This function blocks until recipe finishes. |
| 875 It mainly executes the recipe, and has some exception handling logic, and | |
| 876 adds the step history to the result. | |
| 869 | 877 |
| 870 Args: | 878 Args: |
| 871 recipe_script: The recipe to run, as represented by a RecipeScript object. | 879 recipe_script: The recipe to run, as represented by a RecipeScript object. |
| 872 api: The api, with loaded module dependencies. | 880 api: The api, with loaded module dependencies. |
| 873 Used by the some special modules. | 881 Used by the some special modules. |
| 874 | 882 |
| 875 Returns: | 883 Returns: |
| 876 RecipeExecutionResult which has status code, list of steps ran, | 884 RecipeExecutionResult which has status code, list of steps ran, |
| 877 and return value. | 885 and return value. |
| 878 """ | 886 """ |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 933 | 941 |
| 934 Args: | 942 Args: |
| 935 step: ConfigGroup object with information about the step, see | 943 step: ConfigGroup object with information about the step, see |
| 936 recipe_modules/step/config.py. | 944 recipe_modules/step/config.py. |
| 937 | 945 |
| 938 Returns: | 946 Returns: |
| 939 Opaque engine specific object that is understood by 'run_steps' method. | 947 Opaque engine specific object that is understood by 'run_steps' method. |
| 940 """ | 948 """ |
| 941 return step.as_jsonish() | 949 return step.as_jsonish() |
| 942 | 950 |
| 951 def depend_on(self, recipe, properties, distributor=None): | |
| 952 return self.depend_on_multi( | |
| 953 ((recipe, properties),), distributor=distributor) | |
| 943 | 954 |
| 955 def depend_on_multi(self, dependencies, distributor=None): | |
| 956 if self._test_data.enabled: | |
| 957 # TODO(martiniss) test properties against the recipe | |
| 958 for recipe, properties in dependencies: | |
| 959 recipe_script = self._universe.load_recipe(recipe) | |
|
luqui
2015/11/16 20:48:00
This precludes one use case, which is that the rec
| |
| 960 loader._invoke_with_properties( | |
| 961 lambda *args, **kwargs: None, properties, recipe_script.PROPERTIES, | |
| 962 properties.keys()) | |
| 963 | |
| 964 return self._test_data.depend_on_data[types.freeze((recipe, properties), )] | |
|
luqui
2015/11/16 20:48:00
line wrap
| |
| 965 | |
| 966 # TODO(martiniss) Add DM integration | |
| 967 for recipe, properties in dependencies: | |
| 968 recipes_py_loc = os.path.join( | |
| 969 self._universe.package_deps._context.repo_root, 'recipes.py') | |
| 970 | |
| 971 with tempfile.NamedTemporaryFile() as f: | |
| 972 cmd = [sys.executable, recipes_py_loc, | |
| 973 '--package=%s' % self._universe._config_file, 'run', | |
| 974 '--result-file=%s' % f.name, recipe] | |
|
luqui
2015/11/16 20:48:00
The convention for this argument has been --output
martiniss
2015/11/18 01:00:00
Fixed.
| |
| 975 cmd.extend(['%s=%s' % (k, v) for k, v in properties.iteritems()]) | |
| 976 | |
| 977 rval = subprocess.call(cmd) | |
|
estaab
2015/11/17 23:07:16
We should probably throw an exception when rval is
martiniss
2015/11/18 01:00:00
Good idea. Raising an InfraFailure.
| |
| 978 return json.load(f) | |
| 979 | |
| 980 | |
| 981 | |
| OLD | NEW |