Chromium Code Reviews| 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 22 matching lines...) Expand all Loading... | |
| 33 import gm_json | 33 import gm_json |
| 34 | 34 |
| 35 # Imports from local dir | 35 # Imports from local dir |
| 36 # | 36 # |
| 37 # pylint: disable=C0301 | 37 # pylint: disable=C0301 |
| 38 # Note: we import results under a different name, to avoid confusion with the | 38 # Note: we import results under a different name, to avoid confusion with the |
| 39 # Server.results() property. See discussion at | 39 # Server.results() property. See discussion at |
| 40 # https://codereview.chromium.org/195943004/diff/1/gm/rebaseline_server/server.p y#newcode44 | 40 # https://codereview.chromium.org/195943004/diff/1/gm/rebaseline_server/server.p y#newcode44 |
| 41 # pylint: enable=C0301 | 41 # pylint: enable=C0301 |
| 42 import compare_configs | 42 import compare_configs |
| 43 import compare_rendered_pictures | |
| 43 import compare_to_expectations | 44 import compare_to_expectations |
| 44 import download_actuals | 45 import download_actuals |
| 45 import imagediffdb | 46 import imagediffdb |
| 46 import imagepairset | 47 import imagepairset |
| 47 import results as results_mod | 48 import results as results_mod |
| 48 | 49 |
| 49 PATHSPLIT_RE = re.compile('/([^/]+)/(.+)') | 50 PATHSPLIT_RE = re.compile('/([^/]+)/(.+)') |
| 50 | 51 |
| 51 # A simple dictionary of file name extensions to MIME types. The empty string | 52 # A simple dictionary of file name extensions to MIME types. The empty string |
| 52 # entry is used as the default when no extension was given or if the extension | 53 # entry is used as the default when no extension was given or if the extension |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 66 KEY__EDITS__OLD_RESULTS_TYPE = 'oldResultsType' | 67 KEY__EDITS__OLD_RESULTS_TYPE = 'oldResultsType' |
| 67 | 68 |
| 68 DEFAULT_ACTUALS_DIR = results_mod.DEFAULT_ACTUALS_DIR | 69 DEFAULT_ACTUALS_DIR = results_mod.DEFAULT_ACTUALS_DIR |
| 69 DEFAULT_GM_SUMMARIES_BUCKET = download_actuals.GM_SUMMARIES_BUCKET | 70 DEFAULT_GM_SUMMARIES_BUCKET = download_actuals.GM_SUMMARIES_BUCKET |
| 70 DEFAULT_JSON_FILENAME = download_actuals.DEFAULT_JSON_FILENAME | 71 DEFAULT_JSON_FILENAME = download_actuals.DEFAULT_JSON_FILENAME |
| 71 DEFAULT_PORT = 8888 | 72 DEFAULT_PORT = 8888 |
| 72 | 73 |
| 73 PARENT_DIRECTORY = os.path.dirname(os.path.realpath(__file__)) | 74 PARENT_DIRECTORY = os.path.dirname(os.path.realpath(__file__)) |
| 74 TRUNK_DIRECTORY = os.path.dirname(os.path.dirname(PARENT_DIRECTORY)) | 75 TRUNK_DIRECTORY = os.path.dirname(os.path.dirname(PARENT_DIRECTORY)) |
| 75 # Directory, relative to PARENT_DIRECTORY, within which the server will serve | 76 # Directory, relative to PARENT_DIRECTORY, within which the server will serve |
| 76 # out live results (not static files). | 77 # out image diff data from within the precomputed _SERVER.results . |
| 77 RESULTS_SUBDIR = 'results' | 78 PRECOMPUTED_RESULTS_SUBDIR = 'results' |
| 79 # Directory, relative to PARENT_DIRECTORY, within which the server will serve | |
| 80 # out live-generated image diff data. | |
| 81 LIVE_RESULTS_SUBDIR = 'live-results' | |
| 78 # Directory, relative to PARENT_DIRECTORY, within which the server will serve | 82 # Directory, relative to PARENT_DIRECTORY, within which the server will serve |
| 79 # out static files. | 83 # out static files. |
| 80 STATIC_CONTENTS_SUBDIR = 'static' | 84 STATIC_CONTENTS_SUBDIR = 'static' |
| 81 # All of the GENERATED_*_SUBDIRS are relative to STATIC_CONTENTS_SUBDIR | 85 # All of the GENERATED_*_SUBDIRS are relative to STATIC_CONTENTS_SUBDIR |
| 82 GENERATED_HTML_SUBDIR = 'generated-html' | 86 GENERATED_HTML_SUBDIR = 'generated-html' |
| 83 GENERATED_IMAGES_SUBDIR = 'generated-images' | 87 GENERATED_IMAGES_SUBDIR = 'generated-images' |
| 84 GENERATED_JSON_SUBDIR = 'generated-json' | 88 GENERATED_JSON_SUBDIR = 'generated-json' |
| 85 | 89 |
| 86 # How often (in seconds) clients should reload while waiting for initial | 90 # How often (in seconds) clients should reload while waiting for initial |
| 87 # results to load. | 91 # results to load. |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 158 '<!DOCTYPE html><html>' | 162 '<!DOCTYPE html><html>' |
| 159 '<head><title>rebaseline_server</title></head>' | 163 '<head><title>rebaseline_server</title></head>' |
| 160 '<body><ul>') | 164 '<body><ul>') |
| 161 if SUMMARY_TYPES: | 165 if SUMMARY_TYPES: |
| 162 file_handle.write('<li>Expectations vs Actuals</li><ul>') | 166 file_handle.write('<li>Expectations vs Actuals</li><ul>') |
| 163 for summary_type in SUMMARY_TYPES: | 167 for summary_type in SUMMARY_TYPES: |
| 164 file_handle.write( | 168 file_handle.write( |
| 165 '<li><a href="/{static_subdir}/view.html#/view.html?' | 169 '<li><a href="/{static_subdir}/view.html#/view.html?' |
| 166 'resultsToLoad=/{results_subdir}/{summary_type}">' | 170 'resultsToLoad=/{results_subdir}/{summary_type}">' |
| 167 '{summary_type}</a></li>'.format( | 171 '{summary_type}</a></li>'.format( |
| 168 results_subdir=RESULTS_SUBDIR, | 172 results_subdir=PRECOMPUTED_RESULTS_SUBDIR, |
| 169 static_subdir=STATIC_CONTENTS_SUBDIR, | 173 static_subdir=STATIC_CONTENTS_SUBDIR, |
| 170 summary_type=summary_type)) | 174 summary_type=summary_type)) |
| 171 file_handle.write('</ul>') | 175 file_handle.write('</ul>') |
| 172 if config_pairs: | 176 if config_pairs: |
| 173 file_handle.write('<li>Comparing configs within actual results</li><ul>') | 177 file_handle.write('<li>Comparing configs within actual results</li><ul>') |
| 174 for config_pair in config_pairs: | 178 for config_pair in config_pairs: |
| 175 file_handle.write('<li>%s vs %s:' % config_pair) | 179 file_handle.write('<li>%s vs %s:' % config_pair) |
| 176 for summary_type in SUMMARY_TYPES: | 180 for summary_type in SUMMARY_TYPES: |
| 177 file_handle.write( | 181 file_handle.write( |
| 178 ' <a href="/%s/view.html#/view.html?' | 182 ' <a href="/%s/view.html#/view.html?' |
| 179 'resultsToLoad=/%s/%s/%s-vs-%s_%s.json">%s</a>' % ( | 183 'resultsToLoad=/%s/%s/%s-vs-%s_%s.json">%s</a>' % ( |
| 180 STATIC_CONTENTS_SUBDIR, STATIC_CONTENTS_SUBDIR, | 184 STATIC_CONTENTS_SUBDIR, STATIC_CONTENTS_SUBDIR, |
| 181 GENERATED_JSON_SUBDIR, config_pair[0], config_pair[1], | 185 GENERATED_JSON_SUBDIR, config_pair[0], config_pair[1], |
| 182 summary_type, summary_type)) | 186 summary_type, summary_type)) |
| 183 file_handle.write('</li>') | 187 file_handle.write('</li>') |
| 184 file_handle.write('</ul>') | 188 file_handle.write('</ul>') |
| 185 file_handle.write('</ul></body></html>') | 189 file_handle.write('</ul></body></html>') |
| 186 | 190 |
| 187 | 191 |
| 188 class Server(object): | 192 class Server(object): |
| 189 """ HTTP server for our HTML rebaseline viewer. """ | 193 """ HTTP server for our HTML rebaseline viewer. """ |
| 190 | 194 |
| 191 def __init__(self, | 195 def __init__(self, |
| 192 actuals_dir=DEFAULT_ACTUALS_DIR, | 196 actuals_dir=DEFAULT_ACTUALS_DIR, |
| 193 json_filename=DEFAULT_JSON_FILENAME, | 197 json_filename=DEFAULT_JSON_FILENAME, |
| 194 gm_summaries_bucket=DEFAULT_GM_SUMMARIES_BUCKET, | 198 gm_summaries_bucket=DEFAULT_GM_SUMMARIES_BUCKET, |
| 195 port=DEFAULT_PORT, export=False, editable=True, | 199 port=DEFAULT_PORT, export=False, editable=True, |
| 196 reload_seconds=0, config_pairs=None, builder_regex_list=None): | 200 reload_seconds=0, config_pairs=None, builder_regex_list=None, |
| 201 boto_file_path=None): | |
| 197 """ | 202 """ |
| 198 Args: | 203 Args: |
| 199 actuals_dir: directory under which we will check out the latest actual | 204 actuals_dir: directory under which we will check out the latest actual |
| 200 GM results | 205 GM results |
| 201 json_filename: basename of the JSON summary file to load for each builder | 206 json_filename: basename of the JSON summary file to load for each builder |
| 202 gm_summaries_bucket: Google Storage bucket to download json_filename | 207 gm_summaries_bucket: Google Storage bucket to download json_filename |
| 203 files from; if None or '', don't fetch new actual-results files | 208 files from; if None or '', don't fetch new actual-results files |
| 204 at all, just compare to whatever files are already in actuals_dir | 209 at all, just compare to whatever files are already in actuals_dir |
| 205 port: which TCP port to listen on for HTTP requests | 210 port: which TCP port to listen on for HTTP requests |
| 206 export: whether to allow HTTP clients on other hosts to access this server | 211 export: whether to allow HTTP clients on other hosts to access this server |
| 207 editable: whether HTTP clients are allowed to submit new baselines | 212 editable: whether HTTP clients are allowed to submit new baselines |
| 208 reload_seconds: polling interval with which to check for new results; | 213 reload_seconds: polling interval with which to check for new results; |
| 209 if 0, don't check for new results at all | 214 if 0, don't check for new results at all |
| 210 config_pairs: List of (string, string) tuples; for each tuple, compare | 215 config_pairs: List of (string, string) tuples; for each tuple, compare |
| 211 actual results of these two configs. If None or empty, | 216 actual results of these two configs. If None or empty, |
| 212 don't compare configs at all. | 217 don't compare configs at all. |
| 213 builder_regex_list: List of regular expressions specifying which builders | 218 builder_regex_list: List of regular expressions specifying which builders |
| 214 we will process. If None, process all builders. | 219 we will process. If None, process all builders. |
| 220 boto_file_path: Path to .boto file giving us credentials to access | |
| 221 Google Storage buckets; if None, we will only be able to access | |
| 222 public GS buckets. | |
| 215 """ | 223 """ |
| 216 self._actuals_dir = actuals_dir | 224 self._actuals_dir = actuals_dir |
| 217 self._json_filename = json_filename | 225 self._json_filename = json_filename |
| 218 self._gm_summaries_bucket = gm_summaries_bucket | 226 self._gm_summaries_bucket = gm_summaries_bucket |
| 219 self._port = port | 227 self._port = port |
| 220 self._export = export | 228 self._export = export |
| 221 self._editable = editable | 229 self._editable = editable |
| 222 self._reload_seconds = reload_seconds | 230 self._reload_seconds = reload_seconds |
| 223 self._config_pairs = config_pairs or [] | 231 self._config_pairs = config_pairs or [] |
| 224 self._builder_regex_list = builder_regex_list | 232 self._builder_regex_list = builder_regex_list |
| 225 self._gs = gs_utils.GSUtils() | 233 |
| 234 if boto_file_path: | |
| 235 self._gs = gs_utils.GSUtils(boto_file_path=boto_file_path) | |
| 236 else: | |
| 237 self._gs = gs_utils.GSUtils() | |
| 238 | |
| 226 _create_index( | 239 _create_index( |
| 227 file_path=os.path.join( | 240 file_path=os.path.join( |
| 228 PARENT_DIRECTORY, STATIC_CONTENTS_SUBDIR, GENERATED_HTML_SUBDIR, | 241 PARENT_DIRECTORY, STATIC_CONTENTS_SUBDIR, GENERATED_HTML_SUBDIR, |
| 229 "index.html"), | 242 "index.html"), |
| 230 config_pairs=config_pairs) | 243 config_pairs=config_pairs) |
| 231 | 244 |
| 232 # Reentrant lock that must be held whenever updating EITHER of: | 245 # Reentrant lock that must be held whenever updating EITHER of: |
| 233 # 1. self._results | 246 # 1. self._results |
| 234 # 2. the expected or actual results on local disk | 247 # 2. the expected or actual results on local disk |
| 235 self.results_rlock = threading.RLock() | 248 self.results_rlock = threading.RLock() |
| 236 | 249 |
| 237 # These will be filled in by calls to update_results() | 250 # Create a single ImageDiffDB instance that is used by all our differs. |
| 251 self._image_diff_db = imagediffdb.ImageDiffDB( | |
| 252 gs=self._gs, | |
| 253 storage_root=os.path.join( | |
| 254 PARENT_DIRECTORY, STATIC_CONTENTS_SUBDIR, | |
| 255 GENERATED_IMAGES_SUBDIR)) | |
| 256 | |
| 257 # This will be filled in by calls to update_results() | |
| 238 self._results = None | 258 self._results = None |
| 239 self._image_diff_db = None | |
| 240 | 259 |
| 241 @property | 260 @property |
| 242 def results(self): | 261 def results(self): |
| 243 """ Returns the most recently generated results, or None if we don't have | 262 """ Returns the most recently generated results, or None if we don't have |
| 244 any valid results (update_results() has not completed yet). """ | 263 any valid results (update_results() has not completed yet). """ |
| 245 return self._results | 264 return self._results |
| 246 | 265 |
| 247 @property | 266 @property |
| 248 def is_exported(self): | 267 def is_exported(self): |
| 249 """ Returns true iff HTTP clients on other hosts are allowed to access | 268 """ Returns true iff HTTP clients on other hosts are allowed to access |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 336 # updated expectations into a temp directory, and leaving the rest of | 355 # updated expectations into a temp directory, and leaving the rest of |
| 337 # the checkout alone. This could be done using "git show", or by | 356 # the checkout alone. This could be done using "git show", or by |
| 338 # downloading individual expectation JSON files from | 357 # downloading individual expectation JSON files from |
| 339 # skia.googlesource.com . | 358 # skia.googlesource.com . |
| 340 if self._reload_seconds: | 359 if self._reload_seconds: |
| 341 logging.info( | 360 logging.info( |
| 342 'Updating expected GM results in %s by syncing Skia repo ...' % | 361 'Updating expected GM results in %s by syncing Skia repo ...' % |
| 343 compare_to_expectations.DEFAULT_EXPECTATIONS_DIR) | 362 compare_to_expectations.DEFAULT_EXPECTATIONS_DIR) |
| 344 _run_command(['gclient', 'sync'], TRUNK_DIRECTORY) | 363 _run_command(['gclient', 'sync'], TRUNK_DIRECTORY) |
| 345 | 364 |
| 346 if not self._image_diff_db: | |
| 347 self._image_diff_db = imagediffdb.ImageDiffDB( | |
| 348 storage_root=os.path.join( | |
| 349 PARENT_DIRECTORY, STATIC_CONTENTS_SUBDIR, | |
| 350 GENERATED_IMAGES_SUBDIR)) | |
| 351 | |
| 352 self._results = compare_to_expectations.ExpectationComparisons( | 365 self._results = compare_to_expectations.ExpectationComparisons( |
| 353 image_diff_db=self._image_diff_db, | 366 image_diff_db=self._image_diff_db, |
| 354 actuals_root=self._actuals_dir, | 367 actuals_root=self._actuals_dir, |
| 355 diff_base_url=posixpath.join( | 368 diff_base_url=posixpath.join( |
| 356 os.pardir, STATIC_CONTENTS_SUBDIR, GENERATED_IMAGES_SUBDIR), | 369 os.pardir, STATIC_CONTENTS_SUBDIR, GENERATED_IMAGES_SUBDIR), |
| 357 builder_regex_list=self._builder_regex_list) | 370 builder_regex_list=self._builder_regex_list) |
| 358 | 371 |
| 359 json_dir = os.path.join( | 372 json_dir = os.path.join( |
| 360 PARENT_DIRECTORY, STATIC_CONTENTS_SUBDIR, GENERATED_JSON_SUBDIR) | 373 PARENT_DIRECTORY, STATIC_CONTENTS_SUBDIR, GENERATED_JSON_SUBDIR) |
| 361 if not os.path.isdir(json_dir): | 374 if not os.path.isdir(json_dir): |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 436 self.redirect_to('/%s/favicon.ico' % STATIC_CONTENTS_SUBDIR) | 449 self.redirect_to('/%s/favicon.ico' % STATIC_CONTENTS_SUBDIR) |
| 437 return | 450 return |
| 438 | 451 |
| 439 # All requests must be of this form: | 452 # All requests must be of this form: |
| 440 # /dispatcher/remainder | 453 # /dispatcher/remainder |
| 441 # where 'dispatcher' indicates which do_GET_* dispatcher to run | 454 # where 'dispatcher' indicates which do_GET_* dispatcher to run |
| 442 # and 'remainder' is the remaining path sent to that dispatcher. | 455 # and 'remainder' is the remaining path sent to that dispatcher. |
| 443 normpath = posixpath.normpath(self.path) | 456 normpath = posixpath.normpath(self.path) |
| 444 (dispatcher_name, remainder) = PATHSPLIT_RE.match(normpath).groups() | 457 (dispatcher_name, remainder) = PATHSPLIT_RE.match(normpath).groups() |
| 445 dispatchers = { | 458 dispatchers = { |
| 446 RESULTS_SUBDIR: self.do_GET_results, | 459 PRECOMPUTED_RESULTS_SUBDIR: self.do_GET_precomputed_results, |
| 460 LIVE_RESULTS_SUBDIR: self.do_GET_live_results, | |
| 447 STATIC_CONTENTS_SUBDIR: self.do_GET_static, | 461 STATIC_CONTENTS_SUBDIR: self.do_GET_static, |
| 448 } | 462 } |
| 449 dispatcher = dispatchers[dispatcher_name] | 463 dispatcher = dispatchers[dispatcher_name] |
| 450 dispatcher(remainder) | 464 dispatcher(remainder) |
| 451 except: | 465 except: |
| 452 self.send_error(404) | 466 self.send_error(404) |
| 453 raise | 467 raise |
| 454 | 468 |
| 455 def do_GET_results(self, results_type): | 469 def do_GET_precomputed_results(self, results_type): |
|
epoger
2014/07/31 15:18:31
For now, leaving this one in place to fetch the la
| |
| 456 """ Handle a GET request for GM results. | 470 """ Handle a GET request for part of the precomputed _SERVER.results object. |
| 457 | 471 |
| 458 Args: | 472 Args: |
| 459 results_type: string indicating which set of results to return; | 473 results_type: string indicating which set of results to return; |
| 460 must be one of the results_mod.RESULTS_* constants | 474 must be one of the results_mod.RESULTS_* constants |
| 461 """ | 475 """ |
| 462 logging.debug('do_GET_results: sending results of type "%s"' % results_type) | 476 logging.debug('do_GET_precomputed_results: sending results of type "%s"' % |
| 477 results_type) | |
| 463 # Since we must make multiple calls to the ExpectationComparisons object, | 478 # Since we must make multiple calls to the ExpectationComparisons object, |
| 464 # grab a reference to it in case it is updated to point at a new | 479 # grab a reference to it in case it is updated to point at a new |
| 465 # ExpectationComparisons object within another thread. | 480 # ExpectationComparisons object within another thread. |
| 466 # | 481 # |
| 467 # TODO(epoger): Rather than using a global variable for the handler | 482 # TODO(epoger): Rather than using a global variable for the handler |
| 468 # to refer to the Server object, make Server a subclass of | 483 # to refer to the Server object, make Server a subclass of |
| 469 # HTTPServer, and then it could be available to the handler via | 484 # HTTPServer, and then it could be available to the handler via |
| 470 # the handler's .server instance variable. | 485 # the handler's .server instance variable. |
| 471 results_obj = _SERVER.results | 486 results_obj = _SERVER.results |
| 472 if results_obj: | 487 if results_obj: |
| 473 response_dict = results_obj.get_packaged_results_of_type( | 488 response_dict = results_obj.get_packaged_results_of_type( |
| 474 results_type=results_type, reload_seconds=_SERVER.reload_seconds, | 489 results_type=results_type, reload_seconds=_SERVER.reload_seconds, |
| 475 is_editable=_SERVER.is_editable, is_exported=_SERVER.is_exported) | 490 is_editable=_SERVER.is_editable, is_exported=_SERVER.is_exported) |
| 476 else: | 491 else: |
| 477 now = int(time.time()) | 492 now = int(time.time()) |
| 478 response_dict = { | 493 response_dict = { |
| 479 imagepairset.KEY__ROOT__HEADER: { | 494 imagepairset.KEY__ROOT__HEADER: { |
| 480 results_mod.KEY__HEADER__SCHEMA_VERSION: ( | 495 results_mod.KEY__HEADER__SCHEMA_VERSION: ( |
| 481 results_mod.VALUE__HEADER__SCHEMA_VERSION), | 496 results_mod.VALUE__HEADER__SCHEMA_VERSION), |
| 482 results_mod.KEY__HEADER__IS_STILL_LOADING: True, | 497 results_mod.KEY__HEADER__IS_STILL_LOADING: True, |
| 483 results_mod.KEY__HEADER__TIME_UPDATED: now, | 498 results_mod.KEY__HEADER__TIME_UPDATED: now, |
| 484 results_mod.KEY__HEADER__TIME_NEXT_UPDATE_AVAILABLE: ( | 499 results_mod.KEY__HEADER__TIME_NEXT_UPDATE_AVAILABLE: ( |
| 485 now + RELOAD_INTERVAL_UNTIL_READY), | 500 now + RELOAD_INTERVAL_UNTIL_READY), |
| 486 }, | 501 }, |
| 487 } | 502 } |
| 488 self.send_json_dict(response_dict) | 503 self.send_json_dict(response_dict) |
| 489 | 504 |
| 505 def do_GET_live_results(self, url_remainder): | |
| 506 """ Handle a GET request for live-generated image diff data. | |
| 507 | |
| 508 Args: | |
| 509 url_remainder: string indicating which image diffs to generate | |
| 510 """ | |
| 511 # EPOGER: move these definitions to the top of the file? | |
| 512 PARAM_ACTUALS_DIR = 'actualsDir' | |
| 513 PARAM_EXPECTATIONS_DIR = 'expectationsDir' | |
| 514 | |
| 515 logging.debug('do_GET_live_results: url_remainder="%s"' % url_remainder) | |
| 516 param_dict = urlparse.parse_qs(url_remainder) | |
| 517 results_obj = compare_rendered_pictures.RenderedPicturesComparisons( | |
| 518 actuals_dirs=param_dict[PARAM_ACTUALS_DIR], | |
|
epoger
2014/07/31 15:18:31
The live results are nice and flexible, because th
| |
| 519 expectations_dirs=param_dict[PARAM_EXPECTATIONS_DIR], | |
| 520 image_diff_db=_SERVER._image_diff_db, | |
| 521 diff_base_url='/static/generated-images') | |
| 522 self.send_json_dict(results_obj.get_packaged_results_of_type( | |
| 523 results_mod.KEY__HEADER__RESULTS_ALL)) | |
| 524 | |
| 490 def do_GET_static(self, path): | 525 def do_GET_static(self, path): |
| 491 """ Handle a GET request for a file under STATIC_CONTENTS_SUBDIR . | 526 """ Handle a GET request for a file under STATIC_CONTENTS_SUBDIR . |
| 492 Only allow serving of files within STATIC_CONTENTS_SUBDIR that is a | 527 Only allow serving of files within STATIC_CONTENTS_SUBDIR that is a |
| 493 filesystem sibling of this script. | 528 filesystem sibling of this script. |
| 494 | 529 |
| 495 Args: | 530 Args: |
| 496 path: path to file (within STATIC_CONTENTS_SUBDIR) to retrieve | 531 path: path to file (within STATIC_CONTENTS_SUBDIR) to retrieve |
| 497 """ | 532 """ |
| 498 # Strip arguments ('?resultsToLoad=all') from the path | 533 # Strip arguments ('?resultsToLoad=all') from the path |
| 499 path = urlparse.urlparse(path).path | 534 path = urlparse.urlparse(path).path |
| (...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 636 def main(): | 671 def main(): |
| 637 logging.basicConfig(format='%(asctime)s %(levelname)s %(message)s', | 672 logging.basicConfig(format='%(asctime)s %(levelname)s %(message)s', |
| 638 datefmt='%m/%d/%Y %H:%M:%S', | 673 datefmt='%m/%d/%Y %H:%M:%S', |
| 639 level=logging.INFO) | 674 level=logging.INFO) |
| 640 parser = argparse.ArgumentParser() | 675 parser = argparse.ArgumentParser() |
| 641 parser.add_argument('--actuals-dir', | 676 parser.add_argument('--actuals-dir', |
| 642 help=('Directory into which we will check out the latest ' | 677 help=('Directory into which we will check out the latest ' |
| 643 'actual GM results. If this directory does not ' | 678 'actual GM results. If this directory does not ' |
| 644 'exist, it will be created. Defaults to %(default)s'), | 679 'exist, it will be created. Defaults to %(default)s'), |
| 645 default=DEFAULT_ACTUALS_DIR) | 680 default=DEFAULT_ACTUALS_DIR) |
| 681 parser.add_argument('--boto', | |
| 682 help=('Path to .boto file giving us credentials to access ' | |
| 683 'Google Storage buckets. If not specified, we will ' | |
| 684 'only be able to access public GS buckets (and thus ' | |
| 685 'won\'t be able to download SKP images).'), | |
| 686 default='') | |
| 646 # TODO(epoger): Before https://codereview.chromium.org/310093003 , | 687 # TODO(epoger): Before https://codereview.chromium.org/310093003 , |
| 647 # when this tool downloaded the JSON summaries from skia-autogen, | 688 # when this tool downloaded the JSON summaries from skia-autogen, |
| 648 # it had an --actuals-revision the caller could specify to download | 689 # it had an --actuals-revision the caller could specify to download |
| 649 # actual results as of a specific point in time. We should add similar | 690 # actual results as of a specific point in time. We should add similar |
| 650 # functionality when retrieving the summaries from Google Storage. | 691 # functionality when retrieving the summaries from Google Storage. |
| 651 parser.add_argument('--builders', metavar='BUILDER_REGEX', nargs='+', | 692 parser.add_argument('--builders', metavar='BUILDER_REGEX', nargs='+', |
| 652 help=('Only process builders matching these regular ' | 693 help=('Only process builders matching these regular ' |
| 653 'expressions. If unspecified, process all ' | 694 'expressions. If unspecified, process all ' |
| 654 'builders.')) | 695 'builders.')) |
| 655 parser.add_argument('--compare-configs', action='store_true', | 696 parser.add_argument('--compare-configs', action='store_true', |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 693 config_pairs = CONFIG_PAIRS_TO_COMPARE | 734 config_pairs = CONFIG_PAIRS_TO_COMPARE |
| 694 else: | 735 else: |
| 695 config_pairs = None | 736 config_pairs = None |
| 696 | 737 |
| 697 global _SERVER | 738 global _SERVER |
| 698 _SERVER = Server(actuals_dir=args.actuals_dir, | 739 _SERVER = Server(actuals_dir=args.actuals_dir, |
| 699 json_filename=args.json_filename, | 740 json_filename=args.json_filename, |
| 700 gm_summaries_bucket=args.gm_summaries_bucket, | 741 gm_summaries_bucket=args.gm_summaries_bucket, |
| 701 port=args.port, export=args.export, editable=args.editable, | 742 port=args.port, export=args.export, editable=args.editable, |
| 702 reload_seconds=args.reload, config_pairs=config_pairs, | 743 reload_seconds=args.reload, config_pairs=config_pairs, |
| 703 builder_regex_list=args.builders) | 744 builder_regex_list=args.builders, boto_file_path=args.boto) |
| 704 _SERVER.run() | 745 _SERVER.run() |
| 705 | 746 |
| 706 | 747 |
| 707 if __name__ == '__main__': | 748 if __name__ == '__main__': |
| 708 main() | 749 main() |
| OLD | NEW |