Add new backup preferences

Allow user to specify a backup directory.
Add option to backup on exit.
Add option to autobackup at regular intervals.
This commit is contained in:
Nick Hall 2016-12-06 22:44:38 +00:00
parent eceeddb1e4
commit 593f5a8f2b
8 changed files with 127 additions and 46 deletions

View File

@ -159,7 +159,9 @@ register('behavior.addons-url', "https://raw.githubusercontent.com/gramps-projec
register('database.backend', 'bsddb')
register('database.compress-backup', True)
register('database.autobackup', True) ## make backup when exiting, if there are changes
register('database.backup-path', USER_HOME)
register('database.backup-on-exit', True)
register('database.autobackup', 0)
register('database.path', os.path.join(HOME_DIR, 'grampsdb'))
register('export.proxy-order',

View File

@ -1995,23 +1995,3 @@ class DbWriteBase(DbReadBase):
person.birth_ref_index = birth_ref_index
person.death_ref_index = death_ref_index
def autobackup(self, user=None):
"""
Backup the current file as a backup file.
"""
from gramps.cli.user import User
if user is None:
user = User()
if self.is_open() and self.has_changed:
if user.uistate:
user.uistate.set_busy_cursor(True)
user.uistate.progress.show()
user.uistate.push_message(user.dbstate, _("Autobackup..."))
try:
self.backup(user=user)
except DbException as msg:
user.notify_error(_("Error saving backup data"), msg)
if user.uistate:
user.uistate.set_busy_cursor(False)
user.uistate.progress.hide()

View File

@ -646,8 +646,6 @@ class DbGeneric(DbWriteBase, DbReadBase, UpdateCallback, Callback):
"""
if self._directory:
if update:
if config.get('database.autobackup'):
self.autobackup(user)
# This is just a dummy file to indicate last modified time of
# the database for gramps.cli.clidbman:
filename = os.path.join(self._directory, "meta_data.db")
@ -2576,20 +2574,6 @@ class DbGeneric(DbWriteBase, DbReadBase, UpdateCallback, Callback):
def redo(self, update_history=True):
return self.undodb.redo(update_history)
def backup(self, user=None):
"""
If you wish to support an optional backup routine, put it here.
"""
from gramps.plugins.export.exportxml import XmlWriter
from gramps.cli.user import User
if user is None:
user = User()
compress = config.get('database.compress-backup')
writer = XmlWriter(self, user, strip_photos=0, compress=compress)
timestamp = '{0:%Y-%m-%d-%H-%M-%S}'.format(datetime.datetime.now())
filename = os.path.join(self._directory, "backup-%s.gramps" % timestamp)
writer.write(filename)
def get_summary(self):
"""
Returns dictionary of summary item.

View File

@ -1239,6 +1239,11 @@ class GrampsPreferences(ConfigureDialog):
def date_calendar_changed(self, obj):
config.set('preferences.calendar-format-report', obj.get_active())
def autobackup_changed(self, obj):
active = obj.get_active()
config.set('database.autobackup', active)
self.uistate.set_autobackup_timer()
def add_date_panel(self, configdialog):
grid = Gtk.Grid()
grid.set_border_width(12)
@ -1464,6 +1469,33 @@ class GrampsPreferences(ConfigureDialog):
current_line, 'behavior.autoload')
current_line += 1
self.backup_path_entry = Gtk.Entry()
self.add_path_box(grid,
_('Backup path'),
current_line, self.backup_path_entry,
config.get('database.backup-path'),
self.set_backup_path, self.select_backup_path)
current_line += 1
self.add_checkbox(grid,
_('Backup on exit'),
current_line, 'database.backup-on-exit')
current_line += 1
# Check for updates:
obox = Gtk.ComboBoxText()
formats = [_("Never"),
_("Every 15 minutes"),
_("Every 30 minutes"),
_("Every hour")]
list(map(obox.append_text, formats))
active = config.get('database.autobackup')
obox.set_active(active)
obox.connect('changed', self.autobackup_changed)
lwidget = BasicLabel("%s: " % _('Autobackup'))
grid.attach(lwidget, 1, current_line, 1, 1)
grid.attach(obox, 2, current_line, 1, 1)
return _('Family Tree'), grid
def __create_backend_combo(self):
@ -1543,6 +1575,31 @@ class GrampsPreferences(ConfigureDialog):
self.dbpath_entry.set_text(val)
f.destroy()
def set_backup_path(self, *obj):
path = self.backup_path_entry.get_text().strip()
config.set('database.backup-path', path)
def select_backup_path(self, *obj):
f = Gtk.FileChooserDialog(title=_("Select backup directory"),
parent=self.window,
action=Gtk.FileChooserAction.SELECT_FOLDER,
buttons=(_('_Cancel'),
Gtk.ResponseType.CANCEL,
_('_Apply'),
Gtk.ResponseType.OK)
)
backup_path = config.get('database.backup-path')
if not backup_path:
backup_path = config.get('database.path')
f.set_current_folder(os.path.dirname(backup_path))
status = f.run()
if status == Gtk.ResponseType.OK:
val = f.get_filename()
if val:
self.backup_path_entry.set_text(val)
f.destroy()
def update_idformat_entry(self, obj, constant):
config.set(constant, obj.get_text())
self.dbstate.db.set_prefixes(

View File

@ -371,6 +371,7 @@ class DisplayState(Callback):
'nameformat-changed' : None,
'grampletbar-close-changed' : None,
'update-available' : (list, ),
'autobackup' : None,
}
#nav_type to message
@ -409,6 +410,7 @@ class DisplayState(Callback):
self.disprel_active = None
self.set_relationship_class()
self.export = False
self.backup_timer = None
formatter = logging.Formatter('%(levelname)s %(name)s: %(message)s')
warnbtn = status.get_warning_button()
@ -421,6 +423,31 @@ class DisplayState(Callback):
# but this connection is still made!
# self.dbstate.connect('database-changed', self.db_changed)
def set_backup_timer(self):
"""
Set the backup timer.
"""
interval = config.get('database.autobackup')
if self.backup_timer is not None:
GLib.source_remove(self.backup_timer)
self.backup_timer = None
if interval == 1:
minutes = 15
elif interval == 2:
minutes = 30
elif interval == 3:
minutes = 60
if interval > 0:
self.backup_timer = GLib.timeout_add_seconds(
minutes*60, self.__emit_autobackup)
def __emit_autobackup(self):
"""
Emit an 'autobackup' signal.
"""
self.emit('autobackup')
return True
def screen_width(self):
"""
Return the width of the current screen.

View File

@ -91,6 +91,7 @@ from .aboutdialog import GrampsAboutDialog
from .navigator import Navigator
from .views.tags import Tags
from .actiongroup import ActionGroup
from gramps.gen.db.exceptions import DbWriteFailure
#-------------------------------------------------------------------------
#
@ -311,6 +312,9 @@ class ViewManager(CLIManager):
# Need to call after plugins have been registered
self.uistate.connect('update-available', self.process_updates)
self.check_for_updates()
# Set autobackup
self.uistate.connect('autobackup', self.autobackup)
self.uistate.set_backup_timer()
def check_for_updates(self):
"""
@ -750,7 +754,11 @@ class ViewManager(CLIManager):
# mark interface insenstitive to prevent unexpected events
self.uistate.set_sensitive(False)
# backup data, and close the database
# backup data
if config.get('database.backup-on-exit'):
self.autobackup()
# close the database
if self.dbstate.is_open():
self.dbstate.db.close(user=self.user)
@ -1400,6 +1408,37 @@ class ViewManager(CLIManager):
self.uistate.push_message(self.dbstate, _("Backup aborted"))
window.destroy()
def autobackup(self):
"""
Backup the current family tree.
"""
if self.dbstate.db.is_open() and self.dbstate.db.has_changed:
self.uistate.set_busy_cursor(True)
self.uistate.progress.show()
self.uistate.push_message(self.dbstate, _("Autobackup..."))
try:
self.__backup()
except DbWriteFailure as msg:
self.uistate.push_message(self.dbstate,
_("Error saving backup data"))
self.uistate.set_busy_cursor(False)
self.uistate.progress.hide()
def __backup(self):
"""
Backup database to a Gramps XML file.
"""
from gramps.plugins.export.exportxml import XmlWriter
backup_path = config.get('database.backup-path')
compress = config.get('database.compress-backup')
writer = XmlWriter(self.dbstate.db, self.user, strip_photos=0,
compress=compress)
timestamp = '{0:%Y-%m-%d-%H-%M-%S}'.format(datetime.datetime.now())
backup_name = "%s-%s.gramps" % (self.dbstate.db.get_dbname(),
timestamp)
filename = os.path.join(backup_path, backup_name)
writer.write(filename)
def select_backup_path(self, widget, path_entry):
"""
Choose a backup folder. Make sure there is one highlighted in

View File

@ -1507,7 +1507,6 @@ class DbBsddb(DbBsddbRead, DbWriteBase, UpdateCallback):
"""
if not self.db_is_open:
return
self.autobackup(user)
if self.txn:
self.transaction_abort(self.transaction)
self.env.txn_checkpoint()

View File

@ -54,13 +54,6 @@ class InMemoryDB(DBAPI):
with open(versionpath, "w") as version_file:
version_file.write(str(self.VERSION))
def autobackup(self, user=None):
"""
Nothing to do, as we write it out anyway.
No backups for inmemory databases.
"""
pass
def load(self, directory, callback=None, mode=None,
force_schema_upgrade=False,
force_bsddb_upgrade=False,