feat: enable actual actions
Signed-off-by: kjuulh <contact@kjuulh.io>
This commit is contained in:
parent
2d7a053ab0
commit
7804eaa667
8
Cargo.lock
generated
8
Cargo.lock
generated
@ -7,7 +7,7 @@ name = "action"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"cuddle-actions 0.1.0",
|
||||
"cuddle-actions 0.2.0 (git+ssh://git@git.front.kjuulh.io/kjuulh/cuddle-v2)",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
@ -268,11 +268,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cuddle-actions"
|
||||
version = "0.1.0"
|
||||
source = "git+ssh://git@git.front.kjuulh.io/kjuulh/cuddle-v2#fb2e4b3234a249d17aaf9bdff18825a36a132bbd"
|
||||
version = "0.2.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
"pretty_assertions",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
@ -280,10 +280,10 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "cuddle-actions"
|
||||
version = "0.2.0"
|
||||
source = "git+ssh://git@git.front.kjuulh.io/kjuulh/cuddle-v2#71cc6a0a000dbdb1b62b518cd2d955e9121627f1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
"pretty_assertions",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
@ -12,7 +12,7 @@ anyhow = { version = "1" }
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
tracing = { version = "0.1", features = ["log"] }
|
||||
tracing-subscriber = { version = "0.3.18" }
|
||||
clap = { version = "4", features = ["derive", "env"] }
|
||||
clap = { version = "4", features = ["derive", "env", "string"] }
|
||||
dotenv = { version = "0.15" }
|
||||
serde = { version = "1.0.197", features = ["derive"] }
|
||||
serde_json = "1.0.127"
|
||||
|
@ -3,7 +3,14 @@ use cuddle_actions::AddActionOptions;
|
||||
#[tokio::main]
|
||||
async fn main() -> anyhow::Result<()> {
|
||||
cuddle_actions::CuddleActions::default()
|
||||
.add_action("something", || Ok(()), &AddActionOptions::default())
|
||||
.add_action(
|
||||
"something",
|
||||
|| {
|
||||
println!("did something");
|
||||
Ok(())
|
||||
},
|
||||
&AddActionOptions::default(),
|
||||
)
|
||||
.execute()?;
|
||||
|
||||
Ok(())
|
||||
|
@ -1,6 +1,10 @@
|
||||
use std::{
|
||||
collections::BTreeMap,
|
||||
future::{self, Future},
|
||||
ops::Deref,
|
||||
path::{Path, PathBuf},
|
||||
pin::Pin,
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
use rust_builder::RustActionsBuilder;
|
||||
@ -16,6 +20,10 @@ pub mod rust_builder {
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::actions::CuddleActionsSchema;
|
||||
|
||||
use super::ExecutableActions;
|
||||
|
||||
pub struct RustActionsBuilder {
|
||||
@ -138,7 +146,7 @@ pub mod rust_builder {
|
||||
.output()
|
||||
.await?;
|
||||
|
||||
let actions: ExecutableActions = match serde_json::from_slice(&output.stdout) {
|
||||
let actions: CuddleActionsSchema = match serde_json::from_slice(&output.stdout) {
|
||||
Ok(output) => output,
|
||||
Err(e) => {
|
||||
let schema_output = std::str::from_utf8(&output.stdout)?;
|
||||
@ -151,7 +159,7 @@ pub mod rust_builder {
|
||||
}
|
||||
};
|
||||
|
||||
Ok(actions)
|
||||
Ok(actions.to_executable(action_path)?)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -180,7 +188,7 @@ impl Actions {
|
||||
Ok(Some(Self { variants }))
|
||||
}
|
||||
|
||||
pub async fn build(&mut self) -> anyhow::Result<Vec<ExecutableActions>> {
|
||||
pub async fn build(&mut self) -> anyhow::Result<ExecutableActions> {
|
||||
let mut executable_actions = Vec::default();
|
||||
|
||||
for variant in &mut self.variants {
|
||||
@ -194,8 +202,23 @@ impl Actions {
|
||||
}
|
||||
}
|
||||
|
||||
Ok(executable_actions)
|
||||
let mut exec_actions = ExecutableActions::default();
|
||||
for mut actions in executable_actions {
|
||||
exec_actions.actions.append(&mut actions.actions);
|
||||
}
|
||||
|
||||
Ok(exec_actions)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct CuddleActionsSchema {
|
||||
actions: Vec<CuddleActionSchema>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct CuddleActionSchema {
|
||||
name: String,
|
||||
}
|
||||
|
||||
pub enum ActionVariant {
|
||||
@ -203,16 +226,25 @@ pub enum ActionVariant {
|
||||
Docker,
|
||||
}
|
||||
|
||||
#[derive(Default, Serialize, Deserialize)]
|
||||
#[derive(Default)]
|
||||
pub struct ExecutableActions {
|
||||
actions: Vec<ExecutableAction>,
|
||||
pub actions: Vec<ExecutableAction>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct ExecutableAction {
|
||||
name: String,
|
||||
description: String,
|
||||
flags: BTreeMap<String, ExecutableActionFlag>,
|
||||
pub name: String,
|
||||
pub description: String,
|
||||
pub flags: BTreeMap<String, ExecutableActionFlag>,
|
||||
call_fn: LazyResolve,
|
||||
}
|
||||
|
||||
impl ExecutableAction {
|
||||
pub async fn call(&self) -> anyhow::Result<()> {
|
||||
// Bad hack until .call becomes stable
|
||||
(self.call_fn.0)().await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
@ -220,3 +252,67 @@ pub enum ExecutableActionFlag {
|
||||
String,
|
||||
Bool,
|
||||
}
|
||||
|
||||
impl CuddleActionsSchema {
|
||||
fn to_executable(self, action_path: &Path) -> anyhow::Result<ExecutableActions> {
|
||||
Ok(ExecutableActions {
|
||||
actions: self
|
||||
.actions
|
||||
.into_iter()
|
||||
.map(|a| {
|
||||
let name = a.name.clone();
|
||||
let action_path = action_path.to_string_lossy().to_string();
|
||||
|
||||
ExecutableAction {
|
||||
name: a.name,
|
||||
description: String::new(),
|
||||
flags: BTreeMap::default(),
|
||||
call_fn: LazyResolve::new(Box::new(move || {
|
||||
let name = name.clone();
|
||||
let action_path = action_path.clone();
|
||||
|
||||
Box::pin(async move {
|
||||
tracing::debug!("calling: {}", name);
|
||||
let mut cmd = tokio::process::Command::new(action_path);
|
||||
cmd.args(["do", &name]);
|
||||
|
||||
let output = cmd.output().await?;
|
||||
let stdout = std::str::from_utf8(&output.stdout)?;
|
||||
for line in stdout.lines() {
|
||||
println!("{}: {}", &name, line);
|
||||
}
|
||||
|
||||
tracing::debug!("finished call for output: {}", &name);
|
||||
|
||||
Ok(())
|
||||
})
|
||||
})),
|
||||
}
|
||||
})
|
||||
.collect(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
struct LazyResolve(
|
||||
Arc<dyn Fn() -> Pin<Box<dyn Future<Output = anyhow::Result<()>> + Send>> + Send + Sync>,
|
||||
);
|
||||
|
||||
impl LazyResolve {
|
||||
pub fn new(
|
||||
func: Box<
|
||||
dyn Fn() -> Pin<Box<dyn Future<Output = anyhow::Result<()>> + Send>> + Send + Sync,
|
||||
>,
|
||||
) -> Self {
|
||||
Self(Arc::new(func))
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for LazyResolve {
|
||||
type Target =
|
||||
Arc<dyn Fn() -> Pin<Box<dyn Future<Output = anyhow::Result<()>> + Send>> + Send + Sync>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
@ -40,8 +40,19 @@ impl Cli {
|
||||
}
|
||||
|
||||
async fn get_commands(&self) -> anyhow::Result<Vec<clap::Command>> {
|
||||
let actions = self
|
||||
.cuddle
|
||||
.state
|
||||
.actions
|
||||
.actions
|
||||
.iter()
|
||||
.map(|a| clap::Command::new(&a.name))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
Ok(vec![
|
||||
clap::Command::new("do").subcommand_required(true),
|
||||
clap::Command::new("do")
|
||||
.subcommand_required(true)
|
||||
.subcommands(actions.as_slice()),
|
||||
clap::Command::new("get")
|
||||
.about(GetCommand::description())
|
||||
.arg(
|
||||
@ -67,8 +78,23 @@ impl Cli {
|
||||
.subcommand()
|
||||
.ok_or(anyhow::anyhow!("failed to find subcommand"))?
|
||||
{
|
||||
("do", _args) => {
|
||||
("do", args) => {
|
||||
tracing::debug!("executing do");
|
||||
|
||||
let (action_name, args) = args
|
||||
.subcommand()
|
||||
.ok_or(anyhow::anyhow!("failed to find do subcommand"))?;
|
||||
|
||||
let action = self
|
||||
.cuddle
|
||||
.state
|
||||
.actions
|
||||
.actions
|
||||
.iter()
|
||||
.find(|a| a.name == action_name)
|
||||
.ok_or(anyhow::anyhow!("failed to find {}", action_name))?;
|
||||
|
||||
action.call().await?;
|
||||
}
|
||||
("get", args) => {
|
||||
if !self.cuddle.has_project() {
|
||||
|
@ -54,7 +54,7 @@ impl Cuddle<PrepareProject> {
|
||||
}
|
||||
|
||||
impl Cuddle<PreparePlan> {
|
||||
pub async fn build_state(&self) -> anyhow::Result<Cuddle<ValidatedState>> {
|
||||
pub async fn build_state(&mut self) -> anyhow::Result<Cuddle<ValidatedState>> {
|
||||
let mut state = if let Some(project) = &self.state.project {
|
||||
let state = state::State::new();
|
||||
let raw_state = state.build_state(project, &self.state.plan).await?;
|
||||
|
@ -1,7 +1,7 @@
|
||||
use validated_project::Project;
|
||||
|
||||
use crate::{
|
||||
actions::Actions,
|
||||
actions::{Actions, ExecutableActions},
|
||||
plan::{self, ClonedPlan, PlanPathExt},
|
||||
project::{self, ProjectPlan},
|
||||
schema_validator::SchemaValidator,
|
||||
@ -43,7 +43,7 @@ impl State {
|
||||
Ok(ValidatedState {
|
||||
project: Some(project),
|
||||
plan: None,
|
||||
actions: LocalActions::default(),
|
||||
actions: ExecutableActions::default(),
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -58,20 +58,21 @@ pub struct ValidatedState {
|
||||
pub project: Option<Project>,
|
||||
pub plan: Option<Plan>,
|
||||
|
||||
pub actions: LocalActions,
|
||||
pub actions: ExecutableActions,
|
||||
}
|
||||
|
||||
impl ValidatedState {
|
||||
pub(crate) async fn build_actions(&mut self) -> anyhow::Result<&mut Self> {
|
||||
tracing::debug!("building actions");
|
||||
|
||||
let mut local_actions = LocalActions::default();
|
||||
if let Some(project) = &self.project {
|
||||
if let Some(actions) = Actions::new(&project.root, &project.value).await? {
|
||||
self.actions.add(actions);
|
||||
local_actions.add(actions);
|
||||
}
|
||||
}
|
||||
|
||||
self.actions.build().await?;
|
||||
self.actions = local_actions.build().await?;
|
||||
|
||||
Ok(self)
|
||||
}
|
||||
@ -89,12 +90,15 @@ impl LocalActions {
|
||||
self
|
||||
}
|
||||
|
||||
pub async fn build(&mut self) -> anyhow::Result<&mut Self> {
|
||||
pub async fn build(&mut self) -> anyhow::Result<ExecutableActions> {
|
||||
let mut executable_actions = ExecutableActions::default();
|
||||
|
||||
for actions in &mut self.0 {
|
||||
actions.build().await?;
|
||||
let mut exec_actions = actions.build().await?;
|
||||
executable_actions.actions.append(&mut exec_actions.actions)
|
||||
}
|
||||
|
||||
Ok(self)
|
||||
Ok(executable_actions)
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user