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

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: Ravi comments 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
« no previous file with comments | « gm/rebaseline_server/results.py ('k') | gm/rebaseline_server/static/live-loader.js » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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
90 # Parameters we use within do_GET_live_results()
91 LIVE_PARAM__SET_A_DIR = 'setADir'
92 LIVE_PARAM__SET_B_DIR = 'setBDir'
93
86 # How often (in seconds) clients should reload while waiting for initial 94 # How often (in seconds) clients should reload while waiting for initial
87 # results to load. 95 # results to load.
88 RELOAD_INTERVAL_UNTIL_READY = 10 96 RELOAD_INTERVAL_UNTIL_READY = 10
89 97
90 SUMMARY_TYPES = [ 98 SUMMARY_TYPES = [
91 results_mod.KEY__HEADER__RESULTS_FAILURES, 99 results_mod.KEY__HEADER__RESULTS_FAILURES,
92 results_mod.KEY__HEADER__RESULTS_ALL, 100 results_mod.KEY__HEADER__RESULTS_ALL,
93 ] 101 ]
94 # If --compare-configs is specified, compare these configs. 102 # If --compare-configs is specified, compare these configs.
95 CONFIG_PAIRS_TO_COMPARE = [('8888', 'gpu')] 103 CONFIG_PAIRS_TO_COMPARE = [('8888', 'gpu')]
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
158 '<!DOCTYPE html><html>' 166 '<!DOCTYPE html><html>'
159 '<head><title>rebaseline_server</title></head>' 167 '<head><title>rebaseline_server</title></head>'
160 '<body><ul>') 168 '<body><ul>')
161 if SUMMARY_TYPES: 169 if SUMMARY_TYPES:
162 file_handle.write('<li>Expectations vs Actuals</li><ul>') 170 file_handle.write('<li>Expectations vs Actuals</li><ul>')
163 for summary_type in SUMMARY_TYPES: 171 for summary_type in SUMMARY_TYPES:
164 file_handle.write( 172 file_handle.write(
165 '<li><a href="/{static_subdir}/view.html#/view.html?' 173 '<li><a href="/{static_subdir}/view.html#/view.html?'
166 'resultsToLoad=/{results_subdir}/{summary_type}">' 174 'resultsToLoad=/{results_subdir}/{summary_type}">'
167 '{summary_type}</a></li>'.format( 175 '{summary_type}</a></li>'.format(
168 results_subdir=RESULTS_SUBDIR, 176 results_subdir=PRECOMPUTED_RESULTS_SUBDIR,
169 static_subdir=STATIC_CONTENTS_SUBDIR, 177 static_subdir=STATIC_CONTENTS_SUBDIR,
170 summary_type=summary_type)) 178 summary_type=summary_type))
171 file_handle.write('</ul>') 179 file_handle.write('</ul>')
172 if config_pairs: 180 if config_pairs:
173 file_handle.write('<li>Comparing configs within actual results</li><ul>') 181 file_handle.write('<li>Comparing configs within actual results</li><ul>')
174 for config_pair in config_pairs: 182 for config_pair in config_pairs:
175 file_handle.write('<li>%s vs %s:' % config_pair) 183 file_handle.write('<li>%s vs %s:' % config_pair)
176 for summary_type in SUMMARY_TYPES: 184 for summary_type in SUMMARY_TYPES:
177 file_handle.write( 185 file_handle.write(
178 ' <a href="/%s/view.html#/view.html?' 186 ' <a href="/%s/view.html#/view.html?'
179 'resultsToLoad=/%s/%s/%s-vs-%s_%s.json">%s</a>' % ( 187 'resultsToLoad=/%s/%s/%s-vs-%s_%s.json">%s</a>' % (
180 STATIC_CONTENTS_SUBDIR, STATIC_CONTENTS_SUBDIR, 188 STATIC_CONTENTS_SUBDIR, STATIC_CONTENTS_SUBDIR,
181 GENERATED_JSON_SUBDIR, config_pair[0], config_pair[1], 189 GENERATED_JSON_SUBDIR, config_pair[0], config_pair[1],
182 summary_type, summary_type)) 190 summary_type, summary_type))
183 file_handle.write('</li>') 191 file_handle.write('</li>')
184 file_handle.write('</ul>') 192 file_handle.write('</ul>')
185 file_handle.write('</ul></body></html>') 193 file_handle.write('</ul></body></html>')
186 194
187 195
188 class Server(object): 196 class Server(object):
189 """ HTTP server for our HTML rebaseline viewer. """ 197 """ HTTP server for our HTML rebaseline viewer. """
190 198
191 def __init__(self, 199 def __init__(self,
192 actuals_dir=DEFAULT_ACTUALS_DIR, 200 actuals_dir=DEFAULT_ACTUALS_DIR,
193 json_filename=DEFAULT_JSON_FILENAME, 201 json_filename=DEFAULT_JSON_FILENAME,
194 gm_summaries_bucket=DEFAULT_GM_SUMMARIES_BUCKET, 202 gm_summaries_bucket=DEFAULT_GM_SUMMARIES_BUCKET,
195 port=DEFAULT_PORT, export=False, editable=True, 203 port=DEFAULT_PORT, export=False, editable=True,
196 reload_seconds=0, config_pairs=None, builder_regex_list=None): 204 reload_seconds=0, config_pairs=None, builder_regex_list=None,
205 boto_file_path=None,
206 imagediffdb_threads=imagediffdb.DEFAULT_NUM_WORKER_THREADS):
197 """ 207 """
198 Args: 208 Args:
199 actuals_dir: directory under which we will check out the latest actual 209 actuals_dir: directory under which we will check out the latest actual
200 GM results 210 GM results
201 json_filename: basename of the JSON summary file to load for each builder 211 json_filename: basename of the JSON summary file to load for each builder
202 gm_summaries_bucket: Google Storage bucket to download json_filename 212 gm_summaries_bucket: Google Storage bucket to download json_filename
203 files from; if None or '', don't fetch new actual-results files 213 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 214 at all, just compare to whatever files are already in actuals_dir
205 port: which TCP port to listen on for HTTP requests 215 port: which TCP port to listen on for HTTP requests
206 export: whether to allow HTTP clients on other hosts to access this server 216 export: whether to allow HTTP clients on other hosts to access this server
207 editable: whether HTTP clients are allowed to submit new baselines 217 editable: whether HTTP clients are allowed to submit new baselines
208 reload_seconds: polling interval with which to check for new results; 218 reload_seconds: polling interval with which to check for new results;
209 if 0, don't check for new results at all 219 if 0, don't check for new results at all
210 config_pairs: List of (string, string) tuples; for each tuple, compare 220 config_pairs: List of (string, string) tuples; for each tuple, compare
211 actual results of these two configs. If None or empty, 221 actual results of these two configs. If None or empty,
212 don't compare configs at all. 222 don't compare configs at all.
213 builder_regex_list: List of regular expressions specifying which builders 223 builder_regex_list: List of regular expressions specifying which builders
214 we will process. If None, process all builders. 224 we will process. If None, process all builders.
225 boto_file_path: Path to .boto file giving us credentials to access
226 Google Storage buckets; if None, we will only be able to access
227 public GS buckets.
228 imagediffdb_threads: How many threads to spin up within imagediffdb.
215 """ 229 """
216 self._actuals_dir = actuals_dir 230 self._actuals_dir = actuals_dir
217 self._json_filename = json_filename 231 self._json_filename = json_filename
218 self._gm_summaries_bucket = gm_summaries_bucket 232 self._gm_summaries_bucket = gm_summaries_bucket
219 self._port = port 233 self._port = port
220 self._export = export 234 self._export = export
221 self._editable = editable 235 self._editable = editable
222 self._reload_seconds = reload_seconds 236 self._reload_seconds = reload_seconds
223 self._config_pairs = config_pairs or [] 237 self._config_pairs = config_pairs or []
224 self._builder_regex_list = builder_regex_list 238 self._builder_regex_list = builder_regex_list
225 self._gs = gs_utils.GSUtils() 239 self.truncate_results = False
240
241 if boto_file_path:
242 self._gs = gs_utils.GSUtils(boto_file_path=boto_file_path)
243 else:
244 self._gs = gs_utils.GSUtils()
245
226 _create_index( 246 _create_index(
227 file_path=os.path.join( 247 file_path=os.path.join(
228 PARENT_DIRECTORY, STATIC_CONTENTS_SUBDIR, GENERATED_HTML_SUBDIR, 248 PARENT_DIRECTORY, STATIC_CONTENTS_SUBDIR, GENERATED_HTML_SUBDIR,
229 "index.html"), 249 "index.html"),
230 config_pairs=config_pairs) 250 config_pairs=config_pairs)
231 251
232 # Reentrant lock that must be held whenever updating EITHER of: 252 # Reentrant lock that must be held whenever updating EITHER of:
233 # 1. self._results 253 # 1. self._results
234 # 2. the expected or actual results on local disk 254 # 2. the expected or actual results on local disk
235 self.results_rlock = threading.RLock() 255 self.results_rlock = threading.RLock()
236 256
237 # These will be filled in by calls to update_results() 257 # Create a single ImageDiffDB instance that is used by all our differs.
258 self._image_diff_db = imagediffdb.ImageDiffDB(
259 gs=self._gs,
260 storage_root=os.path.join(
261 PARENT_DIRECTORY, STATIC_CONTENTS_SUBDIR,
262 GENERATED_IMAGES_SUBDIR),
263 num_worker_threads=imagediffdb_threads)
264
265 # This will be filled in by calls to update_results()
238 self._results = None 266 self._results = None
239 self._image_diff_db = None
240 267
241 @property 268 @property
242 def results(self): 269 def results(self):
243 """ Returns the most recently generated results, or None if we don't have 270 """ Returns the most recently generated results, or None if we don't have
244 any valid results (update_results() has not completed yet). """ 271 any valid results (update_results() has not completed yet). """
245 return self._results 272 return self._results
246 273
247 @property 274 @property
275 def image_diff_db(self):
276 """ Returns reference to our ImageDiffDB object."""
277 return self._image_diff_db
278
279 @property
280 def gs(self):
281 """ Returns reference to our GSUtils object."""
282 return self._gs
283
284 @property
248 def is_exported(self): 285 def is_exported(self):
249 """ Returns true iff HTTP clients on other hosts are allowed to access 286 """ Returns true iff HTTP clients on other hosts are allowed to access
250 this server. """ 287 this server. """
251 return self._export 288 return self._export
252 289
253 @property 290 @property
254 def is_editable(self): 291 def is_editable(self):
255 """ Returns true iff HTTP clients are allowed to submit new baselines. """ 292 """ Returns true iff HTTP clients are allowed to submit new baselines. """
256 return self._editable 293 return self._editable
257 294
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
336 # updated expectations into a temp directory, and leaving the rest of 373 # updated expectations into a temp directory, and leaving the rest of
337 # the checkout alone. This could be done using "git show", or by 374 # the checkout alone. This could be done using "git show", or by
338 # downloading individual expectation JSON files from 375 # downloading individual expectation JSON files from
339 # skia.googlesource.com . 376 # skia.googlesource.com .
340 if self._reload_seconds: 377 if self._reload_seconds:
341 logging.info( 378 logging.info(
342 'Updating expected GM results in %s by syncing Skia repo ...' % 379 'Updating expected GM results in %s by syncing Skia repo ...' %
343 compare_to_expectations.DEFAULT_EXPECTATIONS_DIR) 380 compare_to_expectations.DEFAULT_EXPECTATIONS_DIR)
344 _run_command(['gclient', 'sync'], TRUNK_DIRECTORY) 381 _run_command(['gclient', 'sync'], TRUNK_DIRECTORY)
345 382
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( 383 self._results = compare_to_expectations.ExpectationComparisons(
353 image_diff_db=self._image_diff_db, 384 image_diff_db=self._image_diff_db,
354 actuals_root=self._actuals_dir, 385 actuals_root=self._actuals_dir,
355 diff_base_url=posixpath.join( 386 diff_base_url=posixpath.join(
356 os.pardir, STATIC_CONTENTS_SUBDIR, GENERATED_IMAGES_SUBDIR), 387 os.pardir, STATIC_CONTENTS_SUBDIR, GENERATED_IMAGES_SUBDIR),
357 builder_regex_list=self._builder_regex_list) 388 builder_regex_list=self._builder_regex_list)
358 389
359 json_dir = os.path.join( 390 json_dir = os.path.join(
360 PARENT_DIRECTORY, STATIC_CONTENTS_SUBDIR, GENERATED_JSON_SUBDIR) 391 PARENT_DIRECTORY, STATIC_CONTENTS_SUBDIR, GENERATED_JSON_SUBDIR)
361 if not os.path.isdir(json_dir): 392 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) 467 self.redirect_to('/%s/favicon.ico' % STATIC_CONTENTS_SUBDIR)
437 return 468 return
438 469
439 # All requests must be of this form: 470 # All requests must be of this form:
440 # /dispatcher/remainder 471 # /dispatcher/remainder
441 # where 'dispatcher' indicates which do_GET_* dispatcher to run 472 # where 'dispatcher' indicates which do_GET_* dispatcher to run
442 # and 'remainder' is the remaining path sent to that dispatcher. 473 # and 'remainder' is the remaining path sent to that dispatcher.
443 normpath = posixpath.normpath(self.path) 474 normpath = posixpath.normpath(self.path)
444 (dispatcher_name, remainder) = PATHSPLIT_RE.match(normpath).groups() 475 (dispatcher_name, remainder) = PATHSPLIT_RE.match(normpath).groups()
445 dispatchers = { 476 dispatchers = {
446 RESULTS_SUBDIR: self.do_GET_results, 477 PRECOMPUTED_RESULTS_SUBDIR: self.do_GET_precomputed_results,
478 LIVE_RESULTS_SUBDIR: self.do_GET_live_results,
447 STATIC_CONTENTS_SUBDIR: self.do_GET_static, 479 STATIC_CONTENTS_SUBDIR: self.do_GET_static,
448 } 480 }
449 dispatcher = dispatchers[dispatcher_name] 481 dispatcher = dispatchers[dispatcher_name]
450 dispatcher(remainder) 482 dispatcher(remainder)
451 except: 483 except:
452 self.send_error(404) 484 self.send_error(404)
453 raise 485 raise
454 486
455 def do_GET_results(self, results_type): 487 def do_GET_precomputed_results(self, results_type):
456 """ Handle a GET request for GM results. 488 """ Handle a GET request for part of the precomputed _SERVER.results object.
457 489
458 Args: 490 Args:
459 results_type: string indicating which set of results to return; 491 results_type: string indicating which set of results to return;
460 must be one of the results_mod.RESULTS_* constants 492 must be one of the results_mod.RESULTS_* constants
461 """ 493 """
462 logging.debug('do_GET_results: sending results of type "%s"' % results_type) 494 logging.debug('do_GET_precomputed_results: sending results of type "%s"' %
495 results_type)
463 # Since we must make multiple calls to the ExpectationComparisons object, 496 # 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 497 # grab a reference to it in case it is updated to point at a new
465 # ExpectationComparisons object within another thread. 498 # ExpectationComparisons object within another thread.
466 # 499 #
467 # TODO(epoger): Rather than using a global variable for the handler 500 # TODO(epoger): Rather than using a global variable for the handler
468 # to refer to the Server object, make Server a subclass of 501 # to refer to the Server object, make Server a subclass of
469 # HTTPServer, and then it could be available to the handler via 502 # HTTPServer, and then it could be available to the handler via
470 # the handler's .server instance variable. 503 # the handler's .server instance variable.
471 results_obj = _SERVER.results 504 results_obj = _SERVER.results
472 if results_obj: 505 if results_obj:
473 response_dict = results_obj.get_packaged_results_of_type( 506 response_dict = results_obj.get_packaged_results_of_type(
474 results_type=results_type, reload_seconds=_SERVER.reload_seconds, 507 results_type=results_type, reload_seconds=_SERVER.reload_seconds,
475 is_editable=_SERVER.is_editable, is_exported=_SERVER.is_exported) 508 is_editable=_SERVER.is_editable, is_exported=_SERVER.is_exported)
476 else: 509 else:
477 now = int(time.time()) 510 now = int(time.time())
478 response_dict = { 511 response_dict = {
479 imagepairset.KEY__ROOT__HEADER: { 512 imagepairset.KEY__ROOT__HEADER: {
480 results_mod.KEY__HEADER__SCHEMA_VERSION: ( 513 results_mod.KEY__HEADER__SCHEMA_VERSION: (
481 results_mod.VALUE__HEADER__SCHEMA_VERSION), 514 results_mod.VALUE__HEADER__SCHEMA_VERSION),
482 results_mod.KEY__HEADER__IS_STILL_LOADING: True, 515 results_mod.KEY__HEADER__IS_STILL_LOADING: True,
483 results_mod.KEY__HEADER__TIME_UPDATED: now, 516 results_mod.KEY__HEADER__TIME_UPDATED: now,
484 results_mod.KEY__HEADER__TIME_NEXT_UPDATE_AVAILABLE: ( 517 results_mod.KEY__HEADER__TIME_NEXT_UPDATE_AVAILABLE: (
485 now + RELOAD_INTERVAL_UNTIL_READY), 518 now + RELOAD_INTERVAL_UNTIL_READY),
486 }, 519 },
487 } 520 }
488 self.send_json_dict(response_dict) 521 self.send_json_dict(response_dict)
489 522
523 def do_GET_live_results(self, url_remainder):
524 """ Handle a GET request for live-generated image diff data.
525
526 Args:
527 url_remainder: string indicating which image diffs to generate
528 """
529 logging.debug('do_GET_live_results: url_remainder="%s"' % url_remainder)
530 param_dict = urlparse.parse_qs(url_remainder)
531 results_obj = compare_rendered_pictures.RenderedPicturesComparisons(
532 setA_dirs=param_dict[LIVE_PARAM__SET_A_DIR],
533 setB_dirs=param_dict[LIVE_PARAM__SET_B_DIR],
534 image_diff_db=_SERVER.image_diff_db,
535 diff_base_url='/static/generated-images',
536 gs=_SERVER.gs, truncate_results=_SERVER.truncate_results)
537 self.send_json_dict(results_obj.get_packaged_results_of_type(
538 results_mod.KEY__HEADER__RESULTS_ALL))
539
490 def do_GET_static(self, path): 540 def do_GET_static(self, path):
491 """ Handle a GET request for a file under STATIC_CONTENTS_SUBDIR . 541 """ Handle a GET request for a file under STATIC_CONTENTS_SUBDIR .
492 Only allow serving of files within STATIC_CONTENTS_SUBDIR that is a 542 Only allow serving of files within STATIC_CONTENTS_SUBDIR that is a
493 filesystem sibling of this script. 543 filesystem sibling of this script.
494 544
495 Args: 545 Args:
496 path: path to file (within STATIC_CONTENTS_SUBDIR) to retrieve 546 path: path to file (within STATIC_CONTENTS_SUBDIR) to retrieve
497 """ 547 """
498 # Strip arguments ('?resultsToLoad=all') from the path 548 # Strip arguments ('?resultsToLoad=all') from the path
499 path = urlparse.urlparse(path).path 549 path = urlparse.urlparse(path).path
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after
636 def main(): 686 def main():
637 logging.basicConfig(format='%(asctime)s %(levelname)s %(message)s', 687 logging.basicConfig(format='%(asctime)s %(levelname)s %(message)s',
638 datefmt='%m/%d/%Y %H:%M:%S', 688 datefmt='%m/%d/%Y %H:%M:%S',
639 level=logging.INFO) 689 level=logging.INFO)
640 parser = argparse.ArgumentParser() 690 parser = argparse.ArgumentParser()
641 parser.add_argument('--actuals-dir', 691 parser.add_argument('--actuals-dir',
642 help=('Directory into which we will check out the latest ' 692 help=('Directory into which we will check out the latest '
643 'actual GM results. If this directory does not ' 693 'actual GM results. If this directory does not '
644 'exist, it will be created. Defaults to %(default)s'), 694 'exist, it will be created. Defaults to %(default)s'),
645 default=DEFAULT_ACTUALS_DIR) 695 default=DEFAULT_ACTUALS_DIR)
696 parser.add_argument('--boto',
697 help=('Path to .boto file giving us credentials to access '
698 'Google Storage buckets. If not specified, we will '
699 'only be able to access public GS buckets (and thus '
700 'won\'t be able to download SKP images).'),
701 default='')
646 # TODO(epoger): Before https://codereview.chromium.org/310093003 , 702 # TODO(epoger): Before https://codereview.chromium.org/310093003 ,
647 # when this tool downloaded the JSON summaries from skia-autogen, 703 # when this tool downloaded the JSON summaries from skia-autogen,
648 # it had an --actuals-revision the caller could specify to download 704 # 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 705 # actual results as of a specific point in time. We should add similar
650 # functionality when retrieving the summaries from Google Storage. 706 # functionality when retrieving the summaries from Google Storage.
651 parser.add_argument('--builders', metavar='BUILDER_REGEX', nargs='+', 707 parser.add_argument('--builders', metavar='BUILDER_REGEX', nargs='+',
652 help=('Only process builders matching these regular ' 708 help=('Only process builders matching these regular '
653 'expressions. If unspecified, process all ' 709 'expressions. If unspecified, process all '
654 'builders.')) 710 'builders.'))
655 parser.add_argument('--compare-configs', action='store_true', 711 parser.add_argument('--compare-configs', action='store_true',
(...skipping 25 matching lines...) Expand all
681 'defaults to %(default)s'), 737 'defaults to %(default)s'),
682 default=DEFAULT_PORT) 738 default=DEFAULT_PORT)
683 parser.add_argument('--reload', type=int, 739 parser.add_argument('--reload', type=int,
684 help=('How often (a period in seconds) to update the ' 740 help=('How often (a period in seconds) to update the '
685 'results. If specified, both expected and actual ' 741 'results. If specified, both expected and actual '
686 'results will be updated by running "gclient sync" ' 742 'results will be updated by running "gclient sync" '
687 'on your Skia checkout as a whole. ' 743 'on your Skia checkout as a whole. '
688 'By default, we do not reload at all, and you ' 744 'By default, we do not reload at all, and you '
689 'must restart the server to pick up new data.'), 745 'must restart the server to pick up new data.'),
690 default=0) 746 default=0)
747 parser.add_argument('--threads', type=int,
748 help=('How many parallel threads we use to download '
749 'images and generate diffs; defaults to '
750 '%(default)s'),
751 default=imagediffdb.DEFAULT_NUM_WORKER_THREADS)
752 parser.add_argument('--truncate', action='store_true',
753 help=('FOR TESTING ONLY: truncate the set of images we '
754 'process, to speed up testing.'))
691 args = parser.parse_args() 755 args = parser.parse_args()
692 if args.compare_configs: 756 if args.compare_configs:
693 config_pairs = CONFIG_PAIRS_TO_COMPARE 757 config_pairs = CONFIG_PAIRS_TO_COMPARE
694 else: 758 else:
695 config_pairs = None 759 config_pairs = None
696 760
697 global _SERVER 761 global _SERVER
698 _SERVER = Server(actuals_dir=args.actuals_dir, 762 _SERVER = Server(actuals_dir=args.actuals_dir,
699 json_filename=args.json_filename, 763 json_filename=args.json_filename,
700 gm_summaries_bucket=args.gm_summaries_bucket, 764 gm_summaries_bucket=args.gm_summaries_bucket,
701 port=args.port, export=args.export, editable=args.editable, 765 port=args.port, export=args.export, editable=args.editable,
702 reload_seconds=args.reload, config_pairs=config_pairs, 766 reload_seconds=args.reload, config_pairs=config_pairs,
703 builder_regex_list=args.builders) 767 builder_regex_list=args.builders, boto_file_path=args.boto,
768 imagediffdb_threads=args.threads)
769 if args.truncate:
770 _SERVER.truncate_results = True
704 _SERVER.run() 771 _SERVER.run()
705 772
706 773
707 if __name__ == '__main__': 774 if __name__ == '__main__':
708 main() 775 main()
OLDNEW
« no previous file with comments | « gm/rebaseline_server/results.py ('k') | gm/rebaseline_server/static/live-loader.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698