YAML task parser
| 13 | |
| 14 | |
| 15 | class YAMLTaskParser: |
| 16 | """YAML task parser""" |
| 17 | |
| 18 | def __init__(self): |
| 19 | self.context = {} |
| 20 | self.variables = {} |
| 21 | |
| 22 | def load_task(self, file_path: str) -> Dict[str, Any]: |
| 23 | """Load and parse a YAML task file""" |
| 24 | with open(file_path, "r", encoding="utf-8") as f: |
| 25 | content = f.read() |
| 26 | |
| 27 | # Expand environment variables first |
| 28 | content = self._expand_env_variables(content) |
| 29 | |
| 30 | # Parse YAML |
| 31 | task_data = yaml.safe_load(content) |
| 32 | |
| 33 | # Validate task format |
| 34 | self._validate_task(task_data) |
| 35 | |
| 36 | return task_data |
| 37 | |
| 38 | def _expand_env_variables(self, content: str) -> str: |
| 39 | """Expand environment variables and template variables""" |
| 40 | |
| 41 | # Handle ${VAR} and ${VAR:-default} formats |
| 42 | def replace_var(match): |
| 43 | var_expr = match.group(1) |
| 44 | if ":-" in var_expr: |
| 45 | var_name, default_value = var_expr.split(":-", 1) |
| 46 | value = os.getenv(var_name, default_value) |
| 47 | else: |
| 48 | value = os.getenv(var_expr, match.group(0)) |
| 49 | |
| 50 | # If the value contains special YAML characters and needs escaping |
| 51 | if value and value != match.group( |
| 52 | 0 |
| 53 | ): # Only if we actually got a value from env |
| 54 | # Escape backslashes and double quotes for YAML double-quoted strings |
| 55 | # This handles JSON strings and other special content |
| 56 | if ( |
| 57 | "\\" in value |
| 58 | or '"' in value |
| 59 | or "\n" in value |
| 60 | or "\r" in value |
| 61 | or "\t" in value |
| 62 | ): |
| 63 | value = value.replace("\\", "\\\\") # Escape backslashes first |
| 64 | value = value.replace('"', '\\"') # Escape double quotes |
| 65 | value = value.replace("\n", "\\n") # Escape newlines |
| 66 | value = value.replace("\r", "\\r") # Escape carriage returns |
| 67 | value = value.replace("\t", "\\t") # Escape tabs |
| 68 | |
| 69 | return value |
| 70 | |
| 71 | # Replace environment variables |
| 72 | content = re.sub(r"\$\{([^}]+)\}", replace_var, content) |
no outgoing calls