proplate_core/template/
resolver.rs1use std::env::current_dir;
2use std::fs;
3use std::path::{Path, PathBuf};
4
5use proplate_tui::logger;
6use uuid::Uuid;
7
8use proplate_errors::{ProplateError, ProplateErrorKind, ProplateResult, TemplateErrorKind};
9use proplate_integration::git;
10
11use crate::join_path;
12
13use crate::{fs as pfs, template::Template};
14
15pub fn clone_template(location: &str, dest: &str) -> ProplateResult<Template> {
18 if !is_valid_location(location) {
19 return Err(
20 ProplateError::create(ProplateErrorKind::Template {
21 kind: TemplateErrorKind::NotFound { is_remote: false },
22 location: location.into(),
23 })
24 .with_ctx("template:clone")
25 .with_cause("The location is neither a local nor a git repo"),
26 );
27 }
28 match is_remote_uri(location) {
29 true => clone_remote_template(location),
30 false => clone_local_template(location, dest),
31 }
32}
33
34fn clone_local_template(location: &str, dest: &str) -> ProplateResult<Template> {
35 let path = join_path!(".temp", format!("{}-{}", dest, Uuid::new_v4()));
37 let from = Path::new(location);
38
39 println!(
40 "{}",
41 logger::step(&format!("Cloning local template {}...", location))
42 );
43
44 pfs::copy_fdir(from, &path, None).map_err(|e| {
45 ProplateError::create(ProplateErrorKind::Fs {
46 concerned_paths: vec![from.display().to_string(), path.display().to_string()],
47 operation: "copy_fdir".into(),
48 })
49 .with_ctx("template:local:clone")
50 .with_cause(&e.to_string())
51 })?;
52
53 template_with_filebase(path.into(), location, location.into())
54}
55
56fn clone_remote_template(uri: &str) -> ProplateResult<Template> {
57 let tail = uri.strip_prefix("https://github.com/").unwrap();
58
59 let id = tail.split("/").collect::<Vec<_>>().join("-");
61 let dest = join_path!(".temp", format!("{}-{}", id, Uuid::new_v4()));
62
63 println!(
64 "{}",
65 logger::step(&format!("Cloning template from git repo {}...", uri))
66 );
67
68 git::exec_cmd(
70 ["clone", uri, dest.to_str().unwrap()],
71 ¤t_dir().unwrap(),
72 )
73 .map_err(|_| {
74 ProplateError::create(ProplateErrorKind::Template {
75 kind: TemplateErrorKind::NotFound { is_remote: true },
76 location: uri.into(),
77 })
78 .with_ctx("template:remote:clone")
79 .with_cause("git clone failed")
80 })?;
81
82 template_with_filebase(dest, &id, uri.to_string())
83}
84
85fn template_with_filebase(path: PathBuf, id: &str, source: String) -> ProplateResult<Template> {
88 let file_list = fs::read_dir(&path)
89 .map_err(|e| {
90 ProplateError::create(ProplateErrorKind::Fs {
91 concerned_paths: vec![path.display().to_string()],
92 operation: "read_dir".into(),
93 })
94 .with_ctx("template:create")
95 .with_cause(&e.to_string())
96 })?
97 .into_iter()
98 .filter_map(|e| match e {
99 Ok(entry) => entry.file_name().to_str().map(|s| s.to_string()).or(None),
100 _ => None,
101 })
102 .collect::<Vec<_>>();
103 Ok(Template::build(id.to_string(), path, file_list, source))
104}
105
106fn is_remote_uri(uri: &str) -> bool {
107 uri.starts_with("https://github.com/")
108}
109
110fn is_local_dir(uri: &str) -> bool {
111 let path = PathBuf::from(uri);
112 path.exists() && path.is_dir()
113}
114
115fn is_valid_location(location: &str) -> bool {
116 is_remote_uri(location) || is_local_dir(location)
117}