epoger@google.com | fc241ee | 2012-02-02 16:49:49 +0000 | [diff] [blame] | 1 | ''' |
| 2 | Compares the gm results within the local checkout against those already |
epoger@google.com | db12fee | 2012-02-03 14:32:34 +0000 | [diff] [blame] | 3 | committed to the Skia repository. |
epoger@google.com | fc241ee | 2012-02-02 16:49:49 +0000 | [diff] [blame] | 4 | |
epoger@google.com | db12fee | 2012-02-03 14:32:34 +0000 | [diff] [blame] | 5 | Launch with --help to see more information. |
epoger@google.com | fc241ee | 2012-02-02 16:49:49 +0000 | [diff] [blame] | 6 | |
| 7 | |
| 8 | Copyright 2012 Google Inc. |
| 9 | |
| 10 | Use of this source code is governed by a BSD-style license that can be |
| 11 | found in the LICENSE file. |
| 12 | ''' |
| 13 | |
| 14 | # common Python modules |
| 15 | import fnmatch |
| 16 | import optparse |
| 17 | import os |
| 18 | import shutil |
| 19 | import tempfile |
| 20 | |
| 21 | # modules declared within this same directory |
| 22 | import svn |
| 23 | |
epoger@google.com | 1610a68 | 2012-04-12 18:02:25 +0000 | [diff] [blame] | 24 | USAGE_STRING = 'Usage: %s [options]' |
| 25 | HOWTO_STRING = ''' |
| 26 | To update the checked-in baselines across all platforms, follow these steps: |
| 27 | |
| 28 | cd .../trunk |
| 29 | svn update |
| 30 | svn stat # and make sure there are no files awaiting svn commit |
| 31 | make tools BUILDTYPE=Release |
| 32 | python tools/download_baselines.py |
| 33 | python tools/compare_baselines.py |
| 34 | # view compare_baselines output in a browser and make sure it's reasonable |
| 35 | # upload CL for review |
| 36 | # validate that the diffs look right in the review tool |
| 37 | # commit CL |
| 38 | |
| 39 | Note that the above instructions will only *update* already-checked-in |
| 40 | baseline images; if you want to check in new baseline images (ones that the |
| 41 | bots have been generating but we don't have a golden master for yet), you need |
| 42 | to use download_baselines.py's --add-new-files option. |
| 43 | ''' |
| 44 | HELP_STRING = ''' |
epoger@google.com | fc241ee | 2012-02-02 16:49:49 +0000 | [diff] [blame] | 45 | |
epoger@google.com | db12fee | 2012-02-03 14:32:34 +0000 | [diff] [blame] | 46 | Compares the gm results within the local checkout against those already |
| 47 | committed to the Skia repository. Relies on skdiff to do the low-level |
| 48 | comparison. |
| 49 | |
epoger@google.com | 1610a68 | 2012-04-12 18:02:25 +0000 | [diff] [blame] | 50 | ''' + HOWTO_STRING |
epoger@google.com | db12fee | 2012-02-03 14:32:34 +0000 | [diff] [blame] | 51 | |
| 52 | TRUNK_PATH = os.path.join(os.path.dirname(__file__), os.pardir) |
| 53 | |
| 54 | OPTION_GM_BASEDIR = '--gm-basedir' |
| 55 | DEFAULT_GM_BASEDIR = os.path.join(TRUNK_PATH, 'gm') |
epoger@google.com | fc241ee | 2012-02-02 16:49:49 +0000 | [diff] [blame] | 56 | OPTION_PATH_TO_SKDIFF = '--path-to-skdiff' |
epoger@google.com | db12fee | 2012-02-03 14:32:34 +0000 | [diff] [blame] | 57 | # default PATH_TO_SKDIFF is determined at runtime |
| 58 | OPTION_SVN_GM_URL = '--svn-gm-url' |
| 59 | DEFAULT_SVN_GM_URL = 'http://skia.googlecode.com/svn/trunk/gm' |
epoger@google.com | fc241ee | 2012-02-02 16:49:49 +0000 | [diff] [blame] | 60 | |
| 61 | def CopyAllFilesAddingPrefix(source_dir, dest_dir, prefix): |
| 62 | """Copy all files from source_dir into dest_dir, adding prefix to the name |
| 63 | of each one as we copy it. |
| 64 | prefixes. |
| 65 | |
| 66 | @param source_dir |
| 67 | @param dest_dir where to save the copied files |
| 68 | @param prefix prefix to add to each filename when we make the copy |
| 69 | """ |
| 70 | all_filenames = os.listdir(source_dir) |
| 71 | for filename in all_filenames: |
| 72 | source_path = os.path.join(source_dir, filename) |
| 73 | if os.path.isdir(source_path): |
| 74 | print 'skipping %s because it is a directory, not a file' % filename |
| 75 | continue |
| 76 | dest_path = os.path.join(dest_dir, '%s%s' % (prefix, filename)) |
| 77 | shutil.copyfile(source_path, dest_path) |
| 78 | |
| 79 | def Flatten(source_dir, dest_dir, subdirectory_pattern): |
| 80 | """Copy all files from matching subdirectories under source_dir into |
| 81 | dest_dir, flattened into a single directory using subdirectory names as |
| 82 | prefixes. |
| 83 | |
| 84 | @param source_dir |
| 85 | @param dest_dir where to save the copied files |
| 86 | @param subdirectory_pattern only copy files from subdirectories that match |
| 87 | this Unix-style filename pattern (e.g., 'base-*') |
| 88 | """ |
| 89 | all_filenames = os.listdir(source_dir) |
| 90 | matching_filenames = fnmatch.filter(all_filenames, subdirectory_pattern) |
| 91 | for filename in matching_filenames: |
| 92 | source_path = os.path.join(source_dir, filename) |
| 93 | if not os.path.isdir(source_path): |
| 94 | print 'skipping %s because it is a file, not a directory' % filename |
| 95 | continue |
| 96 | print 'flattening directory %s' % source_path |
| 97 | CopyAllFilesAddingPrefix(source_dir=source_path, dest_dir=dest_dir, |
| 98 | prefix='%s_' % filename) |
| 99 | |
| 100 | def RunCommand(command): |
| 101 | """Run a command, raising an exception if it fails. |
| 102 | |
| 103 | @param command the command as a single string |
| 104 | """ |
| 105 | print 'running command [%s]...' % command |
| 106 | retval = os.system(command) |
bsalomon@google.com | c0961f5 | 2012-06-28 19:50:27 +0000 | [diff] [blame] | 107 | #if retval is not 0: |
| 108 | # raise Exception('command [%s] failed' % command) |
epoger@google.com | fc241ee | 2012-02-02 16:49:49 +0000 | [diff] [blame] | 109 | |
epoger@google.com | db12fee | 2012-02-03 14:32:34 +0000 | [diff] [blame] | 110 | def FindPathToSkDiff(user_set_path=None): |
| 111 | """Return path to an existing skdiff binary, or raise an exception if we |
| 112 | cannot find one. |
| 113 | |
| 114 | @param user_set_path if None, the user did not specify a path, so look in |
| 115 | some likely places; otherwise, only check at this path |
| 116 | """ |
| 117 | if user_set_path is not None: |
| 118 | if os.path.isfile(user_set_path): |
| 119 | return user_set_path |
| 120 | raise Exception('unable to find skdiff at user-set path %s' % |
| 121 | user_set_path) |
| 122 | trunk_path = os.path.join(os.path.dirname(__file__), os.pardir) |
| 123 | possible_paths = [os.path.join(trunk_path, 'out', 'Release', 'skdiff'), |
| 124 | os.path.join(trunk_path, 'out', 'Debug', 'skdiff')] |
| 125 | for try_path in possible_paths: |
| 126 | if os.path.isfile(try_path): |
| 127 | return try_path |
| 128 | raise Exception('cannot find skdiff in paths %s; maybe you need to ' |
| 129 | 'specify the %s option or build skdiff?' % ( |
| 130 | possible_paths, OPTION_PATH_TO_SKDIFF)) |
| 131 | |
| 132 | def CompareBaselines(gm_basedir, path_to_skdiff, svn_gm_url): |
| 133 | """Compare the gm results within gm_basedir against those already |
epoger@google.com | fc241ee | 2012-02-02 16:49:49 +0000 | [diff] [blame] | 134 | committed to the Skia repository. |
| 135 | |
epoger@google.com | db12fee | 2012-02-03 14:32:34 +0000 | [diff] [blame] | 136 | @param gm_basedir |
| 137 | @param path_to_skdiff |
| 138 | @param svn_gm_url base URL of Subversion repository where we store the |
| 139 | expected GM results |
epoger@google.com | fc241ee | 2012-02-02 16:49:49 +0000 | [diff] [blame] | 140 | """ |
epoger@google.com | db12fee | 2012-02-03 14:32:34 +0000 | [diff] [blame] | 141 | # Validate parameters, filling in default values if necessary and possible. |
| 142 | if not os.path.isdir(gm_basedir): |
| 143 | raise Exception('cannot find gm_basedir at %s; maybe you need to ' |
| 144 | 'specify the %s option?' % ( |
| 145 | gm_basedir, OPTION_GM_BASEDIR)) |
| 146 | path_to_skdiff = FindPathToSkDiff(path_to_skdiff) |
epoger@google.com | fc241ee | 2012-02-02 16:49:49 +0000 | [diff] [blame] | 147 | |
| 148 | tempdir_base = tempfile.mkdtemp() |
| 149 | |
| 150 | # Download all checked-in baseline images to a temp directory |
| 151 | checkedin_dir = os.path.join(tempdir_base, 'checkedin') |
| 152 | os.mkdir(checkedin_dir) |
epoger@google.com | db12fee | 2012-02-03 14:32:34 +0000 | [diff] [blame] | 153 | svn.Svn(checkedin_dir).Checkout(svn_gm_url, '.') |
epoger@google.com | fc241ee | 2012-02-02 16:49:49 +0000 | [diff] [blame] | 154 | |
| 155 | # Flatten those checked-in baseline images into checkedin_flattened_dir |
| 156 | checkedin_flattened_dir = os.path.join(tempdir_base, 'checkedin_flattened') |
| 157 | os.mkdir(checkedin_flattened_dir) |
| 158 | Flatten(source_dir=checkedin_dir, dest_dir=checkedin_flattened_dir, |
| 159 | subdirectory_pattern='base-*') |
| 160 | |
| 161 | # Flatten the local baseline images into local_flattened_dir |
| 162 | local_flattened_dir = os.path.join(tempdir_base, 'local_flattened') |
| 163 | os.mkdir(local_flattened_dir) |
| 164 | Flatten(source_dir=gm_basedir, dest_dir=local_flattened_dir, |
| 165 | subdirectory_pattern='base-*') |
| 166 | |
| 167 | # Run skdiff to compare checkedin_flattened_dir against local_flattened_dir |
| 168 | diff_dir = os.path.join(tempdir_base, 'diffs') |
| 169 | os.mkdir(diff_dir) |
epoger@google.com | db12fee | 2012-02-03 14:32:34 +0000 | [diff] [blame] | 170 | RunCommand('%s %s %s %s' % (path_to_skdiff, checkedin_flattened_dir, |
epoger@google.com | fc241ee | 2012-02-02 16:49:49 +0000 | [diff] [blame] | 171 | local_flattened_dir, diff_dir)) |
| 172 | print '\nskdiff results are ready in file://%s/index.html' % diff_dir |
epoger@google.com | db12fee | 2012-02-03 14:32:34 +0000 | [diff] [blame] | 173 | # TODO(epoger): delete tempdir_base tree to clean up after ourselves (but |
| 174 | # not before the user gets a chance to examine the results), and/or |
| 175 | # allow user to specify a different directory to write into? |
epoger@google.com | fc241ee | 2012-02-02 16:49:49 +0000 | [diff] [blame] | 176 | |
| 177 | def RaiseUsageException(): |
epoger@google.com | 1610a68 | 2012-04-12 18:02:25 +0000 | [diff] [blame] | 178 | raise Exception('%s\nRun with --help for more detail.' % ( |
epoger@google.com | db12fee | 2012-02-03 14:32:34 +0000 | [diff] [blame] | 179 | USAGE_STRING % __file__)) |
| 180 | |
| 181 | def Main(options, args): |
| 182 | """Allow other scripts to call this script with fake command-line args. |
| 183 | """ |
| 184 | num_args = len(args) |
| 185 | if num_args != 0: |
| 186 | RaiseUsageException() |
| 187 | CompareBaselines(gm_basedir=options.gm_basedir, |
| 188 | path_to_skdiff=options.path_to_skdiff, |
| 189 | svn_gm_url=options.svn_gm_url) |
epoger@google.com | fc241ee | 2012-02-02 16:49:49 +0000 | [diff] [blame] | 190 | |
| 191 | if __name__ == '__main__': |
epoger@google.com | 1610a68 | 2012-04-12 18:02:25 +0000 | [diff] [blame] | 192 | parser = optparse.OptionParser(USAGE_STRING % '%prog' + HELP_STRING) |
epoger@google.com | db12fee | 2012-02-03 14:32:34 +0000 | [diff] [blame] | 193 | parser.add_option(OPTION_GM_BASEDIR, |
| 194 | action='store', type='string', default=DEFAULT_GM_BASEDIR, |
| 195 | help='path to root of locally stored baseline images ' |
| 196 | 'to compare against those checked into the svn repo; ' |
| 197 | 'defaults to "%s"' % DEFAULT_GM_BASEDIR) |
epoger@google.com | fc241ee | 2012-02-02 16:49:49 +0000 | [diff] [blame] | 198 | parser.add_option(OPTION_PATH_TO_SKDIFF, |
epoger@google.com | db12fee | 2012-02-03 14:32:34 +0000 | [diff] [blame] | 199 | action='store', type='string', default=None, |
| 200 | help='path to already-built skdiff tool; if not set, ' |
| 201 | 'will search for it in typical directories near this ' |
| 202 | 'script') |
| 203 | parser.add_option(OPTION_SVN_GM_URL, |
| 204 | action='store', type='string', default=DEFAULT_SVN_GM_URL, |
| 205 | help='URL of SVN repository within which we store the ' |
| 206 | 'expected GM baseline images; defaults to "%s"' % |
| 207 | DEFAULT_SVN_GM_URL) |
epoger@google.com | fc241ee | 2012-02-02 16:49:49 +0000 | [diff] [blame] | 208 | (options, args) = parser.parse_args() |
| 209 | Main(options, args) |