use rune::alloc::clone::TryClone;
use rune::alloc::fmt::TryWrite;
use rune::alloc::Vec;
use rune::runtime::{Bytes, Formatter, Mut, Value, VmResult};
use rune::{vm_try, vm_write, Any, ContextError, Module};
use std::io;
use tokio::process;
#[rune::module(::process)]
pub fn module(_stdio: bool) -> Result<Module, ContextError> {
let mut module = Module::from_meta(self::module_meta)?;
module.ty::<Command>()?;
module.function_meta(Command::new__meta)?;
module.function_meta(Command::arg__meta)?;
module.function_meta(Command::args__meta)?;
module.function_meta(Command::debug_fmt__meta)?;
#[cfg(unix)]
module.function_meta(Command::arg0__meta)?;
module.function_meta(Command::stdin__meta)?;
module.function_meta(Command::stdout__meta)?;
module.function_meta(Command::stderr__meta)?;
module.function_meta(Command::kill_on_drop__meta)?;
module.function_meta(Command::spawn__meta)?;
module.ty::<Child>()?;
module.function_meta(Child::debug_fmt__meta)?;
module.function_meta(Child::stdin__meta)?;
module.function_meta(Child::stdout__meta)?;
module.function_meta(Child::stderr__meta)?;
module.function_meta(Child::id__meta)?;
module.function_meta(Child::start_kill__meta)?;
module.function_meta(Child::kill__meta)?;
module.function_meta(Child::wait__meta)?;
module.function_meta(Child::wait_with_output__meta)?;
module.ty::<ExitStatus>()?;
module.function_meta(ExitStatus::code__meta)?;
module.function_meta(ExitStatus::success__meta)?;
module.function_meta(ExitStatus::display_fmt__meta)?;
module.function_meta(ExitStatus::debug_fmt__meta)?;
module.ty::<Output>()?;
module.function_meta(Output::debug_fmt__meta)?;
module.ty::<Stdio>()?;
module.function_meta(Stdio::null__meta)?;
module.function_meta(Stdio::inherit__meta)?;
module.function_meta(Stdio::piped__meta)?;
module.function_meta(Stdio::debug_fmt__meta)?;
module.ty::<ChildStdin>()?;
module.function_meta(ChildStdin::debug_fmt__meta)?;
module.function_meta(ChildStdin::try_into_stdio__meta)?;
module.ty::<ChildStdout>()?;
module.function_meta(ChildStdout::debug_fmt__meta)?;
module.function_meta(ChildStdout::try_into_stdio__meta)?;
module.ty::<ChildStderr>()?;
module.function_meta(ChildStderr::debug_fmt__meta)?;
module.function_meta(ChildStderr::try_into_stdio__meta)?;
Ok(module)
}
#[derive(Debug, Any)]
#[rune(item = ::process)]
struct Command {
inner: process::Command,
}
impl Command {
#[rune::function(keep, path = Self::new)]
fn new(command: &str) -> Self {
Self {
inner: process::Command::new(command),
}
}
#[rune::function(keep, instance)]
fn arg(&mut self, arg: &str) {
self.inner.arg(arg);
}
#[rune::function(keep, instance)]
fn args(&mut self, args: &[Value]) -> VmResult<()> {
for arg in args {
self.inner.arg(&*vm_try!(arg.borrow_string_ref()));
}
VmResult::Ok(())
}
#[cfg(unix)]
#[rune::function(keep, instance)]
fn arg0(&mut self, arg: &str) {
self.inner.arg0(arg);
}
#[rune::function(keep, instance)]
fn stdin(&mut self, stdio: Stdio) {
self.inner.stdin(stdio.inner);
}
#[rune::function(keep, instance)]
fn stdout(&mut self, stdio: Stdio) {
self.inner.stdout(stdio.inner);
}
#[rune::function(keep, instance)]
fn stderr(&mut self, stdio: Stdio) {
self.inner.stderr(stdio.inner);
}
#[rune::function(keep, instance)]
pub fn kill_on_drop(&mut self, kill_on_drop: bool) {
self.inner.kill_on_drop(kill_on_drop);
}
#[rune::function(keep, instance)]
fn spawn(&mut self) -> io::Result<Child> {
Ok(Child {
inner: self.inner.spawn()?,
})
}
#[rune::function(keep, protocol = DEBUG_FMT)]
fn debug_fmt(&self, f: &mut Formatter) -> VmResult<()> {
vm_write!(f, "{self:?}")
}
}
#[derive(Debug, Any)]
#[rune(item = ::process)]
struct Child {
inner: process::Child,
}
impl Child {
#[rune::function(keep, instance)]
fn stdin(&mut self) -> Option<ChildStdin> {
let inner = self.inner.stdin.take()?;
Some(ChildStdin { inner })
}
#[rune::function(keep, instance)]
fn stdout(&mut self) -> Option<ChildStdout> {
let inner = self.inner.stdout.take()?;
Some(ChildStdout { inner })
}
#[rune::function(keep, instance)]
fn stderr(&mut self) -> Option<ChildStderr> {
let inner = self.inner.stderr.take()?;
Some(ChildStderr { inner })
}
#[rune::function(keep, instance)]
fn id(&self) -> Option<u32> {
self.inner.id()
}
#[rune::function(keep, instance)]
fn start_kill(&mut self) -> io::Result<()> {
self.inner.start_kill()
}
#[rune::function(keep, instance, path = Self::kill)]
async fn kill(mut this: Mut<Self>) -> io::Result<()> {
this.inner.kill().await
}
#[rune::function(keep, instance, path = Self::wait)]
async fn wait(mut this: Mut<Self>) -> io::Result<ExitStatus> {
let inner = this.inner.wait().await?;
Ok(ExitStatus { inner })
}
#[rune::function(keep, vm_result, instance)]
async fn wait_with_output(self) -> io::Result<Output> {
let output = self.inner.wait_with_output().await?;
Ok(Output {
status: ExitStatus {
inner: output.status,
},
stdout: Value::new(Bytes::from_vec(Vec::try_from(output.stdout).vm?)).vm?,
stderr: Value::new(Bytes::from_vec(Vec::try_from(output.stderr).vm?)).vm?,
})
}
#[rune::function(keep, protocol = DEBUG_FMT)]
fn debug_fmt(&self, f: &mut Formatter) -> VmResult<()> {
vm_write!(f, "{:?}", self.inner)
}
}
#[derive(Debug, Any)]
#[rune(item = ::process)]
struct Output {
#[rune(get, copy)]
status: ExitStatus,
#[rune(get)]
stdout: Value,
#[rune(get)]
stderr: Value,
}
impl Output {
#[rune::function(keep, protocol = DEBUG_FMT)]
fn debug_fmt(&self, f: &mut Formatter) -> VmResult<()> {
vm_write!(f, "{self:?}")
}
}
#[derive(Debug, TryClone, Clone, Copy, Any)]
#[rune(item = ::process)]
struct ExitStatus {
inner: std::process::ExitStatus,
}
impl ExitStatus {
#[rune::function(keep)]
fn success(&self) -> bool {
self.inner.success()
}
#[rune::function(keep)]
fn code(&self) -> Option<i32> {
self.inner.code()
}
#[rune::function(keep, protocol = DISPLAY_FMT)]
fn display_fmt(&self, f: &mut Formatter) -> VmResult<()> {
vm_write!(f, "{}", self.inner)
}
#[rune::function(keep, protocol = DEBUG_FMT)]
fn debug_fmt(&self, f: &mut Formatter) -> VmResult<()> {
vm_write!(f, "{:?}", self.inner)
}
}
#[derive(Debug, Any)]
#[rune(item = ::process)]
struct Stdio {
inner: std::process::Stdio,
}
impl Stdio {
#[rune::function(keep, path = Self::null)]
fn null() -> Self {
Self {
inner: std::process::Stdio::null(),
}
}
#[rune::function(keep, path = Self::inherit)]
fn inherit() -> Self {
Self {
inner: std::process::Stdio::inherit(),
}
}
#[rune::function(keep, path = Self::piped)]
fn piped() -> Self {
Self {
inner: std::process::Stdio::piped(),
}
}
#[rune::function(keep, protocol = DEBUG_FMT)]
fn debug_fmt(&self, f: &mut Formatter) -> VmResult<()> {
vm_write!(f, "{:?}", self.inner)
}
}
macro_rules! stdio_stream {
($name:ident, $stream:tt) => {
#[derive(Debug, Any)]
#[rune(item = ::process)]
#[doc = concat!("The ", $stream, " stream for spawned children.")]
struct $name {
inner: process::$name,
}
impl $name {
#[rune::function(keep, instance)]
fn try_into_stdio(self) -> io::Result<Stdio> {
Ok(Stdio {
inner: self.inner.try_into()?,
})
}
#[rune::function(keep, protocol = DEBUG_FMT)]
fn debug_fmt(&self, f: &mut Formatter) -> VmResult<()> {
vm_write!(f, "{:?}", self.inner)
}
}
};
}
stdio_stream!(ChildStdin, "stdin");
stdio_stream!(ChildStdout, "stdout");
stdio_stream!(ChildStderr, "stderr");