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

Side by Side Diff: tools/rebaseline.py

Issue 17379004: rebaseline.py: split image-based rebaselining, which will go away soon, into its own script (Closed) Base URL: http://skia.googlecode.com/svn/trunk/
Patch Set: sync_to_r9687 Created 7 years, 6 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 | Annotate | Revision Log
« no previous file with comments | « no previous file | tools/rebaseline_imagefiles.py » ('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 2012 Google Inc. 4 Copyright 2012 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 9
10 ''' 10 '''
11 Rebaselines the given GM tests, on all bots and all configurations. 11 Rebaselines the given GM tests, on all bots and all configurations.
12 Must be run from the gm-expected directory. If run from a git or SVN 12 Must be run from the gm-expected directory. If run from a git or SVN
13 checkout, the files will be added to the staging area for commit. 13 checkout, the files will be added to the staging area for commit.
14 ''' 14 '''
15 15
16 # System-level imports 16 # System-level imports
17 import argparse 17 import argparse
18 import os 18 import os
19 import re 19 import re
20 import subprocess 20 import subprocess
21 import sys 21 import sys
22 import urllib2 22 import urllib2
23 23
24 # Imports from local directory
25 import rebaseline_imagefiles
26
24 # Imports from within Skia 27 # Imports from within Skia
25 # 28 #
26 # We need to add the 'gm' directory, so that we can import gm_json.py within 29 # We need to add the 'gm' directory, so that we can import gm_json.py within
27 # that directory. That script allows us to parse the actual-results.json file 30 # that directory. That script allows us to parse the actual-results.json file
28 # written out by the GM tool. 31 # written out by the GM tool.
29 # Make sure that the 'gm' dir is in the PYTHONPATH, but add it at the *end* 32 # Make sure that the 'gm' dir is in the PYTHONPATH, but add it at the *end*
30 # so any dirs that are already in the PYTHONPATH will be preferred. 33 # so any dirs that are already in the PYTHONPATH will be preferred.
31 # 34 #
32 # This assumes that the 'gm' directory has been checked out as a sibling of 35 # This assumes that the 'gm' directory has been checked out as a sibling of
33 # the 'tools' directory containing this script, which will be the case if 36 # the 'tools' directory containing this script, which will be the case if
34 # 'trunk' was checked out as a single unit. 37 # 'trunk' was checked out as a single unit.
35 GM_DIRECTORY = os.path.realpath( 38 GM_DIRECTORY = os.path.realpath(
36 os.path.join(os.path.dirname(os.path.dirname(__file__)), 'gm')) 39 os.path.join(os.path.dirname(os.path.dirname(__file__)), 'gm'))
37 if GM_DIRECTORY not in sys.path: 40 if GM_DIRECTORY not in sys.path:
38 sys.path.append(GM_DIRECTORY) 41 sys.path.append(GM_DIRECTORY)
39 import gm_json 42 import gm_json
40 43
44 JSON_EXPECTATIONS_FILENAME='expected-results.json'
41 45
42 # Mapping of gm-expectations subdir (under 46 # Mapping of gm-expectations subdir (under
43 # https://skia.googlecode.com/svn/gm-expected/ ) 47 # https://skia.googlecode.com/svn/gm-expected/ )
44 # to builder name (see list at http://108.170.217.252:10117/builders ) 48 # to builder name (see list at http://108.170.217.252:10117/builders )
45 SUBDIR_MAPPING = { 49 SUBDIR_MAPPING = {
46 'base-shuttle-win7-intel-float': 50 'base-shuttle-win7-intel-float':
47 'Test-Win7-ShuttleA-HD2000-x86-Release', 51 'Test-Win7-ShuttleA-HD2000-x86-Release',
48 'base-shuttle-win7-intel-angle': 52 'base-shuttle-win7-intel-angle':
49 'Test-Win7-ShuttleA-HD2000-x86-Release-ANGLE', 53 'Test-Win7-ShuttleA-HD2000-x86-Release-ANGLE',
50 'base-shuttle-win7-intel-directwrite': 54 'base-shuttle-win7-intel-directwrite':
(...skipping 13 matching lines...) Expand all
64 'base-android-xoom': 68 'base-android-xoom':
65 'Test-Android-Xoom-Tegra2-Arm7-Release', 69 'Test-Android-Xoom-Tegra2-Arm7-Release',
66 'base-android-nexus-10': 70 'base-android-nexus-10':
67 'Test-Android-Nexus10-MaliT604-Arm7-Release', 71 'Test-Android-Nexus10-MaliT604-Arm7-Release',
68 } 72 }
69 73
70 74
71 class CommandFailedException(Exception): 75 class CommandFailedException(Exception):
72 pass 76 pass
73 77
74 class Rebaseliner(object): 78 # Object that rebaselines a JSON expectations file (not individual image files).
79 #
80 # TODO(epoger): Most of this is just the code from the old ImageRebaseliner...
81 # some of it will need to be updated in order to properly rebaseline JSON files.
82 # There is a lot of code duplicated between here and ImageRebaseliner, but
83 # that's fine because we will delete ImageRebaseliner soon.
84 class JsonRebaseliner(object):
75 85
76 # params: 86 # params:
87 # expectations_root: root directory of all expectations
77 # json_base_url: base URL from which to read json_filename 88 # json_base_url: base URL from which to read json_filename
78 # json_filename: filename (under json_base_url) from which to read a 89 # json_filename: filename (under json_base_url) from which to read a
79 # summary of results; typically "actual-results.json" 90 # summary of results; typically "actual-results.json"
80 # subdirs: which platform subdirectories to rebaseline; if not specified,
81 # rebaseline all platform subdirectories
82 # tests: list of tests to rebaseline, or None if we should rebaseline 91 # tests: list of tests to rebaseline, or None if we should rebaseline
83 # whatever files the JSON results summary file tells us to 92 # whatever files the JSON results summary file tells us to
84 # configs: which configs to run for each test; this should only be 93 # configs: which configs to run for each test; this should only be
85 # specified if the list of tests was also specified (otherwise, 94 # specified if the list of tests was also specified (otherwise,
86 # the JSON file will give us test names and configs) 95 # the JSON file will give us test names and configs)
87 # dry_run: if True, instead of actually downloading files or adding 96 # dry_run: if True, instead of actually downloading files or adding
88 # files to checkout, display a list of operations that 97 # files to checkout, display a list of operations that
89 # we would normally perform 98 # we would normally perform
90 # add_new: if True, add expectations for tests which don't have any yet 99 # add_new: if True, add expectations for tests which don't have any yet
91 def __init__(self, json_base_url, json_filename, 100 # missing_json_is_fatal: whether to halt execution if we cannot read a
92 subdirs=None, tests=None, configs=None, dry_run=False, 101 # JSON actual result summary file
93 add_new=False): 102 def __init__(self, expectations_root, json_base_url, json_filename,
103 tests=None, configs=None, dry_run=False,
104 add_new=False, missing_json_is_fatal=False):
105 raise ValueError('JsonRebaseliner not yet implemented') # TODO(epoger)
94 if configs and not tests: 106 if configs and not tests:
95 raise ValueError('configs should only be specified if tests ' + 107 raise ValueError('configs should only be specified if tests ' +
96 'were specified also') 108 'were specified also')
109 self._expectations_root = expectations_root
97 self._tests = tests 110 self._tests = tests
98 self._configs = configs 111 self._configs = configs
99 if not subdirs:
100 self._subdirs = sorted(SUBDIR_MAPPING.keys())
101 self._missing_json_is_fatal = False
102 else:
103 self._subdirs = subdirs
104 self._missing_json_is_fatal = True
105 self._json_base_url = json_base_url 112 self._json_base_url = json_base_url
106 self._json_filename = json_filename 113 self._json_filename = json_filename
107 self._dry_run = dry_run 114 self._dry_run = dry_run
108 self._add_new = add_new 115 self._add_new = add_new
116 self._missing_json_is_fatal = missing_json_is_fatal
109 self._googlestorage_gm_actuals_root = ( 117 self._googlestorage_gm_actuals_root = (
110 'http://chromium-skia-gm.commondatastorage.googleapis.com/gm') 118 'http://chromium-skia-gm.commondatastorage.googleapis.com/gm')
111 self._testname_pattern = re.compile('(\S+)_(\S+).png') 119 self._testname_pattern = re.compile('(\S+)_(\S+).png')
112 self._is_svn_checkout = ( 120 self._is_svn_checkout = (
113 os.path.exists('.svn') or 121 os.path.exists('.svn') or
114 os.path.exists(os.path.join(os.pardir, '.svn'))) 122 os.path.exists(os.path.join(os.pardir, '.svn')))
115 self._is_git_checkout = ( 123 self._is_git_checkout = (
116 os.path.exists('.git') or 124 os.path.exists('.git') or
117 os.path.exists(os.path.join(os.pardir, '.git'))) 125 os.path.exists(os.path.join(os.pardir, '.git')))
118 126
(...skipping 213 matching lines...) Expand 10 before | Expand all | Expand 10 after
332 print '# ' + expectations_subdir + ':' 340 print '# ' + expectations_subdir + ':'
333 for config in configs: 341 for config in configs:
334 infilename = test + '_' + config + '.png' 342 infilename = test + '_' + config + '.png'
335 outfilename = os.path.join(expectations_subdir, infilename); 343 outfilename = os.path.join(expectations_subdir, infilename);
336 self._RebaselineOneFile(expectations_subdir=expectations_subdir, 344 self._RebaselineOneFile(expectations_subdir=expectations_subdir,
337 builder_name=builder_name, 345 builder_name=builder_name,
338 infilename=infilename, 346 infilename=infilename,
339 outfilename=outfilename, 347 outfilename=outfilename,
340 all_results=all_results) 348 all_results=all_results)
341 349
342 # Rebaseline all platforms/tests/types we specified in the constructor. 350 # Rebaseline all tests/types we specified in the constructor,
343 def RebaselineAll(self): 351 # within this gm-expectations subdir.
344 for subdir in self._subdirs: 352 #
345 if not subdir in SUBDIR_MAPPING.keys(): 353 # params:
346 raise Exception(('unrecognized platform subdir "%s"; ' + 354 # subdir : e.g. 'base-shuttle-win7-intel-float'
347 'should be one of %s') % ( 355 # builder : e.g. 'Test-Win7-ShuttleA-HD2000-x86-Release'
348 subdir, SUBDIR_MAPPING.keys())) 356 def RebaselineSubdir(self, subdir, builder):
349 builder_name = SUBDIR_MAPPING[subdir] 357 json_url = '/'.join([self._json_base_url,
350 json_url = '/'.join([self._json_base_url, 358 subdir, builder, subdir,
351 subdir, builder_name, subdir, 359 self._json_filename])
352 self._json_filename]) 360 all_results = self._GetActualResults(json_url=json_url)
353 all_results = self._GetActualResults(json_url=json_url)
354 361
355 if self._tests: 362 if self._tests:
356 for test in self._tests: 363 for test in self._tests:
357 self._RebaselineOneTest(expectations_subdir=subdir, 364 self._RebaselineOneTest(expectations_subdir=subdir,
358 builder_name=builder_name, 365 builder_name=builder,
359 test=test, all_results=all_results) 366 test=test, all_results=all_results)
360 else: # get the raw list of files that need rebaselining from JSON 367 else: # get the raw list of files that need rebaselining from JSON
361 filenames = self._GetFilesToRebaseline(json_url=json_url, 368 filenames = self._GetFilesToRebaseline(json_url=json_url,
362 add_new=self._add_new) 369 add_new=self._add_new)
363 for filename in filenames: 370 for filename in filenames:
364 outfilename = os.path.join(subdir, filename); 371 outfilename = os.path.join(subdir, filename);
365 self._RebaselineOneFile(expectations_subdir=subdir, 372 self._RebaselineOneFile(expectations_subdir=subdir,
366 builder_name=builder_name, 373 builder_name=builder,
367 infilename=filename, 374 infilename=filename,
368 outfilename=outfilename, 375 outfilename=outfilename,
369 all_results=all_results) 376 all_results=all_results)
370 377
371 # main... 378 # main...
372 379
373 parser = argparse.ArgumentParser() 380 parser = argparse.ArgumentParser()
374 parser.add_argument('--add-new', action='store_true', 381 parser.add_argument('--add-new', action='store_true',
375 help='in addition to the standard behavior of ' + 382 help='in addition to the standard behavior of ' +
376 'updating expectations for failing tests, add ' + 383 'updating expectations for failing tests, add ' +
377 'expectations for tests which don\'t have expectations ' + 384 'expectations for tests which don\'t have expectations ' +
378 'yet.') 385 'yet.')
379 parser.add_argument('--configs', metavar='CONFIG', nargs='+', 386 parser.add_argument('--configs', metavar='CONFIG', nargs='+',
380 help='which configurations to rebaseline, e.g. ' + 387 help='which configurations to rebaseline, e.g. ' +
381 '"--configs 565 8888"; if unspecified, run a default ' + 388 '"--configs 565 8888"; if unspecified, run a default ' +
382 'set of configs. This should ONLY be specified if ' + 389 'set of configs. This should ONLY be specified if ' +
383 '--tests has also been specified.') 390 '--tests has also been specified.')
384 parser.add_argument('--dry-run', action='store_true', 391 parser.add_argument('--dry-run', action='store_true',
385 help='instead of actually downloading files or adding ' + 392 help='instead of actually downloading files or adding ' +
386 'files to checkout, display a list of operations that ' + 393 'files to checkout, display a list of operations that ' +
387 'we would normally perform') 394 'we would normally perform')
395 parser.add_argument('--expectations-root',
396 help='root of expectations directory to update-- should ' +
397 'contain one or more base-* subdirectories. Defaults to ' +
398 '%(default)s',
399 default='.')
388 parser.add_argument('--json-base-url', 400 parser.add_argument('--json-base-url',
389 help='base URL from which to read JSON_FILENAME ' + 401 help='base URL from which to read JSON_FILENAME ' +
390 'files; defaults to %(default)s', 402 'files; defaults to %(default)s',
391 default='http://skia-autogen.googlecode.com/svn/gm-actual') 403 default='http://skia-autogen.googlecode.com/svn/gm-actual')
392 parser.add_argument('--json-filename', 404 parser.add_argument('--json-filename',
393 help='filename (under JSON_BASE_URL) to read a summary ' + 405 help='filename (under JSON_BASE_URL) to read a summary ' +
394 'of results from; defaults to %(default)s', 406 'of results from; defaults to %(default)s',
395 default='actual-results.json') 407 default='actual-results.json')
396 parser.add_argument('--subdirs', metavar='SUBDIR', nargs='+', 408 parser.add_argument('--subdirs', metavar='SUBDIR', nargs='+',
397 help='which platform subdirectories to rebaseline; ' + 409 help='which platform subdirectories to rebaseline; ' +
398 'if unspecified, rebaseline all subdirs, same as ' + 410 'if unspecified, rebaseline all subdirs, same as ' +
399 '"--subdirs %s"' % ' '.join(sorted(SUBDIR_MAPPING.keys()))) 411 '"--subdirs %s"' % ' '.join(sorted(SUBDIR_MAPPING.keys())))
400 parser.add_argument('--tests', metavar='TEST', nargs='+', 412 parser.add_argument('--tests', metavar='TEST', nargs='+',
401 help='which tests to rebaseline, e.g. ' + 413 help='which tests to rebaseline, e.g. ' +
402 '"--tests aaclip bigmatrix"; if unspecified, then all ' + 414 '"--tests aaclip bigmatrix"; if unspecified, then all ' +
403 'failing tests (according to the actual-results.json ' + 415 'failing tests (according to the actual-results.json ' +
404 'file) will be rebaselined.') 416 'file) will be rebaselined.')
405 args = parser.parse_args() 417 args = parser.parse_args()
406 rebaseliner = Rebaseliner(tests=args.tests, configs=args.configs, 418 if args.subdirs:
407 subdirs=args.subdirs, dry_run=args.dry_run, 419 subdirs = args.subdirs
408 json_base_url=args.json_base_url, 420 missing_json_is_fatal = True
409 json_filename=args.json_filename, 421 else:
410 add_new=args.add_new) 422 subdirs = sorted(SUBDIR_MAPPING.keys())
411 rebaseliner.RebaselineAll() 423 missing_json_is_fatal = False
424 for subdir in subdirs:
425 if not subdir in SUBDIR_MAPPING.keys():
426 raise Exception(('unrecognized platform subdir "%s"; ' +
427 'should be one of %s') % (
428 subdir, SUBDIR_MAPPING.keys()))
429 builder = SUBDIR_MAPPING[subdir]
430
431 # We instantiate different Rebaseliner objects depending
432 # on whether we are rebaselining an expected-results.json file, or
433 # individual image files. Different gm-expected subdirectories may move
434 # from individual image files to JSON-format expectations at different
435 # times, so we need to make this determination per subdirectory.
436 #
437 # See https://goto.google.com/ChecksumTransitionDetail
438 expectations_json_file = os.path.join(args.expectations_root, subdir,
439 JSON_EXPECTATIONS_FILENAME)
440 if os.path.isfile(expectations_json_file):
441 sys.stderr.write('ERROR: JsonRebaseliner is not implemented yet.\n')
442 sys.exit(1)
443 rebaseliner = JsonRebaseliner(
444 expectations_root=args.expectations_root,
445 tests=args.tests, configs=args.configs,
446 dry_run=args.dry_run,
447 json_base_url=args.json_base_url,
448 json_filename=args.json_filename,
449 add_new=args.add_new,
450 missing_json_is_fatal=missing_json_is_fatal)
451 else:
452 rebaseliner = rebaseline_imagefiles.ImageRebaseliner(
453 expectations_root=args.expectations_root,
454 tests=args.tests, configs=args.configs,
455 dry_run=args.dry_run,
456 json_base_url=args.json_base_url,
457 json_filename=args.json_filename,
458 add_new=args.add_new,
459 missing_json_is_fatal=missing_json_is_fatal)
460 rebaseliner.RebaselineSubdir(subdir=subdir, builder=builder)
OLDNEW
« no previous file with comments | « no previous file | tools/rebaseline_imagefiles.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698