X-Git-Url: https://git.openstreetmap.org./nominatim.git/blobdiff_plain/5e477e3b5b99da6fc4e54749d4671a6fc8fdcd66..78c19bc006d5957f183968d086226be4b2b65fe3:/nominatim/cli.py diff --git a/nominatim/cli.py b/nominatim/cli.py index 8c2136f4..720a8ece 100644 --- a/nominatim/cli.py +++ b/nominatim/cli.py @@ -2,13 +2,14 @@ # # This file is part of Nominatim. (https://nominatim.org) # -# Copyright (C) 2022 by the Nominatim developer community. +# Copyright (C) 2023 by the Nominatim developer community. # For a full list of authors see the git log. """ Command-line interface to the Nominatim functions for import, update, database administration and querying. """ -from typing import Optional, Any, List, Union +from typing import Optional, Any +import importlib import logging import os import sys @@ -16,7 +17,7 @@ import argparse from pathlib import Path from nominatim.config import Configuration -from nominatim.tools.exec_utils import run_legacy_script, run_php_server +from nominatim.tools.exec_utils import run_php_server from nominatim.errors import UsageError from nominatim import clicmd from nominatim import version @@ -60,7 +61,7 @@ class CommandlineParser: def nominatim_version_text(self) -> str: """ Program name and version number as string """ - text = f'Nominatim version {version.version_str()}' + text = f'Nominatim version {version.NOMINATIM_VERSION!s}' if version.GIT_COMMIT_HASH is not None: text += f' ({version.GIT_COMMIT_HASH})' return text @@ -100,9 +101,6 @@ class CommandlineParser: self.parser.print_help() return 1 - for arg in ('module_dir', 'osm2pgsql_path', 'phplib_dir', 'sqllib_dir', - 'data_dir', 'config_dir', 'phpcgi_path'): - setattr(args, arg, Path(kwargs[arg])) args.project_dir = Path(args.project_dir).resolve() if 'cli_args' not in kwargs: @@ -111,13 +109,10 @@ class CommandlineParser: datefmt='%Y-%m-%d %H:%M:%S', level=max(4 - args.verbose, 1) * 10) - args.config = Configuration(args.project_dir, args.config_dir, + args.config = Configuration(args.project_dir, environ=kwargs.get('environ', os.environ)) - args.config.set_libdirs(module=args.module_dir, - osm2pgsql=args.osm2pgsql_path, - php=args.phplib_dir, - sql=args.sqllib_dir, - data=args.data_dir) + args.config.set_libdirs(module=kwargs['module_dir'], + osm2pgsql=kwargs['osm2pgsql_path']) log = logging.getLogger() log.warning('Using project directory: %s', str(args.project_dir)) @@ -144,68 +139,19 @@ class CommandlineParser: # # No need to document the functions each time. # pylint: disable=C0111 -class QueryExport: - """\ - Export addresses as CSV file from the database. - """ - - def add_args(self, parser: argparse.ArgumentParser) -> None: - group = parser.add_argument_group('Output arguments') - group.add_argument('--output-type', default='street', - choices=('continent', 'country', 'state', 'county', - 'city', 'suburb', 'street', 'path'), - help='Type of places to output (default: street)') - group.add_argument('--output-format', - default='street;suburb;city;county;state;country', - help=("Semicolon-separated list of address types " - "(see --output-type). Multiple ranks can be " - "merged into one column by simply using a " - "comma-separated list.")) - group.add_argument('--output-all-postcodes', action='store_true', - help=("List all postcodes for address instead of " - "just the most likely one")) - group.add_argument('--language', - help=("Preferred language for output " - "(use local name, if omitted)")) - group = parser.add_argument_group('Filter arguments') - group.add_argument('--restrict-to-country', metavar='COUNTRY_CODE', - help='Export only objects within country') - group.add_argument('--restrict-to-osm-node', metavar='ID', type=int, - help='Export only children of this OSM node') - group.add_argument('--restrict-to-osm-way', metavar='ID', type=int, - help='Export only children of this OSM way') - group.add_argument('--restrict-to-osm-relation', metavar='ID', type=int, - help='Export only children of this OSM relation') - - - def run(self, args: NominatimArgs) -> int: - params: List[Union[int, str]] = [ - '--output-type', args.output_type, - '--output-format', args.output_format] - if args.output_all_postcodes: - params.append('--output-all-postcodes') - if args.language: - params.extend(('--language', args.language)) - if args.restrict_to_country: - params.extend(('--restrict-to-country', args.restrict_to_country)) - if args.restrict_to_osm_node: - params.extend(('--restrict-to-osm-node', args.restrict_to_osm_node)) - if args.restrict_to_osm_way: - params.extend(('--restrict-to-osm-way', args.restrict_to_osm_way)) - if args.restrict_to_osm_relation: - params.extend(('--restrict-to-osm-relation', args.restrict_to_osm_relation)) - - return run_legacy_script('export.php', *params, nominatim_env=args) - - class AdminServe: """\ Start a simple web server for serving the API. - This command starts the built-in PHP webserver to serve the website + This command starts a built-in webserver to serve the website from the current project directory. This webserver is only suitable for testing and development. Do not use it in production setups! + There are different webservers available. The default 'php' engine + runs the classic PHP frontend. The other engines are Python servers + which run the new Python frontend code. This is highly experimental + at the moment and may not include the full API. + By the default, the webserver can be accessed at: http://127.0.0.1:8088 """ @@ -213,14 +159,36 @@ class AdminServe: group = parser.add_argument_group('Server arguments') group.add_argument('--server', default='127.0.0.1:8088', help='The address the server will listen to.') + group.add_argument('--engine', default='falcon', + choices=('php', 'falcon', 'starlette'), + help='Webserver framework to run. (default: falcon)') def run(self, args: NominatimArgs) -> int: - run_php_server(args.server, args.project_dir / 'website') + if args.engine == 'php': + if args.config.lib_dir.php is None: + raise UsageError("PHP frontend not configured.") + run_php_server(args.server, args.project_dir / 'website') + else: + import uvicorn # pylint: disable=import-outside-toplevel + server_info = args.server.split(':', 1) + host = server_info[0] + if len(server_info) > 1: + if not server_info[1].isdigit(): + raise UsageError('Invalid format for --server parameter. Use :') + port = int(server_info[1]) + else: + port = 8088 + + server_module = importlib.import_module(f'nominatim.server.{args.engine}.server') + + app = server_module.get_application(args.project_dir) + uvicorn.run(app, host=host, port=port) + return 0 -def get_set_parser(**kwargs: Any) -> CommandlineParser: +def get_set_parser() -> CommandlineParser: """\ Initializes the parser and adds various subcommands for nominatim cli. @@ -239,17 +207,15 @@ def get_set_parser(**kwargs: Any) -> CommandlineParser: parser.add_subcommand('admin', clicmd.AdminFuncs()) - parser.add_subcommand('export', QueryExport()) + parser.add_subcommand('export', clicmd.QueryExport()) + parser.add_subcommand('convert', clicmd.ConvertDB()) parser.add_subcommand('serve', AdminServe()) - if kwargs.get('phpcgi_path'): - parser.add_subcommand('search', clicmd.APISearch()) - parser.add_subcommand('reverse', clicmd.APIReverse()) - parser.add_subcommand('lookup', clicmd.APILookup()) - parser.add_subcommand('details', clicmd.APIDetails()) - parser.add_subcommand('status', clicmd.APIStatus()) - else: - parser.parser.epilog = 'php-cgi not found. Query commands not available.' + parser.add_subcommand('search', clicmd.APISearch()) + parser.add_subcommand('reverse', clicmd.APIReverse()) + parser.add_subcommand('lookup', clicmd.APILookup()) + parser.add_subcommand('details', clicmd.APIDetails()) + parser.add_subcommand('status', clicmd.APIStatus()) return parser @@ -259,6 +225,4 @@ def nominatim(**kwargs: Any) -> int: Command-line tools for importing, updating, administrating and querying the Nominatim database. """ - parser = get_set_parser(**kwargs) - - return parser.run(**kwargs) + return get_set_parser().run(**kwargs)