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 from skypy.paths import 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 |
11 import os | 11 import os |
12 import pipes | 12 import pipes |
13 import requests | 13 import requests |
14 import signal | 14 import signal |
15 import subprocess | 15 import subprocess |
16 import sys | 16 import sys |
17 import time | 17 import time |
18 import urlparse | 18 import urlparse |
19 | 19 |
20 sys.path.insert(0, os.path.join(Paths('ignored').src_root, 'build', 'android')) | 20 SRC_ROOT = skypy.paths.Paths('ignored').src_root |
| 21 sys.path.insert(0, os.path.join(SRC_ROOT, 'build', 'android')) |
21 from pylib import android_commands | 22 from pylib import android_commands |
22 from pylib import constants | 23 from pylib import constants |
23 from pylib import forwarder | 24 from pylib import forwarder |
24 | 25 |
25 | 26 |
26 SUPPORTED_MIME_TYPES = [ | 27 SUPPORTED_MIME_TYPES = [ |
27 'text/html', | 28 'text/html', |
28 'text/sky', | 29 'text/sky', |
29 'text/plain', | 30 'text/plain', |
30 ] | 31 ] |
(...skipping 14 matching lines...) Expand all Loading... |
45 config = {} | 46 config = {} |
46 for line in subprocess.check_output(gn_cmd).strip().split('\n'): | 47 for line in subprocess.check_output(gn_cmd).strip().split('\n'): |
47 # FIXME: This doesn't handle = in values. | 48 # FIXME: This doesn't handle = in values. |
48 key, value = line.split(' = ') | 49 key, value = line.split(' = ') |
49 config[key] = value | 50 config[key] = value |
50 return config | 51 return config |
51 | 52 |
52 | 53 |
53 class SkyDebugger(object): | 54 class SkyDebugger(object): |
54 def __init__(self): | 55 def __init__(self): |
| 56 self.pids = {} |
55 self.paths = None | 57 self.paths = None |
56 self.pids = {} | |
57 | 58 |
58 def _server_root_for_url(self, url_or_path): | 59 def _server_root_for_url(self, url_or_path): |
59 path = os.path.abspath(url_or_path) | 60 path = os.path.abspath(url_or_path) |
60 if os.path.commonprefix([path, self.paths.src_root]) == self.paths.src_r
oot: | 61 if os.path.commonprefix([path, SRC_ROOT]) == SRC_ROOT: |
61 server_root = self.paths.src_root | 62 server_root = SRC_ROOT |
62 else: | 63 else: |
63 server_root = os.path.dirname(path) | 64 server_root = os.path.dirname(path) |
64 logging.warn( | 65 logging.warn( |
65 '%s is outside of mojo root, using %s as server root' % | 66 '%s is outside of mojo root, using %s as server root' % |
66 (path, server_root)) | 67 (path, server_root)) |
67 return server_root | 68 return server_root |
68 | 69 |
69 def _in_chromoting(self): | 70 def _in_chromoting(self): |
70 return os.environ.get('CHROME_REMOTE_DESKTOP_SESSION', False) | 71 return os.environ.get('CHROME_REMOTE_DESKTOP_SESSION', False) |
71 | 72 |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
109 if args.use_osmesa: | 110 if args.use_osmesa: |
110 shell_args.append('--args-for=mojo:native_viewport_service --use-osm
esa') | 111 shell_args.append('--args-for=mojo:native_viewport_service --use-osm
esa') |
111 | 112 |
112 if 'remote_sky_server_port' in self.pids: | 113 if 'remote_sky_server_port' in self.pids: |
113 shell_command = self._wrap_for_android(shell_args) | 114 shell_command = self._wrap_for_android(shell_args) |
114 else: | 115 else: |
115 shell_command = [self.paths.mojo_shell_path] + shell_args | 116 shell_command = [self.paths.mojo_shell_path] + shell_args |
116 | 117 |
117 # FIXME: This doesn't work for android | 118 # FIXME: This doesn't work for android |
118 if args.gdb: | 119 if args.gdb: |
119 shell_command = ['gdb', '--args'] + shell_command | 120 shell_command = ['gdb'] + shell_command |
120 | 121 |
121 return shell_command | 122 return shell_command |
122 | 123 |
123 def _connect_to_device(self): | 124 def _connect_to_device(self): |
124 device = android_commands.AndroidCommands( | 125 device = android_commands.AndroidCommands( |
125 android_commands.GetAttachedDevices()[0]) | 126 android_commands.GetAttachedDevices()[0]) |
126 device.EnableAdbRoot() | 127 device.EnableAdbRoot() |
127 return device | 128 return device |
128 | 129 |
129 def sky_server_for_args(self, args): | 130 def sky_server_for_args(self, args): |
130 # FIXME: This is a hack. sky_server should just take a build_dir | 131 # FIXME: This is a hack. sky_server should just take a build_dir |
131 # not a magical "configuration" name. | 132 # not a magical "configuration" name. |
132 configuration = os.path.basename(os.path.normpath(args.build_dir)) | 133 configuration = os.path.basename(os.path.normpath(args.build_dir)) |
133 server_root = self._server_root_for_url(args.url_or_path) | 134 server_root = self._server_root_for_url(args.url_or_path) |
134 sky_server = SkyServer(self.paths, SKY_SERVER_PORT, | 135 sky_server = SkyServer(self.paths, SKY_SERVER_PORT, |
135 configuration, server_root) | 136 configuration, server_root) |
136 return sky_server | 137 return sky_server |
137 | 138 |
138 def start_command(self, args): | 139 def start_command(self, args): |
| 140 # skypy.paths.Paths takes a root-relative build_dir argument. :( |
| 141 build_dir = os.path.abspath(args.build_dir) |
| 142 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 = Paths(args.build_dir) | 144 self.paths = skypy.paths.Paths(root_relative_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 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
188 if not pid: | 192 if not pid: |
189 logging.info('No pid for %s, nothing to do.' % name) | 193 logging.info('No pid for %s, nothing to do.' % name) |
190 return | 194 return |
191 logging.info('Killing %s (%s).' % (name, pid)) | 195 logging.info('Killing %s (%s).' % (name, pid)) |
192 try: | 196 try: |
193 os.kill(pid, signal.SIGTERM) | 197 os.kill(pid, signal.SIGTERM) |
194 except OSError: | 198 except OSError: |
195 logging.info('%s (%s) already gone.' % (name, pid)) | 199 logging.info('%s (%s) already gone.' % (name, pid)) |
196 | 200 |
197 def stop_command(self, args): | 201 def stop_command(self, args): |
198 try: | 202 # TODO(eseidel): mojo_shell crashes when attempting graceful shutdown. |
199 self._send_command_to_sky('/quit') | 203 # self._send_command_to_sky('/quit') |
200 except: | |
201 pass | |
202 # Kill the mojo process for good measure. :) | |
203 self._kill_if_exists('mojo_shell_pid', 'mojo_shell') | 204 self._kill_if_exists('mojo_shell_pid', 'mojo_shell') |
204 | 205 |
205 self._kill_if_exists('sky_server_pid', 'sky_server') | 206 self._kill_if_exists('sky_server_pid', 'sky_server') |
206 # We could be much more surgical here: | 207 # We could be much more surgical here: |
207 if 'remote_sky_command_port' in self.pids: | 208 if 'remote_sky_command_port' in self.pids: |
208 device = android_commands.AndroidCommands( | 209 device = android_commands.AndroidCommands( |
209 self.pids['device_serial']) | 210 self.pids['device_serial']) |
210 forwarder.Forwarder.UnmapAllDevicePorts(device) | 211 forwarder.Forwarder.UnmapAllDevicePorts(device) |
211 | 212 |
212 if 'remote_sky_command_port' in self.pids: | 213 if 'remote_sky_command_port' in self.pids: |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
267 return True | 268 return True |
268 except: | 269 except: |
269 tries += 1 | 270 tries += 1 |
270 if tries == 3: | 271 if tries == 3: |
271 logging.warn('Still waiting for sky on port %s' % | 272 logging.warn('Still waiting for sky on port %s' % |
272 self.pids['sky_command_port']) | 273 self.pids['sky_command_port']) |
273 if tries > 10: | 274 if tries > 10: |
274 return False | 275 return False |
275 time.sleep(1) | 276 time.sleep(1) |
276 | 277 |
| 278 def logcat_command(self, args): |
| 279 TAGS = [ |
| 280 'AndroidHandler', |
| 281 'MojoMain', |
| 282 'MojoShellActivity', |
| 283 'MojoShellApplication', |
| 284 'chromium', |
| 285 ] |
| 286 subprocess.call(['adb', 'logcat', '-s'] + TAGS) |
| 287 |
277 def main(self): | 288 def main(self): |
278 logging.basicConfig(level=logging.INFO) | 289 logging.basicConfig(level=logging.INFO) |
279 logging.getLogger("requests").setLevel(logging.WARNING) | 290 logging.getLogger("requests").setLevel(logging.WARNING) |
280 | 291 |
281 self.pids = self._load_pid_file(PID_FILE_PATH) | 292 self.pids = self._load_pid_file(PID_FILE_PATH) |
282 | 293 |
283 parser = argparse.ArgumentParser(description='Sky launcher/debugger') | 294 parser = argparse.ArgumentParser(description='Sky launcher/debugger') |
284 subparsers = parser.add_subparsers(help='sub-command help') | 295 subparsers = parser.add_subparsers(help='sub-command help') |
285 | 296 |
286 start_parser = subparsers.add_parser('start', | 297 start_parser = subparsers.add_parser('start', |
287 help='launch a new mojo_shell with sky') | 298 help='launch a new mojo_shell with sky') |
288 start_parser.add_argument('--gdb', action='store_true') | 299 start_parser.add_argument('--gdb', action='store_true') |
289 start_parser.add_argument('--command-port', type=int, | 300 start_parser.add_argument('--command-port', type=int, |
290 default=DEFAULT_SKY_COMMAND_PORT) | 301 default=DEFAULT_SKY_COMMAND_PORT) |
291 start_parser.add_argument('--use-osmesa', action='store_true', | 302 start_parser.add_argument('--use-osmesa', action='store_true', |
292 default=self._in_chromoting()) | 303 default=self._in_chromoting()) |
293 start_parser.add_argument('build_dir', type=str) | 304 start_parser.add_argument('build_dir', type=str) |
294 start_parser.add_argument('url_or_path', nargs='?', type=str, | 305 start_parser.add_argument('url_or_path', nargs='?', type=str, |
295 default=DEFAULT_URL) | 306 default=DEFAULT_URL) |
296 start_parser.add_argument('--show-command', action='store_true', | 307 start_parser.add_argument('--show-command', action='store_true', |
297 help='Display the shell command and exit') | 308 help='Display the shell command and exit') |
298 start_parser.set_defaults(func=self.start_command) | 309 start_parser.set_defaults(func=self.start_command) |
299 | 310 |
300 stop_parser = subparsers.add_parser('stop', | 311 stop_parser = subparsers.add_parser('stop', |
301 help=('stop sky (as listed in %s)' % PID_FILE_PATH)) | 312 help=('stop sky (as listed in %s)' % PID_FILE_PATH)) |
302 stop_parser.set_defaults(func=self.stop_command) | 313 stop_parser.set_defaults(func=self.stop_command) |
303 | 314 |
| 315 logcat_parser = subparsers.add_parser('logcat', |
| 316 help=('dump sky-related logs from device')) |
| 317 logcat_parser.set_defaults(func=self.logcat_command) |
| 318 |
304 self._add_basic_command(subparsers, 'trace', '/trace', | 319 self._add_basic_command(subparsers, 'trace', '/trace', |
305 'toggle tracing') | 320 'toggle tracing') |
306 self._add_basic_command(subparsers, 'reload', '/reload', | 321 self._add_basic_command(subparsers, 'reload', '/reload', |
307 'reload the current page') | 322 'reload the current page') |
308 self._add_basic_command(subparsers, 'inspect', '/inspect', | 323 self._add_basic_command(subparsers, 'inspect', '/inspect', |
309 'stop the running sky instance') | 324 'stop the running sky instance') |
310 | 325 |
311 load_parser = subparsers.add_parser('load', | 326 load_parser = subparsers.add_parser('load', |
312 help='load a new page in the currently running sky') | 327 help='load a new page in the currently running sky') |
313 load_parser.add_argument('url_or_path', type=str) | 328 load_parser.add_argument('url_or_path', type=str) |
314 load_parser.set_defaults(func=self.load_command) | 329 load_parser.set_defaults(func=self.load_command) |
315 | 330 |
316 args = parser.parse_args() | 331 args = parser.parse_args() |
317 args.func(args) | 332 args.func(args) |
318 | 333 |
319 self._write_pid_file(PID_FILE_PATH, self.pids) | 334 self._write_pid_file(PID_FILE_PATH, self.pids) |
320 | 335 |
321 | 336 |
322 if __name__ == '__main__': | 337 if __name__ == '__main__': |
323 SkyDebugger().main() | 338 SkyDebugger().main() |
OLD | NEW |