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

Side by Side Diff: tools/rebaseline.py

Issue 16363006: rebaseline.py: add --add-new option, and only add new expectations if it is set (Closed) Base URL: http://skia.googlecode.com/svn/trunk/
Patch Set: Created 7 years, 6 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/tests/rebaseline/output/all/output-expected/stdout » ('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 '''
11 Rebaselines the given GM tests, on all bots and all configurations. 11 Rebaselines the given GM tests, on all bots and all configurations.
12 Must be run from the gm-expected directory. If run from a git or SVN 12 Must be run from the gm-expected directory. If run from a git or SVN
13 checkout, the files will be added to the staging area for commit. 13 checkout, the files will be added to the staging area for commit.
14 ''' 14 '''
15 15
16 # System-level imports 16 # System-level imports
17 import argparse 17 import argparse
18 import os 18 import os
19 import subprocess 19 import subprocess
20 import sys 20 import sys
21 import urllib2 21 import urllib2
22 22
23 # Imports from within Skia 23 # Imports from within Skia
24 # 24 #
25 # Make sure that they are in the PYTHONPATH, but add them at the *end* 25 # We need to add the 'gm' directory, so that we can import gm_json.py within
26 # so any that are already in the PYTHONPATH will be preferred. 26 # that directory. That script allows us to parse the actual-results.json file
27 # written out by the GM tool.
Stephen White 2013/06/11 17:29:39 Thinking about this some more, maybe gm_json.py sh
epoger 2013/06/11 18:10:20 I think this is very topical in the context of rec
28 # Make sure that the 'gm' dir is in the PYTHONPATH, but add it at the *end*
29 # so any dirs that are already in the PYTHONPATH will be preferred.
30 #
31 # This assumes that the 'gm' directory has been checked out as a sibling of
32 # the 'tools' directory containing this script, which will be the case if
33 # 'trunk' was checked out as a single unit.
27 GM_DIRECTORY = os.path.realpath( 34 GM_DIRECTORY = os.path.realpath(
28 os.path.join(os.path.dirname(os.path.dirname(__file__)), 'gm')) 35 os.path.join(os.path.dirname(os.path.dirname(__file__)), 'gm'))
29 if GM_DIRECTORY not in sys.path: 36 if GM_DIRECTORY not in sys.path:
30 sys.path.append(GM_DIRECTORY) 37 sys.path.append(GM_DIRECTORY)
31 import gm_json 38 import gm_json
32 39
33 40
34 # Mapping of gm-expectations subdir (under 41 # Mapping of gm-expectations subdir (under
35 # https://skia.googlecode.com/svn/gm-expected/ ) 42 # https://skia.googlecode.com/svn/gm-expected/ )
36 # to builder name (see list at http://108.170.217.252:10117/builders ) 43 # to builder name (see list at http://108.170.217.252:10117/builders )
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
72 # subdirs: which platform subdirectories to rebaseline; if not specified, 79 # subdirs: which platform subdirectories to rebaseline; if not specified,
73 # rebaseline all platform subdirectories 80 # rebaseline all platform subdirectories
74 # tests: list of tests to rebaseline, or None if we should rebaseline 81 # tests: list of tests to rebaseline, or None if we should rebaseline
75 # whatever files the JSON results summary file tells us to 82 # whatever files the JSON results summary file tells us to
76 # configs: which configs to run for each test; this should only be 83 # configs: which configs to run for each test; this should only be
77 # specified if the list of tests was also specified (otherwise, 84 # specified if the list of tests was also specified (otherwise,
78 # the JSON file will give us test names and configs) 85 # the JSON file will give us test names and configs)
79 # dry_run: if True, instead of actually downloading files or adding 86 # dry_run: if True, instead of actually downloading files or adding
80 # files to checkout, display a list of operations that 87 # files to checkout, display a list of operations that
81 # we would normally perform 88 # we would normally perform
89 # add_new: if True, add expectations for tests which don't have any yet
82 def __init__(self, json_base_url, json_filename, 90 def __init__(self, json_base_url, json_filename,
83 subdirs=None, tests=None, configs=None, dry_run=False): 91 subdirs=None, tests=None, configs=None, dry_run=False,
92 add_new=False):
84 if configs and not tests: 93 if configs and not tests:
85 raise ValueError('configs should only be specified if tests ' + 94 raise ValueError('configs should only be specified if tests ' +
86 'were specified also') 95 'were specified also')
87 self._tests = tests 96 self._tests = tests
88 self._configs = configs 97 self._configs = configs
89 if not subdirs: 98 if not subdirs:
90 self._subdirs = sorted(SUBDIR_MAPPING.keys()) 99 self._subdirs = sorted(SUBDIR_MAPPING.keys())
91 self._missing_json_is_fatal = False 100 self._missing_json_is_fatal = False
92 else: 101 else:
93 self._subdirs = subdirs 102 self._subdirs = subdirs
94 self._missing_json_is_fatal = True 103 self._missing_json_is_fatal = True
95 self._json_base_url = json_base_url 104 self._json_base_url = json_base_url
96 self._json_filename = json_filename 105 self._json_filename = json_filename
97 self._dry_run = dry_run 106 self._dry_run = dry_run
107 self._add_new = add_new
98 self._is_svn_checkout = ( 108 self._is_svn_checkout = (
99 os.path.exists('.svn') or 109 os.path.exists('.svn') or
100 os.path.exists(os.path.join(os.pardir, '.svn'))) 110 os.path.exists(os.path.join(os.pardir, '.svn')))
101 self._is_git_checkout = ( 111 self._is_git_checkout = (
102 os.path.exists('.git') or 112 os.path.exists('.git') or
103 os.path.exists(os.path.join(os.pardir, '.git'))) 113 os.path.exists(os.path.join(os.pardir, '.git')))
104 114
105 # If dry_run is False, execute subprocess.call(cmd). 115 # If dry_run is False, execute subprocess.call(cmd).
106 # If dry_run is True, print the command we would have otherwise run. 116 # If dry_run is True, print the command we would have otherwise run.
107 # Raises a CommandFailedException if the command fails. 117 # Raises a CommandFailedException if the command fails.
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
147 # ['imageblur', 'xfermodes'] 157 # ['imageblur', 'xfermodes']
148 # 158 #
149 # If the JSON actual result summary file cannot be loaded, the behavior 159 # If the JSON actual result summary file cannot be loaded, the behavior
150 # depends on self._missing_json_is_fatal: 160 # depends on self._missing_json_is_fatal:
151 # - if true: execution will halt with an exception 161 # - if true: execution will halt with an exception
152 # - if false: we will log an error message but return an empty list so we 162 # - if false: we will log an error message but return an empty list so we
153 # go on to the next platform 163 # go on to the next platform
154 # 164 #
155 # params: 165 # params:
156 # json_url: URL pointing to a JSON actual result summary file 166 # json_url: URL pointing to a JSON actual result summary file
167 # add_new: if True, then return files listed in any of these sections:
168 # - JSONKEY_ACTUALRESULTS_FAILED
169 # - JSONKEY_ACTUALRESULTS_FAILUREIGNORED
epoger 2013/06/12 14:24:11 Patchset 4 removes FAILUREIGNORED from the list of
170 # - JSONKEY_ACTUALRESULTS_NOCOMPARISON
171 # if False, then return files listed in these sections:
172 # - JSONKEY_ACTUALRESULTS_FAILED
173 # - JSONKEY_ACTUALRESULTS_FAILUREIGNORED
157 # 174 #
158 # TODO(epoger): add a parameter indicating whether "no-comparison" 175 def _GetFilesToRebaseline(self, json_url, add_new):
159 # results (those for which we don't have any expectations yet)
160 # should be rebaselined. For now, we only return failed expectations.
161 def _GetFilesToRebaseline(self, json_url):
162 if self._dry_run: 176 if self._dry_run:
163 print '' 177 print ''
164 print '#' 178 print '#'
165 print ('# Getting files to rebaseline from JSON summary URL %s ...' 179 print ('# Getting files to rebaseline from JSON summary URL %s ...'
166 % json_url) 180 % json_url)
167 try: 181 try:
168 json_contents = self._GetContentsOfUrl(json_url) 182 json_contents = self._GetContentsOfUrl(json_url)
169 except urllib2.HTTPError: 183 except urllib2.HTTPError:
170 message = 'unable to load JSON summary URL %s' % json_url 184 message = 'unable to load JSON summary URL %s' % json_url
171 if self._missing_json_is_fatal: 185 if self._missing_json_is_fatal:
172 raise ValueError(message) 186 raise ValueError(message)
173 else: 187 else:
174 print '# %s' % message 188 print '# %s' % message
175 return [] 189 return []
176 190
177 json_dict = gm_json.LoadFromString(json_contents) 191 json_dict = gm_json.LoadFromString(json_contents)
178 actual_results = json_dict[gm_json.JSONKEY_ACTUALRESULTS] 192 actual_results = json_dict[gm_json.JSONKEY_ACTUALRESULTS]
193 sections = [gm_json.JSONKEY_ACTUALRESULTS_FAILED,
194 gm_json.JSONKEY_ACTUALRESULTS_FAILUREIGNORED]
195 if add_new:
196 sections.append(gm_json.JSONKEY_ACTUALRESULTS_NOCOMPARISON)
179 197
180 files_to_rebaseline = [] 198 files_to_rebaseline = []
181 failed_results = actual_results[gm_json.JSONKEY_ACTUALRESULTS_FAILED] 199 for section in sections:
182 if failed_results: 200 section_results = actual_results[section]
183 files_to_rebaseline.extend(failed_results.keys()) 201 if section_results:
202 files_to_rebaseline.extend(section_results.keys())
184 203
185 print '# ... found files_to_rebaseline %s' % files_to_rebaseline 204 print '# ... found files_to_rebaseline %s' % files_to_rebaseline
186 if self._dry_run: 205 if self._dry_run:
187 print '#' 206 print '#'
188 return files_to_rebaseline 207 return files_to_rebaseline
189 208
190 # Rebaseline a single file. 209 # Rebaseline a single file.
191 def _RebaselineOneFile(self, expectations_subdir, builder_name, 210 def _RebaselineOneFile(self, expectations_subdir, builder_name,
192 infilename, outfilename): 211 infilename, outfilename):
193 if self._dry_run: 212 if self._dry_run:
(...skipping 14 matching lines...) Expand all
208 # then fail if any of those expected combinations are 227 # then fail if any of those expected combinations are
209 # missing... but then this tool would become useless every 228 # missing... but then this tool would become useless every
210 # time someone tweaked the configs on the bots without 229 # time someone tweaked the configs on the bots without
211 # updating this script. 230 # updating this script.
212 try: 231 try:
213 self._DownloadFile(source_url=url, dest_filename=outfilename) 232 self._DownloadFile(source_url=url, dest_filename=outfilename)
214 except CommandFailedException: 233 except CommandFailedException:
215 print '# Couldn\'t fetch ' + url 234 print '# Couldn\'t fetch ' + url
216 return 235 return
217 236
218 # Add this file to version control (if it isn't already). 237 # Add this file to version control (if appropriate).
219 if self._is_svn_checkout: 238 if self._add_new:
Stephen White 2013/06/11 17:29:39 Actually, at least for git, I think we want to do
epoger 2013/06/11 18:10:20 Brian and/or Rob, do you have any thoughts on this
robertphillips 2013/06/12 14:13:41 I would greatly prefer if the addition of new base
220 cmd = [ 'svn', 'add', '--quiet', outfilename ] 239 if self._is_svn_checkout:
221 self._Call(cmd) 240 cmd = [ 'svn', 'add', '--quiet', outfilename ]
222 cmd = [ 'svn', 'propset', '--quiet', 'svn:mime-type', 'image/png', 241 self._Call(cmd)
223 outfilename ]; 242 cmd = [ 'svn', 'propset', '--quiet', 'svn:mime-type',
224 self._Call(cmd) 243 'image/png', outfilename ];
225 elif self._is_git_checkout: 244 self._Call(cmd)
226 cmd = [ 'git', 'add', outfilename ] 245 elif self._is_git_checkout:
227 self._Call(cmd) 246 cmd = [ 'git', 'add', outfilename ]
247 self._Call(cmd)
228 248
229 # Rebaseline the given configs for a single test. 249 # Rebaseline the given configs for a single test.
230 # 250 #
231 # params: 251 # params:
232 # expectations_subdir 252 # expectations_subdir
233 # builder_name 253 # builder_name
234 # test: a single test to rebaseline 254 # test: a single test to rebaseline
235 def _RebaselineOneTest(self, expectations_subdir, builder_name, test): 255 def _RebaselineOneTest(self, expectations_subdir, builder_name, test):
236 if self._configs: 256 if self._configs:
237 configs = self._configs 257 configs = self._configs
(...skipping 24 matching lines...) Expand all
262 builder_name = SUBDIR_MAPPING[subdir] 282 builder_name = SUBDIR_MAPPING[subdir]
263 if self._tests: 283 if self._tests:
264 for test in self._tests: 284 for test in self._tests:
265 self._RebaselineOneTest(expectations_subdir=subdir, 285 self._RebaselineOneTest(expectations_subdir=subdir,
266 builder_name=builder_name, 286 builder_name=builder_name,
267 test=test) 287 test=test)
268 else: # get the raw list of files that need rebaselining from JSON 288 else: # get the raw list of files that need rebaselining from JSON
269 json_url = '/'.join([self._json_base_url, 289 json_url = '/'.join([self._json_base_url,
270 subdir, builder_name, subdir, 290 subdir, builder_name, subdir,
271 self._json_filename]) 291 self._json_filename])
272 filenames = self._GetFilesToRebaseline(json_url=json_url) 292 filenames = self._GetFilesToRebaseline(json_url=json_url,
293 add_new=self._add_new)
273 for filename in filenames: 294 for filename in filenames:
274 outfilename = os.path.join(subdir, filename); 295 outfilename = os.path.join(subdir, filename);
275 self._RebaselineOneFile(expectations_subdir=subdir, 296 self._RebaselineOneFile(expectations_subdir=subdir,
276 builder_name=builder_name, 297 builder_name=builder_name,
277 infilename=filename, 298 infilename=filename,
278 outfilename=outfilename) 299 outfilename=outfilename)
279 300
280 # main... 301 # main...
281 302
282 parser = argparse.ArgumentParser() 303 parser = argparse.ArgumentParser()
304 parser.add_argument('--add-new', action='store_true',
305 help='in addition to the standard behavior of ' +
306 'updating expectations for failing tests, add ' +
307 'expectations for tests which don\'t have expectations ' +
308 'yet.')
283 parser.add_argument('--configs', metavar='CONFIG', nargs='+', 309 parser.add_argument('--configs', metavar='CONFIG', nargs='+',
284 help='which configurations to rebaseline, e.g. ' + 310 help='which configurations to rebaseline, e.g. ' +
285 '"--configs 565 8888"; if unspecified, run a default ' + 311 '"--configs 565 8888"; if unspecified, run a default ' +
286 'set of configs. This should ONLY be specified if ' + 312 'set of configs. This should ONLY be specified if ' +
287 '--tests has also been specified.') 313 '--tests has also been specified.')
288 parser.add_argument('--dry-run', action='store_true', 314 parser.add_argument('--dry-run', action='store_true',
289 help='instead of actually downloading files or adding ' + 315 help='instead of actually downloading files or adding ' +
290 'files to checkout, display a list of operations that ' + 316 'files to checkout, display a list of operations that ' +
291 'we would normally perform') 317 'we would normally perform')
292 parser.add_argument('--json-base-url', 318 parser.add_argument('--json-base-url',
(...skipping 10 matching lines...) Expand all
303 '"--subdirs %s"' % ' '.join(sorted(SUBDIR_MAPPING.keys()))) 329 '"--subdirs %s"' % ' '.join(sorted(SUBDIR_MAPPING.keys())))
304 parser.add_argument('--tests', metavar='TEST', nargs='+', 330 parser.add_argument('--tests', metavar='TEST', nargs='+',
305 help='which tests to rebaseline, e.g. ' + 331 help='which tests to rebaseline, e.g. ' +
306 '"--tests aaclip bigmatrix"; if unspecified, then all ' + 332 '"--tests aaclip bigmatrix"; if unspecified, then all ' +
307 'failing tests (according to the actual-results.json ' + 333 'failing tests (according to the actual-results.json ' +
308 'file) will be rebaselined.') 334 'file) will be rebaselined.')
309 args = parser.parse_args() 335 args = parser.parse_args()
310 rebaseliner = Rebaseliner(tests=args.tests, configs=args.configs, 336 rebaseliner = Rebaseliner(tests=args.tests, configs=args.configs,
311 subdirs=args.subdirs, dry_run=args.dry_run, 337 subdirs=args.subdirs, dry_run=args.dry_run,
312 json_base_url=args.json_base_url, 338 json_base_url=args.json_base_url,
313 json_filename=args.json_filename) 339 json_filename=args.json_filename,
340 add_new=args.add_new)
314 rebaseliner.RebaselineAll() 341 rebaseliner.RebaselineAll()
OLDNEW
« no previous file with comments | « no previous file | tools/tests/rebaseline/output/all/output-expected/stdout » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698