use std::path::Path;
use anyhow::{Context, Result};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ProgramType {
Solana,
RiscvC,
RiscvRust,
}
pub fn detect_program_type(path: &Path) -> Result<ProgramType> {
crate::validate_program_path(path)?;
let cargo_toml = path.join("Cargo.toml");
if cargo_toml.exists() {
if is_solana_program(&cargo_toml)? {
return Ok(ProgramType::Solana);
} else {
return Ok(ProgramType::RiscvRust);
}
}
if has_c_sources(path)? {
return Ok(ProgramType::RiscvC);
}
Err(anyhow::anyhow!(
"Could not detect program type in {}. Directory should contain:\n\
- Cargo.toml (for Solana or RISC-V Rust programs)\n\
- C source files (.c or .S) (for RISC-V C programs)",
path.display()
))
}
fn is_solana_program(cargo_toml_path: &Path) -> Result<bool> {
let manifest = cargo_toml::Manifest::from_path(cargo_toml_path).with_context(|| {
format!(
"Failed to parse Cargo.toml at {}",
cargo_toml_path.display()
)
})?;
let solana_deps = [
"solana-program",
"solana-sdk",
"rialo-s-program",
"rialo-s-sdk",
];
for dep_name in solana_deps {
if manifest.dependencies.contains_key(dep_name) {
return Ok(true);
}
}
for dep_name in solana_deps {
if manifest.dev_dependencies.contains_key(dep_name) {
return Ok(true);
}
}
Ok(false)
}
fn has_c_sources(path: &Path) -> Result<bool> {
if has_c_files_in_dir(path)? {
return Ok(true);
}
let src_dir = path.join("src");
if src_dir.exists() && has_c_files_in_dir(&src_dir)? {
return Ok(true);
}
Ok(false)
}
fn has_c_files_in_dir(dir: &Path) -> Result<bool> {
if !dir.is_dir() {
return Ok(false);
}
let entries = std::fs::read_dir(dir)
.with_context(|| format!("Failed to read directory {}", dir.display()))?;
for entry in entries.flatten() {
let path = entry.path();
if path.is_file() {
if let Some(ext) = path.extension() {
if ext == "c" || ext == "S" {
return Ok(true);
}
}
}
}
Ok(false)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_program_type_equality() {
assert_eq!(ProgramType::Solana, ProgramType::Solana);
assert_ne!(ProgramType::Solana, ProgramType::RiscvC);
assert_ne!(ProgramType::RiscvC, ProgramType::RiscvRust);
}
}