00001
00002
00003
00004 licenceEn="""
00005 file usbThread.py
00006 this file is part of the project scolasync
00007
00008 Copyright (C) 2010 Georges Khaznadar <georgesk@ofset.org>
00009
00010 This program is free software: you can redistribute it and/or modify
00011 it under the terms of the GNU General Public License as published by
00012 the Free Software Foundation, either version3 of the License, or
00013 (at your option) any later version.
00014
00015 This program is distributed in the hope that it will be useful,
00016 but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00018 GNU General Public License for more details.
00019
00020 You should have received a copy of the GNU General Public License
00021 along with this program. If not, see <http://www.gnu.org/licenses/>.
00022 """
00023
00024 import subprocess, threading, re, os, os.path, shutil, time, glob, shlex
00025 from PyQt4.QtCore import *
00026
00027 _threadNumber=0
00028
00029
00030
00031
00032
00033 class ThreadRegister:
00034
00035
00036
00037
00038
00039 def __init__(self):
00040 self.dico={}
00041
00042 def __str__(self):
00043 return "ThreadRegister: %s" %self.dico
00044
00045
00046
00047
00048
00049
00050
00051 def push(self, ud, thread):
00052 if ud.owner not in self.dico.keys():
00053 self.dico[ud.owner]=[thread]
00054 else:
00055 self.dico[ud.owner].append(thread)
00056
00057
00058
00059
00060
00061
00062
00063 def pop(self, ud, thread):
00064 self.dico[ud.owner].remove(thread)
00065
00066
00067
00068
00069
00070
00071
00072 def busy(self, owner):
00073 if owner in self.dico.keys():
00074 return self.dico[owner]
00075 return []
00076
00077
00078
00079
00080
00081 def threadSet(self):
00082 result=set()
00083 for o in self.dico.keys():
00084 for t in self.dico[o]:
00085 result.add(t)
00086 return result
00087
00088
00089
00090
00091
00092
00093
00094
00095 def _sanitizePath(path):
00096 pattern=re.compile(".*([^/]+)")
00097 m=pattern.match(str(path))
00098 if m:
00099 return m.group(1)
00100 else:
00101 return str(path).replace('/','_')
00102
00103
00104
00105
00106
00107
00108
00109
00110 def _threadName(ud):
00111 global _threadNumber
00112 name="th_%04d_%s" %(_threadNumber,_sanitizePath(ud.path))
00113 _threadNumber+=1
00114 return name
00115
00116
00117
00118
00119
00120
00121 def _date():
00122 return time.strftime("%Y/%m/%d-%H:%M:%S")
00123
00124
00125
00126
00127
00128
00129
00130 class abstractThreadUSB(threading.Thread):
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143 def __init__(self,ud, fileList, subdir, dest=None, logfile="/dev/null",
00144 parent=None):
00145 threading.Thread.__init__(self,target=self.toDo,
00146 args=(ud, fileList, subdir, dest, logfile),
00147 name=_threadName(ud))
00148 self.cmd=u"echo This is an abstract method, don't call it"
00149 self.ud=ud
00150 ud.threadRunning=True
00151 self.fileList=fileList
00152 self.subdir=subdir
00153 self.dest=dest
00154 self.logfile=logfile
00155 self.parent=parent
00156
00157
00158
00159
00160
00161
00162 def writeToLog(self, msg):
00163 open(os.path.expanduser(self.logfile),"a").write(msg+"\n")
00164 return
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179 def copytree(self,src, dst, symlinks=False, ignore=None, erase=False, errors=[]):
00180 names = os.listdir(src)
00181 if ignore is not None:
00182 ignored_names = ignore(src, names)
00183 else:
00184 ignored_names = set()
00185
00186 try:
00187 os.makedirs(dst)
00188 except OSError, err:
00189 pass
00190 for name in names:
00191 if name in ignored_names:
00192 continue
00193 srcname = os.path.join(src, name)
00194 dstname = os.path.join(dst, name)
00195 try:
00196 if symlinks and os.path.islink(srcname):
00197 linkto = os.readlink(srcname)
00198 os.symlink(linkto, dstname)
00199 if not errors and erase:
00200 os.unlink(srcname)
00201 elif os.path.isdir(srcname):
00202 errors=self.copytree(srcname, dstname,
00203 symlinks=symlinks, ignore=ignore,
00204 erase=erase, errors=errors)
00205 if not errors and erase:
00206 os.rmdir(srcname)
00207 else:
00208 shutil.copy2(srcname, dstname)
00209 if not errors and erase:
00210 os.unlink(srcname)
00211
00212 except (IOError, os.error), why:
00213 errors.append((srcname, dstname, str(why)))
00214
00215
00216 except Exception, err:
00217 errors.extend(err.args[0])
00218 return errors
00219
00220
00221
00222
00223
00224
00225
00226 def __str__(self):
00227 result="%s(\n" %self.threadType()
00228 result+=" ud = %s\n" %self.ud
00229 result+=" fileList = %s\n" %self.fileList
00230 result+=" subdir = %s\n" %self.subdir
00231 result+=" dest = %s\n" %self.dest
00232 result+=" logfile = %s\n" %self.logfile
00233 result+=" cmd = %s\n" %self.cmd
00234 result+="\n"
00235 return result
00236
00237
00238
00239
00240
00241 def threadType(self):
00242 return "abstractThreadUSB"
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253 def toDo(self, ud, fileList, subdir, dest, logfile):
00254
00255 pass
00256
00257
00258
00259
00260
00261 class threadCopyToUSB(abstractThreadUSB):
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273 def __init__(self,ud, fileList, subdir, logfile="/dev/null",
00274 parent=None):
00275 abstractThreadUSB.__init__(self,ud, fileList, subdir, dest=None, logfile=logfile, parent=parent)
00276 self.cmd=u'mkdir -p "{toDir}"; cp -R {fromFile} "{toDir}"'
00277
00278
00279
00280
00281
00282 def threadType(self):
00283 return "threadCopyToUSB"
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297 def toDo(self, ud, fileList, subdir, dest, logfile):
00298 while subdir[0]=='/':
00299 subdir=subdir[1:]
00300 destpath=os.path.join(ud.ensureMounted(),ud.visibleDir(),subdir)
00301 for f in fileList:
00302 cmd="copying %s to %s" %(f, destpath)
00303 if self.parent:
00304 self.parent.emit(SIGNAL("pushCmd(QString, QString)"), ud.owner, cmd)
00305 destpath1=os.path.join(destpath, os.path.basename(f))
00306 if os.path.isdir(f):
00307 errors=self.copytree(f, destpath1)
00308 else:
00309 errors=[]
00310 try:
00311 shutil.copy2(f, destpath1)
00312 except Exceptio, err:
00313 errors.extend((f, destpath1, str(err)))
00314
00315 msg="[%s] " %_date()
00316 if not errors:
00317 msg += "Success: "
00318 else:
00319 msg += "Error: "
00320 msg += cmd
00321 for e in errors:
00322 msg += " <%s>" %e
00323 if self.parent:
00324 self.parent.emit(SIGNAL("popCmd(QString, QString)"), ud.owner, msg)
00325 self.writeToLog(msg)
00326
00327
00328
00329
00330
00331 class threadCopyFromUSB(abstractThreadUSB):
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345 def __init__(self,ud, fileList, subdir=".", dest="/tmp",
00346 rootPath="/", logfile="/dev/null", parent=None):
00347 abstractThreadUSB.__init__(self,ud, fileList, subdir, dest=dest,
00348 logfile=logfile, parent=parent)
00349 self.rootPath=rootPath
00350 self.cmd=u'mkdir -p "{toPath}"; cp -R {fromPath} "{toPath}"'
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363 def toDo(self, ud, fileList, subdir, dest, logfile):
00364
00365 for f in fileList:
00366
00367 fromPath=os.path.join(ud.ensureMounted(), f)
00368 owner=ud.ownerByDb()
00369
00370 newName=u"%s_%s" %(owner,os.path.dirname(f))
00371
00372 toPath=os.path.join(dest,newName)
00373 cmd="copying %s to %s" %(fromPath, toPath)
00374 if self.parent:
00375 self.parent.emit(SIGNAL("pushCmd(QString, QString)"), ud.owner, cmd)
00376 destpath1=os.path.join(toPath, os.path.basename(f))
00377 if os.path.isdir(fromPath):
00378 errors=self.copytree(fromPath, destpath1)
00379 else:
00380 errors=[]
00381 try:
00382 shutil.copy2(fromPath, destpath1)
00383 except Exception, err:
00384 errors.extend((fromPath, destpath1, str(err)))
00385
00386 msg="[%s] " %_date()
00387 if not errors:
00388 msg += "Success: "
00389 else:
00390 msg += "Error: "
00391 msg += cmd
00392 for e in errors:
00393 msg += " <%s>" %e
00394 if self.parent:
00395 self.parent.emit(SIGNAL("popCmd(QString, QString)"), ud.owner, msg)
00396 self.writeToLog(msg)
00397
00398
00399
00400
00401
00402 class threadMoveFromUSB(abstractThreadUSB):
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416 def __init__(self,ud, fileList, subdir=".", dest="/tmp",
00417 rootPath="/", logfile="/dev/null", parent=None):
00418 abstractThreadUSB.__init__(self,ud, fileList, subdir, dest=dest,
00419 logfile=logfile, parent=parent)
00420 self.rootPath=rootPath
00421 self.cmd=u'mkdir -p "{toPath}"; cp -R {fromPath} "{toPath}" && rm -rf {fromPath}'
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435 def toDo(self, ud, fileList, subdir, dest, logfile):
00436 for f in fileList:
00437
00438 fromPath=os.path.join(ud.ensureMounted(), f)
00439 owner=ud.ownerByDb()
00440
00441 newName=u"%s_%s" %(owner,os.path.dirname(f))
00442
00443 toPath=os.path.join(dest,newName)
00444 cmd="copying %s to %s" %(fromPath, toPath)
00445 if self.parent:
00446 self.parent.emit(SIGNAL("pushCmd(QString, QString)"), ud.owner, cmd)
00447 destpath1=os.path.join(toPath, os.path.basename(f))
00448 if os.path.isdir(fromPath):
00449 errors=self.copytree(fromPath, destpath1, erase=True)
00450 try:
00451 os.rmdir(fromPath)
00452 except Exception, err:
00453 errors.extend((fromPath, destpath1, str(err)))
00454 else:
00455 errors=[]
00456 try:
00457 shutil.copy2(fromPath, destpath1)
00458 os.unlink(fromPath)
00459 except Exception, err:
00460 errors.extend((fromPath, destpath1, str(err)))
00461
00462 msg="[%s] " %_date()
00463 if not errors:
00464 msg += "Success: "
00465 else:
00466 msg += "Error: "
00467 msg += cmd
00468 for e in errors:
00469 msg += " <%s>" %e
00470 if self.parent:
00471 self.parent.emit(SIGNAL("popCmd(QString, QString)"), ud.owner, msg)
00472 self.writeToLog(msg)
00473
00474
00475
00476
00477
00478 class threadDeleteInUSB(abstractThreadUSB):
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490 def __init__(self,ud, fileList, subdir, logfile="/dev/null",
00491 parent=None):
00492 abstractThreadUSB.__init__(self,ud, fileList, subdir, dest=None,
00493 logfile=logfile, parent=parent)
00494 self.cmd=u'rm -rf {toDel}'
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509 def toDo(self, ud, fileList, subdir, dest, logfile):
00510 for f in fileList:
00511 toDel=os.path.join(ud.ensureMounted(), f)
00512 cmd="Deleting %s" %toDel
00513 errors=[]
00514 if self.parent:
00515 self.parent.emit(SIGNAL("pushCmd(QString, QString)"), ud.owner, cmd)
00516 if os.path.isdir(toDel):
00517 try:
00518 for root, dirs, files in os.walk(toDel, topdown=False):
00519 for name in files:
00520 os.remove(os.path.join(root, name))
00521 for name in dirs:
00522 os.rmdir(os.path.join(root, name))
00523 os.rmdir(toDel)
00524 except Exception, err:
00525 errors.expand((toDel,str(err)))
00526 else:
00527 try:
00528 os.unlink(toDel)
00529 except Exception, err:
00530 errors.expand((toDel,str(err)))
00531 msg="[%s] " %_date()
00532 if not errors:
00533 msg += "Success: "
00534 else:
00535 msg += "Error: "
00536 msg += cmd
00537 for e in errors:
00538 msg += " <%s>" %e
00539 if self.parent:
00540 self.parent.emit(SIGNAL("popCmd(QString, QString)"), ud.owner, msg)
00541 self.writeToLog(msg)
00542