| 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 |