summaryrefslogtreecommitdiff
path: root/src/client
diff options
context:
space:
mode:
authorlittleblack111 <littleblack11111@gmail.com>2025-09-13 22:10:20 +0800
committerlittleblack111 <littleblack11111@gmail.com>2025-09-13 22:10:20 +0800
commit3b27ce15cace19804031024f286754aedf86205e (patch)
tree989cf322a30f35480460b7a60d46eb8228fb5d25 /src/client
parentb03c840683dd92f78c91ba48f0d1abd606bf0ff1 (diff)
feat: `executor`, executs `tasks`
Diffstat (limited to 'src/client')
-rw-r--r--src/client/executor.rs26
-rw-r--r--src/client/executor/tasks.rs77
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)
-// }
-// }