diff options
| author | littleblack111 <littleblack11111@gmail.com> | 2025-09-13 22:10:20 +0800 |
|---|---|---|
| committer | littleblack111 <littleblack11111@gmail.com> | 2025-09-13 22:10:20 +0800 |
| commit | 3b27ce15cace19804031024f286754aedf86205e (patch) | |
| tree | 989cf322a30f35480460b7a60d46eb8228fb5d25 /src/client | |
| parent | b03c840683dd92f78c91ba48f0d1abd606bf0ff1 (diff) | |
feat: `executor`, executs `tasks`
Diffstat (limited to 'src/client')
| -rw-r--r-- | src/client/executor.rs | 26 | ||||
| -rw-r--r-- | src/client/executor/tasks.rs | 77 |
2 files changed, 76 insertions, 27 deletions
diff --git a/src/client/executor.rs b/src/client/executor.rs index eee1b36..df22c57 100644 --- a/src/client/executor.rs +++ b/src/client/executor.rs @@ -1,15 +1,25 @@ -use crate::executor::tasks::Task; +use crate::executor::tasks::{IntoTask, IntoTaskErr, Task}; mod tasks; -struct Executor<T: Task> { - task: T, +struct Executor<'a> { + task: &'a Task, + args: Box<[&'a str]>, + output: Option<Result<String, String>>, } -impl<T: Task> Executor<T> { - // fn new(args: &str) -> Self { - // // exe(parse()) - // } +impl<'a> Executor<'a> { + fn new(task: impl IntoTask, args: &'a str) -> Result<Self, IntoTaskErr> { + let task = task.into_task()?; + Ok(Self { + task: task, + args: Box::new([args]), + output: None, + }) + } - // IntoTask like IntoUrl + fn run(&mut self) -> Option<&Result<String, String>> { + self.output = Some((self.task.exec)(&self.args)); + self.output.as_ref() + } } diff --git a/src/client/executor/tasks.rs b/src/client/executor/tasks.rs index 90094de..c69b310 100644 --- a/src/client/executor/tasks.rs +++ b/src/client/executor/tasks.rs @@ -1,29 +1,68 @@ -use std::str::FromStr; +pub(crate) struct Task { + pub name: &'static str, + pub exec: fn(&[&str]) -> Result<String, String>, +} -pub(crate) trait Task: FromStr { - type Err: std::fmt::Display; - type Success: std::fmt::Display = String; +pub(crate) const TASKS: &[Task] = &[ + Task { + name: "nop", + exec: no_op, + }, + Task { + name: "exec", + exec: exec, + }, +]; - fn execute() -> Result<Self::Success, <Self as Task>::Err>; +fn no_op(_: &[&str]) -> Result<String, String> { + Ok("".to_string()) } -pub(crate) trait IntoTask { - type Err: std::fmt::Display; +fn exec(cmds: &[&str]) -> Result<String, String> { + use std::process::Command; + // TODO: fmt and add exit code, and add support for both stdout and stderr, and support for no output + match Command::new(cmds[0]).args(&cmds[1..]).output() { + Ok(o) => { + if o.status.success() { + Ok(String::from_utf8(o.stdout) + .unwrap_or("Failed decoding vec<u8> -> String".to_string()) + .to_string()) + } else { + Err(String::from_utf8(o.stderr) + .unwrap_or("Failed decoding vec<u8> -> String".to_string()) + .to_string()) + } + } + Err(e) => Err(e.to_string()), + } +} - fn into_task(self) -> Result<impl Task, Self::Err>; +pub(crate) enum IntoTaskErr { + NotFound, +} + +pub(crate) trait IntoTask { + fn into_task<'a>(self) -> Result<&'a Task, IntoTaskErr>; } impl IntoTask for String { - type Err = <String as FromStr>::Err; + fn into_task<'a>(self) -> Result<&'a Task, IntoTaskErr> { + for task in TASKS { + if task.name == self { + return Ok(task); + } + } + Err(IntoTaskErr::NotFound) + } +} - fn into_task(self) -> Result<impl Task, Self::Err> {} +impl IntoTask for &str { + fn into_task<'a>(self) -> Result<&'a Task, IntoTaskErr> { + for task in TASKS { + if task.name == self { + return Ok(task); + } + } + Err(IntoTaskErr::NotFound) + } } -// -// impl Task for { -// type Err = std::num::ParseIntError; -// type Success = u32; -// -// fn execute() -> Result<Self::Success, Self::Err> { -// Ok(42) -// } -// } |
