epoger@google.com | 27442af | 2011-12-29 21:13:08 +0000 | [diff] [blame] | 1 | ''' |
| 2 | Downloads the actual gm results most recently generated by the Skia buildbots, |
| 3 | and adds any new ones to SVN control. |
| 4 | |
| 5 | This tool makes it much easier to check in new baselines, via the following |
| 6 | steps: |
| 7 | |
| 8 | cd .../trunk |
| 9 | svn update |
| 10 | # make sure there are no files awaiting svn commit |
epoger@google.com | d625655 | 2012-01-10 14:10:34 +0000 | [diff] [blame] | 11 | python tools/download-baselines.py gm/base-macmini-lion-fixed # or other gm/ subdir |
epoger@google.com | fc241ee | 2012-02-02 16:49:49 +0000 | [diff] [blame] | 12 | # validate that the new images look right (maybe using compare-baselines.py) |
epoger@google.com | 27442af | 2011-12-29 21:13:08 +0000 | [diff] [blame] | 13 | # upload CL for review |
epoger@google.com | fc241ee | 2012-02-02 16:49:49 +0000 | [diff] [blame] | 14 | # validate that the new images look right in the review tool |
epoger@google.com | 27442af | 2011-12-29 21:13:08 +0000 | [diff] [blame] | 15 | # commit CL |
| 16 | |
epoger@google.com | d625655 | 2012-01-10 14:10:34 +0000 | [diff] [blame] | 17 | Launch with --help to see more options. |
| 18 | |
epoger@google.com | 27442af | 2011-12-29 21:13:08 +0000 | [diff] [blame] | 19 | |
| 20 | Copyright 2011 Google Inc. |
| 21 | |
| 22 | Use of this source code is governed by a BSD-style license that can be |
| 23 | found in the LICENSE file. |
| 24 | ''' |
| 25 | |
| 26 | # common Python modules |
epoger@google.com | 20ad5ac | 2012-01-17 21:26:05 +0000 | [diff] [blame] | 27 | import fnmatch |
epoger@google.com | d625655 | 2012-01-10 14:10:34 +0000 | [diff] [blame] | 28 | import optparse |
| 29 | import os |
epoger@google.com | 27442af | 2011-12-29 21:13:08 +0000 | [diff] [blame] | 30 | import re |
epoger@google.com | 20ad5ac | 2012-01-17 21:26:05 +0000 | [diff] [blame] | 31 | import shutil |
epoger@google.com | 27442af | 2011-12-29 21:13:08 +0000 | [diff] [blame] | 32 | import sys |
epoger@google.com | 20ad5ac | 2012-01-17 21:26:05 +0000 | [diff] [blame] | 33 | import tempfile |
epoger@google.com | 27442af | 2011-12-29 21:13:08 +0000 | [diff] [blame] | 34 | |
| 35 | # modules declared within this same directory |
| 36 | import svn |
| 37 | |
epoger@google.com | 20ad5ac | 2012-01-17 21:26:05 +0000 | [diff] [blame] | 38 | # Base URL of SVN repository where buildbots store actual gm image results. |
| 39 | SVN_BASE_URL = 'http://skia-autogen.googlecode.com/svn/gm-actual' |
epoger@google.com | 27442af | 2011-12-29 21:13:08 +0000 | [diff] [blame] | 40 | |
epoger@google.com | d625655 | 2012-01-10 14:10:34 +0000 | [diff] [blame] | 41 | USAGE_STRING = 'usage: %s [options] <baseline_subdir>' |
| 42 | OPTION_IGNORE_LOCAL_MODS = '--ignore-local-mods' |
| 43 | OPTION_ADD_NEW_FILES = '--add-new-files' |
| 44 | |
epoger@google.com | 20ad5ac | 2012-01-17 21:26:05 +0000 | [diff] [blame] | 45 | def GetLatestResultsSvnUrl(baseline_subdir): |
| 46 | """Return SVN URL from which we can check out the MOST RECENTLY generated |
epoger@google.com | 27442af | 2011-12-29 21:13:08 +0000 | [diff] [blame] | 47 | images for this baseline type. |
| 48 | |
| 49 | @param baseline_subdir indicates which platform we want images for |
| 50 | """ |
epoger@google.com | 20ad5ac | 2012-01-17 21:26:05 +0000 | [diff] [blame] | 51 | # trim off 'gm/' prefix |
| 52 | gm_prefix = 'gm%s' % os.sep |
| 53 | if not baseline_subdir.startswith(gm_prefix): |
| 54 | raise Exception('baseline_subdir "%s" should start with "%s"' % ( |
| 55 | baseline_subdir, gm_prefix)) |
| 56 | return '%s/%s' % (SVN_BASE_URL, baseline_subdir[len(gm_prefix):]) |
epoger@google.com | 27442af | 2011-12-29 21:13:08 +0000 | [diff] [blame] | 57 | |
epoger@google.com | 20ad5ac | 2012-01-17 21:26:05 +0000 | [diff] [blame] | 58 | def CopyMatchingFiles(source_dir, dest_dir, filename_pattern, |
| 59 | only_copy_updates=False): |
| 60 | """Copy all files from source_dir that match filename_pattern, and |
| 61 | save them (with their original filenames) in dest_dir. |
epoger@google.com | 27442af | 2011-12-29 21:13:08 +0000 | [diff] [blame] | 62 | |
epoger@google.com | 20ad5ac | 2012-01-17 21:26:05 +0000 | [diff] [blame] | 63 | @param source_dir |
| 64 | @param dest_dir where to save the copied files |
| 65 | @param filename_pattern only copy files that match this Unix-style filename |
| 66 | pattern (e.g., '*.jpg') |
| 67 | @param only_copy_updates if True, only copy files that are already |
| 68 | present in dest_dir |
epoger@google.com | 27442af | 2011-12-29 21:13:08 +0000 | [diff] [blame] | 69 | """ |
epoger@google.com | 20ad5ac | 2012-01-17 21:26:05 +0000 | [diff] [blame] | 70 | all_filenames = os.listdir(source_dir) |
| 71 | matching_filenames = fnmatch.filter(all_filenames, filename_pattern) |
| 72 | for filename in matching_filenames: |
| 73 | source_path = os.path.join(source_dir, filename) |
| 74 | dest_path = os.path.join(dest_dir, filename) |
| 75 | if only_copy_updates and not os.path.isfile(dest_path): |
epoger@google.com | d625655 | 2012-01-10 14:10:34 +0000 | [diff] [blame] | 76 | continue |
epoger@google.com | 20ad5ac | 2012-01-17 21:26:05 +0000 | [diff] [blame] | 77 | shutil.copyfile(source_path, dest_path) |
epoger@google.com | 27442af | 2011-12-29 21:13:08 +0000 | [diff] [blame] | 78 | |
epoger@google.com | d625655 | 2012-01-10 14:10:34 +0000 | [diff] [blame] | 79 | def Main(options, args): |
epoger@google.com | 27442af | 2011-12-29 21:13:08 +0000 | [diff] [blame] | 80 | """Download most recently generated baseline images for a given platform, |
| 81 | and add any new ones to SVN control. |
| 82 | |
epoger@google.com | d625655 | 2012-01-10 14:10:34 +0000 | [diff] [blame] | 83 | @param options |
| 84 | @param args |
epoger@google.com | 27442af | 2011-12-29 21:13:08 +0000 | [diff] [blame] | 85 | """ |
epoger@google.com | d625655 | 2012-01-10 14:10:34 +0000 | [diff] [blame] | 86 | num_args = len(args) |
| 87 | if num_args != 1: |
| 88 | RaiseUsageException() |
epoger@google.com | 27442af | 2011-12-29 21:13:08 +0000 | [diff] [blame] | 89 | |
epoger@google.com | 20ad5ac | 2012-01-17 21:26:05 +0000 | [diff] [blame] | 90 | # Create repo_to_modify to handle the SVN repository we will add files to. |
| 91 | baseline_subdir = args[0].rstrip(os.sep); |
| 92 | if not os.path.isdir(baseline_subdir): |
| 93 | raise Exception('could not find baseline_subdir "%s"' % baseline_subdir) |
| 94 | repo_to_modify = svn.Svn(baseline_subdir) |
epoger@google.com | d625655 | 2012-01-10 14:10:34 +0000 | [diff] [blame] | 95 | |
| 96 | # If there are any locally modified files in that directory, exit |
| 97 | # (so that we don't risk overwriting the user's previous work). |
epoger@google.com | 20ad5ac | 2012-01-17 21:26:05 +0000 | [diff] [blame] | 98 | new_and_modified_files = repo_to_modify.GetNewAndModifiedFiles() |
epoger@google.com | d625655 | 2012-01-10 14:10:34 +0000 | [diff] [blame] | 99 | if not options.ignore_local_mods: |
| 100 | if new_and_modified_files: |
| 101 | raise Exception('Exiting because there are already new and/or ' |
| 102 | 'modified files in %s. To continue in spite of ' |
| 103 | 'that, run with %s option.' % ( |
| 104 | baseline_subdir, OPTION_IGNORE_LOCAL_MODS)) |
| 105 | |
epoger@google.com | 20ad5ac | 2012-01-17 21:26:05 +0000 | [diff] [blame] | 106 | # Download actual gm images into a separate repo in a temporary directory. |
| 107 | tempdir = tempfile.mkdtemp() |
| 108 | download_repo = svn.Svn(tempdir) |
| 109 | download_repo.Checkout(GetLatestResultsSvnUrl(baseline_subdir), '.') |
| 110 | |
| 111 | # Copy any of those files we are interested in into repo_to_modify, |
| 112 | # and then delete the temporary directory. |
| 113 | CopyMatchingFiles(source_dir=tempdir, dest_dir=baseline_subdir, |
| 114 | filename_pattern='*.png', |
| 115 | only_copy_updates=(not options.add_new_files)) |
| 116 | shutil.rmtree(tempdir) |
| 117 | download_repo = None |
epoger@google.com | d625655 | 2012-01-10 14:10:34 +0000 | [diff] [blame] | 118 | |
| 119 | # Add any new files to SVN control (if we are running with add_new_files). |
epoger@google.com | 20ad5ac | 2012-01-17 21:26:05 +0000 | [diff] [blame] | 120 | new_files = repo_to_modify.GetNewFiles() |
epoger@google.com | d625655 | 2012-01-10 14:10:34 +0000 | [diff] [blame] | 121 | if new_files and options.add_new_files: |
epoger@google.com | 20ad5ac | 2012-01-17 21:26:05 +0000 | [diff] [blame] | 122 | repo_to_modify.AddFiles(new_files) |
| 123 | |
| 124 | # Set the mimetype property on *all* image files in baseline_subdir, even |
| 125 | # the ones that were already there (in case that property wasn't properly |
| 126 | # set already). |
| 127 | repo_to_modify.SetPropertyByFilenamePattern( |
| 128 | '*.png', svn.PROPERTY_MIMETYPE, 'image/png') |
| 129 | repo_to_modify.SetPropertyByFilenamePattern( |
| 130 | '*.pdf', svn.PROPERTY_MIMETYPE, 'application/pdf') |
epoger@google.com | 27442af | 2011-12-29 21:13:08 +0000 | [diff] [blame] | 131 | |
epoger@google.com | d625655 | 2012-01-10 14:10:34 +0000 | [diff] [blame] | 132 | def RaiseUsageException(): |
| 133 | raise Exception(USAGE_STRING % __file__) |
| 134 | |
epoger@google.com | 27442af | 2011-12-29 21:13:08 +0000 | [diff] [blame] | 135 | if __name__ == '__main__': |
epoger@google.com | d625655 | 2012-01-10 14:10:34 +0000 | [diff] [blame] | 136 | parser = optparse.OptionParser(USAGE_STRING % '%prog') |
| 137 | parser.add_option(OPTION_IGNORE_LOCAL_MODS, |
| 138 | action='store_true', default=False, |
| 139 | help='allow tool to run even if there are already ' |
| 140 | 'local modifications in the baseline_subdir') |
| 141 | parser.add_option(OPTION_ADD_NEW_FILES, |
| 142 | action='store_true', default=False, |
| 143 | help='in addition to downloading new versions of ' |
| 144 | 'existing baselines, also download baselines that are ' |
| 145 | 'not under SVN control yet') |
| 146 | (options, args) = parser.parse_args() |
| 147 | Main(options, args) |