mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Make report types optional in CLI
This commit is contained in:
parent
81ad156e53
commit
06bcd520b4
@ -6,7 +6,7 @@ __license__ = 'GPL v3'
|
|||||||
from PyQt4.Qt import QDialog, QVBoxLayout, QTreeWidget, QPushButton, \
|
from PyQt4.Qt import QDialog, QVBoxLayout, QTreeWidget, QPushButton, \
|
||||||
QDialogButtonBox, QApplication, QTreeWidgetItem
|
QDialogButtonBox, QApplication, QTreeWidgetItem
|
||||||
|
|
||||||
from calibre.library.check_library import CheckLibrary
|
from calibre.library.check_library import CheckLibrary, CHECKS
|
||||||
|
|
||||||
class Item(QTreeWidgetItem):
|
class Item(QTreeWidgetItem):
|
||||||
pass
|
pass
|
||||||
@ -71,7 +71,7 @@ class CheckLibraryDialog(QDialog):
|
|||||||
t.clear()
|
t.clear()
|
||||||
t.setColumnCount(3);
|
t.setColumnCount(3);
|
||||||
t.setHeaderLabels([_('Name'), _('Path from library'), _('Additional Information')])
|
t.setHeaderLabels([_('Name'), _('Path from library'), _('Additional Information')])
|
||||||
for check in checker.checks:
|
for check in CHECKS:
|
||||||
builder(t, checker, check)
|
builder(t, checker, check)
|
||||||
|
|
||||||
t.setColumnWidth(0, 200)
|
t.setColumnWidth(0, 200)
|
||||||
|
@ -15,17 +15,18 @@ EBOOK_EXTENSIONS = frozenset(BOOK_EXTENSIONS)
|
|||||||
|
|
||||||
NORMALS = frozenset(['metadata.opf', 'cover.jpg'])
|
NORMALS = frozenset(['metadata.opf', 'cover.jpg'])
|
||||||
|
|
||||||
class CheckLibrary(object):
|
CHECKS = [('invalid_titles', _('Invalid titles')),
|
||||||
|
('extra_titles', _('Extra titles')),
|
||||||
|
('invalid_authors', _('Invalid authors')),
|
||||||
|
('extra_authors', _('Extra authors')),
|
||||||
|
('missing_formats', _('Missing book formats')),
|
||||||
|
('extra_formats', _('Extra book formats')),
|
||||||
|
('extra_files', _('Unknown files in book')),
|
||||||
|
('failed_folders', _('Folders raising exception'))
|
||||||
|
]
|
||||||
|
|
||||||
checks = [('invalid_titles', _('Invalid titles')),
|
|
||||||
('extra_titles', _('Extra titles')),
|
class CheckLibrary(object):
|
||||||
('invalid_authors', _('Invalid authors')),
|
|
||||||
('extra_authors', _('Extra authors')),
|
|
||||||
('missing_formats', _('Missing book formats')),
|
|
||||||
('extra_formats', _('Extra book formats')),
|
|
||||||
('extra_files', _('Unknown files in book')),
|
|
||||||
('failed_folders', _('Folders raising exception'))
|
|
||||||
]
|
|
||||||
|
|
||||||
def __init__(self, library_path, db):
|
def __init__(self, library_path, db):
|
||||||
if isbytestring(library_path):
|
if isbytestring(library_path):
|
||||||
@ -35,7 +36,10 @@ class CheckLibrary(object):
|
|||||||
|
|
||||||
self.all_authors = frozenset([x[1] for x in db.all_authors()])
|
self.all_authors = frozenset([x[1] for x in db.all_authors()])
|
||||||
self.all_ids = frozenset([id for id in db.all_ids()])
|
self.all_ids = frozenset([id for id in db.all_ids()])
|
||||||
|
self.is_case_sensitive = db.is_case_sensitive
|
||||||
self.all_dbpaths = frozenset(self.dbpath(id) for id in self.all_ids)
|
self.all_dbpaths = frozenset(self.dbpath(id) for id in self.all_ids)
|
||||||
|
self.all_lc_dbpaths = frozenset(self.dbpath(id).lower()
|
||||||
|
for id in self.all_ids)
|
||||||
|
|
||||||
self.db_id_regexp = re.compile(r'^.* \((\d+)\)$')
|
self.db_id_regexp = re.compile(r'^.* \((\d+)\)$')
|
||||||
self.bad_ext_pat = re.compile(r'[^a-z]+')
|
self.bad_ext_pat = re.compile(r'[^a-z]+')
|
||||||
@ -55,13 +59,6 @@ class CheckLibrary(object):
|
|||||||
self.extra_formats = []
|
self.extra_formats = []
|
||||||
self.extra_files = []
|
self.extra_files = []
|
||||||
|
|
||||||
self.failed_folders = []
|
|
||||||
self.books = []
|
|
||||||
self.conflicting_custom_cols = {}
|
|
||||||
self.failed_restores = []
|
|
||||||
self.mismatched_dirs = []
|
|
||||||
self.successes = 0
|
|
||||||
self.tb = None
|
|
||||||
|
|
||||||
def dbpath(self, id):
|
def dbpath(self, id):
|
||||||
return self.db.path(id, index_is_id=True)
|
return self.db.path(id, index_is_id=True)
|
||||||
@ -71,34 +68,6 @@ class CheckLibrary(object):
|
|||||||
return self.failed_folders or self.mismatched_dirs or \
|
return self.failed_folders or self.mismatched_dirs or \
|
||||||
self.conflicting_custom_cols or self.failed_restores
|
self.conflicting_custom_cols or self.failed_restores
|
||||||
|
|
||||||
@property
|
|
||||||
def report(self):
|
|
||||||
ans = ''
|
|
||||||
failures = list(self.failed_folders) + [(x['dirpath'], tb) for x, tb in
|
|
||||||
self.failed_restores]
|
|
||||||
if failures:
|
|
||||||
ans += 'Failed to restore the books in the following folders:\n'
|
|
||||||
for dirpath, tb in failures:
|
|
||||||
ans += '\t' + dirpath + ' with error:\n'
|
|
||||||
ans += '\n'.join('\t\t'+x for x in tb.splitlines())
|
|
||||||
ans += '\n\n'
|
|
||||||
|
|
||||||
if self.conflicting_custom_cols:
|
|
||||||
ans += '\n\n'
|
|
||||||
ans += 'The following custom columns were not fully restored:\n'
|
|
||||||
for x in self.conflicting_custom_cols:
|
|
||||||
ans += '\t#'+x+'\n'
|
|
||||||
|
|
||||||
if self.mismatched_dirs:
|
|
||||||
ans += '\n\n'
|
|
||||||
ans += 'The following folders were ignored:\n'
|
|
||||||
for x in self.mismatched_dirs:
|
|
||||||
ans += '\t'+x+'\n'
|
|
||||||
|
|
||||||
|
|
||||||
return ans
|
|
||||||
|
|
||||||
|
|
||||||
def scan_library(self):
|
def scan_library(self):
|
||||||
lib = self.src_library_path
|
lib = self.src_library_path
|
||||||
for auth_dir in os.listdir(lib):
|
for auth_dir in os.listdir(lib):
|
||||||
@ -123,10 +92,16 @@ class CheckLibrary(object):
|
|||||||
|
|
||||||
id = m.group(1)
|
id = m.group(1)
|
||||||
# Third check: the id must be in the DB and the paths must match
|
# Third check: the id must be in the DB and the paths must match
|
||||||
if int(id) not in self.all_ids or \
|
if self.is_case_sensitive:
|
||||||
db_path not in self.all_dbpaths:
|
if int(id) not in self.all_ids or \
|
||||||
self.extra_titles.append((title_dir, db_path, []))
|
db_path not in self.all_dbpaths:
|
||||||
continue
|
self.extra_titles.append((title_dir, db_path, []))
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
if int(id) not in self.all_ids or \
|
||||||
|
db_path.lower() not in self.all_lc_dbpaths:
|
||||||
|
self.extra_titles.append((title_dir, db_path, []))
|
||||||
|
continue
|
||||||
|
|
||||||
# Record the book to check its formats
|
# Record the book to check its formats
|
||||||
self.book_dirs.append((db_path, title_dir, id))
|
self.book_dirs.append((db_path, title_dir, id))
|
||||||
|
@ -875,19 +875,23 @@ def command_saved_searches(args, dbpath):
|
|||||||
return 0
|
return 0
|
||||||
|
|
||||||
def check_library_option_parser():
|
def check_library_option_parser():
|
||||||
from calibre.library.custom_columns import CustomColumns
|
from calibre.library.check_library import CHECKS
|
||||||
parser = get_parser(_('''\
|
parser = get_parser(_('''\
|
||||||
%prog check_library [options]
|
%prog check_library [options]
|
||||||
|
|
||||||
Perform some checks on the filesystem representing a library.
|
Perform some checks on the filesystem representing a library. Reports are {0}
|
||||||
''').format(', '.join(CustomColumns.CUSTOM_DATA_TYPES)))
|
''').format(', '.join([c[0] for c in CHECKS])))
|
||||||
|
|
||||||
parser.add_option('-c', '--csv', default=False, action='store_true',
|
parser.add_option('-c', '--csv', default=False, action='store_true',
|
||||||
help=_('Output in CSV'))
|
help=_('Output in CSV'))
|
||||||
|
|
||||||
|
parser.add_option('-r', '--report', default=None, dest='report',
|
||||||
|
help=_("Comma-separated list of reports.\n"
|
||||||
|
"Default: all"))
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
def command_check_library(args, dbpath):
|
def command_check_library(args, dbpath):
|
||||||
from calibre.library.check_library import CheckLibrary
|
from calibre.library.check_library import CheckLibrary, CHECKS
|
||||||
parser = check_library_option_parser()
|
parser = check_library_option_parser()
|
||||||
opts, args = parser.parse_args(args)
|
opts, args = parser.parse_args(args)
|
||||||
if len(args) != 0:
|
if len(args) != 0:
|
||||||
@ -900,6 +904,21 @@ def command_check_library(args, dbpath):
|
|||||||
if isbytestring(dbpath):
|
if isbytestring(dbpath):
|
||||||
dbpath = dbpath.decode(preferred_encoding)
|
dbpath = dbpath.decode(preferred_encoding)
|
||||||
|
|
||||||
|
if opts.report is None:
|
||||||
|
checks = CHECKS
|
||||||
|
else:
|
||||||
|
checks = []
|
||||||
|
for r in opts.report.split(','):
|
||||||
|
found = False
|
||||||
|
for c in CHECKS:
|
||||||
|
if c[0] == r:
|
||||||
|
checks.append(c)
|
||||||
|
found = True
|
||||||
|
break
|
||||||
|
if not found:
|
||||||
|
print _('Unknown report check'), r
|
||||||
|
return 1
|
||||||
|
|
||||||
def print_one(checker, check):
|
def print_one(checker, check):
|
||||||
attr = check[0]
|
attr = check[0]
|
||||||
list = getattr(checker, attr, None)
|
list = getattr(checker, attr, None)
|
||||||
@ -916,7 +935,7 @@ def command_check_library(args, dbpath):
|
|||||||
db = LibraryDatabase2(dbpath)
|
db = LibraryDatabase2(dbpath)
|
||||||
checker = CheckLibrary(dbpath, db)
|
checker = CheckLibrary(dbpath, db)
|
||||||
checker.scan_library()
|
checker.scan_library()
|
||||||
for check in checker.checks:
|
for check in checks:
|
||||||
print_one(checker, check)
|
print_one(checker, check)
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user