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 """ |
11 | 11 |
12 # System-level imports | 12 # System-level imports |
13 import argparse | 13 import argparse |
14 import fnmatch | 14 import fnmatch |
15 import json | |
16 import logging | 15 import logging |
17 import os | 16 import os |
18 import re | |
19 import sys | |
20 import time | 17 import time |
21 | 18 |
| 19 # Must fix up PYTHONPATH before importing from within Skia |
| 20 # pylint: disable=W0611 |
| 21 import fix_pythonpath |
| 22 # pylint: enable=W0611 |
| 23 |
22 # Imports from within Skia | 24 # Imports from within Skia |
23 import fix_pythonpath # must do this first | |
24 from pyutils import url_utils | 25 from pyutils import url_utils |
25 import gm_json | 26 import gm_json |
26 import imagediffdb | 27 import imagediffdb |
27 import imagepair | 28 import imagepair |
28 import imagepairset | 29 import imagepairset |
29 import results | 30 import results |
30 | 31 |
31 EXPECTATION_FIELDS_PASSED_THRU_VERBATIM = [ | 32 EXPECTATION_FIELDS_PASSED_THRU_VERBATIM = [ |
32 results.KEY__EXPECTATIONS__BUGS, | 33 results.KEY__EXPECTATIONS__BUGS, |
33 results.KEY__EXPECTATIONS__IGNOREFAILURE, | 34 results.KEY__EXPECTATIONS__IGNOREFAILURE, |
34 results.KEY__EXPECTATIONS__REVIEWED, | 35 results.KEY__EXPECTATIONS__REVIEWED, |
35 ] | 36 ] |
36 TRUNK_DIRECTORY = os.path.dirname(os.path.dirname(os.path.dirname(__file__))) | 37 TRUNK_DIRECTORY = os.path.dirname(os.path.dirname(os.path.dirname(__file__))) |
37 DEFAULT_EXPECTATIONS_DIR = os.path.join(TRUNK_DIRECTORY, 'expectations', 'gm') | 38 DEFAULT_EXPECTATIONS_DIR = os.path.join(TRUNK_DIRECTORY, 'expectations', 'gm') |
38 DEFAULT_IGNORE_FAILURES_FILE = 'ignored-tests.txt' | 39 DEFAULT_IGNORE_FAILURES_FILE = 'ignored-tests.txt' |
39 | 40 |
40 IMAGEPAIR_SET_DESCRIPTIONS = ('expected image', 'actual image') | 41 IMAGEPAIR_SET_DESCRIPTIONS = ('expected image', 'actual image') |
41 | 42 |
42 | 43 |
43 class ExpectationComparisons(results.BaseComparisons): | 44 class ExpectationComparisons(results.BaseComparisons): |
44 """Loads actual and expected GM results into an ImagePairSet. | 45 """Loads actual and expected GM results into an ImagePairSet. |
45 | 46 |
46 Loads actual and expected results from all builders, except for those skipped | 47 Loads actual and expected results from all builders, except for those skipped |
47 by _ignore_builder(). | 48 by _ignore_builder(). |
48 | 49 |
49 Once this object has been constructed, the results (in self._results[]) | 50 Once this object has been constructed, the results (in self._results[]) |
50 are immutable. If you want to update the results based on updated JSON | 51 are immutable. If you want to update the results based on updated JSON |
51 file contents, you will need to create a new ExpectationComparisons object.""" | 52 file contents, you will need to create a new ExpectationComparisons object.""" |
52 | 53 |
53 def __init__(self, actuals_root=results.DEFAULT_ACTUALS_DIR, | 54 def __init__(self, image_diff_db, actuals_root=results.DEFAULT_ACTUALS_DIR, |
54 expected_root=DEFAULT_EXPECTATIONS_DIR, | 55 expected_root=DEFAULT_EXPECTATIONS_DIR, |
55 ignore_failures_file=DEFAULT_IGNORE_FAILURES_FILE, | 56 ignore_failures_file=DEFAULT_IGNORE_FAILURES_FILE, |
56 generated_images_root=results.DEFAULT_GENERATED_IMAGES_ROOT, | |
57 diff_base_url=None, builder_regex_list=None): | 57 diff_base_url=None, builder_regex_list=None): |
58 """ | 58 """ |
59 Args: | 59 Args: |
| 60 image_diff_db: instance of ImageDiffDB we use to cache the image diffs |
60 actuals_root: root directory containing all actual-results.json files | 61 actuals_root: root directory containing all actual-results.json files |
61 expected_root: root directory containing all expected-results.json files | 62 expected_root: root directory containing all expected-results.json files |
62 ignore_failures_file: if a file with this name is found within | 63 ignore_failures_file: if a file with this name is found within |
63 expected_root, ignore failures for any tests listed in the file | 64 expected_root, ignore failures for any tests listed in the file |
64 generated_images_root: directory within which to create all pixel diffs; | |
65 if this directory does not yet exist, it will be created | |
66 diff_base_url: base URL within which the client should look for diff | 65 diff_base_url: base URL within which the client should look for diff |
67 images; if not specified, defaults to a "file:///" URL representation | 66 images; if not specified, defaults to a "file:///" URL representation |
68 of generated_images_root | 67 of image_diff_db's storage_root |
69 builder_regex_list: List of regular expressions specifying which builders | 68 builder_regex_list: List of regular expressions specifying which builders |
70 we will process. If None, process all builders. | 69 we will process. If None, process all builders. |
71 """ | 70 """ |
72 time_start = int(time.time()) | 71 time_start = int(time.time()) |
73 if builder_regex_list != None: | 72 if builder_regex_list != None: |
74 self.set_match_builders_pattern_list(builder_regex_list) | 73 self.set_match_builders_pattern_list(builder_regex_list) |
75 self._image_diff_db = imagediffdb.ImageDiffDB(generated_images_root) | 74 self._image_diff_db = image_diff_db |
76 self._diff_base_url = ( | 75 self._diff_base_url = ( |
77 diff_base_url or | 76 diff_base_url or |
78 url_utils.create_filepath_url(generated_images_root)) | 77 url_utils.create_filepath_url(image_diff_db.get_storage_root())) |
79 self._actuals_root = actuals_root | 78 self._actuals_root = actuals_root |
80 self._expected_root = expected_root | 79 self._expected_root = expected_root |
81 self._ignore_failures_on_these_tests = [] | 80 self._ignore_failures_on_these_tests = [] |
82 if ignore_failures_file: | 81 if ignore_failures_file: |
83 self._ignore_failures_on_these_tests = ( | 82 self._ignore_failures_on_these_tests = ( |
84 ExpectationComparisons._read_noncomment_lines( | 83 ExpectationComparisons._read_noncomment_lines( |
85 os.path.join(expected_root, ignore_failures_file))) | 84 os.path.join(expected_root, ignore_failures_file))) |
86 self._load_actual_and_expected() | 85 self._load_actual_and_expected() |
87 self._timestamp = int(time.time()) | 86 self._timestamp = int(time.time()) |
88 logging.info('Results complete; took %d seconds.' % | 87 logging.info('Results complete; took %d seconds.' % |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
164 pattern: which files to write within root (fnmatch-style pattern) | 163 pattern: which files to write within root (fnmatch-style pattern) |
165 | 164 |
166 Raises: | 165 Raises: |
167 IOError if root does not refer to an existing directory | 166 IOError if root does not refer to an existing directory |
168 KeyError if the set of per-builder dictionaries written out was | 167 KeyError if the set of per-builder dictionaries written out was |
169 different than expected | 168 different than expected |
170 """ | 169 """ |
171 if not os.path.isdir(root): | 170 if not os.path.isdir(root): |
172 raise IOError('no directory found at path %s' % root) | 171 raise IOError('no directory found at path %s' % root) |
173 actual_builders_written = [] | 172 actual_builders_written = [] |
174 for dirpath, dirnames, filenames in os.walk(root): | 173 for dirpath, _, filenames in os.walk(root): |
175 for matching_filename in fnmatch.filter(filenames, pattern): | 174 for matching_filename in fnmatch.filter(filenames, pattern): |
176 builder = os.path.basename(dirpath) | 175 builder = os.path.basename(dirpath) |
177 per_builder_dict = meta_dict.get(builder) | 176 per_builder_dict = meta_dict.get(builder) |
178 if per_builder_dict is not None: | 177 if per_builder_dict is not None: |
179 fullpath = os.path.join(dirpath, matching_filename) | 178 fullpath = os.path.join(dirpath, matching_filename) |
180 gm_json.WriteToFile(per_builder_dict, fullpath) | 179 gm_json.WriteToFile(per_builder_dict, fullpath) |
181 actual_builders_written.append(builder) | 180 actual_builders_written.append(builder) |
182 | 181 |
183 # Check: did we write out the set of per-builder dictionaries we | 182 # Check: did we write out the set of per-builder dictionaries we |
184 # expected to? | 183 # expected to? |
(...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
332 imageA_relative_url=expected_image_relative_url, | 331 imageA_relative_url=expected_image_relative_url, |
333 imageB_relative_url=actual_image_relative_url, | 332 imageB_relative_url=actual_image_relative_url, |
334 expectations=expectations_dict, | 333 expectations=expectations_dict, |
335 extra_columns=extra_columns_dict) | 334 extra_columns=extra_columns_dict) |
336 all_image_pairs.add_image_pair(image_pair) | 335 all_image_pairs.add_image_pair(image_pair) |
337 if updated_result_type != results.KEY__RESULT_TYPE__SUCCEEDED: | 336 if updated_result_type != results.KEY__RESULT_TYPE__SUCCEEDED: |
338 failing_image_pairs.add_image_pair(image_pair) | 337 failing_image_pairs.add_image_pair(image_pair) |
339 except Exception: | 338 except Exception: |
340 logging.exception('got exception while creating new ImagePair') | 339 logging.exception('got exception while creating new ImagePair') |
341 | 340 |
| 341 # pylint: disable=W0201 |
342 self._results = { | 342 self._results = { |
343 results.KEY__HEADER__RESULTS_ALL: all_image_pairs.as_dict(), | 343 results.KEY__HEADER__RESULTS_ALL: all_image_pairs.as_dict(), |
344 results.KEY__HEADER__RESULTS_FAILURES: failing_image_pairs.as_dict(), | 344 results.KEY__HEADER__RESULTS_FAILURES: failing_image_pairs.as_dict(), |
345 } | 345 } |
346 | 346 |
347 | 347 |
348 def main(): | 348 def main(): |
349 logging.basicConfig(format='%(asctime)s %(levelname)s %(message)s', | 349 logging.basicConfig(format='%(asctime)s %(levelname)s %(message)s', |
350 datefmt='%m/%d/%Y %H:%M:%S', | 350 datefmt='%m/%d/%Y %H:%M:%S', |
351 level=logging.INFO) | 351 level=logging.INFO) |
(...skipping 18 matching lines...) Expand all Loading... |
370 '--results', default=results.KEY__HEADER__RESULTS_FAILURES, | 370 '--results', default=results.KEY__HEADER__RESULTS_FAILURES, |
371 help='Which result types to include. Defaults to \'%(default)s\'; ' | 371 help='Which result types to include. Defaults to \'%(default)s\'; ' |
372 'must be one of ' + | 372 'must be one of ' + |
373 str([results.KEY__HEADER__RESULTS_FAILURES, | 373 str([results.KEY__HEADER__RESULTS_FAILURES, |
374 results.KEY__HEADER__RESULTS_ALL])) | 374 results.KEY__HEADER__RESULTS_ALL])) |
375 parser.add_argument( | 375 parser.add_argument( |
376 '--workdir', default=results.DEFAULT_GENERATED_IMAGES_ROOT, | 376 '--workdir', default=results.DEFAULT_GENERATED_IMAGES_ROOT, |
377 help='Directory within which to download images and generate diffs; ' | 377 help='Directory within which to download images and generate diffs; ' |
378 'defaults to \'%(default)s\' .') | 378 'defaults to \'%(default)s\' .') |
379 args = parser.parse_args() | 379 args = parser.parse_args() |
| 380 image_diff_db = imagediffdb.ImageDiffDB(storage_root=args.workdir) |
380 results_obj = ExpectationComparisons( | 381 results_obj = ExpectationComparisons( |
| 382 image_diff_db=image_diff_db, |
381 actuals_root=args.actuals, | 383 actuals_root=args.actuals, |
382 expected_root=args.expectations, | 384 expected_root=args.expectations, |
383 ignore_failures_file=args.ignore_failures_file, | 385 ignore_failures_file=args.ignore_failures_file) |
384 generated_images_root=args.workdir) | |
385 gm_json.WriteToFile( | 386 gm_json.WriteToFile( |
386 results_obj.get_packaged_results_of_type(results_type=args.results), | 387 results_obj.get_packaged_results_of_type(results_type=args.results), |
387 args.outfile) | 388 args.outfile) |
388 | 389 |
389 | 390 |
390 if __name__ == '__main__': | 391 if __name__ == '__main__': |
391 main() | 392 main() |
OLD | NEW |