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

Side by Side Diff: tools/rebaseline.py

Issue 19805007: rebaseline.py: add ability to write new expectations to a different file (Closed) Base URL: http://skia.googlecode.com/svn/trunk/
Patch Set: Created 7 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 | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | 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 105 matching lines...) Expand 10 before | Expand all | Expand 10 after
116 print >> sys.stderr, ('Encountered %d failures (see above).' % 116 print >> sys.stderr, ('Encountered %d failures (see above).' %
117 len(self._failures_encountered)) 117 len(self._failures_encountered))
118 self._Exit() 118 self._Exit()
119 119
120 120
121 # Object that rebaselines a JSON expectations file (not individual image files). 121 # Object that rebaselines a JSON expectations file (not individual image files).
122 class JsonRebaseliner(object): 122 class JsonRebaseliner(object):
123 123
124 # params: 124 # params:
125 # expectations_root: root directory of all expectations JSON files 125 # expectations_root: root directory of all expectations JSON files
126 # expectations_filename: filename (under expectations_root) of JSON 126 # expectations_input_filename: filename (under expectations_root) of JSON
127 # expectations file; typically 127 # expectations file to read; typically
128 # "expected-results.json" 128 # "expected-results.json"
129 # expectations_output_filename: filename (under expectations_root) to
130 # which updated expectations should be
131 # written; typically the same as
132 # expectations_input_filename, to overwrite
133 # the old content
129 # actuals_base_url: base URL from which to read actual-result JSON files 134 # actuals_base_url: base URL from which to read actual-result JSON files
130 # actuals_filename: filename (under actuals_base_url) from which to read a 135 # actuals_filename: filename (under actuals_base_url) from which to read a
131 # summary of results; typically "actual-results.json" 136 # summary of results; typically "actual-results.json"
132 # exception_handler: reference to rebaseline.ExceptionHandler object 137 # exception_handler: reference to rebaseline.ExceptionHandler object
133 # tests: list of tests to rebaseline, or None if we should rebaseline 138 # tests: list of tests to rebaseline, or None if we should rebaseline
134 # whatever files the JSON results summary file tells us to 139 # whatever files the JSON results summary file tells us to
135 # configs: which configs to run for each test, or None if we should 140 # configs: which configs to run for each test, or None if we should
136 # rebaseline whatever configs the JSON results summary file tells 141 # rebaseline whatever configs the JSON results summary file tells
137 # us to 142 # us to
138 # add_new: if True, add expectations for tests which don't have any yet 143 # add_new: if True, add expectations for tests which don't have any yet
139 def __init__(self, expectations_root, expectations_filename, 144 def __init__(self, expectations_root, expectations_input_filename,
140 actuals_base_url, actuals_filename, exception_handler, 145 expectations_output_filename, actuals_base_url,
146 actuals_filename, exception_handler,
141 tests=None, configs=None, add_new=False): 147 tests=None, configs=None, add_new=False):
142 self._expectations_root = expectations_root 148 self._expectations_root = expectations_root
143 self._expectations_filename = expectations_filename 149 self._expectations_input_filename = expectations_input_filename
150 self._expectations_output_filename = expectations_output_filename
144 self._tests = tests 151 self._tests = tests
145 self._configs = configs 152 self._configs = configs
146 self._actuals_base_url = actuals_base_url 153 self._actuals_base_url = actuals_base_url
147 self._actuals_filename = actuals_filename 154 self._actuals_filename = actuals_filename
148 self._exception_handler = exception_handler 155 self._exception_handler = exception_handler
149 self._add_new = add_new 156 self._add_new = add_new
150 self._image_filename_re = re.compile(gm_json.IMAGE_FILENAME_PATTERN) 157 self._image_filename_re = re.compile(gm_json.IMAGE_FILENAME_PATTERN)
151 self._using_svn = os.path.isdir(os.path.join(expectations_root, '.svn')) 158 self._using_svn = os.path.isdir(os.path.join(expectations_root, '.svn'))
152 159
153 # Executes subprocess.call(cmd). 160 # Executes subprocess.call(cmd).
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
226 # succeeding, but including the SUCCEEDED results will allow us to 233 # succeeding, but including the SUCCEEDED results will allow us to
227 # re-record expectations if they somehow get out of sync. 234 # re-record expectations if they somehow get out of sync.
228 sections = [gm_json.JSONKEY_ACTUALRESULTS_FAILED, 235 sections = [gm_json.JSONKEY_ACTUALRESULTS_FAILED,
229 gm_json.JSONKEY_ACTUALRESULTS_SUCCEEDED] 236 gm_json.JSONKEY_ACTUALRESULTS_SUCCEEDED]
230 if self._add_new: 237 if self._add_new:
231 sections.append(gm_json.JSONKEY_ACTUALRESULTS_NOCOMPARISON) 238 sections.append(gm_json.JSONKEY_ACTUALRESULTS_NOCOMPARISON)
232 results_to_update = self._GetActualResults(json_url=actuals_url, 239 results_to_update = self._GetActualResults(json_url=actuals_url,
233 sections=sections) 240 sections=sections)
234 241
235 # Read in current expectations. 242 # Read in current expectations.
236 expectations_json_filepath = os.path.join( 243 expectations_input_filepath = os.path.join(
237 self._expectations_root, subdir, self._expectations_filename) 244 self._expectations_root, subdir, self._expectations_input_filename)
238 expectations_dict = gm_json.LoadFromFile(expectations_json_filepath) 245 expectations_dict = gm_json.LoadFromFile(expectations_input_filepath)
239 expected_results = expectations_dict[gm_json.JSONKEY_EXPECTEDRESULTS] 246 expected_results = expectations_dict[gm_json.JSONKEY_EXPECTEDRESULTS]
240 247
241 # Update the expectations in memory, skipping any tests/configs that 248 # Update the expectations in memory, skipping any tests/configs that
242 # the caller asked to exclude. 249 # the caller asked to exclude.
243 skipped_images = [] 250 skipped_images = []
244 if results_to_update: 251 if results_to_update:
245 for (image_name, image_results) in results_to_update.iteritems(): 252 for (image_name, image_results) in results_to_update.iteritems():
246 (test, config) = \ 253 (test, config) = \
247 self._image_filename_re.match(image_name).groups() 254 self._image_filename_re.match(image_name).groups()
248 if self._tests: 255 if self._tests:
249 if test not in self._tests: 256 if test not in self._tests:
250 skipped_images.append(image_name) 257 skipped_images.append(image_name)
251 continue 258 continue
252 if self._configs: 259 if self._configs:
253 if config not in self._configs: 260 if config not in self._configs:
254 skipped_images.append(image_name) 261 skipped_images.append(image_name)
255 continue 262 continue
256 if not expected_results.get(image_name): 263 if not expected_results.get(image_name):
257 expected_results[image_name] = {} 264 expected_results[image_name] = {}
258 expected_results[image_name] \ 265 expected_results[image_name] \
259 [gm_json.JSONKEY_EXPECTEDRESULTS_ALLOWEDDIGESTS] = \ 266 [gm_json.JSONKEY_EXPECTEDRESULTS_ALLOWEDDIGESTS] = \
260 [image_results] 267 [image_results]
261 268
262 # Write out updated expectations. 269 # Write out updated expectations.
263 gm_json.WriteToFile(expectations_dict, expectations_json_filepath) 270 expectations_output_filepath = os.path.join(
271 self._expectations_root, subdir, self._expectations_output_filename)
272 gm_json.WriteToFile(expectations_dict, expectations_output_filepath)
264 273
265 # Mark the JSON file as plaintext, so text-style diffs can be applied. 274 # Mark the JSON file as plaintext, so text-style diffs can be applied.
266 # Fixes https://code.google.com/p/skia/issues/detail?id=1442 275 # Fixes https://code.google.com/p/skia/issues/detail?id=1442
267 if self._using_svn: 276 if self._using_svn:
268 self._Call(['svn', 'propset', '--quiet', 'svn:mime-type', 277 self._Call(['svn', 'propset', '--quiet', 'svn:mime-type',
269 'text/x-json', expectations_json_filepath]) 278 'text/x-json', expectations_output_filepath])
270 279
271 # main... 280 # main...
272 281
273 parser = argparse.ArgumentParser() 282 parser = argparse.ArgumentParser()
274 parser.add_argument('--actuals-base-url', 283 parser.add_argument('--actuals-base-url',
275 help='base URL from which to read files containing JSON ' + 284 help='base URL from which to read files containing JSON ' +
276 'summaries of actual GM results; defaults to %(default)s', 285 'summaries of actual GM results; defaults to %(default)s',
277 default='http://skia-autogen.googlecode.com/svn/gm-actual') 286 default='http://skia-autogen.googlecode.com/svn/gm-actual')
278 parser.add_argument('--actuals-filename', 287 parser.add_argument('--actuals-filename',
279 help='filename (within platform-specific subdirectories ' + 288 help='filename (within platform-specific subdirectories ' +
(...skipping 14 matching lines...) Expand all
294 '*all* configs that are available.') 303 '*all* configs that are available.')
295 # TODO(epoger): The --dry-run argument will no longer be needed once we 304 # TODO(epoger): The --dry-run argument will no longer be needed once we
296 # are only rebaselining JSON files. 305 # are only rebaselining JSON files.
297 parser.add_argument('--dry-run', action='store_true', 306 parser.add_argument('--dry-run', action='store_true',
298 help='instead of actually downloading files or adding ' + 307 help='instead of actually downloading files or adding ' +
299 'files to checkout, display a list of operations that ' + 308 'files to checkout, display a list of operations that ' +
300 'we would normally perform') 309 'we would normally perform')
301 parser.add_argument('--expectations-filename', 310 parser.add_argument('--expectations-filename',
302 help='filename (under EXPECTATIONS_ROOT) to read ' + 311 help='filename (under EXPECTATIONS_ROOT) to read ' +
303 'current expectations from, and to write new ' + 312 'current expectations from, and to write new ' +
304 'expectations into; defaults to %(default)s', 313 'expectations into (unless a separate ' +
314 'EXPECTATIONS_FILENAME_OUTPUT has been specified); ' +
315 'defaults to %(default)s',
305 default='expected-results.json') 316 default='expected-results.json')
317 parser.add_argument('--expectations-filename-output',
epoger 2013/07/24 19:31:34 Here's what this section of the --help output look
318 help='filename (under EXPECTATIONS_ROOT) to write ' +
319 'updated expectations into; by default, overwrites the ' +
320 'input file (EXPECTATIONS_FILENAME)',
321 default='')
306 parser.add_argument('--expectations-root', 322 parser.add_argument('--expectations-root',
307 help='root of expectations directory to update-- should ' + 323 help='root of expectations directory to update-- should ' +
308 'contain one or more base-* subdirectories. Defaults to ' + 324 'contain one or more base-* subdirectories. Defaults to ' +
309 '%(default)s', 325 '%(default)s',
310 default=os.path.join('expectations', 'gm')) 326 default=os.path.join('expectations', 'gm'))
311 parser.add_argument('--keep-going-on-failure', action='store_true', 327 parser.add_argument('--keep-going-on-failure', action='store_true',
312 help='instead of halting at the first error encountered, ' + 328 help='instead of halting at the first error encountered, ' +
313 'keep going and rebaseline as many tests as possible, ' + 329 'keep going and rebaseline as many tests as possible, ' +
314 'and then report the full set of errors at the end') 330 'and then report the full set of errors at the end')
315 parser.add_argument('--subdirs', metavar='SUBDIR', nargs='+', 331 parser.add_argument('--subdirs', metavar='SUBDIR', nargs='+',
(...skipping 27 matching lines...) Expand all
343 # individual image files. Different expectations/gm subdirectories may move 359 # individual image files. Different expectations/gm subdirectories may move
344 # from individual image files to JSON-format expectations at different 360 # from individual image files to JSON-format expectations at different
345 # times, so we need to make this determination per subdirectory. 361 # times, so we need to make this determination per subdirectory.
346 # 362 #
347 # See https://goto.google.com/ChecksumTransitionDetail 363 # See https://goto.google.com/ChecksumTransitionDetail
348 expectations_json_file = os.path.join(args.expectations_root, subdir, 364 expectations_json_file = os.path.join(args.expectations_root, subdir,
349 args.expectations_filename) 365 args.expectations_filename)
350 if os.path.isfile(expectations_json_file): 366 if os.path.isfile(expectations_json_file):
351 rebaseliner = JsonRebaseliner( 367 rebaseliner = JsonRebaseliner(
352 expectations_root=args.expectations_root, 368 expectations_root=args.expectations_root,
353 expectations_filename=args.expectations_filename, 369 expectations_input_filename=args.expectations_filename,
370 expectations_output_filename=(args.expectations_filename_output or
371 args.expectations_filename),
354 tests=args.tests, configs=args.configs, 372 tests=args.tests, configs=args.configs,
355 actuals_base_url=args.actuals_base_url, 373 actuals_base_url=args.actuals_base_url,
356 actuals_filename=args.actuals_filename, 374 actuals_filename=args.actuals_filename,
357 exception_handler=exception_handler, 375 exception_handler=exception_handler,
358 add_new=args.add_new) 376 add_new=args.add_new)
359 else: 377 else:
360 # TODO(epoger): When we get rid of the ImageRebaseliner implementation, 378 # TODO(epoger): When we get rid of the ImageRebaseliner implementation,
361 # we should raise an Exception in this case (no JSON expectations file 379 # we should raise an Exception in this case (no JSON expectations file
362 # found to update), to prevent a recurrence of 380 # found to update), to prevent a recurrence of
363 # https://code.google.com/p/skia/issues/detail?id=1403 ('rebaseline.py 381 # https://code.google.com/p/skia/issues/detail?id=1403 ('rebaseline.py
364 # script fails with misleading output when run outside of gm-expected 382 # script fails with misleading output when run outside of gm-expected
365 # dir') 383 # dir')
366 rebaseliner = rebaseline_imagefiles.ImageRebaseliner( 384 rebaseliner = rebaseline_imagefiles.ImageRebaseliner(
367 expectations_root=args.expectations_root, 385 expectations_root=args.expectations_root,
368 tests=args.tests, configs=args.configs, 386 tests=args.tests, configs=args.configs,
369 dry_run=args.dry_run, 387 dry_run=args.dry_run,
370 json_base_url=args.actuals_base_url, 388 json_base_url=args.actuals_base_url,
371 json_filename=args.actuals_filename, 389 json_filename=args.actuals_filename,
372 exception_handler=exception_handler, 390 exception_handler=exception_handler,
373 add_new=args.add_new, 391 add_new=args.add_new,
374 missing_json_is_fatal=missing_json_is_fatal) 392 missing_json_is_fatal=missing_json_is_fatal)
375 393
376 try: 394 try:
377 rebaseliner.RebaselineSubdir(subdir=subdir, builder=builder) 395 rebaseliner.RebaselineSubdir(subdir=subdir, builder=builder)
378 except BaseException as e: 396 except BaseException as e:
379 exception_handler.RaiseExceptionOrContinue(e) 397 exception_handler.RaiseExceptionOrContinue(e)
380 398
381 exception_handler.ReportAllFailures() 399 exception_handler.ReportAllFailures()
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698