Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(391)

Side by Side Diff: gm/rebaseline_server/server.py

Issue 424263005: teach rebaseline_server to generate diffs of rendered SKPs (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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
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
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
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()
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698