2022-08-14 20:19:29 +02:00

183 lines
5.6 KiB
Rust

mod subcommands;
use std::{
path::PathBuf,
sync::{Arc, Mutex},
};
use clap::Command;
use crate::{
actions::CuddleAction,
context::{CuddleContext, CuddleTreeType},
model::*,
util::git::GitCommit,
};
use self::subcommands::render_template::RenderTemplateCommand;
#[derive(Debug, Clone)]
pub struct CuddleCli<'a> {
scripts: Vec<CuddleAction>,
variables: Vec<CuddleVariable>,
context: Arc<Mutex<Vec<CuddleContext>>>,
command: Option<Command<'a>>,
tmp_dir: Option<PathBuf>,
}
impl<'a> CuddleCli<'a> {
pub fn new(context: Arc<Mutex<Vec<CuddleContext>>>) -> anyhow::Result<CuddleCli<'a>> {
let mut cli = CuddleCli {
scripts: vec![],
variables: vec![],
context: context.clone(),
command: None,
tmp_dir: None,
};
cli = cli
.process_variables()
.process_scripts()
.process_templates()?
.build_cli();
Ok(cli)
}
fn process_variables(mut self) -> Self {
if let Ok(context_iter) = self.context.clone().lock() {
for ctx in context_iter.iter() {
if let Some(variables) = ctx.plan.vars.clone() {
for (name, var) in variables {
self.variables.push(CuddleVariable::new(name, var))
}
}
if let CuddleTreeType::Root = ctx.node_type {
let mut temp_path = ctx.path.clone();
temp_path.push(".cuddle/tmp");
self.variables.push(CuddleVariable::new(
"tmp".into(),
temp_path.clone().to_string_lossy().to_string(),
));
self.tmp_dir = Some(temp_path);
}
}
}
match GitCommit::new() {
Ok(commit) => self.variables.push(CuddleVariable::new(
"commit_sha".into(),
commit.commit_sha.clone(),
)),
Err(e) => {
log::debug!("{}", e);
}
}
self
}
fn process_scripts(mut self) -> Self {
if let Ok(context_iter) = self.context.clone().lock() {
for ctx in context_iter.iter() {
if let Some(scripts) = ctx.plan.scripts.clone() {
for (name, script) in scripts {
self.scripts
.push(CuddleAction::new(script.clone(), ctx.path.clone(), name))
}
}
}
}
self
}
fn process_templates(self) -> anyhow::Result<Self> {
if let None = self.tmp_dir {
log::debug!("cannot process template as bare bones cli");
return Ok(self);
}
// Make sure tmp_dir exists and clean it up first
let tmp_dir = self
.tmp_dir
.clone()
.ok_or(anyhow::anyhow!("tmp_dir does not exist aborting"))?;
if tmp_dir.exists() && tmp_dir.ends_with("tmp") {
std::fs::remove_dir_all(tmp_dir.clone())?;
}
std::fs::create_dir_all(tmp_dir.clone())?;
// Handle all templating with variables and such.
// TODO: use actual templating engine, for new we just copy templates to the final folder
if let Ok(context_iter) = self.context.clone().lock() {
for ctx in context_iter.iter() {
let mut template_path = ctx.path.clone();
template_path.push("templates");
log::trace!("template path: {}", template_path.clone().to_string_lossy());
if !template_path.exists() {
continue;
}
for file in std::fs::read_dir(template_path)?.into_iter() {
let f = file?;
let mut dest_file = tmp_dir.clone();
dest_file.push(f.file_name());
std::fs::copy(f.path(), dest_file)?;
}
}
}
Ok(self)
}
fn build_cli(mut self) -> Self {
let mut root_cmd = Command::new("cuddle")
.version("1.0")
.author("kjuulh <contact@kasperhermansen.com>")
.about("cuddle is your domain specific organization tool. It enabled widespread sharing through repositories, as well as collaborating while maintaining speed and integrity")
.subcommand_required(true)
.arg_required_else_help(true)
.propagate_version(true);
root_cmd = subcommands::x::build_command(root_cmd, self.clone());
root_cmd = subcommands::render_template::build_command(root_cmd);
self.command = Some(root_cmd);
self
}
pub fn execute(self) -> anyhow::Result<Self> {
if let Some(mut cli) = self.command.clone() {
let matches = cli.clone().get_matches();
let res = match matches.subcommand() {
Some(("x", exe_submatch)) => subcommands::x::execute_x(exe_submatch, self.clone()),
Some(("render_template", sub_matches)) => {
RenderTemplateCommand::from_matches(sub_matches, self.clone())
.and_then(|cmd| cmd.execute())?;
Ok(())
}
_ => Err(anyhow::anyhow!("could not find a match")),
};
match res {
Ok(()) => {}
Err(e) => {
let _ = cli.print_long_help();
return Err(e);
}
}
}
Ok(self)
}
}