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 |