use anyhow::Result;
use std::collections::HashMap;
use std::fs;
use std::path::Path;
use std::process::Command;
pub fn is_executable(path: &Path) -> Result<bool> {
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt;
let metadata = path.metadata()?;
let permissions = metadata.permissions();
Ok(permissions.mode() & 0o111 != 0)
}
#[cfg(not(unix))]
{
if let Some(name) = path.file_name() {
let name_str = name.to_string_lossy();
Ok(!name_str.contains('.') || name_str.ends_with(".exe"))
} else {
Ok(false)
}
}
}
pub fn calculate_checksum(path: &Path) -> Result<String> {
use std::io::Read;
let mut file = fs::File::open(path)?;
let mut hasher = blake3::Hasher::new();
let mut buffer = vec![0; 8192];
loop {
let n = file.read(&mut buffer)?;
if n == 0 {
break;
}
hasher.update(&buffer[..n]);
}
Ok(hasher.finalize().to_hex().to_string())
}
pub fn determine_config_type(path: &Path) -> String {
let path_str = path.to_string_lossy().to_lowercase();
if path_str.contains("infrastructure") {
"infrastructure".to_string()
} else if path_str.contains("node") {
"node".to_string()
} else if path_str.contains("behavior") {
"behavior".to_string()
} else {
"unknown".to_string()
}
}
pub fn determine_asset_type(path: &Path) -> String {
let path_str = path.to_string_lossy().to_lowercase();
if path_str.contains("model") || path_str.ends_with(".onnx") || path_str.ends_with(".pt") {
"model".to_string()
} else if path_str.contains("calibration") || path_str.ends_with(".yaml") {
"calibration".to_string()
} else {
"data".to_string()
}
}
pub fn collect_dependencies(project_root: &Path) -> Result<HashMap<String, String>> {
let mut dependencies = HashMap::new();
let cargo_lock_path = project_root.join("Cargo.lock");
if cargo_lock_path.exists() {
let lock_content = fs::read_to_string(&cargo_lock_path)?;
for line in lock_content.lines() {
if line.starts_with("name = ") {
if let Some(name) = line.split('"').nth(1) {
dependencies.insert(name.to_string(), "unknown".to_string());
}
}
}
}
Ok(dependencies)
}
pub fn get_git_commit(project_root: &Path) -> Option<String> {
Command::new("git")
.args(["rev-parse", "HEAD"])
.current_dir(project_root)
.output()
.ok()
.and_then(|output| {
if output.status.success() {
String::from_utf8(output.stdout).ok().map(|s| s.trim().to_string())
} else {
None
}
})
}
pub fn copy_dir_recursive(src: &Path, dst: &Path) -> Result<()> {
if !dst.exists() {
fs::create_dir_all(dst)?;
}
for entry in fs::read_dir(src)? {
let entry = entry?;
let path = entry.path();
let dest_path = dst.join(entry.file_name());
if path.is_dir() {
copy_dir_recursive(&path, &dest_path)?;
} else {
fs::copy(&path, &dest_path)?;
}
}
Ok(())
}