Further fixes to external program version testing
This commit is contained in:
@@ -85,7 +85,6 @@ For example, if you have a development build of Tesseract don't wish to use the
|
||||
|
||||
In this example ``TESSDATA_PREFIX`` is required to redirect Tesseract to an alternate folder for its "tessdata" files.
|
||||
|
||||
|
||||
Overriding other support programs
|
||||
"""""""""""""""""""""""""""""""""
|
||||
|
||||
|
||||
@@ -13,13 +13,18 @@ Note that it is licensed under GPLv3, so scripts that ``import ocrmypdf`` and ar
|
||||
find: [^`]\#([0-9]{1,3})[^0-9]
|
||||
replace: `#$1 <https://github.com/jbarlow83/OCRmyPDF/issues/$1>`_
|
||||
|
||||
v8.2.1
|
||||
v8.2.2
|
||||
------
|
||||
|
||||
- Fixed a regression from v8.2.0, an exception that occurred while attempting to report that ``unpaper`` or another optional dependency was unavailable.
|
||||
|
||||
- In some cases, ``ocrmypdf [-c|--clean]`` failed to exit with an error when ``unpaper`` is not installed.
|
||||
|
||||
v8.2.1
|
||||
------
|
||||
|
||||
- This release was canceled.
|
||||
|
||||
v8.2.0
|
||||
------
|
||||
|
||||
|
||||
+30
-67
@@ -46,6 +46,7 @@ from .exceptions import (
|
||||
)
|
||||
from .exec import (
|
||||
ghostscript,
|
||||
jbig2enc,
|
||||
qpdf,
|
||||
tesseract,
|
||||
check_external_program,
|
||||
@@ -602,47 +603,19 @@ def check_options_sidecar(options, log):
|
||||
options.sidecar = options.output_file + '.txt'
|
||||
|
||||
|
||||
def _optional_program_required(name, version_fn, min_version, for_argument):
|
||||
try:
|
||||
version = version_fn()
|
||||
except (FileNotFoundError, MissingDependencyError):
|
||||
raise MissingDependencyError(
|
||||
f"Install the '{name}' program to use {for_argument}."
|
||||
)
|
||||
else:
|
||||
if version < min_version:
|
||||
raise MissingDependencyError(
|
||||
f"The installed '{name}' is not supported. "
|
||||
f"Install version {min_version} or newer."
|
||||
)
|
||||
|
||||
|
||||
def _optional_program_recommended(name, version_fn, min_version, for_argument):
|
||||
try:
|
||||
version = version_fn()
|
||||
except (FileNotFoundError, MissingDependencyError):
|
||||
complain(
|
||||
f"For best results, install the optional program '{name}' to use the "
|
||||
f"argument {for_argument}."
|
||||
)
|
||||
else:
|
||||
if version < min_version:
|
||||
raise MissingDependencyError(
|
||||
f"The installed '{name}' is not supported. "
|
||||
f"Install version {min_version} or newer."
|
||||
)
|
||||
|
||||
|
||||
def check_options_preprocessing(options, log):
|
||||
if options.clean_final:
|
||||
options.clean = True
|
||||
if options.unpaper_args and not options.clean:
|
||||
raise argparse.ArgumentError(None, "--clean is required for --unpaper-args")
|
||||
if options.clean:
|
||||
from .exec import unpaper
|
||||
|
||||
_optional_program_required(
|
||||
'unpaper', unpaper.version, '6.1', '--clean, --clean-final'
|
||||
check_external_program(
|
||||
log=log,
|
||||
program='unpaper',
|
||||
package='unpaper',
|
||||
version_checker=unpaper.version,
|
||||
need_version='6.1',
|
||||
required_for=['--clean, --clean-final'],
|
||||
)
|
||||
try:
|
||||
if options.unpaper_args:
|
||||
@@ -668,19 +641,26 @@ def check_options_ocr_behavior(options, log):
|
||||
|
||||
def check_options_optimizing(options, log):
|
||||
if options.optimize >= 2:
|
||||
from .exec import pngquant, jbig2enc
|
||||
|
||||
_optional_program_required(
|
||||
'pngquant', pngquant.version, '2.0.1', '--optimize {2,3}'
|
||||
check_external_program(
|
||||
log=log,
|
||||
program='pngquant',
|
||||
package='pngquant',
|
||||
version_checker=pngquant.version,
|
||||
need_version='2.0.1',
|
||||
required_for='--optimize {2,3}',
|
||||
)
|
||||
|
||||
if options.jbig2_lossy:
|
||||
_optional_program_required('jbig2', jbig2enc.version, '0.28', '--jbig2-lossy')
|
||||
elif options.optimize >= 2:
|
||||
if options.optimize >= 2:
|
||||
# Although we use JBIG2 for optimize=1, don't nag about it unless the
|
||||
# user is asking for more optimization
|
||||
_optional_program_recommended(
|
||||
'jbig2', jbig2enc.version, '0.28', '--optimize {2,3}'
|
||||
check_external_program(
|
||||
log=log,
|
||||
program='jbig2',
|
||||
package='jbig2enc',
|
||||
version_checker=jbig2enc.version,
|
||||
need_version='0.28',
|
||||
required_for='--optimize {2,3} | --jbig2-lossy',
|
||||
recommended=True if not options.jbig2_lossy else False,
|
||||
)
|
||||
|
||||
if options.optimize == 0 and any(
|
||||
@@ -1031,7 +1011,7 @@ def report_output_file_size(options, _log, input_file, output_file):
|
||||
)
|
||||
|
||||
|
||||
def check_dependency_versions(log):
|
||||
def check_dependency_versions(options, log):
|
||||
check_external_program(
|
||||
log=log,
|
||||
program='tesseract',
|
||||
@@ -1055,27 +1035,10 @@ def check_dependency_versions(log):
|
||||
return ExitCode.missing_dependency
|
||||
check_external_program(
|
||||
log=log,
|
||||
program='unpaper',
|
||||
package='unpaper',
|
||||
version_checker=unpaper.version,
|
||||
need_version='6.1', # latest sane version
|
||||
optional=True,
|
||||
)
|
||||
if os.environ.get('TRAVIS') != 'true': # Suppress for Ubuntu trusty
|
||||
check_external_program(
|
||||
log=log,
|
||||
program='qpdf',
|
||||
package='qpdf',
|
||||
version_checker=qpdf.version,
|
||||
need_version='8.0.2',
|
||||
)
|
||||
check_external_program(
|
||||
log=log,
|
||||
program='pngquant',
|
||||
package='pngquant',
|
||||
version_checker=pngquant.version,
|
||||
need_version='2.0.0',
|
||||
optional=True,
|
||||
program='qpdf',
|
||||
package='qpdf',
|
||||
version_checker=qpdf.version,
|
||||
need_version='8.0.2',
|
||||
)
|
||||
|
||||
|
||||
@@ -1095,7 +1058,7 @@ def run_pipeline(args=None):
|
||||
)
|
||||
preamble(_log)
|
||||
check_options(options, _log)
|
||||
check_dependency_versions(_log)
|
||||
check_dependency_versions(options, _log)
|
||||
|
||||
# Any changes to options will not take effect for options that are already
|
||||
# bound to function parameters in the pipeline. (For example
|
||||
|
||||
@@ -21,7 +21,7 @@ import os
|
||||
import re
|
||||
import sys
|
||||
from subprocess import run, STDOUT, PIPE, CalledProcessError
|
||||
from ..exceptions import MissingDependencyError
|
||||
from ..exceptions import MissingDependencyError, ExitCode
|
||||
from collections.abc import Mapping
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ def get_version(program, *, version_arg='--version', regex=r'(\d+(\.\d+)*)'):
|
||||
f"Could not find program '{program}' on the PATH"
|
||||
) from e
|
||||
except CalledProcessError as e:
|
||||
if e.returncode < 0:
|
||||
if e.returncode != 0:
|
||||
raise MissingDependencyError(
|
||||
f"Ran program '{program}' but it exited with an error:\n{e.output}"
|
||||
) from e
|
||||
@@ -66,10 +66,17 @@ The program '{program}' could not be executed or was not found on your
|
||||
system PATH.
|
||||
'''
|
||||
|
||||
unknown_version = '''
|
||||
OCRmyPDF requires '{program}' {need_version} or higher. Your system has
|
||||
'{program}' but we cannot tell what version is installed. Contact the
|
||||
package maintainer.
|
||||
missing_optional_program = '''
|
||||
The program '{program}' could not be executed or was not found on your
|
||||
system PATH. This program is required when you use the
|
||||
{required_for} arguments. You could try omitting these arguments, or install
|
||||
the package.
|
||||
'''
|
||||
|
||||
missing_recommend_program = '''
|
||||
The program '{program}' could not be executed or was not found on your
|
||||
system PATH. This program is recommended when using the {required_for} arguments,
|
||||
but not required, so we will proceed. For best results, install the program.
|
||||
'''
|
||||
|
||||
old_version = '''
|
||||
@@ -77,20 +84,15 @@ OCRmyPDF requires '{program}' {need_version} or higher. Your system appears
|
||||
to have {found_version}. Please update this program.
|
||||
'''
|
||||
|
||||
okay_its_optional = '''
|
||||
This program is OPTIONAL, so installation of OCRmyPDF can proceed, but
|
||||
some functionality may be missing.
|
||||
'''
|
||||
|
||||
not_okay_its_required = '''
|
||||
This program is REQUIRED for OCRmyPDF to work. Installation will abort.
|
||||
old_version_required_for = '''
|
||||
OCRmyPDF requires '{program}' {need_version} or higher when run with the
|
||||
{required_for} arguments. If you omit these arguments, OCRmyPDF may be able to
|
||||
proceed. For best results, install the program.
|
||||
'''
|
||||
|
||||
osx_install_advice = '''
|
||||
If you have homebrew installed, try these command to install the missing
|
||||
packages:
|
||||
brew update
|
||||
brew upgrade
|
||||
package:
|
||||
brew install {package}
|
||||
'''
|
||||
|
||||
@@ -105,7 +107,7 @@ installing the RPM for {program}.
|
||||
'''
|
||||
|
||||
|
||||
def get_platform():
|
||||
def _get_platform():
|
||||
if sys.platform.startswith('freebsd'):
|
||||
return 'freebsd'
|
||||
elif sys.platform.startswith('linux'):
|
||||
@@ -113,48 +115,59 @@ def get_platform():
|
||||
return sys.platform
|
||||
|
||||
|
||||
def _error_trailer(log, program, package, optional, **kwargs):
|
||||
if optional:
|
||||
log.error(okay_its_optional.format(**locals()))
|
||||
else:
|
||||
log.error(not_okay_its_required.format(**locals()))
|
||||
|
||||
def _error_trailer(log, program, package, **kwargs):
|
||||
if isinstance(package, Mapping):
|
||||
package = package[get_platform()]
|
||||
package = package[_get_platform()]
|
||||
|
||||
if get_platform() == 'darwin':
|
||||
log.error(osx_install_advice.format(**locals()))
|
||||
elif get_platform() == 'linux':
|
||||
log.error(linux_install_advice.format(**locals()))
|
||||
if _get_platform() == 'darwin':
|
||||
log.info(osx_install_advice.format(**locals()))
|
||||
elif _get_platform() == 'linux':
|
||||
log.info(linux_install_advice.format(**locals()))
|
||||
|
||||
|
||||
def error_missing_program(log, program, package, optional):
|
||||
log.error(missing_program.format(**locals()))
|
||||
def _error_missing_program(log, program, package, required_for, recommended):
|
||||
if required_for:
|
||||
log.error(missing_optional_program.format(**locals()))
|
||||
elif recommended:
|
||||
log.info(missing_recommend_program.format(**locals()))
|
||||
else:
|
||||
log.error(missing_program.format(**locals()))
|
||||
_error_trailer(**locals())
|
||||
|
||||
|
||||
def error_unknown_version(log, program, package, optional, need_version):
|
||||
log.error(unknown_version.format(**locals()))
|
||||
_error_trailer(**locals())
|
||||
|
||||
|
||||
def error_old_version(log, program, package, optional, need_version, found_version):
|
||||
log.error(old_version.format(**locals()))
|
||||
def _error_old_version(
|
||||
log, program, package, need_version, found_version, required_for
|
||||
):
|
||||
if required_for:
|
||||
log.error(old_version_required_for.format(**locals()))
|
||||
else:
|
||||
log.error(old_version.format(**locals()))
|
||||
_error_trailer(**locals())
|
||||
|
||||
|
||||
def check_external_program(
|
||||
log, program, package, version_checker, need_version, optional=False
|
||||
*,
|
||||
log,
|
||||
program,
|
||||
package,
|
||||
version_checker,
|
||||
need_version,
|
||||
required_for=None,
|
||||
recommended=False,
|
||||
):
|
||||
try:
|
||||
found_version = version_checker()
|
||||
except (CalledProcessError, FileNotFoundError, MissingDependencyError):
|
||||
error_missing_program(log, program, package, optional)
|
||||
if not optional:
|
||||
sys.exit(1)
|
||||
_error_missing_program(log, program, package, required_for, recommended)
|
||||
if not recommended:
|
||||
sys.exit(ExitCode.missing_dependency)
|
||||
return
|
||||
|
||||
if found_version < need_version:
|
||||
error_old_version(log, program, package, optional, need_version, found_version)
|
||||
_error_old_version(
|
||||
log, program, package, need_version, found_version, required_for
|
||||
)
|
||||
if not recommended:
|
||||
sys.exit(ExitCode.missing_dependency)
|
||||
|
||||
log.debug(f'Found {program} {found_version}')
|
||||
|
||||
Reference in New Issue
Block a user