terminal_magic/modules/
update.rs1use std::{path::Path, process::Command};
2
3use colored::Colorize;
4use indexmap::IndexMap;
5use mustache::MapBuilder;
6
7use crate::{models::{GlobalConfig, ModuleState, EntryType, PluginType}, prompts::{boolean_prompt, read, read_array, get_short_names}, modules::print_diff, template::{add_files_as_vars, render}};
8
9use super::{read_config, check_module_state, install::{install, write_file}, get_old_script};
10
11pub fn update(
17 global_config: &GlobalConfig,
18 git_repo: &str,
19 plugin_name: &str,
20 fail_on_error: bool,
21 silent: bool,
22) {
23 let home_path = global_config.home.join(plugin_name);
24 if !home_path.exists() {
25 eprintln!("module is not installed");
26 if fail_on_error {
27 std::process::exit(1);
28 }
29 return;
30 }
31 let path_to_module = Path::new(git_repo).join(plugin_name);
32 if !path_to_module.exists() {
33 eprintln!(
34 "{}",
35 "Could not find module in the git repo. Did you execute `git pull`?".red()
36 );
37 if fail_on_error {
38 std::process::exit(1);
39 }
40 return;
41 }
42 let mustache = mustache::compile_path(path_to_module.join("template.sh"))
43 .expect("Could not parse mustache template");
44
45 let mut toml = read_config(&home_path.join("data.toml")).expect("Cannot find TOML");
46 let old_toml = toml.clone();
47 let old_config = read_config(&home_path.join("config.toml"))
48 .expect("Cannot find old config (maybe you did update terminal-magic)");
49 let new_config =
50 read_config(&path_to_module.join("config.toml")).expect("module config not found");
51 let mut mustache_map_builder = MapBuilder::new();
52 if old_config != new_config {
53 println!("{}", "Config changed check the changes".yellow());
54
55 let old_config_str = toml::to_string(&old_config).unwrap();
56 let new_config_str = toml::to_string(&new_config).unwrap();
57 print_diff(&old_config_str, &new_config_str);
58 if old_config.placeholders != new_config.placeholders {
59 let mut update_map = IndexMap::new();
60 if let Some(new_placeholders) = &new_config.placeholders {
61 for (key, entry) in new_placeholders {
62 if let Some(v) = toml.placeholders.as_ref().and_then(|a| a.get(key)) {
63 update_map.insert(key.to_owned(), v.to_owned());
64 } else {
65 let (new_mustache_map_builder, object) =
67 read(key, entry, mustache_map_builder);
68 mustache_map_builder = new_mustache_map_builder;
69 update_map.insert(key.to_owned(), object);
70 }
71 }
72 toml.placeholders = Some(update_map);
73 } else {
74 toml.placeholders = None;
75 }
76 }
77 }
78 toml.plugin_info = new_config.plugin_info.clone();
79
80 if let Some(internal_deps) = toml.plugin_info.internal_dependencies.as_mut() {
81 for dep in internal_deps {
82 match check_module_state(global_config, git_repo, dep) {
83 ModuleState::NotInstalled => install(global_config, git_repo, dep),
84 ModuleState::UpToDate => {}
85 ModuleState::NeedsUpdate(reason) => {
86 println!("Update since: {:?}", reason);
87 update(global_config, git_repo, dep, false, true)
88 }
89 }
90 }
91 }
92 if let Some(external_deps) = toml.plugin_info.external_dependencies.as_ref() {
93 for dep in external_deps {
94 println!(
95 "[{}] needs external dependency {}",
96 plugin_name.yellow(),
97 dep.yellow()
98 );
99 }
100 }
101
102 if let Some(placeholders) = toml.placeholders.as_mut() {
103 for placeholder in placeholders.iter_mut() {
104 if old_toml
105 .placeholders
106 .as_ref()
107 .and_then(|a| a.get(placeholder.0))
108 .is_some()
109 {
110 if let EntryType::Array(arr) = placeholder.1 {
111 if !silent && boolean_prompt(&format!("Add new elements [{}]? ", placeholder.0))
112 {
113 if old_config
114 .placeholders
115 .as_ref()
116 .unwrap()
117 .get(placeholder.0)
118 .is_some()
119 {
120 let (new_mustache_map_builder, object) =
121 read_array(placeholder.0, &arr[0], mustache_map_builder);
122 mustache_map_builder = new_mustache_map_builder;
123 arr.extend(if let EntryType::Array(a) = object {
124 a
125 } else {
126 unreachable!("read_array MUST always return an EntryType::Array")
127 });
128 }
129 } else {
130 let name = get_short_names(arr);
131 mustache_map_builder = mustache_map_builder
132 .insert_str(format!("{}_shortNames", placeholder.0), name);
133 }
134 }
135 }
136 mustache_map_builder = mustache_map_builder
137 .insert(placeholder.0, &placeholder.1)
138 .expect("Could not parse object");
139 }
140 }
141 let should_overwrite = boolean_prompt("Update supporting files?");
142
143 if let Some(files) = &new_config.supporting_files {
144 let home_path = global_config.home.join(plugin_name);
145 mustache_map_builder = add_files_as_vars(
146 files,
147 mustache_map_builder,
148 &home_path,
149 &path_to_module,
150 &home_path,
151 should_overwrite,
152 );
153 }
154
155 let mustache_map = mustache_map_builder.build();
156 let script = render(mustache, mustache_map);
157 let old_script = get_old_script(global_config, plugin_name);
158
159 print_diff(&old_script, &script);
160
161 if !boolean_prompt("Update?") {
162 return;
163 }
164
165 if let PluginType::RustPackage { path, git, tag } = new_config.plugin_info.plugin_type {
166 let mut install_command = Command::new("cargo");
167 if let Some(git) = git {
168 install_command
169 .env("CARGO_NET_GIT_FETCH_WITH_CLI", "true")
170 .arg("install")
171 .arg("--git")
172 .arg(git);
173 if let Some(tag) = tag {
174 install_command.arg("--tag").arg(tag);
175 }
176 } else if let Some(path) = path {
177 install_command
178 .arg("install")
179 .arg("--path")
180 .arg(&path_to_module.join(path));
181 } else {
182 panic!("either path or git should be set");
183 };
184 match install_command
185 .spawn()
186 .expect("Could not install module")
187 .wait_with_output()
188 {
189 Ok(_) => println!("Successfully installed rust-module"),
190 Err(err) => panic!("{:?}", err),
191 }
192 }
193 write_file(global_config, toml, script, plugin_name, &path_to_module);
194}