Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(795)

Side by Side Diff: sky/tools/skydb

Issue 816693006: Fix skydb to work for android (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 from skypy.paths import 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 requests 13 import requests
13 import signal 14 import signal
14 import skypy.configuration as configuration
15 import subprocess 15 import subprocess
16 import sys
17 import time
16 import urlparse 18 import urlparse
17 import time 19
20 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
21 from pylib import android_commands
22 from pylib import constants
23 from pylib import forwarder
18 24
19 25
20 SUPPORTED_MIME_TYPES = [ 26 SUPPORTED_MIME_TYPES = [
21 'text/html', 27 'text/html',
22 'text/sky', 28 'text/sky',
23 'text/plain', 29 'text/plain',
24 ] 30 ]
25 31
26 DEFAULT_SKY_COMMAND_PORT = 7777 32 DEFAULT_SKY_COMMAND_PORT = 7777
27 SKY_SERVER_PORT = 9999 33 SKY_SERVER_PORT = 9999
28 PID_FILE_PATH = "/tmp/skydb.pids" 34 PID_FILE_PATH = "/tmp/skydb.pids"
29 DEFAULT_URL = "https://raw.githubusercontent.com/domokit/mojo/master/sky/example s/home.sky" 35 DEFAULT_URL = "https://raw.githubusercontent.com/domokit/mojo/master/sky/example s/home.sky"
30 36
31 37
38 # FIXME: Move this into mopy.config
39 def gn_args_from_build_dir(build_dir):
40 gn_cmd = [
41 'gn', 'args',
42 build_dir,
43 '--list', '--short'
44 ]
45 config = {}
46 for line in subprocess.check_output(gn_cmd).strip().split('\n'):
47 # FIXME: This doesn't handle = in values.
48 key, value = line.split(' = ')
49 config[key] = value
50 return config
51
52
32 class SkyDebugger(object): 53 class SkyDebugger(object):
33 def __init__(self): 54 def __init__(self):
34 self.paths = None 55 self.paths = None
35 self.pids = {} 56 self.pids = {}
36 57
37 def _server_root_for_url(self, url_or_path): 58 def _server_root_for_url(self, url_or_path):
38 path = os.path.abspath(url_or_path) 59 path = os.path.abspath(url_or_path)
39 if os.path.commonprefix([path, self.paths.src_root]) == self.paths.src_r oot: 60 if os.path.commonprefix([path, self.paths.src_root]) == self.paths.src_r oot:
40 server_root = self.paths.src_root 61 server_root = self.paths.src_root
41 else: 62 else:
42 server_root = os.path.dirname(path) 63 server_root = os.path.dirname(path)
43 logging.warn( 64 logging.warn(
44 '%s is outside of mojo root, using %s as server root' % 65 '%s is outside of mojo root, using %s as server root' %
45 (path, server_root)) 66 (path, server_root))
46 return server_root 67 return server_root
47 68
48 def _in_chromoting(self): 69 def _in_chromoting(self):
49 return os.environ.get('CHROME_REMOTE_DESKTOP_SESSION', False) 70 return os.environ.get('CHROME_REMOTE_DESKTOP_SESSION', False)
50 71
72 def _wrap_for_android(self, shell_args):
73 build_dir_url = SkyServer.url_for_path(
74 self.pids['remote_sky_server_port'],
75 self.pids['sky_server_root'],
76 self.pids['build_dir'])
77 shell_args += ['--origin=%s' % build_dir_url]
78
79 # am shell --esa: (someone shoot me now)
80 # [--esa <EXTRA_KEY> <EXTRA_STRING_VALUE>[,<EXTRA_STRING_VALUE...]]
81 # (to embed a comma into a string escape it using "\,")
82 escaped_args = map(lambda arg: arg.replace(',', '\\,'), shell_args)
83 return [
84 'adb', 'shell',
85 'am', 'start',
86 '-W',
87 '-S',
88 '-a', 'android.intent.action.VIEW',
89 '-n', 'org.chromium.mojo.shell/.MojoShellActivity',
90 # FIXME: This quoting is very error-prone. Perhaps we should read
91 # our args from a file instead?
92 '--esa', 'parameters', ','.join(escaped_args),
93 ]
94
51 def _build_mojo_shell_command(self, args): 95 def _build_mojo_shell_command(self, args):
52 self.paths = Paths(os.path.join('out', args.configuration))
53
54 content_handlers = ['%s,%s' % (mime_type, 'mojo:sky_viewer') 96 content_handlers = ['%s,%s' % (mime_type, 'mojo:sky_viewer')
55 for mime_type in SUPPORTED_MIME_TYPES] 97 for mime_type in SUPPORTED_MIME_TYPES]
56 shell_command = [ 98
57 self.paths.mojo_shell_path, 99 remote_command_port = self.pids.get('remote_sky_command_port', self.pids ['sky_command_port'])
100
101 shell_args = [
58 '--v=1', 102 '--v=1',
59 '--content-handlers=%s' % ','.join(content_handlers), 103 '--content-handlers=%s' % ','.join(content_handlers),
60 '--url-mappings=mojo:window_manager=mojo:sky_debugger', 104 '--url-mappings=mojo:window_manager=mojo:sky_debugger',
61 '--args-for=mojo:sky_debugger_prompt %d' % args.command_port, 105 '--args-for=mojo:sky_debugger_prompt %d' % remote_command_port,
62 'mojo:window_manager', 106 'mojo:window_manager',
63 ] 107 ]
108 # FIXME: This probably is wrong for android?
64 if args.use_osmesa: 109 if args.use_osmesa:
65 shell_command.append('--args-for=mojo:native_viewport_service --use- osmesa') 110 shell_args.append('--args-for=mojo:native_viewport_service --use-osm esa')
66 111
112 if 'remote_sky_server_port' in self.pids:
113 shell_command = self._wrap_for_android(shell_args)
114 else:
115 shell_command = [self.paths.mojo_shell_path] + shell_args
116
117 # FIXME: This doesn't work for android
67 if args.gdb: 118 if args.gdb:
68 shell_command = ['gdb', '--args'] + shell_command 119 shell_command = ['gdb', '--args'] + shell_command
69 120
70 return shell_command 121 return shell_command
71 122
123 def _connect_to_device(self):
124 device = android_commands.AndroidCommands(
125 android_commands.GetAttachedDevices()[0])
126 device.EnableAdbRoot()
127 return device
128
129 def sky_server_for_args(self, args):
130 # FIXME: This is a hack. sky_server should just take a build_dir
131 # not a magical "configuration" name.
132 configuration = os.path.basename(os.path.normpath(args.build_dir))
133 server_root = self._server_root_for_url(args.url_or_path)
134 sky_server = SkyServer(self.paths, SKY_SERVER_PORT,
135 configuration, server_root)
136 return sky_server
137
72 def start_command(self, args): 138 def start_command(self, args):
73 shell_command = self._build_mojo_shell_command(args) 139 # FIXME: Lame that we use self for a command-specific variable.
74 if args.show_command: 140 self.paths = Paths(args.build_dir)
eseidel 2015/01/09 22:58:50 I removed support for --show-command. Sorry Hans.
75 print " ".join(shell_command)
76 return
77 141
78 self.stop_command(None) # Quit any existing process. 142 self.stop_command(None) # Quit any existing process.
143 self.pids = {} # Clear out our pid file.
79 144
80 print args.url_or_path 145 # FIXME: This is probably not the right way to compute is_android
81 # We only start a server for paths: 146 # from the build directory?
82 if not urlparse.urlparse(args.url_or_path).scheme: 147 gn_args = gn_args_from_build_dir(args.build_dir)
83 server_root = self._server_root_for_url(args.url_or_path) 148 is_android = 'android_sdk_version' in gn_args
84 sky_server = SkyServer(self.paths, SKY_SERVER_PORT,
85 args.configuration, server_root)
86 self.pids['sky_server_pid'] = sky_server.start()
87 self.pids['sky_server_port'] = sky_server.port
88 self.pids['sky_server_root'] = sky_server.root
89 149
150 sky_server = self.sky_server_for_args(args)
151 self.pids['sky_server_pid'] = sky_server.start()
152 self.pids['sky_server_port'] = sky_server.port
153 self.pids['sky_server_root'] = sky_server.root
154
155 self.pids['build_dir'] = args.build_dir
156 self.pids['sky_command_port'] = args.command_port
157
158 if is_android:
159 # Pray to the build/android gods in their misspelled tongue.
160 constants.SetOutputDirectort(args.build_dir)
161
162 device = self._connect_to_device()
163 self.pids['device_serial'] = device.GetDevice()
164
165 forwarder.Forwarder.Map([(0, sky_server.port)], device)
166 device_http_port = forwarder.Forwarder.DevicePortForHostPort(
167 sky_server.port)
168 self.pids['remote_sky_server_port'] = device_http_port
169
170 port_string = 'tcp:%s' % args.command_port
171 subprocess.check_call([
172 'adb', 'forward', port_string, port_string
173 ])
174 self.pids['remote_sky_command_port'] = args.command_port
175
176 shell_command = self._build_mojo_shell_command(args)
177 print ' '.join(map(pipes.quote, shell_command))
90 self.pids['mojo_shell_pid'] = subprocess.Popen(shell_command).pid 178 self.pids['mojo_shell_pid'] = subprocess.Popen(shell_command).pid
91 self.pids['sky_command_port'] = args.command_port
92 179
93 if not self._wait_for_sky_command_port(): 180 if not self._wait_for_sky_command_port():
94 logging.error('Failed to start sky') 181 logging.error('Failed to start sky')
95 self.stop_command(None) 182 self.stop_command(None)
96 else: 183 else:
97 self.load_command(args) 184 self.load_command(args)
98 185
99 def _kill_if_exists(self, key, name): 186 def _kill_if_exists(self, key, name):
100 pid = self.pids.pop(key, None) 187 pid = self.pids.pop(key, None)
101 if not pid: 188 if not pid:
102 logging.info('No pid for %s, nothing to do.' % name) 189 logging.info('No pid for %s, nothing to do.' % name)
103 return 190 return
104 logging.info('Killing %s (%s).' % (name, pid)) 191 logging.info('Killing %s (%s).' % (name, pid))
105 try: 192 try:
106 os.kill(pid, signal.SIGTERM) 193 os.kill(pid, signal.SIGTERM)
107 except OSError: 194 except OSError:
108 logging.info('%s (%s) already gone.' % (name, pid)) 195 logging.info('%s (%s) already gone.' % (name, pid))
109 196
110 def stop_command(self, args): 197 def stop_command(self, args):
111 # FIXME: Send /quit to sky prompt instead of killing. 198 try:
112 # self._send_command_to_sky('/quit') 199 self._send_command_to_sky('/quit')
200 except:
201 pass
202 # Kill the mojo process for good measure. :)
113 self._kill_if_exists('mojo_shell_pid', 'mojo_shell') 203 self._kill_if_exists('mojo_shell_pid', 'mojo_shell')
204
114 self._kill_if_exists('sky_server_pid', 'sky_server') 205 self._kill_if_exists('sky_server_pid', 'sky_server')
206 # We could be much more surgical here:
207 if 'remote_sky_command_port' in self.pids:
208 device = android_commands.AndroidCommands(
209 self.pids['device_serial'])
210 forwarder.Forwarder.UnmapAllDevicePorts(device)
211
212 if 'remote_sky_command_port' in self.pids:
213 # adb forward --remove takes the *host* port, not the remote port.
214 port_string = 'tcp:%s' % self.pids['sky_command_port']
215 subprocess.call(['adb', 'forward', '--remove', port_string])
115 216
116 def load_command(self, args): 217 def load_command(self, args):
117 if not urlparse.urlparse(args.url_or_path).scheme: 218 if not urlparse.urlparse(args.url_or_path).scheme:
118 url = SkyServer.url_for_path(self.pids['sky_server_port'], 219 # The load happens on the remote device, use the remote port.
220 remote_sky_server_port = self.pids.get('remote_sky_server_port',
221 self.pids['sky_server_port'])
222 url = SkyServer.url_for_path(remote_sky_server_port,
119 self.pids['sky_server_root'], args.url_or_path) 223 self.pids['sky_server_root'], args.url_or_path)
120 else: 224 else:
121 url = args.url_or_path 225 url = args.url_or_path
122 self._send_command_to_sky('/load', url) 226 self._send_command_to_sky('/load', url)
123 227
124 def _command_base_url(self): 228 def _command_base_url(self):
125 return 'http://localhost:%s' % self.pids['sky_command_port'] 229 return 'http://localhost:%s' % self.pids['sky_command_port']
126 230
127 def _send_command_to_sky(self, command_path, payload=None): 231 def _send_command_to_sky(self, command_path, payload=None):
128 url = 'http://localhost:%s%s' % ( 232 url = 'http://localhost:%s%s' % (
(...skipping 10 matching lines...) Expand all
139 with open(path, 'r') as pid_file: 243 with open(path, 'r') as pid_file:
140 return json.load(pid_file) 244 return json.load(pid_file)
141 except: 245 except:
142 if os.path.exists(path): 246 if os.path.exists(path):
143 logging.warn('Failed to read pid file: %s' % path) 247 logging.warn('Failed to read pid file: %s' % path)
144 return {} 248 return {}
145 249
146 def _write_pid_file(self, path, pids): 250 def _write_pid_file(self, path, pids):
147 try: 251 try:
148 with open(path, 'w') as pid_file: 252 with open(path, 'w') as pid_file:
149 json.dump(pids, pid_file) 253 json.dump(pids, pid_file, indent=2, sort_keys=True)
150 except: 254 except:
151 logging.warn('Failed to write pid file: %s' % path) 255 logging.warn('Failed to write pid file: %s' % path)
152 256
153 def _add_basic_command(self, subparsers, name, url_path, help_text): 257 def _add_basic_command(self, subparsers, name, url_path, help_text):
154 parser = subparsers.add_parser(name, help=help_text) 258 parser = subparsers.add_parser(name, help=help_text)
155 command = lambda args: self._send_command_to_sky(url_path) 259 command = lambda args: self._send_command_to_sky(url_path)
156 parser.set_defaults(func=command) 260 parser.set_defaults(func=command)
157 261
158 def _wait_for_sky_command_port(self): 262 def _wait_for_sky_command_port(self):
159 tries = 0 263 tries = 0
160 while True: 264 while True:
161 try: 265 try:
162 self._send_command_to_sky('/') 266 self._send_command_to_sky('/')
163 return True 267 return True
164 except: 268 except:
165 tries += 1 269 tries += 1
166 if tries == 3: 270 if tries == 3:
167 logging.warn('Still waiting for sky on port %s' % 271 logging.warn('Still waiting for sky on port %s' %
168 self.pids['sky_command_port']) 272 self.pids['sky_command_port'])
169 if tries > 10: 273 if tries > 10:
170 return False 274 return False
171 time.sleep(1) 275 time.sleep(1)
172 276
173 def main(self): 277 def main(self):
174 logging.basicConfig(level=logging.INFO) 278 logging.basicConfig(level=logging.INFO)
279 logging.getLogger("requests").setLevel(logging.WARNING)
175 280
176 self.pids = self._load_pid_file(PID_FILE_PATH) 281 self.pids = self._load_pid_file(PID_FILE_PATH)
177 282
178 parser = argparse.ArgumentParser(description='Sky launcher/debugger') 283 parser = argparse.ArgumentParser(description='Sky launcher/debugger')
179 subparsers = parser.add_subparsers(help='sub-command help') 284 subparsers = parser.add_subparsers(help='sub-command help')
180 285
181 start_parser = subparsers.add_parser('start', 286 start_parser = subparsers.add_parser('start',
182 help='launch a new mojo_shell with sky') 287 help='launch a new mojo_shell with sky')
183 configuration.add_arguments(start_parser)
184 start_parser.add_argument('--gdb', action='store_true') 288 start_parser.add_argument('--gdb', action='store_true')
185 start_parser.add_argument('--command-port', type=int, 289 start_parser.add_argument('--command-port', type=int,
186 default=DEFAULT_SKY_COMMAND_PORT) 290 default=DEFAULT_SKY_COMMAND_PORT)
187 start_parser.add_argument('--use-osmesa', action='store_true', 291 start_parser.add_argument('--use-osmesa', action='store_true',
188 default=self._in_chromoting()) 292 default=self._in_chromoting())
293 start_parser.add_argument('build_dir', type=str)
189 start_parser.add_argument('url_or_path', nargs='?', type=str, 294 start_parser.add_argument('url_or_path', nargs='?', type=str,
190 default=DEFAULT_URL) 295 default=DEFAULT_URL)
191 start_parser.add_argument('--show-command', action='store_true', 296 start_parser.add_argument('--show-command', action='store_true',
192 help='Display the shell command and exit') 297 help='Display the shell command and exit')
193 start_parser.set_defaults(func=self.start_command) 298 start_parser.set_defaults(func=self.start_command)
194 299
195 stop_parser = subparsers.add_parser('stop', 300 stop_parser = subparsers.add_parser('stop',
196 help=('stop sky (as listed in %s)' % PID_FILE_PATH)) 301 help=('stop sky (as listed in %s)' % PID_FILE_PATH))
197 stop_parser.set_defaults(func=self.stop_command) 302 stop_parser.set_defaults(func=self.stop_command)
198 303
(...skipping 10 matching lines...) Expand all
209 load_parser.set_defaults(func=self.load_command) 314 load_parser.set_defaults(func=self.load_command)
210 315
211 args = parser.parse_args() 316 args = parser.parse_args()
212 args.func(args) 317 args.func(args)
213 318
214 self._write_pid_file(PID_FILE_PATH, self.pids) 319 self._write_pid_file(PID_FILE_PATH, self.pids)
215 320
216 321
217 if __name__ == '__main__': 322 if __name__ == '__main__':
218 SkyDebugger().main() 323 SkyDebugger().main()
OLDNEW
« sky/tools/debugger/prompt/prompt.cc ('K') | « sky/tools/debugger/prompt/prompt.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698