| 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 |  |  |  |