1144: Auto backup at exit, but not when opening another database

This commit is contained in:
Doug Blank 2016-04-30 10:25:09 -04:00
parent 9690c20cbc
commit 8f77d6db9f
10 changed files with 60 additions and 34 deletions

View File

@ -48,14 +48,15 @@ class User(user.User):
This class provides a means to interact with the user via CLI. This class provides a means to interact with the user via CLI.
It implements the interface in :class:`.gen.user.User` It implements the interface in :class:`.gen.user.User`
""" """
def __init__(self, callback=None, error=None, auto_accept=False, quiet=False): def __init__(self, callback=None, error=None, auto_accept=False, quiet=False,
uistate=None, dbstate=None):
""" """
Init. Init.
:param error: If given, notify_error delegates to this callback :param error: If given, notify_error delegates to this callback
:type error: function(title, error) :type error: function(title, error)
""" """
user.User.__init__(self, callback, error) user.User.__init__(self, callback, error, uistate, dbstate)
self.steps = 0; self.steps = 0;
self.current_step = 0; self.current_step = 0;
self._input = input self._input = input

View File

@ -33,12 +33,14 @@ from this class.
import re import re
import time import time
from operator import itemgetter from operator import itemgetter
import logging
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
# #
# Gramps libraries # Gramps libraries
# #
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
from ..db.dbconst import DBLOGNAME
from ..const import GRAMPS_LOCALE as glocale from ..const import GRAMPS_LOCALE as glocale
_ = glocale.translation.gettext _ = glocale.translation.gettext
from ..lib.childreftype import ChildRefType from ..lib.childreftype import ChildRefType
@ -46,6 +48,8 @@ from ..lib.childref import ChildRef
from .txn import DbTxn from .txn import DbTxn
from .exceptions import DbTransactionCancel from .exceptions import DbTransactionCancel
_LOG = logging.getLogger(DBLOGNAME)
def eval_order_by(order_by, obj, db): def eval_order_by(order_by, obj, db):
""" """
Given a list of [[field, DIRECTION], ...] Given a list of [[field, DIRECTION], ...]
@ -2094,6 +2098,26 @@ class DbWriteBase(DbReadBase):
""" """
return getattr(self, table_name) return getattr(self, table_name)
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()
class QuerySet(object): class QuerySet(object):
""" """
A container for selection criteria before being actually A container for selection criteria before being actually

View File

@ -1696,16 +1696,17 @@ class DbGeneric(DbWriteBase, DbReadBase, UpdateCallback, Callback):
return False return False
return True return True
def close(self, update=True): def close(self, update=True, user=None):
""" """
Close the database. Close the database.
if update is False, don't change access times, etc. if update is False, don't change access times, etc.
""" """
if self._directory: if self._directory:
if update:
self.autobackup(user)
# This is just a dummy file to indicate last modified time of the # This is just a dummy file to indicate last modified time of the
# database for gramps.cli.clidbman: # database for gramps.cli.clidbman:
filename = os.path.join(self._directory, "meta_data.db") filename = os.path.join(self._directory, "meta_data.db")
if update:
touch(filename) touch(filename)
# Save metadata # Save metadata
self.set_metadata('name_formats', self.name_formats) self.set_metadata('name_formats', self.name_formats)

View File

@ -32,11 +32,12 @@ class User():
provide the appropriate interaction (eg. dialogs for GTK, prompts for CLI). provide the appropriate interaction (eg. dialogs for GTK, prompts for CLI).
""" """
def __init__(self, callback=None, error=None): def __init__(self, callback=None, error=None, uistate=None, dbstate=None):
self.callback_function = callback self.callback_function = callback
self.error_function = error self.error_function = error
self._fileout = sys.stderr # redirected to mocks by unit tests self._fileout = sys.stderr # redirected to mocks by unit tests
self.uistate = None self.uistate = uistate
self.dbstate = dbstate
def begin_progress(self, title, message, steps): def begin_progress(self, title, message, steps):
""" """

View File

@ -254,7 +254,8 @@ class DbLoader(CLIDbLoader):
#returns that info. Otherwise None is set to import_info #returns that info. Otherwise None is set to import_info
self.import_info = importer(self.dbstate.db, filename, self.import_info = importer(self.dbstate.db, filename,
User(callback=self._pulse_progress, User(callback=self._pulse_progress,
uistate=self.uistate)) uistate=self.uistate,
dbstate=self.dbstate))
dirname = os.path.dirname(filename) + os.path.sep dirname = os.path.dirname(filename) + os.path.sep
config.set('paths.recent-import-dir', dirname) config.set('paths.recent-import-dir', dirname)
except UnicodeError as msg: except UnicodeError as msg:
@ -330,6 +331,11 @@ class DbLoader(CLIDbLoader):
force_bsddb_downgrade, force_bsddb_downgrade,
force_python_upgrade) force_python_upgrade)
db.set_save_path(filename) db.set_save_path(filename)
if self.dbstate.db.is_open():
self.dbstate.db.close(
user=User(callback=self._pulse_progress,
uistate=self.uistate,
dbstate=self.dbstate))
self.dbstate.change_database(db) self.dbstate.change_database(db)
break break
except DbUpgradeRequiredError as msg: except DbUpgradeRequiredError as msg:

View File

@ -639,7 +639,7 @@ class DbManager(CLIDbManager):
self.__start_cursor(_("Extracting archive...")) self.__start_cursor(_("Extracting archive..."))
dbase = self.dbstate.make_database("bsddb") dbase = self.dbstate.make_database("bsddb")
dbase.load(new_path, None) dbase.load(new_path)
self.__start_cursor(_("Importing archive...")) self.__start_cursor(_("Importing archive..."))
check_out(dbase, revision, db_path, self.user) check_out(dbase, revision, db_path, self.user)

View File

@ -48,10 +48,9 @@ class User(user.User):
This class provides a means to interact with the user via GTK. This class provides a means to interact with the user via GTK.
It implements the interface in :class:`.gen.user.User` It implements the interface in :class:`.gen.user.User`
""" """
def __init__(self, callback=None, error=None, uistate=None): def __init__(self, callback=None, error=None, uistate=None, dbstate=None):
user.User.__init__(self, callback, error) user.User.__init__(self, callback, error, uistate, dbstate)
self._progress = None self._progress = None
self.uistate = uistate
def begin_progress(self, title, message, steps): def begin_progress(self, title, message, steps):
""" """

View File

@ -298,7 +298,8 @@ class ViewManager(CLIManager):
if self.user is None: if self.user is None:
self.user = User(error=ErrorDialog, self.user = User(error=ErrorDialog,
callback=self.uistate.pulse_progressbar, callback=self.uistate.pulse_progressbar,
uistate=self.uistate) uistate=self.uistate,
dbstate=self.dbstate)
self.__connect_signals() self.__connect_signals()
if _GTKOSXAPPLICATION: if _GTKOSXAPPLICATION:
self.macapp.ready() self.macapp.ready()
@ -739,8 +740,7 @@ class ViewManager(CLIManager):
self.uistate.set_sensitive(False) self.uistate.set_sensitive(False)
# backup data, and close the database # backup data, and close the database
self.__backup() self.dbstate.db.close(user=self.user)
self.dbstate.db.close()
# have each page save anything, if they need to: # have each page save anything, if they need to:
self.__delete_pages() self.__delete_pages()
@ -752,22 +752,6 @@ class ViewManager(CLIManager):
config.save() config.save()
Gtk.main_quit() Gtk.main_quit()
def __backup(self):
"""
Backup the current file as a backup file.
"""
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.dbstate.db.backup(user=self.user)
except DbException as msg:
ErrorDialog(_("Error saving backup data"), msg,
parent=self.uistate.window)
self.uistate.set_busy_cursor(False)
self.uistate.progress.hide()
def abort(self, obj=None): def abort(self, obj=None):
""" """
Abandon changes and quit. Abandon changes and quit.
@ -1097,6 +1081,8 @@ class ViewManager(CLIManager):
dialog = DbManager(self.uistate, self.dbstate, self.window) dialog = DbManager(self.uistate, self.dbstate, self.window)
value = dialog.run() value = dialog.run()
if value: if value:
if self.dbstate.db.is_open():
self.dbstate.db.close(user=self.user)
(filename, title) = value (filename, title) = value
self.db_loader.read_file(filename) self.db_loader.read_file(filename)
self._post_load_newdb(filename, 'x-directory/normal', title) self._post_load_newdb(filename, 'x-directory/normal', title)

View File

@ -1510,13 +1510,14 @@ class DbBsddb(DbBsddbRead, DbWriteBase, UpdateCallback):
self.db_is_open = False self.db_is_open = False
@catch_db_error @catch_db_error
def close(self, update=True): def close(self, update=True, user=None):
""" """
Close the database. Close the database.
if update is False, don't change access times, etc. if update is False, don't change access times, etc.
""" """
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()

View File

@ -53,6 +53,13 @@ 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,