OLD | NEW |
---|---|
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 159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
170 # Currently, there is no way to make this script mark | 170 # Currently, there is no way to make this script mark |
171 # expectations as reviewed-by-human=True. | 171 # expectations as reviewed-by-human=True. |
172 # TODO(epoger): Add that capability to a review tool. | 172 # TODO(epoger): Add that capability to a review tool. |
173 # mark_ignore_failure: if True, mark failures of a given test as being | 173 # mark_ignore_failure: if True, mark failures of a given test as being |
174 # ignored. | 174 # ignored. |
175 def __init__(self, expectations_root, expectations_input_filename, | 175 def __init__(self, expectations_root, expectations_input_filename, |
176 expectations_output_filename, actuals_base_url, | 176 expectations_output_filename, actuals_base_url, |
177 actuals_filename, exception_handler, | 177 actuals_filename, exception_handler, |
178 tests=None, configs=None, add_new=False, bugs=None, notes=None, | 178 tests=None, configs=None, add_new=False, bugs=None, notes=None, |
179 mark_unreviewed=None, mark_ignore_failure=False, | 179 mark_unreviewed=None, mark_ignore_failure=False, |
180 from_trybot=False): | 180 from_trybot=False, skip_pattern_matching=False): |
epoger
2013/10/10 15:05:09
please update the docstring above
scroggo
2013/10/10 19:32:36
Done.
| |
181 self._expectations_root = expectations_root | 181 self._expectations_root = expectations_root |
182 self._expectations_input_filename = expectations_input_filename | 182 self._expectations_input_filename = expectations_input_filename |
183 self._expectations_output_filename = expectations_output_filename | 183 self._expectations_output_filename = expectations_output_filename |
184 self._tests = tests | 184 self._tests = tests |
185 self._configs = configs | 185 self._configs = configs |
186 self._actuals_base_url = actuals_base_url | 186 self._actuals_base_url = actuals_base_url |
187 self._actuals_filename = actuals_filename | 187 self._actuals_filename = actuals_filename |
188 self._exception_handler = exception_handler | 188 self._exception_handler = exception_handler |
189 self._add_new = add_new | 189 self._add_new = add_new |
190 self._bugs = bugs | 190 self._bugs = bugs |
191 self._notes = notes | 191 self._notes = notes |
192 self._mark_unreviewed = mark_unreviewed | 192 self._mark_unreviewed = mark_unreviewed |
193 self._mark_ignore_failure = mark_ignore_failure; | 193 self._mark_ignore_failure = mark_ignore_failure; |
194 self._image_filename_re = re.compile(gm_json.IMAGE_FILENAME_PATTERN) | 194 # TODO(scroggo): This is a hack. Since the filenames will not match |
195 # the pattern in skimage, we skip the pattern matching entirely. | |
196 if skip_pattern_matching: | |
197 self._image_filename_re = None | |
198 else: | |
199 self._image_filename_re = re.compile(gm_json.IMAGE_FILENAME_PATTERN) | |
195 self._using_svn = os.path.isdir(os.path.join(expectations_root, '.svn')) | 200 self._using_svn = os.path.isdir(os.path.join(expectations_root, '.svn')) |
196 self._from_trybot = from_trybot | 201 self._from_trybot = from_trybot |
197 | 202 |
198 # Executes subprocess.call(cmd). | 203 # Executes subprocess.call(cmd). |
199 # Raises an Exception if the command fails. | 204 # Raises an Exception if the command fails. |
200 def _Call(self, cmd): | 205 def _Call(self, cmd): |
201 if subprocess.call(cmd) != 0: | 206 if subprocess.call(cmd) != 0: |
202 raise _InternalException('error running command: ' + ' '.join(cmd)) | 207 raise _InternalException('error running command: ' + ' '.join(cmd)) |
203 | 208 |
204 # Returns the full contents of filepath, as a single string. | 209 # Returns the full contents of filepath, as a single string. |
205 # If filepath looks like a URL, try to read it that way instead of as | 210 # If filepath looks like a URL, try to read it that way instead of as |
206 # a path on local storage. | 211 # a path on local storage. |
207 # | 212 # |
208 # Raises _InternalException if there is a problem. | 213 # Raises _InternalException if there is a problem. |
209 def _GetFileContents(self, filepath): | 214 def _GetFileContents(self, filepath): |
210 if filepath.startswith('http:') or filepath.startswith('https:'): | 215 if filepath.startswith('http:') or filepath.startswith('https:'): |
211 try: | 216 try: |
212 return urllib2.urlopen(filepath).read() | 217 return urllib2.urlopen(filepath).read() |
213 except urllib2.HTTPError as e: | 218 except urllib2.HTTPError as e: |
214 raise _InternalException('unable to read URL %s: %s' % ( | 219 raise _InternalException('unable to read URL %s: %s' % ( |
215 filepath, e)) | 220 filepath, e)) |
221 elif filepath.startswith('gs:'): | |
epoger
2013/10/10 15:05:09
As discussed live: I think it's better to download
scroggo
2013/10/10 19:32:36
Done.
| |
222 try: | |
223 return subprocess.check_output(['gsutil', 'cat', filepath]) | |
224 except subprocess.CalledProcessError: | |
225 raise _InternalException('unable to read Google Storage URL %s: %s' % ( | |
226 filepath, e)) | |
216 else: | 227 else: |
217 return open(filepath, 'r').read() | 228 return open(filepath, 'r').read() |
218 | 229 |
219 # Returns a dictionary of actual results from actual-results.json file. | 230 # Returns a dictionary of actual results from actual-results.json file. |
220 # | 231 # |
221 # The dictionary returned has this format: | 232 # The dictionary returned has this format: |
222 # { | 233 # { |
223 # u'imageblur_565.png': [u'bitmap-64bitMD5', 3359963596899141322], | 234 # u'imageblur_565.png': [u'bitmap-64bitMD5', 3359963596899141322], |
224 # u'imageblur_8888.png': [u'bitmap-64bitMD5', 4217923806027861152], | 235 # u'imageblur_8888.png': [u'bitmap-64bitMD5', 4217923806027861152], |
225 # u'shadertext3_8888.png': [u'bitmap-64bitMD5', 3713708307125704716] | 236 # u'shadertext3_8888.png': [u'bitmap-64bitMD5', 3713708307125704716] |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
286 expected_results = expectations_dict.get(gm_json.JSONKEY_EXPECTEDRESULTS) | 297 expected_results = expectations_dict.get(gm_json.JSONKEY_EXPECTEDRESULTS) |
287 if not expected_results: | 298 if not expected_results: |
288 expected_results = {} | 299 expected_results = {} |
289 expectations_dict[gm_json.JSONKEY_EXPECTEDRESULTS] = expected_results | 300 expectations_dict[gm_json.JSONKEY_EXPECTEDRESULTS] = expected_results |
290 | 301 |
291 # Update the expectations in memory, skipping any tests/configs that | 302 # Update the expectations in memory, skipping any tests/configs that |
292 # the caller asked to exclude. | 303 # the caller asked to exclude. |
293 skipped_images = [] | 304 skipped_images = [] |
294 if results_to_update: | 305 if results_to_update: |
295 for (image_name, image_results) in results_to_update.iteritems(): | 306 for (image_name, image_results) in results_to_update.iteritems(): |
296 (test, config) = self._image_filename_re.match(image_name).groups() | 307 if self._image_filename_re: |
297 if self._tests: | 308 (test, config) = self._image_filename_re.match(image_name).groups() |
298 if test not in self._tests: | 309 if self._tests: |
299 skipped_images.append(image_name) | 310 if test not in self._tests: |
300 continue | 311 skipped_images.append(image_name) |
301 if self._configs: | 312 continue |
302 if config not in self._configs: | 313 if self._configs: |
303 skipped_images.append(image_name) | 314 if config not in self._configs: |
304 continue | 315 skipped_images.append(image_name) |
316 continue | |
305 if not expected_results.get(image_name): | 317 if not expected_results.get(image_name): |
306 expected_results[image_name] = {} | 318 expected_results[image_name] = {} |
307 expected_results[image_name]\ | 319 expected_results[image_name]\ |
308 [gm_json.JSONKEY_EXPECTEDRESULTS_ALLOWEDDIGESTS]\ | 320 [gm_json.JSONKEY_EXPECTEDRESULTS_ALLOWEDDIGESTS]\ |
309 = [image_results] | 321 = [image_results] |
310 if self._mark_unreviewed: | 322 if self._mark_unreviewed: |
311 expected_results[image_name]\ | 323 expected_results[image_name]\ |
312 [gm_json.JSONKEY_EXPECTEDRESULTS_REVIEWED]\ | 324 [gm_json.JSONKEY_EXPECTEDRESULTS_REVIEWED]\ |
313 = False | 325 = False |
314 if self._mark_ignore_failure: | 326 if self._mark_ignore_failure: |
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
407 help=('mark all expectations modified by this run as ' | 419 help=('mark all expectations modified by this run as ' |
408 '"%s": False' % | 420 '"%s": False' % |
409 gm_json.JSONKEY_EXPECTEDRESULTS_REVIEWED)) | 421 gm_json.JSONKEY_EXPECTEDRESULTS_REVIEWED)) |
410 parser.add_argument('--ignore-failure', action='store_true', | 422 parser.add_argument('--ignore-failure', action='store_true', |
411 help=('mark all expectations modified by this run as ' | 423 help=('mark all expectations modified by this run as ' |
412 '"%s": True' % | 424 '"%s": True' % |
413 gm_json.JSONKEY_ACTUALRESULTS_FAILUREIGNORED)) | 425 gm_json.JSONKEY_ACTUALRESULTS_FAILUREIGNORED)) |
414 parser.add_argument('--from-trybot', action='store_true', | 426 parser.add_argument('--from-trybot', action='store_true', |
415 help=('pull the actual-results.json file from the ' | 427 help=('pull the actual-results.json file from the ' |
416 'corresponding trybot, rather than the main builder')) | 428 'corresponding trybot, rather than the main builder')) |
429 parser.add_argument('--skimage', action='store_true', | |
430 help=('Rebaseline skimage results instead of gm. Defaults ' | |
431 'to False.')) | |
417 args = parser.parse_args() | 432 args = parser.parse_args() |
418 exception_handler = ExceptionHandler( | 433 exception_handler = ExceptionHandler( |
419 keep_going_on_failure=args.keep_going_on_failure) | 434 keep_going_on_failure=args.keep_going_on_failure) |
420 if args.builders: | 435 if args.builders: |
421 builders = args.builders | 436 builders = args.builders |
422 missing_json_is_fatal = True | 437 missing_json_is_fatal = True |
423 else: | 438 else: |
424 builders = sorted(TEST_BUILDERS) | 439 builders = sorted(TEST_BUILDERS) |
425 missing_json_is_fatal = False | 440 missing_json_is_fatal = False |
441 if args.skimage: | |
442 # Hardcode variables for skimage. | |
443 args.actuals_base_url = 'gs://chromium-skia-gm/skimage/actuals' | |
epoger
2013/10/10 15:05:09
I think it will be surprising that these args are
scroggo
2013/10/10 19:32:36
Done, for --tests and --configs.
| |
444 args.expectations_root = os.path.join('expectations', 'skimage') | |
426 for builder in builders: | 445 for builder in builders: |
427 if not builder in TEST_BUILDERS: | 446 if not builder in TEST_BUILDERS: |
428 raise Exception(('unrecognized builder "%s"; ' + | 447 raise Exception(('unrecognized builder "%s"; ' + |
429 'should be one of %s') % ( | 448 'should be one of %s') % ( |
430 builder, TEST_BUILDERS)) | 449 builder, TEST_BUILDERS)) |
431 | 450 |
432 expectations_json_file = os.path.join(args.expectations_root, builder, | 451 expectations_json_file = os.path.join(args.expectations_root, builder, |
433 args.expectations_filename) | 452 args.expectations_filename) |
434 if os.path.isfile(expectations_json_file): | 453 if os.path.isfile(expectations_json_file): |
435 rebaseliner = JsonRebaseliner( | 454 rebaseliner = JsonRebaseliner( |
436 expectations_root=args.expectations_root, | 455 expectations_root=args.expectations_root, |
437 expectations_input_filename=args.expectations_filename, | 456 expectations_input_filename=args.expectations_filename, |
438 expectations_output_filename=(args.expectations_filename_output or | 457 expectations_output_filename=(args.expectations_filename_output or |
439 args.expectations_filename), | 458 args.expectations_filename), |
440 tests=args.tests, configs=args.configs, | 459 tests=args.tests, configs=args.configs, |
441 actuals_base_url=args.actuals_base_url, | 460 actuals_base_url=args.actuals_base_url, |
442 actuals_filename=args.actuals_filename, | 461 actuals_filename=args.actuals_filename, |
443 exception_handler=exception_handler, | 462 exception_handler=exception_handler, |
444 add_new=args.add_new, bugs=args.bugs, notes=args.notes, | 463 add_new=args.add_new, bugs=args.bugs, notes=args.notes, |
445 mark_unreviewed=args.unreviewed, | 464 mark_unreviewed=args.unreviewed, |
446 mark_ignore_failure=args.ignore_failure, | 465 mark_ignore_failure=args.ignore_failure, |
447 from_trybot=args.from_trybot) | 466 from_trybot=args.from_trybot, |
467 skip_pattern_matching=args.skimage) | |
448 try: | 468 try: |
449 rebaseliner.RebaselineSubdir(builder=builder) | 469 rebaseliner.RebaselineSubdir(builder=builder) |
450 except: | 470 except: |
451 exception_handler.RaiseExceptionOrContinue() | 471 exception_handler.RaiseExceptionOrContinue() |
452 else: | 472 else: |
453 try: | 473 try: |
454 raise _InternalException('expectations_json_file %s not found' % | 474 raise _InternalException('expectations_json_file %s not found' % |
455 expectations_json_file) | 475 expectations_json_file) |
456 except: | 476 except: |
457 exception_handler.RaiseExceptionOrContinue() | 477 exception_handler.RaiseExceptionOrContinue() |
458 | 478 |
459 exception_handler.ReportAllFailures() | 479 exception_handler.ReportAllFailures() |
OLD | NEW |