use std::io::Write;
use std::path::PathBuf;
use crate::engine::{interface::PatinaInterface, PatinaEngine};
use clap::{Args, Parser, Subcommand};
use log::info;
#[derive(Parser, Debug)]
#[clap(name = "dotpatina", version)]
pub struct PatinaCli {
#[clap(flatten)]
global_options: GlobalOptions,
#[clap(subcommand)]
command: Command,
}
#[derive(Debug, Args)]
struct GlobalOptions {
#[command(flatten)]
verbosity: clap_verbosity_flag::Verbosity,
}
#[derive(Debug, Subcommand)]
enum Command {
#[clap(about = "Render a patina to stdout")]
Render {
#[clap(flatten)]
options: PatinaCommandOptions,
},
#[clap(about = "Render and apply a patina")]
Apply {
#[clap(flatten)]
options: PatinaCommandOptions,
#[clap(long = "no-input")]
no_input: bool,
#[clap(long = "no-trash")]
no_trash: bool,
},
}
#[derive(Debug, Args)]
struct PatinaCommandOptions {
#[clap(flatten)]
global_options: GlobalOptions,
patina_path: PathBuf,
#[clap(long = "no-color")]
no_color: bool,
#[clap(short = 't', long = "tags", help = "A set of tags to filter on")]
tags: Vec<String>,
#[clap(short = 'f', long = "vars", help = "A set of variables files")]
variables_files: Vec<PathBuf>,
}
impl PatinaCli {
pub fn parse_args() -> PatinaCli {
PatinaCli::parse()
}
pub fn run(&mut self) {
env_logger::Builder::new()
.filter_level(self.global_options.verbosity.into())
.init();
let mut pi = CliPatinaInterface::new();
let result = match &self.command {
Command::Render { options } => options.engine(&pi).render_patina(),
Command::Apply {
options,
no_input,
no_trash,
} => {
pi.set_is_input_enabled(!*no_input);
options.engine(&pi).apply_patina(!*no_trash)
}
};
if let Err(e) = result {
panic!("{:?}", e)
}
}
}
struct CliPatinaInterface {
is_input_enabled: bool,
}
impl CliPatinaInterface {
fn new() -> CliPatinaInterface {
CliPatinaInterface {
is_input_enabled: true,
}
}
}
impl PatinaInterface for CliPatinaInterface {
fn output<S>(&self, s: S)
where
S: Into<String>,
{
print!("{}", s.into());
let _ = std::io::stdout().flush();
}
fn set_is_input_enabled(&mut self, value: bool) {
self.is_input_enabled = value
}
fn is_input_enabled(&self) -> bool {
self.is_input_enabled
}
}
impl PatinaCommandOptions {
fn engine<'a, PI>(&self, pi: &'a PI) -> PatinaEngine<'a, PI>
where
PI: PatinaInterface,
{
let engine = PatinaEngine::new(
pi,
&self.patina_path,
self.tags.clone(),
self.variables_files.clone(),
);
info!(
r#"New PatinaEngine
path = {}
tags = {:?}
"#,
self.patina_path.display(),
self.tags
);
if self.no_color {
colored::control::set_override(false);
}
engine
}
}