mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-06-23 15:30:45 -04:00
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)
This commit is contained in:
parent
488069faad
commit
5d9716f271
@ -5,12 +5,14 @@ __license__ = 'GPL v3'
|
|||||||
__copyright__ = '2011, Kovid Goyal <kovid@kovidgoyal.net>'
|
__copyright__ = '2011, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||||
__docformat__ = 'restructuredtext en'
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|
||||||
from PyQt4.Qt import QDialog, QLabel, QVBoxLayout, QDialogButtonBox, \
|
from PyQt4.Qt import (QDialog, QLabel, QVBoxLayout, QDialogButtonBox,
|
||||||
QProgressBar, QSize, QTimer, pyqtSignal, Qt
|
QProgressBar, QSize, QTimer, pyqtSignal, Qt)
|
||||||
|
|
||||||
from calibre.library.restore import Restore
|
from calibre.library.restore import Restore
|
||||||
from calibre.gui2 import error_dialog, question_dialog, warning_dialog, \
|
from calibre.gui2 import (error_dialog, question_dialog, warning_dialog,
|
||||||
info_dialog
|
info_dialog)
|
||||||
|
from calibre import force_unicode
|
||||||
|
from calibre.constants import filesystem_encoding
|
||||||
|
|
||||||
class DBRestore(QDialog):
|
class DBRestore(QDialog):
|
||||||
|
|
||||||
@ -73,6 +75,19 @@ class DBRestore(QDialog):
|
|||||||
self.msg.setText(msg)
|
self.msg.setText(msg)
|
||||||
self.pb.setValue(step)
|
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):
|
def restore_database(db, parent=None):
|
||||||
if not question_dialog(parent, _('Are you sure?'), '<p>'+
|
if not question_dialog(parent, _('Are you sure?'), '<p>'+
|
||||||
@ -102,14 +117,21 @@ def restore_database(db, parent=None):
|
|||||||
_('Restoring database failed, click Show details to see details'),
|
_('Restoring database failed, click Show details to see details'),
|
||||||
det_msg=r.tb, show=True)
|
det_msg=r.tb, show=True)
|
||||||
else:
|
else:
|
||||||
if r.errors_occurred:
|
_show_success_msg(r, parent=parent)
|
||||||
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)
|
|
||||||
return True
|
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
|
||||||
|
|
||||||
|
|
||||||
|
@ -4,16 +4,15 @@ __copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
|
|||||||
import sys, os, time, socket, traceback
|
import sys, os, time, socket, traceback
|
||||||
from functools import partial
|
from functools import partial
|
||||||
|
|
||||||
from PyQt4.Qt import QCoreApplication, QIcon, QObject, QTimer, \
|
from PyQt4.Qt import (QCoreApplication, QIcon, QObject, QTimer,
|
||||||
QThread, pyqtSignal, Qt, QProgressDialog, QString, QPixmap, \
|
QPixmap, QSplashScreen, QApplication)
|
||||||
QSplashScreen, QApplication
|
|
||||||
|
|
||||||
from calibre import prints, plugins
|
from calibre import prints, plugins
|
||||||
from calibre.constants import iswindows, __appname__, isosx, DEBUG, \
|
from calibre.constants import (iswindows, __appname__, isosx, DEBUG,
|
||||||
filesystem_encoding
|
filesystem_encoding)
|
||||||
from calibre.utils.ipc import ADDRESS, RC
|
from calibre.utils.ipc import ADDRESS, RC
|
||||||
from calibre.gui2 import ORG_NAME, APP_UID, initialize_file_icon_provider, \
|
from calibre.gui2 import (ORG_NAME, APP_UID, initialize_file_icon_provider,
|
||||||
Application, choose_dir, error_dialog, question_dialog, gprefs
|
Application, choose_dir, error_dialog, question_dialog, gprefs)
|
||||||
from calibre.gui2.main_window import option_parser as _option_parser
|
from calibre.gui2.main_window import option_parser as _option_parser
|
||||||
from calibre.utils.config import prefs, dynamic
|
from calibre.utils.config import prefs, dynamic
|
||||||
from calibre.library.database2 import LibraryDatabase2
|
from calibre.library.database2 import LibraryDatabase2
|
||||||
@ -110,36 +109,9 @@ def get_library_path(parent=None):
|
|||||||
default_dir=get_default_library_path())
|
default_dir=get_default_library_path())
|
||||||
return library_path
|
return library_path
|
||||||
|
|
||||||
class DBRepair(QThread):
|
def repair_library(library_path):
|
||||||
|
from calibre.gui2.dialogs.restore_library import repair_library_at
|
||||||
repair_done = pyqtSignal(object, object)
|
return repair_library_at(library_path)
|
||||||
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)
|
|
||||||
|
|
||||||
class GuiRunner(QObject):
|
class GuiRunner(QObject):
|
||||||
'''Make sure an event loop is running before starting the main work of
|
'''Make sure an event loop is running before starting the main work of
|
||||||
@ -184,9 +156,6 @@ class GuiRunner(QObject):
|
|||||||
raise SystemExit(1)
|
raise SystemExit(1)
|
||||||
|
|
||||||
def initialize_db_stage2(self, db, tb):
|
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:
|
if db is None and tb is not None:
|
||||||
# DB Repair failed
|
# DB Repair failed
|
||||||
@ -219,23 +188,15 @@ class GuiRunner(QObject):
|
|||||||
db = LibraryDatabase2(self.library_path)
|
db = LibraryDatabase2(self.library_path)
|
||||||
except (sqlite.Error, DatabaseException):
|
except (sqlite.Error, DatabaseException):
|
||||||
repair = question_dialog(self.splash_screen, _('Corrupted database'),
|
repair = question_dialog(self.splash_screen, _('Corrupted database'),
|
||||||
_('Your calibre database appears to be corrupted. Do '
|
_('Your calibre library database appears to be corrupted. Do '
|
||||||
'you want calibre to try and repair it automatically? '
|
'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.'),
|
'If you say No, a new empty calibre library will be created.'),
|
||||||
det_msg=traceback.format_exc()
|
det_msg=traceback.format_exc()
|
||||||
)
|
)
|
||||||
if repair:
|
if repair:
|
||||||
self.repair_pd = QProgressDialog(_('Repairing database. This '
|
if repair_library(self.library_path):
|
||||||
'can take a very long time for a large collection'), QString(),
|
db = LibraryDatabase2(self.library_path)
|
||||||
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
|
|
||||||
except:
|
except:
|
||||||
error_dialog(self.splash_screen, _('Bad database location'),
|
error_dialog(self.splash_screen, _('Bad database location'),
|
||||||
_('Bad database location %r. Will start with '
|
_('Bad database location %r. Will start with '
|
||||||
|
Loading…
x
Reference in New Issue
Block a user