Passed
Pull Request — master (#559)
by Konstantin
02:08
created

ocrd.cli.resmgr   A

Complexity

Total Complexity 37

Size/Duplication

Total Lines 141
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 37
eloc 109
dl 0
loc 141
rs 9.44
c 0
b 0
f 0

5 Functions

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