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

Side by Side Diff: tools/rebaseline.py

Issue 18348018: rebaseline.py: if expectations dir contains JSON format results, update those instead of image files (Closed) Base URL: http://skia.googlecode.com/svn/trunk/
Patch Set: Created 7 years, 5 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
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 # EPOGER: check if any of these are no longer needed
17 import argparse 18 import argparse
18 import os 19 import os
19 import re 20 import re
20 import subprocess 21 import subprocess
21 import sys 22 import sys
22 import urllib2 23 import urllib2
23 24
24 # Imports from local directory 25 # Imports from local directory
25 import rebaseline_imagefiles 26 import rebaseline_imagefiles
26 27
27 # Imports from within Skia 28 # Imports from within Skia
28 # 29 #
29 # We need to add the 'gm' directory, so that we can import gm_json.py within 30 # We need to add the 'gm' directory, so that we can import gm_json.py within
30 # that directory. That script allows us to parse the actual-results.json file 31 # that directory. That script allows us to parse the actual-results.json file
31 # written out by the GM tool. 32 # written out by the GM tool.
32 # Make sure that the 'gm' dir is in the PYTHONPATH, but add it at the *end* 33 # Make sure that the 'gm' dir is in the PYTHONPATH, but add it at the *end*
33 # so any dirs that are already in the PYTHONPATH will be preferred. 34 # so any dirs that are already in the PYTHONPATH will be preferred.
34 # 35 #
35 # This assumes that the 'gm' directory has been checked out as a sibling of 36 # This assumes that the 'gm' directory has been checked out as a sibling of
36 # the 'tools' directory containing this script, which will be the case if 37 # the 'tools' directory containing this script, which will be the case if
37 # 'trunk' was checked out as a single unit. 38 # 'trunk' was checked out as a single unit.
38 GM_DIRECTORY = os.path.realpath( 39 GM_DIRECTORY = os.path.realpath(
39 os.path.join(os.path.dirname(os.path.dirname(__file__)), 'gm')) 40 os.path.join(os.path.dirname(os.path.dirname(__file__)), 'gm'))
40 if GM_DIRECTORY not in sys.path: 41 if GM_DIRECTORY not in sys.path:
41 sys.path.append(GM_DIRECTORY) 42 sys.path.append(GM_DIRECTORY)
42 import gm_json 43 import gm_json
43 44
45 # EPOGER: make this a command-line argument
44 JSON_EXPECTATIONS_FILENAME='expected-results.json' 46 JSON_EXPECTATIONS_FILENAME='expected-results.json'
45 47
46 # Mapping of gm-expectations subdir (under 48 # Mapping of gm-expectations subdir (under
47 # https://skia.googlecode.com/svn/gm-expected/ ) 49 # https://skia.googlecode.com/svn/gm-expected/ )
48 # to builder name (see list at http://108.170.217.252:10117/builders ) 50 # to builder name (see list at http://108.170.217.252:10117/builders )
49 SUBDIR_MAPPING = { 51 SUBDIR_MAPPING = {
50 'base-shuttle-win7-intel-float': 52 'base-shuttle-win7-intel-float':
51 'Test-Win7-ShuttleA-HD2000-x86-Release', 53 'Test-Win7-ShuttleA-HD2000-x86-Release',
52 'base-shuttle-win7-intel-angle': 54 'base-shuttle-win7-intel-angle':
53 'Test-Win7-ShuttleA-HD2000-x86-Release-ANGLE', 55 'Test-Win7-ShuttleA-HD2000-x86-Release-ANGLE',
(...skipping 17 matching lines...) Expand all
71 'Test-Android-Nexus10-MaliT604-Arm7-Release', 73 'Test-Android-Nexus10-MaliT604-Arm7-Release',
72 'base-android-nexus-4': 74 'base-android-nexus-4':
73 'Test-Android-Nexus4-Adreno320-Arm7-Release', 75 'Test-Android-Nexus4-Adreno320-Arm7-Release',
74 } 76 }
75 77
76 78
77 class CommandFailedException(Exception): 79 class CommandFailedException(Exception):
78 pass 80 pass
79 81
80 # Object that rebaselines a JSON expectations file (not individual image files). 82 # Object that rebaselines a JSON expectations file (not individual image files).
81 #
82 # TODO(epoger): Most of this is just the code from the old ImageRebaseliner...
83 # some of it will need to be updated in order to properly rebaseline JSON files.
84 # There is a lot of code duplicated between here and ImageRebaseliner, but
85 # that's fine because we will delete ImageRebaseliner soon.
86 class JsonRebaseliner(object): 83 class JsonRebaseliner(object):
87 84
88 # params: 85 # params:
89 # expectations_root: root directory of all expectations 86 # expectations_root: root directory of all expectations JSON files
90 # json_base_url: base URL from which to read json_filename 87 # actuals_base_url: base URL from which to read actual-result JSON files
91 # json_filename: filename (under json_base_url) from which to read a 88 # actuals_filename: filename (under actuals_base_url) from which to read a
92 # summary of results; typically "actual-results.json" 89 # summary of results; typically "actual-results.json"
93 # tests: list of tests to rebaseline, or None if we should rebaseline 90 # tests: list of tests to rebaseline, or None if we should rebaseline
94 # whatever files the JSON results summary file tells us to 91 # whatever files the JSON results summary file tells us to
95 # configs: which configs to run for each test; this should only be 92 # configs: which configs to run for each test; this should only be
96 # specified if the list of tests was also specified (otherwise, 93 # specified if the list of tests was also specified (otherwise,
97 # the JSON file will give us test names and configs) 94 # the JSON file will give us test names and configs)
98 # dry_run: if True, instead of actually downloading files or adding
99 # files to checkout, display a list of operations that
100 # we would normally perform
101 # add_new: if True, add expectations for tests which don't have any yet 95 # add_new: if True, add expectations for tests which don't have any yet
102 # missing_json_is_fatal: whether to halt execution if we cannot read a 96 def __init__(self, expectations_root, actuals_base_url, actuals_filename,
103 # JSON actual result summary file 97 tests=None, configs=None, add_new=False):
104 def __init__(self, expectations_root, json_base_url, json_filename,
105 tests=None, configs=None, dry_run=False,
106 add_new=False, missing_json_is_fatal=False):
107 raise ValueError('JsonRebaseliner not yet implemented') # TODO(epoger)
108 if configs and not tests: 98 if configs and not tests:
109 raise ValueError('configs should only be specified if tests ' + 99 raise ValueError('configs should only be specified if tests ' +
110 'were specified also') 100 'were specified also')
111 self._expectations_root = expectations_root 101 self._expectations_root = expectations_root
112 self._tests = tests 102 self._tests = tests
113 self._configs = configs 103 self._configs = configs
114 self._json_base_url = json_base_url 104 self._actuals_base_url = actuals_base_url
115 self._json_filename = json_filename 105 self._actuals_filename = actuals_filename
116 self._dry_run = dry_run
117 self._add_new = add_new 106 self._add_new = add_new
118 self._missing_json_is_fatal = missing_json_is_fatal
119 self._googlestorage_gm_actuals_root = (
120 'http://chromium-skia-gm.commondatastorage.googleapis.com/gm')
121 self._testname_pattern = re.compile('(\S+)_(\S+).png') 107 self._testname_pattern = re.compile('(\S+)_(\S+).png')
122 self._is_svn_checkout = (
123 os.path.exists('.svn') or
124 os.path.exists(os.path.join(os.pardir, '.svn')))
125 self._is_git_checkout = (
126 os.path.exists('.git') or
127 os.path.exists(os.path.join(os.pardir, '.git')))
128 108
129 # If dry_run is False, execute subprocess.call(cmd). 109 # EPOGER: check if this (or any other method) is no longer needed.
130 # If dry_run is True, print the command we would have otherwise run. 110 # Execute subprocess.call(cmd).
131 # Raises a CommandFailedException if the command fails. 111 # Raises a CommandFailedException if the command fails.
132 def _Call(self, cmd): 112 def _Call(self, cmd):
133 if self._dry_run:
134 print '%s' % ' '.join(cmd)
135 return
136 if subprocess.call(cmd) != 0: 113 if subprocess.call(cmd) != 0:
137 raise CommandFailedException('error running command: ' + 114 raise CommandFailedException('error running command: ' +
138 ' '.join(cmd)) 115 ' '.join(cmd))
139 116
140 # Download a single actual result from GoogleStorage, returning True if it
141 # succeeded.
142 def _DownloadFromGoogleStorage(self, infilename, outfilename, all_results):
143 test_name = self._testname_pattern.match(infilename).group(1)
144 if not test_name:
145 print '# unable to find test_name for infilename %s' % infilename
146 return False
147 try:
148 hash_type, hash_value = all_results[infilename]
149 except KeyError:
150 print ('# unable to find filename %s in all_results dict' %
151 infilename)
152 return False
153 except ValueError as e:
154 print '# ValueError reading filename %s from all_results dict: %s'%(
155 infilename, e)
156 return False
157 url = '%s/%s/%s/%s.png' % (self._googlestorage_gm_actuals_root,
158 hash_type, test_name, hash_value)
159 try:
160 self._DownloadFile(source_url=url, dest_filename=outfilename)
161 return True
162 except CommandFailedException:
163 print '# Couldn\'t fetch gs_url %s' % url
164 return False
165
166 # Download a single actual result from skia-autogen, returning True if it 117 # Download a single actual result from skia-autogen, returning True if it
167 # succeeded. 118 # succeeded.
168 def _DownloadFromAutogen(self, infilename, outfilename, 119 def _DownloadFromAutogen(self, infilename, outfilename,
169 expectations_subdir, builder_name): 120 expectations_subdir, builder_name):
170 url = ('http://skia-autogen.googlecode.com/svn/gm-actual/' + 121 url = ('http://skia-autogen.googlecode.com/svn/gm-actual/' +
171 expectations_subdir + '/' + builder_name + '/' + 122 expectations_subdir + '/' + builder_name + '/' +
172 expectations_subdir + '/' + infilename) 123 expectations_subdir + '/' + infilename)
173 try: 124 try:
174 self._DownloadFile(source_url=url, dest_filename=outfilename) 125 self._DownloadFile(source_url=url, dest_filename=outfilename)
175 return True 126 return True
176 except CommandFailedException: 127 except CommandFailedException:
177 print '# Couldn\'t fetch autogen_url %s' % url 128 print '# Couldn\'t fetch autogen_url %s' % url
178 return False 129 return False
179 130
180 # Download a single file, raising a CommandFailedException if it fails. 131 # Download a single file, raising a CommandFailedException if it fails.
181 def _DownloadFile(self, source_url, dest_filename): 132 def _DownloadFile(self, source_url, dest_filename):
182 # Download into a temporary file and then rename it afterwards, 133 # Download into a temporary file and then rename it afterwards,
183 # so that we don't corrupt the existing file if it fails midway thru. 134 # so that we don't corrupt the existing file if it fails midway thru.
184 temp_filename = os.path.join(os.path.dirname(dest_filename), 135 temp_filename = os.path.join(os.path.dirname(dest_filename),
185 '.temp-' + os.path.basename(dest_filename)) 136 '.temp-' + os.path.basename(dest_filename))
186 137
187 # TODO(epoger): Replace calls to "curl"/"mv" (which will only work on 138 # TODO(epoger): Replace calls to "curl"/"mv" (which will only work on
188 # Unix) with a Python HTTP library (which should work cross-platform) 139 # Unix) with a Python HTTP library (which should work cross-platform)
189 self._Call([ 'curl', '--fail', '--silent', source_url, 140 self._Call([ 'curl', '--fail', '--silent', source_url,
190 '--output', temp_filename ]) 141 '--output', temp_filename ])
191 self._Call([ 'mv', temp_filename, dest_filename ]) 142 self._Call([ 'mv', temp_filename, dest_filename ])
192 143
193 # Returns the full contents of a URL, as a single string. 144 # Returns the full contents of filepath, as a single string.
194 # 145 # If filepath looks like a URL, try to read it that way instead of as
195 # Unlike standard URL handling, we allow relative "file:" URLs; 146 # a path on local storage.
196 # for example, "file:one/two" resolves to the file ./one/two 147 def _GetFileContents(self, filepath):
197 # (relative to current working dir) 148 if filepath.startswith('http:') or filepath.startswith('https:'):
198 def _GetContentsOfUrl(self, url): 149 return urllib2.urlopen(filepath).read()
199 file_prefix = 'file:'
200 if url.startswith(file_prefix):
201 filename = url[len(file_prefix):]
202 return open(filename, 'r').read()
203 else: 150 else:
204 return urllib2.urlopen(url).read() 151 return open(filepath, 'r').read()
205 152
206 # Returns a dictionary of actual results from actual-results.json file. 153 # Returns a dictionary of actual results from actual-results.json file.
207 # 154 #
208 # The dictionary returned has this format: 155 # The dictionary returned has this format:
209 # { 156 # {
210 # u'imageblur_565.png': [u'bitmap-64bitMD5', 3359963596899141322], 157 # u'imageblur_565.png': [u'bitmap-64bitMD5', 3359963596899141322],
211 # u'imageblur_8888.png': [u'bitmap-64bitMD5', 4217923806027861152], 158 # u'imageblur_8888.png': [u'bitmap-64bitMD5', 4217923806027861152],
212 # u'shadertext3_8888.png': [u'bitmap-64bitMD5', 3713708307125704716] 159 # u'shadertext3_8888.png': [u'bitmap-64bitMD5', 3713708307125704716]
213 # } 160 # }
214 # 161 #
215 # If the JSON actual result summary file cannot be loaded, the behavior 162 # If the JSON actual result summary file cannot be loaded, raise an
216 # depends on self._missing_json_is_fatal: 163 # exception.
217 # - if true: execution will halt with an exception
218 # - if false: we will log an error message but return an empty dictionary
219 # 164 #
220 # params: 165 # params:
221 # json_url: URL pointing to a JSON actual result summary file 166 # json_url: URL pointing to a JSON actual result summary file
222 # sections: a list of section names to include in the results, e.g. 167 # sections: a list of section names to include in the results, e.g.
223 # [gm_json.JSONKEY_ACTUALRESULTS_FAILED, 168 # [gm_json.JSONKEY_ACTUALRESULTS_FAILED,
224 # gm_json.JSONKEY_ACTUALRESULTS_NOCOMPARISON] ; 169 # gm_json.JSONKEY_ACTUALRESULTS_NOCOMPARISON] ;
225 # if None, then include ALL sections. 170 # if None, then include ALL sections.
226 def _GetActualResults(self, json_url, sections=None): 171 def _GetActualResults(self, json_url, sections=None):
227 try: 172 json_contents = self._GetFileContents(json_url)
228 json_contents = self._GetContentsOfUrl(json_url)
229 except (urllib2.HTTPError, IOError):
230 message = 'unable to load JSON summary URL %s' % json_url
231 if self._missing_json_is_fatal:
232 raise ValueError(message)
233 else:
234 print '# %s' % message
235 return {}
236
237 json_dict = gm_json.LoadFromString(json_contents) 173 json_dict = gm_json.LoadFromString(json_contents)
238 results_to_return = {} 174 results_to_return = {}
239 actual_results = json_dict[gm_json.JSONKEY_ACTUALRESULTS] 175 actual_results = json_dict[gm_json.JSONKEY_ACTUALRESULTS]
240 if not sections: 176 if not sections:
241 sections = actual_results.keys() 177 sections = actual_results.keys()
242 for section in sections: 178 for section in sections:
243 section_results = actual_results[section] 179 section_results = actual_results[section]
244 if section_results: 180 if section_results:
245 results_to_return.update(section_results) 181 results_to_return.update(section_results)
246 return results_to_return 182 return results_to_return
247 183
248 # Returns a list of files that require rebaselining. 184 # Returns a list of files that require rebaselining.
249 # 185 #
250 # Note that this returns a list of FILES, like this: 186 # Note that this returns a list of FILES, like this:
251 # ['imageblur_565.png', 'xfermodes_pdf.png'] 187 # ['imageblur_565.png', 'xfermodes_pdf.png']
252 # rather than a list of TESTS, like this: 188 # rather than a list of TESTS, like this:
253 # ['imageblur', 'xfermodes'] 189 # ['imageblur', 'xfermodes']
254 # 190 #
255 # params: 191 # params:
256 # json_url: URL pointing to a JSON actual result summary file 192 # json_url: URL pointing to a JSON actual result summary file
257 # add_new: if True, then return files listed in any of these sections: 193 # add_new: if True, then return files listed in any of these sections:
258 # - JSONKEY_ACTUALRESULTS_FAILED 194 # - JSONKEY_ACTUALRESULTS_FAILED
259 # - JSONKEY_ACTUALRESULTS_NOCOMPARISON 195 # - JSONKEY_ACTUALRESULTS_NOCOMPARISON
260 # if False, then return files listed in these sections: 196 # if False, then return files listed in these sections:
261 # - JSONKEY_ACTUALRESULTS_FAILED 197 # - JSONKEY_ACTUALRESULTS_FAILED
262 # 198 #
263 def _GetFilesToRebaseline(self, json_url, add_new): 199 def _GetFilesToRebaseline(self, json_url, add_new):
264 if self._dry_run:
265 print ''
266 print '#'
267 print ('# Getting files to rebaseline from JSON summary URL %s ...' 200 print ('# Getting files to rebaseline from JSON summary URL %s ...'
268 % json_url) 201 % json_url)
269 sections = [gm_json.JSONKEY_ACTUALRESULTS_FAILED] 202 sections = [gm_json.JSONKEY_ACTUALRESULTS_FAILED]
270 if add_new: 203 if add_new:
271 sections.append(gm_json.JSONKEY_ACTUALRESULTS_NOCOMPARISON) 204 sections.append(gm_json.JSONKEY_ACTUALRESULTS_NOCOMPARISON)
272 results_to_rebaseline = self._GetActualResults(json_url=json_url, 205 results_to_rebaseline = self._GetActualResults(json_url=json_url,
273 sections=sections) 206 sections=sections)
274 files_to_rebaseline = results_to_rebaseline.keys() 207 files_to_rebaseline = results_to_rebaseline.keys()
275 files_to_rebaseline.sort() 208 files_to_rebaseline.sort()
276 print '# ... found files_to_rebaseline %s' % files_to_rebaseline 209 print '# ... found files_to_rebaseline %s' % files_to_rebaseline
277 if self._dry_run:
278 print '#'
279 return files_to_rebaseline 210 return files_to_rebaseline
280 211
281 # Rebaseline a single file. 212 # Rebaseline a single file.
282 def _RebaselineOneFile(self, expectations_subdir, builder_name, 213 def _RebaselineOneFile(self, expectations_subdir, builder_name,
283 infilename, outfilename, all_results): 214 infilename, outfilename, all_results):
284 if self._dry_run:
285 print ''
286 print '# ' + infilename 215 print '# ' + infilename
287 216
288 # First try to download this result image from Google Storage. 217 # First try to download this result image from Google Storage.
289 # If that fails, try skia-autogen. 218 # If that fails, try skia-autogen.
290 # If that fails too, just go on to the next file. 219 # If that fails too, just go on to the next file.
291 # 220 #
292 # This not treated as a fatal failure because not all 221 # This not treated as a fatal failure because not all
293 # platforms generate all configs (e.g., Android does not 222 # platforms generate all configs (e.g., Android does not
294 # generate PDF). 223 # generate PDF).
295 # 224 #
296 # TODO(epoger): Once we are downloading only files that the 225 # TODO(epoger): Once we are downloading only files that the
297 # actual-results.json file told us to, this should become a 226 # actual-results.json file told us to, this should become a
298 # fatal error. (If the actual-results.json file told us that 227 # fatal error. (If the actual-results.json file told us that
299 # the test failed with XXX results, we should be able to download 228 # the test failed with XXX results, we should be able to download
300 # those results every time.) 229 # those results every time.)
301 if not self._DownloadFromGoogleStorage(infilename=infilename, 230 if not self._DownloadFromGoogleStorage(infilename=infilename,
302 outfilename=outfilename, 231 outfilename=outfilename,
303 all_results=all_results): 232 all_results=all_results):
304 if not self._DownloadFromAutogen(infilename=infilename, 233 if not self._DownloadFromAutogen(infilename=infilename,
305 outfilename=outfilename, 234 outfilename=outfilename,
306 expectations_subdir=expectations_su bdir, 235 expectations_subdir=expectations_su bdir,
307 builder_name=builder_name): 236 builder_name=builder_name):
308 print '# Couldn\'t fetch infilename ' + infilename 237 print '# Couldn\'t fetch infilename ' + infilename
309 return 238 return
310 239
311 # Add this file to version control (if appropriate).
312 if self._add_new:
313 if self._is_svn_checkout:
314 cmd = [ 'svn', 'add', '--quiet', outfilename ]
315 self._Call(cmd)
316 cmd = [ 'svn', 'propset', '--quiet', 'svn:mime-type',
317 'image/png', outfilename ];
318 self._Call(cmd)
319 elif self._is_git_checkout:
320 cmd = [ 'git', 'add', outfilename ]
321 self._Call(cmd)
322
323 # Rebaseline the given configs for a single test. 240 # Rebaseline the given configs for a single test.
324 # 241 #
325 # params: 242 # params:
326 # expectations_subdir 243 # expectations_subdir
327 # builder_name 244 # builder_name
328 # test: a single test to rebaseline 245 # test: a single test to rebaseline
329 # all_results: a dictionary of all actual results 246 # all_results: a dictionary of all actual results
330 def _RebaselineOneTest(self, expectations_subdir, builder_name, test, 247 def _RebaselineOneTest(self, expectations_subdir, builder_name, test,
331 all_results): 248 all_results):
332 if self._configs: 249 if self._configs:
333 configs = self._configs 250 configs = self._configs
334 else: 251 else:
335 if (expectations_subdir == 'base-shuttle-win7-intel-angle'): 252 if (expectations_subdir == 'base-shuttle-win7-intel-angle'):
336 configs = [ 'angle', 'anglemsaa16' ] 253 configs = [ 'angle', 'anglemsaa16' ]
337 else: 254 else:
338 configs = [ '565', '8888', 'gpu', 'pdf', 'mesa', 'msaa16', 255 configs = [ '565', '8888', 'gpu', 'pdf', 'mesa', 'msaa16',
339 'msaa4' ] 256 'msaa4' ]
340 if self._dry_run:
341 print ''
342 print '# ' + expectations_subdir + ':' 257 print '# ' + expectations_subdir + ':'
343 for config in configs: 258 for config in configs:
344 infilename = test + '_' + config + '.png' 259 infilename = test + '_' + config + '.png'
345 outfilename = os.path.join(expectations_subdir, infilename); 260 outfilename = os.path.join(expectations_subdir, infilename);
346 self._RebaselineOneFile(expectations_subdir=expectations_subdir, 261 self._RebaselineOneFile(expectations_subdir=expectations_subdir,
347 builder_name=builder_name, 262 builder_name=builder_name,
348 infilename=infilename, 263 infilename=infilename,
349 outfilename=outfilename, 264 outfilename=outfilename,
350 all_results=all_results) 265 all_results=all_results)
351 266
352 # Rebaseline all tests/types we specified in the constructor, 267 # Rebaseline all tests/types we specified in the constructor,
353 # within this gm-expectations subdir. 268 # within this gm-expectations subdir.
354 # 269 #
355 # params: 270 # params:
356 # subdir : e.g. 'base-shuttle-win7-intel-float' 271 # subdir : e.g. 'base-shuttle-win7-intel-float'
357 # builder : e.g. 'Test-Win7-ShuttleA-HD2000-x86-Release' 272 # builder : e.g. 'Test-Win7-ShuttleA-HD2000-x86-Release'
358 def RebaselineSubdir(self, subdir, builder): 273 def RebaselineSubdir(self, subdir, builder):
359 json_url = '/'.join([self._json_base_url, 274 # Read in the actual result summary, and extract all the tests whose
360 subdir, builder, subdir, 275 # results we need to update.
361 self._json_filename]) 276 actuals_url = '/'.join([self._actuals_base_url,
362 all_results = self._GetActualResults(json_url=json_url) 277 subdir, builder, subdir,
278 self._actuals_filename])
279 sections = [gm_json.JSONKEY_ACTUALRESULTS_FAILED]
280 if self._add_new:
281 sections.append(gm_json.JSONKEY_ACTUALRESULTS_NOCOMPARISON)
282 results_to_update = self._GetActualResults(json_url=actuals_url,
283 sections=sections)
284 #print 'EPOGER: results_to_update is...\n%s\n\n' % results_to_update
285
286 # EPOGER implement this section...
287 # If tests or configs were set, throw out any new expectations that
288 # don't match.
289
290 # Read in current expectations.
291 expectations_json_filepath = os.path.join(
292 self._expectations_root, subdir, JSON_EXPECTATIONS_FILENAME)
293 expectations_dict = gm_json.LoadFromFile(expectations_json_filepath)
294 #print 'EPOGER: expectations_dict is...\n%s\n\n' % expectations_dict
295
296 # EPOGER implement this section...
297 # Update the expectations in memory.
298
299 # Write out updated expectations.
300 gm_json.WriteToFile(expectations_dict, expectations_json_filepath)
301
302 # EPOGER: delete
303 def OLDRebaselineSubdir(self, subdir, builder):
304 results_to_rebaseline = self._GetActualResults(json_url=json_url,
305 sections=sections)
363 306
364 if self._tests: 307 if self._tests:
365 for test in self._tests: 308 for test in self._tests:
366 self._RebaselineOneTest(expectations_subdir=subdir, 309 self._RebaselineOneTest(expectations_subdir=subdir,
367 builder_name=builder, 310 builder_name=builder,
368 test=test, all_results=all_results) 311 test=test, all_results=all_results)
369 else: # get the raw list of files that need rebaselining from JSON 312 else: # get the raw list of files that need rebaselining from JSON
370 filenames = self._GetFilesToRebaseline(json_url=json_url, 313 filenames = self._GetFilesToRebaseline(json_url=json_url,
371 add_new=self._add_new) 314 add_new=self._add_new)
372 for filename in filenames: 315 for filename in filenames:
(...skipping 19 matching lines...) Expand all
392 '--tests has also been specified.') 335 '--tests has also been specified.')
393 parser.add_argument('--dry-run', action='store_true', 336 parser.add_argument('--dry-run', action='store_true',
394 help='instead of actually downloading files or adding ' + 337 help='instead of actually downloading files or adding ' +
395 'files to checkout, display a list of operations that ' + 338 'files to checkout, display a list of operations that ' +
396 'we would normally perform') 339 'we would normally perform')
397 parser.add_argument('--expectations-root', 340 parser.add_argument('--expectations-root',
398 help='root of expectations directory to update-- should ' + 341 help='root of expectations directory to update-- should ' +
399 'contain one or more base-* subdirectories. Defaults to ' + 342 'contain one or more base-* subdirectories. Defaults to ' +
400 '%(default)s', 343 '%(default)s',
401 default='.') 344 default='.')
402 parser.add_argument('--json-base-url', 345 parser.add_argument('--actuals-base-url',
403 help='base URL from which to read JSON_FILENAME ' + 346 help='base URL from which to read ACTUALS_FILENAME ' +
404 'files; defaults to %(default)s', 347 'files; defaults to %(default)s',
405 default='http://skia-autogen.googlecode.com/svn/gm-actual') 348 default='http://skia-autogen.googlecode.com/svn/gm-actual')
406 parser.add_argument('--json-filename', 349 parser.add_argument('--actuals-filename',
407 help='filename (under JSON_BASE_URL) to read a summary ' + 350 help='filename (under ACTUALS_BASE_URL) to read a ' +
408 'of results from; defaults to %(default)s', 351 'summary of results from; defaults to %(default)s',
409 default='actual-results.json') 352 default='actual-results.json')
410 parser.add_argument('--subdirs', metavar='SUBDIR', nargs='+', 353 parser.add_argument('--subdirs', metavar='SUBDIR', nargs='+',
411 help='which platform subdirectories to rebaseline; ' + 354 help='which platform subdirectories to rebaseline; ' +
412 'if unspecified, rebaseline all subdirs, same as ' + 355 'if unspecified, rebaseline all subdirs, same as ' +
413 '"--subdirs %s"' % ' '.join(sorted(SUBDIR_MAPPING.keys()))) 356 '"--subdirs %s"' % ' '.join(sorted(SUBDIR_MAPPING.keys())))
414 parser.add_argument('--tests', metavar='TEST', nargs='+', 357 parser.add_argument('--tests', metavar='TEST', nargs='+',
415 help='which tests to rebaseline, e.g. ' + 358 help='which tests to rebaseline, e.g. ' +
416 '"--tests aaclip bigmatrix"; if unspecified, then all ' + 359 '"--tests aaclip bigmatrix"; if unspecified, then all ' +
417 'failing tests (according to the actual-results.json ' + 360 'failing tests (according to the actual-results.json ' +
418 'file) will be rebaselined.') 361 'file) will be rebaselined.')
(...skipping 14 matching lines...) Expand all
433 # We instantiate different Rebaseliner objects depending 376 # We instantiate different Rebaseliner objects depending
434 # on whether we are rebaselining an expected-results.json file, or 377 # on whether we are rebaselining an expected-results.json file, or
435 # individual image files. Different gm-expected subdirectories may move 378 # individual image files. Different gm-expected subdirectories may move
436 # from individual image files to JSON-format expectations at different 379 # from individual image files to JSON-format expectations at different
437 # times, so we need to make this determination per subdirectory. 380 # times, so we need to make this determination per subdirectory.
438 # 381 #
439 # See https://goto.google.com/ChecksumTransitionDetail 382 # See https://goto.google.com/ChecksumTransitionDetail
440 expectations_json_file = os.path.join(args.expectations_root, subdir, 383 expectations_json_file = os.path.join(args.expectations_root, subdir,
441 JSON_EXPECTATIONS_FILENAME) 384 JSON_EXPECTATIONS_FILENAME)
442 if os.path.isfile(expectations_json_file): 385 if os.path.isfile(expectations_json_file):
443 sys.stderr.write('ERROR: JsonRebaseliner is not implemented yet.\n')
444 sys.exit(1)
445 rebaseliner = JsonRebaseliner( 386 rebaseliner = JsonRebaseliner(
446 expectations_root=args.expectations_root, 387 expectations_root=args.expectations_root,
447 tests=args.tests, configs=args.configs, 388 tests=args.tests, configs=args.configs,
448 dry_run=args.dry_run, 389 actuals_base_url=args.actuals_base_url,
449 json_base_url=args.json_base_url, 390 actuals_filename=args.actuals_filename,
450 json_filename=args.json_filename, 391 add_new=args.add_new)
451 add_new=args.add_new,
452 missing_json_is_fatal=missing_json_is_fatal)
453 else: 392 else:
454 rebaseliner = rebaseline_imagefiles.ImageRebaseliner( 393 rebaseliner = rebaseline_imagefiles.ImageRebaseliner(
455 expectations_root=args.expectations_root, 394 expectations_root=args.expectations_root,
456 tests=args.tests, configs=args.configs, 395 tests=args.tests, configs=args.configs,
457 dry_run=args.dry_run, 396 dry_run=args.dry_run,
458 json_base_url=args.json_base_url, 397 json_base_url=args.actuals_base_url,
459 json_filename=args.json_filename, 398 json_filename=args.actuals_filename,
460 add_new=args.add_new, 399 add_new=args.add_new,
461 missing_json_is_fatal=missing_json_is_fatal) 400 missing_json_is_fatal=missing_json_is_fatal)
462 rebaseliner.RebaselineSubdir(subdir=subdir, builder=builder) 401 rebaseliner.RebaselineSubdir(subdir=subdir, builder=builder)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698