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.
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.
:param error: If given, notify_error delegates to this callback
:type error: function(title, error)
"""
user.User.__init__(self, callback, error)
user.User.__init__(self, callback, error, uistate, dbstate)
self.steps = 0;
self.current_step = 0;
self._input = input

View File

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

View File

@ -1696,16 +1696,17 @@ class DbGeneric(DbWriteBase, DbReadBase, UpdateCallback, Callback):
return False
return True
def close(self, update=True):
def close(self, update=True, user=None):
"""
Close the database.
if update is False, don't change access times, etc.
"""
if self._directory:
if update:
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")
if update:
touch(filename)
# Save metadata
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).
"""
def __init__(self, callback=None, error=None):
def __init__(self, callback=None, error=None, uistate=None, dbstate=None):
self.callback_function = callback
self.error_function = error
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):
"""

View File

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

View File

@ -639,7 +639,7 @@ class DbManager(CLIDbManager):
self.__start_cursor(_("Extracting archive..."))
dbase = self.dbstate.make_database("bsddb")
dbase.load(new_path, None)
dbase.load(new_path)
self.__start_cursor(_("Importing archive..."))
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.
It implements the interface in :class:`.gen.user.User`
"""
def __init__(self, callback=None, error=None, uistate=None):
user.User.__init__(self, callback, error)
def __init__(self, callback=None, error=None, uistate=None, dbstate=None):
user.User.__init__(self, callback, error, uistate, dbstate)
self._progress = None
self.uistate = uistate
def begin_progress(self, title, message, steps):
"""

View File

@ -298,7 +298,8 @@ class ViewManager(CLIManager):
if self.user is None:
self.user = User(error=ErrorDialog,
callback=self.uistate.pulse_progressbar,
uistate=self.uistate)
uistate=self.uistate,
dbstate=self.dbstate)
self.__connect_signals()
if _GTKOSXAPPLICATION:
self.macapp.ready()
@ -739,8 +740,7 @@ class ViewManager(CLIManager):
self.uistate.set_sensitive(False)
# backup data, and close the database
self.__backup()
self.dbstate.db.close()
self.dbstate.db.close(user=self.user)
# have each page save anything, if they need to:
self.__delete_pages()
@ -752,22 +752,6 @@ class ViewManager(CLIManager):
config.save()
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):
"""
Abandon changes and quit.
@ -1097,6 +1081,8 @@ class ViewManager(CLIManager):
dialog = DbManager(self.uistate, self.dbstate, self.window)
value = dialog.run()
if value:
if self.dbstate.db.is_open():
self.dbstate.db.close(user=self.user)
(filename, title) = value
self.db_loader.read_file(filename)
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
@catch_db_error
def close(self, update=True):
def close(self, update=True, user=None):
"""
Close the database.
if update is False, don't change access times, etc.
"""
if not self.db_is_open:
return
self.autobackup(user)
if self.txn:
self.transaction_abort(self.transaction)
self.env.txn_checkpoint()

View File

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