feat: WIP setup actions

Signed-off-by: kjuulh <contact@kjuulh.io>
This commit is contained in:
2024-10-24 22:59:27 +02:00
parent dfa70b3485
commit db49af5fa2
16 changed files with 815 additions and 11 deletions

View File

@@ -0,0 +1,93 @@
use std::{
collections::BTreeMap,
path::{Path, PathBuf},
};
use rust_builder::RustActionsBuilder;
use crate::state::validated_project::Value;
pub mod builder;
pub mod rust_builder {
use std::path::PathBuf;
use super::ExecutableActions;
pub struct RustActionsBuilder {
root_path: PathBuf,
}
impl RustActionsBuilder {
pub fn new(root_path: PathBuf) -> Self {
Self { root_path }
}
pub async fn build(&self) -> anyhow::Result<ExecutableActions> {
Ok(ExecutableActions::default())
}
}
}
pub struct Actions {
variants: Vec<ActionVariant>,
}
impl Actions {
pub async fn new(path: &Path, value: &Value) -> anyhow::Result<Option<Self>> {
let Some(project) = value.get(&["project", "actions"]) else {
tracing::debug!("found no actions folder");
return Ok(None);
};
let mut variants = Vec::default();
if let Some(Value::Bool(true)) = project.get(&["rust"]) {
tracing::debug!("rust actions enabled");
variants.push(ActionVariant::Rust {
root_path: path.to_path_buf(),
});
} else {
tracing::trace!("rust actions not enabled");
}
Ok(Some(Self { variants }))
}
pub async fn build(&mut self) -> anyhow::Result<Vec<ExecutableActions>> {
let mut executable_actions = Vec::default();
for variant in &mut self.variants {
match variant {
ActionVariant::Rust { root_path } => {
let actions = RustActionsBuilder::new(root_path.clone()).build().await?;
executable_actions.push(actions);
}
ActionVariant::Docker => todo!(),
}
}
Ok(executable_actions)
}
}
pub enum ActionVariant {
Rust { root_path: PathBuf },
Docker,
}
#[derive(Default)]
pub struct ExecutableActions {
actions: Vec<ExecutableAction>,
}
pub struct ExecutableAction {
name: String,
description: String,
flags: BTreeMap<String, ExecutableActionFlag>,
}
pub enum ExecutableActionFlag {
String,
Bool,
}

View File

@@ -0,0 +1 @@
pub struct ActionsBuilder {}

View File

@@ -1,17 +1,24 @@
use std::{borrow::BorrowMut, io::Write};
use std::io::Write;
use anyhow::anyhow;
use clap::{FromArgMatches, Subcommand};
use get_command::GetCommand;
use crate::{cuddle_state::Cuddle, state::ValidatedState};
mod get_command;
mod init_command;
pub struct Cli {
cli: clap::Command,
cuddle: Cuddle<ValidatedState>,
}
#[derive(clap::Parser, Debug)]
pub enum Subcommands {
Init(init_command::InitCommand),
}
impl Cli {
pub fn new(cuddle: Cuddle<ValidatedState>) -> Self {
let cli = clap::Command::new("cuddle").subcommand_required(true);
@@ -24,6 +31,8 @@ impl Cli {
self.cli = self.cli.subcommands(commands);
self.cli = Subcommands::augment_subcommands(self.cli);
// TODO: Add global
// TODO: Add components
@@ -44,9 +53,17 @@ impl Cli {
}
pub async fn execute(self) -> anyhow::Result<()> {
match self
.cli
.get_matches_from(std::env::args())
let matches = self.cli.get_matches_from(std::env::args());
if let Ok(subcommand) = Subcommands::from_arg_matches(&matches) {
match subcommand {
Subcommands::Init(init_command) => {
init_command.execute(&self.cuddle).await?;
}
}
}
match matches
.subcommand()
.ok_or(anyhow::anyhow!("failed to find subcommand"))?
{

View File

@@ -0,0 +1,31 @@
use clap::Parser;
use rust_action::RustAction;
use crate::{cuddle_state::Cuddle, state::ValidatedState};
pub mod rust_action;
#[derive(Parser, Debug)]
#[command(subcommand_required = true)]
pub struct InitCommand {
#[clap(subcommand)]
commands: InitCommands,
}
#[derive(clap::Parser, Debug)]
pub enum InitCommands {
#[clap(name = "actions:rust")]
RustAction(RustAction),
}
impl InitCommand {
pub async fn execute(&self, cuddle: &Cuddle<ValidatedState>) -> anyhow::Result<()> {
match &self.commands {
InitCommands::RustAction(rust_action) => {
rust_action.execute(cuddle).await?;
}
}
Ok(())
}
}

View File

@@ -0,0 +1,13 @@
use crate::{cuddle_state::Cuddle, state::ValidatedState};
#[derive(clap::Parser, Debug)]
pub struct RustAction {}
impl RustAction {
pub async fn execute(&self, cuddle: &Cuddle<ValidatedState>) -> anyhow::Result<()> {
let project = cuddle.must_project()?;
let root = &project.root;
Ok(())
}
}

View File

@@ -1,5 +1,6 @@
use crate::plan::{ClonedPlan, Plan};
use crate::project::ProjectPlan;
use crate::state::validated_project::Project;
use crate::state::{self, ValidatedState};
pub struct Start {}
@@ -54,7 +55,7 @@ impl Cuddle<PrepareProject> {
impl Cuddle<PreparePlan> {
pub async fn build_state(&self) -> anyhow::Result<Cuddle<ValidatedState>> {
let state = if let Some(project) = &self.state.project {
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?;
@@ -63,6 +64,8 @@ impl Cuddle<PreparePlan> {
ValidatedState::default()
};
state.build_actions().await?;
Ok(Cuddle { state })
}
}
@@ -79,4 +82,13 @@ impl Cuddle<ValidatedState> {
false
}
pub fn project(&self) -> Option<&Project> {
self.state.project.as_ref()
}
pub fn must_project(&self) -> anyhow::Result<&Project> {
self.project()
.ok_or(anyhow::anyhow!("project is not available in this context"))
}
}

View File

@@ -1,6 +1,7 @@
use cli::Cli;
use cuddle_state::Cuddle;
mod actions;
mod cli;
mod cuddle_state;
mod plan;

View File

@@ -1,6 +1,7 @@
use validated_project::Project;
use crate::{
actions::Actions,
plan::{self, ClonedPlan, PlanPathExt},
project::{self, ProjectPlan},
schema_validator::SchemaValidator,
@@ -42,6 +43,7 @@ impl State {
Ok(ValidatedState {
project: Some(project),
plan: None,
actions: LocalActions::default(),
})
}
}
@@ -55,6 +57,51 @@ pub struct RawState {
pub struct ValidatedState {
pub project: Option<Project>,
pub plan: Option<Plan>,
pub actions: LocalActions,
}
impl ValidatedState {
pub(crate) async fn build_actions(&mut self) -> anyhow::Result<&mut Self> {
tracing::debug!("building actions");
if let Some(project) = &self.project {
if let Some(actions) = Actions::new(&project.root, &project.value).await? {
self.actions.add(actions);
}
}
self.actions.build().await?;
Ok(self)
}
}
pub struct Plan {}
#[derive(Default)]
pub struct LocalActions(Vec<Actions>);
impl LocalActions {
pub fn add(&mut self, actions: Actions) -> &mut Self {
self.0.push(actions);
self
}
pub async fn build(&mut self) -> anyhow::Result<&mut Self> {
for actions in &mut self.0 {
actions.build().await?;
}
Ok(self)
}
}
impl std::ops::Deref for LocalActions {
type Target = Vec<Actions>;
fn deref(&self) -> &Self::Target {
&self.0
}
}

View File

@@ -73,3 +73,18 @@ impl From<&toml::Value> for Value {
}
}
}
impl Value {
pub fn get(&self, path: &[&str]) -> Option<&Value> {
match path.split_first() {
Some((current, rest)) => match self {
Value::Map(map) => match map.get(&current.to_string()) {
Some(value) => value.get(rest),
None => None,
},
_ => None,
},
None => Some(self),
}
}
}