Skip to content

Instantly share code, notes, and snippets.

@mrenouf
Created September 28, 2012 00:47
Show Gist options
  • Save mrenouf/3797328 to your computer and use it in GitHub Desktop.
Save mrenouf/3797328 to your computer and use it in GitHub Desktop.
An adb convenience wrapper
#!/usr/bin/python
# Handles call to adb and prompts for device selection if
# necessary when more than once device is connected.
#
# by Mark Renouf <[email protected]>
# To install:
# 1. Place this script somewhere in your path, and make it executable.
# 2. Make sure 'adb' is also in your path.
# 3. Run 'adb-wrapper.py' as you would in place of 'adb'.
# 3. (Optional) Run 'adb-wrapper.py --wrap' to make 'adb' invoke this script.
import os;
import subprocess;
import re;
from stat import S_IXUSR, S_IXGRP, S_IXOTH;
import shutil;
import sys;
def get_devices(adb='adb.real'):
args = ['adb.real', 'devices']
devices = subprocess.check_output(args)
lines = devices.strip().splitlines()
devices = {}
for line in lines[1:]:
(serial, type) = line.split('\t')
devices[serial] = type
return devices
def get_props(device_serial, adb='adb.real'):
args = ['adb.real', '-s', device_serial, 'shell', 'cat', '/system/build.prop']
out = subprocess.check_output(args)
props = {}
for line in out.splitlines():
line = line.strip()
if line.startswith("#") or line == "": continue
(key, value) = line.split("=", 1)
props[key] = value.strip()
return props
def device_label(props):
manufacturer_model = "%s %s" % (
props['ro.product.manufacturer'].title(),
props['ro.product.model'])
return "%-25s [%s]" % (manufacturer_model[:25], props['ro.build.description'])
def prompt_number(prompt, min, max):
sys.stdout.write(prompt)
try:
choice = int(raw_input())
if choice < min or choice > max:
return None
return choice
except (ValueError):
pass
except (KeyboardInterrupt):
pass
except (EOFError):
pass
return None
def prompt_yes_no(prompt):
sys.stdout.write(prompt)
try:
matched = re.match('^[Yy](es)?', raw_input())
if matched is not None:
return True
except (ValueError):
pass
except (KeyboardInterrupt):
pass
except (EOFError):
pass
return False
def do_install(self_path, self_name):
adb_name = 'adb'
bin_name = 'adb.real'
target_path = subprocess.check_output(['which', adb_name]).strip()
target_dir = os.path.dirname(target_path)
self_target = os.path.join(target_dir, self_name)
target_real = os.path.join(target_dir, bin_name)
symlink_path = os.path.join(target_dir, adb_name)
print 'Installing as %s' % (target_path)
if prompt_yes_no('Continue? [y/N]?'):
print "renaming %s => %s" % (target_path, 'adb.real')
shutil.move(target_path, target_real)
print "copying %s => %s" % (self_path, self_target)
shutil.copyfile(self_path, self_target)
fstat = os.stat(self_target)
os.chmod(self_target, fstat.st_mode | S_IXUSR | S_IXGRP | S_IXOTH)
print "create symlink adb => %s" % (self_target)
os.symlink(self_name, symlink_path)
target_flags = { '-d', '-e', '-s', '-p'}
device_commands = {'connect', 'disconnect', 'push', 'pull', 'sync',
'shell', 'logcat', 'forward', 'jdwp', 'install', 'uninstall',
'bugreport', 'backup', 'restore', 'get-state', 'get-serialno',
'remount', 'reboot', 'reboot-bootloader', 'root', 'tcpip', 'ppp'}
def main(args):
self_path = os.path.normpath(args[0])
self_name = os.path.basename(self_path)
self_dir = os.path.dirname(self_path)
if self_name != 'adb' and len(args) > 1 and args[1] == '--wrap':
do_install(self_path, self_name)
else:
if self_name == 'adb':
args[0] = os.path.join(self_dir, 'adb.real')
else:
args[0] = 'adb'
if len(args) > 1:
first_arg = args[1]
# see if the command would work without a serial number
# or if possibly a serial number was already supplied
if (first_arg not in target_flags) and first_arg in device_commands:
devices = get_devices()
if len(devices) > 1:
i = 1
serials = devices.keys()
for device_serial in serials:
device_type = 'device'
if device_serial.startswith('emulator'):
device_type = 'emulator'
print "[%3d] [%8s] %s" % (i, device_type, device_label(get_props(device_serial, args[0])))
i = i + 1
selection = prompt_number("device? ", 1, len(serials))
if selection is None:
print 'Cancelled!'
sys.exit(1)
device_serial = serials[selection - 1]
args.insert(1, '-s')
args.insert(2, device_serial)
try:
subprocess.call(args)
except:
pass
if __name__ == "__main__":
main(sys.argv)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment