1 # SPDX-License-Identifier: GPL-2.0-only
 
   3 # This file is part of Nominatim. (https://nominatim.org)
 
   5 # Copyright (C) 2022 by the Nominatim developer community.
 
   6 # For a full list of authors see the git log.
 
   8 Provides custom functions over command-line arguments.
 
  10 from typing import Optional, List, Dict, Any, Sequence, Tuple
 
  13 from functools import reduce
 
  14 from pathlib import Path
 
  16 from nominatim.errors import UsageError
 
  17 from nominatim.config import Configuration
 
  18 from nominatim.typing import Protocol
 
  19 import nominatim.api as napi
 
  21 LOG = logging.getLogger()
 
  23 class Subcommand(Protocol):
 
  25     Interface to be implemented by classes implementing a CLI subcommand.
 
  28     def add_args(self, parser: argparse.ArgumentParser) -> None:
 
  30         Fill the given parser for the subcommand with the appropriate
 
  34     def run(self, args: 'NominatimArgs') -> int:
 
  36         Run the subcommand with the given parsed arguments.
 
  41     """ Customized namespace class for the nominatim command line tool
 
  42         to receive the command-line arguments.
 
  44     # Basic environment set by root program.
 
  50     subcommand: Optional[str]
 
  54     osm2pgsql_cache: Optional[int]
 
  57     # Arguments added to all subcommands.
 
  59     threads: Optional[int]
 
  61     # Arguments to 'add-data'
 
  66     relation: Optional[int]
 
  67     tiger_data: Optional[str]
 
  70     # Arguments to 'admin'
 
  75     analyse_indexing: bool
 
  78     place_id: Optional[int]
 
  80     # Arguments to 'import'
 
  82     continue_at: Optional[str]
 
  90     # Arguments to 'index'
 
  96     # Arguments to 'export'
 
  99     output_all_postcodes: bool
 
 100     language: Optional[str]
 
 101     restrict_to_country: Optional[str]
 
 103     # Arguments to 'refresh'
 
 110     secondary_importance: bool
 
 114     enable_debug_statements: bool
 
 115     data_object: Sequence[Tuple[str, int]]
 
 116     data_area: Sequence[Tuple[str, int]]
 
 118     # Arguments to 'replication'
 
 120     update_functions: bool
 
 121     check_for_updates: bool
 
 126     # Arguments to 'serve'
 
 130     # Arguments to 'special-phrases
 
 131     import_from_wiki: bool
 
 132     import_from_csv: Optional[str]
 
 135     # Arguments to all query functions
 
 141     polygon_output: Optional[str]
 
 142     polygon_threshold: Optional[float]
 
 144     # Arguments to 'search'
 
 146     amenity: Optional[str]
 
 147     street: Optional[str]
 
 149     county: Optional[str]
 
 151     country: Optional[str]
 
 152     postalcode: Optional[str]
 
 153     countrycodes: Optional[str]
 
 154     exclude_place_ids: Optional[str]
 
 156     viewbox: Optional[str]
 
 160     # Arguments to 'reverse'
 
 164     layers: Optional[Sequence[str]]
 
 166     # Arguments to 'lookup'
 
 169     # Arguments to 'details'
 
 170     object_class: Optional[str]
 
 174     polygon_geojson: bool
 
 175     group_hierarchy: bool
 
 178     def osm2pgsql_options(self, default_cache: int,
 
 179                           default_threads: int) -> Dict[str, Any]:
 
 180         """ Return the standard osm2pgsql options that can be derived
 
 181             from the command line arguments. The resulting dict can be
 
 182             further customized and then used in `run_osm2pgsql()`.
 
 184         return dict(osm2pgsql=self.config.OSM2PGSQL_BINARY or self.config.lib_dir.osm2pgsql,
 
 185                     osm2pgsql_cache=self.osm2pgsql_cache or default_cache,
 
 186                     osm2pgsql_style=self.config.get_import_style_file(),
 
 187                     osm2pgsql_style_path=self.config.config_dir,
 
 188                     threads=self.threads or default_threads,
 
 189                     dsn=self.config.get_libpq_dsn(),
 
 190                     flatnode_file=str(self.config.get_path('FLATNODE_FILE') or ''),
 
 191                     tablespaces=dict(slim_data=self.config.TABLESPACE_OSM_DATA,
 
 192                                      slim_index=self.config.TABLESPACE_OSM_INDEX,
 
 193                                      main_data=self.config.TABLESPACE_PLACE_DATA,
 
 194                                      main_index=self.config.TABLESPACE_PLACE_INDEX
 
 199     def get_osm_file_list(self) -> Optional[List[Path]]:
 
 200         """ Return the --osm-file argument as a list of Paths or None
 
 201             if no argument was given. The function also checks if the files
 
 202             exist and raises a UsageError if one cannot be found.
 
 204         if not self.osm_file:
 
 207         files = [Path(f) for f in self.osm_file]
 
 209             if not fname.is_file():
 
 210                 LOG.fatal("OSM file '%s' does not exist.", fname)
 
 211                 raise UsageError('Cannot access file.')
 
 216     def get_geometry_output(self) -> napi.GeometryFormat:
 
 217         """ Get the requested geometry output format in a API-compatible
 
 220         if not self.polygon_output:
 
 221             return napi.GeometryFormat.NONE
 
 222         if self.polygon_output == 'geojson':
 
 223             return napi.GeometryFormat.GEOJSON
 
 224         if self.polygon_output == 'kml':
 
 225             return napi.GeometryFormat.KML
 
 226         if self.polygon_output == 'svg':
 
 227             return napi.GeometryFormat.SVG
 
 228         if self.polygon_output == 'text':
 
 229             return napi.GeometryFormat.TEXT
 
 232             return napi.GeometryFormat[self.polygon_output.upper()]
 
 233         except KeyError as exp:
 
 234             raise UsageError(f"Unknown polygon output format '{self.polygon_output}'.") from exp
 
 237     def get_locales(self, default: Optional[str]) -> napi.Locales:
 
 238         """ Get the locales from the language parameter.
 
 241             return napi.Locales.from_accept_languages(self.lang)
 
 243             return napi.Locales.from_accept_languages(default)
 
 245         return napi.Locales()
 
 248     def get_layers(self, default: napi.DataLayer) -> Optional[napi.DataLayer]:
 
 249         """ Get the list of selected layers as a DataLayer enum.
 
 254         return reduce(napi.DataLayer.__or__,
 
 255                       (napi.DataLayer[s.upper()] for s in self.layers))