OLD | NEW |
1 # Copyright 2013 The Chromium Authors. All rights reserved. | 1 # Copyright 2013 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 import functools | 5 import functools |
6 import json | 6 import json |
7 import os | 7 import os |
8 import tempfile | 8 import tempfile |
9 | 9 |
10 from slave import recipe_api | 10 from slave import recipe_api |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
48 try: | 48 try: |
49 result_data.output = json.loads(raw_data) | 49 result_data.output = json.loads(raw_data) |
50 stream.emit('step returned json data: """\n%s\n"""' % | 50 stream.emit('step returned json data: """\n%s\n"""' % |
51 (result_data.output,)) | 51 (result_data.output,)) |
52 except ValueError: | 52 except ValueError: |
53 stream.emit('step had invalid json data: """\n%s\n"""' % | 53 stream.emit('step had invalid json data: """\n%s\n"""' % |
54 raw_data) | 54 raw_data) |
55 os.unlink(self.output_file) | 55 os.unlink(self.output_file) |
56 | 56 |
57 | 57 |
58 class JsonInputPlaceholder(recipe_api.Placeholder): | |
59 """JsonInputPlaceholder is meant to be a non-singleton object which, when | |
60 added to a step's cmd list, will be replaced by annotated_run with a | |
61 /path/to/json file during the evaluation of your recipe generator. | |
62 | |
63 The file will have the json-string passed to __init__, and is guaranteed to | |
64 exist solely for the duration of the step. | |
65 | |
66 Multiple instances of thif placeholder can occur in a step's command, and | |
67 each will be serialized to a different input file. | |
68 """ | |
69 __slots__ = ['json_string'] | |
70 | |
71 def __init__(self, json_string): | |
72 assert isinstance(json_string, basestring) | |
73 self.json_string = json_string | |
74 self.input_file = None | |
75 super(JsonInputPlaceholder, self).__init__() | |
76 | |
77 def render(self, test_data): | |
78 if test_data is not None: | |
79 # cheat and pretend like we're going to pass the data on the | |
80 # cmdline for test expectation purposes. | |
81 return [self.json_string] | |
82 else: # pragma: no cover | |
83 json_input_fd, self.input_file = tempfile.mkstemp() | |
84 os.write(json_input_fd, self.json_string) | |
85 os.close(json_input_fd) | |
86 return [self.input_file] | |
87 | |
88 def step_finished(self, stream, step_result, test_data): | |
89 if test_data is None: # pragma: no cover | |
90 os.unlink(self.input_file) | |
91 | |
92 | |
93 class JsonApi(recipe_api.RecipeApi): | 58 class JsonApi(recipe_api.RecipeApi): |
94 def __init__(self, **kwargs): | 59 def __init__(self, **kwargs): |
95 super(JsonApi, self).__init__(**kwargs) | 60 super(JsonApi, self).__init__(**kwargs) |
96 self.loads = json.loads | 61 self.loads = json.loads |
97 @functools.wraps(json.dumps) | 62 @functools.wraps(json.dumps) |
98 def dumps(*args, **kwargs): | 63 def dumps(*args, **kwargs): |
99 kwargs['sort_keys'] = True | 64 kwargs['sort_keys'] = True |
100 return json.dumps(*args, **kwargs) | 65 return json.dumps(*args, **kwargs) |
101 self.dumps = dumps | 66 self.dumps = dumps |
102 | 67 |
103 def input(self, data): | 68 def input(self, data): |
104 """A placeholder which will expand to a file path containing <data>.""" | 69 """A placeholder which will expand to a file path containing <data>.""" |
105 return JsonInputPlaceholder(self.dumps(data)) | 70 return recipe_api.InputDataPlaceholder(self.dumps(data), '.json') |
106 | 71 |
107 @staticmethod | 72 @staticmethod |
108 def output(): | 73 def output(): |
109 """A placeholder which will expand to '--output-json /tmp/file'.""" | 74 """A placeholder which will expand to '--output-json /tmp/file'.""" |
110 return JsonOutputPlaceholder() | 75 return JsonOutputPlaceholder() |
111 | 76 |
112 def property_args(self): | 77 def property_args(self): |
113 """Return --build-properties and --factory-properties arguments. LEGACY! | 78 """Return --build-properties and --factory-properties arguments. LEGACY! |
114 | 79 |
115 Since properties is the merge of build_properties and factory_properties, | 80 Since properties is the merge of build_properties and factory_properties, |
116 pass the merged dict as both arguments. | 81 pass the merged dict as both arguments. |
117 | 82 |
118 It's vastly preferable to have your recipe only pass the bare minimum | 83 It's vastly preferable to have your recipe only pass the bare minimum |
119 of arguments to steps. Passing property objects obscures the data that | 84 of arguments to steps. Passing property objects obscures the data that |
120 the script actually consumes from the property object. | 85 the script actually consumes from the property object. |
121 """ | 86 """ |
122 prop_str = self.dumps(dict(self.m.properties)) | 87 prop_str = self.dumps(dict(self.m.properties)) |
123 return [ | 88 return [ |
124 '--factory-properties', prop_str, | 89 '--factory-properties', prop_str, |
125 '--build-properties', prop_str | 90 '--build-properties', prop_str |
126 ] | 91 ] |
127 | 92 |
OLD | NEW |