aboutsummaryrefslogtreecommitdiffhomepage
path: root/tools/compare_baselines.py
diff options
context:
space:
mode:
Diffstat (limited to 'tools/compare_baselines.py')
-rw-r--r--tools/compare_baselines.py196
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)