feat: with init command

Signed-off-by: kjuulh <contact@kjuulh.io>
This commit is contained in:
2023-06-17 03:38:48 +02:00
parent 91ee9d4387
commit 6c5fed87b1
13 changed files with 1914 additions and 310 deletions

View File

@@ -0,0 +1,147 @@
use std::fs::{create_dir_all, read, read_dir};
use std::io::Write;
use clap::{ArgMatches, Command};
use crate::cli::CuddleCli;
pub fn build_command(root_cmd: Command, cli: CuddleCli) -> Command {
let mut repo_url = clap::Arg::new("repo").long("repo").short('r');
if let Ok(cuddle_template_url) = std::env::var("CUDDLE_TEMPLATE_URL") {
repo_url = repo_url.default_value(cuddle_template_url);
} else {
repo_url = repo_url.required(true);
}
let mut execute_cmd = Command::new("init")
.about("init bootstraps a repository from a template")
.arg(repo_url)
.arg(clap::Arg::new("name"))
.arg(clap::Arg::new("path"));
root_cmd.subcommand(execute_cmd)
}
pub fn execute_init(exe_submatch: &ArgMatches, cli: CuddleCli) -> anyhow::Result<()> {
let repo = exe_submatch.get_one::<String>("repo").unwrap();
let name = exe_submatch.get_one::<String>("name");
let path = exe_submatch.get_one::<String>("path");
tracing::info!("Downloading: {}", repo);
create_dir_all(std::env::temp_dir())?;
let tmpdir = tempfile::tempdir()?;
let tmpdir_path = tmpdir.path().canonicalize()?;
let output = std::process::Command::new("git")
.args(&["clone", repo, "."])
.current_dir(tmpdir_path)
.output()?;
std::io::stdout().write_all(&output.stdout)?;
std::io::stderr().write_all(&output.stderr)?;
let templates_path = tmpdir.path().join("cuddle-templates.json");
let template_path = tmpdir.path().join("cuddle-template.json");
let templates = if templates_path.exists() {
let templates = read(templates_path)?;
let templates: CuddleTemplates = serde_json::from_slice(&templates)?;
let mut single_templates = Vec::new();
for template_name in templates.templates.iter() {
let template = read(
tmpdir
.path()
.join(template_name)
.join("cuddle-template.json"),
)?;
let template = serde_json::from_slice::<CuddleTemplate>(&template)?;
single_templates.push((template_name, template))
}
single_templates
.into_iter()
.map(|(name, template)| (name.clone(), tmpdir.path().join(name), template))
.collect::<Vec<_>>()
} else if template_path.exists() {
let template = read(template_path)?;
let template = serde_json::from_slice::<CuddleTemplate>(&template)?;
vec![(template.clone().name, tmpdir.path().to_path_buf(), template)]
} else {
anyhow::bail!("No cuddle-template.json or cuddle-templates.json found");
};
let template = match name {
Some(name) => {
let template = read(tmpdir.path().join(name).join("cuddle-template.json"))?;
let template = serde_json::from_slice::<CuddleTemplate>(&template)?;
Ok((name.clone(), tmpdir.path().join(name), template))
}
None => {
if templates.len() > 1 {
let name = inquire::Select::new(
"template",
templates.iter().map(|t| t.0.clone()).collect(),
)
.with_help_message("name of which template to use")
.prompt()?;
let found_template = templates
.iter()
.find(|item| item.0 == name)
.ok_or(anyhow::anyhow!("could not find an item with that name"))?;
Ok(found_template.clone())
} else if templates.len() == 1 {
Ok(templates[0].clone())
} else {
Err(anyhow::anyhow!("No templates found, with any valid names"))
}
}
};
let (name, template_dir, template) = template?;
let path = match path {
Some(path) => path.clone(),
None => inquire::Text::new("path")
.with_help_message("to where it should be placed")
.with_default(".")
.prompt()?,
};
create_dir_all(&path)?;
let dir = std::fs::read_dir(&path)?;
if dir.count() != 0 {
anyhow::bail!("Directory {} is not empty", &path);
}
for entry in read_dir(template_dir)? {
let entry = entry?;
let entry_path = entry.path();
let name = entry.file_name();
if name == "cuddle-template.json" || name == "cuddle-templates.json" {
continue;
}
std::fs::rename(entry_path, std::path::PathBuf::from(&path).join(name))?;
}
Ok(())
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
struct CuddleTemplates {
pub templates: Vec<String>,
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
struct CuddleTemplate {
pub name: String,
}