From 7f4f546ce254e558e6a3743b534b25efbfc768a7 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 2 May 2017 11:00:40 +0530 Subject: [PATCH] Port calibredb restore_database --- src/calibre/db/cli/cmd_restore_database.py | 71 ++++++++++++++++++++-- src/calibre/db/cli/main.py | 4 +- 2 files changed, 69 insertions(+), 6 deletions(-) diff --git a/src/calibre/db/cli/cmd_restore_database.py b/src/calibre/db/cli/cmd_restore_database.py index 2f6f22ae56..18eb117127 100644 --- a/src/calibre/db/cli/cmd_restore_database.py +++ b/src/calibre/db/cli/cmd_restore_database.py @@ -4,19 +4,82 @@ from __future__ import absolute_import, division, print_function, unicode_literals +from calibre import prints +from calibre.db.restore import Restore + readonly = False version = 0 # change this if you change signature of implementation() +no_remote = True def implementation(db, notify_changes, *args): - is_remote = notify_changes is not None - is_remote + raise NotImplementedError() def option_parser(get_parser, args): - pass + parser = get_parser( + _( + '''\ +%prog restore_database [options] + +Restore this database from the metadata stored in OPF files in each +directory of the calibre library. This is useful if your metadata.db file +has been corrupted. + +WARNING: This command completely regenerates your database. You will lose +all saved searches, user categories, plugboards, stored per-book conversion +settings, and custom recipes. Restored metadata will only be as accurate as +what is found in the OPF files. + ''' + ) + ) + + parser.add_option( + '-r', + '--really-do-it', + default=False, + action='store_true', + help=_( + 'Really do the recovery. The command will not run ' + 'unless this option is specified.' + ) + ) + return parser + + +class Progress(object): + + def __init__(self): + self.total = 1 + + def __call__(self, msg, step): + if msg is None: + self.total = float(step) + else: + prints(msg, '...', '%d%%' % int(100 * (step / self.total))) def main(opts, args, dbctx): - raise NotImplementedError('TODO: implement this') + if not opts.really_do_it: + raise SystemExit( + _('You must provide the %s option to do a' + ' recovery') % '--really-do-it' + ) + + r = Restore(dbctx.library_path, progress_callback=Progress()) + r.start() + r.join() + + if r.tb is not None: + prints('Restoring database failed with error:') + prints(r.tb) + else: + prints('Restoring database succeeded') + prints('old database saved as', r.olddb) + if r.errors_occurred: + name = 'calibre_db_restore_report.txt' + lopen('calibre_db_restore_report.txt', + 'wb').write(r.report.encode('utf-8')) + prints('Some errors occurred. A detailed report was ' 'saved to', name) + return 0 diff --git a/src/calibre/db/cli/main.py b/src/calibre/db/cli/main.py index e4634207ce..e9cc1095cf 100644 --- a/src/calibre/db/cli/main.py +++ b/src/calibre/db/cli/main.py @@ -21,8 +21,8 @@ from calibre.utils.serialize import MSGPACK_MIME COMMANDS = ( 'list', 'add', 'remove', 'add_format', 'remove_format', 'show_metadata', 'set_metadata', 'export', 'catalog', 'saved_searches', 'add_custom_column', - 'custom_columns', 'remove_custom_column', 'set_custom', - # 'restore_database', 'check_library', 'list_categories', 'backup_metadata', 'clone', 'embed_metadata', 'search' + 'custom_columns', 'remove_custom_column', 'set_custom', 'restore_database', + # 'check_library', 'list_categories', 'backup_metadata', 'clone', 'embed_metadata', 'search' )