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