OLD | NEW |
1 #!/usr/bin/python | 1 #!/usr/bin/python |
2 | 2 |
3 """ | 3 """ |
4 Copyright 2013 Google Inc. | 4 Copyright 2013 Google Inc. |
5 | 5 |
6 Use of this source code is governed by a BSD-style license that can be | 6 Use of this source code is governed by a BSD-style license that can be |
7 found in the LICENSE file. | 7 found in the LICENSE file. |
8 | 8 |
9 Repackage expected/actual GM results as needed by our HTML rebaseline viewer. | 9 Repackage expected/actual GM results as needed by our HTML rebaseline viewer. |
10 """ | 10 """ |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
52 KEY__HEADER__TYPE = 'type' | 52 KEY__HEADER__TYPE = 'type' |
53 KEY__NEW_IMAGE_URL = 'newImageUrl' | 53 KEY__NEW_IMAGE_URL = 'newImageUrl' |
54 KEY__RESULT_TYPE__FAILED = gm_json.JSONKEY_ACTUALRESULTS_FAILED | 54 KEY__RESULT_TYPE__FAILED = gm_json.JSONKEY_ACTUALRESULTS_FAILED |
55 KEY__RESULT_TYPE__FAILUREIGNORED = gm_json.JSONKEY_ACTUALRESULTS_FAILUREIGNORED | 55 KEY__RESULT_TYPE__FAILUREIGNORED = gm_json.JSONKEY_ACTUALRESULTS_FAILUREIGNORED |
56 KEY__RESULT_TYPE__NOCOMPARISON = gm_json.JSONKEY_ACTUALRESULTS_NOCOMPARISON | 56 KEY__RESULT_TYPE__NOCOMPARISON = gm_json.JSONKEY_ACTUALRESULTS_NOCOMPARISON |
57 KEY__RESULT_TYPE__SUCCEEDED = gm_json.JSONKEY_ACTUALRESULTS_SUCCEEDED | 57 KEY__RESULT_TYPE__SUCCEEDED = gm_json.JSONKEY_ACTUALRESULTS_SUCCEEDED |
58 | 58 |
59 IMAGE_FILENAME_RE = re.compile(gm_json.IMAGE_FILENAME_PATTERN) | 59 IMAGE_FILENAME_RE = re.compile(gm_json.IMAGE_FILENAME_PATTERN) |
60 IMAGE_FILENAME_FORMATTER = '%s_%s.png' # pass in (testname, config) | 60 IMAGE_FILENAME_FORMATTER = '%s_%s.png' # pass in (testname, config) |
61 | 61 |
62 # Ignore expectations/actuals for builders matching any of these patterns. | 62 DEFAULT_ACTUALS_DIR = '.gm-actuals' |
| 63 DEFAULT_GENERATED_IMAGES_ROOT = os.path.join( |
| 64 PARENT_DIRECTORY, '.generated-images') |
| 65 |
| 66 # Define the default set of builders we will process expectations/actuals for. |
63 # This allows us to ignore builders for which we don't maintain expectations | 67 # This allows us to ignore builders for which we don't maintain expectations |
64 # (trybots, Valgrind, ASAN, TSAN), and avoid problems like | 68 # (trybots, Valgrind, ASAN, TSAN), and avoid problems like |
65 # https://code.google.com/p/skia/issues/detail?id=2036 ('rebaseline_server | 69 # https://code.google.com/p/skia/issues/detail?id=2036 ('rebaseline_server |
66 # produces error when trying to add baselines for ASAN/TSAN builders') | 70 # produces error when trying to add baselines for ASAN/TSAN builders') |
67 SKIP_BUILDERS_PATTERN_LIST = [re.compile(p) for p in [ | 71 DEFAULT_MATCH_BUILDERS_PATTERN_LIST = ['.*'] |
68 '.*-Trybot', '.*Valgrind.*', '.*TSAN.*', '.*ASAN.*']] | 72 DEFAULT_SKIP_BUILDERS_PATTERN_LIST = [ |
69 | 73 '.*-Trybot', '.*Valgrind.*', '.*TSAN.*', '.*ASAN.*'] |
70 DEFAULT_ACTUALS_DIR = '.gm-actuals' | |
71 DEFAULT_GENERATED_IMAGES_ROOT = os.path.join( | |
72 PARENT_DIRECTORY, '.generated-images') | |
73 | 74 |
74 | 75 |
75 class BaseComparisons(object): | 76 class BaseComparisons(object): |
76 """Base class for generating summary of comparisons between two image sets. | 77 """Base class for generating summary of comparisons between two image sets. |
77 """ | 78 """ |
78 | 79 |
79 def __init__(self): | |
80 raise NotImplementedError('cannot instantiate the abstract base class') | |
81 | |
82 def get_results_of_type(self, results_type): | 80 def get_results_of_type(self, results_type): |
83 """Return results of some/all tests (depending on 'results_type' parameter). | 81 """Return results of some/all tests (depending on 'results_type' parameter). |
84 | 82 |
85 Args: | 83 Args: |
86 results_type: string describing which types of results to include; must | 84 results_type: string describing which types of results to include; must |
87 be one of the RESULTS_* constants | 85 be one of the RESULTS_* constants |
88 | 86 |
89 Results are returned in a dictionary as output by ImagePairSet.as_dict(). | 87 Results are returned in a dictionary as output by ImagePairSet.as_dict(). |
90 """ | 88 """ |
91 return self._results[results_type] | 89 return self._results[results_type] |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
131 KEY__HEADER__IS_EXPORTED: is_exported, | 129 KEY__HEADER__IS_EXPORTED: is_exported, |
132 } | 130 } |
133 return response_dict | 131 return response_dict |
134 | 132 |
135 def get_timestamp(self): | 133 def get_timestamp(self): |
136 """Return the time at which this object was created, in seconds past epoch | 134 """Return the time at which this object was created, in seconds past epoch |
137 (UTC). | 135 (UTC). |
138 """ | 136 """ |
139 return self._timestamp | 137 return self._timestamp |
140 | 138 |
141 @staticmethod | 139 _match_builders_pattern_list = [ |
142 def _ignore_builder(builder): | 140 re.compile(p) for p in DEFAULT_MATCH_BUILDERS_PATTERN_LIST] |
143 """Returns True if this builder matches any of SKIP_BUILDERS_PATTERN_LIST. | 141 _skip_builders_pattern_list = [ |
| 142 re.compile(p) for p in DEFAULT_SKIP_BUILDERS_PATTERN_LIST] |
| 143 |
| 144 def set_match_builders_pattern_list(self, pattern_list): |
| 145 """Override the default set of builders we should process. |
| 146 |
| 147 The default is DEFAULT_MATCH_BUILDERS_PATTERN_LIST . |
| 148 |
| 149 Note that skip_builders_pattern_list overrides this; regardless of whether a |
| 150 builder is in the "match" list, if it's in the "skip" list, we will skip it. |
| 151 |
| 152 Args: |
| 153 pattern_list: list of regex patterns; process builders that match any |
| 154 entry within this list |
| 155 """ |
| 156 if pattern_list == None: |
| 157 pattern_list = [] |
| 158 self._match_builders_pattern_list = [re.compile(p) for p in pattern_list] |
| 159 |
| 160 def set_skip_builders_pattern_list(self, pattern_list): |
| 161 """Override the default set of builders we should skip while processing. |
| 162 |
| 163 The default is DEFAULT_SKIP_BUILDERS_PATTERN_LIST . |
| 164 |
| 165 This overrides match_builders_pattern_list; regardless of whether a |
| 166 builder is in the "match" list, if it's in the "skip" list, we will skip it. |
| 167 |
| 168 Args: |
| 169 pattern_list: list of regex patterns; skip builders that match any |
| 170 entry within this list |
| 171 """ |
| 172 if pattern_list == None: |
| 173 pattern_list = [] |
| 174 self._skip_builders_pattern_list = [re.compile(p) for p in pattern_list] |
| 175 |
| 176 def _ignore_builder(self, builder): |
| 177 """Returns True if we should skip processing this builder. |
144 | 178 |
145 Args: | 179 Args: |
146 builder: name of this builder, as a string | 180 builder: name of this builder, as a string |
147 | 181 |
148 Returns: | 182 Returns: |
149 True if we should ignore expectations and actuals for this builder. | 183 True if we should ignore expectations and actuals for this builder. |
150 """ | 184 """ |
151 for pattern in SKIP_BUILDERS_PATTERN_LIST: | 185 for pattern in self._skip_builders_pattern_list: |
152 if pattern.match(builder): | 186 if pattern.match(builder): |
153 return True | 187 return True |
154 return False | 188 for pattern in self._match_builders_pattern_list: |
| 189 if pattern.match(builder): |
| 190 return False |
| 191 return True |
155 | 192 |
156 @staticmethod | 193 def _read_dicts_from_root(self, root, pattern='*.json'): |
157 def _read_dicts_from_root(root, pattern='*.json'): | |
158 """Read all JSON dictionaries within a directory tree. | 194 """Read all JSON dictionaries within a directory tree. |
159 | 195 |
160 Args: | 196 Args: |
161 root: path to root of directory tree | 197 root: path to root of directory tree |
162 pattern: which files to read within root (fnmatch-style pattern) | 198 pattern: which files to read within root (fnmatch-style pattern) |
163 | 199 |
164 Returns: | 200 Returns: |
165 A meta-dictionary containing all the JSON dictionaries found within | 201 A meta-dictionary containing all the JSON dictionaries found within |
166 the directory tree, keyed by the builder name of each dictionary. | 202 the directory tree, keyed by the builder name of each dictionary. |
167 | 203 |
168 Raises: | 204 Raises: |
169 IOError if root does not refer to an existing directory | 205 IOError if root does not refer to an existing directory |
170 """ | 206 """ |
171 if not os.path.isdir(root): | 207 if not os.path.isdir(root): |
172 raise IOError('no directory found at path %s' % root) | 208 raise IOError('no directory found at path %s' % root) |
173 meta_dict = {} | 209 meta_dict = {} |
174 for dirpath, dirnames, filenames in os.walk(root): | 210 for dirpath, dirnames, filenames in os.walk(root): |
175 for matching_filename in fnmatch.filter(filenames, pattern): | 211 for matching_filename in fnmatch.filter(filenames, pattern): |
176 builder = os.path.basename(dirpath) | 212 builder = os.path.basename(dirpath) |
177 if BaseComparisons._ignore_builder(builder): | 213 if self._ignore_builder(builder): |
178 continue | 214 continue |
179 fullpath = os.path.join(dirpath, matching_filename) | 215 fullpath = os.path.join(dirpath, matching_filename) |
180 meta_dict[builder] = gm_json.LoadFromFile(fullpath) | 216 meta_dict[builder] = gm_json.LoadFromFile(fullpath) |
181 return meta_dict | 217 return meta_dict |
182 | 218 |
183 @staticmethod | 219 @staticmethod |
184 def _create_relative_url(hashtype_and_digest, test_name): | 220 def _create_relative_url(hashtype_and_digest, test_name): |
185 """Returns the URL for this image, relative to GM_ACTUALS_ROOT_HTTP_URL. | 221 """Returns the URL for this image, relative to GM_ACTUALS_ROOT_HTTP_URL. |
186 | 222 |
187 If we don't have a record of this image, returns None. | 223 If we don't have a record of this image, returns None. |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
220 | 256 |
221 If this would result in any repeated keys, it will raise an Exception. | 257 If this would result in any repeated keys, it will raise an Exception. |
222 """ | 258 """ |
223 output_dict = {} | 259 output_dict = {} |
224 for key, subdict in input_dict.iteritems(): | 260 for key, subdict in input_dict.iteritems(): |
225 for subdict_key, subdict_value in subdict.iteritems(): | 261 for subdict_key, subdict_value in subdict.iteritems(): |
226 if subdict_key in output_dict: | 262 if subdict_key in output_dict: |
227 raise Exception('duplicate key %s in combine_subdicts' % subdict_key) | 263 raise Exception('duplicate key %s in combine_subdicts' % subdict_key) |
228 output_dict[subdict_key] = subdict_value | 264 output_dict[subdict_key] = subdict_value |
229 return output_dict | 265 return output_dict |
OLD | NEW |