aboutsummaryrefslogtreecommitdiff
path: root/tools/cru-py/cru/template.py
diff options
context:
space:
mode:
Diffstat (limited to 'tools/cru-py/cru/template.py')
-rw-r--r--tools/cru-py/cru/template.py207
1 files changed, 0 insertions, 207 deletions
diff --git a/tools/cru-py/cru/template.py b/tools/cru-py/cru/template.py
deleted file mode 100644
index 35d68ac..0000000
--- a/tools/cru-py/cru/template.py
+++ /dev/null
@@ -1,207 +0,0 @@
-from abc import ABCMeta, abstractmethod
-from collections.abc import Callable, Mapping
-from pathlib import Path
-from string import Template
-from typing import Generic, TypeVar
-
-from ._iter import CruIterator
-from ._error import CruException
-
-from .parsing import StrWrapperVarParser
-
-
-class CruTemplateError(CruException):
- pass
-
-
-class CruTemplateBase(metaclass=ABCMeta):
- def __init__(self, text: str):
- self._text = text
- self._variables: set[str] | None = None
-
- @abstractmethod
- def _get_variables(self) -> set[str]:
- raise NotImplementedError()
-
- @property
- def text(self) -> str:
- return self._text
-
- @property
- def variables(self) -> set[str]:
- if self._variables is None:
- self._variables = self._get_variables()
- return self._variables
-
- @property
- def variable_count(self) -> int:
- return len(self.variables)
-
- @property
- def has_variables(self) -> bool:
- return self.variable_count > 0
-
- @abstractmethod
- def _do_generate(self, mapping: dict[str, str]) -> str:
- raise NotImplementedError()
-
- def generate(self, mapping: Mapping[str, str], allow_extra: bool = True) -> str:
- values = dict(mapping)
- if not self.variables <= set(values.keys()):
- raise CruTemplateError("Missing variables.")
- if not allow_extra and not set(values.keys()) <= self.variables:
- raise CruTemplateError("Extra variables.")
- return self._do_generate(values)
-
-
-class CruTemplate(CruTemplateBase):
- def __init__(self, prefix: str, text: str):
- super().__init__(text)
- self._prefix = prefix
- self._template = Template(text)
-
- def _get_variables(self) -> set[str]:
- return (
- CruIterator(self._template.get_identifiers())
- .filter(lambda i: i.startswith(self.prefix))
- .to_set()
- )
-
- @property
- def prefix(self) -> str:
- return self._prefix
-
- @property
- def py_template(self) -> Template:
- return self._template
-
- @property
- def all_variables(self) -> set[str]:
- return set(self._template.get_identifiers())
-
- def _do_generate(self, mapping: dict[str, str]) -> str:
- return self._template.safe_substitute(mapping)
-
-
-class CruStrWrapperTemplate(CruTemplateBase):
- def __init__(self, text: str, wrapper: str = "@@"):
- super().__init__(text)
- self._wrapper = wrapper
- self._tokens: StrWrapperVarParser.Result
-
- @property
- def wrapper(self) -> str:
- return self._wrapper
-
- def _get_variables(self):
- self._tokens = StrWrapperVarParser(self.wrapper).parse(self.text)
- return (
- self._tokens.cru_iter()
- .filter(lambda t: t.is_var)
- .map(lambda t: t.value)
- .to_set()
- )
-
- def _do_generate(self, mapping):
- return (
- self._tokens.cru_iter()
- .map(lambda t: mapping[t.value] if t.is_var else t.value)
- .join_str("")
- )
-
-
-_Template = TypeVar("_Template", bound=CruTemplateBase)
-
-
-class TemplateTree(Generic[_Template]):
- def __init__(
- self,
- template_generator: Callable[[str], _Template],
- source: str,
- *,
- template_file_suffix: str | None = ".template",
- ):
- """
- If template_file_suffix is not None, the files will be checked according to the
- suffix of the file name. If the suffix matches, the file will be regarded as a
- template file. Otherwise, it will be regarded as a non-template file.
- Content of template file must contain variables that need to be replaced, while
- content of non-template file may not contain any variables.
- If either case is false, it generally means whether the file is a template is
- wrongly handled.
- """
- self._template_generator = template_generator
- self._files: list[tuple[Path, _Template]] = []
- self._source = source
- self._template_file_suffix = template_file_suffix
- self._load()
-
- @property
- def templates(self) -> list[tuple[Path, _Template]]:
- return self._files
-
- @property
- def source(self) -> str:
- return self._source
-
- @property
- def template_file_suffix(self) -> str | None:
- return self._template_file_suffix
-
- @staticmethod
- def _scan_files(root: str) -> list[Path]:
- root_path = Path(root)
- result: list[Path] = []
- for path in root_path.glob("**/*"):
- if not path.is_file():
- continue
- path = path.relative_to(root_path)
- result.append(Path(path))
- return result
-
- def _load(self) -> None:
- files = self._scan_files(self.source)
- for file_path in files:
- template_file = Path(self.source) / file_path
- with open(template_file, "r") as f:
- content = f.read()
- template = self._template_generator(content)
- if self.template_file_suffix is not None:
- should_be_template = file_path.name.endswith(self.template_file_suffix)
- if should_be_template and not template.has_variables:
- raise CruTemplateError(
- f"Template file {file_path} has no variables."
- )
- elif not should_be_template and template.has_variables:
- raise CruTemplateError(f"Non-template {file_path} has variables.")
- self._files.append((file_path, template))
-
- @property
- def variables(self) -> set[str]:
- s = set()
- for _, template in self.templates:
- s.update(template.variables)
- return s
-
- def generate(self, variables: Mapping[str, str]) -> list[tuple[Path, str]]:
- result: list[tuple[Path, str]] = []
- for path, template in self.templates:
- if self.template_file_suffix is not None and path.name.endswith(
- self.template_file_suffix
- ):
- path = path.parent / (path.name[: -len(self.template_file_suffix)])
-
- text = template.generate(variables)
- result.append((path, text))
- return result
-
- def generate_to(
- self, destination: str, variables: Mapping[str, str], dry_run: bool
- ) -> None:
- generated = self.generate(variables)
- if not dry_run:
- for path, text in generated:
- des = Path(destination) / path
- des.parent.mkdir(parents=True, exist_ok=True)
- with open(des, "w") as f:
- f.write(text)