from argparse import ArgumentParser, ArgumentTypeError, Namespace from enum import Enum, auto from ...lib.log import WARNING, log from .Cmd import Cmd, Parent from .lib.pkg_relations import VersionSyntax, pkg_relations from .lib.templates import ListDict, RenderValues, tmpl_render def key_value(s): try: key, value = s.split('=', 1) except ValueError: raise ArgumentTypeError('Expected KEY=VALUE') return key, value # TODO: Put the more elaborate stuff into lib class Fmt(Enum): Pyright = auto() class CmdCreateFile(Cmd): # export def __jw_required( self, *, module: str | None = None, include_self: bool = False, ) -> list[str]: if module is None: module = self.app.args.module if module is None: raise Exception('Can\'t get required packages without module name') ret = pkg_relations( self.app, rel_type = 'requires', flavours = ['run'], subsections = ['jw'], seed_pkgs = [module], syntax = VersionSyntax.names_only, no_subpackages = True, recursive = True, quote = False, hide_self = False, hide_jw_pkg = False, ) if include_self and module not in ret: ret = [module, *ret] return ret def __render( self, template_name: str, values: list[RenderValues], li_quote = False, li_delimiter = '\n', ) -> str: return tmpl_render( template_name, values, li_quote = li_quote, li_delimiter = li_delimiter, search_path = self.app.args.search_path.split(':'), ) def render_tmpl(self, module: str, extra_fields: RenderValues) -> str: template_name = self.app.args.template_name if template_name is None: raise Exception('Can\'t render template without name') return self.__render( template_name, [extra_fields], li_quote = self.app.args.quote, li_delimiter = ',\n' ) def render_pyright(self, module: str, extra_fields: RenderValues) -> str: extra_paths = [] for m in self.__jw_required(include_self = True): path = self.app.find_dir(m, search_subdirs = ['src/python', 'tools/python']) if path is None: log(WARNING, f'No project directory for module "{m}"') continue extra_paths.append(path) values: ListDict = { 'extra_paths': extra_paths, } return self.__render( 'pyrightconfig.json', [values, extra_fields], li_quote = True, li_delimiter = ',\n' ) def __init__(self, parent: Parent) -> None: super().__init__( parent, 'create-file', help = 'Generate a file from project metadata' ) def add_arguments(self, parser: ArgumentParser) -> None: super().add_arguments(parser) parser.add_argument( '--format', help = ( 'Output format, for example: ' ', '.join([fmt.name.lower() for fmt in Fmt]) ) ) parser.add_argument( '--search-path', default = '/etc/opt/jw-pkg/templates', help = 'Template search path, colon separated', ) parser.add_argument('--template-name', help = 'Template file name') parser.add_argument( '--quote', action = 'store_true', help = 'Enclose variable values in double quotes before substituting' ) parser.add_argument( '-f', '--field', action = 'append', type = key_value, default = [], metavar = 'KEY=VALUE', help = 'Additional fields to insert into the output file', ) parser.add_argument('module', help = 'The module to generate the file for') async def _run(self, args: Namespace) -> None: method = getattr(self, 'render_' + args.format, None) if method is None: # Should be prevented by choices=[] but keeps linter happy raise Exception(f'Unsupported output format {args.format}') print(method(args.module, args.field))