From 5d9716f271a37cf6054f9e93b35ef573d5f58c53 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 28 Sep 2011 18:53:20 -0600 Subject: [PATCH] When starting with a library that has a corrupted db, offer the user the option of rebuilding the db from backups, instead of trying to repair the db (which is likely to fail anyway) --- src/calibre/gui2/dialogs/restore_library.py | 48 +++++++++++---- src/calibre/gui2/main.py | 67 +++++---------------- 2 files changed, 49 insertions(+), 66 deletions(-) diff --git a/src/calibre/gui2/dialogs/restore_library.py b/src/calibre/gui2/dialogs/restore_library.py index 60b224d1cd..42bb06ae29 100644 --- a/src/calibre/gui2/dialogs/restore_library.py +++ b/src/calibre/gui2/dialogs/restore_library.py @@ -5,12 +5,14 @@ __license__ = 'GPL v3' __copyright__ = '2011, Kovid Goyal ' __docformat__ = 'restructuredtext en' -from PyQt4.Qt import QDialog, QLabel, QVBoxLayout, QDialogButtonBox, \ - QProgressBar, QSize, QTimer, pyqtSignal, Qt +from PyQt4.Qt import (QDialog, QLabel, QVBoxLayout, QDialogButtonBox, + QProgressBar, QSize, QTimer, pyqtSignal, Qt) from calibre.library.restore import Restore -from calibre.gui2 import error_dialog, question_dialog, warning_dialog, \ - info_dialog +from calibre.gui2 import (error_dialog, question_dialog, warning_dialog, + info_dialog) +from calibre import force_unicode +from calibre.constants import filesystem_encoding class DBRestore(QDialog): @@ -73,6 +75,19 @@ class DBRestore(QDialog): self.msg.setText(msg) self.pb.setValue(step) +def _show_success_msg(restorer, parent=None): + r = restorer + olddb = _('The old database was saved as: %s')%force_unicode(r.olddb, + filesystem_encoding) + if r.errors_occurred: + warning_dialog(parent, _('Success'), + _('Restoring the database succeeded with some warnings' + ' click Show details to see the details. %s')%olddb, + det_msg=r.report, show=True) + else: + info_dialog(parent, _('Success'), + _('Restoring database was successful. %s')%olddb, show=True, + show_copy_button=False) def restore_database(db, parent=None): if not question_dialog(parent, _('Are you sure?'), '

'+ @@ -102,14 +117,21 @@ def restore_database(db, parent=None): _('Restoring database failed, click Show details to see details'), det_msg=r.tb, show=True) else: - if r.errors_occurred: - warning_dialog(parent, _('Success'), - _('Restoring the database succeeded with some warnings' - ' click Show details to see the details.'), - det_msg=r.report, show=True) - else: - info_dialog(parent, _('Success'), - _('Restoring database was successful'), show=True, - show_copy_button=False) + _show_success_msg(r, parent=parent) return True +def repair_library_at(library_path): + d = DBRestore(None, library_path) + d.exec_() + if d.rejected: + return False + r = d.restorer + if r.tb is not None: + error_dialog(None, _('Failed'), + _('Restoring database failed, click Show details to see details'), + det_msg=r.tb, show=True) + return False + _show_success_msg(r) + return True + + diff --git a/src/calibre/gui2/main.py b/src/calibre/gui2/main.py index 76b734a718..76dd400829 100644 --- a/src/calibre/gui2/main.py +++ b/src/calibre/gui2/main.py @@ -4,16 +4,15 @@ __copyright__ = '2008, Kovid Goyal ' import sys, os, time, socket, traceback from functools import partial -from PyQt4.Qt import QCoreApplication, QIcon, QObject, QTimer, \ - QThread, pyqtSignal, Qt, QProgressDialog, QString, QPixmap, \ - QSplashScreen, QApplication +from PyQt4.Qt import (QCoreApplication, QIcon, QObject, QTimer, + QPixmap, QSplashScreen, QApplication) from calibre import prints, plugins -from calibre.constants import iswindows, __appname__, isosx, DEBUG, \ - filesystem_encoding +from calibre.constants import (iswindows, __appname__, isosx, DEBUG, + filesystem_encoding) from calibre.utils.ipc import ADDRESS, RC -from calibre.gui2 import ORG_NAME, APP_UID, initialize_file_icon_provider, \ - Application, choose_dir, error_dialog, question_dialog, gprefs +from calibre.gui2 import (ORG_NAME, APP_UID, initialize_file_icon_provider, + Application, choose_dir, error_dialog, question_dialog, gprefs) from calibre.gui2.main_window import option_parser as _option_parser from calibre.utils.config import prefs, dynamic from calibre.library.database2 import LibraryDatabase2 @@ -110,36 +109,9 @@ def get_library_path(parent=None): default_dir=get_default_library_path()) return library_path -class DBRepair(QThread): - - repair_done = pyqtSignal(object, object) - progress = pyqtSignal(object, object) - - def __init__(self, library_path, parent, pd): - QThread.__init__(self, parent) - self.library_path = library_path - self.pd = pd - self.progress.connect(self._callback, type=Qt.QueuedConnection) - - def _callback(self, num, is_length): - if is_length: - self.pd.setRange(0, num-1) - num = 0 - self.pd.setValue(num) - - def callback(self, num, is_length): - self.progress.emit(num, is_length) - - def run(self): - from calibre.debug import reinit_db - try: - reinit_db(os.path.join(self.library_path, 'metadata.db'), - self.callback) - db = LibraryDatabase2(self.library_path) - tb = None - except: - db, tb = None, traceback.format_exc() - self.repair_done.emit(db, tb) +def repair_library(library_path): + from calibre.gui2.dialogs.restore_library import repair_library_at + return repair_library_at(library_path) class GuiRunner(QObject): '''Make sure an event loop is running before starting the main work of @@ -184,9 +156,6 @@ class GuiRunner(QObject): raise SystemExit(1) def initialize_db_stage2(self, db, tb): - repair_pd = getattr(self, 'repair_pd', None) - if repair_pd is not None: - repair_pd.cancel() if db is None and tb is not None: # DB Repair failed @@ -219,23 +188,15 @@ class GuiRunner(QObject): db = LibraryDatabase2(self.library_path) except (sqlite.Error, DatabaseException): repair = question_dialog(self.splash_screen, _('Corrupted database'), - _('Your calibre database appears to be corrupted. Do ' - 'you want calibre to try and repair it automatically? ' + _('Your calibre library database appears to be corrupted. Do ' + 'you want calibre to try and rebuild it automatically? ' + 'The rebuild may not be completely successful. ' 'If you say No, a new empty calibre library will be created.'), det_msg=traceback.format_exc() ) if repair: - self.repair_pd = QProgressDialog(_('Repairing database. This ' - 'can take a very long time for a large collection'), QString(), - 0, 0) - self.repair_pd.setWindowModality(Qt.WindowModal) - self.repair_pd.show() - - self.repair = DBRepair(self.library_path, self, self.repair_pd) - self.repair.repair_done.connect(self.initialize_db_stage2, - type=Qt.QueuedConnection) - self.repair.start() - return + if repair_library(self.library_path): + db = LibraryDatabase2(self.library_path) except: error_dialog(self.splash_screen, _('Bad database location'), _('Bad database location %r. Will start with '