source: gignore/src/template.rs@ 5e61643

file_locations help logging man multi_arg trunk
Last change on this file since 5e61643 was 5e61643, checked in by Asher Mullaney <asher.mullaney@…>, 2 months ago

Completed template file location update

  • Property mode set to 100644
File size: 8.9 KB
Line 
1use std::{
2 path::{
3 Path,
4 PathBuf,
5 },
6 io::{self, Write},
7 fs,
8 os::unix::fs::MetadataExt,
9 process,
10};
11
12use anyhow::{
13 Result,
14 Error,
15 Context
16};
17
18use serde::{Serialize, Deserialize};
19
20use super::{
21 open_append,
22 open_truncate,
23};
24
25#[derive(Serialize, Deserialize, Debug)]
26pub(crate) struct Template {
27 source_file: PathBuf,
28 name: String,
29 append: bool,
30}
31
32impl Template {
33 pub(crate) fn new(source_file: &Path, name: &str, append: bool) -> Self {
34 Template {
35 source_file: source_file.to_owned(),
36 name: String::from(name),
37 append,
38 }
39 }
40
41 fn get_source_file(&self) -> &PathBuf {
42 &self.source_file
43 }
44 fn change_source_file<T: AsRef<Path>>(&mut self, new: T) {
45 self.source_file = new.as_ref().to_owned();
46 }
47 pub(crate) fn get_name(&self) -> &str {
48 &self.name
49 }
50 pub(crate) fn is_append(&self) -> bool {
51 self.append
52 }
53 fn save(&self) -> Result<()> {
54 let path = "/usr/lib/gignore/gignore_templates";
55
56 if !fs::exists(path).context("cannot search for `/usr/lib/gignore/gignore_templates`")? {
57 return Err(Error::msg("`/usr/lib/gignore/gignore_templates` does not exist"));
58 }
59
60 let mut file_handle = open_append(path.as_ref()).context("cannot open `/usr/lib/gignore/gignore_templates`")?;
61
62 let write_string = serde_json::to_string(&self).context("cannot convert template to JSON using `serde_json`")?;
63
64 file_handle.write_all(
65 format!("{write_string}\n").as_bytes()
66 ).context("cannot write to `/usr/lib/gignore/gignore_templates`")?;
67
68 Ok(())
69 }
70}
71
72
73
74fn lib_read() -> Result<Vec<Template>> {
75 let path = "/usr/lib/gignore/gignore_templates";
76
77 let mut template_vec: Vec<Template> = Vec::new();
78
79 if fs::read_to_string(path).context("cannot read `/usr/lib/gignore/gignore_templates`")?.is_empty() {
80 return Ok(template_vec);
81 }
82
83 for line in fs::read_to_string(path).context("cannot read `/usr/lib/gignore/gignore_templates`")?.lines() {
84 template_vec.push(serde_json::from_str(&line.trim()).context("cannot convert JSON to `template` instance")?);
85 }
86 Ok(template_vec)
87}
88
89pub(crate) fn find_name(name: &str) -> Result<Option<Template>> {
90 let template_vec: Vec<Template> = lib_read().context("cannot read template library")?;
91
92 for item in template_vec {
93 if item.get_name() == name {
94 return Ok(Some(item));
95 }
96 }
97 Ok(None)
98}
99
100pub(crate) fn remove(name: &str) -> Result<()> {
101 let path = "/usr/lib/gignore/gignore_templates";
102
103 let mut template_vec: Vec<Template> = lib_read().context("cannot read template library")?;
104
105 template_vec.extract_if(.., |item| item.get_name() == name).for_each(drop);
106
107 let template = match find_name(name).context(format!("cannot search for name {name} in /usr/lib/gignore/gignore_templates"))? {
108 None => {
109 eprintln!("No template exists in `/usr/lib/gignore/gignore_templates` under the name `{name}`.");
110 process::exit(0);
111 },
112 Some(t) => t,
113 };
114
115 clear().context("cannot clear template library file")?;
116
117 if template_vec.is_empty() {
118 println!("{path} is now empty.");
119 fs::write(path, b"").context("cannot write to `/usr/lib/gignore/gignore_templates`")?;
120 } else {
121 for item in template_vec {
122 item.save().context("cannot save template")?;
123 }
124 }
125
126 fs::remove_file(template.get_source_file()).context(format!("cannot remove `{}`", template.get_source_file().display()))?;
127 Ok(())
128}
129
130pub(crate) fn add(mut template: Template) -> Result<()> {
131 if !fs::exists(template.get_source_file()).context(format!("cannot search for `{}`", template.get_name()))? {
132 return Err(Error::msg(format!("The source file specified, `{}`, does not exist.", template.get_source_file().display())));
133 }
134
135 if (*(template.get_source_file())).to_str().expect("FATAL: Could not convert source_file to string!").split_terminator('.').nth(2) != Some("ggnr") {
136 eprintln!("WARNING: specified source file, `{}`, does not have the file extension for gignore templates (`.ggnr`). Continue anyway? [y/N]", template.get_source_file().display());
137
138 let mut buf = String::new();
139 io::stdin()
140 .read_line(&mut buf)
141 .context("cannot read from stdin")?;
142
143 match &*buf.to_lowercase().trim() {
144 "y" => { eprintln!("Continuing..."); },
145 _ => {
146 eprintln!("User denied operation. Exiting.");
147 process::exit(0);
148 },
149 }
150 };
151
152 let new_template_path = format!("/usr/lib/gignore/{}", template.get_source_file().display());
153
154 if fs::exists(&new_template_path).context(format!("cannot search for `{new_template_path}`"))? {
155 eprintln!("WARNING: the file `{new_template_path}` already exists. Overwrite it? [y/N]");
156
157 let mut buf = String::new();
158 io::stdin()
159 .read_line(&mut buf)
160 .context("cannot read from stdin")?;
161
162 match &*buf.to_lowercase().trim() {
163 "y" => {
164 eprintln!("Continuing...");
165
166 fs::remove_file(&new_template_path).context(format!("cannot remove {new_template_path}"))?
167 },
168 _ => {
169 eprintln!("User denied operation. Exiting.");
170 process::exit(0);
171 },
172 };
173 };
174
175 drop(
176 fs::File::create_new(&new_template_path)
177 .context(
178 format!("cannot create file `{new_template_path}`")
179 )?
180 );
181
182 let bytes_written = fs::copy(template.get_source_file(), &*new_template_path).context(format!("cannot copy bytes from `{}` to `{new_template_path}`", template.get_source_file().display()))?;
183 if !bytes_written == fs::metadata(
184 template.get_source_file()
185 )
186 .context(
187 format!("cannot read metadata of `{}`", template.get_source_file().display()))?
188 .size()
189 {
190 eprintln!("WARNING: Not all bytes of `{}` were written to `{new_template_path}`. ", template.get_source_file().display());
191 }
192
193 if find_name(template.get_name()).context("cannot search for name in template library")?.is_some() {
194 return Err(Error::msg(format!("A template with the name `{}` already exists!", template.get_name())));
195 }
196 template.change_source_file(new_template_path);
197
198 template.save().context("cannot save template")?;
199
200 Ok(())
201}
202
203fn get_template_contents(name: &str) -> Result<String> {
204 let template = find_name(name).context("cannot search for name in template library")?;
205
206 Ok(
207 fs::read_to_string(match template {
208 Some(ref template) => template,
209 None => { return Err(Error::msg(format!("No template under name `{name}`"))) },
210 }.get_source_file()).context(format!("cannot read {}", template.unwrap().get_source_file().display()))?
211 )
212}
213
214pub(crate) fn clear() -> Result<()> {
215 let path = "/usr/lib/gignore/gignore_templates";
216
217 open_truncate(path.as_ref()).context("cannot open `/usr/lib/gignore/gignore_templates` in `truncate` mode")?
218 .write_all(b"").context("cannot write to /usr/lib/gignore/gignore_templates")?;
219
220 Ok(())
221}
222
223pub(crate) fn gitignore_write(name: &str) -> Result<()> {
224 let template = find_name(name).context("cannot search for name in template library")?;
225
226 if match template {
227 Some(template) => template.is_append(),
228 None => { return Err(Error::msg(format!("No template under name `{name}`"))) },
229 } {
230 let mut file_handle = open_append(".gitignore".as_ref()).context("cannot open `.gitignore` in `append` mode")?;
231
232 file_handle.write_all(get_template_contents(name).context("cannot retrieve contents of template")?.as_bytes()).context("cannot write to `.gitignore`")?;
233
234 return Ok(());
235 }
236
237 let mut file_handle = open_truncate(".gitignore".as_ref()).context("cannot open `.gitignore` in `truncate` mode")?;
238
239 file_handle.write_all(
240 get_template_contents(name).context("cannot retrieve contents of template")?.as_bytes()
241 ).context("cannot write to `.gitignore`")?;
242
243 Ok(())
244}
245
246pub(crate) fn list(oneline: bool) -> Result<()> {
247 if !oneline {
248 for item in lib_read().context("cannot read template library")? {
249 if item.is_append() {
250 println!("{}: {} <append>", item.get_name(), item.get_source_file().display());
251 } else {
252 println!("{}: {}", item.get_name(), item.get_source_file().display());
253 }
254 }
255 return Ok(());
256 }
257
258 println!();
259 for item in lib_read().context("cannot read template library")? {
260 if item.is_append() {
261 print!("{}: {} (append), ", item.get_name(), item.get_source_file().display());
262 } else {
263 print!("{}: {}, ", item.get_name(), item.get_source_file().display());
264 }
265 }
266 println!();
267
268 Ok(())
269}
Note: See TracBrowser for help on using the repository browser.