|
| 1 | +#!/usr/bin/env python3 |
| 2 | +""" |
| 3 | +Snapshot Management Example |
| 4 | +
|
| 5 | +Demonstrates how to: |
| 6 | +1. Create snapshots with tags |
| 7 | +2. List and filter snapshots |
| 8 | +3. Find snapshots by tag |
| 9 | +4. Restore snapshots |
| 10 | +5. Delete snapshots |
| 11 | +
|
| 12 | +Usage: |
| 13 | + python examples/snapshot_example.py |
| 14 | +""" |
| 15 | + |
| 16 | +import sys |
| 17 | +import tempfile |
| 18 | +from pathlib import Path |
| 19 | + |
| 20 | +from sandd import Server |
| 21 | + |
| 22 | + |
| 23 | +def main(): |
| 24 | + # Create a temporary workspace |
| 25 | + with tempfile.TemporaryDirectory() as workspace: |
| 26 | + workspace_path = Path(workspace) |
| 27 | + print(f"📁 Using workspace: {workspace_path}\n") |
| 28 | + |
| 29 | + # Create some test files |
| 30 | + (workspace_path / "file1.txt").write_text("Hello World") |
| 31 | + (workspace_path / "file2.txt").write_text("Python Snapshot Example") |
| 32 | + (workspace_path / "subdir").mkdir() |
| 33 | + (workspace_path / "subdir" / "file3.txt").write_text("Nested file") |
| 34 | + |
| 35 | + # Start server |
| 36 | + server = Server(host="0.0.0.0", port=8765) |
| 37 | + print("✅ Server started on 0.0.0.0:8765") |
| 38 | + print("⏳ Waiting for daemon to connect...\n") |
| 39 | + |
| 40 | + # Wait for at least one daemon to connect |
| 41 | + import time |
| 42 | + while server.daemon_count() == 0: |
| 43 | + time.sleep(0.5) |
| 44 | + |
| 45 | + daemons = server.list_daemons() |
| 46 | + daemon_id = daemons[0].id |
| 47 | + print(f"✅ Connected to daemon: {daemon_id}\n") |
| 48 | + |
| 49 | + # ========== 1. Create Snapshots ========== |
| 50 | + print("=" * 60) |
| 51 | + print("1️⃣ Creating Snapshots") |
| 52 | + print("=" * 60) |
| 53 | + |
| 54 | + snapshot_id1 = server.create_snapshot( |
| 55 | + daemon_id=daemon_id, |
| 56 | + workspace=str(workspace_path), |
| 57 | + message="Initial snapshot with 3 files", |
| 58 | + tags=["v1.0", "initial"], |
| 59 | + ) |
| 60 | + print(f"✅ Created snapshot 1: {snapshot_id1}") |
| 61 | + print(f" Tags: v1.0, initial\n") |
| 62 | + |
| 63 | + # Modify workspace |
| 64 | + (workspace_path / "file2.txt").write_text("Modified content") |
| 65 | + (workspace_path / "file4.txt").write_text("New file") |
| 66 | + |
| 67 | + snapshot_id2 = server.create_snapshot( |
| 68 | + daemon_id=daemon_id, |
| 69 | + workspace=str(workspace_path), |
| 70 | + message="After modifications", |
| 71 | + tags=["v1.1"], |
| 72 | + ) |
| 73 | + print(f"✅ Created snapshot 2: {snapshot_id2}") |
| 74 | + print(f" Tags: v1.1\n") |
| 75 | + |
| 76 | + # ========== 2. List All Snapshots ========== |
| 77 | + print("=" * 60) |
| 78 | + print("2️⃣ Listing All Snapshots") |
| 79 | + print("=" * 60) |
| 80 | + |
| 81 | + snapshots = server.list_snapshots(daemon_id=daemon_id) |
| 82 | + for i, snap in enumerate(snapshots, 1): |
| 83 | + print(f"\nSnapshot {i}:") |
| 84 | + print(f" ID: {snap.id}") |
| 85 | + print(f" Message: {snap.message}") |
| 86 | + print(f" Tags: {', '.join(snap.tags)}") |
| 87 | + print(f" Files: {snap.file_count}") |
| 88 | + print(f" Size: {snap.total_size} bytes") |
| 89 | + print(f" Created: {snap.created_at}") |
| 90 | + |
| 91 | + # ========== 3. Filter by Tags ========== |
| 92 | + print("\n" + "=" * 60) |
| 93 | + print("3️⃣ Filtering Snapshots by Tag") |
| 94 | + print("=" * 60) |
| 95 | + |
| 96 | + v1_snapshots = server.list_snapshots(daemon_id=daemon_id, tags=["v1.0"]) |
| 97 | + print(f"\n📌 Snapshots with tag 'v1.0': {len(v1_snapshots)}") |
| 98 | + for snap in v1_snapshots: |
| 99 | + print(f" - {snap.message} ({snap.id})") |
| 100 | + |
| 101 | + # ========== 4. Find by Tag ========== |
| 102 | + print("\n" + "=" * 60) |
| 103 | + print("4️⃣ Finding Snapshot by Tag") |
| 104 | + print("=" * 60) |
| 105 | + |
| 106 | + initial_snapshot = server.find_snapshot_by_tag(daemon_id=daemon_id, tag="initial") |
| 107 | + if initial_snapshot: |
| 108 | + print(f"\n✅ Found snapshot with tag 'initial':") |
| 109 | + print(f" ID: {initial_snapshot.id}") |
| 110 | + print(f" Message: {initial_snapshot.message}") |
| 111 | + else: |
| 112 | + print("❌ No snapshot found with tag 'initial'") |
| 113 | + |
| 114 | + # ========== 5. Get Snapshot Details ========== |
| 115 | + print("\n" + "=" * 60) |
| 116 | + print("5️⃣ Getting Snapshot Details") |
| 117 | + print("=" * 60) |
| 118 | + |
| 119 | + snapshot = server.get_snapshot(daemon_id=daemon_id, snapshot_id=snapshot_id1) |
| 120 | + if snapshot: |
| 121 | + print(f"\n✅ Snapshot details:") |
| 122 | + print(f" ID: {snapshot.id}") |
| 123 | + print(f" Message: {snapshot.message}") |
| 124 | + print(f" Tags: {snapshot.tags}") |
| 125 | + print(f" File count: {snapshot.file_count}") |
| 126 | + print(f" Total size: {snapshot.total_size} bytes") |
| 127 | + else: |
| 128 | + print("❌ Snapshot not found") |
| 129 | + |
| 130 | + # ========== 6. Restore Snapshot ========== |
| 131 | + print("\n" + "=" * 60) |
| 132 | + print("6️⃣ Restoring Snapshot") |
| 133 | + print("=" * 60) |
| 134 | + |
| 135 | + restore_path = workspace_path / "restored" |
| 136 | + restore_path.mkdir() |
| 137 | + |
| 138 | + file_count = server.restore_snapshot( |
| 139 | + daemon_id=daemon_id, |
| 140 | + snapshot_id=snapshot_id1, |
| 141 | + destination=str(restore_path), |
| 142 | + ) |
| 143 | + print(f"\n✅ Restored {file_count} files to: {restore_path}") |
| 144 | + |
| 145 | + # Verify restored files |
| 146 | + restored_files = list(restore_path.rglob("*")) |
| 147 | + print(f" Files in restored directory:") |
| 148 | + for f in restored_files: |
| 149 | + if f.is_file(): |
| 150 | + print(f" - {f.relative_to(restore_path)}") |
| 151 | + |
| 152 | + # ========== 7. Delete Snapshot ========== |
| 153 | + print("\n" + "=" * 60) |
| 154 | + print("7️⃣ Deleting Snapshot") |
| 155 | + print("=" * 60) |
| 156 | + |
| 157 | + server.delete_snapshot(daemon_id=daemon_id, snapshot_id=snapshot_id2) |
| 158 | + print(f"\n✅ Deleted snapshot: {snapshot_id2}") |
| 159 | + |
| 160 | + # Verify deletion |
| 161 | + remaining = server.list_snapshots(daemon_id=daemon_id) |
| 162 | + print(f" Remaining snapshots: {len(remaining)}") |
| 163 | + |
| 164 | + print("\n" + "=" * 60) |
| 165 | + print("✅ Snapshot example completed successfully!") |
| 166 | + print("=" * 60) |
| 167 | + |
| 168 | + |
| 169 | +if __name__ == "__main__": |
| 170 | + try: |
| 171 | + main() |
| 172 | + except KeyboardInterrupt: |
| 173 | + print("\n\n👋 Interrupted by user") |
| 174 | + sys.exit(0) |
| 175 | + except Exception as e: |
| 176 | + print(f"\n❌ Error: {e}", file=sys.stderr) |
| 177 | + sys.exit(1) |
0 commit comments