OLD | NEW |
| (Empty) |
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 Launch with --help to see more information. | |
6 | |
7 | |
8 Copyright 2011 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 re | |
19 import shutil | |
20 import sys | |
21 import tempfile | |
22 | |
23 # modules declared within this same directory | |
24 import compare_baselines | |
25 import svn | |
26 | |
27 USAGE_STRING = 'Usage: %s [options] [baseline_subdir]...' | |
28 HELP_STRING = ''' | |
29 | |
30 Downloads the actual gm results most recently generated by the Skia buildbots, | |
31 and adds any new ones to SVN control. | |
32 | |
33 If no baseline_subdir is given, then this tool will download the most-recently | |
34 generated actual gm results for ALL platforms. | |
35 | |
36 ''' + compare_baselines.HOWTO_STRING | |
37 | |
38 # Base URL of SVN repository where buildbots store actual gm image results. | |
39 GM_ACTUAL_URL = 'http://skia-autogen.googlecode.com/svn/gm-actual' | |
40 | |
41 # GM baseline image URL in regular Skia SVN repository | |
42 GM_BASELINE_URL = 'https://skia.googlecode.com/svn/gm-expected' | |
43 | |
44 GM_EXPECTED_DIR = 'gm-expected' | |
45 | |
46 OPTION_ADD_NEW_FILES = '--add-new-files' | |
47 OPTION_BUILDER_SUFFIX = '--builder-suffix' | |
48 DEFAULT_BUILDER_SUFFIX = '32' | |
49 OPTION_IGNORE_LOCAL_MODS = '--ignore-local-mods' | |
50 | |
51 def GetLatestResultsSvnUrl(svn, baseline_subdir, builder_suffix): | |
52 """Return SVN URL from which we can check out the MOST RECENTLY generated im
ages for this | |
53 baseline type. | |
54 | |
55 @param svn an Svn object we can use to call ListSubdirs() | |
56 @param baseline_subdir indicates which platform we want images for | |
57 @param builder_suffix if multiple builders uploaded actual GM images for thi
s baseline type, | |
58 choose the one whose builder_name matches this suffix | |
59 """ | |
60 root_url = '%s/%s' % (GM_ACTUAL_URL, baseline_subdir) | |
61 subdirs = sorted(svn.ListSubdirs(root_url)) | |
62 num_subdirs = len(subdirs) | |
63 print('Within actual-results root URL %s, found these %d subdirs (presumably
builder_names): %s' | |
64 % (root_url, num_subdirs, subdirs)) | |
65 | |
66 selected_subdir = None | |
67 if num_subdirs == 0: | |
68 print 'Found no builder_name subdirs, so reading actual images from the
root_url itself.' | |
69 return root_url | |
70 elif num_subdirs == 1: | |
71 selected_subdir = subdirs[0] | |
72 print 'Found exactly one subdir in actual-results root_url: %s' % select
ed_subdir | |
73 else: | |
74 for possible_subdir in subdirs: | |
75 if possible_subdir.endswith(builder_suffix): | |
76 selected_subdir = possible_subdir | |
77 print 'Selected the first subdir ending in "%s": %s' % ( | |
78 builder_suffix, selected_subdir) | |
79 break | |
80 | |
81 if selected_subdir: | |
82 return '%s/%s/%s' % (root_url, selected_subdir, baseline_subdir) | |
83 else: | |
84 raise Exception('none of these subdirs of %s ended in "%s": %s' % ( | |
85 root_url, builder_suffix, subdirs)) | |
86 | |
87 def GetBaselineSvnUrl(baseline_subdir): | |
88 """Return SVN URL from which we can check out the baseline images for this | |
89 baseline type. | |
90 | |
91 @param baseline_subdir indicates which platform we want baselines for | |
92 """ | |
93 return '%s/%s' % (GM_BASELINE_URL, baseline_subdir) | |
94 | |
95 def CopyMatchingFiles(source_dir, dest_dir, filename_pattern, only_copy_updates=
False): | |
96 """Copy all files from source_dir that match filename_pattern, and save them
(with their | |
97 original filenames) in dest_dir. | |
98 | |
99 @param source_dir | |
100 @param dest_dir where to save the copied files | |
101 @param filename_pattern only copy files that match this Unix-style filename | |
102 pattern (e.g., '*.jpg') | |
103 @param only_copy_updates if True, only copy files that are already present i
n dest_dir | |
104 """ | |
105 all_filenames = os.listdir(source_dir) | |
106 matching_filenames = fnmatch.filter(all_filenames, filename_pattern) | |
107 for filename in matching_filenames: | |
108 source_path = os.path.join(source_dir, filename) | |
109 dest_path = os.path.join(dest_dir, filename) | |
110 if only_copy_updates and not os.path.isfile(dest_path): | |
111 continue | |
112 shutil.copyfile(source_path, dest_path) | |
113 | |
114 def DownloadBaselinesForOnePlatform(baseline_subdir): | |
115 """Download most recently generated baseline images for a single platform, | |
116 and add any new ones to SVN control. | |
117 | |
118 @param baseline_subdir | |
119 """ | |
120 # Create repo_to_modify to handle the SVN repository we will add files to. | |
121 gm_dir = os.path.join(os.pardir, GM_EXPECTED_DIR) # Shouldn't assume we're i
n trunk... | |
122 try: | |
123 os.makedirs(gm_dir) | |
124 except: | |
125 pass | |
126 repo_to_modify = svn.Svn(gm_dir) | |
127 repo_to_modify.Checkout(GetBaselineSvnUrl(baseline_subdir), baseline_subdir) | |
128 | |
129 # If there are any locally modified files in that directory, exit | |
130 # (so that we don't risk overwriting the user's previous work). | |
131 new_and_modified_files = repo_to_modify.GetNewAndModifiedFiles() | |
132 if not options.ignore_local_mods: | |
133 if new_and_modified_files: | |
134 raise Exception('Exiting because there are already new and/or ' | |
135 'modified files in %s. To continue in spite of ' | |
136 'that, run with %s option.' % ( | |
137 baseline_subdir, OPTION_IGNORE_LOCAL_MODS)) | |
138 | |
139 # Download actual gm images into a separate repo in a temporary directory. | |
140 actual_dir = tempfile.mkdtemp() | |
141 actual_repo = svn.Svn(actual_dir) | |
142 print 'Using %s as a temp dir' % actual_dir | |
143 actual_url = GetLatestResultsSvnUrl(svn=actual_repo, baseline_subdir=baselin
e_subdir, | |
144 builder_suffix=options.builder_suffix) | |
145 print 'Reading actual buildbot GM results from %s' % actual_url | |
146 actual_repo.Checkout(actual_url, '.') | |
147 | |
148 # Copy any of those files we are interested in into repo_to_modify, | |
149 # and then delete the temporary directory. | |
150 CopyMatchingFiles(source_dir=actual_dir, | |
151 dest_dir=os.path.join(gm_dir, baseline_subdir), | |
152 filename_pattern='*.png', | |
153 only_copy_updates=(not options.add_new_files)) | |
154 shutil.rmtree(actual_dir) | |
155 actual_repo = None | |
156 | |
157 # Add any new files to SVN control (if we are running with add_new_files). | |
158 if options.add_new_files: | |
159 new_files = repo_to_modify.GetNewFiles() | |
160 if new_files: | |
161 repo_to_modify.AddFiles(sorted(new_files)) | |
162 | |
163 # Set the mimetype property on any new/modified image files in | |
164 # baseline_subdir. (We used to set the mimetype property on *all* image | |
165 # files in the directory, even those whose content wasn't changing, | |
166 # but that caused confusion. See | |
167 # http://code.google.com/p/skia/issues/detail?id=618 .) | |
168 modified_files = repo_to_modify.GetNewAndModifiedFiles() | |
169 repo_to_modify.SetProperty(sorted(fnmatch.filter(modified_files, '*.png')), | |
170 svn.PROPERTY_MIMETYPE, 'image/png') | |
171 repo_to_modify.SetProperty(sorted(fnmatch.filter(modified_files, '*.pdf')), | |
172 svn.PROPERTY_MIMETYPE, 'application/pdf') | |
173 | |
174 def RaiseUsageException(): | |
175 raise Exception('%s\nRun with --help for more detail.' % ( | |
176 USAGE_STRING % __file__)) | |
177 | |
178 def Main(options, args): | |
179 """Allow other scripts to call this script with fake command-line args. | |
180 """ | |
181 # If no platforms are specified, do 'em all. | |
182 num_args = len(args) | |
183 if num_args == 0: | |
184 # TODO(epoger): automate the default set of platforms. We want to ensure | |
185 # that the user gets all of the platforms that the bots are running, | |
186 # not just whatever subdirectories he happens to have checked out... | |
187 # See http://code.google.com/p/skia/issues/detail?id=678 | |
188 # Now that we have added Svn.ListSubdirs(), we should be able to do this | |
189 # pretty easily... | |
190 # | |
191 # For now, I generate this list using these Unix commands: | |
192 # svn ls http://skia.googlecode.com/svn/gm-expected | grep ^base | sort
>/tmp/baselines | |
193 # svn ls http://skia-autogen.googlecode.com/svn/gm-actual | grep ^base |
sort >/tmp/actual | |
194 # comm -1 -2 /tmp/baselines /tmp/actual | |
195 args = [ | |
196 'base-android-galaxy-nexus', | |
197 'base-android-nexus-7', | |
198 'base-android-nexus-s', | |
199 'base-android-xoom', | |
200 'base-macmini', | |
201 'base-macmini-lion-float', | |
202 'base-shuttle-win7-intel-float', | |
203 'base-shuttle_ubuntu12_ati5770', | |
204 'base-shuttle-win7-intel-angle', | |
205 'base-shuttle-win7-intel-directwrite', | |
206 ] | |
207 | |
208 # Trim all subdir names. | |
209 baseline_subdirs = [] | |
210 for arg in args: | |
211 baseline_subdirs.append(arg.rstrip(os.sep)) | |
212 | |
213 # Process the subdirs, one at a time. | |
214 for baseline_subdir in baseline_subdirs: | |
215 DownloadBaselinesForOnePlatform(baseline_subdir=baseline_subdir) | |
216 | |
217 if __name__ == '__main__': | |
218 parser = optparse.OptionParser(USAGE_STRING % '%prog' + HELP_STRING) | |
219 parser.add_option(OPTION_ADD_NEW_FILES, | |
220 action='store_true', default=False, | |
221 help='in addition to downloading new versions of ' | |
222 'existing baselines, also download baselines that are ' | |
223 'not under SVN control yet') | |
224 parser.add_option(OPTION_BUILDER_SUFFIX, | |
225 action='store', type='string', default=DEFAULT_BUILDER_SUF
FIX, | |
226 help='if multiple builders have uploaded actual GM images
' | |
227 'for this platform, download the images uploaded by the ' | |
228 'builder whose name ends in this suffix; defaults to ' | |
229 '"%s".' % DEFAULT_BUILDER_SUFFIX) | |
230 parser.add_option(OPTION_IGNORE_LOCAL_MODS, | |
231 action='store_true', default=False, | |
232 help='allow tool to run even if there are already ' | |
233 'local modifications in the baseline_subdir') | |
234 (options, args) = parser.parse_args() | |
235 Main(options, args) | |
OLD | NEW |