Browse Source

Made pep8 compliant

refactor
Raphael Roberts 7 years ago
parent
commit
e69757152a
  1. 1
      .gitignore
  2. 1
      pyadb/__init__.py
  3. 163
      pyadb/adb.py
  4. 1
      pyadb/extras/__init__.py
  5. 10
      pyadb/extras/open_youtube.py
  6. 15
      pyadb/extras/sync_clip.py
  7. 1
      pyadb/internal/__init__.py
  8. 34
      pyadb/internal/android_db.py
  9. 34
      pyadb/internal/cli_wrap.py
  10. 13
      pyadb/internal/load_config.py
  11. 8
      pyadb/test.py
  12. 1
      setup.py

1
.gitignore

@ -465,3 +465,4 @@ decoded.txt
parcel_ex.txt parcel_ex.txt
Pipfile Pipfile
Pipfile.lock Pipfile.lock
*#*#

1
pyadb/__init__.py

@ -1 +0,0 @@

163
pyadb/adb.py

@ -14,7 +14,8 @@ config = loaded.config
keycodes = loaded.keycodes keycodes = loaded.keycodes
exe = config.defaults.exe exe = config.defaults.exe
def merge(src, dst,log = False):
def merge(src, dst, log=False):
if not os.path.exists(dst): if not os.path.exists(dst):
return False return False
ok = True ok = True
@ -27,7 +28,8 @@ def merge(src, dst,log = False):
destFile = os.path.join(destPath, file) destFile = os.path.join(destPath, file)
if os.path.isfile(destFile): if os.path.isfile(destFile):
if log: if log:
print("Skipping existing file: " + os.path.join(relPath, file))
print("Skipping existing file: " +
os.path.join(relPath, file))
ok = False ok = False
continue continue
srcFile = os.path.join(path, file) srcFile = os.path.join(path, file)
@ -37,65 +39,71 @@ def merge(src, dst,log = False):
os.rmdir(path) os.rmdir(path)
return ok return ok
def _adb(*args,output = "shell"):
def _adb(*args, output="shell"):
'''Output modes: '''Output modes:
"out": return output "out": return output
"shell": print to shell "shell": print to shell
"buffered": read line by line''' "buffered": read line by line'''
args = [exe] + list(args) args = [exe] + list(args)
if output == "out": if output == "out":
return subprocess.check_output(args,shell = False).decode().replace('\r\n','\n').rstrip()
return subprocess.check_output(args, shell=False).decode().replace('\r\n', '\n').rstrip()
elif output == "shell": elif output == "shell":
ret = subprocess.call(args,shell = False)
ret = subprocess.call(args, shell=False)
if ret: if ret:
raise subprocess.CalledProcessError(ret,args)
raise subprocess.CalledProcessError(ret, args)
elif output == "buffered": elif output == "buffered":
p = subprocess.Popen(args,stdout = subprocess.PIPE)
p = subprocess.Popen(args, stdout=subprocess.PIPE)
return p.stdout return p.stdout
def kill_server(): def kill_server():
_adb('kill-server') _adb('kill-server')
def start_server(): def start_server():
_adb('start-server') _adb('start-server')
def get_info(): def get_info():
start_server() start_server()
thing = _adb("devices","-l",output="out")
formed = list(filter(bool,thing.split("\n")))[1:]
thing = _adb("devices", "-l", output="out")
formed = list(filter(bool, thing.split("\n")))[1:]
main = {} main = {}
for device in formed: for device in formed:
categories = re.split(" +",device)
categories = re.split(" +", device)
device_dict = { device_dict = {
"serial":categories[0],
"mode":categories[1]
"serial": categories[0],
"mode": categories[1]
} }
device_dict.update(dict(category.split(":") for category in categories[2:]))
device_dict.update(dict(category.split(":")
for category in categories[2:]))
main[categories[0]] = device_dict main[categories[0]] = device_dict
return main return main
class ADBWrapper: class ADBWrapper:
root_mode = False root_mode = False
def connect(ip,port=5555):
if not re.match(r'(\d{1,3}\.){3}\d{1,3}',ip):
def connect(ip, port=5555):
if not re.match(r'(\d{1,3}\.){3}\d{1,3}', ip):
raise TypeError("Invalid ip") raise TypeError("Invalid ip")
if not all(int(n) <= 255 and int(n) >= 0 for n in ip.split('.')): if not all(int(n) <= 255 and int(n) >= 0 for n in ip.split('.')):
raise TypeError("Invalid ip") raise TypeError("Invalid ip")
if not (port >= 0 and port <= 2**16-1): if not (port >= 0 and port <= 2**16-1):
raise TyperError("Port must be in the range 0-65536") raise TyperError("Port must be in the range 0-65536")
id = '{}:{}'.format(ip,port)
_adb('connect','{}:{}'.format(ip,port))
id = '{}:{}'.format(ip, port)
_adb('connect', '{}:{}'.format(ip, port))
dev = Device(id) dev = Device(id)
dev.tcip = True dev.tcip = True
return dev return dev
def disconnect(self): def disconnect(self):
if self.tcip: if self.tcip:
_adb('disconnect',self.serial)
_adb('disconnect', self.serial)
def db_connect(self,filepath):
return AndroidSQLConn(self,filepath)
def db_connect(self, filepath):
return AndroidSQLConn(self, filepath)
def prim_device(): def prim_device():
cont = True cont = True
@ -107,28 +115,28 @@ class ADBWrapper:
time.sleep(1) time.sleep(1)
return d return d
def __init__(self,serial=None):
def __init__(self, serial=None):
self.tcip = False self.tcip = False
if serial: if serial:
self.serial = serial self.serial = serial
info = get_info()[serial] info = get_info()[serial]
else: else:
serial,info = list(get_info().items())[0]
serial, info = list(get_info().items())[0]
self.__dict__.update(info) self.__dict__.update(info)
def adb(self,*args,output="shell"):
args = ['-s',self.serial]+ list(args)
return _adb(*args,output = output)
def adb(self, *args, output="shell"):
args = ['-s', self.serial] + list(args)
return _adb(*args, output=output)
def shell(self,*args,output="shell"):
def shell(self, *args, output="shell"):
args = ('shell',)+args args = ('shell',)+args
return self.adb(*args,output=output)
return self.adb(*args, output=output)
def sudo(self,*args,output="shell"):
def sudo(self, *args, output="shell"):
if self.mode == 'recovery' or self.root_mode: if self.mode == 'recovery' or self.root_mode:
return self.shell(*args,output=output)
return self.shell(*args, output=output)
else: else:
return self.shell('su','--','--',*args,output=output)
return self.shell('su', '--', '--', *args, output=output)
@classmethod @classmethod
def root(cls): def root(cls):
@ -140,16 +148,16 @@ class ADBWrapper:
cls.root_mode = False cls.root_mode = False
_adb('unroot') _adb('unroot')
def reboot(self,mode = None):
def reboot(self, mode=None):
if mode: if mode:
if mode == "soft": if mode == "soft":
if self.mode != 'recovery': if self.mode != 'recovery':
pid = self.shell("pidof","zygote",output="out")
return self.sudo("kill",pid,output="shell")
pid = self.shell("pidof", "zygote", output="out")
return self.sudo("kill", pid, output="shell")
else: else:
return self.reboot() return self.reboot()
else: else:
self.adb("reboot",mode)
self.adb("reboot", mode)
else: else:
self.adb("reboot") self.adb("reboot")
while True: while True:
@ -159,9 +167,10 @@ class ADBWrapper:
break break
time.sleep(1) time.sleep(1)
class FSActionWrapper(ADBWrapper): class FSActionWrapper(ADBWrapper):
def stat(self,file):
def stat(self, file):
'''\ '''\
%a Access bits (octal) |%A Access bits (flags)|%b Size/512 %a Access bits (octal) |%A Access bits (flags)|%b Size/512
%B Bytes per %b (512) |%d Device ID (dec) |%D Device ID (hex) %B Bytes per %b (512) |%d Device ID (dec) |%D Device ID (hex)
@ -179,27 +188,27 @@ The valid format escape sequences for filesystems:
%l Max filename length |%n File name |%s Fragment size %l Max filename length |%n File name |%s Fragment size
%S Best transfer size |%t FS type (hex) |%T FS type (driver name)''' %S Best transfer size |%t FS type (hex) |%T FS type (driver name)'''
command = 'stat -c "%A;%F;%U;%G" {};echo $?'.format(file) command = 'stat -c "%A;%F;%U;%G" {};echo $?'.format(file)
res = self.sudo(command,output = "out")
output,res = res.split('\n')
res = self.sudo(command, output="out")
output, res = res.split('\n')
if res == '0': if res == '0':
return output.split(';') return output.split(';')
def exists(self,file):
def exists(self, file):
return self.stat(file) is not None return self.stat(file) is not None
def isfile(self,file):
def isfile(self, file):
return self.stat(file)[1] == 'file' return self.stat(file)[1] == 'file'
def isdir(self,file):
def isdir(self, file):
return self.stat(file)[1] == 'directory' return self.stat(file)[1] == 'directory'
def islink(self,file):
def islink(self, file):
return self.stat(file)[1] == 'symbolic link' return self.stat(file)[1] == 'symbolic link'
def delete(self,path):
return self.sudo("rm","-rf",path,output="out")
def delete(self, path):
return self.sudo("rm", "-rf", path, output="out")
def copy(self,remote,local,del_duplicates = True,ignore_error=True):
def copy(self, remote, local, del_duplicates=True, ignore_error=True):
remote_stat = self.stat(remote) remote_stat = self.stat(remote)
if remote_stat is not None: if remote_stat is not None:
if remote_stat[1] == "directory" and not remote.endswith('/'): if remote_stat[1] == "directory" and not remote.endswith('/'):
@ -208,54 +217,57 @@ The valid format escape sequences for filesystems:
if os.path.exists(local): if os.path.exists(local):
last = os.path.split(local)[-1] last = os.path.split(local)[-1]
real_dir = local real_dir = local
local = os.path.join(config['local']['temp'],last)
local = os.path.join(config['local']['temp'], last)
merge_flag = True merge_flag = True
try: try:
self.adb("pull","-a",remote,local)
self.adb("pull", "-a", remote, local)
except subprocess.CalledProcessError as e: except subprocess.CalledProcessError as e:
if ignore_error: if ignore_error:
pass pass
else: else:
raise e raise e
if merge_flag: if merge_flag:
merge(local,real_dir)
merge(local, real_dir)
if os.path.exists(local) and del_duplicates: if os.path.exists(local) and del_duplicates:
shutil.rmtree(local) shutil.rmtree(local)
else: else:
print("File not found: {}".format(remote)) print("File not found: {}".format(remote))
def move(self,remote,local,del_duplicates = True,ignore_error=False):
def move(self, remote, local, del_duplicates=True, ignore_error=False):
if self.exists(remote): if self.exists(remote):
self.copy(remote,local,del_duplicates = del_duplicates,ignore_error=ignore_error)
self.copy(remote, local, del_duplicates=del_duplicates,
ignore_error=ignore_error)
self.delete(remote) self.delete(remote)
else: else:
print("File not found: {}".format(remote)) print("File not found: {}".format(remote))
def push(self,local,remote):
self.adb('push',local,remote)
def push(self, local, remote):
self.adb('push', local, remote)
class Input(ADBWrapper): class Input(ADBWrapper):
def send_keycode(self,code):
def send_keycode(self, code):
try: try:
keycode = keycodes[code] keycode = keycodes[code]
except KeyError: except KeyError:
keycode = str(code) keycode = str(code)
self.shell("input","keyevent",keycode)
self.shell("input", "keyevent", keycode)
def unlock_phone(self,password):
def unlock_phone(self, password):
if self.mode == 'recovery': if self.mode == 'recovery':
return return
if not decode_parcel(self.shell('service','call', 'power','12',output="out"),'int'):
if not decode_parcel(self.shell('service', 'call', 'power', '12', output="out"), 'int'):
self.send_keycode('power') self.send_keycode('power')
if decode_parcel(self.shell('service','call','trust','7',output="out"),'int'):
if decode_parcel(self.shell('service', 'call', 'trust', '7', output="out"), 'int'):
self.send_keycode('space') self.send_keycode('space')
self.shell("input","text",str(password))
self.shell("input", "text", str(password))
self.send_keycode('enter') self.send_keycode('enter')
class TWRP(FSActionWrapper): class TWRP(FSActionWrapper):
def backup(self,*partitions,name = None,backupdir = None):
def backup(self, *partitions, name=None, backupdir=None):
if self.mode != 'recovery': if self.mode != 'recovery':
self.reboot('recovery') self.reboot('recovery')
if backupdir is None: if backupdir is None:
@ -275,33 +287,38 @@ class TWRP(FSActionWrapper):
} }
options = "".join(options_dict[option] for option in partitions) options = "".join(options_dict[option] for option in partitions)
if not name: if not name:
name = "backup_"+datetime.datetime.today().strftime(defaults['date_format'])
filename = os.path.join(backupdir,name)
self.shell("twrp","backup",options,name)
phone_dir = "/data/media/0/TWRP/BACKUPS/{serial}/{name}".format(serial = self.serial,name = name)
self.move(phone_dir,filename)
def wipe(self,partition):
name = "backup_" + \
datetime.datetime.today().strftime(defaults['date_format'])
filename = os.path.join(backupdir, name)
self.shell("twrp", "backup", options, name)
phone_dir = "/data/media/0/TWRP/BACKUPS/{serial}/{name}".format(
serial=self.serial, name=name)
self.move(phone_dir, filename)
def wipe(self, partition):
if self.mode != 'recovery': if self.mode != 'recovery':
self.reboot('recovery') self.reboot('recovery')
self.shell("twrp","wipe",partition)
self.shell("twrp", "wipe", partition)
def install(self,name):
def install(self, name):
if self.mode != 'recovery': if self.mode != 'recovery':
self.reboot('recovery') self.reboot('recovery')
if os.path.exists(name): if os.path.exists(name):
local_name = name local_name = name
name = os.path.split(name)[-1] name = os.path.split(name)[-1]
update_path = '{}/{}'.format(config['remote']['updates'],name)
update_path = '{}/{}'.format(config['remote']['updates'], name)
if not self.exists(config['remote']['updates']): if not self.exists(config['remote']['updates']):
self.sudo('mkdir',config['remote']['updates'])
self.sudo('mkdir', config['remote']['updates'])
if not self.exists(update_path): if not self.exists(update_path):
self.push(local_name,config['remote']['updates'])
self.push(local_name, config['remote']['updates'])
else: else:
update_path = '{}/{}'.format(config['remote']['updates'],name)
self.shell("twrp","install",update_path)
update_path = '{}/{}'.format(config['remote']['updates'], name)
self.shell("twrp", "install", update_path)
class Device(TWRP,Input):
class Device(TWRP, Input):
pass pass
if __name__ == "__main__" and debug: if __name__ == "__main__" and debug:
d = Device.prim_device() d = Device.prim_device()

1
pyadb/extras/__init__.py

@ -1 +0,0 @@

10
pyadb/extras/open_youtube.py

@ -1,7 +1,11 @@
from adb import Device from adb import Device
import pyperclip import pyperclip
def open_youtube(Device,link):
Device.shell(*('am start -a android.intent.action.VIEW'.split(' ')),link)
def open_youtube(Device, link):
Device.shell(*('am start -a android.intent.action.VIEW'.split(' ')), link)
if __name__ == "__main__": if __name__ == "__main__":
d = Device.prim_device() d = Device.prim_device()
open_youtube(d,pyperclip.paste())
open_youtube(d, pyperclip.paste())

15
pyadb/extras/sync_clip.py

@ -1,18 +1,25 @@
import pyperclip import pyperclip
import time import time
import re import re
def sync_clipboard(dev): def sync_clipboard(dev):
db_file = '/data/data/com.catchingnow.tinyclipboardmanager/databases/clippingnow.db' db_file = '/data/data/com.catchingnow.tinyclipboardmanager/databases/clippingnow.db'
try: try:
pid = dev.shell('pidof','com.catchingnow.tinyclipboardmanager',output="out")
dev.sudo('kill',pid,output='shell')
pid = dev.shell(
'pidof', 'com.catchingnow.tinyclipboardmanager', output="out")
dev.sudo('kill', pid, output='shell')
except: except:
pass pass
t = time.time() t = time.time()
text = pyperclip.paste() text = pyperclip.paste()
conn = dev.db_connect(db_file) conn = dev.db_connect(db_file)
out = conn.execute("INSERT INTO cliphistory VALUES (?,?,?);",[int(1000*t),text,False])
dev.shell('am', 'start', '-n', 'com.catchingnow.tinyclipboardmanager/.activity.ActivityMain')
out = conn.execute("INSERT INTO cliphistory VALUES (?,?,?);", [
int(1000*t), text, False])
dev.shell('am', 'start', '-n',
'com.catchingnow.tinyclipboardmanager/.activity.ActivityMain')
if __name__ == "__main__": if __name__ == "__main__":
import adb import adb
d = adb.Device.prim_device() d = adb.Device.prim_device()

1
pyadb/internal/__init__.py

@ -1 +0,0 @@

34
pyadb/internal/android_db.py

@ -5,48 +5,54 @@ import sys
csv.field_size_limit(2**31-1) csv.field_size_limit(2**31-1)
dict_params = re.compile(r':([^\ \,\.\\\(\)\=]+)') dict_params = re.compile(r':([^\ \,\.\\\(\)\=]+)')
list_params = re.compile(r'\?') list_params = re.compile(r'\?')
class AndroidSQLConn: class AndroidSQLConn:
def __init__(self,device,filepath,use_root=True):
def __init__(self, device, filepath, use_root=True):
self.device = device self.device = device
self.filepath = filepath self.filepath = filepath
self.root = use_root self.root = use_root
def _quote_param_(param): def _quote_param_(param):
if isinstance(param,str):
return "'{}'".format(param.replace("'","''"))
elif isinstance(param,bool):
if isinstance(param, str):
return "'{}'".format(param.replace("'", "''"))
elif isinstance(param, bool):
return '1' if param else '0' return '1' if param else '0'
elif param is None: elif param is None:
return 'NULL' return 'NULL'
else: else:
return str(param) return str(param)
def _sub_params_(SQL,params):
def _sub_params_(SQL, params):
params = iter(params) params = iter(params)
try: try:
return list_params.sub(lambda match: AndroidSQLConn._quote_param_(next(params)),SQL)
return list_params.sub(lambda match: AndroidSQLConn._quote_param_(next(params)), SQL)
except StopIteration: except StopIteration:
raise TypeError("Not enough parameters") raise TypeError("Not enough parameters")
def _sub_params_dict_(SQL,params):
def _sub_params_dict_(SQL, params):
try: try:
return dict_params.sub(lambda match: AndroidSQLConn._quote_param_(params[match.group(1)]),SQL)
return dict_params.sub(lambda match: AndroidSQLConn._quote_param_(params[match.group(1)]), SQL)
except KeyError: except KeyError:
raise TypeError("Parameter specified but not in mapping") raise TypeError("Parameter specified but not in mapping")
def execute(self,SQL,params = None):
def execute(self, SQL, params=None):
if params: if params:
if isinstance(params,dict):
SQL = AndroidSQLConn._sub_params_dict_(SQL,params)
if isinstance(params, dict):
SQL = AndroidSQLConn._sub_params_dict_(SQL, params)
else: else:
SQL = AndroidSQLConn._sub_params_(SQL,params)
SQL = AndroidSQLConn._sub_params_(SQL, params)
SQL = shlex.quote(SQL) SQL = shlex.quote(SQL)
if self.root: if self.root:
shell = self.device.sudo shell = self.device.sudo
else: else:
shell = self.device.shell shell = self.device.shell
out = shell('sqlite3','-header','-csv',shlex.quote(self.filepath),SQL,output="out")
out = shell('sqlite3', '-header', '-csv',
shlex.quote(self.filepath), SQL, output="out")
if out: if out:
return csv.DictReader(out.splitlines()) return csv.DictReader(out.splitlines())
if __name__ == "__main__": if __name__ == "__main__":
print(AndroidSQLConn._sub_params_("SELECT * FROM table WHERE name=?,age=?;",["boby;DROP TABLE table",1]))
print(AndroidSQLConn._sub_params_(
"SELECT * FROM table WHERE name=?,age=?;", ["boby;DROP TABLE table", 1]))

34
pyadb/internal/cli_wrap.py

@ -1,41 +1,42 @@
import subprocess import subprocess
import shlex import shlex
class AdbWrapper: class AdbWrapper:
def __init__(self, def __init__(self,
executable_path, executable_path,
serial = None
serial=None
): ):
self.executable_path = executable_path self.executable_path = executable_path
self.serial = serial self.serial = serial
self.selfrooted = False self.selfrooted = False
def exec(self,comspec,output_streams = False):
if isinstance(comspec,str):
def exec(self, comspec, output_streams=False):
if isinstance(comspec, str):
comspec = shlex.split(comspec) comspec = shlex.split(comspec)
comspec.insert(0,self.executable_path)
comspec.insert(0, self.executable_path)
if self.serial: if self.serial:
comspec = comspec[:1] + ['-s',self.serial] + comspec[1:]
comspec = comspec[:1] + ['-s', self.serial] + comspec[1:]
if output_streams: if output_streams:
res = subprocess.run(comspec,capture_output=True,check=True)
res = subprocess.run(comspec, capture_output=True, check=True)
return res.stdout return res.stdout
else: else:
ret = subprocess.check_call(comspec,shell=False)
ret = subprocess.check_call(comspec, shell=False)
def shell(self,comspec,output_streams = False):
if isinstance(comspec,str):
def shell(self, comspec, output_streams=False):
if isinstance(comspec, str):
comspec = shlex.split(comspec) comspec = shlex.split(comspec)
comspec.insert(0,'exec-out')
return self.exec(comspec,output_streams)
comspec.insert(0, 'exec-out')
return self.exec(comspec, output_streams)
def sudo(self,comspec,output_streams = False):
def sudo(self, comspec, output_streams=False):
if not self.rooted: if not self.rooted:
comspec = ['su','--','--'] + comspec
return self.shell(comspec,output_streams)
comspec = ['su', '--', '--'] + comspec
return self.shell(comspec, output_streams)
def root(self): def root(self):
self.exec('root') self.exec('root')
@ -45,8 +46,9 @@ class AdbWrapper:
self.exec('unroot') self.exec('unroot')
self.rooted = False self.rooted = False
if __name__ == "__main__": if __name__ == "__main__":
exec_path = r"C:\Program Files\platform-tools\adb.exe" exec_path = r"C:\Program Files\platform-tools\adb.exe"
wrapper = AdbWrapper(exec_path,'LGD415d60b8c9b')
wrapper = AdbWrapper(exec_path, 'LGD415d60b8c9b')
wrapper.root() wrapper.root()
wrapper.sudo(['ls','/'])
wrapper.sudo(['ls', '/'])

13
pyadb/internal/load_config.py

@ -2,13 +2,14 @@ import json
import munch import munch
import os import os
import configparser import configparser
path = os.path.abspath(os.path.join(os.path.dirname(__file__),'..\\'))
parser = configparser.ConfigParser(interpolation=configparser.ExtendedInterpolation())
parser.read(os.path.join(path,'config.ini'))
with open(os.path.join(path,'keycodes.json')) as k:
path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..\\'))
parser = configparser.ConfigParser(
interpolation=configparser.ExtendedInterpolation())
parser.read(os.path.join(path, 'config.ini'))
with open(os.path.join(path, 'keycodes.json')) as k:
keycodes = munch.munchify(json.load(k)) keycodes = munch.munchify(json.load(k))
config = parser.__dict__['_sections'] config = parser.__dict__['_sections']
for key,value in config['local'].items():
for key, value in config['local'].items():
config['local'][key] = os.path.expandvars(value) config['local'][key] = os.path.expandvars(value)
loaded = munch.munchify(dict(config = config,keycodes = keycodes))
loaded = munch.munchify(dict(config=config, keycodes=keycodes))

8
pyadb/test.py

@ -1,6 +1,8 @@
import time
from adb import Device from adb import Device
d = Device.prim_device() d = Device.prim_device()
import time
d.root() d.root()
conn = d.db_connect('/data/data/com.catchingnow.tinyclipboardmanager/databases/clippingnow.db')
out = conn.execute('INSERT INTO cliphistory (date,history,star) values (?,?,?)',[int(time.time()*1000),"test_test",False])
conn = d.db_connect(
'/data/data/com.catchingnow.tinyclipboardmanager/databases/clippingnow.db')
out = conn.execute('INSERT INTO cliphistory (date,history,star) values (?,?,?)', [
int(time.time()*1000), "test_test", False])

1
setup.py

@ -1 +0,0 @@
Loading…
Cancel
Save