jw-pkg/src/python/jw/pkg/cmds/projects/CmdCreateFile.py
Jan Lindemann 60bd4b461b
cmds.projects.CmdCreateFile: Add self to extra_paths
pyrightconfig.json as generated by CmdCreateFile, doesn't contain the
repository's own Python source location in "extra_paths", fix that.

Signed-off-by: Jan Lindemann <jan@janware.com>
2026-07-22 12:01:29 +02:00

131 lines
4.3 KiB
Python

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))