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

Side by Side Diff: sky/tools/shelldb

Issue 960233007: Add super-primitive shelldb (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Created 5 years, 9 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
« no previous file with comments | « mojo/tools/mojo_demo.py ('k') | sky/tools/skydb » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 #!/usr/bin/env python
2 # Copyright 2015 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
5
6 from skypy.skyserver import SkyServer
7 import argparse
8 import json
9 import logging
10 import os
11 import subprocess
12 import sys
13 import urllib
14 import urlparse
15
16 SKY_TOOLS_DIR = os.path.dirname(__file__)
17 SKY_ROOT = os.path.dirname(SKY_TOOLS_DIR)
18 SRC_ROOT = os.path.dirname(SKY_ROOT)
19
20 SKY_SERVER_PORT = 9888
21 DEFAULT_URL = "sky://domokit.github.io/home"
22 APK_NAME = 'SkyDemo.apk'
23 ADB_PATH = os.path.join(SRC_ROOT,
24 'third_party/android_tools/sdk/platform-tools/adb')
25
26
27 PID_FILE_PATH = "/tmp/skydemo.pids"
28 PID_FILE_KEYS = frozenset([
29 'remote_sky_server_port',
30 'sky_server_pid',
31 'sky_server_port',
32 'sky_server_root',
33 'build_dir',
34 ])
35
36 # This 'strict dictionary' approach is useful for catching typos.
37 class Pids(object):
38 def __init__(self, known_keys, contents=None):
39 self._known_keys = known_keys
40 self._dict = contents if contents is not None else {}
41
42 def __len__(self):
43 return len(self._dict)
44
45 def __getitem__(self, key):
46 assert key in self._known_keys, '%s not in known_keys' % key
47 return self._dict[key]
48
49 def __setitem__(self, key, value):
50 assert key in self._known_keys, '%s not in known_keys' % key
51 self._dict[key] = value
52
53 def __delitem__(self, key):
54 assert key in self._known_keys, '%s not in known_keys' % key
55 del self._dict[key]
56
57 def __iter__(self):
58 return iter(self._dict)
59
60 def __contains__(self, key):
61 assert key in self._known_keys, '%s not in allowed_keys' % key
62 return key in self._dict
63
64 def clear():
65 self._dict = {}
66
67 @classmethod
68 def read_from(cls, path, known_keys):
69 contents = {}
70 try:
71 with open(path, 'r') as pid_file:
72 contents = json.load(pid_file)
73 except:
74 if os.path.exists(path):
75 logging.warn('Failed to read pid file: %s' % path)
76 return cls(known_keys, contents)
77
78 def write_to(self, path):
79 try:
80 with open(path, 'w') as pid_file:
81 json.dump(self._dict, pid_file, indent=2, sort_keys=True)
82 except:
83 logging.warn('Failed to write pid file: %s' % path)
84
85
86 def _convert_to_sky_url(url):
87 result = urllib.parse.urlsplit(url)
88 result.scheme = 'sky'
89 return urllib.parse.urlunsplit(result)
90
91
92 # A free function for possible future sharing with a 'load' command.
93 def _url_from_args(args):
94 if urlparse.urlparse(args.url_or_path).scheme:
95 return args.url_or_path
96 # The load happens on the remote device, use the remote port.
97 remote_sky_server_port = self.pids.get('remote_sky_server_port',
98 self.pids['sky_server_port'])
99 url = SkyServer.url_for_path(remote_sky_server_port,
100 self.pids['sky_server_root'], args.url_or_path)
101 return _convert_to_sky_url(url)
102
103
104 class StartSky(object):
105 def add_subparser(self, subparsers):
106 start_parser = subparsers.add_parser('start',
107 help='launch SKyShell.apk on the device')
108 start_parser.add_argument('build_dir', type=str)
109 start_parser.add_argument('url_or_path', nargs='?', type=str,
110 default=DEFAULT_URL)
111 start_parser.set_defaults(func=self.run)
112
113 def _server_root_for_url(self, url_or_path):
114 path = os.path.abspath(url_or_path)
115 if os.path.commonprefix([path, SRC_ROOT]) == SRC_ROOT:
116 server_root = SRC_ROOT
117 else:
118 server_root = os.path.dirname(path)
119 logging.warn(
120 '%s is outside of mojo root, using %s as server root' %
121 (path, server_root))
122 return server_root
123
124 def _sky_server_for_args(self, args):
125 # FIXME: This is a hack. sky_server should just take a build_dir
126 # not a magical "configuration" name.
127 configuration = os.path.basename(os.path.normpath(args.build_dir))
128 server_root = self._server_root_for_url(args.url_or_path)
129 sky_server = SkyServer(SKY_SERVER_PORT, configuration, server_root)
130 return sky_server
131
132 def run(self, args, pids):
133 apk_path = os.path.join(args.build_dir, 'apks', APK_NAME)
134 if not os.path.exists(apk_path):
135 print "'%s' does not exist?" % apk_path
136 return 2
137
138 sky_server = self._sky_server_for_args(args)
139 pids['sky_server_pid'] = sky_server.start()
140 pids['sky_server_port'] = sky_server.port
141 pids['sky_server_root'] = sky_server.root
142
143 pids['build_dir'] = args.build_dir
144
145 subprocess.check_call([ADB_PATH, 'install', '-r', apk_path])
146
147 port_string = 'tcp:%s' % sky_server.port
148 subprocess.check_call([
149 ADB_PATH, 'reverse', port_string, port_string
150 ])
151 pids['remote_sky_server_port'] = sky_server.port
152
153 subprocess.check_call([ADB_PATH, 'shell',
154 'am', 'start',
155 '-a', 'android.intent.action.VIEW',
156 '-d', _url_from_args(args)])
157
158
159 class StopSky(object):
160 def add_subparser(self, subparsers):
161 stop_parser = subparsers.add_parser('stop',
162 help=('kill all running SkyShell.apk processes'))
163 stop_parser.set_defaults(func=self.run)
164
165 def _kill_if_exists(self, pids, key, name):
166 pid = pids.pop(key, None)
167 if not pid:
168 logging.info('No pid for %s, nothing to do.' % name)
169 return
170 logging.info('Killing %s (%d).' % (name, pid))
171 try:
172 os.kill(pid, signal.SIGTERM)
173 except OSError:
174 logging.info('%s (%d) already gone.' % (name, pid))
175
176 def run(self, args, pids):
177 self._kill_if_exists(pids, 'sky_server_pid', 'sky_server')
178
179 if 'remote_sky_server_port' in self.pids:
180 port_string = 'tcp:%s' % self.pids['remote_sky_server_port']
181 subprocess.call([ADB_PATH, 'reverse', '--remove', port_string])
182
183 subprocess.call([
184 ADB_PATH, 'shell', 'am', 'force-stop', ANDROID_PACKAGE])
185
186 pids.clear()
187
188
189 class SkyShellRunner(object):
190 def main(self):
191 logging.basicConfig(level=logging.WARNING)
192
193 parser = argparse.ArgumentParser(description='Sky Shell Runner')
194 subparsers = parser.add_subparsers(help='sub-command help')
195
196 for command in [StartSky(), StopSky()]:
197 command.add_subparser(subparsers)
198
199 args = parser.parse_args()
200 pids = Pids.read_from(PID_FILE_PATH, PID_FILE_KEYS)
201 exit_code = args.func(args, pids)
202 # We could do this with an at-exit handler instead?
203 pids.write_to(PID_FILE_PATH)
204 sys.exit(exit_code)
205
206
207 if __name__ == '__main__':
208 SkyShellRunner().main()
OLDNEW
« no previous file with comments | « mojo/tools/mojo_demo.py ('k') | sky/tools/skydb » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698