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

Side by Side Diff: recipe_engine/util.py

Issue 1773273003: Make output placeholders like json.output index-able by name. (Closed) Base URL: https://chromium.googlesource.com/external/github.com/luci/recipes-py@master
Patch Set: Rebase uppon https://codereview.chromium.org/1785543004/ Created 4 years, 9 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
OLDNEW
1 # Copyright 2013-2015 The Chromium Authors. All rights reserved. 1 # Copyright 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 import contextlib 5 import contextlib
6 import functools 6 import functools
7 import os 7 import os
8 import sys 8 import sys
9 import traceback 9 import traceback
10 import urllib 10 import urllib
(...skipping 18 matching lines...) Expand all
29 "RecipeApi has no dependency %r. (Add it to DEPS?)" % (key,)) 29 "RecipeApi has no dependency %r. (Add it to DEPS?)" % (key,))
30 else: 30 else:
31 raise ModuleInjectionError( 31 raise ModuleInjectionError(
32 "Recipe Module %r has no dependency %r. (Add it to __init__.py:DEPS?)" 32 "Recipe Module %r has no dependency %r. (Add it to __init__.py:DEPS?)"
33 % (self.owner_module.name, key)) 33 % (self.owner_module.name, key))
34 34
35 35
36 class Placeholder(object): 36 class Placeholder(object):
37 """Base class for command line argument placeholders. Do not use directly.""" 37 """Base class for command line argument placeholders. Do not use directly."""
38 def __init__(self): 38 def __init__(self):
39 self.name_pieces = None 39 self.namespaces = None
40 40
41 @property 41 @property
42 def backing_file(self): # pragma: no cover 42 def backing_file(self): # pragma: no cover
43 """Return path to a temp file that holds or receives the data. 43 """Return path to a temp file that holds or receives the data.
44 44
45 Valid only after 'render' has been called. 45 Valid only after 'render' has been called.
46 """ 46 """
47 raise NotImplementedError 47 raise NotImplementedError
48 48
49 def render(self, test): # pragma: no cover 49 def render(self, test): # pragma: no cover
50 """Return [cmd items]*""" 50 """Return [cmd items]*"""
51 raise NotImplementedError 51 raise NotImplementedError
52 52
53 def result(self, presentation, test): 53 def result(self, presentation, test):
54 """Called after step completion. 54 """Called after step completion.
55 55
56 Args: 56 Args:
57 presentation (StepPresentation) - for the current step. 57 presentation (StepPresentation) - for the current step.
58 test (PlaceholderTestData) - test data for this placeholder. 58 test (PlaceholderTestData) - test data for this placeholder.
59 59
60 May optionally modify presentation as a side-effect. 60 May optionally modify presentation as a side-effect.
61 """ 61 """
62 pass 62 pass
63 63
64 @property 64 @property
65 def name(self): 65 def namespace(self):
66 assert self.name_pieces 66 assert self.namespaces
67 return "%s.%s" % self.name_pieces 67 return "%s.%s" % self.namespaces
iannucci 2016/03/12 03:43:55 should we consider a format like "json.output[labe
stgao 2016/03/22 05:58:04 This is handled by the full_name below. Moved it u
68 68
69 69
70 class InputPlaceholder(Placeholder): 70 class InputPlaceholder(Placeholder):
71 """Base class for json/raw_io input placeholders. Do not use directly.""" 71 """Base class for json/raw_io input placeholders. Do not use directly."""
72 def result(self, presentation, test): 72 def result(self, presentation, test):
73 """Returned value will be discarded.""" 73 """Returned value will be discarded."""
74 pass 74 pass
75 result.__doc__ = Placeholder.result.__doc__ 75 result.__doc__ = Placeholder.result.__doc__
76 76
77 77
78 class OutputPlaceholder(Placeholder): 78 class OutputPlaceholder(Placeholder):
79 """Base class for json/raw_io output placeholders. Do not use directly.""" 79 """Base class for json/raw_io output placeholders. Do not use directly."""
80
81 def __init__(self, name=None):
82 if name is not None:
83 assert isinstance(name, basestring)
84 self.name = name
85 super(OutputPlaceholder, self).__init__()
86
80 def result(self, presentation, test): 87 def result(self, presentation, test):
81 """Returned value will be added to the step result.""" 88 """Returned value will be added to the step result."""
82 pass 89 pass
83 result.__doc__ = Placeholder.result.__doc__ 90 result.__doc__ = Placeholder.result.__doc__
84 91
92 @property
93 def full_name(self):
94 if self.name is None:
95 return super(OutputPlaceholder, self).namespace
96 else:
97 return "%s.%s" % (self.name, super(OutputPlaceholder, self).namespace)
98
85 99
86 def static_wraps(func): 100 def static_wraps(func):
87 wrapped_fn = func 101 wrapped_fn = func
88 if isinstance(func, staticmethod): 102 if isinstance(func, staticmethod):
89 # __get__(obj) is the way to get the function contained in the staticmethod. 103 # __get__(obj) is the way to get the function contained in the staticmethod.
90 # python 2.7+ has a __func__ member, but previous to this the attribute 104 # python 2.7+ has a __func__ member, but previous to this the attribute
91 # doesn't exist. It doesn't matter what the obj is, as long as it's not 105 # doesn't exist. It doesn't matter what the obj is, as long as it's not
92 # None. 106 # None.
93 wrapped_fn = func.__get__(object) 107 wrapped_fn = func.__get__(object)
94 return functools.wraps(wrapped_fn) 108 return functools.wraps(wrapped_fn)
(...skipping 11 matching lines...) Expand all
106 return func.__get__(obj).__name__ 120 return func.__get__(obj).__name__
107 else: 121 else:
108 return func.__name__ 122 return func.__name__
109 123
110 124
111 def returns_placeholder(func): 125 def returns_placeholder(func):
112 @static_wraps(func) 126 @static_wraps(func)
113 def inner(self, *args, **kwargs): 127 def inner(self, *args, **kwargs):
114 ret = static_call(self, func, *args, **kwargs) 128 ret = static_call(self, func, *args, **kwargs)
115 assert isinstance(ret, Placeholder) 129 assert isinstance(ret, Placeholder)
116 ret.name_pieces = (self.name, static_name(self, func)) 130 ret.namespaces = (self.name, static_name(self, func))
117 return ret 131 return ret
118 # prevent this placeholder-returning function from becoming a composite_step. 132 # prevent this placeholder-returning function from becoming a composite_step.
119 inner._non_step = True # pylint: disable=protected-access 133 inner._non_step = True # pylint: disable=protected-access
120 return inner 134 return inner
121 135
122 136
123 def scan_directory(path, predicate): 137 def scan_directory(path, predicate):
124 """Recursively scans a directory and yields paths that match predicate.""" 138 """Recursively scans a directory and yields paths that match predicate."""
125 for root, _dirs, files in os.walk(path): 139 for root, _dirs, files in os.walk(path):
126 for file_name in (f for f in files if predicate(f)): 140 for file_name in (f for f in files if predicate(f)):
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
178 self.lines[-1].write(s) 192 self.lines[-1].write(s)
179 break 193 break
180 self.lines[-1].write(s[:i]) 194 self.lines[-1].write(s[:i])
181 self.lines[-1] = self.lines[-1].getvalue() 195 self.lines[-1] = self.lines[-1].getvalue()
182 self.lines.append(StringIO()) 196 self.lines.append(StringIO())
183 s = s[i+1:] 197 s = s[i+1:]
184 198
185 def close(self): 199 def close(self):
186 if not isinstance(self.lines[-1], basestring): 200 if not isinstance(self.lines[-1], basestring):
187 self.lines[-1] = self.lines[-1].getvalue() 201 self.lines[-1] = self.lines[-1].getvalue()
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698