use anyhow::{Context, Result};
use std::path::Path;
use crate::types::{CachePath, ModelName};
pub fn validate_model_name(model_name: &ModelName) -> Result<()> {
let model_str = model_name.as_str();
if model_str.is_empty() {
return Err(anyhow::anyhow!(
"[HUGGINGFACE] [VALIDATION] failed: Model name cannot be empty"
));
}
if !model_str.contains('/') {
return Err(anyhow::anyhow!(
"[HUGGINGFACE] [VALIDATION] failed: Model name '{}' must follow HuggingFace format 'organization/model-name'",
model_str
));
}
let parts: Vec<&str> = model_str.split('/').collect();
if parts.len() != 2 || parts[0].is_empty() || parts[1].is_empty() {
return Err(anyhow::anyhow!(
"[HUGGINGFACE] [VALIDATION] failed: Model name '{}' has invalid format. Expected 'organization/model-name'",
model_str
));
}
let allowed_chars =
|c: char| c.is_alphanumeric() || c == '-' || c == '_' || c == '.' || c == '/';
if !model_str.chars().all(allowed_chars) {
return Err(anyhow::anyhow!(
"[HUGGINGFACE] [VALIDATION] failed: Model name '{}' contains invalid characters. Only alphanumeric, '-', '_', '.', and '/' are allowed",
model_str
));
}
Ok(())
}
pub fn validate_cache_directory(cache_dir: &CachePath) -> Result<()> {
let cache_path = cache_dir.as_ref();
if !cache_path.exists() {
return Err(anyhow::anyhow!(
"[HUGGINGFACE] [VALIDATION] failed: Cache directory does not exist: {}",
cache_dir
));
}
if !cache_path.is_dir() {
return Err(anyhow::anyhow!(
"[HUGGINGFACE] [VALIDATION] failed: Cache path is not a directory: {}",
cache_dir
));
}
Ok(())
}
pub fn validate_cache_permissions(cache_path: &Path) -> Result<()> {
let metadata = std::fs::metadata(cache_path).with_context(|| {
format!(
"[HUGGINGFACE] [VALIDATION] failed: Cannot read cache directory metadata: {}",
cache_path.display()
)
})?;
if metadata.permissions().readonly() {
return Err(anyhow::anyhow!(
"[HUGGINGFACE] [VALIDATION] failed: Cache directory is read-only: {}. Write permissions required for model downloads",
cache_path.display()
));
}
let test_file = cache_path.join(".turboprop_write_test");
match std::fs::File::create(&test_file) {
Ok(_) => {
let _ = std::fs::remove_file(&test_file);
}
Err(e) => {
return Err(anyhow::anyhow!(
"[HUGGINGFACE] [VALIDATION] failed: Cannot write to cache directory: {}. Error: {}",
cache_path.display(),
e
));
}
}
Ok(())
}
pub fn validate_model_inputs(model_name: &ModelName, cache_dir: &CachePath) -> Result<()> {
validate_model_name(model_name)?;
validate_cache_directory(cache_dir)?;
validate_cache_permissions(cache_dir.as_path())?;
Ok(())
}