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

Side by Side Diff: recipe_modules/json/api.py

Issue 2989423002: Add add_json_log='on_failure' to json module. (Closed)
Patch Set: Add unittests Created 3 years, 4 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 | « README.recipes.md ('k') | recipe_modules/json/tests/add_json_log.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 2013 The LUCI Authors. All rights reserved. 1 # Copyright 2013 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 """Methods for producing and consuming JSON.""" 5 """Methods for producing and consuming JSON."""
6 6
7 import functools 7 import functools
8 import collections 8 import collections
9 import contextlib 9 import contextlib
10 import json 10 import json
(...skipping 20 matching lines...) Expand all
31 will be available as part of the step result. 31 will be available as part of the step result.
32 32
33 Example: 33 Example:
34 result = api.step('step name', 34 result = api.step('step name',
35 ['write_json_to_file.sh', api.json.output()]) 35 ['write_json_to_file.sh', api.json.output()])
36 # `result.json.output` is the parsed JSON value. 36 # `result.json.output` is the parsed JSON value.
37 37
38 See the example recipe (./examples/full.py) for some more uses. 38 See the example recipe (./examples/full.py) for some more uses.
39 """ 39 """
40 def __init__(self, api, add_json_log, name=None, leak_to=None): 40 def __init__(self, api, add_json_log, name=None, leak_to=None):
41 assert add_json_log in (True, False, 'on_failure'), (
42 'add_json_log=%r' % add_json_log)
41 self.raw = api.m.raw_io.output_text('.json', leak_to=leak_to) 43 self.raw = api.m.raw_io.output_text('.json', leak_to=leak_to)
42 self.add_json_log = add_json_log 44 self.add_json_log = add_json_log
43 super(JsonOutputPlaceholder, self).__init__(name=name) 45 super(JsonOutputPlaceholder, self).__init__(name=name)
44 46
45 @property 47 @property
46 def backing_file(self): 48 def backing_file(self):
47 return self.raw.backing_file 49 return self.raw.backing_file
48 50
49 def render(self, test): 51 def render(self, test):
50 return self.raw.render(test) 52 return self.raw.render(test)
51 53
52 def result(self, presentation, test): 54 def result(self, presentation, test):
53 raw_data = self.raw.result(presentation, test) 55 raw_data = self.raw.result(presentation, test)
54 56
55 valid = False 57 valid = False
56 invalid_error = '' 58 invalid_error = ''
57 ret = None 59 ret = None
58 try: 60 try:
59 ret = JsonApi.loads( 61 ret = JsonApi.loads(
60 raw_data, object_pairs_hook=collections.OrderedDict) 62 raw_data, object_pairs_hook=collections.OrderedDict)
61 valid = True 63 valid = True
62 # TypeError is raised when raw_data is None, which can happen if the json 64 # TypeError is raised when raw_data is None, which can happen if the json
63 # file was not created. We then correctly handle this as invalid result. 65 # file was not created. We then correctly handle this as invalid result.
64 except (ValueError, TypeError) as ex: # pragma: no cover 66 except (ValueError, TypeError) as ex: # pragma: no cover
65 invalid_error = str(ex) 67 invalid_error = str(ex)
66 68
67 if self.add_json_log: 69 if self.add_json_log is True or (
70 self.add_json_log == 'on_failure' and presentation.status != 'SUCCESS'):
68 if valid: 71 if valid:
69 with contextlib.closing(recipe_util.StringListIO()) as listio: 72 with contextlib.closing(recipe_util.StringListIO()) as listio:
70 json.dump(ret, listio, indent=2, sort_keys=True) 73 json.dump(ret, listio, indent=2, sort_keys=True)
71 presentation.logs[self.label] = listio.lines 74 presentation.logs[self.label] = listio.lines
72 else: 75 else:
73 presentation.logs[self.label + ' (invalid)'] = raw_data.splitlines() 76 presentation.logs[self.label + ' (invalid)'] = raw_data.splitlines()
74 presentation.logs[self.label + ' (exception)'] = ( 77 presentation.logs[self.label + ' (exception)'] = (
75 invalid_error.splitlines()) 78 invalid_error.splitlines())
76 79
77 return ret 80 return ret
(...skipping 23 matching lines...) Expand all
101 """A placeholder which will expand to a file path containing <data>.""" 104 """A placeholder which will expand to a file path containing <data>."""
102 return self.m.raw_io.input_text(self.dumps(data), '.json') 105 return self.m.raw_io.input_text(self.dumps(data), '.json')
103 106
104 @recipe_util.returns_placeholder 107 @recipe_util.returns_placeholder
105 def output(self, add_json_log=True, name=None, leak_to=None): 108 def output(self, add_json_log=True, name=None, leak_to=None):
106 """A placeholder which will expand to '/tmp/file'. 109 """A placeholder which will expand to '/tmp/file'.
107 110
108 If leak_to is provided, it must be a Path object. This path will be used in 111 If leak_to is provided, it must be a Path object. This path will be used in
109 place of a random temporary file, and the file will not be deleted at the 112 place of a random temporary file, and the file will not be deleted at the
110 end of the step. 113 end of the step.
114
115 Args:
116 * add_json_log (True|False|'on_failure') - Log a copy of the output json
117 to a step link named `name`. If this is 'on_failure', only create this
118 log when the step has a non-SUCCESS status.
111 """ 119 """
112 return JsonOutputPlaceholder(self, add_json_log, name=name, leak_to=leak_to) 120 return JsonOutputPlaceholder(self, add_json_log, name=name, leak_to=leak_to)
113 121
114 # TODO(you): This method should be in the `file` recipe_module 122 # TODO(you): This method should be in the `file` recipe_module
115 def read(self, name, path, add_json_log=True, output_name=None, **kwargs): 123 def read(self, name, path, add_json_log=True, output_name=None, **kwargs):
116 """Returns a step that reads a JSON file.""" 124 """Returns a step that reads a JSON file."""
117 return self.m.python.inline( 125 return self.m.python.inline(
118 name, 126 name,
119 """ 127 """
120 import shutil 128 import shutil
121 import sys 129 import sys
122 shutil.copy(sys.argv[1], sys.argv[2]) 130 shutil.copy(sys.argv[1], sys.argv[2])
123 """, 131 """,
124 args=[path, 132 args=[path,
125 self.output(add_json_log=add_json_log, name=output_name)], 133 self.output(add_json_log=add_json_log, name=output_name)],
126 add_python_log=False, 134 add_python_log=False,
127 **kwargs 135 **kwargs
128 ) 136 )
OLDNEW
« no previous file with comments | « README.recipes.md ('k') | recipe_modules/json/tests/add_json_log.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698