Save changes to the .env file. Preserves comments and structure, only updating changed values. Returns: True if save was successful
(self)
| 388 | return list(set(modified)) |
| 389 | |
| 390 | def save(self) -> bool: |
| 391 | """ |
| 392 | Save changes to the .env file. |
| 393 | |
| 394 | Preserves comments and structure, only updating changed values. |
| 395 | |
| 396 | Returns: |
| 397 | True if save was successful |
| 398 | """ |
| 399 | try: |
| 400 | new_lines = [] |
| 401 | keys_written = set() |
| 402 | |
| 403 | for line in self._file_lines: |
| 404 | stripped = line.strip() |
| 405 | |
| 406 | # Keep empty lines and comments |
| 407 | if not stripped or stripped.startswith("#"): |
| 408 | new_lines.append(line) |
| 409 | continue |
| 410 | |
| 411 | # Check if this is a key=value line |
| 412 | match = re.match(r"^([A-Z_][A-Z0-9_]*)\s*=", stripped, re.IGNORECASE) |
| 413 | if match: |
| 414 | key = match.group(1) |
| 415 | if key in self._values: |
| 416 | # Update the value, preserve comment if any |
| 417 | comment_match = re.search(r"#.*$", line) |
| 418 | comment = comment_match.group(0) if comment_match else "" |
| 419 | |
| 420 | value = self._values[key] |
| 421 | # Quote values with spaces |
| 422 | if " " in value and not ( |
| 423 | value.startswith('"') or value.startswith("'") |
| 424 | ): |
| 425 | value = f'"{value}"' |
| 426 | |
| 427 | new_line = f"{key}={value}" |
| 428 | if comment: |
| 429 | new_line += f" {comment}" |
| 430 | new_lines.append(new_line + "\n") |
| 431 | keys_written.add(key) |
| 432 | else: |
| 433 | new_lines.append(line) |
| 434 | else: |
| 435 | new_lines.append(line) |
| 436 | |
| 437 | # Add any new keys at the end |
| 438 | for key, value in self._values.items(): |
| 439 | if key not in keys_written: |
| 440 | new_lines.append(f"\n{key}={value}\n") |
| 441 | |
| 442 | # Write the file |
| 443 | with open(self.env_path, "w", encoding="utf-8") as f: |
| 444 | f.writelines(new_lines) |
| 445 | |
| 446 | # Reload to update line cache |
| 447 | self.load() |