use std::{
path::{Path, PathBuf},
sync::Arc,
};
use async_trait::async_trait;
use tokio::sync::RwLock;
use watchso::{
command::WCommand,
framework::{Framework, WatchableFramework},
framework_utils::{get_bpf_or_sbf, get_program_name_path_hashmap, ProjectMap},
};
#[derive(Default)]
pub struct Native {
origin: Arc<PathBuf>,
project_map: ProjectMap,
build_cmd: BuildCommand,
}
impl Native {
pub fn new<P: AsRef<Path>>(origin: P) -> Self {
Self {
origin: Arc::new(origin.as_ref().to_path_buf()),
..Default::default()
}
}
}
impl WatchableFramework for Native {}
#[async_trait]
impl Framework for Native {
fn origin(&self) -> &Path {
self.origin.as_path()
}
async fn check_toolset(&self) -> miette::Result<()> {
let build_cmd = get_bpf_or_sbf().await?;
self.build_cmd.set(build_cmd).await;
Ok(())
}
async fn map_program_names(&self) -> miette::Result<()> {
for (name, path) in get_program_name_path_hashmap(self.origin()).await? {
self.project_map.set_program_path(name, path).await;
}
Ok(())
}
async fn get_program_path(&self, path: &Path) -> Option<PathBuf> {
self.project_map.get_program_path(path).await
}
async fn build(&self, program_path: &Path) -> WCommand {
let mut command = WCommand::new(self.build_cmd.get().await);
command.current_dir(program_path);
command
}
async fn deploy(&self, elf_path: &Path) -> WCommand {
WCommand::new(format!("solana program deploy {}", elf_path.display()))
}
}
struct BuildCommand(Arc<RwLock<&'static str>>);
impl BuildCommand {
async fn get(&self) -> &'static str {
*self.0.read().await
}
async fn set(&self, build_cmd: &'static str) {
*self.0.write().await = build_cmd;
}
}
impl Default for BuildCommand {
fn default() -> Self {
Self(Arc::new(RwLock::new("cargo build-sbf")))
}
}