use color_eyre::Result;
use std::cell::RefCell;
use std::collections::VecDeque;
use tokio::process::Command;
use tokio_process_stream as tps;
use crate::process_wrapper::Cmd;
use crate::process_wrapper::Item;
use crate::process_wrapper::ProcessStream;
use crate::term_wrapper;
use crate::time_wrapper::Duration;
use crate::time_wrapper::Instant;
use crate::user_wrapper::UserStream;
pub trait SysApi: std::fmt::Debug + Clone + Default {
fn now(&self) -> Instant;
#[allow(dead_code)]
fn get_width(&self) -> Option<u16>;
fn run_command(&mut self, command: Cmd) -> Result<ProcessStream, std::io::Error>;
fn user_stream(&mut self) -> Option<UserStream>;
}
#[derive(Debug, Clone, Default)]
pub struct SysReal {}
impl SysApi for SysReal {
fn now(&self) -> Instant {
Instant::from(chrono::offset::Utc::now())
}
fn get_width(&self) -> Option<u16> {
term_wrapper::get_width()
}
fn run_command(&mut self, cmd: Cmd) -> Result<ProcessStream, std::io::Error> {
let process_stream = tps::ProcessLineStream::try_from(Command::from(&cmd))?;
Ok(ProcessStream::from(process_stream))
}
fn user_stream(&mut self) -> Option<UserStream> {
UserStream::new_real()
}
}
#[derive(Debug, Clone, Default)]
pub struct SysVirtual {
now: RefCell<Instant>,
items: VecDeque<Item>,
}
impl SysApi for SysVirtual {
fn now(&self) -> Instant {
let mut now_ref = self.now.borrow_mut();
let now = *now_ref;
*now_ref = &now + &Duration::seconds(1);
now
}
fn get_width(&self) -> Option<u16> {
Some(80)
}
fn run_command(&mut self, _cmd: Cmd) -> Result<ProcessStream, std::io::Error> {
let items = std::mem::take(&mut self.items);
Ok(ProcessStream::from(items))
}
fn user_stream(&mut self) -> Option<UserStream> {
Some(UserStream::new_virtual())
}
}
impl SysVirtual {
#[allow(dead_code)]
pub fn set_items(&mut self, items: Vec<Item>) {
self.items = items.into_iter().collect();
}
}
#[cfg(test)]
pub mod test {
use color_eyre::Result;
use tokio_stream::StreamExt;
use crate::process_wrapper::ExitSts;
use crate::sys::SysReal;
use crate::sys::SysVirtual;
use super::*;
#[tokio::test]
async fn test_sysvirtual() -> Result<()> {
let list = vec![
Item::Stdout("stdout".into()),
Item::Stderr("stderr".into()),
Item::Done(Ok(ExitSts::default())),
];
let mut sys = SysVirtual::default();
sys.set_items(list.clone());
let cmd = Cmd::default();
assert_eq!(format!("{}", cmd), "");
let streamer = sys.run_command(cmd)?;
assert_eq!(format!("{:?}", streamer), "ProcessStream::Virtual");
let streamed = streamer.collect::<Vec<_>>().await;
assert_eq!(streamed, list);
assert_eq!(sys.now(), Instant::default());
assert_eq!(sys.now(), &Instant::default() + &Duration::seconds(1));
assert_eq!(sys.get_width(), Some(80));
Ok(())
}
#[test]
fn test_sysreal_now() {
let sys = SysReal::default();
let now = sys.now();
let now2 = sys.now();
assert!(&now2 >= &now);
}
#[tokio::test]
async fn test_sysreal_run_command() -> Result<()> {
let mut sys = SysReal::default();
let cmdarr = ["true"];
let cmd = Cmd::from(&cmdarr[..]);
let streamer = sys.run_command(cmd)?;
let streamed = streamer.collect::<Vec<_>>().await;
assert_eq!(streamed, vec![Item::Done(Ok(ExitSts::default())),]);
Ok(())
}
}