iosfu/iosfu/backup.py

198 lines
4.9 KiB
Python

from __future__ import with_statement
from os import listdir
from os.path import join as join_paths, basename, isdir, isfile
from plistlib import readPlist
from biplist import readPlist as readBinaryPlist
from .conf import BACKUPS_PATH, BACKUP_DEFAULT_SETTINGS
from iosfu import utils
class BackupManager(object):
# Path to backups
path = None
# Backups loaded
backups = {}
def __init__(self, path=BACKUPS_PATH):
self.path = path
def lookup(self):
"""
Look for backup folders on PATH
"""
folders = listdir(self.path)
for dirname in folders:
path = join_paths(self.path, dirname)
if isdir(path):
backup = Backup(path)
self.backups[backup.id] = backup
def get(self, backup_id):
if backup_id in self.backups and self.backups[backup_id].valid:
return self.backups[backup_id]
else:
raise Exception('Backup not registered')
class Backup(object):
"""
Backup object
"""
# Backup id
id = None
# Backup path
path = None
# Files
files = []
# bool if its valid -> self.init_check()
valid = True
# Required files to mark as valid
_required_files = [
'Info.plist', 'Manifest.mbdb', 'Manifest.plist', 'Status.plist'
]
# File handlers to call methods
_file_handlers = {
'.plist': '_read_plist'
}
_plist = {}
# Data
_data_file = None
_data = {}
def __init__(self, path):
self.path = path
self.get_info()
self._data_file = self.get_data_file()
self.init_check()
self.read_data_file()
@property
def name(self):
name = self.data('name') or self.id
return name
def get_data_file(self):
return "{}.iosfu".format(self.path)
def read_data_file(self):
try:
handler = open(self._data_file)
except (OSError, IOError):
# Create default config file if non-existant
handler = open(self._data_file, 'w+')
handler.write(utils.serialize(BACKUP_DEFAULT_SETTINGS))
handler.seek(0)
finally:
with handler as f:
data_file = f.read()
self._data = utils.deserialize(data_file)
handler.close()
def get_info(self):
"""
Get all the basic info for the backup
"""
self.id = basename(self.path)
# Check all files
for filename in listdir(self.path):
if isfile(join_paths(self.path, filename)):
self.files.append(filename)
# Check handlers
for match in self._file_handlers.keys():
if match in filename:
handler = getattr(self, self._file_handlers[match])
handler(filename)
def init_check(self):
"""
Check if the needed stuff are there to consider this a backup
"""
for required_file in self._required_files:
# Check if required files are there
# FIXME Sometimes it doesn't work :?
if required_file not in self.files:
self.valid = False
def exists(self, filename):
"""
Check if the given file exists
"""
return filename in self.files
def get_file(self, filename, handler=False):
"""
Returns given file path
- handler (bool) - Returns handler instead of path
"""
result = None
if self.exists(filename):
file_path = join_paths(self.path, filename)
if handler:
result = open(file_path, 'rb')
else:
result = file_path
return result
#
# File handlers
#
def _read_plist(self, filename):
"""
Handler for .plist files
Reads them and stores on self._plist for plugin access
"""
file_path = self.get_file(filename)
try:
self._plist[filename] = readPlist(file_path)
except:
# Is binaryPlist?
try:
self._plist[filename] = readBinaryPlist(file_path)
except:
# What is it?
pass
#
# Backup data file
#
def data(self, key, value=None):
result = value
if value:
self._data[key] = value
elif key in self._data:
result = self._data[key]
return result
def cache(self, key, value=None):
result = value
if value:
self._data['cache'][key] = value
elif key in self._data['cache']:
result = self._data['cache'][key]
return result
def clear_cache(self):
self._data['cache'] = {}
self.write_data_file()
def write_data_file(self):
handler = open(self._data_file, 'w+')
handler.write(utils.serialize(self._data))
handler.close()