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

Side by Side Diff: webkit/tools/layout_tests/rebaseline.py

Issue 345008: Modify rebaseline tool to work with git and add vista rebaseline... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 11 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 | 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/env python 1 #!/usr/bin/env python
2 # Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. 2 # Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be 3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file. 4 # found in the LICENSE file.
5 5
6 """Rebaselining tool that automatically produces baselines for all platforms. 6 """Rebaselining tool that automatically produces baselines for all platforms.
7 7
8 The script does the following for each platform specified: 8 The script does the following for each platform specified:
9 1. Compile a list of tests that need rebaselining. 9 1. Compile a list of tests that need rebaselining.
10 2. Download test result archive from buildbot for the platform. 10 2. Download test result archive from buildbot for the platform.
(...skipping 17 matching lines...) Expand all
28 import time 28 import time
29 import urllib 29 import urllib
30 import webbrowser 30 import webbrowser
31 import zipfile 31 import zipfile
32 32
33 from layout_package import path_utils 33 from layout_package import path_utils
34 from layout_package import test_expectations 34 from layout_package import test_expectations
35 from test_types import image_diff 35 from test_types import image_diff
36 from test_types import text_diff 36 from test_types import text_diff
37 37
38 # Repository type constants.
39 REPO_SVN, REPO_UNKNOWN = range(2)
40
38 BASELINE_SUFFIXES = ['.txt', '.png', '.checksum'] 41 BASELINE_SUFFIXES = ['.txt', '.png', '.checksum']
39 REBASELINE_PLATFORM_ORDER = ['mac', 'win', 'win-xp', 'linux'] 42 REBASELINE_PLATFORM_ORDER = ['mac', 'win', 'win-xp', 'win-vista', 'linux']
40 ARCHIVE_DIR_NAME_DICT = {'win': 'webkit-rel', 43 ARCHIVE_DIR_NAME_DICT = {'win': 'webkit-rel',
41 'win-vista': 'webkit-dbg-vista', 44 'win-vista': 'webkit-dbg-vista',
42 'win-xp': 'webkit-rel', 45 'win-xp': 'webkit-rel',
43 'mac': 'webkit-rel-mac5', 46 'mac': 'webkit-rel-mac5',
44 'linux': 'webkit-rel-linux', 47 'linux': 'webkit-rel-linux',
45 'win-canary': 'webkit-rel-webkit-org', 48 'win-canary': 'webkit-rel-webkit-org',
46 'win-vista-canary': 'webkit-dbg-vista', 49 'win-vista-canary': 'webkit-dbg-vista',
47 'win-xp-canary': 'webkit-rel-webkit-org', 50 'win-xp-canary': 'webkit-rel-webkit-org',
48 'mac-canary': 'webkit-rel-mac-webkit-org', 51 'mac-canary': 'webkit-rel-mac-webkit-org',
49 'linux-canary': 'webkit-rel-linux-webkit-org'} 52 'linux-canary': 'webkit-rel-linux-webkit-org'}
50 53
51 def RunShell(command, print_output=False): 54 def RunShellWithReturnCode(command, print_output=False):
52 """Executes a command and returns the output. 55 """Executes a command and returns the output and process return code.
53 56
54 Args: 57 Args:
55 command: program and arguments. 58 command: program and arguments.
56 print_output: if true, print the command results to standard output. 59 print_output: if true, print the command results to standard output.
57 60
58 Returns: 61 Returns:
59 command output 62 command output, return code
60 """ 63 """
61 64
62 # Use a shell for subcommands on Windows to get a PATH search. 65 # Use a shell for subcommands on Windows to get a PATH search.
63 use_shell = sys.platform.startswith('win') 66 use_shell = sys.platform.startswith('win')
64 p = subprocess.Popen(command, stdout=subprocess.PIPE, 67 p = subprocess.Popen(command, stdout=subprocess.PIPE,
65 stderr=subprocess.STDOUT, shell=use_shell) 68 stderr=subprocess.STDOUT, shell=use_shell)
66 if print_output: 69 if print_output:
67 output_array = [] 70 output_array = []
68 while True: 71 while True:
69 line = p.stdout.readline() 72 line = p.stdout.readline()
70 if not line: 73 if not line:
71 break 74 break
72 if print_output: 75 if print_output:
73 print line.strip('\n') 76 print line.strip('\n')
74 output_array.append(line) 77 output_array.append(line)
75 output = ''.join(output_array) 78 output = ''.join(output_array)
76 else: 79 else:
77 output = p.stdout.read() 80 output = p.stdout.read()
78 p.wait() 81 p.wait()
79 p.stdout.close() 82 p.stdout.close()
83
84 return output, p.returncode
85
86 def RunShell(command, print_output=False):
87 """Executes a command and returns the output.
88
89 Args:
90 command: program and arguments.
91 print_output: if true, print the command results to standard output.
92
93 Returns:
94 command output
95 """
96
97 output, return_code = RunShellWithReturnCode(command, print_output)
80 return output 98 return output
81 99
82
83 def LogDashedString(text, platform, logging_level=logging.INFO): 100 def LogDashedString(text, platform, logging_level=logging.INFO):
84 """Log text message with dashes on both sides.""" 101 """Log text message with dashes on both sides."""
85 102
86 msg = text 103 msg = text
87 if platform: 104 if platform:
88 msg += ': ' + platform 105 msg += ': ' + platform
89 if len(msg) < 78: 106 if len(msg) < 78:
90 dashes = '-' * ((78 - len(msg)) / 2) 107 dashes = '-' * ((78 - len(msg)) / 2)
91 msg = '%s %s %s' % (dashes, msg, dashes) 108 msg = '%s %s %s' % (dashes, msg, dashes)
92 109
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
165 182
166 # Create tests and expectations helper which is used to: 183 # Create tests and expectations helper which is used to:
167 # -. compile list of tests that need rebaselining. 184 # -. compile list of tests that need rebaselining.
168 # -. update the tests in test_expectations file after rebaseline is done. 185 # -. update the tests in test_expectations file after rebaseline is done.
169 self._test_expectations = test_expectations.TestExpectations(None, 186 self._test_expectations = test_expectations.TestExpectations(None,
170 self._file_dir, 187 self._file_dir,
171 platform, 188 platform,
172 False, 189 False,
173 False) 190 False)
174 191
192 self._repo_type = self._GetRepoType()
193
175 def Run(self, backup): 194 def Run(self, backup):
176 """Run rebaseline process.""" 195 """Run rebaseline process."""
177 196
178 LogDashedString('Compiling rebaselining tests', self._platform) 197 LogDashedString('Compiling rebaselining tests', self._platform)
179 if not self._CompileRebaseliningTests(): 198 if not self._CompileRebaseliningTests():
180 return True 199 return True
181 200
182 LogDashedString('Downloading archive', self._platform) 201 LogDashedString('Downloading archive', self._platform)
183 archive_file = self._DownloadBuildBotArchive() 202 archive_file = self._DownloadBuildBotArchive()
184 logging.info('') 203 logging.info('')
(...skipping 19 matching lines...) Expand all
204 return False 223 return False
205 224
206 logging.warning('All tests needing rebaselining were successfully ' 225 logging.warning('All tests needing rebaselining were successfully '
207 'rebaselined.') 226 'rebaselined.')
208 227
209 return True 228 return True
210 229
211 def GetRebaseliningTests(self): 230 def GetRebaseliningTests(self):
212 return self._rebaselining_tests 231 return self._rebaselining_tests
213 232
233 def _GetRepoType(self):
234 """Get the repository type that client is using."""
235
236 output, return_code = RunShellWithReturnCode(['svn', 'info'], False)
237 if return_code == 0:
238 return REPO_SVN
239
240 return REPO_UNKNOWN
241
214 def _CompileRebaseliningTests(self): 242 def _CompileRebaseliningTests(self):
215 """Compile list of tests that need rebaselining for the platform. 243 """Compile list of tests that need rebaselining for the platform.
216 244
217 Returns: 245 Returns:
218 List of tests that need rebaselining or 246 List of tests that need rebaselining or
219 None if there is no such test. 247 None if there is no such test.
220 """ 248 """
221 249
222 self._rebaselining_tests = self._test_expectations.GetRebaseliningFailures() 250 self._rebaselining_tests = self._test_expectations.GetRebaseliningFailures()
223 if not self._rebaselining_tests: 251 if not self._rebaselining_tests:
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after
354 test_basename, 382 test_basename,
355 suffix) 383 suffix)
356 logging.debug(' Archive test file name: "%s"', archive_test_name) 384 logging.debug(' Archive test file name: "%s"', archive_test_name)
357 if not archive_test_name in zip_namelist: 385 if not archive_test_name in zip_namelist:
358 logging.info(' %s file not in archive.', suffix) 386 logging.info(' %s file not in archive.', suffix)
359 continue 387 continue
360 388
361 found = True 389 found = True
362 logging.info(' %s file found in archive.', suffix) 390 logging.info(' %s file found in archive.', suffix)
363 391
392 # Extract new baseline from archive and save it to a temp file.
393 data = zip_file.read(archive_test_name)
394 temp_fd, temp_name = tempfile.mkstemp(suffix)
395 f = os.fdopen(temp_fd, 'wb')
396 f.write(data)
397 f.close()
398
364 expected_filename = '%s-expected%s' % (test_basename, suffix) 399 expected_filename = '%s-expected%s' % (test_basename, suffix)
365 expected_fullpath = os.path.join( 400 expected_fullpath = os.path.join(
366 path_utils.ChromiumBaselinePath(platform), expected_filename) 401 path_utils.ChromiumBaselinePath(platform), expected_filename)
367 expected_fullpath = os.path.normpath(expected_fullpath) 402 expected_fullpath = os.path.normpath(expected_fullpath)
368 logging.debug(' Expected file full path: "%s"', expected_fullpath) 403 logging.debug(' Expected file full path: "%s"', expected_fullpath)
369 404
370 data = zip_file.read(archive_test_name) 405 # TODO(victorw): for now, the rebaselining tool checks whether
406 # or not THIS baseline is duplicate and should be skipped.
407 # We could improve the tool to check all baselines in upper and lower
408 # levels and remove all duplicated baselines.
409 if self._IsDupBaseline(temp_name,
410 expected_fullpath,
411 test,
412 suffix,
413 self._platform):
414 os.remove(temp_name)
415 self._DeleteBaseline(expected_fullpath)
416 continue
371 417
372 # Create the new baseline directory if it doesn't already exist. 418 # Create the new baseline directory if it doesn't already exist.
373 path_utils.MaybeMakeDirectory(os.path.dirname(expected_fullpath)) 419 path_utils.MaybeMakeDirectory(os.path.dirname(expected_fullpath))
374 420
375 f = open(expected_fullpath, 'wb') 421 shutil.move(temp_name, expected_fullpath)
376 f.write(data)
377 f.close()
378
379 # TODO(victorw): for now, the rebaselining tool checks whether
380 # or not THIS baseline is duplicate and should be skipped.
381 # We could improve the tool to check all baselines in upper and lower
382 # levels and remove all duplicated baselines.
383 if self._IsDupBaseline(expected_fullpath, test, suffix, self._platform):
384 # Clean up the duplicate baseline.
385 self._DeleteBaseline(expected_fullpath)
386 continue
387 422
388 if not self._SvnAdd(expected_fullpath): 423 if not self._SvnAdd(expected_fullpath):
389 svn_error = True 424 svn_error = True
390 elif suffix != '.checksum': 425 elif suffix != '.checksum':
391 self._CreateHtmlBaselineFiles(expected_fullpath) 426 self._CreateHtmlBaselineFiles(expected_fullpath)
392 427
393 if not found: 428 if not found:
394 logging.warn(' No new baselines found in archive.') 429 logging.warn(' No new baselines found in archive.')
395 else: 430 else:
396 if svn_error: 431 if svn_error:
397 logging.warn(' Failed to add baselines to SVN.') 432 logging.warn(' Failed to add baselines to SVN.')
398 else: 433 else:
399 logging.info(' Rebaseline succeeded.') 434 logging.info(' Rebaseline succeeded.')
400 self._rebaselined_tests.append(test) 435 self._rebaselined_tests.append(test)
401 436
402 test_no += 1 437 test_no += 1
403 438
404 zip_file.close() 439 zip_file.close()
405 os.remove(archive_file) 440 os.remove(archive_file)
406 441
407 return self._rebaselined_tests 442 return self._rebaselined_tests
408 443
409 def _IsDupBaseline(self, baseline_path, test, suffix, platform): 444 def _IsDupBaseline(self, new_baseline, baseline_path, test, suffix, platform):
410 """Check whether a baseline is duplicate and can fallback to same 445 """Check whether a baseline is duplicate and can fallback to same
411 baseline for another platform. For example, if a test has same baseline 446 baseline for another platform. For example, if a test has same baseline
412 on linux and windows, then we only store windows baseline and linux 447 on linux and windows, then we only store windows baseline and linux
413 baseline will fallback to the windows version. 448 baseline will fallback to the windows version.
414 449
415 Args: 450 Args:
416 expected_filename: baseline expectation file name. 451 expected_filename: baseline expectation file name.
417 test: test name. 452 test: test name.
418 suffix: file suffix of the expected results, including dot; e.g. '.txt' 453 suffix: file suffix of the expected results, including dot; e.g. '.txt'
419 or '.png'. 454 or '.png'.
420 platform: baseline platform 'mac', 'win' or 'linux'. 455 platform: baseline platform 'mac', 'win' or 'linux'.
421 456
422 Returns: 457 Returns:
423 True if the baseline is unnecessary. 458 True if the baseline is unnecessary.
424 False otherwise. 459 False otherwise.
425 """ 460 """
426 test_filepath = os.path.join(path_utils.LayoutTestsDir(), test) 461 test_filepath = os.path.join(path_utils.LayoutTestsDir(), test)
427 all_baselines = path_utils.ExpectedBaseline(test_filepath, 462 all_baselines = path_utils.ExpectedBaseline(test_filepath,
428 suffix, 463 suffix,
429 platform, 464 platform,
430 True) 465 True)
431 for (fallback_dir, fallback_file) in all_baselines: 466 for (fallback_dir, fallback_file) in all_baselines:
432 if fallback_dir and fallback_file: 467 if fallback_dir and fallback_file:
433 fallback_fullpath = os.path.normpath( 468 fallback_fullpath = os.path.normpath(
434 os.path.join(fallback_dir, fallback_file)) 469 os.path.join(fallback_dir, fallback_file))
435 if fallback_fullpath.lower() != baseline_path.lower(): 470 if fallback_fullpath.lower() != baseline_path.lower():
436 if not self._DiffBaselines(baseline_path, fallback_fullpath): 471 if not self._DiffBaselines(new_baseline, fallback_fullpath):
437 logging.info(' Found same baseline at %s', fallback_fullpath) 472 logging.info(' Found same baseline at %s', fallback_fullpath)
438 return True 473 return True
439 else: 474 else:
440 return False 475 return False
441 476
442 return False 477 return False
443 478
444 def _DiffBaselines(self, file1, file2): 479 def _DiffBaselines(self, file1, file2):
445 """Check whether two baselines are different. 480 """Check whether two baselines are different.
446 481
(...skipping 13 matching lines...) Expand all
460 return True 495 return True
461 496
462 if ext1 == '.PNG': 497 if ext1 == '.PNG':
463 return image_diff.ImageDiff(self._platform, '').DiffFiles(file1, 498 return image_diff.ImageDiff(self._platform, '').DiffFiles(file1,
464 file2) 499 file2)
465 else: 500 else:
466 return text_diff.TestTextDiff(self._platform, '').DiffFiles(file1, 501 return text_diff.TestTextDiff(self._platform, '').DiffFiles(file1,
467 file2) 502 file2)
468 503
469 def _DeleteBaseline(self, filename): 504 def _DeleteBaseline(self, filename):
470 """Remove the file from SVN repository and delete it from disk. 505 """Remove the file from repository and delete it from disk.
471 506
472 Args: 507 Args:
473 filename: full path of the file to delete. 508 filename: full path of the file to delete.
474 """ 509 """
475 510
476 if not filename: 511 if not filename or not os.path.isfile(filename):
477 return 512 return
478 513
479 parent_dir, basename = os.path.split(filename) 514 if self._repo_type == REPO_SVN:
480 original_dir = os.getcwd() 515 parent_dir, basename = os.path.split(filename)
481 os.chdir(parent_dir) 516 original_dir = os.getcwd()
482 status_output = RunShell(['svn', 'delete', '--force', basename], False) 517 os.chdir(parent_dir)
483 os.chdir(original_dir) 518 RunShell(['svn', 'delete', '--force', basename], False)
519 os.chdir(original_dir)
520 else:
521 os.remove(filename)
484 522
485 def _UpdateRebaselinedTestsInFile(self, backup): 523 def _UpdateRebaselinedTestsInFile(self, backup):
486 """Update the rebaselined tests in test expectations file. 524 """Update the rebaselined tests in test expectations file.
487 525
488 Args: 526 Args:
489 backup: if True, backup the original test expectations file. 527 backup: if True, backup the original test expectations file.
490 528
491 Returns: 529 Returns:
492 no 530 no
493 """ 531 """
(...skipping 13 matching lines...) Expand all
507 545
508 Returns: 546 Returns:
509 True if the file already exists in SVN or is sucessfully added to SVN. 547 True if the file already exists in SVN or is sucessfully added to SVN.
510 False otherwise. 548 False otherwise.
511 """ 549 """
512 550
513 if not filename: 551 if not filename:
514 return False 552 return False
515 553
516 parent_dir, basename = os.path.split(filename) 554 parent_dir, basename = os.path.split(filename)
517 if parent_dir == filename: 555 if self._repo_type != REPO_SVN or parent_dir == filename:
518 logging.info("No svn checkout found. Assuming it's a git repo and not " 556 logging.info("No svn checkout found, skip svn add.")
519 "adding")
520 return True 557 return True
521 558
522 original_dir = os.getcwd() 559 original_dir = os.getcwd()
523 os.chdir(parent_dir) 560 os.chdir(parent_dir)
524 status_output = RunShell(['svn', 'status', basename], False) 561 status_output = RunShell(['svn', 'status', basename], False)
525 os.chdir(original_dir) 562 os.chdir(original_dir)
526 output = status_output.upper() 563 output = status_output.upper()
527 if output.startswith('A') or output.startswith('M'): 564 if output.startswith('A') or output.startswith('M'):
528 logging.info(' File already added to SVN: "%s"', filename) 565 logging.info(' File already added to SVN: "%s"', filename)
529 return True 566 return True
(...skipping 328 matching lines...) Expand 10 before | Expand all | Expand 10 after
858 def main(): 895 def main():
859 """Main function to produce new baselines.""" 896 """Main function to produce new baselines."""
860 897
861 option_parser = optparse.OptionParser() 898 option_parser = optparse.OptionParser()
862 option_parser.add_option('-v', '--verbose', 899 option_parser.add_option('-v', '--verbose',
863 action='store_true', 900 action='store_true',
864 default=False, 901 default=False,
865 help='include debug-level logging.') 902 help='include debug-level logging.')
866 903
867 option_parser.add_option('-p', '--platforms', 904 option_parser.add_option('-p', '--platforms',
868 default='mac,win,win-xp,linux', 905 default='mac,win,win-xp,win-vista,linux',
869 help=('Comma delimited list of platforms that need ' 906 help=('Comma delimited list of platforms that need '
870 'rebaselining.')) 907 'rebaselining.'))
871 908
872 option_parser.add_option('-u', '--archive_url', 909 option_parser.add_option('-u', '--archive_url',
873 default=('http://build.chromium.org/buildbot/' 910 default=('http://build.chromium.org/buildbot/'
874 'layout_test_results'), 911 'layout_test_results'),
875 help=('Url to find the layout test result archive ' 912 help=('Url to find the layout test result archive '
876 'file.')) 913 'file.'))
877 914
878 option_parser.add_option('-t', '--archive_name', 915 option_parser.add_option('-t', '--archive_name',
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after
972 rebaseline_platforms, 1009 rebaseline_platforms,
973 rebaselining_tests) 1010 rebaselining_tests)
974 html_generator.GenerateHtml() 1011 html_generator.GenerateHtml()
975 html_generator.ShowHtml() 1012 html_generator.ShowHtml()
976 LogDashedString('Rebaselining result comparison done', None) 1013 LogDashedString('Rebaselining result comparison done', None)
977 1014
978 sys.exit(0) 1015 sys.exit(0)
979 1016
980 if '__main__' == __name__: 1017 if '__main__' == __name__:
981 main() 1018 main()
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