use crate::{
method::{Fetchable, Method, Methodical},
schemes::Configuration,
Error, Result,
};
use dircpy::CopyBuilder;
use regex::{Regex, RegexBuilder};
use std::path::Path;
use std::{collections::HashMap, fs, path::PathBuf, sync::LazyLock};
use tempfile::{tempdir, TempDir};
use url::Url;
pub static REGEX: LazyLock<Regex> =
LazyLock::new(|| RegexBuilder::new(r"@([a-zA-Z0-9-_]+)@").build().unwrap());
#[derive(Default, Debug)]
pub struct ManageBuilder {
remote: Option<Url>,
temporary: Option<TempDir>,
method: Option<Method>,
}
impl ManageBuilder {
pub fn new() -> Self {
Self {
remote: None,
temporary: None,
method: None,
}
}
pub fn tempdir(self) -> Result<Self> {
tempdir().map_err(Error::IOError).map(|t| Self {
remote: self.remote,
temporary: Some(t),
method: self.method,
})
}
pub fn source<T: AsRef<str>>(self, url: T) -> Result<Self> {
Url::parse(url.as_ref())
.map_err(Error::UrlError)
.map(|l| Self {
temporary: self.temporary,
method: self.method,
remote: Some(l),
})
}
pub fn fetch_method<T: Methodical>(self, method: T) -> Result<Self> {
if self.temporary.is_none() || self.remote.is_none() {
return Err(Error::InsufficientArgumentsToDecide);
}
let destination = self.temporary.unwrap();
let method = method.to_method(
self.remote.clone().unwrap(),
destination.path().to_path_buf(),
);
Ok(Self {
method: Some(method),
remote: self.remote,
temporary: Some(destination),
})
}
pub fn build(self) -> Result<Manager> {
Ok(Manager::new(
self.remote.unwrap(),
self.temporary.unwrap(),
self.method.unwrap(),
))
}
}
#[derive(Debug)]
pub struct Manager {
remote: Url,
temporary: TempDir,
method: Method,
template: Configuration,
globals: HashMap<String, String>,
}
impl Manager {
pub fn new(remote: Url, temporary: TempDir, method: Method) -> Self {
Self {
remote,
temporary,
method,
template: Default::default(),
globals: HashMap::default(),
}
}
pub fn instantiate(self) -> Result<Self> {
self.method.fetch().map(|_| Self {
remote: self.remote,
temporary: self.temporary,
method: self.method,
template: self.template,
globals: self.globals,
})
}
pub fn parse(self) -> Result<Self> {
Configuration::surely_template(self.temporary.path().to_path_buf(), 1).map(|t| Self {
template: t,
remote: self.remote,
temporary: self.temporary,
method: self.method,
globals: self.globals,
})
}
pub fn evaluate(mut self) -> Result<Self> {
self.template
.clone()
.template()?
.computable()
.compute(&mut self.globals)
.map(|_| self)
}
pub fn recursively_copy(self, destination: PathBuf) -> Result<Self> {
if !Path::new(&destination).exists() {
fs::create_dir_all(&destination)?
}
CopyBuilder::new(self.template.clone().template()?.path(), destination)
.overwrite(true)
.overwrite_if_newer(true)
.overwrite_if_size_differs(true)
.run()?;
Ok(self)
}
}
pub trait Glubtastic {
fn globs<T: AsRef<str>>(&self, text: T) -> Vec<String>;
}
impl Glubtastic for HashMap<String, String> {
fn globs<T: AsRef<str>>(&self, text: T) -> Vec<String> {
REGEX
.captures_iter(text.as_ref())
.map(|caps| {
let (_, [input]) = caps.extract();
input.to_owned()
})
.collect::<Vec<String>>()
}
}