When switching to a library with a corrupted database, offer the user the option of rebuilding the database instead of erroring out.

This commit is contained in:
Kovid Goyal 2011-09-28 19:26:59 -06:00
parent 5d9716f271
commit 23a28b430b
5 changed files with 34 additions and 14 deletions

View File

@ -64,4 +64,6 @@ Various things that require other things before they can be migrated:
columns/categories/searches info into columns/categories/searches info into
self.field_metadata. Finally, implement metadata dirtied self.field_metadata. Finally, implement metadata dirtied
functionality. functionality.
2. Catching DatabaseException and sqlite.Error when creating new
libraries/switching/on calibre startup.
''' '''

View File

@ -405,13 +405,12 @@ class ChooseLibraryAction(InterfaceAction):
else: else:
return return
prefs['library_path'] = loc
#from calibre.utils.mem import memory #from calibre.utils.mem import memory
#import weakref #import weakref
#from PyQt4.Qt import QTimer #from PyQt4.Qt import QTimer
#self.dbref = weakref.ref(self.gui.library_view.model().db) #self.dbref = weakref.ref(self.gui.library_view.model().db)
#self.before_mem = memory()/1024**2 #self.before_mem = memory()/1024**2
self.gui.library_moved(loc) self.gui.library_moved(loc, allow_rebuild=True)
#QTimer.singleShot(5000, self.debug_leak) #QTimer.singleShot(5000, self.debug_leak)
def debug_leak(self): def debug_leak(self):
@ -455,7 +454,8 @@ class ChooseLibraryAction(InterfaceAction):
self.choose_dialog_library_renamed = getattr(c, 'library_renamed', False) self.choose_dialog_library_renamed = getattr(c, 'library_renamed', False)
def choose_library_callback(self, newloc, copy_structure=False): def choose_library_callback(self, newloc, copy_structure=False):
self.gui.library_moved(newloc, copy_structure=copy_structure) self.gui.library_moved(newloc, copy_structure=copy_structure,
allow_rebuild=True)
if getattr(self, 'choose_dialog_library_renamed', False): if getattr(self, 'choose_dialog_library_renamed', False):
self.stats.rename(self.pre_choose_dialog_location, prefs['library_path']) self.stats.rename(self.pre_choose_dialog_location, prefs['library_path'])
self.build_menus() self.build_menus()

View File

@ -13,7 +13,6 @@ from calibre.gui2.dialogs.choose_library_ui import Ui_Dialog
from calibre.gui2 import error_dialog, choose_dir from calibre.gui2 import error_dialog, choose_dir
from calibre.constants import filesystem_encoding, iswindows from calibre.constants import filesystem_encoding, iswindows
from calibre import isbytestring, patheq from calibre import isbytestring, patheq
from calibre.utils.config import prefs
from calibre.gui2.wizard import move_library from calibre.gui2.wizard import move_library
from calibre.library.database2 import LibraryDatabase2 from calibre.library.database2 import LibraryDatabase2
@ -77,7 +76,6 @@ class ChooseLibrary(QDialog, Ui_Dialog):
def perform_action(self, ac, loc): def perform_action(self, ac, loc):
if ac in ('new', 'existing'): if ac in ('new', 'existing'):
prefs['library_path'] = loc
self.callback(loc, copy_structure=self.copy_structure.isChecked()) self.callback(loc, copy_structure=self.copy_structure.isChecked())
else: else:
self.db.prefs.disable_setting = True self.db.prefs.disable_setting = True

View File

@ -120,18 +120,18 @@ def restore_database(db, parent=None):
_show_success_msg(r, parent=parent) _show_success_msg(r, parent=parent)
return True return True
def repair_library_at(library_path): def repair_library_at(library_path, parent=None):
d = DBRestore(None, library_path) d = DBRestore(parent, library_path)
d.exec_() d.exec_()
if d.rejected: if d.rejected:
return False return False
r = d.restorer r = d.restorer
if r.tb is not None: if r.tb is not None:
error_dialog(None, _('Failed'), error_dialog(parent, _('Failed'),
_('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)
return False return False
_show_success_msg(r) _show_success_msg(r, parent=parent)
return True return True

View File

@ -18,8 +18,8 @@ from PyQt4.Qt import (Qt, SIGNAL, QTimer, QHelpEvent, QAction,
QMenu, QIcon, pyqtSignal, QUrl, QMenu, QIcon, pyqtSignal, QUrl,
QDialog, QSystemTrayIcon, QApplication) QDialog, QSystemTrayIcon, QApplication)
from calibre import prints from calibre import prints, force_unicode
from calibre.constants import __appname__, isosx from calibre.constants import __appname__, isosx, filesystem_encoding
from calibre.utils.config import prefs, dynamic from calibre.utils.config import prefs, dynamic
from calibre.utils.ipc.server import Server from calibre.utils.ipc.server import Server
from calibre.library.database2 import LibraryDatabase2 from calibre.library.database2 import LibraryDatabase2
@ -41,7 +41,7 @@ from calibre.gui2.search_box import SearchBoxMixin, SavedSearchBoxMixin
from calibre.gui2.search_restriction_mixin import SearchRestrictionMixin from calibre.gui2.search_restriction_mixin import SearchRestrictionMixin
from calibre.gui2.tag_browser.ui import TagBrowserMixin from calibre.gui2.tag_browser.ui import TagBrowserMixin
from calibre.gui2.keyboard import Manager from calibre.gui2.keyboard import Manager
from calibre.library.sqlite import sqlite, DatabaseException
class Listener(Thread): # {{{ class Listener(Thread): # {{{
@ -475,7 +475,8 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, EmailMixin, # {{{
def booklists(self): def booklists(self):
return self.memory_view.model().db, self.card_a_view.model().db, self.card_b_view.model().db return self.memory_view.model().db, self.card_a_view.model().db, self.card_b_view.model().db
def library_moved(self, newloc, copy_structure=False, call_close=True): def library_moved(self, newloc, copy_structure=False, call_close=True,
allow_rebuild=False):
if newloc is None: return if newloc is None: return
default_prefs = None default_prefs = None
try: try:
@ -484,7 +485,26 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, EmailMixin, # {{{
default_prefs = olddb.prefs default_prefs = olddb.prefs
except: except:
olddb = None olddb = None
try:
db = LibraryDatabase2(newloc, default_prefs=default_prefs) db = LibraryDatabase2(newloc, default_prefs=default_prefs)
except (DatabaseException, sqlite.Error):
if not allow_rebuild: raise
import traceback
repair = question_dialog(self, _('Corrupted database'),
_('The library database at %s appears to be corrupted. Do '
'you want calibre to try and rebuild it automatically? '
'The rebuild may not be completely successful.')
% force_unicode(newloc, filesystem_encoding),
det_msg=traceback.format_exc()
)
if repair:
from calibre.gui2.dialogs.restore_library import repair_library_at
if repair_library_at(newloc, parent=self):
db = LibraryDatabase2(newloc, default_prefs=default_prefs)
else:
return
else:
return
if self.content_server is not None: if self.content_server is not None:
self.content_server.set_database(db) self.content_server.set_database(db)
self.library_path = newloc self.library_path = newloc