You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

239 lines
7.2 KiB

8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
  1. import datetime
  2. import json
  3. import os
  4. import re
  5. import shutil
  6. import subprocess
  7. import time
  8. debug = True
  9. path = os.path.dirname(__file__)
  10. with open(os.path.join(path,'defaults.json')) as d,open(os.path.join(path,'keycodes.json')) as k:
  11. defaults = json.load(d)
  12. keycodes = json.load(k)
  13. exe = defaults['exe']
  14. for key,value in defaults['local'].items():
  15. defaults['local'][key] = os.path.expandvars(value)
  16. def merge(src, dst,log = False):
  17. if not os.path.exists(dst):
  18. return False
  19. ok = True
  20. for path, dirs, files in os.walk(src):
  21. relPath = os.path.relpath(path, src)
  22. destPath = os.path.join(dst, relPath)
  23. if not os.path.exists(destPath):
  24. os.makedirs(destPath)
  25. for file in files:
  26. destFile = os.path.join(destPath, file)
  27. if os.path.isfile(destFile):
  28. if log:
  29. print("Skipping existing file: " + os.path.join(relPath, file))
  30. ok = False
  31. continue
  32. srcFile = os.path.join(path, file)
  33. shutil.move(srcFile, destFile)
  34. for path, dirs, files in os.walk(src, False):
  35. if len(files) == 0 and len(dirs) == 0:
  36. os.rmdir(path)
  37. return ok
  38. def _adb(*args,out = False):
  39. args = [exe] + list(args)
  40. if out:
  41. return subprocess.check_output(args,shell = False).decode().rstrip('\r\n')
  42. else:
  43. subprocess.call(args,shell = False)
  44. def get_info():
  45. thing = _adb("devices","-l",out = True)
  46. formed = list(filter(bool,thing.split("\r\n")))[1:]
  47. main = {}
  48. for device in formed:
  49. categories = re.split(" +",device)
  50. device_dict = {
  51. "serial":categories[0],
  52. "mode":categories[1]
  53. }
  54. device_dict.update(dict(category.split(":") for category in categories[2:]))
  55. main[categories[0]] = device_dict
  56. return main
  57. class device:
  58. #init operations
  59. def prim_device():
  60. cont = True
  61. while cont:
  62. try:
  63. d = device()
  64. cont = False
  65. except IndexError:
  66. time.sleep(1)
  67. return d
  68. #todo connect over tcip
  69. def __init__(self,serial=None):
  70. if serial:
  71. self.serial = serial
  72. info = get_info()[serial]
  73. else:
  74. serial,info = list(get_info().items())[0]
  75. self.__dict__.update(info)
  76. #end of init operations
  77. #command interface
  78. def adb(self,*args,out = False):
  79. args = ['-s',self.serial]+ list(args)
  80. return _adb(*args,out = out)
  81. def sudo(self,*args,out = False,pie=True):
  82. if self.mode == 'recovery':
  83. args.insert(0,"shell")
  84. return self.adb(*args,out=out)
  85. else:
  86. args = '"{}"'.format(' '.join(args).replace('"','\\"'))
  87. return self.adb('shell','su','-c',args,out = out)
  88. #end of cammand interface
  89. #file operations
  90. def type(self,file):
  91. exists = '''if [ -e "{file}" ]; then
  92. if [ -d "{file}" ]; then
  93. echo "directory"
  94. elif [ -f "{file}" ]; then
  95. echo "file"
  96. else
  97. echo "error"
  98. fi
  99. else
  100. echo "na"
  101. fi'''
  102. e = exists.format(file = file)
  103. res = self.sudo(e,out=True)
  104. return res
  105. def exists(self,file):
  106. return self.type(file) != "na"
  107. def isfile(self,file):
  108. return self.type(file) == 'file'
  109. def isdir(self,file):
  110. return self.type(file) == 'directory'
  111. def delete(self,path):
  112. return self.sudo("rm","-rf",path,out=True)
  113. def copy(self,remote,local,del_duplicates = True,ignore_error=True):
  114. remote_type = self.type(remote)
  115. if remote_type != "na":
  116. if remote_type == "directory" and not remote.endswith('/'):
  117. remote += '/'
  118. flag = False
  119. if os.path.exists(local):
  120. last = os.path.split(local)[-1]
  121. real_dir = local
  122. local = os.path.join(defaults['local']['temp'],last)
  123. flag = True
  124. try:
  125. self.adb("pull","-a",remote,local,out=True)
  126. except subprocess.CalledProcessError as e:
  127. if ignore_error:
  128. pass
  129. else:
  130. raise e
  131. if flag:
  132. merge(local,real_dir)
  133. if os.path.exists(local) and del_duplicates:
  134. shutil.rmtree(local)
  135. else:
  136. print("File not found: {}".format(remote))
  137. def move(self,remote,local,del_duplicates = True,ignore_error=False):
  138. if self.exists(remote):
  139. self.copy(remote,local,del_duplicates = del_duplicates,ignore_error=ignore_error)
  140. self.delete(remote)
  141. else:
  142. print("File not found: {}".format(remote))
  143. def push(self,local,remote):
  144. self.adb('push',local,remote)
  145. #end of file operations
  146. #convenience
  147. def reboot(self,mode = None):
  148. if mode:
  149. if mode == "soft":
  150. if self.mode != 'recovery':
  151. pid = self.adb("shell","pidof","zygote",out = True)
  152. return self.sudo("kill",pid,out=False)
  153. else:
  154. return self.reboot()
  155. else:
  156. self.adb("reboot",mode)
  157. else:
  158. self.adb("reboot")
  159. while True:
  160. infos = get_info()
  161. if len(infos) > 0:
  162. self.__dict__.update(get_info()[self.serial])
  163. break
  164. time.sleep(1)
  165. def send_keycode(self,code):
  166. try:
  167. keycode = keycodes[code]
  168. except KeyError:
  169. keycode = str(code)
  170. self.adb("shell","input","keyevent",keycode)
  171. def unlock_phone(self,pin):
  172. self.send_keycode('power')
  173. self.send_keycode('space')
  174. self.adb("shell","input","text",str(pin))
  175. self.send_keycode('enter')
  176. #end of convenience
  177. #twrp
  178. def backup(self,*partitions,name = None):
  179. backupdir = defaults['local']['TWRP']
  180. options_dict = {
  181. "system": "S",
  182. "data": "D",
  183. "cache": "C",
  184. "recovery": "R",
  185. "spec_part_1": "1",
  186. "spec_part_2": "2",
  187. "spec_part_3": "3",
  188. "boot": "B",
  189. "as": "A"
  190. }
  191. options = "".join(options_dict[option] for option in partitions)
  192. if not name:
  193. name = "backup_"+datetime.datetime.today().strftime(defaults['date_format'])
  194. filename = os.path.join(backupdir,name)
  195. self.adb("shell","twrp","backup",options,name)
  196. phone_dir = "/data/media/0/TWRP/BACKUPS/{serial}/{name}".format(serial = self.serial,name = name)
  197. self.move(phone_dir,filename)
  198. def wipe(self,partition):
  199. self.adb("shell","twrp","wipe",partition)
  200. def install(self,name):
  201. if os.path.exists(name):
  202. local_name = name
  203. name = os.path.split(name)[-1]
  204. update_path = '{}/{}'.format(defaults['remote']['updates'],name)
  205. if not self.exists(update_path):
  206. self.push(local_name,defaults['remote']['updates'])
  207. else:
  208. update_path = '{}/{}'.format(defaults['remote']['updates'],name)
  209. self.adb("shell","twrp","install",update_path)
  210. #end of twrp
  211. if __name__ == "__main__" and debug:
  212. d = device.prim_device()