diff --git a/doc/changelog b/doc/changelog index 7314187d..859e4e9a 100644 --- a/doc/changelog +++ b/doc/changelog @@ -4,8 +4,10 @@ ocrodjvu (0.8) UNRELEASED; urgency=low * Add the “tesseract: ” prefix to messages Tesseract prints on stderr. https://bitbucket.org/jwilk/ocrodjvu/issue/10 Thanks to Janusz S. Bień for the bug report. + * Ensure that exit code is non-zero if the program recovered from an error. + https://bitbucket.org/jwilk/ocrodjvu/issue/6 - -- Jakub Wilk Fri, 05 Jun 2015 22:05:09 +0200 + -- Jakub Wilk Fri, 05 Jun 2015 23:14:11 +0200 ocrodjvu (0.7.19) unstable; urgency=low diff --git a/doc/ocrodjvu.xml b/doc/ocrodjvu.xml index 0d41e46a..95f0cc60 100644 --- a/doc/ocrodjvu.xml +++ b/doc/ocrodjvu.xml @@ -491,6 +491,27 @@ + + Exit status + + One of the following exit values can be returned by &p;: + + + 0 + The program finished successfully. + + + 1 + A fatal error occurred. + + + 2 + The program recovered from an error (). + + + + + Environment diff --git a/lib/cli/ocrodjvu.py b/lib/cli/ocrodjvu.py index 0a8c8fca..e9247e1b 100644 --- a/lib/cli/ocrodjvu.py +++ b/lib/cli/ocrodjvu.py @@ -14,6 +14,7 @@ from __future__ import print_function import argparse +import collections import contextlib import inspect import locale @@ -252,10 +253,10 @@ def __call__(self, parser, namespace, values, option_string=None): print(language) except errors.EngineNotFound as ex: logger.error(ex) - sys.exit(1) + sys.exit(errors.EXIT_FATAL) except errors.UnknownLanguageList as ex: logger.error(ex) - sys.exit(1) + sys.exit(errors.EXIT_FATAL) else: sys.exit(0) @@ -334,6 +335,12 @@ def parse_args(self, args=None, namespace=None): options.n_jobs = get_cpu_count() return options +class Results(dict): + seen_exception = False + + def __missing__(self, key): + return + class Context(djvu.decode.Context): def init(self, options): @@ -430,6 +437,7 @@ def page_thread(self, pages, results, condition): if self._options.resume_on_error and not interrupted_by_user: # As requested by user, don't abort on error and pretend that nothing happened. results[n] = False + results.seen_exception = True continue else: # The main thread will take care of aborting the application. @@ -452,7 +460,7 @@ def _process(self, path, pages=None): pages = list(document.pages) else: pages = [document.pages[i - 1] for i in pages] - results = dict((page.n, None) for page in pages) + results = Results() condition = threading.Condition() threads = [ threading.Thread(target=self.page_thread, args=(pages, results, condition)) @@ -497,7 +505,7 @@ def stop_threads(): for thread in threads: thread.join() self._debug = True - sys.exit(1) + sys.exit(errors.EXIT_FATAL) if result is False: # No image suitable for OCR. pass @@ -518,6 +526,8 @@ def stop_threads(): raise finally: sed_file.close() + if results.seen_exception: + sys.exit(errors.EXIT_NONFATAL) def process(self, *args, **kwargs): try: @@ -542,7 +552,7 @@ def main(argv=sys.argv): context.process(options.path, options.pages) except KeyboardInterrupt: logger.info('Interrupted by user.') - sys.exit(1) + sys.exit(errors.FATAL) finally: temp_dir = context.close() if temp_dir is not None: diff --git a/lib/errors.py b/lib/errors.py index 067ba7f1..33f2e8c8 100644 --- a/lib/errors.py +++ b/lib/errors.py @@ -1,6 +1,6 @@ # encoding=UTF-8 -# Copyright © 2009, 2010, 2013 Jakub Wilk +# Copyright © 2009-2015 Jakub Wilk # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -41,4 +41,7 @@ class MalformedHocr(MalformedOcrOutput): def __init__(self, message): Exception.__init__(self, 'Malformed hOCR document: %s' % message) +EXIT_FATAL = 1 +EXIT_NONFATAL = 2 + # vim:ts=4 sts=4 sw=4 et