terminal_magic/modules/
install.rs1use std::{path::{Path, PathBuf}, process::Command};
2
3use colored::Colorize;
4use indexmap::IndexMap;
5use mustache::MapBuilder;
6
7use crate::{modules::{update::update, read_config}, models::{GlobalConfig, PluginType, FileSystemEntry, PluginInfo}, prompts::read, template::{add_files_as_vars, render}};
8
9pub fn install(global_config: &GlobalConfig, git_repo: &str, plugin_name: &str) {
16 let home_path = global_config.home.join(plugin_name);
17 if home_path.exists() {
18 update(global_config, git_repo, plugin_name, false, true);
19 return;
20 }
21 let path_to_module = Path::new(git_repo).join(plugin_name);
22 if !path_to_module.exists() {
23 eprintln!(
24 "{}",
25 "Could not find module in the git repo. Did you execute `git pull`?".red()
26 );
27 std::process::exit(1);
28 }
29 let mustache = mustache::compile_path(path_to_module.join("template.sh"))
30 .expect("Could not parse mustache template");
31
32 let mut toml = read_config(&path_to_module.join("config.toml")).expect("Cannot find TOML");
33 if let Some(internal_deps) = toml.plugin_info.internal_dependencies.as_mut() {
34 for dep in internal_deps {
35 install(global_config, git_repo, dep);
36 }
37 }
38 if let Some(external_deps) = toml.plugin_info.external_dependencies.as_ref() {
39 for dep in external_deps {
40 println!(
41 "[{}] needs external dependency {}",
42 plugin_name.yellow(),
43 dep.yellow()
44 );
45 }
46 }
47 let mut mustache_map_builder = MapBuilder::new();
48 if let Some(placeholders) = toml.placeholders.as_mut() {
49 for placeholder in placeholders.iter_mut() {
50 println!("Read {}", placeholder.0);
51 let (new_mustache_map_builder, object) =
52 read(placeholder.0, placeholder.1, mustache_map_builder);
53 mustache_map_builder = new_mustache_map_builder;
54
55 mustache_map_builder = mustache_map_builder
56 .insert(placeholder.0, &object)
57 .expect("Could not parse object");
58 *placeholder.1 = object;
59 }
60 }
61 let home_path = global_config.home.join(plugin_name);
62 if std::fs::create_dir_all(&home_path).is_ok() {
63 println!("Created Plugin directory");
64 }
65 println!("Copying supporting files");
66 if let Some(files) = &toml.supporting_files {
67 mustache_map_builder = add_files_as_vars(
68 files,
69 mustache_map_builder,
70 &home_path,
71 &path_to_module,
72 &home_path,
73 true,
74 );
75 }
76 if let PluginType::RustPackage { path, git, tag } = &toml.plugin_info.plugin_type {
77 let mut install_command = Command::new("cargo");
78 if let Some(git) = git {
79 install_command
80 .env("CARGO_NET_GIT_FETCH_WITH_CLI", "true")
81 .arg("install")
82 .arg("--git")
83 .arg(git);
84 if let Some(tag) = tag {
85 install_command.arg("--tag").arg(tag);
86 }
87 } else if let Some(path) = path {
88 install_command
89 .arg("install")
90 .arg("--path")
91 .arg(&path_to_module.join(path));
92 } else {
93 panic!("either path or git should be set");
94 };
95 match install_command
96 .spawn()
97 .expect("Could not install module")
98 .wait_with_output()
99 {
100 Ok(_) => println!("Successfully installed rust-module"),
101 Err(err) => panic!("{:?}", err),
102 }
103 }
104
105 let mustache_map = mustache_map_builder.build();
106 let script = render(mustache, mustache_map);
107 write_file(global_config, toml, script, plugin_name, &path_to_module);
108}
109
110
111pub fn write_supporting_files(
112 files: &IndexMap<String, FileSystemEntry>,
113 home: &Path,
114 path_to_module: &Path,
115 cwd: &Path,
116) {
117 for (_, file) in files {
118 match file {
119 FileSystemEntry::File {
120 version,
121 path,
122 destination,
123 } => {
124 let destination = if let Some(destination) = destination {
125 destination
126 .to_owned()
127 .parse()
128 .expect("Could not parse path")
129 } else {
130 cwd.join(path)
131 };
132 if std::fs::remove_file(&destination).is_ok() {
133 println!(
134 "{:?} existed, overwriting with new version: {}",
135 destination, version
136 );
137 }
138 let source_relative = path.parse::<PathBuf>().expect("Source path is invalid");
139 let source = path_to_module.join(source_relative);
140 if let Err(err) = std::fs::copy(&source, &destination) {
141 panic!(
142 "Could not copy file from source {:?} to {:?}\n{:?}",
143 source, destination, err
144 );
145 }
146 }
147 FileSystemEntry::Directory {
148 version,
149 path,
150 destination,
151 files,
152 } => {
153 let destination = if let Some(destination) = destination {
154 destination
155 .to_owned()
156 .parse()
157 .expect("Could not parse path")
158 } else {
159 cwd.join(path)
160 };
161
162 if std::fs::create_dir_all(&destination).is_ok() {
163 println!("Created {:?} [{}]", destination, version);
164 }
165 write_supporting_files(files, home, path_to_module, &destination);
166 }
167 }
168 }
169}
170
171
172pub fn write_file(global_config: &GlobalConfig, toml: PluginInfo, script: String, plugin_name: &str, path_to_module: &Path) {
173 let home_path = global_config.home.join(plugin_name);
174 if std::fs::create_dir_all(&home_path).is_ok() {
175 println!("Created directory");
176 }
177 if std::fs::remove_file(home_path.join("script.sh")).is_ok() {
178 println!("script.sh already existed");
179 }
180 if std::fs::copy(
181 path_to_module.join("config.toml"),
182 home_path.join("config.toml"),
183 )
184 .is_ok()
185 {}
186
187 if std::fs::write(home_path.join("script.sh"), script).is_ok() {
192 if std::fs::remove_file(home_path.join("data.toml")).is_ok() {
193 println!("data.toml File existed");
194 }
195 if std::fs::write(
196 home_path.join("data.toml"),
197 toml::to_vec(&toml).expect("could not serialize data"),
198 )
199 .is_ok()
200 {
201 println!("Successfully wrote plugin {}!", plugin_name);
202 }
203 }
204}