use crate::error::{CarchError, Result};
use include_dir::{Dir, include_dir};
use std::fs;
use std::os::unix::fs::PermissionsExt;
use std::path::Path;
pub mod error;
pub mod ui;
pub mod version;
static EMBEDDED_DIR: Dir = include_dir!("$CARGO_MANIFEST_DIR/src/modules");
pub const VALID_THEMES: &[&str] = &["catppuccin-mocha", "dracula", "gruvbox", "nord", "rose-pine"];
#[must_use]
pub fn is_valid_theme(theme: &str) -> bool {
VALID_THEMES.contains(&theme)
}
const EXECUTABLE_MODE: u32 = 0o755;
#[must_use]
#[cfg(unix)]
pub fn is_running_as_root() -> bool {
unsafe { libc::geteuid() == 0 }
}
#[must_use]
#[cfg(not(unix))]
pub fn is_running_as_root() -> bool {
false
}
pub fn extract_scripts(temp_path: &Path) -> Result<()> {
let modules_dir = temp_path.join("modules");
fs::create_dir_all(&modules_dir)
.map_err(|e| CarchError::CreateDir(modules_dir.display().to_string(), e))?;
extract_dir_recursive(&EMBEDDED_DIR, &modules_dir)?;
let preview_link = temp_path.join("preview_scripts");
let _ = fs::remove_file(&preview_link);
std::os::unix::fs::symlink(&modules_dir, &preview_link).map_err(|e| {
CarchError::Symlink(format!(
"{} -> {}: {}",
modules_dir.display(),
preview_link.display(),
e
))
})?;
Ok(())
}
fn extract_dir_recursive(dir: &Dir, target_path: &Path) -> Result<()> {
fs::create_dir_all(target_path)
.map_err(|e| CarchError::CreateDir(target_path.display().to_string(), e))?;
for entry in dir.entries() {
match entry {
include_dir::DirEntry::File(file) => {
let file_path = target_path.join(file.path().file_name().unwrap_or_default());
fs::write(&file_path, file.contents())
.map_err(|e| CarchError::WriteFile(file_path.display().to_string(), e))?;
if file_path.extension().is_some_and(|ext| ext == "sh") {
set_executable(&file_path)?;
}
}
include_dir::DirEntry::Dir(subdir) => {
let subdir_path = target_path.join(subdir.path().file_name().unwrap_or_default());
extract_dir_recursive(subdir, &subdir_path)?;
}
}
}
Ok(())
}
fn set_executable(path: &Path) -> Result<()> {
let mut perms = fs::metadata(path)
.map_err(|e| CarchError::Metadata(path.display().to_string(), e))?
.permissions();
perms.set_mode(EXECUTABLE_MODE);
fs::set_permissions(path, perms)
.map_err(|e| CarchError::SetPermissions(path.display().to_string(), e))?;
Ok(())
}