diff options
Diffstat (limited to 'tools/compare_baselines.py')
-rw-r--r-- | tools/compare_baselines.py | 196 |
1 files changed, 196 insertions, 0 deletions
diff --git a/tools/compare_baselines.py b/tools/compare_baselines.py new file mode 100644 index 0000000000..19614ce1ff --- /dev/null +++ b/tools/compare_baselines.py @@ -0,0 +1,196 @@ +''' +Compares the gm results within the local checkout against those already +committed to the Skia repository. + +Launch with --help to see more information. + + +Copyright 2012 Google Inc. + +Use of this source code is governed by a BSD-style license that can be +found in the LICENSE file. +''' + +# common Python modules +import fnmatch +import optparse +import os +import shutil +import tempfile + +# modules declared within this same directory +import svn + +USAGE_STRING = '''usage: %s [options] + +Compares the gm results within the local checkout against those already +committed to the Skia repository. Relies on skdiff to do the low-level +comparison. + +for example: + +cd .../trunk +# modify local gm images, maybe by running download-baselines.py +make tools +python tools/compare-baselines.py +# validate that the image diffs look right +''' + +TRUNK_PATH = os.path.join(os.path.dirname(__file__), os.pardir) + +OPTION_GM_BASEDIR = '--gm-basedir' +DEFAULT_GM_BASEDIR = os.path.join(TRUNK_PATH, 'gm') +OPTION_PATH_TO_SKDIFF = '--path-to-skdiff' +# default PATH_TO_SKDIFF is determined at runtime +OPTION_SVN_GM_URL = '--svn-gm-url' +DEFAULT_SVN_GM_URL = 'http://skia.googlecode.com/svn/trunk/gm' + +def CopyAllFilesAddingPrefix(source_dir, dest_dir, prefix): + """Copy all files from source_dir into dest_dir, adding prefix to the name + of each one as we copy it. + prefixes. + + @param source_dir + @param dest_dir where to save the copied files + @param prefix prefix to add to each filename when we make the copy + """ + all_filenames = os.listdir(source_dir) + for filename in all_filenames: + source_path = os.path.join(source_dir, filename) + if os.path.isdir(source_path): + print 'skipping %s because it is a directory, not a file' % filename + continue + dest_path = os.path.join(dest_dir, '%s%s' % (prefix, filename)) + shutil.copyfile(source_path, dest_path) + +def Flatten(source_dir, dest_dir, subdirectory_pattern): + """Copy all files from matching subdirectories under source_dir into + dest_dir, flattened into a single directory using subdirectory names as + prefixes. + + @param source_dir + @param dest_dir where to save the copied files + @param subdirectory_pattern only copy files from subdirectories that match + this Unix-style filename pattern (e.g., 'base-*') + """ + all_filenames = os.listdir(source_dir) + matching_filenames = fnmatch.filter(all_filenames, subdirectory_pattern) + for filename in matching_filenames: + source_path = os.path.join(source_dir, filename) + if not os.path.isdir(source_path): + print 'skipping %s because it is a file, not a directory' % filename + continue + print 'flattening directory %s' % source_path + CopyAllFilesAddingPrefix(source_dir=source_path, dest_dir=dest_dir, + prefix='%s_' % filename) + +def RunCommand(command): + """Run a command, raising an exception if it fails. + + @param command the command as a single string + """ + print 'running command [%s]...' % command + retval = os.system(command) + if retval is not 0: + raise Exception('command [%s] failed' % command) + +def FindPathToSkDiff(user_set_path=None): + """Return path to an existing skdiff binary, or raise an exception if we + cannot find one. + + @param user_set_path if None, the user did not specify a path, so look in + some likely places; otherwise, only check at this path + """ + if user_set_path is not None: + if os.path.isfile(user_set_path): + return user_set_path + raise Exception('unable to find skdiff at user-set path %s' % + user_set_path) + trunk_path = os.path.join(os.path.dirname(__file__), os.pardir) + possible_paths = [os.path.join(trunk_path, 'out', 'Release', 'skdiff'), + os.path.join(trunk_path, 'out', 'Debug', 'skdiff')] + for try_path in possible_paths: + if os.path.isfile(try_path): + return try_path + raise Exception('cannot find skdiff in paths %s; maybe you need to ' + 'specify the %s option or build skdiff?' % ( + possible_paths, OPTION_PATH_TO_SKDIFF)) + +def CompareBaselines(gm_basedir, path_to_skdiff, svn_gm_url): + """Compare the gm results within gm_basedir against those already + committed to the Skia repository. + + @param gm_basedir + @param path_to_skdiff + @param svn_gm_url base URL of Subversion repository where we store the + expected GM results + """ + # Validate parameters, filling in default values if necessary and possible. + if not os.path.isdir(gm_basedir): + raise Exception('cannot find gm_basedir at %s; maybe you need to ' + 'specify the %s option?' % ( + gm_basedir, OPTION_GM_BASEDIR)) + path_to_skdiff = FindPathToSkDiff(path_to_skdiff) + + tempdir_base = tempfile.mkdtemp() + + # Download all checked-in baseline images to a temp directory + checkedin_dir = os.path.join(tempdir_base, 'checkedin') + os.mkdir(checkedin_dir) + svn.Svn(checkedin_dir).Checkout(svn_gm_url, '.') + + # Flatten those checked-in baseline images into checkedin_flattened_dir + checkedin_flattened_dir = os.path.join(tempdir_base, 'checkedin_flattened') + os.mkdir(checkedin_flattened_dir) + Flatten(source_dir=checkedin_dir, dest_dir=checkedin_flattened_dir, + subdirectory_pattern='base-*') + + # Flatten the local baseline images into local_flattened_dir + local_flattened_dir = os.path.join(tempdir_base, 'local_flattened') + os.mkdir(local_flattened_dir) + Flatten(source_dir=gm_basedir, dest_dir=local_flattened_dir, + subdirectory_pattern='base-*') + + # Run skdiff to compare checkedin_flattened_dir against local_flattened_dir + diff_dir = os.path.join(tempdir_base, 'diffs') + os.mkdir(diff_dir) + RunCommand('%s %s %s %s' % (path_to_skdiff, checkedin_flattened_dir, + local_flattened_dir, diff_dir)) + print '\nskdiff results are ready in file://%s/index.html' % diff_dir + # TODO(epoger): delete tempdir_base tree to clean up after ourselves (but + # not before the user gets a chance to examine the results), and/or + # allow user to specify a different directory to write into? + +def RaiseUsageException(): + raise Exception('%s\n\nRun with --help for more detail.' % ( + USAGE_STRING % __file__)) + +def Main(options, args): + """Allow other scripts to call this script with fake command-line args. + """ + num_args = len(args) + if num_args != 0: + RaiseUsageException() + CompareBaselines(gm_basedir=options.gm_basedir, + path_to_skdiff=options.path_to_skdiff, + svn_gm_url=options.svn_gm_url) + +if __name__ == '__main__': + parser = optparse.OptionParser(USAGE_STRING % '%prog') + parser.add_option(OPTION_GM_BASEDIR, + action='store', type='string', default=DEFAULT_GM_BASEDIR, + help='path to root of locally stored baseline images ' + 'to compare against those checked into the svn repo; ' + 'defaults to "%s"' % DEFAULT_GM_BASEDIR) + parser.add_option(OPTION_PATH_TO_SKDIFF, + action='store', type='string', default=None, + help='path to already-built skdiff tool; if not set, ' + 'will search for it in typical directories near this ' + 'script') + parser.add_option(OPTION_SVN_GM_URL, + action='store', type='string', default=DEFAULT_SVN_GM_URL, + help='URL of SVN repository within which we store the ' + 'expected GM baseline images; defaults to "%s"' % + DEFAULT_SVN_GM_URL) + (options, args) = parser.parse_args() + Main(options, args) |