from typing import TYPE_CHECKING
if TYPE_CHECKING:
from render import Render
try:
from .error import RenderError
from .formatter import escape_dollar
from .validations import valid_octal_mode_or_raise, valid_fs_path_or_raise
except ImportError:
from error import RenderError
from formatter import escape_dollar
from validations import valid_octal_mode_or_raise, valid_fs_path_or_raise
class Configs:
def __init__(self, render_instance: "Render"):
self._render_instance = render_instance
self._configs: dict[str, dict] = {}
def add(self, name: str, data: str):
if not isinstance(data, str):
raise RenderError(f"Expected [data] to be a string, got [{type(data)}]")
if data == "":
raise RenderError(f"Expected [data] to be non-empty for config [{name}]")
if name not in self._configs:
self._configs[name] = {"name": name, "data": data}
return
if data == self._configs[name]["data"]:
return
raise RenderError(f"Config [{name}] already added with different data")
def has_configs(self):
return bool(self._configs)
def render(self):
return {
c["name"]: {"content": escape_dollar(c["data"])}
for c in sorted(self._configs.values(), key=lambda c: c["name"])
}
class ContainerConfigs:
def __init__(self, render_instance: "Render", configs: Configs):
self._render_instance = render_instance
self.top_level_configs: Configs = configs
self.container_configs: set[ContainerConfig] = set()
def add(self, name: str, data: str, target: str, mode: str = ""):
self.top_level_configs.add(name, data)
if target == "":
raise RenderError(f"Expected [target] to be set for config [{name}]")
if mode != "":
mode = valid_octal_mode_or_raise(mode)
if target in [c.target for c in self.container_configs]:
raise RenderError(f"Target [{target}] already used for another config")
target = valid_fs_path_or_raise(target)
self.container_configs.add(ContainerConfig(self._render_instance, name, target, mode))
def has_configs(self):
return bool(self.container_configs)
def render(self):
return [c.render() for c in sorted(self.container_configs, key=lambda c: c.source)]
class ContainerConfig:
def __init__(self, render_instance: "Render", source: str, target: str, mode: str):
self._render_instance = render_instance
self.source = source
self.target = target
self.mode = mode
def render(self):
result: dict[str, str | int] = {
"source": self.source,
"target": self.target,
}
if self.mode:
result["mode"] = int(self.mode, 8)
return result