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 |