Passed
Pull Request — master (#800)
by Konstantin
02:21
created

ocrd.cli.resmgr.discover()   A

Complexity

Conditions 2

Size

Total Lines 8
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 8
dl 0
loc 8
rs 10
c 0
b 0
f 0
cc 2
nop 2
1
"""
2
OCR-D CLI: management of processor resources
3
4
.. click:: ocrd.cli.resmgr:resmgr_cli
5
    :prog: ocrd resmgr
6
    :nested: full
7
"""
8
import sys
9
from os import environ
10
from pathlib import Path
11
from distutils.spawn import find_executable as which
12
13
import requests
14
import click
15
16
from ocrd_utils import (
17
    initLogging,
18
    getLogger,
19
    RESOURCE_LOCATIONS
20
)
21
22
from ..resource_manager import OcrdResourceManager
23
24
def print_resources(executable, reslist, resmgr):
25
    print('%s' % executable)
26
    for resdict in reslist:
27
        print('- %s %s (%s)\n  %s' % (
28
            resdict['name'],
29
            '@ %s' % resmgr.resource_dir_to_location(resdict['path']) if 'path' in resdict else '',
30
            resdict['url'],
31
            resdict['description']
32
        ))
33
    print()
34
35
@click.group("resmgr")
36
def resmgr_cli():
37
    """
38
    Managing processor resources
39
    """
40
    initLogging()
41
42
@resmgr_cli.command('discover')
43
@click.option('-e', '--executable', 'glob', default='ocrd-*', help="Glob pattern for executables to inspect")
44
@click.option('-n', '--dry-run', is_flag=True, default=False, help="Do not save to user resource_list.yml")
45
def discover(glob, dry_run):
46
    resmgr = OcrdResourceManager()
47
    ocrd_processors = []
48
    for executable, reslist in resmgr.discover(glob=glob, dry_run=dry_run):
49
        print_resources(executable, reslist, resmgr)
50
51
@resmgr_cli.command('list-available')
52
@click.option('-e', '--executable', help='Show only resources for executable EXEC', metavar='EXEC')
53
def list_available(executable=None):
54
    """
55
    List available resources
56
    """
57
    resmgr = OcrdResourceManager()
58
    for executable, reslist in resmgr.list_available(executable):
59
        print_resources(executable, reslist, resmgr)
60
61
@resmgr_cli.command('list-installed')
62
@click.option('-e', '--executable', help='Show only resources for executable EXEC', metavar='EXEC')
63
def list_installed(executable=None):
64
    """
65
    List installed resources
66
    """
67
    resmgr = OcrdResourceManager()
68
    ret = []
69
    for executable, reslist in resmgr.list_installed(executable):
70
        print_resources(executable, reslist, resmgr)
71
72
@resmgr_cli.command('download')
73
@click.option('-n', '--any-url', help='Allow downloading/copying unregistered resources', is_flag=True)
74
@click.option('-a', '--allow-uninstalled', help="Allow installing resources for uninstalled processors", is_flag=True)
75
@click.option('-o', '--overwrite', help='Overwrite existing resources', is_flag=True)
76
@click.option('-l', '--location', help='Where to store resources', type=click.Choice(RESOURCE_LOCATIONS), default='data', show_default=True)
77
@click.argument('executable', required=True)
78
@click.argument('url_or_name', required=False)
79
def download(any_url, allow_uninstalled, overwrite, location, executable, url_or_name):
80
    """
81
    Download resource URL_OR_NAME for processor EXECUTABLE.
82
83
    URL_OR_NAME can either be the ``name`` or ``url`` of a registered resource.
84
85
    If URL_OR_NAME is '*' (asterisk), download all known resources for this processor
86
87
    If ``--any-url`` is given, also accepts URL or filenames of non-registered resources for ``URL_OR_NAME``.
88
    """
89
    log = getLogger('ocrd.cli.resmgr')
90
    resmgr = OcrdResourceManager()
91
    basedir = resmgr.location_to_resource_dir(location)
92
    if executable != '*' and not url_or_name:
93
        log.error("Unless EXECUTABLE ('%s') is the '*' wildcard, URL_OR_NAME is required" % executable)
94
        sys.exit(1)
95
    elif executable == '*':
96
        executable = None
97
    is_url = (url_or_name.startswith('https://') or url_or_name.startswith('http://')) if url_or_name else False
98
    is_filename = Path(url_or_name).exists() if url_or_name else False
99
    if executable and not which(executable):
100
        if not allow_uninstalled:
101
            log.error("Executable %s is not installed. Is there a typo in the executable? " \
102
                "To install resources for uninstalled processor, use the -a/--allow-uninstalled flag" % executable)
103
            sys.exit(1)
104
        else:
105
            log.warning("Executable %s is not installed but -a/--allow-uninstalled was given, so proceeding" % executable)
106
    find_kwargs = {'executable': executable}
107
    if url_or_name and url_or_name != '*':
108
        find_kwargs['url' if is_url else 'name'] = url_or_name
109
    reslist = resmgr.find_resources(**find_kwargs)
110
    if not reslist:
111
        log.info("No resources found in registry")
112
        if any_url and (is_url or is_filename):
113
            log.info("%s unregistered resource %s" % ("Downloading" if is_url else "Copying", url_or_name))
114
            if is_url:
115
                with requests.get(url_or_name, stream=True) as r:
116
                    content_length = int(r.headers.get('content-length'))
117
            else:
118
                url_or_name = str(Path(url_or_name).resolve())
119
                content_length = Path(url_or_name).stat().st_size
120
            with click.progressbar(length=content_length, label="Downloading" if is_url else "Copying") as bar:
121
                fpath = resmgr.download(
122
                    executable,
123
                    url_or_name,
124
                    overwrite=overwrite,
125
                    basedir=basedir,
126
                    no_subdir=location == 'cwd',
127
                    progress_cb=lambda delta: bar.update(delta))
128
            log.info("%s resource '%s' (%s) not a known resource, creating stub in %s'" % (executable, fpath.name, url_or_name, resmgr.user_list))
129
            resmgr.add_to_user_database(executable, fpath, url_or_name)
130
            log.info("%s %s to %s" % ("Downloaded" if is_url else "Copied", url_or_name, fpath))
131
            log.info("Use in parameters as '%s'" % fpath.name)
132
        else:
133
            sys.exit(1)
134
    else:
135
        for executable, resdict in reslist:
136
            if not allow_uninstalled and not which(executable):
137
                log.info("Skipping installing resources for %s as it is not installed. (Use -a/--allow-uninstalled to force)")
138
                continue
139
            if resdict['url'] == '???':
140
                log.info("Cannot download user resource %s" % (resdict['name'])),
141
                continue
142
            log.info("Downloading resource %s" % resdict)
143
            with click.progressbar(length=resdict['size']) as bar:
144
                fpath = resmgr.download(
145
                    executable,
146
                    resdict['url'],
147
                    name=resdict['name'],
148
                    resource_type=resdict['type'],
149
                    path_in_archive=resdict.get('path_in_archive', '.'),
150
                    overwrite=overwrite,
151
                    size=resdict['size'],
152
                    no_subdir=location == 'cwd',
153
                    basedir=basedir,
154
                    progress_cb=lambda delta: bar.update(delta)
155
                )
156
            log.info("Downloaded %s to %s" % (resdict['url'], fpath))
157
            log.info("Use in parameters as '%s'" % resmgr.parameter_usage(resdict['name'], usage=resdict['parameter_usage']))
158
159