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:
parent
eceeddb1e4
commit
593f5a8f2b
@ -159,7 +159,9 @@ register('behavior.addons-url', "https://raw.githubusercontent.com/gramps-projec
|
|||||||
|
|
||||||
register('database.backend', 'bsddb')
|
register('database.backend', 'bsddb')
|
||||||
register('database.compress-backup', True)
|
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('database.path', os.path.join(HOME_DIR, 'grampsdb'))
|
||||||
|
|
||||||
register('export.proxy-order',
|
register('export.proxy-order',
|
||||||
|
@ -1995,23 +1995,3 @@ class DbWriteBase(DbReadBase):
|
|||||||
|
|
||||||
person.birth_ref_index = birth_ref_index
|
person.birth_ref_index = birth_ref_index
|
||||||
person.death_ref_index = death_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()
|
|
||||||
|
@ -646,8 +646,6 @@ class DbGeneric(DbWriteBase, DbReadBase, UpdateCallback, Callback):
|
|||||||
"""
|
"""
|
||||||
if self._directory:
|
if self._directory:
|
||||||
if update:
|
if update:
|
||||||
if config.get('database.autobackup'):
|
|
||||||
self.autobackup(user)
|
|
||||||
# This is just a dummy file to indicate last modified time of
|
# This is just a dummy file to indicate last modified time of
|
||||||
# the database for gramps.cli.clidbman:
|
# the database for gramps.cli.clidbman:
|
||||||
filename = os.path.join(self._directory, "meta_data.db")
|
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):
|
def redo(self, update_history=True):
|
||||||
return self.undodb.redo(update_history)
|
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):
|
def get_summary(self):
|
||||||
"""
|
"""
|
||||||
Returns dictionary of summary item.
|
Returns dictionary of summary item.
|
||||||
|
@ -1239,6 +1239,11 @@ class GrampsPreferences(ConfigureDialog):
|
|||||||
def date_calendar_changed(self, obj):
|
def date_calendar_changed(self, obj):
|
||||||
config.set('preferences.calendar-format-report', obj.get_active())
|
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):
|
def add_date_panel(self, configdialog):
|
||||||
grid = Gtk.Grid()
|
grid = Gtk.Grid()
|
||||||
grid.set_border_width(12)
|
grid.set_border_width(12)
|
||||||
@ -1464,6 +1469,33 @@ class GrampsPreferences(ConfigureDialog):
|
|||||||
current_line, 'behavior.autoload')
|
current_line, 'behavior.autoload')
|
||||||
current_line += 1
|
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
|
return _('Family Tree'), grid
|
||||||
|
|
||||||
def __create_backend_combo(self):
|
def __create_backend_combo(self):
|
||||||
@ -1543,6 +1575,31 @@ class GrampsPreferences(ConfigureDialog):
|
|||||||
self.dbpath_entry.set_text(val)
|
self.dbpath_entry.set_text(val)
|
||||||
f.destroy()
|
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):
|
def update_idformat_entry(self, obj, constant):
|
||||||
config.set(constant, obj.get_text())
|
config.set(constant, obj.get_text())
|
||||||
self.dbstate.db.set_prefixes(
|
self.dbstate.db.set_prefixes(
|
||||||
|
@ -371,6 +371,7 @@ class DisplayState(Callback):
|
|||||||
'nameformat-changed' : None,
|
'nameformat-changed' : None,
|
||||||
'grampletbar-close-changed' : None,
|
'grampletbar-close-changed' : None,
|
||||||
'update-available' : (list, ),
|
'update-available' : (list, ),
|
||||||
|
'autobackup' : None,
|
||||||
}
|
}
|
||||||
|
|
||||||
#nav_type to message
|
#nav_type to message
|
||||||
@ -409,6 +410,7 @@ class DisplayState(Callback):
|
|||||||
self.disprel_active = None
|
self.disprel_active = None
|
||||||
self.set_relationship_class()
|
self.set_relationship_class()
|
||||||
self.export = False
|
self.export = False
|
||||||
|
self.backup_timer = None
|
||||||
|
|
||||||
formatter = logging.Formatter('%(levelname)s %(name)s: %(message)s')
|
formatter = logging.Formatter('%(levelname)s %(name)s: %(message)s')
|
||||||
warnbtn = status.get_warning_button()
|
warnbtn = status.get_warning_button()
|
||||||
@ -421,6 +423,31 @@ class DisplayState(Callback):
|
|||||||
# but this connection is still made!
|
# but this connection is still made!
|
||||||
# self.dbstate.connect('database-changed', self.db_changed)
|
# 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):
|
def screen_width(self):
|
||||||
"""
|
"""
|
||||||
Return the width of the current screen.
|
Return the width of the current screen.
|
||||||
|
@ -91,6 +91,7 @@ from .aboutdialog import GrampsAboutDialog
|
|||||||
from .navigator import Navigator
|
from .navigator import Navigator
|
||||||
from .views.tags import Tags
|
from .views.tags import Tags
|
||||||
from .actiongroup import ActionGroup
|
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
|
# Need to call after plugins have been registered
|
||||||
self.uistate.connect('update-available', self.process_updates)
|
self.uistate.connect('update-available', self.process_updates)
|
||||||
self.check_for_updates()
|
self.check_for_updates()
|
||||||
|
# Set autobackup
|
||||||
|
self.uistate.connect('autobackup', self.autobackup)
|
||||||
|
self.uistate.set_backup_timer()
|
||||||
|
|
||||||
def check_for_updates(self):
|
def check_for_updates(self):
|
||||||
"""
|
"""
|
||||||
@ -750,7 +754,11 @@ class ViewManager(CLIManager):
|
|||||||
# mark interface insenstitive to prevent unexpected events
|
# mark interface insenstitive to prevent unexpected events
|
||||||
self.uistate.set_sensitive(False)
|
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():
|
if self.dbstate.is_open():
|
||||||
self.dbstate.db.close(user=self.user)
|
self.dbstate.db.close(user=self.user)
|
||||||
|
|
||||||
@ -1400,6 +1408,37 @@ class ViewManager(CLIManager):
|
|||||||
self.uistate.push_message(self.dbstate, _("Backup aborted"))
|
self.uistate.push_message(self.dbstate, _("Backup aborted"))
|
||||||
window.destroy()
|
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):
|
def select_backup_path(self, widget, path_entry):
|
||||||
"""
|
"""
|
||||||
Choose a backup folder. Make sure there is one highlighted in
|
Choose a backup folder. Make sure there is one highlighted in
|
||||||
|
@ -1507,7 +1507,6 @@ class DbBsddb(DbBsddbRead, DbWriteBase, UpdateCallback):
|
|||||||
"""
|
"""
|
||||||
if not self.db_is_open:
|
if not self.db_is_open:
|
||||||
return
|
return
|
||||||
self.autobackup(user)
|
|
||||||
if self.txn:
|
if self.txn:
|
||||||
self.transaction_abort(self.transaction)
|
self.transaction_abort(self.transaction)
|
||||||
self.env.txn_checkpoint()
|
self.env.txn_checkpoint()
|
||||||
|
@ -54,13 +54,6 @@ class InMemoryDB(DBAPI):
|
|||||||
with open(versionpath, "w") as version_file:
|
with open(versionpath, "w") as version_file:
|
||||||
version_file.write(str(self.VERSION))
|
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,
|
def load(self, directory, callback=None, mode=None,
|
||||||
force_schema_upgrade=False,
|
force_schema_upgrade=False,
|
||||||
force_bsddb_upgrade=False,
|
force_bsddb_upgrade=False,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user