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

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

Issue 688353003: Add support for rebaselining from trybots. (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Fixup exception handling. Created 6 years, 1 month 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 242 matching lines...) Expand 10 before | Expand all | Expand 10 after
253 _SKP_PLATFORMS[0], _SKP_PLATFORMS[1])) 253 _SKP_PLATFORMS[0], _SKP_PLATFORMS[1]))
254 file_handle.write('</li>') 254 file_handle.write('</li>')
255 255
256 file_handle.write('\n</ul></body></html>') 256 file_handle.write('\n</ul></body></html>')
257 257
258 258
259 class Server(object): 259 class Server(object):
260 """ HTTP server for our HTML rebaseline viewer. """ 260 """ HTTP server for our HTML rebaseline viewer. """
261 261
262 def __init__(self, 262 def __init__(self,
263 actuals_source,
263 actuals_dir=DEFAULT_ACTUALS_DIR, 264 actuals_dir=DEFAULT_ACTUALS_DIR,
264 json_filename=DEFAULT_JSON_FILENAME, 265 json_filename=DEFAULT_JSON_FILENAME,
265 gm_summaries_bucket=DEFAULT_GM_SUMMARIES_BUCKET,
266 port=DEFAULT_PORT, export=False, editable=True, 266 port=DEFAULT_PORT, export=False, editable=True,
267 reload_seconds=0, config_pairs=None, builder_regex_list=None, 267 reload_seconds=0, config_pairs=None, builder_regex_list=None,
268 boto_file_path=None, 268 boto_file_path=None,
269 imagediffdb_threads=imagediffdb.DEFAULT_NUM_WORKER_THREADS): 269 imagediffdb_threads=imagediffdb.DEFAULT_NUM_WORKER_THREADS):
270 """ 270 """
271 Args: 271 Args:
272 actuals_source: actuals_source.get_builders() ->
273 {builder:string -> [ bucket:string, path:string, generation:string ]}
274 If None, don't fetch new actual-results files
275 at all, just compare to whatever files are already in actuals_dir
272 actuals_dir: directory under which we will check out the latest actual 276 actuals_dir: directory under which we will check out the latest actual
273 GM results 277 GM results
274 json_filename: basename of the JSON summary file to load for each builder 278 json_filename: basename of the JSON summary file to load for each builder
275 gm_summaries_bucket: Google Storage bucket to download json_filename
276 files from; if None or '', don't fetch new actual-results files
277 at all, just compare to whatever files are already in actuals_dir
278 port: which TCP port to listen on for HTTP requests 279 port: which TCP port to listen on for HTTP requests
279 export: whether to allow HTTP clients on other hosts to access this server 280 export: whether to allow HTTP clients on other hosts to access this server
280 editable: whether HTTP clients are allowed to submit new GM baselines 281 editable: whether HTTP clients are allowed to submit new GM baselines
281 (SKP baseline modifications are performed using an entirely different 282 (SKP baseline modifications are performed using an entirely different
282 mechanism, not affected by this parameter) 283 mechanism, not affected by this parameter)
283 reload_seconds: polling interval with which to check for new results; 284 reload_seconds: polling interval with which to check for new results;
284 if 0, don't check for new results at all 285 if 0, don't check for new results at all
285 config_pairs: List of (string, string) tuples; for each tuple, compare 286 config_pairs: List of (string, string) tuples; for each tuple, compare
286 actual results of these two configs. If None or empty, 287 actual results of these two configs. If None or empty,
287 don't compare configs at all. 288 don't compare configs at all.
288 builder_regex_list: List of regular expressions specifying which builders 289 builder_regex_list: List of regular expressions specifying which builders
289 we will process. If None, process all builders. 290 we will process. If None, process all builders.
290 boto_file_path: Path to .boto file giving us credentials to access 291 boto_file_path: Path to .boto file giving us credentials to access
291 Google Storage buckets; if None, we will only be able to access 292 Google Storage buckets; if None, we will only be able to access
292 public GS buckets. 293 public GS buckets.
293 imagediffdb_threads: How many threads to spin up within imagediffdb. 294 imagediffdb_threads: How many threads to spin up within imagediffdb.
294 """ 295 """
296 self._actuals_source = actuals_source
295 self._actuals_dir = actuals_dir 297 self._actuals_dir = actuals_dir
296 self._json_filename = json_filename 298 self._json_filename = json_filename
297 self._gm_summaries_bucket = gm_summaries_bucket
298 self._port = port 299 self._port = port
299 self._export = export 300 self._export = export
300 self._editable = editable 301 self._editable = editable
301 self._reload_seconds = reload_seconds 302 self._reload_seconds = reload_seconds
302 self._config_pairs = config_pairs or [] 303 self._config_pairs = config_pairs or []
303 self._builder_regex_list = builder_regex_list 304 self._builder_regex_list = builder_regex_list
304 self.truncate_results = False 305 self.truncate_results = False
305 306
306 if boto_file_path: 307 if boto_file_path:
307 self._gs = gs_utils.GSUtils(boto_file_path=boto_file_path) 308 self._gs = gs_utils.GSUtils(boto_file_path=boto_file_path)
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
378 the same time. 379 the same time.
379 380
380 Args: 381 Args:
381 invalidate: if True, invalidate self._results immediately upon entry; 382 invalidate: if True, invalidate self._results immediately upon entry;
382 otherwise, we will let readers see those results until we 383 otherwise, we will let readers see those results until we
383 replace them 384 replace them
384 """ 385 """
385 with self.results_rlock: 386 with self.results_rlock:
386 if invalidate: 387 if invalidate:
387 self._results = None 388 self._results = None
388 if self._gm_summaries_bucket: 389
390 if self._actuals_source:
389 logging.info( 391 logging.info(
390 'Updating GM result summaries in %s from gm_summaries_bucket %s ...' 392 'Updating GM result summaries in %s from %s ...'
391 % (self._actuals_dir, self._gm_summaries_bucket)) 393 % (self._actuals_dir, self._actuals_source.description()))
392 394
393 # Clean out actuals_dir first, in case some builders have gone away 395 # Clean out actuals_dir first, in case some builders have gone away
394 # since we last ran. 396 # since we last ran.
395 if os.path.isdir(self._actuals_dir): 397 if os.path.isdir(self._actuals_dir):
396 shutil.rmtree(self._actuals_dir) 398 shutil.rmtree(self._actuals_dir)
397 399
398 # Get the list of builders we care about. 400 # Get the list of actuals we care about.
399 all_builders = download_actuals.get_builders_list( 401 all_actuals = self._actuals_source.get_builders()
400 summaries_bucket=self._gm_summaries_bucket) 402
401 if self._builder_regex_list: 403 if self._builder_regex_list:
402 matching_builders = [] 404 matching_builders = []
403 for builder in all_builders: 405 for builder in all_actuals:
404 for regex in self._builder_regex_list: 406 for regex in self._builder_regex_list:
405 if re.match(regex, builder): 407 if re.match(regex, builder):
406 matching_builders.append(builder) 408 matching_builders.append(builder)
407 break # go on to the next builder, no need to try more regexes 409 break # go on to the next builder, no need to try more regexes
408 else: 410 else:
409 matching_builders = all_builders 411 matching_builders = all_actuals.keys()
410 412
411 # Download the JSON file for each builder we care about. 413 # Download the JSON file for each builder we care about.
412 # 414 #
413 # TODO(epoger): When this is a large number of builders, we would be 415 # TODO(epoger): When this is a large number of builders, we would be
414 # better off downloading them in parallel! 416 # better off downloading them in parallel!
415 for builder in matching_builders: 417 for builder in matching_builders:
416 self._gs.download_file( 418 self._gs.download_file(
417 source_bucket=self._gm_summaries_bucket, 419 source_bucket=all_actuals[builder].bucket,
418 source_path=posixpath.join(builder, self._json_filename), 420 source_path=all_actuals[builder].path,
421 source_generation=all_actuals[builder].generation,
419 dest_path=os.path.join(self._actuals_dir, builder, 422 dest_path=os.path.join(self._actuals_dir, builder,
420 self._json_filename), 423 self._json_filename),
421 create_subdirs_if_needed=True) 424 create_subdirs_if_needed=True)
422 425
423 # We only update the expectations dir if the server was run with a 426 # We only update the expectations dir if the server was run with a
424 # nonzero --reload argument; otherwise, we expect the user to maintain 427 # nonzero --reload argument; otherwise, we expect the user to maintain
425 # her own expectations as she sees fit. 428 # her own expectations as she sees fit.
426 # 429 #
427 # Because the Skia repo is hosted using git, and git does not 430 # Because the Skia repo is hosted using git, and git does not
428 # support updating a single directory tree, we have to update the entire 431 # support updating a single directory tree, we have to update the entire
(...skipping 463 matching lines...) Expand 10 before | Expand all | Expand 10 after
892 parser.add_argument('--editable', action='store_true', 895 parser.add_argument('--editable', action='store_true',
893 help=('Allow HTTP clients to submit new GM baselines; ' 896 help=('Allow HTTP clients to submit new GM baselines; '
894 'SKP baselines can be edited regardless of this ' 897 'SKP baselines can be edited regardless of this '
895 'setting.')) 898 'setting.'))
896 parser.add_argument('--export', action='store_true', 899 parser.add_argument('--export', action='store_true',
897 help=('Instead of only allowing access from HTTP clients ' 900 help=('Instead of only allowing access from HTTP clients '
898 'on localhost, allow HTTP clients on other hosts ' 901 'on localhost, allow HTTP clients on other hosts '
899 'to access this server. WARNING: doing so will ' 902 'to access this server. WARNING: doing so will '
900 'allow users on other hosts to modify your ' 903 'allow users on other hosts to modify your '
901 'GM expectations, if combined with --editable.')) 904 'GM expectations, if combined with --editable.'))
905 parser.add_argument('--rietveld-issue',
906 help=('Download json_filename files from latest trybot'
907 'runs on this codereview.chromium.org issue.'
908 'Overrides --gm-summaries-bucket.'))
902 parser.add_argument('--gm-summaries-bucket', 909 parser.add_argument('--gm-summaries-bucket',
903 help=('Google Cloud Storage bucket to download ' 910 help=('Google Cloud Storage bucket to download '
904 'JSON_FILENAME files from. ' 911 'JSON_FILENAME files from. '
905 'Defaults to %(default)s ; if set to ' 912 'Defaults to %(default)s ; if set to '
906 'empty string, just compare to actual-results ' 913 'empty string, just compare to actual-results '
907 'already found in ACTUALS_DIR.'), 914 'already found in ACTUALS_DIR.'),
908 default=DEFAULT_GM_SUMMARIES_BUCKET) 915 default=DEFAULT_GM_SUMMARIES_BUCKET)
909 parser.add_argument('--json-filename', 916 parser.add_argument('--json-filename',
910 help=('JSON summary filename to read for each builder; ' 917 help=('JSON summary filename to read for each builder; '
911 'defaults to %(default)s.'), 918 'defaults to %(default)s.'),
(...skipping 17 matching lines...) Expand all
929 default=imagediffdb.DEFAULT_NUM_WORKER_THREADS) 936 default=imagediffdb.DEFAULT_NUM_WORKER_THREADS)
930 parser.add_argument('--truncate', action='store_true', 937 parser.add_argument('--truncate', action='store_true',
931 help=('FOR TESTING ONLY: truncate the set of images we ' 938 help=('FOR TESTING ONLY: truncate the set of images we '
932 'process, to speed up testing.')) 939 'process, to speed up testing.'))
933 args = parser.parse_args() 940 args = parser.parse_args()
934 if args.compare_configs: 941 if args.compare_configs:
935 config_pairs = CONFIG_PAIRS_TO_COMPARE 942 config_pairs = CONFIG_PAIRS_TO_COMPARE
936 else: 943 else:
937 config_pairs = None 944 config_pairs = None
938 945
946 if args.rietveld_issue:
947 actuals_source = download_actuals.RietveldIssueActuals(args.rietveld_issue,
948 args.json_filename)
949 else:
950 actuals_source = download_actuals.TipOfTreeActuals(args.gm_summaries_bucket,
951 args.json_filename)
952
939 global _SERVER 953 global _SERVER
940 _SERVER = Server(actuals_dir=args.actuals_dir, 954 _SERVER = Server(actuals_source,
955 actuals_dir=args.actuals_dir,
941 json_filename=args.json_filename, 956 json_filename=args.json_filename,
942 gm_summaries_bucket=args.gm_summaries_bucket,
943 port=args.port, export=args.export, editable=args.editable, 957 port=args.port, export=args.export, editable=args.editable,
944 reload_seconds=args.reload, config_pairs=config_pairs, 958 reload_seconds=args.reload, config_pairs=config_pairs,
945 builder_regex_list=args.builders, boto_file_path=args.boto, 959 builder_regex_list=args.builders, boto_file_path=args.boto,
946 imagediffdb_threads=args.threads) 960 imagediffdb_threads=args.threads)
947 if args.truncate: 961 if args.truncate:
948 _SERVER.truncate_results = True 962 _SERVER.truncate_results = True
949 _SERVER.run() 963 _SERVER.run()
950 964
951 965
952 if __name__ == '__main__': 966 if __name__ == '__main__':
953 main() 967 main()
OLDNEW
« gm/rebaseline_server/download_actuals.py ('K') | « gm/rebaseline_server/download_actuals.py ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698