diff --git a/apps/backups/api.py b/apps/backups/api.py index 5483a91108..f373ddab68 100644 --- a/apps/backups/api.py +++ b/apps/backups/api.py @@ -1,39 +1,72 @@ from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext +from django.core.management.commands.dumpdata import Command +from django.db import router, DEFAULT_DB_ALIAS -class BackupManagerBase(object): +class ElementBackupBase(object): + """ + Sub classes must provide at least: + info() + backup() + restore() + """ + label = _(u'Base backup manager') - #def __init__(self, name, label): - # self.label = label - # self.name = name def info(self): + """ + Must return at least None + """ return None + def link(self, app_backup): + self.app_backup = app_backup + return self + def __unicode__(self): return unicode(self.__class__.label) -class ModelFixtures(BackupManagerBase): +class ElementBackupModel(ElementBackupBase): label = _(u'Model fixtures') def __init__(self, models=None): self.model_list = models or [] def info(self): - return u', '.join(self.model_list) or _(u'All') + return _(u'models: %s') % (u', '.join(self.model_list) if self.model_list else _(u'All')) + + def backup(self): + """ + TODO: turn into a generator maybe? + """ + command = Command() + if not self.model_list: + result = [self.app_backup.name] + else: + result = [u'%s.%s' (self.app_backup.name, model) for model in self.model_list] + result = command.handle(u' '.join(result), format='json', indent=4, using=DEFAULT_DB_ALIAS, exclude=[], user_base_manager=False, use_natural_keys=False) + return result -class DirectoryCopy(BackupManagerBase): - label = _(u'Directory copy') +class ElementBackupFile(ElementBackupBase): + label = _(u'File copy') - def __init__(self, path): - self.path = path + def __init__(self, storage_class, filepath): + self.storage_class = storage_class + self.filepath = filepath def info(self): - return self.path + return _(u'%s from %s') % (self.filepath, self.storage_class) + def backup(self): + """ + Fetch a file specified by filepath from the Django storage class + and return a file like object + """ + return None + class AppBackup(object): _registry = {} @@ -59,25 +92,27 @@ class AppBackup(object): def __init__(self, name, label, backup_managers): self.label = label self.name = name - self.backup_managers = backup_managers + self.backup_managers = [manager.link(self) for manager in backup_managers] self.state = self.__class__.STATE_IDLE self.__class__._registry[name] = self - @property def info(self): results = [] for manager in self.backup_managers: results.append(u'%s - %s' % (manager, manager.info() or _(u'Nothing'))) return u', '.join(results) - def backup(self, storage_module=None): + def backup(self, storage_module, *args, **kwargs): self.state = self.__class__.STATE_BACKING_UP - # call storage_module + for manager in self.backup_managers: + result = manager.backup() + storage_module.backup(result) self.state = self.__class__.STATE_IDLE def restore(self, storage_module=None): self.state = self.__class__.STATE_RESTORING - # call storage_module + for manager in self.backup_managers: + manager.restore(storage_module.restore()) self.state = self.__class__.STATE_IDLE def __unicode__(self): @@ -85,15 +120,55 @@ class AppBackup(object): class StorageModuleBase(object): - _registry = {} + #_registry = {} + _registry = [] + + REALM_LOCAL = 'local' + REALM_REMOTE = 'remote' + + REALM_CHOICES = ( + (REALM_LOCAL, _(u'local')), + (REALM_REMOTE, _(u'remote')), + ) + + # TODO: register subclasses of StorageModuleBase + # do not register instances + #def __new__(cls, *args, **kwargs): + # print "NEW" - def __init__(self, name, label): - self.label = label - self.name = name - self.__class__._registry[name] = self - - def backup(self, *args, **kwargs): + @classmethod + def register(cls, klass): + cls._registry.append(klass) + + def __init__(self, *args, **kwargs): + pass + + def backup(self, data): raise NotImplemented - def restore(self, *args, **kwargs): + def restore(self): + """ + Must return data or a file like object + """ raise NotImplemented + + +class TestStorageModule(StorageModuleBase): + label = _(u'Test storage module') + + def __init__(self, *args, **kwargs): + self.backup_path = kwargs.pop('backup_path', None) + self.restore_path = kwargs.pop('restore_path', None) + return super(TestStorageModule, self).__init__(*args, **kwargs) + + def backup(self, data): + print '***** received data' + print data + print '***** saving to path: %s' % self.backup_path + + def restore(self):- + print 'restore from path: %s' % self.restore_path + return 'sample_data' + +# TODO: get rid of register and try to register on subclassing +StorageModuleBase.register(TestStorageModule)