# -*- coding: utf-8 -*- """ Created on Sat Jul 12 21:42:56 2014 @author: yves """ import re, os, gnupg from subprocess import Popen, PIPE from PyQt5.QtCore import QDir, QFileInfo,pyqtSignal,QThread class checkThread(QThread): sha3Signal= pyqtSignal(int) dateSignal=pyqtSignal(int) sizeFinalSignal=pyqtSignal(int,str) checkStartSignal=pyqtSignal(int) def __init__(self, parent=None): super(checkThread, self).__init__(parent) def processSum(self,sumType): import hashlib checkvalue=0 if sumType=='sha3': hashfunc = hashlib.sha3_512() # Check if the sum file has a valid signature gpg = gnupg.GPG() gpg.encoding = 'utf-8' gpg.recv_keys('pgp.mit.edu', 'EDCA7A90') sum_file = self.destination+'/'+self.path+'/'+self.name+'.'+sumType sig_file = sum_file +'.gpg' try: with open(sig_file, 'rb') as g: verified = gpg.verify_file(g,sum_file) if verified.valid: checkvalue=64 print('Valid signature') else: print('Invalid signature for %s'%self.name+'.'+sumType) print(verified.key_status) return 0 except: print('Signature file %s not found'%sig_file) checkvalue = 32 try: fs=open(sum_file,'r') except: # reference file not found return checkvalue try: with open(self.destination+'/'+self.path+'/'+self.name, 'rb') as f: while True: block = f.read(2**10) if not block: break hashfunc.update(block) sumcalc=hashfunc.hexdigest() except: return checkvalue sumcheck=(fs.readline()).split()[0] if sumcalc.upper()==sumcheck: checkvalue += 128 return checkvalue def setup(self, destination, path,name,isoIndex): self.destination=destination self.path=path self.name=name self.isoIndex=isoIndex def run(self): signal=200+self.isoIndex isoSize=QFileInfo(str(self.destination)+'/'+self.path+'/' +self.name).size() self.sizeFinalSignal.emit(signal, '{:,}'.format(isoSize).replace(',',' ')) signal=300+self.isoIndex self.checkStartSignal.emit(signal) checkSha=self.processSum('sha3') self.sha3Signal.emit(self.isoIndex+checkSha) self.quit() class syncThread(QThread): progressSignal = pyqtSignal(int) speedSignal= pyqtSignal(int) endSignal=pyqtSignal(int) remainSignal=pyqtSignal(str) checkSignal=pyqtSignal(int) sizeSignal=pyqtSignal(str) lvM=pyqtSignal(str) def __init__(self, parent=None): super(syncThread, self).__init__(parent) self.stopped=False self.list=[] def setup(self,nameWithPath, destination,row,): # row is the index in 'model' iso={'nameWithPath':str(nameWithPath),'destination':str(destination),'row':row} self.list.append(iso) def params(self, password, bwl): self.password=password self.bwl=bwl # Bandwith limit def stop(self): self.stopped=True try: self.process.terminate() self.lvM.emit(self.tr("Process rsync stopped")) self.list=[] except: self.lvM.emit(self.tr("Process rsync already stopped")) # Init progressbar and speed counter self.endSignal.emit(0) def run(self): if len(self.list)==0: self.lvM.emit(self.tr("No entry selected")) for iso in self.list: errorOccured=True self.lvM.emit(self.tr("Starting rsync with ")+iso['nameWithPath']) if self.bwl!=0: commande=['rsync','-avP','--no-p','--modify-window=1',"--bwlimit="+str(self.bwl), iso['nameWithPath'], iso['destination']] else: commande=['rsync','-avP','--no-p','--modify-window=1', iso['nameWithPath'], iso['destination']] try: if self.password != "": envir = os.environ.copy() envir['RSYNC_PASSWORD']=str(self.password) self.process = Popen(commande, shell=False, stdout=PIPE, stderr=PIPE, env=envir) else: self.process = Popen(commande, shell=False, stdout=PIPE, stderr=PIPE) errorOccured=False except OSError as e: self.endSignal.emit(1) # Command rsync not found except ValueError as e: self.endSignal.emit(2) # Error in rsync parameters except Exception as e : self.endSignal.emit(3) # Unknown error in rsync if not errorOccured: buf='' while not self.stopped: letter=self.process.stdout.read(1).decode('unicode_escape') buf=buf+letter if letter=='\n' or letter=='\r': progressL=re.findall("([0-9]*)%", buf) speedK=re.findall("([0-9.]*)kB/s", buf) speedM=re.findall("([0-9.]*)MB/s", buf) remain=re.findall("[0-9]*:[0-9]*:[0-9]*",buf) sizeB=re.findall("[1-9](?:\d{0,2})(?:,\d{3})*",buf) if len(progressL) != 0: progress= float(progressL[0]) self.progressSignal.emit(progress) if len(sizeB) != 0: self.sizeSignal.emit(sizeB[0].replace(","," ")) else: if (len(buf) !=0): self.lvM.emit(buf.rstrip()) if len(speedK) != 0: speed= float(speedK[0]) self.speedSignal.emit(speed) if len(speedM) != 0: speed= 1024*float(speedM[0]) self.speedSignal.emit(speed) if len(remain) != 0: self.remainSignal.emit(remain[0]) buf="" self.process.poll() if self.process.returncode != None: break self.lvM.emit(self.tr("Ending with ")+iso['nameWithPath']) if self.stopped: break else: self.checkSignal.emit(iso['row']) self.endSignal.emit(0) self.speedSignal.emit(0) self.progressSignal.emit(0) self.sizeSignal.emit('0') self.remainSignal.emit('0') self.stopped=False self.list=[] self.quit() def rename(directory,oldRelease,newRelease, nbf, nbr): # nbf: number of files renamed # nbr: number of directories renamed # the function is recursive for entry in os.listdir(directory): name = entry entry=os.path.join(directory,entry) if os.path.isfile(entry): if name.startswith(oldRelease): # gpg keys are no more valid if name.endswith('.gpg'): os.remove(entry) else: newPath = os.path.join( os.path.dirname(entry) , name.replace(oldRelease, newRelease,1)) os.rename(entry, newPath) nbf = nbf + 1 if os.path.isdir(entry): nbf, nbr = rename(entry,oldRelease,newRelease, nbf, nbr) if name.startswith(oldRelease) : newPath = os.path.join( os.path.dirname(entry) , name.replace(oldRelease, newRelease,1)) os.rename(entry, newPath) nbr = nbr + 1 return nbf, nbr class findIsos(QThread): endSignal=pyqtSignal(int) lvM=pyqtSignal(str) def __init__(self, parent=None): super(findIsos, self).__init__(parent) self.list=[] self.localList=[] def setup(self,path, password, destination): self.path=path self.password=password self.destination=destination self.lvM.emit(path+password+destination) def getList(self): return self.list def getLocal(self): return self.localList def run(self): # Lists ISO files in local directory root=QDir(self.destination) root.setFilter(QDir.AllDirs|QDir.NoDot|QDir.NoDotDot) dirs=root.entryList() for dir in dirs: sub=QDir(self.destination+'/'+dir) sub.setNameFilters(["*.iso"]) sub.setFilter(QDir.Files) local=sub.entryList() if len(local)!=0: for iso in local: isoSize=QFileInfo(sub.absolutePath()+'/' +iso).size() self.localList.append([dir,iso,isoSize]) # List the remote directory commande = ['rsync', '-avHP', '--list-only',str(self.path)] try: if self.password != "": envir = os.environ.copy() envir['RSYNC_PASSWORD']=str(self.password) process = Popen(commande, shell=False, stdout=PIPE, stderr=PIPE, env=envir) else: process = Popen(commande, shell=False, stdout=PIPE, stderr=PIPE) except OSError as e: self.lvM.emit(self.tr("Command rsync not found: ")+str(e)) self.endSignal.emit(1) return except ValueError as e: self.lvM.emit(self.tr("Error in rsync parameters: ")+str(e)) self.endSignal.emit(2) return except Exception as e: # Unknown error in rsync self.lvM.emit(self.tr("Error in rsync: ")+str(e)) self.endSignal.emit(3) return process.poll() while True : item=process.stdout.readline().rstrip().decode('unicode_escape') self.lvM.emit(item) if str(item.lower()).endswith('.iso') : words = item.split() size = words[1] date = words[2]+' '+ words[3] self.list.append([size,date,words[-1]]) process.poll() if process.returncode != None: break self.endSignal.emit(0) def findRelease(releasePath, password): # List the remote list of releases releaseList =[] code=0 commande = ['rsync', '--list-only',str(releasePath)] try: if password != "": envir = os.environ.copy() envir['RSYNC_PASSWORD']=str(password) process = Popen(commande, shell=False, stdout=PIPE, stderr=PIPE, env=envir) else: process = Popen(commande, shell=False, stdout=PIPE, stderr=PIPE) except OSError as e: code=1 return code,self.tr("Command rsync not found: ")+str(e) except ValueError as e: code=2 return code,self.tr("Error in rsync parameters: ")+str(e) except Exception as e: # Unknown error in rsync code=3 return code,self.tr("Error in rsync: ")+str(e) process.poll() while True : item=process.stdout.readline().rstrip().decode('unicode_escape') words=item.split() if words !=[] and words[-1] != "." and words[0].startswith('d'): releaseList.append(words[-1]) process.poll() if process.returncode != None: break return code, releaseList