launcher/headless/
snapshot.rs1use std::path::PathBuf;
2use std::process::ExitCode;
3use std::thread;
4
5use crate::utils::create_storage;
6use serde_json;
7use supreme_fs::SnapshotEvent;
8use supreme_snapshot::SnapshotManifest;
9
10pub fn run_snapshot_list() -> ExitCode {
12 let storage = create_storage();
13
14 match storage.list_snapshots_profiles() {
15 Ok(profiles) => {
16 if profiles.is_empty() {
17 println!("No local snapshots found.");
18 } else {
19 println!("Local snapshots ({}):", profiles.len());
20 for profile in profiles {
21 if let Ok(content) = storage.get_profile(&profile)
23 && let Ok(manifest) = serde_json::from_slice::<SnapshotManifest>(&content)
24 {
25 let name = manifest.name.unwrap_or_else(|| "Unnamed".to_string());
26 let desc = manifest
27 .description
28 .unwrap_or_else(|| "No description".to_string());
29 let version = manifest.version.unwrap_or_else(|| "Unknown".to_string());
30 println!(
31 " {} (name: {}, version: {}, files: {})",
32 profile,
33 name,
34 version,
35 manifest.files.len()
36 );
37 println!(" Description: {}", desc);
38 continue;
39 }
40 println!(" {}", profile);
41 }
42 }
43 ExitCode::SUCCESS
44 }
45 Err(e) => {
46 eprintln!("Error listing snapshots: {e}");
47 ExitCode::FAILURE
48 }
49 }
50}
51
52pub fn run_snapshot_create(
54 name: String,
55 description: Option<String>,
56 version: Option<String>,
57 compression: u32,
58 directory: Option<PathBuf>,
59) -> ExitCode {
60 let storage = create_storage();
61 let (tx, rx) = std::sync::mpsc::channel::<SnapshotEvent>();
62
63 println!("Creating snapshot '{}'...", name);
64
65 let progress_handle = thread::spawn(move || {
67 while let Ok(event) = rx.recv() {
68 match event {
69 SnapshotEvent::SetStatus(msg) => {
70 println!("Status: {}", msg);
71 }
72 SnapshotEvent::Log(msg) => {
73 println!("Log: {}", msg);
74 }
75 SnapshotEvent::InitProgress(total) => {
76 println!("Progress: 0/{} files", total);
77 }
78 SnapshotEvent::IncrementProgress => {
79 }
81 SnapshotEvent::Perf(op, target, ms) => {
82 println!("Perf: {} -> {} in {}ms", op, target, ms);
83 }
84 }
85 }
86 });
87
88 match supreme_snapshot::create_snapshot(
89 &storage,
90 &name,
91 description,
92 version,
93 directory,
94 tx,
95 compression,
96 ) {
97 Ok(hash) => {
98 if progress_handle.join().is_err() {
99 eprintln!("Progress reporting thread panicked");
100 }
101 println!("Snapshot created successfully! Hash: {}", hash);
102 ExitCode::SUCCESS
103 }
104 Err(e) => {
105 if progress_handle.join().is_err() {
106 eprintln!("Progress reporting thread panicked");
107 }
108 eprintln!("Failed to create snapshot: {e}");
109 ExitCode::FAILURE
110 }
111 }
112}
113
114pub fn run_snapshot_restore(profile: String) -> ExitCode {
116 let storage = create_storage();
117 let (tx, rx) = std::sync::mpsc::channel::<SnapshotEvent>();
118
119 println!("Restoring snapshot '{}'...", profile);
120
121 let progress_handle = thread::spawn(move || {
123 while let Ok(event) = rx.recv() {
124 match event {
125 SnapshotEvent::SetStatus(msg) => {
126 println!("Status: {}", msg);
127 }
128 SnapshotEvent::Log(msg) => {
129 println!("Log: {}", msg);
130 }
131 SnapshotEvent::InitProgress(total) => {
132 println!("Progress: 0/{} files", total);
133 }
134 SnapshotEvent::IncrementProgress => {
135 }
137 SnapshotEvent::Perf(op, target, ms) => {
138 println!("Perf: {} -> {} in {}ms", op, target, ms);
139 }
140 }
141 }
142 });
143
144 let result = supreme_snapshot::restore_snapshot(&storage, &profile, tx);
145 if progress_handle.join().is_err() {
147 eprintln!("Progress reporting thread panicked");
148 }
149
150 match result {
151 Ok(manifest) => {
152 let (music_tx, music_rx) = std::sync::mpsc::channel::<SnapshotEvent>();
154 let music_handle = thread::spawn(move || {
155 while let Ok(event) = music_rx.recv() {
156 if let SnapshotEvent::Log(msg) = event {
157 println!("Music: {}", msg);
158 }
159 }
160 });
161
162 if let Err(e) =
163 supreme_snapshot::reconcile_music_after_restore(&storage, &manifest, &music_tx)
164 {
165 eprintln!("Failed to reconcile music after restore: {e}");
166 }
167 drop(music_tx);
168 if music_handle.join().is_err() {
169 eprintln!("Music reconciliation logging thread panicked");
170 }
171
172 println!("Snapshot restored successfully!");
173 ExitCode::SUCCESS
174 }
175 Err(e) => {
176 eprintln!("Failed to restore snapshot: {e}");
177 ExitCode::FAILURE
178 }
179 }
180}