Fix Python f-strings in heredocs that reference undefined WORKSPACE variable.
(apply: bool)
| 51 | |
| 52 | |
| 53 | def fix_heredoc_fstring(apply: bool): |
| 54 | """Fix Python f-strings in heredocs that reference undefined WORKSPACE variable.""" |
| 55 | for sh_file in sorted(TASKS_ROOT.rglob("*.sh")): |
| 56 | content = sh_file.read_text() |
| 57 | |
| 58 | if "f'{WORKSPACE}" not in content and 'f"{WORKSPACE}' not in content: |
| 59 | continue |
| 60 | if "os.environ" in content and "WORKSPACE" in content: |
| 61 | continue |
| 62 | |
| 63 | task_name = sh_file.parent.parent.name if sh_file.parent.name in ("solution", "environment") else sh_file.parent.name |
| 64 | |
| 65 | fix_line = "import os; WORKSPACE = os.environ.get('WORKSPACE', os.getcwd())\n" |
| 66 | |
| 67 | new_content = content |
| 68 | # Find Python heredoc blocks and inject os.environ at the top |
| 69 | patterns = [ |
| 70 | (r"(python3\s+-\s*<<\s*'?EOF'?\s*\n)", r"\1" + fix_line), |
| 71 | (r"(python3\s*<<\s*'?EOF'?\s*\n)", r"\1" + fix_line), |
| 72 | (r"(python3\s+-c\s*')", None), |
| 73 | ] |
| 74 | |
| 75 | for pat, repl in patterns: |
| 76 | if repl: |
| 77 | new_content = re.sub(pat, repl, new_content) |
| 78 | |
| 79 | # Also handle cases where python3 -c is used with f-strings |
| 80 | if new_content == content: |
| 81 | # Fallback: replace f'{WORKSPACE} with proper os.environ usage |
| 82 | new_content = new_content.replace( |
| 83 | "f'{WORKSPACE}", "f'{os.environ.get(\"WORKSPACE\", os.getcwd())}" |
| 84 | ) |
| 85 | new_content = new_content.replace( |
| 86 | 'f"{WORKSPACE}', 'f"{os.environ.get(\\"WORKSPACE\\", os.getcwd())}' |
| 87 | ) |
| 88 | |
| 89 | if new_content != content: |
| 90 | stats["heredoc"] += 1 |
| 91 | if apply: |
| 92 | sh_file.write_text(new_content) |
| 93 | print(f" [heredoc] {task_name}: fixed f-string in {sh_file.name}") |
| 94 | |
| 95 | |
| 96 | def fix_verifier_workspace(apply: bool): |