OLD | NEW |
---|---|
(Empty) | |
1 #!/usr/bin/env python | |
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
3 # Use of this source code is governed by a BSD-style license that can be | |
4 # found in the LICENSE file. | |
5 | |
6 """Automate the setup process of Chrome Endure environment. | |
7 | |
8 Usage: | |
9 python endure_setup.py [option] | |
10 | |
11 We use <ENDURE_DIR> to refer to the root directory in which Chrome Endure | |
12 is set up. By default, <ENDURE_DIR> is the current working directory. | |
13 | |
14 First, run "python endure_setup.py". This command will automatically setup | |
15 Chrome Endure in <ENDURE_DIR>. | |
16 | |
17 Next, run your first endure test by: | |
18 TEST_LENGTH=30 LOCAL_GRAPH="<ENDURE_DIR>/chrome_graph" \\ | |
dennis_jeffrey
2012/08/15 17:53:08
should LOCAL_GRAPH be LOCAL_PERF_DIR?
fdeng1
2012/08/17 00:26:10
Thanks for catching it.
Done.
| |
19 python <ENDURE_DIR>/src/chrome/test/functional/perf_endure.py \\ | |
20 perf_endure.ChromeEndureGmailTest.testGmailComposeDiscard \\ | |
21 The above commands runs a Chrome Endure test for 30 seconds and saves | |
22 the results to <ENDURE_DIR>/chrome_graph. | |
23 | |
24 Last, to view the graphs, run another script endure_server.py | |
25 within <ENDURE_DIR> to start a local HTTP server that serves | |
26 the graph directory, see endure_server.py for details. | |
27 | |
28 Use python endure_setup.py --help for more options. | |
29 | |
30 This script depends on the following modules | |
31 (which will be downloaded automatically): | |
32 depot_tools | |
33 src/chrome/test/pyautolib/fetch_prebuilt_pyauto.py | |
34 """ | |
35 | |
36 import logging | |
37 import optparse | |
38 import os | |
39 import platform | |
40 import shutil | |
41 import subprocess | |
42 import sys | |
43 import urllib | |
44 import urllib2 | |
45 import zipfile | |
46 | |
47 | |
48 class SetupError(Exception): | |
49 """Catch errors in setting up Chrome Endure.""" | |
50 pass | |
51 | |
52 | |
53 class HelpFormatter(optparse.IndentedHelpFormatter): | |
54 """Format the help message of this script.""" | |
55 | |
56 def format_description(self, description): | |
dennis_jeffrey
2012/08/15 17:53:08
add a comment explaining why you're overriding thi
fdeng1
2012/08/17 00:26:10
Done.
| |
57 if description: | |
58 return description + '\n' | |
59 else: | |
60 return '' | |
dennis_jeffrey
2012/08/15 17:53:08
similar comment as in the other file: i think this
fdeng1
2012/08/17 00:26:10
Done.
| |
61 | |
62 | |
63 class CmdFetch(object): | |
dennis_jeffrey
2012/08/15 17:53:08
this probably doesn't need to be a class. There's
fdeng1
2012/08/17 00:26:10
Done.
| |
64 """Fetch Chrome Endure. | |
65 | |
66 Usage: | |
67 python endure_setup.py [options] | |
68 | |
69 Examples: | |
70 python endure_setup.py | |
dennis_jeffrey
2012/08/15 17:53:08
similar comment as in the other file: add a > at t
fdeng1
2012/08/17 00:26:10
Done.
| |
71 Fetch the latest version of Chrome Endure to the current | |
72 working directory. | |
73 | |
74 python endure_setup.py --endure-dir=/home/user/endure_dir | |
dennis_jeffrey
2012/08/15 17:53:08
same comment as line 70 above
fdeng1
2012/08/17 00:26:10
Done.
| |
75 Fetch the latest version of Chrome Endure to /home/user/endure_dir. | |
76 """ | |
77 _URLS = {'depot_tools': ('http://src.chromium.org' | |
78 '/chrome/trunk/tools/depot_tools'), | |
79 'pyauto': ('https://src.chromium.org/' | |
80 'chrome/trunk/src/chrome/test/functional.DEPS'), | |
81 'binary': ('http://commondatastorage.googleapis.com/' | |
82 'chromium-browser-continuous/{os_type}/{revision}'), | |
83 # TODO(fdeng): change to an external address after graph code | |
84 # is checked in | |
85 'graph': ('http://www.corp.google.com/' | |
86 '~dennisjeffrey/chrome_perf/local_graphs.zip'), | |
dennis_jeffrey
2012/08/15 17:53:08
for now, let's remove this directory from the scri
fdeng1
2012/08/17 00:26:10
Add an option --graph-zip-url.
If not specified, w
| |
87 } | |
88 | |
89 def _ParseArgs(self, argv): | |
90 parser = optparse.OptionParser( | |
91 formatter=HelpFormatter(), | |
92 description=self.__doc__) | |
93 parser.add_option( | |
94 '-d', '--endure-dir', type='string', default=os.getcwd(), | |
95 help='Directory in which to setup or update. ' \ | |
96 'Default value is the current working directory.') | |
97 return parser.parse_args(argv) | |
98 | |
99 def Run(self, argv): | |
100 """Run this command.""" | |
101 options, _ = self._ParseArgs(argv) | |
102 self._endure_dir = os.path.abspath(options.endure_dir) | |
103 self._depot_dir = os.path.join(self._endure_dir, 'depot_tools') | |
104 self._os_type = self._GetCurrentOSType() | |
105 if self._os_type == 'Win': | |
106 self._gclient = os.path.join(self._depot_dir, 'gclient.bat') | |
fdeng1
2012/08/14 19:14:20
I haven't got a chance to test this script on othe
dennis_jeffrey
2012/08/15 17:53:08
Let's assume for now that it's only going to run o
fdeng1
2012/08/17 00:26:10
Ok, it now checks whether the system is Linux and
| |
107 else: | |
108 self._gclient = os.path.join(self._depot_dir, 'gclient') | |
109 self._fetch_py = os.path.join(self._endure_dir, 'src', 'chrome', | |
110 'test', 'pyautolib', | |
111 'fetch_prebuilt_pyauto.py') | |
112 self._binary_dir = os.path.join(self._endure_dir, 'src', 'out', 'Release') | |
113 self._graph_dir = os.path.join(self._endure_dir, 'chrome_graph') | |
114 | |
115 if not os.path.isdir(self._endure_dir): | |
116 os.makedirs(self._endure_dir) | |
117 | |
118 logging.info('Fetching depot tools...') | |
119 self._FetchDepot() | |
120 logging.info('Fetching PyAuto (python code)...') | |
121 self._FetchPyAuto() | |
122 logging.info('Fetching binaries(chrome, pyautolib, chrome driver)...') | |
123 self._FetchBinaries() | |
124 # TODO(fdeng): remove this after it is check into the chrome tree. | |
125 logging.info('Fetching chrome graphing files...') | |
126 self._FetchGraph() | |
127 return 0 | |
128 | |
129 def _FetchDepot(self): | |
130 """Fetch depot_tools.""" | |
131 if self._CheckDepot(): | |
132 return | |
133 else: | |
dennis_jeffrey
2012/08/15 17:53:08
maybe we can just remove the above 3 lines and alw
fdeng1
2012/08/17 00:26:10
Done.
| |
134 subprocess.call(['svn', 'co', self._URLS['depot_tools'], | |
135 self._depot_dir]) | |
136 if not self._CheckDepot(): | |
137 raise SetupError('Could not get depot_tools.') | |
138 | |
139 def _CheckDepot(self): | |
140 """Check that some known depot_tools files exist. | |
141 | |
142 Returns: | |
143 True if check passes otherwise False. | |
144 """ | |
145 gclient_py = os.path.join(self._depot_dir, 'gclient.py') | |
146 files = [self._gclient, gclient_py] | |
147 for f in files: | |
148 if not os.path.exists(f): | |
149 return False | |
150 try: | |
151 subprocess.call([self._gclient, '--version']) | |
152 except OSError: | |
153 return False | |
154 return True | |
155 | |
156 def _FetchPyAuto(self): | |
157 """Use gclient to fetch python code.""" | |
158 cur_dir = os.getcwd() | |
159 os.chdir(self._endure_dir) | |
160 # gclient config | |
161 config_cmd = [self._gclient, 'config', self._URLS['pyauto']] | |
162 code = subprocess.call(config_cmd) | |
163 if code != 0: | |
dennis_jeffrey
2012/08/15 17:53:08
can just get rid of the "code" variable:
if subpr
fdeng1
2012/08/17 00:26:10
Done.
| |
164 raise SetupError('Running "%s" failed.' % ' '.join(config_cmd)) | |
165 # gclient sync | |
166 sync_cmd = [self._gclient, 'sync'] | |
167 code = subprocess.call(sync_cmd) | |
168 if code != 0: | |
dennis_jeffrey
2012/08/15 17:53:08
same comment as line 163 above
fdeng1
2012/08/17 00:26:10
Done.
| |
169 raise SetupError('Running "%s" failed.' % ' '.join(sync_cmd)) | |
170 self._CheckPyAuto() | |
171 logging.info('Sync PyAuto python code done.') | |
172 os.chdir(cur_dir) | |
173 | |
174 def _CheckPyAuto(self): | |
175 pyauto_py = os.path.join(self._endure_dir, 'src', | |
176 'chrome', 'test', | |
177 'pyautolib', 'pyauto.py') | |
178 files = [self._fetch_py, pyauto_py] | |
179 for f in files: | |
180 if not os.path.exists(f): | |
181 raise SetupError('Checking %s failed.' % f) | |
182 | |
183 def _FetchBinaries(self): | |
184 """Get the prebuilt binaries from continuous build archive.""" | |
185 revision = self._GetLatestRevision(self._os_type) | |
186 logging.info('Cleaning %s', self._binary_dir) | |
187 if os.path.exists(self._binary_dir): | |
188 shutil.rmtree(self._binary_dir) | |
189 logging.info('Downloading binaries...') | |
190 cmd = [self._fetch_py, '-d', self._binary_dir, | |
191 self._URLS['binary'].format( | |
192 os_type=self._os_type, revision=revision)] | |
193 code = subprocess.call(cmd) | |
194 if code == 0: | |
dennis_jeffrey
2012/08/15 17:53:08
same comment as line 163 above
fdeng1
2012/08/17 00:26:10
Done.
| |
195 logging.info('Binaries at revision %s', revision) | |
196 else: | |
197 raise SetupError('Running "%s" failed.' % ' '.join(cmd)) | |
198 | |
199 def _FetchGraph(self): | |
200 """Fetch graph code.""" | |
201 graph_zip = urllib.urlretrieve(self._URLS['graph'])[0] | |
202 if graph_zip is None or not os.path.exists(graph_zip): | |
203 raise SetupError('Unable to retrieve %s' % self._URLS['graph']) | |
204 if not os.path.exists(self._graph_dir): | |
205 os.mkdir(self._graph_dir) | |
206 self._UnzipFilenameToDir(graph_zip, self._graph_dir) | |
207 logging.info('Graph code is downloaded to %s', self._graph_dir) | |
208 | |
209 def _GetCurrentOSType(self): | |
210 """Get a string representation for the current os. | |
dennis_jeffrey
2012/08/15 17:53:08
nit: os --> OS
fdeng1
2012/08/17 00:26:10
Done.
| |
211 | |
212 Returns: | |
213 'Mac', 'Win', 'Linux', or 'Linux_64' | |
214 Raises: | |
dennis_jeffrey
2012/08/15 17:53:08
add a blank line right above this
fdeng1
2012/08/17 00:26:10
Done.
| |
215 RuntimeError: if os can't be identified. | |
dennis_jeffrey
2012/08/15 17:53:08
nit: os --> OS
fdeng1
2012/08/17 00:26:10
Done.
| |
216 """ | |
217 if sys.platform == 'darwin': | |
218 os_type = 'Mac' | |
219 if sys.platform == 'win32': | |
220 os_type = 'Win' | |
221 if sys.platform.startswith('linux'): | |
222 os_type = 'Linux' | |
223 if platform.architecture()[0] == '64bit': | |
224 os_type += '_x64' | |
225 else: | |
226 raise RuntimeError('Unknown platform') | |
227 return os_type | |
228 | |
229 def _GetLatestRevision(self, os_type): | |
230 """Figure out the latest revision number of the prebuilt binary archive. | |
231 | |
232 Args: | |
233 os_type: 'Mac', 'Win', 'Linux', or 'Linux_64' | |
234 | |
235 Returns: | |
236 A string of latest revision number. | |
237 | |
238 Raises: | |
239 SetupError: if unable to get the latest revision number. | |
240 """ | |
241 last_change_url = ('http://commondatastorage.googleapis.com/' | |
242 'chromium-browser-continuous/%s/LAST_CHANGE' % os_type) | |
243 response = urllib2.urlopen(last_change_url) | |
244 last_change = response.read() | |
245 if not last_change: | |
246 raise SetupError('Unable to get the latest revision number from %s' % | |
dennis_jeffrey
2012/08/15 17:53:08
remove one of the spaces in "get the"
fdeng1
2012/08/17 00:26:10
Done.
| |
247 last_change_url) | |
248 return last_change | |
249 | |
250 @classmethod | |
251 def _UnzipFilenameToDir(cls, filename, directory): | |
dennis_jeffrey
2012/08/15 17:53:08
This function will probably go away as soon as the
fdeng1
2012/08/17 00:26:10
Done.
| |
252 """Unzip |filename| to directory |directory|. | |
253 | |
254 This works with as low as python2.4 (used on win). | |
255 (Code is adapted from fetch_prebuilt_pyauto.py) | |
256 """ | |
257 zf = zipfile.ZipFile(filename) | |
258 pushd = os.getcwd() | |
259 if not os.path.isdir(directory): | |
260 os.mkdir(directory) | |
261 os.chdir(directory) | |
262 # Extract files. | |
263 for info in zf.infolist(): | |
264 name = info.filename | |
265 if name.endswith('/'): # dir | |
266 if not os.path.isdir(name): | |
267 os.makedirs(name) | |
268 else: # file | |
269 directory = os.path.dirname(name) | |
270 if directory and not os.path.isdir(directory): | |
271 os.makedirs(directory) | |
272 out = open(name, 'wb') | |
273 out.write(zf.read(name)) | |
274 out.close() | |
275 # Set permissions. Permission info in external_attr is shifted 16 bits. | |
276 os.chmod(name, info.external_attr >> 16L) | |
277 os.chdir(pushd) | |
278 | |
279 | |
280 def Main(argv): | |
281 command = CmdFetch() | |
282 return command.Run(argv) | |
283 | |
284 | |
285 if '__main__' == __name__: | |
286 logging.basicConfig(format='[%(levelname)s] %(message)s', level=logging.DEBUG) | |
287 sys.exit(Main(sys.argv[1:])) | |
OLD | NEW |