horto_os_ui_shared/kits/
fs.rs1use crate::context::HostContext;
4use crate::error::{HortoError, Result};
5use std::fs;
6use std::path::Path;
7use walkdir::WalkDir;
8
9pub fn ensure_dir(ctx: &mut HostContext, path: &Path) -> Result<()> {
17 if ctx.is_dry_run() {
18 ctx.plan_action(format!("mkdir -p {}", path.display()));
19 return Ok(());
20 }
21 fs::create_dir_all(path)?;
22 Ok(())
23}
24
25pub fn write_file(ctx: &mut HostContext, path: &Path, content: &[u8]) -> Result<()> {
33 if ctx.is_dry_run() {
34 ctx.plan_action(format!(
35 "write {} ({} bytes)",
36 path.display(),
37 content.len()
38 ));
39 return Ok(());
40 }
41 if let Some(parent) = path.parent() {
42 fs::create_dir_all(parent)?;
43 }
44 fs::write(path, content)?;
45 Ok(())
46}
47
48pub fn copy_file(ctx: &mut HostContext, src: &Path, dest: &Path) -> Result<()> {
56 if ctx.is_dry_run() {
57 ctx.plan_action(format!("cp {} -> {}", src.display(), dest.display()));
58 return Ok(());
59 }
60 if let Some(parent) = dest.parent() {
61 fs::create_dir_all(parent)?;
62 }
63 fs::copy(src, dest).map_err(|e| {
64 HortoError::msg(format!("copy {} -> {}: {e}", src.display(), dest.display()))
65 })?;
66 Ok(())
67}
68
69pub fn copy_dir_contents(ctx: &mut HostContext, src: &Path, dest: &Path) -> Result<()> {
77 if ctx.is_dry_run() {
78 ctx.plan_action(format!("cp -a {}/. -> {}/", src.display(), dest.display()));
79 return Ok(());
80 }
81 fs::create_dir_all(dest)?;
82 for entry in WalkDir::new(src)
83 .into_iter()
84 .filter_map(std::result::Result::ok)
85 {
86 let path = entry.path();
87 let rel = path.strip_prefix(src).unwrap_or(path);
88 let target = dest.join(rel);
89 if entry.file_type().is_dir() {
90 fs::create_dir_all(&target)?;
91 } else if entry.file_type().is_file() {
92 if let Some(parent) = target.parent() {
93 fs::create_dir_all(parent)?;
94 }
95 fs::copy(path, &target)?;
96 }
97 }
98 Ok(())
99}
100
101pub fn remove_path(ctx: &mut HostContext, path: &Path) -> Result<()> {
109 if ctx.is_dry_run() {
110 ctx.plan_action(format!("rm -f {}", path.display()));
111 return Ok(());
112 }
113 if path.is_symlink() || path.is_file() {
114 fs::remove_file(path)?;
115 } else if path.is_dir() {
116 fs::remove_dir_all(path)?;
117 }
118 Ok(())
119}
120
121pub fn chmod(ctx: &mut HostContext, path: &Path, mode: u32) -> Result<()> {
130 if ctx.is_dry_run() {
131 ctx.plan_action(format!("chmod {mode:o} {}", path.display()));
132 return Ok(());
133 }
134 #[cfg(unix)]
135 {
136 use std::os::unix::fs::PermissionsExt;
137 let perms = fs::Permissions::from_mode(mode);
138 fs::set_permissions(path, perms)?;
139 }
140 #[cfg(not(unix))]
141 {
142 let _ = (path, mode);
143 }
144 Ok(())
145}