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

Side by Side Diff: tools/rebaseline.py

Issue 18092004: rebaseline.py: add --keep-going-on-failure option, off by default (Closed) Base URL: http://skia.googlecode.com/svn/trunk/
Patch Set: linewrap Created 7 years, 5 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 '''
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
67 'base-android-nexus-10': 67 'base-android-nexus-10':
68 'Test-Android-Nexus10-MaliT604-Arm7-Release', 68 'Test-Android-Nexus10-MaliT604-Arm7-Release',
69 'base-android-nexus-4': 69 'base-android-nexus-4':
70 'Test-Android-Nexus4-Adreno320-Arm7-Release', 70 'Test-Android-Nexus4-Adreno320-Arm7-Release',
71 } 71 }
72 72
73 73
74 class _InternalException(Exception): 74 class _InternalException(Exception):
75 pass 75 pass
76 76
77 # Object that handles exceptions, either raising them immediately or collecting
78 # them to display later on.
79 class ExceptionHandler(object):
80
81 # params:
82 # keep_going_on_failure: if False, report failures and quit right away;
83 # if True, collect failures until
84 # ReportAllFailures() is called
85 def __init__(self, keep_going_on_failure=False):
86 self._keep_going_on_failure = keep_going_on_failure
87 self._failures_encountered = []
88 self._exiting = False
89
90 # Exit the program with the given status value.
91 def _Exit(self, status=1):
92 self._exiting = True
93 sys.exit(status)
94
95 # We have encountered an exception; either collect the info and keep going,
96 # or exit the program right away.
97 def RaiseExceptionOrContinue(self, e):
98 # If we are already quitting the program, propagate any exceptions
99 # so that the proper exit status will be communicated to the shell.
100 if self._exiting:
101 raise e
102
103 if self._keep_going_on_failure:
104 print >> sys.stderr, 'WARNING: swallowing exception %s' % e
105 self._failures_encountered.append(e)
106 else:
107 print >> sys.stderr, e
108 print >> sys.stderr, (
109 'Halting at first exception; to keep going, re-run ' +
110 'with the --keep-going-on-failure option set.')
111 self._Exit()
112
113 def ReportAllFailures(self):
114 if self._failures_encountered:
115 print >> sys.stderr, ('Encountered %d failures (see above).' %
116 len(self._failures_encountered))
117 self._Exit()
118
119
77 # Object that rebaselines a JSON expectations file (not individual image files). 120 # Object that rebaselines a JSON expectations file (not individual image files).
78 class JsonRebaseliner(object): 121 class JsonRebaseliner(object):
79 122
80 # params: 123 # params:
81 # expectations_root: root directory of all expectations JSON files 124 # expectations_root: root directory of all expectations JSON files
82 # expectations_filename: filename (under expectations_root) of JSON 125 # expectations_filename: filename (under expectations_root) of JSON
83 # expectations file; typically 126 # expectations file; typically
84 # "expected-results.json" 127 # "expected-results.json"
85 # actuals_base_url: base URL from which to read actual-result JSON files 128 # actuals_base_url: base URL from which to read actual-result JSON files
86 # actuals_filename: filename (under actuals_base_url) from which to read a 129 # actuals_filename: filename (under actuals_base_url) from which to read a
87 # summary of results; typically "actual-results.json" 130 # summary of results; typically "actual-results.json"
131 # exception_handler: reference to rebaseline.ExceptionHandler object
88 # tests: list of tests to rebaseline, or None if we should rebaseline 132 # tests: list of tests to rebaseline, or None if we should rebaseline
89 # whatever files the JSON results summary file tells us to 133 # whatever files the JSON results summary file tells us to
90 # configs: which configs to run for each test, or None if we should 134 # configs: which configs to run for each test, or None if we should
91 # rebaseline whatever configs the JSON results summary file tells 135 # rebaseline whatever configs the JSON results summary file tells
92 # us to 136 # us to
93 # add_new: if True, add expectations for tests which don't have any yet 137 # add_new: if True, add expectations for tests which don't have any yet
94 def __init__(self, expectations_root, expectations_filename, 138 def __init__(self, expectations_root, expectations_filename,
95 actuals_base_url, actuals_filename, 139 actuals_base_url, actuals_filename, exception_handler,
96 tests=None, configs=None, add_new=False): 140 tests=None, configs=None, add_new=False):
97 self._expectations_root = expectations_root 141 self._expectations_root = expectations_root
98 self._expectations_filename = expectations_filename 142 self._expectations_filename = expectations_filename
99 self._tests = tests 143 self._tests = tests
100 self._configs = configs 144 self._configs = configs
101 self._actuals_base_url = actuals_base_url 145 self._actuals_base_url = actuals_base_url
102 self._actuals_filename = actuals_filename 146 self._actuals_filename = actuals_filename
147 self._exception_handler = exception_handler
103 self._add_new = add_new 148 self._add_new = add_new
104 self._testname_pattern = re.compile('(\S+)_(\S+).png') 149 self._testname_pattern = re.compile('(\S+)_(\S+).png')
105 150
106 # Returns the full contents of filepath, as a single string. 151 # Returns the full contents of filepath, as a single string.
107 # If filepath looks like a URL, try to read it that way instead of as 152 # If filepath looks like a URL, try to read it that way instead of as
108 # a path on local storage. 153 # a path on local storage.
109 # 154 #
110 # Raises _InternalException if there is a problem. 155 # Raises _InternalException if there is a problem.
111 def _GetFileContents(self, filepath): 156 def _GetFileContents(self, filepath):
112 if filepath.startswith('http:') or filepath.startswith('https:'): 157 if filepath.startswith('http:') or filepath.startswith('https:'):
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after
236 parser.add_argument('--expectations-filename', 281 parser.add_argument('--expectations-filename',
237 help='filename (under EXPECTATIONS_ROOT) to read ' + 282 help='filename (under EXPECTATIONS_ROOT) to read ' +
238 'current expectations from, and to write new ' + 283 'current expectations from, and to write new ' +
239 'expectations into; defaults to %(default)s', 284 'expectations into; defaults to %(default)s',
240 default='expected-results.json') 285 default='expected-results.json')
241 parser.add_argument('--expectations-root', 286 parser.add_argument('--expectations-root',
242 help='root of expectations directory to update-- should ' + 287 help='root of expectations directory to update-- should ' +
243 'contain one or more base-* subdirectories. Defaults to ' + 288 'contain one or more base-* subdirectories. Defaults to ' +
244 '%(default)s', 289 '%(default)s',
245 default='.') 290 default='.')
291 parser.add_argument('--keep-going-on-failure', action='store_true',
292 help='instead of halting at the first error encountered, ' +
293 'keep going and rebaseline as many tests as possible, ' +
294 'and then report the full set of errors at the end')
246 parser.add_argument('--subdirs', metavar='SUBDIR', nargs='+', 295 parser.add_argument('--subdirs', metavar='SUBDIR', nargs='+',
247 help='which platform subdirectories to rebaseline; ' + 296 help='which platform subdirectories to rebaseline; ' +
248 'if unspecified, rebaseline all subdirs, same as ' + 297 'if unspecified, rebaseline all subdirs, same as ' +
249 '"--subdirs %s"' % ' '.join(sorted(SUBDIR_MAPPING.keys()))) 298 '"--subdirs %s"' % ' '.join(sorted(SUBDIR_MAPPING.keys())))
250 # TODO(epoger): Add test that exercises --tests argument. 299 # TODO(epoger): Add test that exercises --tests argument.
251 parser.add_argument('--tests', metavar='TEST', nargs='+', 300 parser.add_argument('--tests', metavar='TEST', nargs='+',
252 help='which tests to rebaseline, e.g. ' + 301 help='which tests to rebaseline, e.g. ' +
253 '"--tests aaclip bigmatrix", as a filter over the full ' + 302 '"--tests aaclip bigmatrix", as a filter over the full ' +
254 'set of results in ACTUALS_FILENAME; if unspecified, ' + 303 'set of results in ACTUALS_FILENAME; if unspecified, ' +
255 'rebaseline *all* tests that are available.') 304 'rebaseline *all* tests that are available.')
256 args = parser.parse_args() 305 args = parser.parse_args()
306 exception_handler = ExceptionHandler(
307 keep_going_on_failure=args.keep_going_on_failure)
257 if args.subdirs: 308 if args.subdirs:
258 subdirs = args.subdirs 309 subdirs = args.subdirs
259 missing_json_is_fatal = True 310 missing_json_is_fatal = True
260 else: 311 else:
261 subdirs = sorted(SUBDIR_MAPPING.keys()) 312 subdirs = sorted(SUBDIR_MAPPING.keys())
262 missing_json_is_fatal = False 313 missing_json_is_fatal = False
263 for subdir in subdirs: 314 for subdir in subdirs:
264 if not subdir in SUBDIR_MAPPING.keys(): 315 if not subdir in SUBDIR_MAPPING.keys():
265 raise Exception(('unrecognized platform subdir "%s"; ' + 316 raise Exception(('unrecognized platform subdir "%s"; ' +
266 'should be one of %s') % ( 317 'should be one of %s') % (
267 subdir, SUBDIR_MAPPING.keys())) 318 subdir, SUBDIR_MAPPING.keys()))
268 builder = SUBDIR_MAPPING[subdir] 319 builder = SUBDIR_MAPPING[subdir]
269 320
270 # We instantiate different Rebaseliner objects depending 321 # We instantiate different Rebaseliner objects depending
271 # on whether we are rebaselining an expected-results.json file, or 322 # on whether we are rebaselining an expected-results.json file, or
272 # individual image files. Different gm-expected subdirectories may move 323 # individual image files. Different gm-expected subdirectories may move
273 # from individual image files to JSON-format expectations at different 324 # from individual image files to JSON-format expectations at different
274 # times, so we need to make this determination per subdirectory. 325 # times, so we need to make this determination per subdirectory.
275 # 326 #
276 # See https://goto.google.com/ChecksumTransitionDetail 327 # See https://goto.google.com/ChecksumTransitionDetail
277 expectations_json_file = os.path.join(args.expectations_root, subdir, 328 expectations_json_file = os.path.join(args.expectations_root, subdir,
278 args.expectations_filename) 329 args.expectations_filename)
279 if os.path.isfile(expectations_json_file): 330 if os.path.isfile(expectations_json_file):
280 rebaseliner = JsonRebaseliner( 331 rebaseliner = JsonRebaseliner(
281 expectations_root=args.expectations_root, 332 expectations_root=args.expectations_root,
282 expectations_filename=args.expectations_filename, 333 expectations_filename=args.expectations_filename,
283 tests=args.tests, configs=args.configs, 334 tests=args.tests, configs=args.configs,
284 actuals_base_url=args.actuals_base_url, 335 actuals_base_url=args.actuals_base_url,
285 actuals_filename=args.actuals_filename, 336 actuals_filename=args.actuals_filename,
337 exception_handler=exception_handler,
286 add_new=args.add_new) 338 add_new=args.add_new)
287 else: 339 else:
288 # TODO(epoger): When we get rid of the ImageRebaseliner implementation, 340 # TODO(epoger): When we get rid of the ImageRebaseliner implementation,
289 # we should raise an Exception in this case (no JSON expectations file 341 # we should raise an Exception in this case (no JSON expectations file
290 # found to update), to prevent a recurrence of 342 # found to update), to prevent a recurrence of
291 # https://code.google.com/p/skia/issues/detail?id=1403 ('rebaseline.py 343 # https://code.google.com/p/skia/issues/detail?id=1403 ('rebaseline.py
292 # script fails with misleading output when run outside of gm-expected 344 # script fails with misleading output when run outside of gm-expected
293 # dir') 345 # dir')
294 rebaseliner = rebaseline_imagefiles.ImageRebaseliner( 346 rebaseliner = rebaseline_imagefiles.ImageRebaseliner(
295 expectations_root=args.expectations_root, 347 expectations_root=args.expectations_root,
296 tests=args.tests, configs=args.configs, 348 tests=args.tests, configs=args.configs,
297 dry_run=args.dry_run, 349 dry_run=args.dry_run,
298 json_base_url=args.actuals_base_url, 350 json_base_url=args.actuals_base_url,
299 json_filename=args.actuals_filename, 351 json_filename=args.actuals_filename,
352 exception_handler=exception_handler,
300 add_new=args.add_new, 353 add_new=args.add_new,
301 missing_json_is_fatal=missing_json_is_fatal) 354 missing_json_is_fatal=missing_json_is_fatal)
355
302 try: 356 try:
303 rebaseliner.RebaselineSubdir(subdir=subdir, builder=builder) 357 rebaseliner.RebaselineSubdir(subdir=subdir, builder=builder)
304 except BaseException as e: 358 except BaseException as e:
305 print >> sys.stderr, e 359 exception_handler.RaiseExceptionOrContinue(e)
306 sys.exit(1) 360
361 exception_handler.ReportAllFailures()
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