|
4 | 4 | import datetime as dt |
5 | 5 | import json |
6 | 6 | import logging |
| 7 | +import os |
7 | 8 | import pathlib |
| 9 | +import re |
8 | 10 |
|
9 | 11 | import pydantic |
10 | 12 | import rich |
|
16 | 18 |
|
17 | 19 | _LOG = logging.getLogger(__name__) |
18 | 20 |
|
| 21 | +RE_ENVVAR_STRUCTURE = re.compile(r"\$\{\{\s*env\.(?P<envvar>[A-Za-z0-9_]+)\s*\}\}", flags=re.MULTILINE) |
| 22 | +"""Variable structure looks like ${{ env.MY_VAR_NAME }} and can be inline with other text.""" |
| 23 | + |
19 | 24 |
|
20 | 25 | def is_allowed_object( |
21 | 26 | metadata_object: _types.APIResult, |
@@ -197,6 +202,43 @@ def checkpoint( |
197 | 202 |
|
198 | 203 | def disambiguate(self, tml: _types.TMLObject, delete_unmapped_guids: bool = True) -> _types.TMLObject: |
199 | 204 | """Disambiguate an incoming TML object.""" |
| 205 | + # ADDITIONAL MAPPING NEEDS TO COME FIRST, IN CASE WE DELETE A GUID DURING DISAMBIGUATION. |
| 206 | + if self.additional_mapping: |
| 207 | + try: |
| 208 | + text = original = tml.dumps(format_type="YAML") |
| 209 | + |
| 210 | + for to_find, to_replace in self.additional_mapping.items(): |
| 211 | + # PRE-PROCESS TO FETCH ENVIRONMENT VARIABLES, WITH FALLBACK TO THE ORIGINAL VALUE. |
| 212 | + if match := RE_ENVVAR_STRUCTURE.search(to_replace): |
| 213 | + # the whole matched string ............... ${{ env.MY_VAR_NAME }} |
| 214 | + envvar_template = match.group(0) |
| 215 | + # just the value name .................... MY_VAR_NAME |
| 216 | + envvar_name = match.group("envvar") |
| 217 | + # fetch the value from os.environ ........ anything~ |
| 218 | + envvar_value = os.getenv(envvar_name, envvar_template) |
| 219 | + |
| 220 | + to_replace = to_replace.replace(envvar_template, envvar_value) |
| 221 | + |
| 222 | + # PERFORM STRING REPLACEMENTS VIA EXACT MATCH (case sensitive) |
| 223 | + if to_find in text: |
| 224 | + _LOG.info(f"Replacing '{to_find}' with '{to_replace}' in {tml.name} ({tml.tml_type_name})") |
| 225 | + text = text.replace(to_find, to_replace) |
| 226 | + |
| 227 | + if text != original: |
| 228 | + tml = tml.loads(text) |
| 229 | + |
| 230 | + except (IndexError, thoughtspot_tml.exceptions.TMLDecodeError) as e: |
| 231 | + # JUST FALL BACK TO TML WITH THE VARIABLES IN IT, WHICH SHOULD FAIL ON TML IMPORT ANYWAY. |
| 232 | + _LOG.warning(f"Could not variablize '{tml.name}' ({tml.tml_type_name}), see logs for details..") |
| 233 | + _LOG.debug(e, exc_info=True) |
| 234 | + |
| 235 | + if hasattr(e, "parent_exc"): |
| 236 | + _LOG.debug(f"due to..\n{e}", exc_info=True) |
| 237 | + |
| 238 | + _LOG.info(f"TML MODIFIED STATE:\n\n{text}") |
| 239 | + raise |
| 240 | + |
| 241 | + # STANDARD DISMABIGUATION |
200 | 242 | tml = thoughtspot_tml.utils.disambiguate( |
201 | 243 | tml=tml, |
202 | 244 | guid_mapping=self.mapping, |
|
0 commit comments