mod basename;
mod cat;
mod cd;
mod cp;
mod dirname;
mod echo;
mod env;
mod exit;
mod r#false;
mod ls;
mod mkdir;
mod mv;
mod pwd;
mod rm;
mod seq;
mod sleep;
mod test;
mod touch;
mod r#true;
mod which;
mod yes;
pub use basename::basename;
pub use cat::cat;
pub use cd::cd;
pub use cp::cp;
pub use dirname::dirname;
pub use echo::echo;
pub use env::env;
pub use exit::exit;
pub use ls::ls;
pub use mkdir::mkdir;
pub use mv::mv;
pub use pwd::pwd;
pub use r#false::r#false;
pub use r#true::r#true;
pub use rm::rm;
pub use seq::seq;
pub use sleep::sleep;
pub use test::test;
pub use touch::touch;
pub use which::which;
pub use yes::yes;
use crate::utils::CommandResult;
use std::collections::HashMap;
use std::path::Path;
use tokio::sync::mpsc;
pub struct CommandContext {
pub args: Vec<String>,
pub stdin: Option<String>,
pub cwd: Option<std::path::PathBuf>,
pub env: Option<HashMap<String, String>>,
pub output_tx: Option<mpsc::Sender<StreamChunk>>,
pub is_cancelled: Option<Box<dyn Fn() -> bool + Send + Sync>>,
}
impl std::fmt::Debug for CommandContext {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("CommandContext")
.field("args", &self.args)
.field("stdin", &self.stdin)
.field("cwd", &self.cwd)
.field("env", &self.env)
.field("output_tx", &self.output_tx.is_some())
.field("is_cancelled", &self.is_cancelled.is_some())
.finish()
}
}
#[derive(Debug, Clone)]
pub enum StreamChunk {
Stdout(String),
Stderr(String),
}
impl CommandContext {
pub fn new(args: Vec<String>) -> Self {
CommandContext {
args,
stdin: None,
cwd: None,
env: None,
output_tx: None,
is_cancelled: None,
}
}
pub fn is_cancelled(&self) -> bool {
self.is_cancelled.as_ref().map(|f| f()).unwrap_or(false)
}
pub fn get_cwd(&self) -> std::path::PathBuf {
self.cwd.clone().unwrap_or_else(|| {
std::env::current_dir().unwrap_or_else(|_| std::path::PathBuf::from("/"))
})
}
}
pub type VirtualCommandHandler =
fn(
CommandContext,
) -> std::pin::Pin<Box<dyn std::future::Future<Output = CommandResult> + Send>>;
pub struct VirtualCommandRegistry {
commands: HashMap<String, VirtualCommandHandler>,
}
impl Default for VirtualCommandRegistry {
fn default() -> Self {
Self::new()
}
}
impl VirtualCommandRegistry {
pub fn new() -> Self {
VirtualCommandRegistry {
commands: HashMap::new(),
}
}
pub fn with_builtins() -> Self {
let mut registry = Self::new();
registry.register_builtins();
registry
}
pub fn register(&mut self, name: &str, handler: VirtualCommandHandler) {
self.commands.insert(name.to_string(), handler);
}
pub fn unregister(&mut self, name: &str) -> bool {
self.commands.remove(name).is_some()
}
pub fn get(&self, name: &str) -> Option<&VirtualCommandHandler> {
self.commands.get(name)
}
pub fn contains(&self, name: &str) -> bool {
self.commands.contains_key(name)
}
pub fn list(&self) -> Vec<&str> {
self.commands.keys().map(|s| s.as_str()).collect()
}
pub fn register_builtins(&mut self) {
}
}
static VIRTUAL_COMMANDS_ENABLED: std::sync::atomic::AtomicBool =
std::sync::atomic::AtomicBool::new(true);
pub fn enable_virtual_commands() {
VIRTUAL_COMMANDS_ENABLED.store(true, std::sync::atomic::Ordering::SeqCst);
}
pub fn disable_virtual_commands() {
VIRTUAL_COMMANDS_ENABLED.store(false, std::sync::atomic::Ordering::SeqCst);
}
pub fn are_virtual_commands_enabled() -> bool {
VIRTUAL_COMMANDS_ENABLED.load(std::sync::atomic::Ordering::SeqCst)
}