--- /dev/null
+# low_backup_manager module
+# Authors: Nicholas Alexander && Otacilio Lacerda
+# Backup_manager class:
+# Class responsible for backup functions like creating and removing backups
+
+import os.path
+import os
+import zlib
+import pickle
+
+from PyQt4.QtCore import *
+from zipfile import *
+
+from pcsbackupparser import *
+from pcsbackupinfo import *
+from pcsbackupmanager import *
+from pcsbackupxml import *
+
+import pcsbackuputils as utils
+
+HOME = os.path.expanduser("~")
+BACKUP_FILES_PATH = os.path.join(HOME, ".pcsuite/Backup")
+DEFAULT_CONFIG_PATH = "%s/.pcsuite/config" % HOME
+BACKUPS_FILE = os.path.join(HOME, ".pcsuite/Backup/.backups")
+
+
+class PcsPcBackupManager(PcsBackupManager):
+
+ def __init__(self):
+ PcsBackupManager.__init__(self)
+ self._backupList = []
+ self.backupInProgress = False
+ self.restoreInProgress = False
+ self.copyInProgress = False
+
+ self.myDocsPath = "Root/home/user/MyDocs/"
+ self.backupPath = ""
+ self.currentCategory = ""
+ self.totalSize = 0
+
+ def loadBackups(self):
+ # 'XX Loading the backup list available in the PC'
+ try:
+ if os.path.exists(BACKUPS_FILE):
+ file = open(BACKUPS_FILE)
+ self._backupList = pickle.load(file)
+ file.close()
+ except IOError:
+ print "IOError while loading the PC backups"
+ # FIXME
+ #raise Exception("Error while reading backups")
+ return False
+
+ return True
+
+ def saveBackups(self):
+ # 'XX Saving the backup list in the config file'
+ try:
+ obj = self._backupList
+ file = open(BACKUPS_FILE, "w")
+ pickle.dump(obj, file)
+ file.close()
+ except:
+ #raise Exception("Error while saving backups")
+ return False
+
+ return True
+
+ def getBackupList(self):
+ """Return a list with the name of all done backups. """
+ self.loadBackups()
+ return self._backupList[:]
+
+ def createBackup(self, backup_name, path, host_ip, categories, comment=""):
+ self.backupThread = NewBackupThread(self, backup_name, path, host_ip,
+ categories, comment)
+ self.backupThread.start()
+
+
+ def renameBackup(self, backupName, newName):
+ self.loadBackups()
+
+ backupInfo = self.getBackupInfo(backupName)
+ if backupInfo != None:
+ try:
+ old = os.path.join(str(backupInfo.getPath()), str(backupName))
+ new = os.path.join(str(backupInfo.getPath()), str(newName))
+ os.rename(old, new)
+ backupInfo.setName(newName)
+ except:
+ print "Error while changing backup name"
+ return False
+ else:
+ # "Backup not found"
+ return False
+
+ self.saveBackups()
+ return True
+
+ def removeBackup(self, backupName):
+ """
+ Remove a backup from pc and from _backupList.
+ """
+ self.loadBackups()
+ backupInfo = self.getBackupInfo(backupName)
+ completePath = os.path.join(str(backupInfo.getPath()),
+ str(backupInfo.getName()))
+ if os.path.exists(completePath):
+ utils.removePath(completePath)
+ self._backupList.remove(backupInfo)
+ self.saveBackups()
+
+ return True
+
+ def copyBackupToDevice(self, deviceIp, backupName, memoryStick):
+ """ Copy a backup in the PC to some memory card inside the chosen device.
+
+ Attributes:
+ String deviceIp - String with ip address of device.
+ String backupName - Name of backup to be copied.
+ Int memoryStick - Integer representing which memory stick backup
+ should be copied to.
+ 0 - Removable memory stick
+ 1 - Internal memory stick
+ """
+ try:
+ self.loadBackups()
+ mountPoint = os.path.join(DEVICES_POINT, "%s/Root" % deviceIp)
+ utils.mountDevice(USER_HOST, deviceIp, mountPoint)
+
+ backup = self.getBackupInfo(backupName)
+ backupPath = os.path.join(str(backup.getPath()), str(backupName))
+ if memoryStick != 0 and memoryStick != 1:
+ return -1
+ destination = os.path.join(mountPoint, 'media/mmc%s' %
+ (memoryStick+1), 'backups', backupName)
+
+ self.setCopyInProgress(True)
+ if self.copy(backupPath, destination) == 0:
+ return 0
+ self.setCopyInProgress(False)
+ finally:
+ utils.unmountDevice(mountPoint)
+
+
+ def getBackupInfo(self, backupName):
+ for backupInfo in self._backupList:
+ if backupInfo.getName() == backupName:
+ return backupInfo
+ return None
+
+ def startBackupRestore(self, backupInfo, device_ip, categories):
+ return self.restoreBackup(backupInfo, device_ip, categories)
+
+ def setCopyInProgress(self, status):
+ self.copyInProgress = status
+
+ def setBackupInProgress(self, status):
+ self.backupInProgress = status
+
+
+ def setRestoreInProgress(self, status):
+ self.restoreInProgress = status
+
+ # FIXME: rewrite this method. Add error handling, some more reliable code
+ def _runCreateBackup(self, backup_name, path, host_ip, categories, comment=""):
+ """Create a backup and add it to _backupList.
+
+ Backup all files and directories of categories chosen. The device
+ system file is mounted on PC and them files are compressed in a zip
+ format. All zip files from each category are saved in the given path.
+
+ Arguments:
+ backup_name -- Backup's name. This name will be the name of the backup
+ folder.
+ path -- Location to save Backup file
+ host_ip -- The device IP address.
+ categories -- A python dictonary where the keys are the categories from
+ osso-backup, and the value can be either True or False, to identify
+ which categories to backup.
+ comment -- Any comment about the backup. It will be saved in Backup
+ object.
+
+ """
+
+ backupInfo = None
+ self.setBackupInProgress(True)
+ self.currentCategory = ""
+
+ try:
+ # Mount device folders
+ self.loadBackups()
+ mountPoint = os.path.join(DEVICES_POINT, "%s/Root" % host_ip)
+ utils.mountDevice(USER_HOST, host_ip, mountPoint)
+
+ # Create backup folder in the given path
+ self.backupPath = os.path.join(str(path), backup_name)
+ self._createBackupFolder(self.backupPath)
+
+ # Copying osso-backup configuration files to TabletSuite folder and
+ # parsing backup information from these files.
+ # ( Information = which paths should be in each backup category)
+ utils.copyOssoBackupConfigFiles(DEFAULT_CONFIG_PATH, mountPoint)
+ xmlParser = PcsBackupParser()
+ xmlParser.fillLocationsDict(DEFAULT_CONFIG_PATH)
+ backupItemDict = xmlParser.getLocationsDict()
+
+ # Changing work directory to ease file search. Keeping previous
+ # folder to come back after backup process.
+ current_dir = os.getcwd()
+ workPath = DEVICES_POINT + str(host_ip)
+ os.chdir(workPath)
+
+ # Computing total size that this backup will have.
+ self.totalSize = self._getTotalSize(backupItemDict, categories)
+
+
+ # Start backup process. Create backup of paths for each locations
+ # category
+ self.backedUpNumber = 0
+ filesByCategory = {}
+ for category in backupItemDict.keys():
+ self.currentCategory = category
+
+ for backupItem in backupItemDict[category]:
+ self._emitProgress()
+ # If current backupInfo category is valid and it's value is
+ # True in categories dictionary, add it to current backup.
+ if (category in categories) and (categories[category]):
+ categoryFilesNumber = 0
+ categoryFile = os.path.join(self.backupPath,
+ category + '.zip')
+
+ if os.path.exists(categoryFile):
+ zipfile = utils.openZip(categoryFile, 'a')
+ else:
+ zipfile = utils.openZip(categoryFile, 'w')
+
+ objPath = backupItem.path.replace('/','Root/',1)
+ backupFolder = os.path.join(workPath, objPath)
+ categoryFilesNumber = self.zipFolder(backupFolder,
+ zipfile, objPath,
+ category)
+ if categoryFilesNumber == -1:
+ os.chdir(current_dir)
+ return 0
+ self.backedUpNumber += categoryFilesNumber
+ self._emitProgress()
+
+ # Update the filesByCategory dictionary with the
+ # current number of files from current category that
+ # were already copied.
+ self._updateCategoryCount(filesByCategory, category,
+ categoryFilesNumber)
+ utils.closeZip(zipfile)
+ # If category had no file to copy remove its folder
+ if int(utils.getSize(categoryFile) == 0):
+ os.remove(categoryFile)
+
+
+ # Copying media files from device user folder if media category is
+ # True in categories dictionary.
+ if ("media" in categories) and (categories["media"]):
+ self.currentCategory = "media"
+ result = self._backupMedias(workPath)
+ if result == -1:
+ os.chdir(current_dir)
+ return 0
+ # Update backup files number count
+ self.backedUpNumber += result
+ self._updateCategoryCount(filesByCategory, "media", result)
+ zipPath = os.path.join(self.backupPath,'media.zip')
+ if int(utils.getSize(zipPath) == 0):
+ os.remove(zipPath)
+
+
+ # Copying documents files from device user folder if documents
+ # category is True in categories dictionary.
+ if ("documents" in categories) and (categories["documents"]):
+ self.currentCategory = "documents"
+ result = self._backupDocuments(workPath)
+ # Update backup files number count
+ self.backedUpNumber += result
+ if result == -1:
+ os.chdir(current_dir)
+ return 0
+ self._updateCategoryCount(filesByCategory, "documents",
+ result)
+ zipPath = os.path.join(self.backupPath, 'documents.zip')
+ if int(utils.getSize(zipPath) == 0):
+ os.remove(zipPath)
+
+
+ # Change to previous work directory
+ os.chdir(current_dir)
+
+ if self.backedUpNumber == 0:
+ utils.removePath(self.backupPath)
+ return -1
+
+ # Create Backup Object, add it to this manager backup list and save
+ # the list in the backup file.
+ backup_size = utils.getSize(self.backupPath)
+ backupInfo = PcsBackupInfo(backup_name, path, backup_size, comment)
+ backupInfo.setFilesNumber(self.backedUpNumber)
+ self._backupList.append(backupInfo)
+ self.saveBackups()
+
+ createXml(backupInfo, filesByCategory, host_ip)
+ self.setBackupInProgress(False)
+ finally:
+ utils.unmountDevice(mountPoint)
+
+ return backupInfo
+
+
+ def _backupDocuments(self, workPath):
+ """ Create backup of documents files in user folder. """
+ categoryFilesNumber = 0
+ destinationPath = os.path.join(self.backupPath,'documents.zip')
+ if os.path.exists(destinationPath):
+ zipfile = utils.openZip(destinationPath, 'a')
+ else:
+ zipfile = utils.openZip(destinationPath, 'w')
+
+ docsPath = os.path.join(self.myDocsPath, ".documents")
+
+ if os.path.exists(docsPath):
+ backupPath = os.path.join(workPath, docsPath)
+ categoryFilesNumber = self.zipFolder(backupPath, zipfile, docsPath,
+ "documents")
+
+ utils.closeZip(zipfile)
+ return categoryFilesNumber
+
+
+ def _backupMedias(self, workPath):
+ """ Create backup of media files in user folder. """
+ categoryFilesNumber = 0
+ destinationPath = os.path.join(self.backupPath,'media.zip')
+ if os.path.exists(destinationPath):
+ zipfile = utils.openZip(destinationPath, 'a')
+ else:
+ zipfile = utils.openZip(destinationPath, 'w')
+
+ userFilesPath = self.myDocsPath
+ if os.path.exists(os.path.join(userFilesPath)):
+ for folder in os.listdir(userFilesPath):
+ if folder != '.documents':
+ objPath = os.path.join(userFilesPath, folder)
+ backupDir = os.path.join(workPath, objPath)
+ result = self.zipFolder(backupDir, zipfile,
+ objPath, "media")
+ if result != -1:
+ categoryFilesNumber += result
+ else:
+ return result
+
+ utils.closeZip(zipfile)
+ return categoryFilesNumber
+
+
+ def _createBackupFolder(self, newBackupPath):
+ if not utils.createFolder(newBackupPath):
+ return False
+
+
+ def _emitProgress(self):
+ currentSize = utils.getSize(self.backupPath)
+ percentage = self.computePercentage(self.totalSize, currentSize)
+ self.emit(SIGNAL("backupProgress"), (percentage, self.currentCategory))
+
+
+ def _getTotalSize(self, backupFileDict, categories):
+ size = 0
+ for category in backupFileDict.keys():
+ for backupItem in backupFileDict[category]:
+ if (category in categories) and (categories[category]):
+ objPath = backupItem.path.replace('/','Root/',1)
+ size += utils.getSize(objPath)
+
+ if categories["documents"]:
+ size += utils.getSize(os.path.join(self.myDocsPath,
+ ".documents"))
+ if categories["media"]:
+ for folder in os.listdir(self.myDocsPath):
+ if folder != '.documents':
+ objPath = os.path.join(self.myDocsPath, folder)
+ size += utils.getSize(objPath)
+ return size
+
+ def _updateCategoryCount(self, filesByCategory, category, backed_up_number):
+ if str(category) not in filesByCategory.keys():
+ filesByCategory[category] = backed_up_number
+ else:
+ filesByCategory[category] += backed_up_number
+
+
+ def _verify_backup_name(self, backup_name):
+ """ Check if already exists any backup with the given name inside the
+ pc backup list. In case there is one, this function will return another
+ name to be set as the new backup name, else it will return the same
+ name that was given.
+
+ """
+ if self.getBackupInfo(backup_name) != None:
+ counter = 1
+ new_name = backup_name + "%02d" % counter
+ while(self.getBackupInfo(new_name)) != None:
+ counter += 1
+ new_name = backup_name + "%02d" % counter
+
+ backup_name = new_name
+ return backup_name
+
+ def zipFolder(self, path, zipfile, obj_path, category):
+ # Compress the folder from the given path, with all directories and
+ # files inside it
+ # zipfile: The ZipFile object to append the folder
+ # obj_path: The ZipFile path
+ count = 0
+ self._emitProgress()
+ if os.path.exists(path):
+ if os.path.isdir(path):
+ files = os.listdir(path)
+ for node in files:
+ if os.path.isdir(os.path.join(path, node)):
+ zipCount = self.zipFolder(os.path.join(path, node), zipfile,
+ os.path.join(obj_path, node), category)
+ if zipCount == -1:
+ return -1
+ else:
+ count += zipCount
+ else:
+ # Check if backup was canceled and return -1 case positive
+ if not self.backupInProgress:
+ utils.removePath(self.backupPath)
+ return -1
+
+ if utils.zip(zipfile, os.path.join(obj_path, node)):
+ count += 1
+ self._emitProgress()
+ else:
+ # Check if backup was canceled and return -1 case positive
+ if not self.backupInProgress:
+ utils.removePath(self.backupPath)
+ return -1
+
+ if utils.zip(zipfile, obj_path):
+ count += 1
+ self._emitProgress()
+ return count
+
+
+
+class NewBackupThread(QThread):
+ def __init__(self, manager, backupName, path, hostIp, categories, comment):
+ QThread.__init__(self)
+
+ self.manager = manager
+ self.backupName = backupName
+ self.path = path
+ self.hostIp = hostIp
+ self.categories = categories
+ self.comment = comment
+
+ def run(self):
+ ret = self.manager._runCreateBackup (self.backupName, self.path,
+ self.hostIp, self.categories,
+ str(self.comment))
+ self.manager.emit(SIGNAL("backupDone"), ret,
+ (self.manager.totalSize, self.manager.backedUpNumber))
+
+
+
\ No newline at end of file