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

Side by Side Diff: third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline.py

Issue 2380533003: Revert of In rebaseline.py, update SCM and expectations all at once after all commands. (Closed)
Patch Set: Rebase revert patch Created 4 years, 2 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
OLDNEW
1 # Copyright (c) 2010 Google Inc. All rights reserved. 1 # Copyright (c) 2010 Google Inc. All rights reserved.
2 # 2 #
3 # Redistribution and use in source and binary forms, with or without 3 # Redistribution and use in source and binary forms, with or without
4 # modification, are permitted provided that the following conditions are 4 # modification, are permitted provided that the following conditions are
5 # met: 5 # met:
6 # 6 #
7 # * Redistributions of source code must retain the above copyright 7 # * Redistributions of source code must retain the above copyright
8 # notice, this list of conditions and the following disclaimer. 8 # notice, this list of conditions and the following disclaimer.
9 # * Redistributions in binary form must reproduce the above 9 # * Redistributions in binary form must reproduce the above
10 # copyright notice, this list of conditions and the following disclaimer 10 # copyright notice, this list of conditions and the following disclaimer
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
80 The reason for keeping track of these changes together is that after rebasel ining 80 The reason for keeping track of these changes together is that after rebasel ining
81 many tests in parallel by subprocesses, we can update the git staged files l ist 81 many tests in parallel by subprocesses, we can update the git staged files l ist
82 and the TestExpectations all at once at the end. 82 and the TestExpectations all at once at the end.
83 83
84 Each subprocess can communicate some set of changes by outputting JSON lines , 84 Each subprocess can communicate some set of changes by outputting JSON lines ,
85 and another process can aggregate the changes. 85 and another process can aggregate the changes.
86 86
87 TODO(qyearsley): Refactor this so that lines to remove are only tracked in o ne format. 87 TODO(qyearsley): Refactor this so that lines to remove are only tracked in o ne format.
88 """ 88 """
89 def __init__(self, files_to_add=None, files_to_delete=None, lines_to_remove= None): 89 def __init__(self, files_to_add=None, files_to_delete=None, lines_to_remove= None):
90 self._files_to_add = set(files_to_add or []) 90 self.files_to_add = files_to_add or []
91 self._files_to_delete = set(files_to_delete or []) 91 self.files_to_delete = files_to_delete or []
92 lines_to_remove = lines_to_remove or {} 92 self.lines_to_remove = lines_to_remove or {}
93 self._lines_to_remove = {t: set(builders) for t, builders in lines_to_re move.iteritems()}
94 93
95 def add_file(self, path): 94 def add_file(self, path):
96 self._files_to_add.add(path) 95 self.files_to_add.append(path)
97 96
98 def delete_file(self, path): 97 def delete_file(self, path):
99 self._files_to_delete.add(path) 98 self.files_to_delete.append(path)
100 99
101 def remove_line(self, test, builder): 100 def remove_line(self, test, builder):
102 if test not in self._lines_to_remove: 101 if test not in self.lines_to_remove:
103 self._lines_to_remove[test] = set() 102 self.lines_to_remove[test] = []
104 self._lines_to_remove[test].add(builder) 103 self.lines_to_remove[test].append(builder)
105
106 @property
107 def files_to_add(self):
108 return sorted(self._files_to_add - self._files_to_delete)
109
110 @property
111 def files_to_delete(self):
112 return sorted(self._files_to_delete - self._files_to_add)
113
114 @property
115 def lines_to_remove(self):
116 return {t: sorted(set(builders)) for t, builders in sorted(self._lines_t o_remove.iteritems())}
117 104
118 def to_dict(self): 105 def to_dict(self):
119 remove_lines = [] 106 remove_lines = []
120 for test in sorted(self.lines_to_remove): 107 for test in self.lines_to_remove:
121 for builder in sorted(set(self.lines_to_remove[test])): 108 for builder in self.lines_to_remove[test]:
122 remove_lines.append({'test': test, 'builder': builder}) 109 remove_lines.append({'test': test, 'builder': builder})
123 return { 110 return {
124 'add': self.files_to_add, 111 'add': list(self.files_to_add),
125 'delete': self.files_to_delete, 112 'delete': list(self.files_to_delete),
126 'remove-lines': remove_lines, 113 'remove-lines': remove_lines,
127 } 114 }
128 115
129 @staticmethod 116 @staticmethod
130 def from_dict(change_dict): 117 def from_dict(change_dict):
131 files_to_add = set() 118 files_to_add = set()
132 files_to_delete = set() 119 files_to_delete = set()
133 lines_to_remove = {} 120 lines_to_remove = {}
134 if 'add' in change_dict: 121 if 'add' in change_dict:
135 files_to_add.update(change_dict['add']) 122 files_to_add.update(change_dict['add'])
136 if 'delete' in change_dict: 123 if 'delete' in change_dict:
137 files_to_delete.update(change_dict['delete']) 124 files_to_delete.update(change_dict['delete'])
138 if 'remove-lines' in change_dict: 125 if 'remove-lines' in change_dict:
139 for line_to_remove in change_dict['remove-lines']: 126 for line_to_remove in change_dict['remove-lines']:
140 test = line_to_remove['test'] 127 test = line_to_remove['test']
141 builder = line_to_remove['builder'] 128 builder = line_to_remove['builder']
142 if test not in lines_to_remove: 129 if test not in lines_to_remove:
143 lines_to_remove[test] = [] 130 lines_to_remove[test] = []
144 lines_to_remove[test].append(builder) 131 lines_to_remove[test].append(builder)
145 return ChangeSet( 132 return ChangeSet(
146 files_to_add=files_to_add, 133 files_to_add=list(files_to_add),
147 files_to_delete=files_to_delete, 134 files_to_delete=list(files_to_delete),
148 lines_to_remove=lines_to_remove) 135 lines_to_remove=lines_to_remove)
149 136
150 def update(self, other): 137 def update(self, other):
151 assert isinstance(other, ChangeSet) 138 assert isinstance(other, ChangeSet)
152 self._files_to_add.update(other.files_to_add) 139 assert type(other.lines_to_remove) is dict
153 self._files_to_delete.update(other.files_to_delete) 140 self.files_to_add.extend(other.files_to_add)
141 self.files_to_delete.extend(other.files_to_delete)
154 for test in other.lines_to_remove: 142 for test in other.lines_to_remove:
155 if test not in self._lines_to_remove: 143 if test not in self.lines_to_remove:
156 self._lines_to_remove[test] = set() 144 self.lines_to_remove[test] = []
157 self._lines_to_remove[test].update(other.lines_to_remove[test]) 145 self.lines_to_remove[test].extend(other.lines_to_remove[test])
158 146
159 147
160 class BaseInternalRebaselineCommand(AbstractRebaseliningCommand): 148 class BaseInternalRebaselineCommand(AbstractRebaseliningCommand):
161 """Base class for rebaseline-related commands that are intended to be used b y other commands.""" 149 """Base class for rebaseline-related commands that are intended to be used b y other commands."""
162 # Not overriding execute() - pylint: disable=abstract-method 150 # Not overriding execute() - pylint: disable=abstract-method
163 151
164 def __init__(self): 152 def __init__(self):
165 super(BaseInternalRebaselineCommand, self).__init__(options=[ 153 super(BaseInternalRebaselineCommand, self).__init__(options=[
166 self.results_directory_option, 154 self.results_directory_option,
167 self.suffixes_option, 155 self.suffixes_option,
(...skipping 324 matching lines...) Expand 10 before | Expand all | Expand 10 after
492 def _port_skips_test(port, test, generic_expectations, full_expectations): 480 def _port_skips_test(port, test, generic_expectations, full_expectations):
493 fs = port.host.filesystem 481 fs = port.host.filesystem
494 if port.default_smoke_test_only(): 482 if port.default_smoke_test_only():
495 smoke_test_filename = fs.join(port.layout_tests_dir(), 'SmokeTests') 483 smoke_test_filename = fs.join(port.layout_tests_dir(), 'SmokeTests')
496 if fs.exists(smoke_test_filename) and test not in fs.read_text_file( smoke_test_filename): 484 if fs.exists(smoke_test_filename) and test not in fs.read_text_file( smoke_test_filename):
497 return True 485 return True
498 486
499 return (SKIP in full_expectations.get_expectations(test) and 487 return (SKIP in full_expectations.get_expectations(test) and
500 SKIP not in generic_expectations.get_expectations(test)) 488 SKIP not in generic_expectations.get_expectations(test))
501 489
502 def _run_in_parallel(self, commands): 490 def _run_in_parallel(self, commands, update_scm=True):
503 if not commands: 491 if not commands:
504 return ChangeSet() 492 return {}
505 493
506 command_results = self._tool.executive.run_in_parallel(commands) 494 command_results = self._tool.executive.run_in_parallel(commands)
507 for _, _, stderr in command_results: 495 for _, _, stderr in command_results:
508 if stderr: 496 if stderr:
509 _log.error(stderr) 497 _log.error(stderr)
510 498
511 return self._extract_scm_changes(command_results) 499 change_set = self._extract_scm_changes(command_results)
512 500
513 def _rebaseline(self, options, test_prefix_list): 501 # TODO(qyearsley): Instead of updating the SCM state here, aggregate cha nges
502 # and update once in _rebaseline. See http://crbug.com/639410.
503 if update_scm:
504 if change_set.files_to_delete:
505 self._tool.scm().delete_list(change_set.files_to_delete)
506 if change_set.files_to_add:
507 self._tool.scm().add_list(change_set.files_to_add)
508
509 return change_set.lines_to_remove
510
511 def _rebaseline(self, options, test_prefix_list, update_scm=True):
514 """Downloads new baselines in parallel, then updates expectations files 512 """Downloads new baselines in parallel, then updates expectations files
515 and optimizes baselines. 513 and optimizes baselines.
516 514
517 Args: 515 Args:
518 options: An object with the options passed to the current command. 516 options: An object with the options passed to the current command.
519 test_prefix_list: A map of test names to Build objects to file suffi xes 517 test_prefix_list: A map of test names to Build objects to file suffi xes
520 for new baselines. For example: 518 for new baselines. For example:
521 { 519 {
522 "some/test.html": {Build("builder-1", 412): ["txt"], Build(" builder-2", 100): ["txt"]}, 520 "some/test.html": {Build("builder-1", 412): ["txt"], Build(" builder-2", 100): ["txt"]},
523 "some/other.html": {Build("builder-1", 412): ["txt"]} 521 "some/other.html": {Build("builder-1", 412): ["txt"]}
524 } 522 }
525 This would mean that new text baselines should be downloaded for 523 This would mean that new text baselines should be downloaded for
526 "some/test.html" on both builder-1 (build 412) and builder-2 524 "some/test.html" on both builder-1 (build 412) and builder-2
527 (build 100), and new text baselines should be downloaded for 525 (build 100), and new text baselines should be downloaded for
528 "some/other.html" but only from builder-1. 526 "some/other.html" but only from builder-1.
529 TODO(qyearsley): Replace test_prefix_list everywhere with some 527 TODO(qyearsley): Replace test_prefix_list everywhere with some
530 sort of class that contains the same data. 528 sort of class that contains the same data.
529 update_scm: If True, commands like `git add` and `git rm` will be ru n.
531 """ 530 """
532 for test, builds_to_check in sorted(test_prefix_list.items()): 531 for test, builds_to_check in sorted(test_prefix_list.items()):
533 _log.info("Rebaselining %s", test) 532 _log.info("Rebaselining %s", test)
534 for build, suffixes in sorted(builds_to_check.items()): 533 for build, suffixes in sorted(builds_to_check.items()):
535 _log.debug(" %s: %s", build, ",".join(suffixes)) 534 _log.debug(" %s: %s", build, ",".join(suffixes))
536 535
537 copy_baseline_commands, rebaseline_commands, extra_lines_to_remove = sel f._rebaseline_commands( 536 copy_baseline_commands, rebaseline_commands, extra_lines_to_remove = sel f._rebaseline_commands(
538 test_prefix_list, options) 537 test_prefix_list, options)
538 lines_to_remove = {}
539 539
540 change_set = ChangeSet(lines_to_remove=extra_lines_to_remove) 540 self._run_in_parallel(copy_baseline_commands, update_scm=update_scm)
541 lines_to_remove = self._run_in_parallel(rebaseline_commands, update_scm= update_scm)
541 542
542 change_set.update(self._run_in_parallel(copy_baseline_commands)) 543 for test in extra_lines_to_remove:
543 change_set.update(self._run_in_parallel(rebaseline_commands)) 544 if test in lines_to_remove:
545 lines_to_remove[test] = lines_to_remove[test] + extra_lines_to_r emove[test]
546 else:
547 lines_to_remove[test] = extra_lines_to_remove[test]
544 548
545 if change_set.lines_to_remove: 549 if lines_to_remove:
546 self._update_expectations_files(change_set.lines_to_remove) 550 self._update_expectations_files(lines_to_remove)
547 551
548 if options.optimize: 552 if options.optimize:
549 # TODO(wkorman): Consider changing temporary branch to base off of H EAD rather than 553 # TODO(wkorman): Consider changing temporary branch to base off of H EAD rather than
550 # origin/master to ensure we run baseline optimization processes wit h the same code as 554 # origin/master to ensure we run baseline optimization processes wit h the same code as
551 # auto-rebaseline itself. 555 # auto-rebaseline itself.
552 change_set.update(self._run_in_parallel(self._optimize_baselines(tes t_prefix_list, options.verbose))) 556 self._run_in_parallel(self._optimize_baselines(test_prefix_list, opt ions.verbose), update_scm=update_scm)
553
554 if change_set.files_to_delete:
555 self._tool.scm().delete_list(change_set.files_to_delete)
556 if change_set.files_to_add:
557 self._tool.scm().add_list(change_set.files_to_add)
558 557
559 def _suffixes_for_actual_failures(self, test, build, existing_suffixes): 558 def _suffixes_for_actual_failures(self, test, build, existing_suffixes):
560 """Gets the baseline suffixes for actual mismatch failures in some resul ts. 559 """Gets the baseline suffixes for actual mismatch failures in some resul ts.
561 560
562 Args: 561 Args:
563 test: A full test path string. 562 test: A full test path string.
564 build: A Build object. 563 build: A Build object.
565 existing_suffixes: A collection of all suffixes to consider. 564 existing_suffixes: A collection of all suffixes to consider.
566 565
567 Returns: 566 Returns:
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after
684 for test in args: 683 for test in args:
685 if test not in test_prefix_list: 684 if test not in test_prefix_list:
686 test_prefix_list[test] = {} 685 test_prefix_list[test] = {}
687 build = Build(builder) 686 build = Build(builder)
688 test_prefix_list[test][build] = suffixes_to_update 687 test_prefix_list[test][build] = suffixes_to_update
689 688
690 if options.verbose: 689 if options.verbose:
691 _log.debug("rebaseline-json: " + str(test_prefix_list)) 690 _log.debug("rebaseline-json: " + str(test_prefix_list))
692 691
693 self._rebaseline(options, test_prefix_list) 692 self._rebaseline(options, test_prefix_list)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698