Skip to content
This repository was archived by the owner on Jan 10, 2023. It is now read-only.

Commit f85d3ed

Browse files
committed
Switch use of google-flags (gflags) to more standard argparse.
It is more appropriate for open source projects to use argparse. Keep the 'clever' approach and uses the docstring on methods on AdbCommands/FastbootCommands to generate the arguments on the parser. Override the documentation only when it doesn't make sense, like when an argument can be "object-like". Update default fastboot packet size from 4kb to 1Mb.
1 parent 29e0c83 commit f85d3ed

File tree

6 files changed

+385
-205
lines changed

6 files changed

+385
-205
lines changed

adb/adb_commands.py

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -109,13 +109,13 @@ def Devices(cls):
109109
def GetState(self):
110110
return self._device_state
111111

112-
def Install(self, apk_path, destination_dir=None, timeout_ms=None):
112+
def Install(self, apk_path, destination_dir='', timeout_ms=None):
113113
"""Install an apk to the device.
114114
115115
Doesn't support verifier file, instead allows destination directory to be
116116
overridden.
117117
118-
Arguments:
118+
Args:
119119
apk_path: Local path to apk to install.
120120
destination_dir: Optional destination directory. Use /system/app/ for
121121
persistent applications.
@@ -135,10 +135,10 @@ def Install(self, apk_path, destination_dir=None, timeout_ms=None):
135135
def Push(self, source_file, device_filename, mtime='0', timeout_ms=None):
136136
"""Push a file or directory to the device.
137137
138-
Arguments:
138+
Args:
139139
source_file: Either a filename, a directory or file-like object to push to
140140
the device.
141-
device_filename: The filename on the device to write to.
141+
device_filename: Destination on the device to write to.
142142
mtime: Optional, modification time to set on the file.
143143
timeout_ms: Expected timeout for any part of the push.
144144
"""
@@ -158,11 +158,11 @@ def Push(self, source_file, device_filename, mtime='0', timeout_ms=None):
158158
mtime=int(mtime))
159159
connection.Close()
160160

161-
def Pull(self, device_filename, dest_file=None, timeout_ms=None):
161+
def Pull(self, device_filename, dest_file='', timeout_ms=None):
162162
"""Pull a file from the device.
163163
164-
Arguments:
165-
device_filename: The filename on the device to pull.
164+
Args:
165+
device_filename: Filename on the device to pull.
166166
dest_file: If set, a filename or writable file-like object.
167167
timeout_ms: Expected timeout for any part of the pull.
168168
@@ -192,7 +192,11 @@ def Stat(self, device_filename):
192192
return mode, size, mtime
193193

194194
def List(self, device_path):
195-
"""Return a directory listing of the given path."""
195+
"""Return a directory listing of the given path.
196+
197+
Args:
198+
device_path: Directory to list.
199+
"""
196200
connection = self.protocol_handler.Open(self.handle, destination='sync:')
197201
listing = self.filesync_handler.List(connection, device_path)
198202
connection.Close()
@@ -201,7 +205,8 @@ def List(self, device_path):
201205
def Reboot(self, destination=''):
202206
"""Reboot the device.
203207
204-
Specify 'bootloader' for fastboot.
208+
Args:
209+
destination: Specify 'bootloader' for fastboot.
205210
"""
206211
self.protocol_handler.Open(self.handle, 'reboot:%s' % destination)
207212

@@ -227,7 +232,7 @@ def StreamingShell(self, command, timeout_ms=None):
227232
"""Run command on the device, yielding each line of output.
228233
229234
Args:
230-
command: the command to run on the target.
235+
command: Command to run on the target.
231236
timeout_ms: Maximum time to allow the command to run.
232237
233238
Yields:
@@ -238,7 +243,11 @@ def StreamingShell(self, command, timeout_ms=None):
238243
timeout_ms=timeout_ms)
239244

240245
def Logcat(self, options, timeout_ms=None):
241-
"""Run 'shell logcat' and stream the output to stdout."""
246+
"""Run 'shell logcat' and stream the output to stdout.
247+
248+
Args:
249+
options: Arguments to pass to 'logcat'.
250+
"""
242251
return self.protocol_handler.StreamingCommand(
243252
self.handle, service='shell', command='logcat %s' % options,
244253
timeout_ms=timeout_ms)

adb/adb_debug.py

Lines changed: 143 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,16 @@
1212
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1313
# See the License for the specific language governing permissions and
1414
# limitations under the License.
15-
"""ADB debugging binary.
1615

17-
Call it similar to how you call android's adb. Takes either --serial or
18-
--port_path to connect to a device.
19-
"""
16+
"""Daemon-less ADB client in python."""
17+
18+
import argparse
19+
import logging
2020
import os
21+
import pipes
22+
import stat
2123
import sys
22-
23-
import gflags
24+
import time
2425

2526
import adb_commands
2627
import common_cli
@@ -36,34 +37,147 @@
3637
rsa_signer = None
3738

3839

39-
gflags.ADOPT_module_key_flags(common_cli)
40+
def Devices(args):
41+
"""Lists the available devices.
42+
43+
Mimics 'adb devices' output:
44+
List of devices attached
45+
015DB7591102001A device 1,2
46+
"""
47+
for d in adb_commands.AdbCommands.Devices():
48+
if args.output_port_path:
49+
print('%s\tdevice\t%s' % (
50+
d.serial_number, ','.join(str(p) for p in d.port_path)))
51+
else:
52+
print('%s\tdevice' % d.serial_number)
53+
return 0
54+
55+
56+
def List(self, device_path):
57+
"""Prints a directory listing.
58+
59+
Args:
60+
device_path: Directory to list.
61+
"""
62+
files = adb_commands.AdbCommands.List(self, device_path)
63+
files.sort(key=lambda x: x.filename)
64+
maxname = max(len(f.filename) for f in files)
65+
maxsize = max(len(str(f.size)) for f in files)
66+
for f in files:
67+
mode = (
68+
('d' if stat.S_ISDIR(f.mode) else '-') +
69+
('r' if f.mode & stat.S_IRUSR else '-') +
70+
('w' if f.mode & stat.S_IWUSR else '-') +
71+
('x' if f.mode & stat.S_IXUSR else '-') +
72+
('r' if f.mode & stat.S_IRGRP else '-') +
73+
('w' if f.mode & stat.S_IWGRP else '-') +
74+
('x' if f.mode & stat.S_IXGRP else '-') +
75+
('r' if f.mode & stat.S_IROTH else '-') +
76+
('w' if f.mode & stat.S_IWOTH else '-') +
77+
('x' if f.mode & stat.S_IXOTH else '-'))
78+
t = time.gmtime(f.mtime)
79+
yield '%s %*d %04d-%02d-%02d %02d:%02d:%02d %-*s\n' % (
80+
mode, maxsize, f.size,
81+
t.tm_year, t.tm_mon, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec,
82+
maxname, f.filename)
83+
84+
85+
def Logcat(self, *options):
86+
return adb_commands.AdbCommands.StreamingShell(
87+
self, 'logcat ' + ' '.join(pipes.quote(o) for o in options))
88+
89+
90+
Logcat.__doc__ = adb_commands.AdbCommands.Logcat.__doc__
91+
92+
93+
def Shell(self, *command):
94+
"""Runs a command on the device and prints the stdout.
95+
96+
Args:
97+
command: Command to run on the target.
98+
"""
99+
return adb_commands.AdbCommands.StreamingShell(
100+
self, ' '.join(pipes.quote(o) for o in command))
101+
102+
103+
def main():
104+
common = common_cli.GetCommonArguments()
105+
common.add_argument(
106+
'--rsa_key_path', action='append', default=[],
107+
metavar='~/.android/adbkey',
108+
help='RSA key(s) to use, use multiple times to load mulitple keys')
109+
common.add_argument(
110+
'--auth_timeout_s', default=60., metavar='60', type=int,
111+
help='Seconds to wait for the dialog to be accepted when using '
112+
'authenticated ADB.')
113+
device = common_cli.GetDeviceArguments()
114+
parents = [common, device]
115+
116+
parser = argparse.ArgumentParser(
117+
description=sys.modules[__name__].__doc__, parents=[common])
118+
subparsers = parser.add_subparsers(title='Commands', dest='command_name')
40119

41-
gflags.DEFINE_multistring('rsa_key_path', '~/.android/adbkey',
42-
'RSA key(s) to use')
43-
gflags.DEFINE_integer('auth_timeout_s', 60,
44-
'Seconds to wait for the dialog to be accepted when using '
45-
'authenticated ADB.')
46-
FLAGS = gflags.FLAGS
120+
subparser = subparsers.add_parser(
121+
name='help', help='Prints the commands available')
122+
subparser = subparsers.add_parser(
123+
name='devices', help='Lists the available devices', parents=[common])
124+
subparser.add_argument(
125+
'--output_port_path', action='store_true',
126+
help='Outputs the port_path alongside the serial')
47127

128+
subparser = common_cli.MakeSubparser(
129+
subparsers, parents, adb_commands.AdbCommands.Install)
130+
subparser = common_cli.MakeSubparser(subparsers, parents, List)
131+
subparser = common_cli.MakeSubparser(subparsers, parents, Logcat)
132+
subparser = common_cli.MakeSubparser(
133+
subparsers, parents, adb_commands.AdbCommands.Push,
134+
{'source_file': 'Filename or directory to push to the device.'})
135+
subparser = common_cli.MakeSubparser(
136+
subparsers, parents, adb_commands.AdbCommands.Pull,
137+
{
138+
'dest_file': 'Filename to write to on the host, if not specified, '
139+
'prints the content to stdout.',
140+
})
141+
subparser = common_cli.MakeSubparser(
142+
subparsers, parents, adb_commands.AdbCommands.Reboot)
143+
subparser = common_cli.MakeSubparser(
144+
subparsers, parents, adb_commands.AdbCommands.RebootBootloader)
145+
subparser = common_cli.MakeSubparser(
146+
subparsers, parents, adb_commands.AdbCommands.Remount)
147+
subparser = common_cli.MakeSubparser(
148+
subparsers, parents, adb_commands.AdbCommands.Root)
149+
subparser = common_cli.MakeSubparser(subparsers, parents, Shell)
48150

49-
def GetRSAKwargs():
50-
if FLAGS.rsa_key_path:
51-
if rsa_signer is None:
52-
print >> sys.stderr, 'Please install either M2Crypto or python-rsa'
53-
sys.exit(1)
54-
return {
55-
'rsa_keys': [rsa_signer(os.path.expanduser(path))
56-
for path in FLAGS.rsa_key_path],
57-
'auth_timeout_ms': int(FLAGS.auth_timeout_s * 1000.0),
58-
}
59-
return {}
151+
if len(sys.argv) == 1:
152+
parser.print_help()
153+
return 2
60154

155+
args = parser.parse_args()
156+
if args.verbose:
157+
logging.basicConfig(level=logging.DEBUG)
158+
if not args.rsa_key_path:
159+
default = os.path.expanduser('~/.android/adbkey')
160+
if os.path.isfile(default):
161+
args.rsa_key_path = [default]
162+
if args.rsa_key_path and not rsa_signer:
163+
parser.error('Please install either M2Crypto or python-rsa')
164+
# Hacks so that the generated doc is nicer.
165+
if args.command_name == 'devices':
166+
return Devices(args)
167+
if args.command_name == 'help':
168+
parser.print_help()
169+
return 0
170+
if args.command_name == 'logcat':
171+
args.positional = args.options
172+
elif args.command_name == 'shell':
173+
args.positional = args.command
61174

62-
def main(argv):
63-
common_cli.StartCli(
64-
argv, adb_commands.AdbCommands.ConnectDevice,
65-
list_callback=adb_commands.AdbCommands.Devices, **GetRSAKwargs())
175+
return common_cli.StartCli(
176+
args,
177+
adb_commands.AdbCommands.ConnectDevice,
178+
auth_timeout_ms=args.auth_timeout_s * 1000,
179+
rsa_keys=[rsa_signer(path) for path in args.rsa_key_path])
66180

67181

68182
if __name__ == '__main__':
69-
main(FLAGS(sys.argv))
183+
sys.exit(main())

0 commit comments

Comments
 (0)