OLD | NEW |
---|---|
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # Copyright 2014 The Chromium Authors. All rights reserved. | 2 # Copyright 2014 The Chromium Authors. All rights reserved. |
3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
5 | 5 |
6 import skypy.paths | 6 import skypy.paths |
7 from skypy.skyserver import SkyServer | 7 from skypy.skyserver import SkyServer |
8 import argparse | 8 import argparse |
9 import json | 9 import json |
10 import logging | 10 import logging |
(...skipping 13 matching lines...) Expand all Loading... | |
24 from pylib import forwarder | 24 from pylib import forwarder |
25 | 25 |
26 | 26 |
27 SUPPORTED_MIME_TYPES = [ | 27 SUPPORTED_MIME_TYPES = [ |
28 'text/html', | 28 'text/html', |
29 'text/sky', | 29 'text/sky', |
30 'text/plain', | 30 'text/plain', |
31 ] | 31 ] |
32 | 32 |
33 DEFAULT_SKY_COMMAND_PORT = 7777 | 33 DEFAULT_SKY_COMMAND_PORT = 7777 |
34 GDB_PORT = 8888 | |
34 SKY_SERVER_PORT = 9999 | 35 SKY_SERVER_PORT = 9999 |
35 PID_FILE_PATH = "/tmp/skydb.pids" | 36 PID_FILE_PATH = "/tmp/skydb.pids" |
36 DEFAULT_URL = "https://raw.githubusercontent.com/domokit/mojo/master/sky/example s/home.sky" | 37 DEFAULT_URL = "https://raw.githubusercontent.com/domokit/mojo/master/sky/example s/home.sky" |
37 | 38 |
38 | 39 |
39 # FIXME: Move this into mopy.config | 40 # FIXME: Move this into mopy.config |
40 def gn_args_from_build_dir(build_dir): | 41 def gn_args_from_build_dir(build_dir): |
41 gn_cmd = [ | 42 gn_cmd = [ |
42 'gn', 'args', | 43 'gn', 'args', |
43 build_dir, | 44 build_dir, |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
125 | 126 |
126 def sky_server_for_args(self, args): | 127 def sky_server_for_args(self, args): |
127 # FIXME: This is a hack. sky_server should just take a build_dir | 128 # FIXME: This is a hack. sky_server should just take a build_dir |
128 # not a magical "configuration" name. | 129 # not a magical "configuration" name. |
129 configuration = os.path.basename(os.path.normpath(args.build_dir)) | 130 configuration = os.path.basename(os.path.normpath(args.build_dir)) |
130 server_root = self._server_root_for_url(args.url_or_path) | 131 server_root = self._server_root_for_url(args.url_or_path) |
131 sky_server = SkyServer(self.paths, SKY_SERVER_PORT, | 132 sky_server = SkyServer(self.paths, SKY_SERVER_PORT, |
132 configuration, server_root) | 133 configuration, server_root) |
133 return sky_server | 134 return sky_server |
134 | 135 |
136 def _create_paths_for_build_dir(self, build_dir): | |
137 # skypy.paths.Paths takes a root-relative build_dir argument. :( | |
138 abs_build_dir = os.path.abspath(build_dir) | |
139 root_relative_build_dir = os.path.relpath(abs_build_dir, SRC_ROOT) | |
140 return skypy.paths.Paths(root_relative_build_dir) | |
141 | |
135 def start_command(self, args): | 142 def start_command(self, args): |
136 # skypy.paths.Paths takes a root-relative build_dir argument. :( | |
137 build_dir = os.path.abspath(args.build_dir) | |
138 root_relative_build_dir = os.path.relpath(build_dir, SRC_ROOT) | |
139 # FIXME: Lame that we use self for a command-specific variable. | 143 # FIXME: Lame that we use self for a command-specific variable. |
140 self.paths = skypy.paths.Paths(root_relative_build_dir) | 144 self.paths = self._create_paths_for_build_dir(args.build_dir) |
141 | 145 |
142 self.stop_command(None) # Quit any existing process. | 146 self.stop_command(None) # Quit any existing process. |
143 self.pids = {} # Clear out our pid file. | 147 self.pids = {} # Clear out our pid file. |
144 | 148 |
145 # FIXME: This is probably not the right way to compute is_android | 149 # FIXME: This is probably not the right way to compute is_android |
146 # from the build directory? | 150 # from the build directory? |
147 gn_args = gn_args_from_build_dir(args.build_dir) | 151 gn_args = gn_args_from_build_dir(args.build_dir) |
148 is_android = 'android_sdk_version' in gn_args | 152 is_android = 'android_sdk_version' in gn_args |
149 | 153 |
150 sky_server = self.sky_server_for_args(args) | 154 sky_server = self.sky_server_for_args(args) |
(...skipping 16 matching lines...) Expand all Loading... | |
167 sky_server.port) | 171 sky_server.port) |
168 self.pids['remote_sky_server_port'] = device_http_port | 172 self.pids['remote_sky_server_port'] = device_http_port |
169 | 173 |
170 port_string = 'tcp:%s' % args.command_port | 174 port_string = 'tcp:%s' % args.command_port |
171 subprocess.check_call([ | 175 subprocess.check_call([ |
172 'adb', 'forward', port_string, port_string | 176 'adb', 'forward', port_string, port_string |
173 ]) | 177 ]) |
174 self.pids['remote_sky_command_port'] = args.command_port | 178 self.pids['remote_sky_command_port'] = args.command_port |
175 | 179 |
176 shell_command = self._build_mojo_shell_command(args) | 180 shell_command = self._build_mojo_shell_command(args) |
181 | |
182 # On android we can't launch inside gdb, but rather have to attach. | |
183 if args.gdb and not is_android: | |
184 shell_command = ['gdbserver', ':%s' % GDB_PORT] + shell_command | |
185 | |
177 print ' '.join(map(pipes.quote, shell_command)) | 186 print ' '.join(map(pipes.quote, shell_command)) |
178 self.pids['mojo_shell_pid'] = subprocess.Popen(shell_command).pid | 187 self.pids['mojo_shell_pid'] = subprocess.Popen(shell_command).pid |
179 | 188 |
180 if args.gdb: | 189 if args.gdb and is_android: |
181 print "Sorry, I'm not sure how best to wire up --gdb to work" | 190 gdbserver_cmd = ['gdbserver', '--attach', ':%s' % GDB_PORT] |
182 print "with mojo_shell as a background process. For now use:" | 191 self.pids['remote_gdbserver_pid'] = subprocess.Popen(shell_command). pid |
183 print "gdb --pid %s" % self.pids['mojo_shell_pid'] | |
184 shell_command = ['gdb'] + shell_command | |
185 | 192 |
186 if not self._wait_for_sky_command_port(): | 193 port_string = 'tcp:%s' % GDB_PORT |
187 logging.error('Failed to start sky') | 194 subprocess.check_call([ |
188 self.stop_command(None) | 195 'adb', 'forward', port_string, port_string |
196 ]) | |
197 self.pids['remote_gdbserver_port'] = GDB_PORT | |
198 | |
199 if not args.gdb: | |
200 if not self._wait_for_sky_command_port(): | |
201 logging.error('Failed to start sky') | |
202 self.stop_command(None) | |
203 else: | |
204 self.load_command(args) | |
189 else: | 205 else: |
190 self.load_command(args) | 206 print 'No load issued, connect with gdb first and then run load.' |
191 | 207 |
192 def _kill_if_exists(self, key, name): | 208 def _kill_if_exists(self, key, name): |
193 pid = self.pids.pop(key, None) | 209 pid = self.pids.pop(key, None) |
194 if not pid: | 210 if not pid: |
195 logging.info('No pid for %s, nothing to do.' % name) | 211 logging.info('No pid for %s, nothing to do.' % name) |
196 return | 212 return |
197 logging.info('Killing %s (%s).' % (name, pid)) | 213 logging.info('Killing %s (%s).' % (name, pid)) |
198 try: | 214 try: |
199 os.kill(pid, signal.SIGTERM) | 215 os.kill(pid, signal.SIGTERM) |
200 except OSError: | 216 except OSError: |
201 logging.info('%s (%s) already gone.' % (name, pid)) | 217 logging.info('%s (%s) already gone.' % (name, pid)) |
202 | 218 |
203 def stop_command(self, args): | 219 def stop_command(self, args): |
204 # TODO(eseidel): mojo_shell crashes when attempting graceful shutdown. | 220 # TODO(eseidel): mojo_shell crashes when attempting graceful shutdown. |
205 # self._send_command_to_sky('/quit') | 221 # self._send_command_to_sky('/quit') |
206 self._kill_if_exists('mojo_shell_pid', 'mojo_shell') | 222 self._kill_if_exists('mojo_shell_pid', 'mojo_shell') |
207 | 223 |
208 self._kill_if_exists('sky_server_pid', 'sky_server') | 224 self._kill_if_exists('sky_server_pid', 'sky_server') |
209 # We could be much more surgical here: | 225 # We could be much more surgical here: |
210 if 'remote_sky_command_port' in self.pids: | 226 if 'remote_sky_server_port' in self.pids: |
eseidel
2015/01/13 20:11:32
This was just checking for the wrong key. They bo
| |
211 device = android_commands.AndroidCommands( | 227 device = android_commands.AndroidCommands( |
212 self.pids['device_serial']) | 228 self.pids['device_serial']) |
213 forwarder.Forwarder.UnmapAllDevicePorts(device) | 229 forwarder.Forwarder.UnmapAllDevicePorts(device) |
214 | 230 |
215 if 'remote_sky_command_port' in self.pids: | 231 if 'remote_sky_command_port' in self.pids: |
216 # adb forward --remove takes the *host* port, not the remote port. | 232 # adb forward --remove takes the *host* port, not the remote port. |
217 port_string = 'tcp:%s' % self.pids['sky_command_port'] | 233 port_string = 'tcp:%s' % self.pids['sky_command_port'] |
218 subprocess.call(['adb', 'forward', '--remove', port_string]) | 234 subprocess.call(['adb', 'forward', '--remove', port_string]) |
219 | 235 |
236 if 'remote_gdbserver_port' in self.pids: | |
237 port_string = 'tcp:%s' % self.pids['remote_gdbserver_port'] | |
238 subprocess.call(['adb', 'forward', '--remove', port_string]) | |
239 | |
220 def load_command(self, args): | 240 def load_command(self, args): |
221 if not urlparse.urlparse(args.url_or_path).scheme: | 241 if not urlparse.urlparse(args.url_or_path).scheme: |
222 # The load happens on the remote device, use the remote port. | 242 # The load happens on the remote device, use the remote port. |
223 remote_sky_server_port = self.pids.get('remote_sky_server_port', | 243 remote_sky_server_port = self.pids.get('remote_sky_server_port', |
224 self.pids['sky_server_port']) | 244 self.pids['sky_server_port']) |
225 url = SkyServer.url_for_path(remote_sky_server_port, | 245 url = SkyServer.url_for_path(remote_sky_server_port, |
226 self.pids['sky_server_root'], args.url_or_path) | 246 self.pids['sky_server_root'], args.url_or_path) |
227 else: | 247 else: |
228 url = args.url_or_path | 248 url = args.url_or_path |
229 self._send_command_to_sky('/load', url) | 249 self._send_command_to_sky('/load', url) |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
280 def logcat_command(self, args): | 300 def logcat_command(self, args): |
281 TAGS = [ | 301 TAGS = [ |
282 'AndroidHandler', | 302 'AndroidHandler', |
283 'MojoMain', | 303 'MojoMain', |
284 'MojoShellActivity', | 304 'MojoShellActivity', |
285 'MojoShellApplication', | 305 'MojoShellApplication', |
286 'chromium', | 306 'chromium', |
287 ] | 307 ] |
288 subprocess.call(['adb', 'logcat', '-s'] + TAGS) | 308 subprocess.call(['adb', 'logcat', '-s'] + TAGS) |
289 | 309 |
310 def gdb_attach_command(self, args): | |
311 self.paths = self._create_paths_for_build_dir(self.pids['build_dir']) | |
312 gdb_command = [ | |
313 '/usr/bin/gdb', self.paths.mojo_shell_path, | |
314 '--eval-command', 'target remote localhost:%s' % GDB_PORT | |
315 ] | |
316 print " ".join(gdb_command) | |
317 # We don't want python listenting for signals or anything, so exec | |
318 # gdb and let it take the entire process. | |
319 os.execv(gdb_command[0], gdb_command) | |
320 | |
290 def main(self): | 321 def main(self): |
291 logging.basicConfig(level=logging.INFO) | 322 logging.basicConfig(level=logging.INFO) |
292 logging.getLogger("requests").setLevel(logging.WARNING) | 323 logging.getLogger("requests").setLevel(logging.WARNING) |
293 | 324 |
294 self.pids = self._load_pid_file(PID_FILE_PATH) | 325 self.pids = self._load_pid_file(PID_FILE_PATH) |
295 | 326 |
296 parser = argparse.ArgumentParser(description='Sky launcher/debugger') | 327 parser = argparse.ArgumentParser(description='Sky launcher/debugger') |
297 subparsers = parser.add_subparsers(help='sub-command help') | 328 subparsers = parser.add_subparsers(help='sub-command help') |
298 | 329 |
299 start_parser = subparsers.add_parser('start', | 330 start_parser = subparsers.add_parser('start', |
(...skipping 11 matching lines...) Expand all Loading... | |
311 start_parser.set_defaults(func=self.start_command) | 342 start_parser.set_defaults(func=self.start_command) |
312 | 343 |
313 stop_parser = subparsers.add_parser('stop', | 344 stop_parser = subparsers.add_parser('stop', |
314 help=('stop sky (as listed in %s)' % PID_FILE_PATH)) | 345 help=('stop sky (as listed in %s)' % PID_FILE_PATH)) |
315 stop_parser.set_defaults(func=self.stop_command) | 346 stop_parser.set_defaults(func=self.stop_command) |
316 | 347 |
317 logcat_parser = subparsers.add_parser('logcat', | 348 logcat_parser = subparsers.add_parser('logcat', |
318 help=('dump sky-related logs from device')) | 349 help=('dump sky-related logs from device')) |
319 logcat_parser.set_defaults(func=self.logcat_command) | 350 logcat_parser.set_defaults(func=self.logcat_command) |
320 | 351 |
352 gdb_attach_parser = subparsers.add_parser('gdb_attach', | |
353 help='launch gdb and attach to gdbserver launched from start --gdb') | |
354 gdb_attach_parser.set_defaults(func=self.gdb_attach_command) | |
355 | |
321 self._add_basic_command(subparsers, 'trace', '/trace', | 356 self._add_basic_command(subparsers, 'trace', '/trace', |
322 'toggle tracing') | 357 'toggle tracing') |
323 self._add_basic_command(subparsers, 'reload', '/reload', | 358 self._add_basic_command(subparsers, 'reload', '/reload', |
324 'reload the current page') | 359 'reload the current page') |
325 self._add_basic_command(subparsers, 'inspect', '/inspect', | 360 self._add_basic_command(subparsers, 'inspect', '/inspect', |
326 'stop the running sky instance') | 361 'stop the running sky instance') |
327 | 362 |
328 load_parser = subparsers.add_parser('load', | 363 load_parser = subparsers.add_parser('load', |
329 help='load a new page in the currently running sky') | 364 help='load a new page in the currently running sky') |
330 load_parser.add_argument('url_or_path', type=str) | 365 load_parser.add_argument('url_or_path', type=str) |
331 load_parser.set_defaults(func=self.load_command) | 366 load_parser.set_defaults(func=self.load_command) |
332 | 367 |
333 args = parser.parse_args() | 368 args = parser.parse_args() |
334 args.func(args) | 369 args.func(args) |
335 | 370 |
336 self._write_pid_file(PID_FILE_PATH, self.pids) | 371 self._write_pid_file(PID_FILE_PATH, self.pids) |
337 | 372 |
338 | 373 |
339 if __name__ == '__main__': | 374 if __name__ == '__main__': |
340 SkyDebugger().main() | 375 SkyDebugger().main() |
OLD | NEW |