diff --git a/flamingo/services/alias_engine.py b/flamingo/services/alias_engine.py index 21fc20e..c9a147d 100644 --- a/flamingo/services/alias_engine.py +++ b/flamingo/services/alias_engine.py @@ -1,4 +1,6 @@ import logging +import re +from dataclasses import field, dataclass from typing import Generator, Any, Tuple from sanic_rest.exceptions import ValidationError @@ -8,17 +10,50 @@ logger = logging.getLogger() +ALIAS_REGEX = r"\${(?P.*)}" + + +@dataclass +class ReplacementEngine: + replacements: KeyValue = field(default_factory=dict) + + def add(self, items: KeyValue): + for k, v in items.items(): + if AliasEngine.is_virtual(value=v): + continue + self.replacements[k] = v + + def get(self, value): + return self.replacements[value] + + def replace(self, virtual_value): + alias_to = re.match(ALIAS_REGEX, virtual_value).group('alias_to') + + try: + replace_with = self.replacements[alias_to] + except KeyError as e: + raise ValidationError(f"Could not find the referenced env var for {virtual_value.as_kv}") from e + + return re.sub(ALIAS_REGEX, replace_with, virtual_value) + + class AliasEngine: - def __init__(self, items: KeyValue, replacements: KeyValue = None): + def __init__(self, items: KeyValue, replacements: ReplacementEngine = None): super().__init__() self._concrete: KeyValue = dict() self._virtual: KeyValue = dict() - self._replacements: KeyValue = replacements or items + + if not replacements: + replacements = ReplacementEngine() + replacements.add(items=items) + self._replacements = replacements self.extend(items) - def is_virtual(self, value): - return False # TODO We need an use case for this, the syntax must not be defined too + @classmethod + def is_virtual(cls, value): + matches = re.match(ALIAS_REGEX, str(value)) + return bool(matches) def append(self, key: str, value: Any) -> None: container = self._virtual if self.is_virtual(value) else self._concrete @@ -33,14 +68,4 @@ def extend(self, items: KeyValue) -> None: def items(self) -> Generator[Tuple[str, Any], None, None]: yield from self._concrete.items() for key, virtual_value in self._virtual.items(): - yield key, self._to_concrete(virtual_value=virtual_value) - - def _to_concrete(self, virtual_value) -> Any: - alias_to = virtual_value[1:] - - try: - value = self._replacements[alias_to] - except KeyError as e: - raise ValidationError(f"Could not find the referenced env var for {virtual_value.as_kv}") from e - - return value + yield key, self._replacements.replace(virtual_value=virtual_value) diff --git a/flamingo/services/builders.py b/flamingo/services/builders.py index d2aadd8..134b47c 100644 --- a/flamingo/services/builders.py +++ b/flamingo/services/builders.py @@ -6,15 +6,13 @@ from gcp_pilot.build import CloudBuild, Substitutions from gcp_pilot.exceptions import NotFound from gcp_pilot.run import CloudRun -from gcp_pilot.dns import CloudDNS, RecordType from google.cloud.devtools import cloudbuild_v1 -import settings from models.app import App from models.base import KeyValue from models.buildpack import Target from models.schedule import ScheduledInvocation -from services.alias_engine import AliasEngine +from services.alias_engine import AliasEngine, ReplacementEngine logger = logging.getLogger() @@ -63,10 +61,10 @@ def _get_env_and_build_args(self) -> Tuple[KeyValue, KeyValue]: all_env_vars = {var.key: var.value for var in self.app.get_all_env_vars()} all_build_args = self.app.get_all_build_args() - replacements = dict() - replacements.update(self._setup_params) - replacements.update(all_env_vars) - replacements.update(all_build_args) + replacements = ReplacementEngine() + replacements.add(items=self._setup_params) + replacements.add(items=all_env_vars) + replacements.add(items=all_build_args) env_var_engine = AliasEngine( items=all_env_vars,