pysynch.py 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. # Simple CE synchronisation utility with Python features.
  2. import wincerapi
  3. import win32api
  4. import win32file
  5. import getopt
  6. import sys
  7. import os
  8. import string
  9. import win32con
  10. import fnmatch
  11. class InvalidUsage(Exception): pass
  12. def print_error(api_exc, msg):
  13. hr, fn, errmsg = api_exc
  14. print("%s - %s(%d)" % (msg, errmsg, hr))
  15. def GetFileAttributes(file, local=1):
  16. if local: return win32api.GetFileAttributes(file)
  17. else: return wincerapi.CeGetFileAttributes(file)
  18. def FindFiles(spec, local=1):
  19. if local: return win32api.FindFiles(spec)
  20. else: return wincerapi.CeFindFiles(spec)
  21. def isdir(name, local=1):
  22. try:
  23. attr = GetFileAttributes(name, local)
  24. return attr & win32con.FILE_ATTRIBUTE_DIRECTORY
  25. except win32api.error:
  26. return 0
  27. def CopyFileToCe(src_name, dest_name, progress = None):
  28. sh = win32file.CreateFile(src_name, win32con.GENERIC_READ, 0, None, win32con.OPEN_EXISTING, 0, None)
  29. bytes=0
  30. try:
  31. dh = wincerapi.CeCreateFile(dest_name, win32con.GENERIC_WRITE, 0, None, win32con.OPEN_ALWAYS, 0, None)
  32. try:
  33. while 1:
  34. hr, data = win32file.ReadFile(sh, 2048)
  35. if not data:
  36. break
  37. wincerapi.CeWriteFile(dh, data)
  38. bytes = bytes + len(data)
  39. if progress is not None: progress(bytes)
  40. finally:
  41. pass
  42. dh.Close()
  43. finally:
  44. sh.Close()
  45. return bytes
  46. def BuildFileList(spec, local, recurse, filter, filter_args, recursed_path = ""):
  47. files = []
  48. if isdir(spec, local):
  49. path = spec
  50. raw_spec = "*"
  51. else:
  52. path, raw_spec = os.path.split(spec)
  53. if recurse:
  54. # Need full scan, to get sub-direcetories.
  55. infos = FindFiles(os.path.join(path, "*"), local)
  56. else:
  57. infos = FindFiles(os.path.join(path, raw_spec), local)
  58. for info in infos:
  59. src_name = str(info[8])
  60. full_src_name = os.path.join(path, src_name)
  61. if local: # Can't do this for CE!
  62. full_src_name = win32api.GetFullPathName(full_src_name)
  63. if isdir(full_src_name, local) :
  64. if recurse and src_name not in ['.','..']:
  65. new_spec = os.path.join(full_src_name, raw_spec)
  66. files = files + BuildFileList(new_spec, local, 1, filter, filter_args, os.path.join(recursed_path, src_name))
  67. if fnmatch.fnmatch(src_name, raw_spec):
  68. rel_name = os.path.join(recursed_path, src_name)
  69. filter_data = filter( full_src_name, rel_name, info, local, filter_args )
  70. if filter_data is not None:
  71. files.append( (full_src_name, info, filter_data) )
  72. return files
  73. def _copyfilter(full_name, rel_name, info, local, bMaintainDir):
  74. if isdir(full_name, local): return
  75. if bMaintainDir:
  76. return rel_name
  77. return os.path.split(rel_name)[1]
  78. import pywin.dialogs.status, win32ui
  79. class FileCopyProgressDialog(pywin.dialogs.status.CStatusProgressDialog):
  80. def CopyProgress(self, bytes):
  81. self.Set(bytes/1024)
  82. def copy( args ):
  83. """copy src [src ...], dest
  84. Copy files to/from the CE device
  85. """
  86. bRecurse = bVerbose = 0
  87. bMaintainDir = 1
  88. try:
  89. opts, args = getopt.getopt(args, "rv")
  90. except getopt.error as details:
  91. raise InvalidUsage(details)
  92. for o, v in opts:
  93. if o=="-r":
  94. bRecuse=1
  95. elif o=='-v':
  96. bVerbose=1
  97. if len(args)<2:
  98. raise InvalidUsage("Must specify a source and destination")
  99. src = args[:-1]
  100. dest = args[-1]
  101. # See if WCE: leading anywhere indicates a direction.
  102. if string.find(src[0], "WCE:")==0:
  103. bToDevice = 0
  104. elif string.find(dest, "WCE:")==0:
  105. bToDevice = 1
  106. else:
  107. # Assume copy to device.
  108. bToDevice = 1
  109. if not isdir(dest, not bToDevice):
  110. print("%s does not indicate a directory")
  111. files = [] # List of FQ (from_name, to_name)
  112. num_files = 0
  113. num_bytes = 0
  114. dialog = FileCopyProgressDialog("Copying files")
  115. dialog.CreateWindow(win32ui.GetMainFrame())
  116. if bToDevice:
  117. for spec in src:
  118. new = BuildFileList(spec, 1, bRecurse, _copyfilter, bMaintainDir)
  119. if not new:
  120. print("Warning: '%s' did not match any files" % (spec))
  121. files = files + new
  122. for full_src, src_info, dest_info in files:
  123. dest_name = os.path.join(dest, dest_info)
  124. size = src_info[5]
  125. print("Size=", size)
  126. if bVerbose:
  127. print(full_src, "->", dest_name,"- ", end=' ')
  128. dialog.SetText(dest_name)
  129. dialog.Set(0, size/1024)
  130. bytes = CopyFileToCe(full_src, dest_name, dialog.CopyProgress)
  131. num_bytes = num_bytes + bytes
  132. if bVerbose:
  133. print(bytes, "bytes")
  134. num_files = num_files + 1
  135. dialog.Close()
  136. print("%d files copied (%d bytes)" % (num_files, num_bytes))
  137. def _dirfilter(*args):
  138. return args[1]
  139. def dir(args):
  140. """dir directory_name ...
  141. Perform a directory listing on the remote device
  142. """
  143. bRecurse = 0
  144. try:
  145. opts, args = getopt.getopt(args, "r")
  146. except getopt.error as details:
  147. raise InvalidUsage(details)
  148. for o, v in opts:
  149. if o=="-r":
  150. bRecurse=1
  151. for arg in args:
  152. print("Directory of WCE:%s" % arg)
  153. files = BuildFileList(arg, 0, bRecurse, _dirfilter, None)
  154. total_size=0
  155. for full_name, info, rel_name in files:
  156. date_str = info[3].Format("%d-%b-%Y %H:%M")
  157. attr_string = " "
  158. if info[0] & win32con.FILE_ATTRIBUTE_DIRECTORY: attr_string = "<DIR>"
  159. print("%s %s %10d %s" % (date_str, attr_string, info[5], rel_name))
  160. total_size = total_size + info[5]
  161. print(" " * 14 + "%3d files, %10d bytes" % (len(files), total_size))
  162. def run(args):
  163. """run program [args]
  164. Starts the specified program on the remote device.
  165. """
  166. prog_args = []
  167. for arg in args:
  168. if " " in arg:
  169. prog_args.append('"' + arg + '"')
  170. else:
  171. prog_args.append(arg)
  172. prog_args = string.join(prog_args, " ")
  173. wincerapi.CeCreateProcess(prog_args, "", None, None, 0, 0, None, "", None)
  174. def delete(args):
  175. """delete file, ...
  176. Delete one or more remote files
  177. """
  178. for arg in args:
  179. try:
  180. wincerapi.CeDeleteFile(arg)
  181. print("Deleted: %s" % arg)
  182. except win32api.error as details:
  183. print_error(details, "Error deleting '%s'" % arg)
  184. def DumpCommands():
  185. print("%-10s - %s" % ("Command", "Description"))
  186. print("%-10s - %s" % ("-------", "-----------"))
  187. for name, item in list(globals().items()):
  188. if type(item)==type(DumpCommands):
  189. doc = getattr(item, "__doc__", "")
  190. if doc:
  191. lines = string.split(doc, "\n")
  192. print("%-10s - %s" % (name, lines[0]))
  193. for line in lines[1:]:
  194. if line:
  195. print(" " * 8, line)
  196. def main():
  197. if len(sys.argv)<2:
  198. print("You must specify a command!")
  199. DumpCommands()
  200. return
  201. command = sys.argv[1]
  202. fn = globals().get(command)
  203. if fn is None:
  204. print("Unknown command:", command)
  205. DumpCommands()
  206. return
  207. wincerapi.CeRapiInit()
  208. try:
  209. verinfo = wincerapi.CeGetVersionEx()
  210. print("Connected to device, CE version %d.%d %s" % (verinfo[0], verinfo[1], verinfo[4]))
  211. try:
  212. fn(sys.argv[2:])
  213. except InvalidUsage as msg:
  214. print("Invalid syntax -", msg)
  215. print(fn.__doc__)
  216. finally:
  217. try:
  218. wincerapi.CeRapiUninit()
  219. except win32api.error as details:
  220. print_error(details, "Error disconnecting")
  221. if __name__=='__main__':
  222. main()