diff --git a/src/python/jw/pkg/cmds/projects/lib/templates.py b/src/python/jw/pkg/cmds/projects/lib/templates.py index 3df12aa5..ad55af2f 100644 --- a/src/python/jw/pkg/cmds/projects/lib/templates.py +++ b/src/python/jw/pkg/cmds/projects/lib/templates.py @@ -1,3 +1,4 @@ +import re import textwrap from typing import Any, Iterable, TypeAlias, TypeGuard @@ -7,7 +8,7 @@ ListDict: TypeAlias = dict[str, list[str]] StrDict: TypeAlias = dict[str, str] RenderValues: TypeAlias = ListDict | StrDict | TupleList -def is_str_dict(values: RenderValues) -> TypeGuard[StrDict]: +def is_str_dict(values: object) -> TypeGuard[StrDict]: if not isinstance(values, dict): return False for key, val in values.items(): @@ -17,7 +18,7 @@ def is_str_dict(values: RenderValues) -> TypeGuard[StrDict]: return False return True -def is_list_dict(values: RenderValues) -> TypeGuard[ListDict]: +def is_list_dict(values: object) -> TypeGuard[ListDict]: if not isinstance(values, dict): return False for key, val in values.items(): @@ -32,7 +33,7 @@ def is_list_dict(values: RenderValues) -> TypeGuard[ListDict]: return False return True -def is_tuple_list(values: RenderValues) -> TypeGuard[TupleList]: +def is_tuple_list(values: object) -> TypeGuard[TupleList]: if not isinstance(values, list): return False for item in values: @@ -46,7 +47,7 @@ def is_tuple_list(values: RenderValues) -> TypeGuard[TupleList]: return False return True -def render_values_to_list_dict(values: RenderValues) -> ListDict: +def render_values_to_list_dict(values: object) -> ListDict: def __tuple_list_to_dict(src: TupleList) -> ListDict: ret: ListDict = {} @@ -56,7 +57,12 @@ def render_values_to_list_dict(values: RenderValues) -> ListDict: return ret if is_list_dict(values): - return values + ret: ListDict = {} + for key, val in values.items(): + # -- A string value is treated as a list with a single element; + # merging it unconverted would split it into characters + ret[key] = val if isinstance(val, list) else [val] + return ret if is_tuple_list(values): return __tuple_list_to_dict(values) raise Exception('Unsupported template value layout') @@ -90,12 +96,17 @@ def format_list_dict( parts = template.splitlines(keepends = True) for line in parts: - for key, value in fmt_dict.items(): - marker = '{' + key + '}' - if marker in line: - indent = line[:line.index(marker)] - value = str(value).replace('\n', '\n' + indent) - line = line.replace(marker, value) + for key, val in fmt_dict.items(): + # -- A marker preceded by '$' or '{' is literal text rather + # than a placeholder, so that e.g. ${prefix} survives as a + # pkg-config variable reference + rx = re.compile(r'(?