Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(323)

Side by Side Diff: gm/rebaseline_server/download_actuals.py

Issue 143653006: new tool: download all GM images for a given builder, ready for skdiff (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: more rmistry comments Created 6 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « gm/gm_json.py ('k') | gm/rebaseline_server/download_actuals_test.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 #!/usr/bin/python
2
3 """
4 Copyright 2014 Google Inc.
5
6 Use of this source code is governed by a BSD-style license that can be
7 found in the LICENSE file.
8
9 Download actual GM results for a particular builder.
10 """
11
12 # System-level imports
13 import contextlib
14 import optparse
15 import os
16 import posixpath
17 import re
18 import shutil
19 import sys
20 import urllib
21 import urllib2
22 import urlparse
23
24 # Imports from within Skia
25 #
26 # We need to add the 'gm' and 'tools' directories, so that we can import
27 # gm_json.py and buildbot_globals.py.
28 #
29 # Make sure that these dirs are in the PYTHONPATH, but add them at the *end*
30 # so any dirs that are already in the PYTHONPATH will be preferred.
31 #
32 # TODO(epoger): Is it OK for this to depend on the 'tools' dir, given that
33 # the tools dir is dependent on the 'gm' dir (to import gm_json.py)?
34 TRUNK_DIRECTORY = os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
35 GM_DIRECTORY = os.path.join(TRUNK_DIRECTORY, 'gm')
36 TOOLS_DIRECTORY = os.path.join(TRUNK_DIRECTORY, 'tools')
37 if GM_DIRECTORY not in sys.path:
38 sys.path.append(GM_DIRECTORY)
39 if TOOLS_DIRECTORY not in sys.path:
40 sys.path.append(TOOLS_DIRECTORY)
41 import buildbot_globals
42 import gm_json
43
44 DEFAULT_ACTUALS_BASE_URL = posixpath.join(
45 buildbot_globals.Get('autogen_svn_url'), 'gm-actual')
46 DEFAULT_JSON_FILENAME = 'actual-results.json'
47
48
49 class Download(object):
50
51 def __init__(self, actuals_base_url=DEFAULT_ACTUALS_BASE_URL,
52 json_filename=DEFAULT_JSON_FILENAME,
53 gm_actuals_root_url=gm_json.GM_ACTUALS_ROOT_HTTP_URL):
54 """
55 Args:
56 actuals_base_url: URL pointing at the root directory
57 containing all actual-results.json files, e.g.,
58 http://domain.name/path/to/dir OR
59 file:///absolute/path/to/localdir
60 json_filename: The JSON filename to read from within each directory.
61 gm_actuals_root_url: Base URL under which the actually-generated-by-bots
62 GM images are stored.
63 """
64 self._actuals_base_url = actuals_base_url
65 self._json_filename = json_filename
66 self._gm_actuals_root_url = gm_actuals_root_url
67 self._image_filename_re = re.compile(gm_json.IMAGE_FILENAME_PATTERN)
68
69 def fetch(self, builder_name, dest_dir):
70 """ Downloads actual GM results for a particular builder.
71
72 Args:
73 builder_name: which builder to download results of
74 dest_dir: path to directory where the image files will be written;
75 if the directory does not exist yet, it will be created
76
77 TODO(epoger): Display progress info. Right now, it can take a long time
78 to download all of the results, and there is no indication of progress.
79
80 TODO(epoger): Download multiple images in parallel to speed things up.
81 """
82 json_url = posixpath.join(self._actuals_base_url, builder_name,
83 self._json_filename)
84 json_contents = urllib2.urlopen(json_url).read()
85 results_dict = gm_json.LoadFromString(json_contents)
86
87 actual_results_dict = results_dict[gm_json.JSONKEY_ACTUALRESULTS]
88 for result_type in sorted(actual_results_dict.keys()):
89 results_of_this_type = actual_results_dict[result_type]
90 if not results_of_this_type:
91 continue
92 for image_name in sorted(results_of_this_type.keys()):
93 (test, config) = self._image_filename_re.match(image_name).groups()
94 (hash_type, hash_digest) = results_of_this_type[image_name]
95 source_url = gm_json.CreateGmActualUrl(
96 test_name=test, hash_type=hash_type, hash_digest=hash_digest,
97 gm_actuals_root_url=self._gm_actuals_root_url)
98 dest_path = os.path.join(dest_dir, config, test + '.png')
99 copy_contents(source_url=source_url, dest_path=dest_path,
100 create_subdirs_if_needed=True)
101
102
103 def create_filepath_url(filepath):
rmistry 2014/01/24 18:07:35 I do not see this used in this module, it is here
epoger 2014/01/24 18:23:50 Yes. Added a comment along those lines.
104 """ Returns a file:/// URL pointing at the given filepath on local disk.
105
106 Args:
107 filepath: string; path to a file on local disk (may be absolute or relative,
108 and the file does not need to exist)
109
110 Returns:
111 A file:/// URL pointing at the file. Regardless of whether filepath was
112 specified as a relative or absolute path, the URL will contain an
113 absolute path to the file.
114
115 Raises:
116 An Exception, if filepath is already a URL.
117 """
118 if urlparse.urlparse(filepath).scheme:
119 raise Exception('"%s" is already a URL' % filepath)
120 return urlparse.urljoin(
121 'file:', urllib.pathname2url(os.path.abspath(filepath)))
122
rmistry 2014/01/24 18:07:35 nit: add an extra newline
epoger 2014/01/24 18:23:50 Done.
123 def copy_contents(source_url, dest_path, create_subdirs_if_needed=False):
124 """ Copies the full contents of the URL 'source_url' into
125 filepath 'dest_path'.
126
127 Args:
128 source_url: string; complete URL to read from
129 dest_path: string; complete filepath to write to (may be absolute or
130 relative)
131 create_subdirs_if_needed: boolean; whether to create subdirectories as
132 needed to create dest_path
133
134 Raises:
135 Some subclass of Exception if unable to read source_url or write dest_path.
136 """
137 if create_subdirs_if_needed:
138 dest_dir = os.path.dirname(dest_path)
139 if not os.path.exists(dest_dir):
140 os.makedirs(dest_dir)
141 with contextlib.closing(urllib.urlopen(source_url)) as source_handle:
142 with open(dest_path, 'wb') as dest_handle:
143 shutil.copyfileobj(fsrc=source_handle, fdst=dest_handle)
144
rmistry 2014/01/24 18:07:35 nit: add an extra newline
epoger 2014/01/24 18:23:50 Done.
145 def main():
146 parser = optparse.OptionParser()
147 required_params = []
148 parser.add_option('--actuals-base-url',
149 action='store', type='string',
150 default=DEFAULT_ACTUALS_BASE_URL,
151 help=('Base URL from which to read files containing JSON '
152 'summaries of actual GM results; defaults to '
153 '"%default". To get a specific revision (useful for '
154 'trybots) replace "svn" with "svn-history/r123".'))
155 # TODO(epoger): Rather than telling the user to run "svn ls" to get the list
156 # of builders, add a --list-builders option that will print the list.
157 required_params.append('builder')
158 parser.add_option('--builder',
159 action='store', type='string',
160 help=('REQUIRED: Which builder to download results for. '
161 'To see a list of builders, run "svn ls %s".' %
162 DEFAULT_ACTUALS_BASE_URL))
163 required_params.append('dest_dir')
164 parser.add_option('--dest-dir',
165 action='store', type='string',
166 help=('REQUIRED: Directory where all images should be '
167 'written. If this directory does not exist yet, it '
168 'will be created.'))
169 parser.add_option('--json-filename',
170 action='store', type='string',
171 default=DEFAULT_JSON_FILENAME,
172 help=('JSON summary filename to read for each builder; '
173 'defaults to "%default".'))
174 (params, remaining_args) = parser.parse_args()
175
176 # Make sure all required options were set,
177 # and that there were no items left over in the command line.
178 for required_param in required_params:
179 if not getattr(params, required_param):
180 raise Exception('required option \'%s\' was not set' % required_param)
181 if len(remaining_args) is not 0:
182 raise Exception('extra items specified in the command line: %s' %
183 remaining_args)
184
185 downloader = Download(actuals_base_url=params.actuals_base_url)
186 downloader.fetch(builder_name=params.builder,
187 dest_dir=params.dest_dir)
188
189
190
191 if __name__ == '__main__':
192 main()
OLDNEW
« no previous file with comments | « gm/gm_json.py ('k') | gm/rebaseline_server/download_actuals_test.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698