kjuulh 7804eaa667
feat: enable actual actions
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-10-26 12:55:37 +02:00

136 lines
3.7 KiB
Rust

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);
Self { cli, cuddle }
}
pub async fn setup(mut self) -> anyhow::Result<Self> {
let commands = self.get_commands().await?;
self.cli = self.cli.subcommands(commands);
self.cli = Subcommands::augment_subcommands(self.cli);
// TODO: Add global
// TODO: Add components
Ok(self)
}
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)
.subcommands(actions.as_slice()),
clap::Command::new("get")
.about(GetCommand::description())
.arg(
clap::Arg::new("query")
.required(true)
.help("query is how values are extracted, '.project.name' etc"),
),
])
}
pub async fn execute(self) -> anyhow::Result<()> {
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"))?
{
("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() {
anyhow::bail!("get is not available without a project");
}
let query = args
.get_one::<String>("query")
.ok_or(anyhow!("query is required"))?;
let res = GetCommand::new(self.cuddle).execute(query).await?;
std::io::stdout().write_all(res.as_bytes())?;
std::io::stdout().write_all("\n".as_bytes())?;
}
_ => {}
}
Ok(())
}
async fn add_project_commands(&self) -> anyhow::Result<Vec<clap::Command>> {
if let Some(_project) = self.cuddle.state.project.as_ref() {
// Add project level commands
return Ok(vec![]);
}
Ok(Vec::new())
}
async fn add_plan_commands(self) -> anyhow::Result<Self> {
if let Some(_plan) = self.cuddle.state.plan.as_ref() {
// Add plan level commands
}
Ok(self)
}
}