import logging import os import sys from pathlib import Path from typing import Optional, Literal sys.path.append(os.path.dirname(__file__)) from common import find_module_folder, get_module_config, prompt_choices, prompt_path, prompt_yesno, run_script from common.jinja import is_jinja_installed, generate_file _PRIVATE_PATH = Path('private') _PUBLIC_PATH = Path('public') _HEADER_TEMPLATE_NAME = 'header.hpp.jinja' _SOURCE_TEMPLATE_NAME = 'source.cpp.jinja' _HEADER_CHOICES = { 'public': _PUBLIC_PATH, 'private': _PRIVATE_PATH, 'no': None } _logger = logging.getLogger(__name__) _header_path: Optional[Path] = None _source_path: Optional[Path] = None _namespace: str def verify_tools() -> None: success = True if not is_jinja_installed(): _logger.error('Python module Jinja2 is not installed.') success = False if not success: raise RuntimeError('one or more required tools could not be found') def _make_header_path(header_folder: Path, base_path: Path) -> Path: return header_folder / base_path.with_suffix('.hpp') def _make_source_path(base_path: Path) -> Path: return _PRIVATE_PATH / base_path.with_suffix('.cpp') def _apply_params(header_folder: Path, do_create_source: bool, base_path: Path) -> None: global _header_path, _source_path, _namespace source_path = _make_source_path(base_path) module_folder = find_module_folder(source_path) namespace = None if module_folder is not None: module_subfolder = module_folder.relative_to(_PRIVATE_PATH) module_key = str(module_subfolder) if os.path.sep != '/': module_key = module_key.replace(os.pathsep, '/') all_module_conf = get_module_config() module_conf = all_module_conf.get(module_key) if module_conf is not None: namespace = module_conf.get('cxx_namespace') if namespace is None: namespace = module_key.replace('/', '_') if namespace is None: namespace = base_path.parts[0] _namespace = namespace if header_folder is not None: _header_path = _make_header_path(header_folder, base_path) if do_create_source: _source_path = source_path def query_params() -> None: header_folder = prompt_choices('Create Header?', _HEADER_CHOICES) do_create_source = prompt_yesno('Create source?') if header_folder is None and not do_create_source: raise RuntimeError('Neither header nor source selected for creation.') def _validate_path(path: Path) -> bool: result = True if header_folder is not None: header_path = _make_header_path(header_folder, path) if header_path.exists(): print(f'Header file {header_path} already exists.') result = False if do_create_source: source_path = _make_source_path(path) if source_path.exists(): print(f'Source file {source_path} already exists.') result = False return result input_path = prompt_path('Enter basename for the source (relative to public/private folder, no file extension).', allow_slash=True, validator=_validate_path) _apply_params(header_folder, do_create_source, input_path) def create_header() -> None: if _header_path is None: return _logger.info('Generating header at %s.', str(_header_path)) guard = '_'.join((*_header_path.parts[1:], 'INCLUDED')).upper().replace('.', '_') generate_file(_HEADER_TEMPLATE_NAME, _header_path, { 'guard': guard, 'namespace': _namespace }) def create_source() -> None: if _source_path is None: return _logger.info('Generating source at %s.', str(_source_path)) generate_file(_SOURCE_TEMPLATE_NAME, _source_path, { 'header_path': '/'.join(_header_path.parts[1:]) if _header_path else None, 'namespace': _namespace }) def _run() -> None: create_header() create_source() def run_new_source(header: Literal['private', 'public', 'no'], source: bool, path: Path) -> None: _apply_params(_HEADER_CHOICES[header], source, path) _run() def script_main() -> None: verify_tools() query_params() _run() if __name__ == '__main__': run_script(script_main)