| 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 | 15 import json |
| 16 import logging | 16 import logging |
| 17 import os | 17 import os |
| 18 import re | 18 import re |
| 19 import sys | 19 import sys |
| 20 import time | 20 import time |
| 21 | 21 |
| 22 # Imports from within Skia | 22 # Imports from within Skia |
| 23 # | 23 # |
| 24 # TODO(epoger): Once we move the create_filepath_url() function out of |
| 25 # download_actuals into a shared utility module, we won't need to import |
| 26 # download_actuals anymore. |
| 27 # |
| 24 # We need to add the 'gm' directory, so that we can import gm_json.py within | 28 # We need to add the 'gm' directory, so that we can import gm_json.py within |
| 25 # that directory. That script allows us to parse the actual-results.json file | 29 # that directory. That script allows us to parse the actual-results.json file |
| 26 # written out by the GM tool. | 30 # written out by the GM tool. |
| 27 # Make sure that the 'gm' dir is in the PYTHONPATH, but add it at the *end* | 31 # Make sure that the 'gm' dir is in the PYTHONPATH, but add it at the *end* |
| 28 # so any dirs that are already in the PYTHONPATH will be preferred. | 32 # so any dirs that are already in the PYTHONPATH will be preferred. |
| 29 PARENT_DIRECTORY = os.path.dirname(os.path.realpath(__file__)) | 33 PARENT_DIRECTORY = os.path.dirname(os.path.realpath(__file__)) |
| 30 GM_DIRECTORY = os.path.dirname(PARENT_DIRECTORY) | 34 GM_DIRECTORY = os.path.dirname(PARENT_DIRECTORY) |
| 31 TRUNK_DIRECTORY = os.path.dirname(GM_DIRECTORY) | 35 TRUNK_DIRECTORY = os.path.dirname(GM_DIRECTORY) |
| 32 if GM_DIRECTORY not in sys.path: | 36 if GM_DIRECTORY not in sys.path: |
| 33 sys.path.append(GM_DIRECTORY) | 37 sys.path.append(GM_DIRECTORY) |
| 38 import download_actuals |
| 34 import gm_json | 39 import gm_json |
| 35 import imagediffdb | 40 import imagediffdb |
| 36 import imagepair | 41 import imagepair |
| 37 import imagepairset | 42 import imagepairset |
| 38 | 43 |
| 39 # Keys used to link an image to a particular GM test. | 44 # Keys used to link an image to a particular GM test. |
| 40 # NOTE: Keep these in sync with static/constants.js | 45 # NOTE: Keep these in sync with static/constants.js |
| 41 REBASELINE_SERVER_SCHEMA_VERSION_NUMBER = 2 | 46 REBASELINE_SERVER_SCHEMA_VERSION_NUMBER = 2 |
| 42 KEY__EXPECTATIONS__BUGS = gm_json.JSONKEY_EXPECTEDRESULTS_BUGS | 47 KEY__EXPECTATIONS__BUGS = gm_json.JSONKEY_EXPECTEDRESULTS_BUGS |
| 43 KEY__EXPECTATIONS__IGNOREFAILURE = gm_json.JSONKEY_EXPECTEDRESULTS_IGNOREFAILURE | 48 KEY__EXPECTATIONS__IGNOREFAILURE = gm_json.JSONKEY_EXPECTEDRESULTS_IGNOREFAILURE |
| (...skipping 25 matching lines...) Expand all Loading... |
| 69 KEY__EXPECTATIONS__REVIEWED, | 74 KEY__EXPECTATIONS__REVIEWED, |
| 70 ] | 75 ] |
| 71 | 76 |
| 72 IMAGE_FILENAME_RE = re.compile(gm_json.IMAGE_FILENAME_PATTERN) | 77 IMAGE_FILENAME_RE = re.compile(gm_json.IMAGE_FILENAME_PATTERN) |
| 73 IMAGE_FILENAME_FORMATTER = '%s_%s.png' # pass in (testname, config) | 78 IMAGE_FILENAME_FORMATTER = '%s_%s.png' # pass in (testname, config) |
| 74 | 79 |
| 75 IMAGEPAIR_SET_DESCRIPTIONS = ('expected image', 'actual image') | 80 IMAGEPAIR_SET_DESCRIPTIONS = ('expected image', 'actual image') |
| 76 | 81 |
| 77 DEFAULT_ACTUALS_DIR = '.gm-actuals' | 82 DEFAULT_ACTUALS_DIR = '.gm-actuals' |
| 78 DEFAULT_EXPECTATIONS_DIR = os.path.join(TRUNK_DIRECTORY, 'expectations', 'gm') | 83 DEFAULT_EXPECTATIONS_DIR = os.path.join(TRUNK_DIRECTORY, 'expectations', 'gm') |
| 79 DEFAULT_GENERATED_IMAGES_ROOT = os.path.join(PARENT_DIRECTORY, 'static', | 84 DEFAULT_GENERATED_IMAGES_ROOT = os.path.join( |
| 80 'generated-images') | 85 PARENT_DIRECTORY, '.generated-images') |
| 81 | 86 |
| 82 | 87 |
| 83 class Results(object): | 88 class Results(object): |
| 84 """ Loads actual and expected GM results into an ImagePairSet. | 89 """ Loads actual and expected GM results into an ImagePairSet. |
| 85 | 90 |
| 86 Loads actual and expected results from all builders, except for those skipped | 91 Loads actual and expected results from all builders, except for those skipped |
| 87 by _ignore_builder(). | 92 by _ignore_builder(). |
| 88 | 93 |
| 89 Once this object has been constructed, the results (in self._results[]) | 94 Once this object has been constructed, the results (in self._results[]) |
| 90 are immutable. If you want to update the results based on updated JSON | 95 are immutable. If you want to update the results based on updated JSON |
| 91 file contents, you will need to create a new Results object.""" | 96 file contents, you will need to create a new Results object.""" |
| 92 | 97 |
| 93 def __init__(self, actuals_root=DEFAULT_ACTUALS_DIR, | 98 def __init__(self, actuals_root=DEFAULT_ACTUALS_DIR, |
| 94 expected_root=DEFAULT_EXPECTATIONS_DIR, | 99 expected_root=DEFAULT_EXPECTATIONS_DIR, |
| 95 generated_images_root=DEFAULT_GENERATED_IMAGES_ROOT): | 100 generated_images_root=DEFAULT_GENERATED_IMAGES_ROOT, |
| 101 diff_base_url=None): |
| 96 """ | 102 """ |
| 97 Args: | 103 Args: |
| 98 actuals_root: root directory containing all actual-results.json files | 104 actuals_root: root directory containing all actual-results.json files |
| 99 expected_root: root directory containing all expected-results.json files | 105 expected_root: root directory containing all expected-results.json files |
| 100 generated_images_root: directory within which to create all pixel diffs; | 106 generated_images_root: directory within which to create all pixel diffs; |
| 101 if this directory does not yet exist, it will be created | 107 if this directory does not yet exist, it will be created |
| 108 diff_base_url: base URL within which the client should look for diff |
| 109 images; if not specified, defaults to a "file:///" URL representation |
| 110 of generated_images_root |
| 102 """ | 111 """ |
| 103 time_start = int(time.time()) | 112 time_start = int(time.time()) |
| 104 self._image_diff_db = imagediffdb.ImageDiffDB(generated_images_root) | 113 self._image_diff_db = imagediffdb.ImageDiffDB(generated_images_root) |
| 114 self._diff_base_url = ( |
| 115 diff_base_url or |
| 116 download_actuals.create_filepath_url(generated_images_root)) |
| 105 self._actuals_root = actuals_root | 117 self._actuals_root = actuals_root |
| 106 self._expected_root = expected_root | 118 self._expected_root = expected_root |
| 107 self._load_actual_and_expected() | 119 self._load_actual_and_expected() |
| 108 self._timestamp = int(time.time()) | 120 self._timestamp = int(time.time()) |
| 109 logging.info('Results complete; took %d seconds.' % | 121 logging.info('Results complete; took %d seconds.' % |
| 110 (self._timestamp - time_start)) | 122 (self._timestamp - time_start)) |
| 111 | 123 |
| 112 def get_timestamp(self): | 124 def get_timestamp(self): |
| 113 """Return the time at which this object was created, in seconds past epoch | 125 """Return the time at which this object was created, in seconds past epoch |
| 114 (UTC). | 126 (UTC). |
| (...skipping 221 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 336 files within self._actuals_root and self._expected_root), | 348 files within self._actuals_root and self._expected_root), |
| 337 and stores them in self._results. | 349 and stores them in self._results. |
| 338 """ | 350 """ |
| 339 logging.info('Reading actual-results JSON files from %s...' % | 351 logging.info('Reading actual-results JSON files from %s...' % |
| 340 self._actuals_root) | 352 self._actuals_root) |
| 341 actual_builder_dicts = Results._read_dicts_from_root(self._actuals_root) | 353 actual_builder_dicts = Results._read_dicts_from_root(self._actuals_root) |
| 342 logging.info('Reading expected-results JSON files from %s...' % | 354 logging.info('Reading expected-results JSON files from %s...' % |
| 343 self._expected_root) | 355 self._expected_root) |
| 344 expected_builder_dicts = Results._read_dicts_from_root(self._expected_root) | 356 expected_builder_dicts = Results._read_dicts_from_root(self._expected_root) |
| 345 | 357 |
| 346 all_image_pairs = imagepairset.ImagePairSet(IMAGEPAIR_SET_DESCRIPTIONS) | 358 all_image_pairs = imagepairset.ImagePairSet( |
| 347 failing_image_pairs = imagepairset.ImagePairSet(IMAGEPAIR_SET_DESCRIPTIONS) | 359 descriptions=IMAGEPAIR_SET_DESCRIPTIONS, |
| 360 diff_base_url=self._diff_base_url) |
| 361 failing_image_pairs = imagepairset.ImagePairSet( |
| 362 descriptions=IMAGEPAIR_SET_DESCRIPTIONS, |
| 363 diff_base_url=self._diff_base_url) |
| 348 | 364 |
| 349 all_image_pairs.ensure_extra_column_values_in_summary( | 365 all_image_pairs.ensure_extra_column_values_in_summary( |
| 350 column_id=KEY__EXTRACOLUMN__RESULT_TYPE, values=[ | 366 column_id=KEY__EXTRACOLUMN__RESULT_TYPE, values=[ |
| 351 KEY__RESULT_TYPE__FAILED, | 367 KEY__RESULT_TYPE__FAILED, |
| 352 KEY__RESULT_TYPE__FAILUREIGNORED, | 368 KEY__RESULT_TYPE__FAILUREIGNORED, |
| 353 KEY__RESULT_TYPE__NOCOMPARISON, | 369 KEY__RESULT_TYPE__NOCOMPARISON, |
| 354 KEY__RESULT_TYPE__SUCCEEDED, | 370 KEY__RESULT_TYPE__SUCCEEDED, |
| 355 ]) | 371 ]) |
| 356 failing_image_pairs.ensure_extra_column_values_in_summary( | 372 failing_image_pairs.ensure_extra_column_values_in_summary( |
| 357 column_id=KEY__EXTRACOLUMN__RESULT_TYPE, values=[ | 373 column_id=KEY__EXTRACOLUMN__RESULT_TYPE, values=[ |
| (...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 496 results = Results(actuals_root=args.actuals, | 512 results = Results(actuals_root=args.actuals, |
| 497 expected_root=args.expectations, | 513 expected_root=args.expectations, |
| 498 generated_images_root=args.workdir) | 514 generated_images_root=args.workdir) |
| 499 gm_json.WriteToFile( | 515 gm_json.WriteToFile( |
| 500 results.get_packaged_results_of_type(results_type=args.results), | 516 results.get_packaged_results_of_type(results_type=args.results), |
| 501 args.outfile) | 517 args.outfile) |
| 502 | 518 |
| 503 | 519 |
| 504 if __name__ == '__main__': | 520 if __name__ == '__main__': |
| 505 main() | 521 main() |
| OLD | NEW |