| 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 HTTP server for our HTML rebaseline viewer. | 9 HTTP server for our HTML rebaseline viewer. |
| 10 """ | 10 """ |
| (...skipping 251 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 262 """ | 262 """ |
| 263 Args: | 263 Args: |
| 264 actuals_dir: directory under which we will check out the latest actual | 264 actuals_dir: directory under which we will check out the latest actual |
| 265 GM results | 265 GM results |
| 266 json_filename: basename of the JSON summary file to load for each builder | 266 json_filename: basename of the JSON summary file to load for each builder |
| 267 gm_summaries_bucket: Google Storage bucket to download json_filename | 267 gm_summaries_bucket: Google Storage bucket to download json_filename |
| 268 files from; if None or '', don't fetch new actual-results files | 268 files from; if None or '', don't fetch new actual-results files |
| 269 at all, just compare to whatever files are already in actuals_dir | 269 at all, just compare to whatever files are already in actuals_dir |
| 270 port: which TCP port to listen on for HTTP requests | 270 port: which TCP port to listen on for HTTP requests |
| 271 export: whether to allow HTTP clients on other hosts to access this server | 271 export: whether to allow HTTP clients on other hosts to access this server |
| 272 editable: whether HTTP clients are allowed to submit new baselines | 272 editable: whether HTTP clients are allowed to submit new GM baselines |
| 273 (SKP baseline modifications are performed using an entirely different |
| 274 mechanism, not affected by this parameter) |
| 273 reload_seconds: polling interval with which to check for new results; | 275 reload_seconds: polling interval with which to check for new results; |
| 274 if 0, don't check for new results at all | 276 if 0, don't check for new results at all |
| 275 config_pairs: List of (string, string) tuples; for each tuple, compare | 277 config_pairs: List of (string, string) tuples; for each tuple, compare |
| 276 actual results of these two configs. If None or empty, | 278 actual results of these two configs. If None or empty, |
| 277 don't compare configs at all. | 279 don't compare configs at all. |
| 278 builder_regex_list: List of regular expressions specifying which builders | 280 builder_regex_list: List of regular expressions specifying which builders |
| 279 we will process. If None, process all builders. | 281 we will process. If None, process all builders. |
| 280 boto_file_path: Path to .boto file giving us credentials to access | 282 boto_file_path: Path to .boto file giving us credentials to access |
| 281 Google Storage buckets; if None, we will only be able to access | 283 Google Storage buckets; if None, we will only be able to access |
| 282 public GS buckets. | 284 public GS buckets. |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 337 return self._gs | 339 return self._gs |
| 338 | 340 |
| 339 @property | 341 @property |
| 340 def is_exported(self): | 342 def is_exported(self): |
| 341 """ Returns true iff HTTP clients on other hosts are allowed to access | 343 """ Returns true iff HTTP clients on other hosts are allowed to access |
| 342 this server. """ | 344 this server. """ |
| 343 return self._export | 345 return self._export |
| 344 | 346 |
| 345 @property | 347 @property |
| 346 def is_editable(self): | 348 def is_editable(self): |
| 347 """ Returns true iff HTTP clients are allowed to submit new baselines. """ | 349 """ True iff HTTP clients are allowed to submit new GM baselines. """ |
| 348 return self._editable | 350 return self._editable |
| 349 | 351 |
| 350 @property | 352 @property |
| 351 def reload_seconds(self): | 353 def reload_seconds(self): |
| 352 """ Returns the result reload period in seconds, or 0 if we don't reload | 354 """ Returns the result reload period in seconds, or 0 if we don't reload |
| 353 results. """ | 355 results. """ |
| 354 return self._reload_seconds | 356 return self._reload_seconds |
| 355 | 357 |
| 356 def update_results(self, invalidate=False): | 358 def update_results(self, invalidate=False): |
| 357 """ Create or update self._results, based on the latest expectations and | 359 """ Create or update self._results, based on the latest expectations and |
| (...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 568 results_mod.KEY__HEADER__SCHEMA_VERSION: ( | 570 results_mod.KEY__HEADER__SCHEMA_VERSION: ( |
| 569 results_mod.VALUE__HEADER__SCHEMA_VERSION), | 571 results_mod.VALUE__HEADER__SCHEMA_VERSION), |
| 570 results_mod.KEY__HEADER__IS_STILL_LOADING: True, | 572 results_mod.KEY__HEADER__IS_STILL_LOADING: True, |
| 571 results_mod.KEY__HEADER__TIME_UPDATED: now, | 573 results_mod.KEY__HEADER__TIME_UPDATED: now, |
| 572 results_mod.KEY__HEADER__TIME_NEXT_UPDATE_AVAILABLE: ( | 574 results_mod.KEY__HEADER__TIME_NEXT_UPDATE_AVAILABLE: ( |
| 573 now + RELOAD_INTERVAL_UNTIL_READY), | 575 now + RELOAD_INTERVAL_UNTIL_READY), |
| 574 }, | 576 }, |
| 575 } | 577 } |
| 576 self.send_json_dict(response_dict) | 578 self.send_json_dict(response_dict) |
| 577 | 579 |
| 580 def _get_live_results_or_prefetch(self, url_remainder, prefetch_only=False): |
| 581 """ Handle a GET request for live-generated image diff data. |
| 582 |
| 583 Args: |
| 584 url_remainder: string indicating which image diffs to generate |
| 585 prefetch_only: if True, the user isn't waiting around for results |
| 586 """ |
| 587 param_dict = urlparse.parse_qs(url_remainder) |
| 588 download_all_images = ( |
| 589 param_dict.get(LIVE_PARAM__DOWNLOAD_ONLY_DIFFERING, [''])[0].lower() |
| 590 not in ['1', 'true']) |
| 591 setA_section = self._validate_summary_section( |
| 592 param_dict.get(LIVE_PARAM__SET_A_SECTION, [None])[0]) |
| 593 setB_section = self._validate_summary_section( |
| 594 param_dict.get(LIVE_PARAM__SET_B_SECTION, [None])[0]) |
| 595 results_obj = compare_rendered_pictures.RenderedPicturesComparisons( |
| 596 setA_dirs=param_dict[LIVE_PARAM__SET_A_DIR], |
| 597 setB_dirs=param_dict[LIVE_PARAM__SET_B_DIR], |
| 598 setA_section=setA_section, setB_section=setB_section, |
| 599 image_diff_db=_SERVER.image_diff_db, |
| 600 diff_base_url='/static/generated-images', |
| 601 gs=_SERVER.gs, truncate_results=_SERVER.truncate_results, |
| 602 prefetch_only=prefetch_only, download_all_images=download_all_images) |
| 603 if prefetch_only: |
| 604 self.send_response(200) |
| 605 else: |
| 606 self.send_json_dict(results_obj.get_packaged_results_of_type( |
| 607 results_mod.KEY__HEADER__RESULTS_ALL)) |
| 608 |
| 578 def do_GET_live_results(self, url_remainder): | 609 def do_GET_live_results(self, url_remainder): |
| 579 """ Handle a GET request for live-generated image diff data. | 610 """ Handle a GET request for live-generated image diff data. |
| 580 | 611 |
| 581 Args: | 612 Args: |
| 582 url_remainder: string indicating which image diffs to generate | 613 url_remainder: string indicating which image diffs to generate |
| 583 """ | 614 """ |
| 584 logging.debug('do_GET_live_results: url_remainder="%s"' % url_remainder) | 615 logging.debug('do_GET_live_results: url_remainder="%s"' % url_remainder) |
| 585 param_dict = urlparse.parse_qs(url_remainder) | 616 self._get_live_results_or_prefetch( |
| 586 results_obj = self._call_compare_rendered_pictures( | 617 url_remainder=url_remainder, prefetch_only=False) |
| 587 param_dict=param_dict, prefetch_only=False) | |
| 588 self.send_json_dict(results_obj.get_packaged_results_of_type( | |
| 589 results_mod.KEY__HEADER__RESULTS_ALL)) | |
| 590 | 618 |
| 591 def do_GET_prefetch_results(self, url_remainder): | 619 def do_GET_prefetch_results(self, url_remainder): |
| 592 """ Prefetch image diff data for a future do_GET_live_results() call. | 620 """ Prefetch image diff data for a future do_GET_live_results() call. |
| 593 | 621 |
| 594 Args: | 622 Args: |
| 595 url_remainder: string indicating which image diffs to generate | 623 url_remainder: string indicating which image diffs to generate |
| 596 """ | 624 """ |
| 597 logging.debug('do_GET_prefetch_results: url_remainder="%s"' % url_remainder) | 625 logging.debug('do_GET_prefetch_results: url_remainder="%s"' % url_remainder) |
| 598 param_dict = urlparse.parse_qs(url_remainder) | 626 self._get_live_results_or_prefetch( |
| 599 self._call_compare_rendered_pictures( | 627 url_remainder=url_remainder, prefetch_only=True) |
| 600 param_dict=param_dict, prefetch_only=True) | |
| 601 self.send_response(200) | |
| 602 | 628 |
| 603 def do_GET_static(self, path): | 629 def do_GET_static(self, path): |
| 604 """ Handle a GET request for a file under STATIC_CONTENTS_SUBDIR . | 630 """ Handle a GET request for a file under STATIC_CONTENTS_SUBDIR . |
| 605 Only allow serving of files within STATIC_CONTENTS_SUBDIR that is a | 631 Only allow serving of files within STATIC_CONTENTS_SUBDIR that is a |
| 606 filesystem sibling of this script. | 632 filesystem sibling of this script. |
| 607 | 633 |
| 608 Args: | 634 Args: |
| 609 path: path to file (within STATIC_CONTENTS_SUBDIR) to retrieve | 635 path: path to file (within STATIC_CONTENTS_SUBDIR) to retrieve |
| 610 """ | 636 """ |
| 611 # Strip arguments ('?resultsToLoad=all') from the path | 637 # Strip arguments ('?resultsToLoad=all') from the path |
| (...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 738 mimetype. | 764 mimetype. |
| 739 | 765 |
| 740 Args: | 766 Args: |
| 741 json_dict: dictionary to send | 767 json_dict: dictionary to send |
| 742 """ | 768 """ |
| 743 self.send_response(200) | 769 self.send_response(200) |
| 744 self.send_header('Content-type', 'application/json') | 770 self.send_header('Content-type', 'application/json') |
| 745 self.end_headers() | 771 self.end_headers() |
| 746 json.dump(json_dict, self.wfile) | 772 json.dump(json_dict, self.wfile) |
| 747 | 773 |
| 748 def _call_compare_rendered_pictures(self, param_dict, prefetch_only): | |
| 749 """Instantiates RenderedPicturesComparisons object to serve a GET request. | |
| 750 | |
| 751 Args: | |
| 752 param_dict: dictionary of URL parameters | |
| 753 prefetch_only: parameter to pass into RenderedPicturesComparisons | |
| 754 constructor | |
| 755 | |
| 756 Returns: a reference to the new RenderedPicturesComparisons object. | |
| 757 """ | |
| 758 download_all_images = ( | |
| 759 param_dict.get(LIVE_PARAM__DOWNLOAD_ONLY_DIFFERING, [''])[0].lower() | |
| 760 not in ['1', 'true']) | |
| 761 setA_section = self._validate_summary_section( | |
| 762 param_dict.get(LIVE_PARAM__SET_A_SECTION, [None])[0]) | |
| 763 setB_section = self._validate_summary_section( | |
| 764 param_dict.get(LIVE_PARAM__SET_B_SECTION, [None])[0]) | |
| 765 return compare_rendered_pictures.RenderedPicturesComparisons( | |
| 766 setA_dirs=param_dict[LIVE_PARAM__SET_A_DIR], | |
| 767 setB_dirs=param_dict[LIVE_PARAM__SET_B_DIR], | |
| 768 setA_section=setA_section, setB_section=setB_section, | |
| 769 image_diff_db=_SERVER.image_diff_db, | |
| 770 diff_base_url='/static/generated-images', | |
| 771 gs=_SERVER.gs, truncate_results=_SERVER.truncate_results, | |
| 772 prefetch_only=prefetch_only, download_all_images=download_all_images) | |
| 773 | |
| 774 def _validate_summary_section(self, section_name): | 774 def _validate_summary_section(self, section_name): |
| 775 """Validates the section we have been requested to read within JSON summary. | 775 """Validates the section we have been requested to read within JSON summary. |
| 776 | 776 |
| 777 Args: | 777 Args: |
| 778 section_name: which section of the JSON summary file has been requested | 778 section_name: which section of the JSON summary file has been requested |
| 779 | 779 |
| 780 Returns: the validated section name | 780 Returns: the validated section name |
| 781 | 781 |
| 782 Raises: Exception if an invalid section_name was requested. | 782 Raises: Exception if an invalid section_name was requested. |
| 783 """ | 783 """ |
| (...skipping 27 matching lines...) Expand all Loading... |
| 811 parser.add_argument('--builders', metavar='BUILDER_REGEX', nargs='+', | 811 parser.add_argument('--builders', metavar='BUILDER_REGEX', nargs='+', |
| 812 help=('Only process builders matching these regular ' | 812 help=('Only process builders matching these regular ' |
| 813 'expressions. If unspecified, process all ' | 813 'expressions. If unspecified, process all ' |
| 814 'builders.')) | 814 'builders.')) |
| 815 parser.add_argument('--compare-configs', action='store_true', | 815 parser.add_argument('--compare-configs', action='store_true', |
| 816 help=('In addition to generating differences between ' | 816 help=('In addition to generating differences between ' |
| 817 'expectations and actuals, also generate ' | 817 'expectations and actuals, also generate ' |
| 818 'differences between these config pairs: ' | 818 'differences between these config pairs: ' |
| 819 + str(CONFIG_PAIRS_TO_COMPARE))) | 819 + str(CONFIG_PAIRS_TO_COMPARE))) |
| 820 parser.add_argument('--editable', action='store_true', | 820 parser.add_argument('--editable', action='store_true', |
| 821 help=('Allow HTTP clients to submit new baselines.')) | 821 help=('Allow HTTP clients to submit new GM baselines.')) |
| 822 parser.add_argument('--export', action='store_true', | 822 parser.add_argument('--export', action='store_true', |
| 823 help=('Instead of only allowing access from HTTP clients ' | 823 help=('Instead of only allowing access from HTTP clients ' |
| 824 'on localhost, allow HTTP clients on other hosts ' | 824 'on localhost, allow HTTP clients on other hosts ' |
| 825 'to access this server. WARNING: doing so will ' | 825 'to access this server. WARNING: doing so will ' |
| 826 'allow users on other hosts to modify your ' | 826 'allow users on other hosts to modify your ' |
| 827 'GM expectations, if combined with --editable.')) | 827 'GM expectations, if combined with --editable.')) |
| 828 parser.add_argument('--gm-summaries-bucket', | 828 parser.add_argument('--gm-summaries-bucket', |
| 829 help=('Google Cloud Storage bucket to download ' | 829 help=('Google Cloud Storage bucket to download ' |
| 830 'JSON_FILENAME files from. ' | 830 'JSON_FILENAME files from. ' |
| 831 'Defaults to %(default)s ; if set to ' | 831 'Defaults to %(default)s ; if set to ' |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 870 reload_seconds=args.reload, config_pairs=config_pairs, | 870 reload_seconds=args.reload, config_pairs=config_pairs, |
| 871 builder_regex_list=args.builders, boto_file_path=args.boto, | 871 builder_regex_list=args.builders, boto_file_path=args.boto, |
| 872 imagediffdb_threads=args.threads) | 872 imagediffdb_threads=args.threads) |
| 873 if args.truncate: | 873 if args.truncate: |
| 874 _SERVER.truncate_results = True | 874 _SERVER.truncate_results = True |
| 875 _SERVER.run() | 875 _SERVER.run() |
| 876 | 876 |
| 877 | 877 |
| 878 if __name__ == '__main__': | 878 if __name__ == '__main__': |
| 879 main() | 879 main() |
| OLD | NEW |