1use crate::error::{CarchError, Result};
2use include_dir::{Dir, include_dir};
3use std::fs;
4use std::os::unix::fs::PermissionsExt;
5use std::path::Path;
6
7pub mod error;
8pub mod ui;
9pub mod version;
10
11static EMBEDDED_DIR: Dir = include_dir!("$CARGO_MANIFEST_DIR/src/modules");
12
13const EXECUTABLE_MODE: u32 = 0o755;
14
15pub fn extract_scripts(temp_path: &Path) -> Result<()> {
16 let modules_dir = temp_path.join("modules");
17 fs::create_dir_all(&modules_dir)
18 .map_err(|e| CarchError::CreateDir(modules_dir.display().to_string(), e))?;
19
20 extract_dir_recursive(&EMBEDDED_DIR, &modules_dir)?;
21
22 let preview_link = temp_path.join("preview_scripts");
23 if fs::remove_file(&preview_link).is_err() {
24 }
26
27 std::os::unix::fs::symlink(&modules_dir, &preview_link)
28 .map_err(|e| CarchError::Symlink(e.to_string()))?;
29
30 Ok(())
31}
32
33fn extract_dir_recursive(dir: &Dir, target_path: &Path) -> Result<()> {
34 fs::create_dir_all(target_path)
35 .map_err(|e| CarchError::CreateDir(target_path.display().to_string(), e))?;
36
37 for entry in dir.entries() {
38 match entry {
39 include_dir::DirEntry::File(file) => {
40 let file_path = target_path.join(file.path().file_name().unwrap_or_default());
41 fs::write(&file_path, file.contents())
42 .map_err(|e| CarchError::WriteFile(file_path.display().to_string(), e))?;
43
44 if file_path.extension().is_some_and(|ext| ext == "sh") {
45 set_executable(&file_path)?;
46 }
47 }
48 include_dir::DirEntry::Dir(subdir) => {
49 let subdir_path = target_path.join(subdir.path().file_name().unwrap_or_default());
50 extract_dir_recursive(subdir, &subdir_path)?;
51 }
52 }
53 }
54
55 Ok(())
56}
57
58fn set_executable(path: &Path) -> Result<()> {
59 let mut perms = fs::metadata(path)
60 .map_err(|e| CarchError::Metadata(path.display().to_string(), e))?
61 .permissions();
62 perms.set_mode(EXECUTABLE_MODE);
63 fs::set_permissions(path, perms)
64 .map_err(|e| CarchError::SetPermissions(path.display().to_string(), e))?;
65 Ok(())
66}