Chromium Code Reviews| 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 |