| | |
| | """ |
| | Backup New Memory Directory to GitHub |
| | |
| | Backs up files from the new memory/ directory to git (excluding .db files). |
| | Automatically tracks new files as they're created. |
| | """ |
| |
|
| | import subprocess |
| | import sys |
| | from pathlib import Path |
| | from datetime import datetime |
| |
|
| | def run_git_command(cmd: list[str], check: bool = True) -> subprocess.CompletedProcess: |
| | """Run a git command.""" |
| | try: |
| | result = subprocess.run( |
| | ["git"] + cmd, |
| | capture_output=True, |
| | text=True, |
| | check=check |
| | ) |
| | return result |
| | except subprocess.CalledProcessError as e: |
| | print(f"Git command failed: {' '.join(cmd)}") |
| | print(f"Error: {e.stderr}") |
| | if check: |
| | raise |
| | return e |
| |
|
| | def check_git_repo() -> bool: |
| | """Check if we're in a git repository.""" |
| | result = run_git_command(["rev-parse", "--git-dir"], check=False) |
| | return result.returncode == 0 |
| |
|
| | def backup_new_memory_files() -> dict[str, any]: |
| | """Backup new memory files to git.""" |
| | memory_dir = Path("memory") |
| | |
| | if not memory_dir.exists(): |
| | print("⚠️ Memory directory does not exist yet. It will be created when ATLES uses it.") |
| | return { |
| | "success": False, |
| | "error": "Memory directory does not exist", |
| | "files_backed_up": [] |
| | } |
| | |
| | backup_info = { |
| | "timestamp": datetime.now().isoformat(), |
| | "files_backed_up": [], |
| | "files_skipped": [] |
| | } |
| | |
| | |
| | all_files = list(memory_dir.rglob("*")) |
| | excluded_extensions = {'.db', '.db-journal', '.db-wal', '.db-shm'} |
| | |
| | files_to_backup = [ |
| | f for f in all_files |
| | if f.is_file() and f.suffix.lower() not in excluded_extensions |
| | ] |
| | |
| | if not files_to_backup: |
| | print("ℹ️ No files to backup in memory/ directory (excluding .db files)") |
| | print(" New memory files will be backed up automatically when created.") |
| | return backup_info |
| | |
| | print(f"Found {len(files_to_backup)} files to backup:") |
| | for file_path in files_to_backup: |
| | relative_path = file_path.relative_to(Path(".")) |
| | print(f" - {relative_path}") |
| | |
| | |
| | result = run_git_command(["add", "-f", str(relative_path)], check=False) |
| | if result.returncode == 0: |
| | backup_info["files_backed_up"].append(str(relative_path)) |
| | else: |
| | backup_info["files_skipped"].append(str(relative_path)) |
| | print(f" ⚠️ Could not add: {result.stderr.strip()}") |
| | |
| | return backup_info |
| |
|
| | def commit_backup(backup_info: dict[str, any]) -> bool: |
| | """Commit the backup.""" |
| | timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") |
| | commit_message = f"Backup new memory files: {timestamp}\n\nFiles backed up: {len(backup_info['files_backed_up'])}" |
| | |
| | |
| | result = run_git_command(["status", "--porcelain"], check=False) |
| | if not result.stdout.strip(): |
| | print("\nℹ️ No changes to commit.") |
| | return False |
| | |
| | |
| | run_git_command(["commit", "-m", commit_message]) |
| | print(f"\n✅ Committed backup: {len(backup_info['files_backed_up'])} files") |
| | return True |
| |
|
| | def push_backup() -> bool: |
| | """Push backup to remote.""" |
| | print("\nPushing backup to remote...") |
| | result = run_git_command(["push", "origin", "main"], check=False) |
| | if result.returncode == 0: |
| | print("✅ Pushed backup to remote") |
| | return True |
| | else: |
| | print(f"⚠️ Could not push to remote: {result.stderr}") |
| | print("Backup is saved locally, you can push manually later") |
| | return False |
| |
|
| | def update_gitignore_for_new_memory(): |
| | """Update .gitignore to allow new memory files (but keep .db excluded).""" |
| | gitignore_path = Path(".gitignore") |
| | |
| | if not gitignore_path.exists(): |
| | return |
| | |
| | content = gitignore_path.read_text(encoding='utf-8') |
| | |
| | |
| | if "memory/" in content and "!memory/*.json" not in content: |
| | print("\n📝 Updating .gitignore to allow JSON files in memory/...") |
| | |
| | |
| | lines = content.split('\n') |
| | new_lines = [] |
| | memory_found = False |
| | |
| | for line in lines: |
| | new_lines.append(line) |
| | if line.strip() == "memory/" and not memory_found: |
| | |
| | new_lines.append("!memory/*.json") |
| | new_lines.append("!memory/*.txt") |
| | new_lines.append("!memory/*.yaml") |
| | new_lines.append("!memory/*.yml") |
| | memory_found = True |
| | |
| | gitignore_path.write_text('\n'.join(new_lines), encoding='utf-8') |
| | print("✅ Updated .gitignore") |
| | return True |
| | |
| | return False |
| |
|
| | def main(): |
| | """Main backup function.""" |
| | print("=" * 60) |
| | print("Backup New Memory Directory to GitHub") |
| | print("=" * 60) |
| | print() |
| | |
| | |
| | if not check_git_repo(): |
| | print("❌ Error: Not in a git repository!") |
| | sys.exit(1) |
| | |
| | |
| | result = run_git_command(["branch", "--show-current"]) |
| | current_branch = result.stdout.strip() |
| | print(f"Current branch: {current_branch}") |
| | print() |
| | |
| | |
| | update_gitignore_for_new_memory() |
| | |
| | |
| | print("Scanning memory/ directory...") |
| | backup_info = backup_new_memory_files() |
| | |
| | if not backup_info.get("files_backed_up"): |
| | print("\n✅ Setup complete!") |
| | print(" New memory files will be backed up automatically when created.") |
| | print(" Run this script again after ATLES creates new memory files.") |
| | return |
| | |
| | print(f"\n✅ Found {len(backup_info['files_backed_up'])} files to backup") |
| | if backup_info.get("files_skipped"): |
| | print(f"⚠️ Skipped {len(backup_info['files_skipped'])} files") |
| | |
| | |
| | if commit_backup(backup_info): |
| | |
| | push_backup() |
| | |
| | print() |
| | print("=" * 60) |
| | print("✅ Backup complete!") |
| | print("=" * 60) |
| | print() |
| | print("Note: .db files are excluded (as per .gitignore)") |
| | print("Only non-database files from memory/ are backed up") |
| |
|
| | if __name__ == "__main__": |
| | main() |
| |
|