Skip to main content

wasibox_core/
lib.rs

1pub mod utils;
2#[cfg(test)]
3mod tests;
4
5use std::ffi::OsString;
6use std::path::Path;
7use std::io::{Read, Write};
8use std::sync::atomic::{AtomicBool, Ordering};
9use std::sync::Arc;
10
11/// A token to cancel running commands.
12#[derive(Clone, Default)]
13pub struct CancellationToken {
14    flag: Arc<AtomicBool>,
15}
16
17impl CancellationToken {
18    pub fn new() -> Self {
19        Self { flag: Arc::new(AtomicBool::new(false)) }
20    }
21
22    pub fn cancel(&self) {
23        self.flag.store(true, Ordering::SeqCst);
24    }
25
26    pub fn is_cancelled(&self) -> bool {
27        self.flag.load(Ordering::SeqCst)
28    }
29
30    pub fn reset(&self) {
31        self.flag.store(false, Ordering::SeqCst);
32    }
33}
34
35/// Context for utility IO, allowing redirection of stdin, stdout, and stderr.
36pub struct IoContext {
37    pub stdin: Box<dyn Read + Send>,
38    pub stdout: Box<dyn Write + Send>,
39    pub stderr: Box<dyn Write + Send>,
40    pub cancel_token: CancellationToken,
41}
42
43impl IoContext {
44    pub fn new(
45        stdin: Box<dyn Read + Send>,
46        stdout: Box<dyn Write + Send>,
47        stderr: Box<dyn Write + Send>,
48    ) -> Self {
49        Self { stdin, stdout, stderr, cancel_token: CancellationToken::new() }
50    }
51
52    pub fn with_cancel(
53        stdin: Box<dyn Read + Send>,
54        stdout: Box<dyn Write + Send>,
55        stderr: Box<dyn Write + Send>,
56        cancel_token: CancellationToken,
57    ) -> Self {
58        Self { stdin, stdout, stderr, cancel_token }
59    }
60}
61
62impl Default for IoContext {
63    fn default() -> Self {
64        Self {
65            stdin: Box::new(std::io::stdin()),
66            stdout: Box::new(std::io::stdout()),
67            stderr: Box::new(std::io::stderr()),
68            cancel_token: CancellationToken::new(),
69        }
70    }
71}
72
73pub fn execute<I, T>(args: I) -> Result<(), String>
74where
75    I: IntoIterator<Item = T>,
76    T: Into<OsString> + Clone,
77{
78    execute_with_context(args, &mut IoContext::default())
79}
80
81pub fn execute_with_context<I, T>(args: I, ctx: &mut IoContext) -> Result<(), String>
82where
83    I: IntoIterator<Item = T>,
84    T: Into<OsString> + Clone,
85{
86    let args_vec: Vec<OsString> = args.into_iter().map(|a| a.into()).collect();
87    if args_vec.is_empty() {
88        return Err("No utility specified".to_string());
89    }
90
91    let prog_name_raw = Path::new(&args_vec[0])
92        .file_name()
93        .unwrap_or_default()
94        .to_string_lossy();
95    let prog_name = prog_name_raw
96        .trim_end_matches(".exe")
97        .trim_end_matches(".wasm");
98
99    let (util_name, util_args) = if prog_name == "core" || prog_name == "core-rust" || prog_name == "wasibox-core" {
100        if args_vec.len() < 2 {
101            return Err("Usage: core <utility> [args...]".to_string());
102        }
103        (args_vec[1].to_string_lossy().to_string(), &args_vec[1..])
104    } else {
105        (prog_name.to_string(), &args_vec[..])
106    };
107
108    match util_name.as_str() {
109        #[cfg(feature = "arch")]
110        "arch" => utils::arch::execute_with_context(util_args, ctx),
111        #[cfg(feature = "basename")]
112        "basename" => utils::basename::execute_with_context(util_args, ctx),
113        #[cfg(feature = "cat")]
114        "cat" => utils::cat::execute_with_context(util_args, ctx),
115        #[cfg(feature = "cp")]
116        "cp" => utils::cp::execute_with_context(util_args, ctx),
117        #[cfg(feature = "dir")]
118        "dir" => utils::dir::execute_with_context(util_args, ctx),
119        #[cfg(feature = "dirname")]
120        "dirname" => utils::dirname::execute_with_context(util_args, ctx),
121        #[cfg(feature = "echo")]
122        "echo" => utils::echo::execute_with_context(util_args, ctx),
123        #[cfg(feature = "env")]
124        "env" => utils::env::execute_with_context(util_args, ctx),
125        #[cfg(feature = "false")]
126        "false" => utils::r#false::execute_with_context(util_args, ctx),
127        #[cfg(feature = "grep")]
128        "grep" => utils::grep::execute_with_context(util_args, ctx),
129        #[cfg(feature = "head")]
130        "head" => utils::head::execute_with_context(util_args, ctx),
131        #[cfg(feature = "link")]
132        "link" => utils::link::execute_with_context(util_args, ctx),
133        #[cfg(feature = "ln")]
134        "ln" => utils::ln::execute_with_context(util_args, ctx),
135        #[cfg(feature = "ls")]
136        "ls" => utils::ls::execute_with_context(util_args, ctx),
137        #[cfg(feature = "mkdir")]
138        "mkdir" => utils::mkdir::execute_with_context(util_args, ctx),
139        #[cfg(feature = "mv")]
140        "mv" => utils::mv::execute_with_context(util_args, ctx),
141        #[cfg(feature = "pwd")]
142        "pwd" => utils::pwd::execute_with_context(util_args, ctx),
143        #[cfg(feature = "rm")]
144        "rm" => utils::rm::execute_with_context(util_args, ctx),
145        #[cfg(feature = "rmdir")]
146        "rmdir" => utils::rmdir::execute_with_context(util_args, ctx),
147        #[cfg(feature = "seq")]
148        "seq" => utils::seq::execute_with_context(util_args, ctx),
149        #[cfg(feature = "sleep")]
150        "sleep" => utils::sleep::execute_with_context(util_args, ctx),
151        #[cfg(feature = "tail")]
152        "tail" => utils::tail::execute_with_context(util_args, ctx),
153        #[cfg(feature = "tee")]
154        "tee" => utils::tee::execute_with_context(util_args, ctx),
155        #[cfg(feature = "touch")]
156        "touch" => utils::touch::execute_with_context(util_args, ctx),
157        #[cfg(feature = "tree")]
158        "tree" => utils::tree::execute_with_context(util_args, ctx),
159        #[cfg(feature = "true")]
160        "true" => utils::r#true::execute_with_context(util_args, ctx),
161        #[cfg(feature = "uname")]
162        "uname" => utils::uname::execute_with_context(util_args, ctx),
163        #[cfg(feature = "unlink")]
164        "unlink" => utils::unlink::execute_with_context(util_args, ctx),
165        #[cfg(feature = "wc")]
166        "wc" => utils::wc::execute_with_context(util_args, ctx),
167        #[cfg(feature = "whoami")]
168        "whoami" => utils::whoami::execute_with_context(util_args, ctx),
169        #[cfg(feature = "yes")]
170        "yes" => utils::yes::execute_with_context(util_args, ctx),
171        _ => Err(format!("Unknown utility: {}", util_name)),
172    }
173}