Index: sky/tools/skydb |
diff --git a/sky/tools/skydb b/sky/tools/skydb |
index a84db8782d5ab21627ccbd25ba1d37ab7c162f2d..ff906784fa7b2396051e73ed64664dafc4d62012 100755 |
--- a/sky/tools/skydb |
+++ b/sky/tools/skydb |
@@ -9,12 +9,18 @@ import argparse |
import json |
import logging |
import os |
+import pipes |
import requests |
import signal |
-import skypy.configuration as configuration |
import subprocess |
-import urlparse |
+import sys |
import time |
+import urlparse |
+ |
+sys.path.insert(0, os.path.join(Paths('ignored').src_root, 'build', 'android')) |
eseidel
2015/01/09 22:58:50
As I note in the description, we could *almost* re
|
+from pylib import android_commands |
+from pylib import constants |
+from pylib import forwarder |
SUPPORTED_MIME_TYPES = [ |
@@ -29,6 +35,21 @@ PID_FILE_PATH = "/tmp/skydb.pids" |
DEFAULT_URL = "https://raw.githubusercontent.com/domokit/mojo/master/sky/examples/home.sky" |
+# FIXME: Move this into mopy.config |
+def gn_args_from_build_dir(build_dir): |
+ gn_cmd = [ |
+ 'gn', 'args', |
+ build_dir, |
+ '--list', '--short' |
+ ] |
+ config = {} |
+ for line in subprocess.check_output(gn_cmd).strip().split('\n'): |
+ # FIXME: This doesn't handle = in values. |
+ key, value = line.split(' = ') |
+ config[key] = value |
+ return config |
+ |
+ |
class SkyDebugger(object): |
def __init__(self): |
self.paths = None |
@@ -48,48 +69,114 @@ class SkyDebugger(object): |
def _in_chromoting(self): |
return os.environ.get('CHROME_REMOTE_DESKTOP_SESSION', False) |
- def _build_mojo_shell_command(self, args): |
- self.paths = Paths(os.path.join('out', args.configuration)) |
+ def _wrap_for_android(self, shell_args): |
+ build_dir_url = SkyServer.url_for_path( |
+ self.pids['remote_sky_server_port'], |
+ self.pids['sky_server_root'], |
+ self.pids['build_dir']) |
+ shell_args += ['--origin=%s' % build_dir_url] |
+ |
+ # am shell --esa: (someone shoot me now) |
+ # [--esa <EXTRA_KEY> <EXTRA_STRING_VALUE>[,<EXTRA_STRING_VALUE...]] |
+ # (to embed a comma into a string escape it using "\,") |
+ escaped_args = map(lambda arg: arg.replace(',', '\\,'), shell_args) |
+ return [ |
+ 'adb', 'shell', |
+ 'am', 'start', |
+ '-W', |
+ '-S', |
+ '-a', 'android.intent.action.VIEW', |
+ '-n', 'org.chromium.mojo.shell/.MojoShellActivity', |
+ # FIXME: This quoting is very error-prone. Perhaps we should read |
+ # our args from a file instead? |
+ '--esa', 'parameters', ','.join(escaped_args), |
+ ] |
+ def _build_mojo_shell_command(self, args): |
content_handlers = ['%s,%s' % (mime_type, 'mojo:sky_viewer') |
for mime_type in SUPPORTED_MIME_TYPES] |
- shell_command = [ |
- self.paths.mojo_shell_path, |
+ |
+ remote_command_port = self.pids.get('remote_sky_command_port', self.pids['sky_command_port']) |
+ |
+ shell_args = [ |
'--v=1', |
'--content-handlers=%s' % ','.join(content_handlers), |
'--url-mappings=mojo:window_manager=mojo:sky_debugger', |
- '--args-for=mojo:sky_debugger_prompt %d' % args.command_port, |
+ '--args-for=mojo:sky_debugger_prompt %d' % remote_command_port, |
'mojo:window_manager', |
] |
+ # FIXME: This probably is wrong for android? |
if args.use_osmesa: |
- shell_command.append('--args-for=mojo:native_viewport_service --use-osmesa') |
+ shell_args.append('--args-for=mojo:native_viewport_service --use-osmesa') |
+ |
+ if 'remote_sky_server_port' in self.pids: |
+ shell_command = self._wrap_for_android(shell_args) |
+ else: |
+ shell_command = [self.paths.mojo_shell_path] + shell_args |
+ # FIXME: This doesn't work for android |
if args.gdb: |
shell_command = ['gdb', '--args'] + shell_command |
return shell_command |
+ def _connect_to_device(self): |
+ device = android_commands.AndroidCommands( |
+ android_commands.GetAttachedDevices()[0]) |
+ device.EnableAdbRoot() |
+ return device |
+ |
+ def sky_server_for_args(self, args): |
+ # FIXME: This is a hack. sky_server should just take a build_dir |
+ # not a magical "configuration" name. |
+ configuration = os.path.basename(os.path.normpath(args.build_dir)) |
+ server_root = self._server_root_for_url(args.url_or_path) |
+ sky_server = SkyServer(self.paths, SKY_SERVER_PORT, |
+ configuration, server_root) |
+ return sky_server |
+ |
def start_command(self, args): |
- shell_command = self._build_mojo_shell_command(args) |
- if args.show_command: |
eseidel
2015/01/09 22:58:50
I removed support for --show-command. Sorry Hans.
|
- print " ".join(shell_command) |
- return |
+ # FIXME: Lame that we use self for a command-specific variable. |
+ self.paths = Paths(args.build_dir) |
self.stop_command(None) # Quit any existing process. |
+ self.pids = {} # Clear out our pid file. |
- print args.url_or_path |
- # We only start a server for paths: |
- if not urlparse.urlparse(args.url_or_path).scheme: |
- server_root = self._server_root_for_url(args.url_or_path) |
- sky_server = SkyServer(self.paths, SKY_SERVER_PORT, |
- args.configuration, server_root) |
- self.pids['sky_server_pid'] = sky_server.start() |
- self.pids['sky_server_port'] = sky_server.port |
- self.pids['sky_server_root'] = sky_server.root |
+ # FIXME: This is probably not the right way to compute is_android |
+ # from the build directory? |
+ gn_args = gn_args_from_build_dir(args.build_dir) |
+ is_android = 'android_sdk_version' in gn_args |
- self.pids['mojo_shell_pid'] = subprocess.Popen(shell_command).pid |
+ sky_server = self.sky_server_for_args(args) |
+ self.pids['sky_server_pid'] = sky_server.start() |
+ self.pids['sky_server_port'] = sky_server.port |
+ self.pids['sky_server_root'] = sky_server.root |
+ |
+ self.pids['build_dir'] = args.build_dir |
self.pids['sky_command_port'] = args.command_port |
+ if is_android: |
+ # Pray to the build/android gods in their misspelled tongue. |
+ constants.SetOutputDirectort(args.build_dir) |
+ |
+ device = self._connect_to_device() |
+ self.pids['device_serial'] = device.GetDevice() |
+ |
+ forwarder.Forwarder.Map([(0, sky_server.port)], device) |
+ device_http_port = forwarder.Forwarder.DevicePortForHostPort( |
+ sky_server.port) |
+ self.pids['remote_sky_server_port'] = device_http_port |
+ |
+ port_string = 'tcp:%s' % args.command_port |
+ subprocess.check_call([ |
+ 'adb', 'forward', port_string, port_string |
+ ]) |
+ self.pids['remote_sky_command_port'] = args.command_port |
+ |
+ shell_command = self._build_mojo_shell_command(args) |
+ print ' '.join(map(pipes.quote, shell_command)) |
+ self.pids['mojo_shell_pid'] = subprocess.Popen(shell_command).pid |
+ |
if not self._wait_for_sky_command_port(): |
logging.error('Failed to start sky') |
self.stop_command(None) |
@@ -108,14 +195,31 @@ class SkyDebugger(object): |
logging.info('%s (%s) already gone.' % (name, pid)) |
def stop_command(self, args): |
- # FIXME: Send /quit to sky prompt instead of killing. |
- # self._send_command_to_sky('/quit') |
+ try: |
+ self._send_command_to_sky('/quit') |
+ except: |
+ pass |
+ # Kill the mojo process for good measure. :) |
self._kill_if_exists('mojo_shell_pid', 'mojo_shell') |
+ |
self._kill_if_exists('sky_server_pid', 'sky_server') |
+ # We could be much more surgical here: |
+ if 'remote_sky_command_port' in self.pids: |
+ device = android_commands.AndroidCommands( |
+ self.pids['device_serial']) |
+ forwarder.Forwarder.UnmapAllDevicePorts(device) |
+ |
+ if 'remote_sky_command_port' in self.pids: |
+ # adb forward --remove takes the *host* port, not the remote port. |
+ port_string = 'tcp:%s' % self.pids['sky_command_port'] |
+ subprocess.call(['adb', 'forward', '--remove', port_string]) |
def load_command(self, args): |
if not urlparse.urlparse(args.url_or_path).scheme: |
- url = SkyServer.url_for_path(self.pids['sky_server_port'], |
+ # The load happens on the remote device, use the remote port. |
+ remote_sky_server_port = self.pids.get('remote_sky_server_port', |
+ self.pids['sky_server_port']) |
+ url = SkyServer.url_for_path(remote_sky_server_port, |
self.pids['sky_server_root'], args.url_or_path) |
else: |
url = args.url_or_path |
@@ -146,7 +250,7 @@ class SkyDebugger(object): |
def _write_pid_file(self, path, pids): |
try: |
with open(path, 'w') as pid_file: |
- json.dump(pids, pid_file) |
+ json.dump(pids, pid_file, indent=2, sort_keys=True) |
except: |
logging.warn('Failed to write pid file: %s' % path) |
@@ -172,6 +276,7 @@ class SkyDebugger(object): |
def main(self): |
logging.basicConfig(level=logging.INFO) |
+ logging.getLogger("requests").setLevel(logging.WARNING) |
self.pids = self._load_pid_file(PID_FILE_PATH) |
@@ -180,12 +285,12 @@ class SkyDebugger(object): |
start_parser = subparsers.add_parser('start', |
help='launch a new mojo_shell with sky') |
- configuration.add_arguments(start_parser) |
start_parser.add_argument('--gdb', action='store_true') |
start_parser.add_argument('--command-port', type=int, |
default=DEFAULT_SKY_COMMAND_PORT) |
start_parser.add_argument('--use-osmesa', action='store_true', |
default=self._in_chromoting()) |
+ start_parser.add_argument('build_dir', type=str) |
start_parser.add_argument('url_or_path', nargs='?', type=str, |
default=DEFAULT_URL) |
start_parser.add_argument('--show-command', action='store_true', |