hexz_cli/cmd/data/
commit.rs1use anyhow::{Context, Result};
4use std::path::PathBuf;
5use std::process::Command;
6use colored::Colorize;
7use indicatif::HumanBytes;
8
9use hexz_ops::pack::{PackConfig, PackAnalysisFlags, pack_archive};
10
11use super::workspace::Workspace;
12
13pub fn run(
15 mut output: PathBuf,
16 mountpoint: Option<PathBuf>,
17 base: Option<PathBuf>,
18) -> Result<()> {
19 let current_dir = std::env::current_dir()?;
20 let ws = Workspace::find(¤t_dir)?;
21
22 let mountpoint = if let Some(m) = mountpoint {
23 std::fs::canonicalize(m)?
24 } else {
25 if let Some(ref w) = ws {
27 w.root.clone()
28 } else {
29 anyhow::bail!("No mountpoint provided and no .hexz workspace found.");
30 }
31 };
32
33 if output.is_relative() {
35 if let Some(ref w) = ws {
36 if let Some(ref host_cwd) = w.config.host_cwd {
37 output = host_cwd.join(&output);
38 }
39 }
40 }
41
42 let base = if let Some(b) = base {
44 Some(b)
45 } else {
46 if let Some(ref w) = ws {
48 if let Some(b) = w.config.base_archive.clone() {
49 Some(b)
50 } else {
51 infer_base_archive(&mountpoint)
52 }
53 } else {
54 infer_base_archive(&mountpoint)
55 }
56 };
57
58 println!("{} Committing to {}", "╭".dimmed(), output.display().to_string().cyan());
59 if let Some(ref b) = base {
60 println!("{} Base: {}", "╰".dimmed(), b.display().to_string().bright_black());
61 } else {
62 println!("{} Base: {}", "╰".dimmed(), "(none)".bright_black());
63 }
64
65 let config = PackConfig {
66 input: mountpoint,
67 base,
68 output: output.clone(),
69 compression: "zstd".to_string(), analysis: PackAnalysisFlags {
71 use_dcam: true,
72 show_progress: true,
73 ..Default::default()
74 },
75 ..Default::default()
76 };
77
78 pack_archive(&config, None::<&fn(u64, u64)>).context("Commit failed during packing")?;
79
80 let file_size = std::fs::metadata(&output).map_or(0, |m| m.len());
81 let size_str = HumanBytes(file_size).to_string();
82
83 println!("\n {} Commit complete {}", "✓".green(), format!("({size_str} delta)").bright_black());
84 Ok(())
85}
86fn infer_base_archive(mountpoint: &std::path::Path) -> Option<PathBuf> {
87 if cfg!(target_os = "linux") {
89 let output = Command::new("findmnt")
90 .arg("-n")
91 .arg("-o")
92 .arg("SOURCE")
93 .arg(mountpoint)
94 .output()
95 .ok()?;
96
97 if output.status.success() {
98 let source = String::from_utf8_lossy(&output.stdout).trim().to_string();
99 let p = PathBuf::from(source);
100 if p.exists() && p.extension().is_some_and(|ext| ext == "hxz") {
101 return Some(p);
102 }
103 }
104 }
105 None
106}