jw-pkg/src/python/jw/pkg/cmds/projects/CmdCreateFile.py
Jan Lindemann 01be594103
cmds.projects.CmdCreateFile: Support --search-path

Add --search-path to the list of CmdCreateFile's supported options. Its value is split by ":" and subsequently passed to the tmpl_render()'s search_path argument.

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-06-09 07:46:27 +02:00

118 lines
3.7 KiB
Python

from argparse import ArgumentParser, ArgumentTypeError, Namespace
from enum import Enum, auto
from typing import Iterable, TypeAlias
from ...lib.log import WARNING, log
from .Cmd import Cmd, Parent
from .lib.pkg_relations import VersionSyntax, pkg_relations
from .lib.templates import 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()
TupleList: TypeAlias = Iterable[tuple[str, str]]
ListDict: TypeAlias = dict[str, list[str]]
class CmdCreateFile(Cmd): # export
def __tuple_list_to_dict(self, src: TupleList) -> ListDict:
ret: ListDict = {}
for key, val in src:
entry = ret.setdefault(key, [])
entry.append(val)
return ret
def __update_dict(self, dst: ListDict, src: TupleList) -> ListDict:
ret = dst
for key, val in src:
entry = ret.setdefault(key, [])
entry.append(val)
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_pyright(self, module: str, extra_fields: TupleList) -> str:
prereq = 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,
)
extra_paths = []
for m in prereq:
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,
}
self.__update_dict(values, extra_fields)
return self.__render(
'pyrightconfig.json', [values], 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',
choices = [fmt.name.lower() for fmt in Fmt],
help = 'Output format'
)
parser.add_argument(
'--search-path',
default = '/etc/opt/jw-pkg/templates',
help = 'Template search path, colon separated',
)
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))