Exemple #1
0
	def __init__(self, database="old.db"):
		self.new_db = None
		self.old_db = DatabaseReader(None, database)
		
		self.locked = False
Exemple #2
0
class UpdateEngine(object):
	NORMAL_UPDATE = 0
	FORCED_UPDATE = 1
	CUSTOM_UPDATE = 2
	
	def __init__(self, database="old.db"):
		self.new_db = None
		self.old_db = DatabaseReader(None, database)
		
		self.locked = False
		
		#self.startThread(self.dumpDB, "/~stack/pyupdate/pyacqua.db")
		#self.startThread(self.listInfo, "/~stack/pyupdate/index.xml")
	
	def reportError(self, data, response, args, where):
		"""Ovverride this method"""
		self.lockInterface(False)
	
	def lockInterface(self, lock=True):
		"""Ovverride this method"""
		pass
	
	def fetchComponents(self, callback):
		"""
		callback:
		
		for i in report.programs:
			print "-> %s" % i
			self.startThread(self.dumpXml, "/~stack/pyupdate/%s-update.xml" % i, i)
		"""
		self.startThread(self.__listInfo, "/~stack/pyupdate/index.xml", callback)
	
	def startThread(self, callback, url, args=None):
		print _(">> Creo un thread per %s") % url
		f = Fetcher(callback, url, args)
		f.setDaemon(True)
		f.start()
	
	def __listInfo(self, data, response, args):
		if data == None or response.status != 200:
			return self.reportError(data, response, args, STEP_INDEX)
		
		args(Indexer(data).programs)
	
	def getVersion(self, schema):
		a = (schema.get("mainversion"), schema.get("secondversion"), schema.get("revision"))
		return "-r".join((".".join(map(str,a[:2])), str(a[2])))
	
	def dumpXml(self, data, response, args):
		new_schema = ReportReader(data)
		old_schema = ReportReader(None, os.path.join(utils.DHOME_DIR, "%s.xml" % args))
		
		ret = old_schema.checkDiff(new_schema)
		
		if ret == 0: print "NO_UPDATE"
		elif ret == 1: print "UPDATE"
		elif ret == 2: print "UNSECURE_UPDATE"
		elif ret == 3: print "IMPOSSIBLE"
		
		print "LOCAL version:  %s" % self.getVersion(old_schema)
		print "REMOTE version: %s" % self.getVersion(new_schema)
		
		self.updateProgram(args)
	
	def __updateFirstPass(self, program, u_type, new_pid, old_pid):
		
		# @update standard@ - second pass - soggetto new_db
		# Controlliamo l'esistenza della stessa dir
		# -> se nn c'e' aggiungiamo tutti i file
		# Se esiste
		#    -> controlliamo la revision (se la nuova e' maggiore altrimenti ignore (custom update precedente))
		#       -> for sui file
		#          controlla revision (se la nuova e' maggiore scarica | se minore nulla | se uguale controlla consistenza in caso riscarica)
		
		# @update forzato@ clone (update standard)
		# Controlliamo l'esistenza della stessa dir
		# -> se nn c'e' aggiungiamo tutti i file
		# Se esiste
		#    -> controlliamo la revision (se uguale ignore)
		#       -> for sui file
		#          controlla revision (se diversa riscarica | se uguale controlla consistenza in caso riscarica)
		
		for dir_entry in self.new_db.select("SELECT * FROM directory WHERE program_id=%d" % self.new_db.sanitize(new_pid)):
			# dir_entry => (idx, name, revision, filenum, pid)
			
			new_did, new_dname, new_drev, new_dfilenum, new_pid = dir_entry
			
			print "[1] Checking %s" % new_dname
			old_did, old_drev = self.old_db.getDirRevision(new_dname, old_pid)
			
			if u_type == Update.FORCED_UPDATE:
				if old_drev == new_drev:
					continue
			else: # TODO: add custom
				# Esiste e la revision e' maggiore o uguale
				if old_drev >= new_drev:
					print "[1] Skipping %d >= %d" % (old_drev, new_drev)
					continue
				
			#       -> for sui file
			#          controlla revision (se la nuova e' maggiore scarica | se minore nulla | se uguale controlla consistenza in caso riscarica)
			
			for file_entry in self.new_db.select("SELECT * FROM file WHERE program_id=%d AND directory_id=%d" % self.new_db.sanitize((new_pid, new_did))):
				# file_entry => (idx, name, revision, bytes, md5, did, pid)
				
				new_fid, new_fname, new_frev, new_fbytes, new_fmd5, new_did, new_pid = file_entry
				
				old_fid, old_frev = self.old_db.getFileRevision(new_fname, old_did, old_pid)
				
				if u_type == Update.FORCED_UPDATE:
					
					if old_frev == new_frev and self.old_db.checkConsistence(old_fid, new_frev, new_fbytes, new_fmd5):
						continue # il file e' ok
					elif old_frev != new_frev:
						self.downloadFile(old_fid, new_fname, new_frev, new_fbytes, new_fmd5)
					
				else: # TODO: add custom
					
					if (old_frev == new_frev and not self.old_db.checkConsistence(old_fid, new_frev, new_fbytes, new_fmd5)) or (old_frev < new_frev):
						self.downloadFile(old_fid, new_fname, new_frev, new_fbytes, new_fmd5)
	
	def __updateSecondPass(self, program, u_type, new_pid, old_pid):
		# @update standard@ - removing - soggetto old_db
		# Controlliamo se la dir non esiste
		#   -> Rimuoviamo la dir con tutti i file all'interno
		# se esiste
		#   -> for sui file
		#      se esite controlla md5 e bytes (versione minore | se maggiore non far nulla)
		#        -> se non ok riscarica (o errore di update sul server)
		#      se non esiste
		#        -> elimina file
		
		# @update forzato@ - removing - soggetto old_db
		# Controlliamo se la dir non esiste
		#   -> Rimuoviamo la dir con tutti i file all'interno
		# se esiste
		#   -> for sui file
		#      se esite controlla md5 e bytes (sempre)
		#        -> se non ok riscarica
		#      se non esiste
		#        -> elimina file

		for dir_entry in self.old_db.select("SELECT * FROM directory WHERE program_id=%d" % self.old_db.sanitize(old_pid)):
			old_did, old_dname, old_drev, old_dfilenum, old_pid = dir_entry
			
			print "[2] Checking %s" % old_dname
			new_did, new_drev = self.new_db.getDirRevision(old_dname, new_pid)
			
			if new_did == -1 and new_drev == -1:
				print "[2] Full removing %s (and all contents) ..." % old_dname
				continue
			
			for file_entry in self.old_db.select("SELECT * FROM file WHERE program_id=%d AND directory_id=%d" % self.new_db.sanitize((old_pid, old_did))):
				# file_entry => (idx, name, revision, bytes, md5, did, pid)
				
				old_fid, old_fname, old_frev, old_fbytes, old_fmd5, old_did, old_pid = file_entry
				
				new_fid, new_frev = self.new_db.getFileRevision(old_fname, new_did, new_pid)
				
				if new_fid == -1 and new_frev == -1:
					print "[2] Removing file %s ..." % old_fname
				else:
					if u_type == Update.FORCED_UPDATE:
						if not self.new_db.checkConsistence(new_fid, old_frev, old_fbytes, old_fmd5):
							print "[2] Consistence check failed for file %s." % old_fname
							# riscarica
							
					else: # TODO: add custom
						
						if new_frev <= old_frev and not self.new_db.checkConsistence(new_fid, old_frev, old_fbytes, old_fmd5):
							print "[2] Consistence check failed for file %s." % old_fname
	
	def updateProgram(self, program, u_type=NORMAL_UPDATE):
		if not self.new_db: raise "No db."
		
		new_pid = self.new_db.select("SELECT id FROM program WHERE name='%s'" % self.new_db.sanitize(program))[0][0]
		old_pid = self.old_db.select("SELECT id FROM program WHERE name='%s'" % self.old_db.sanitize(program))[0][0]
		
		print "Pid: old -> %d new -> %d" % (old_pid, new_pid)
		
		self.__updateFirstPass(program, u_type, new_pid, old_pid)
		self.__updateSecondPass(program, u_type, new_pid, old_pid)
	
	def downloadFile(self, file_id, fname, frev, fbytes, fmd5):
		self.startThread(self.checkConsistence, "/~stack/pyupdate/source/%s" % fname, (file_id, fname, frev, fbytes, fmd5))
	
	def checkConsistence(self, data, response, args):
		file_id, fname, frev, fbytes, fmd5 = args
		
		print "\t%s -> " % fname,
		
		if data == None:
			print "Error in recv."
			return

		if response.status != 200:
			print "Error in response."
			return
		
		if len(data) == fbytes and self.MD5(data) == fmd5:
			print "File is ok. merge."
			self.old_db.execute("UPDATE file SET revision=%d, bytes=%d, md5=\"%s\" WHERE id=%d" % self.sanitize((frev, fbytes, fmd5, file_id)))
		else:
			print "Error in file."
	
	def MD5(self, data):
		m = md5.new()
		m.update(data)
		return m.hexdigest()
	
	def dumpDB(self, data, response, args):
		f = open("tmp.database", "wb")
		f.write(data)
		f.close()
		
		self.new_db = DatabaseReader(None, "tmp.database")
		print "Database downloaded."