libimagwikifrontend/
lib.rs1#![forbid(unsafe_code)]
21
22extern crate clap;
23extern crate regex;
24extern crate filters;
25#[macro_use] extern crate log;
26#[macro_use] extern crate failure;
27extern crate resiter;
28
29extern crate libimagrt;
30extern crate libimagerror;
31extern crate libimagstore;
32extern crate libimagwiki;
33extern crate libimagentryedit;
34extern crate libimagentrylink;
35extern crate libimagutil;
36
37use std::io::Write;
38use failure::Fallible as Result;
39use failure::ResultExt;
40use failure::Error;
41use failure::err_msg;
42use clap::App;
43use resiter::AndThen;
44
45use libimagrt::runtime::Runtime;
46use libimagrt::application::ImagApplication;
47use libimagentryedit::edit::{Edit, EditHeader};
48use libimagwiki::store::WikiStore;
49use libimagwiki::entry::WikiEntry;
50
51mod ui;
52
53pub enum ImagWiki {}
58impl ImagApplication for ImagWiki {
59 fn run(rt: Runtime) -> Result<()> {
60 let wiki_name = rt.cli().value_of("wikiname").unwrap_or("default");
61 trace!("wiki_name = {}", wiki_name);
62 trace!("calling = {:?}", rt.cli().subcommand_name());
63
64 match rt.cli().subcommand_name().ok_or_else(|| err_msg("No subcommand called"))? {
65 "list" => list(&rt, wiki_name),
66 "idof" => idof(&rt, wiki_name),
67 "create" => create(&rt, wiki_name),
68 "create-wiki" => create_wiki(&rt),
69 "show" => show(&rt, wiki_name),
70 "delete" => delete(&rt, wiki_name),
71 other => {
72 debug!("Unknown command");
73 if rt.handle_unknown_subcommand("imag-wiki", other, rt.cli())?.success() {
74 Ok(())
75 } else {
76 Err(err_msg("Failed to handle unknown subcommand"))
77 }
78 }
79 } }
81
82 fn build_cli<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
83 ui::build_ui(app)
84 }
85
86 fn name() -> &'static str {
87 env!("CARGO_PKG_NAME")
88 }
89
90 fn description() -> &'static str {
91 "Personal wiki"
92 }
93
94 fn version() -> &'static str {
95 env!("CARGO_PKG_VERSION")
96 }
97}
98
99
100fn list(rt: &Runtime, wiki_name: &str) -> Result<()> {
101 let scmd = rt.cli().subcommand_matches("list").unwrap(); let prefix = if scmd.is_present("list-full") {
103 format!("{}/", rt.store().path().display())
104 } else {
105 String::from("")
106 };
107
108 let out = rt.stdout();
109 let mut outlock = out.lock();
110
111 rt.store()
112 .get_wiki(wiki_name)?
113 .ok_or_else(|| format_err!("No wiki '{}' found", wiki_name))?
114 .all_ids()?
115 .and_then_ok(|id| writeln!(outlock, "{}{}", prefix, id).map_err(Error::from))
116 .collect::<Result<Vec<_>>>()
117 .map(|_| ())
118}
119
120fn idof(rt: &Runtime, wiki_name: &str) -> Result<()> {
121 let scmd = rt.cli().subcommand_matches("idof").unwrap(); let entryname = scmd
124 .value_of("idof-name")
125 .map(String::from)
126 .unwrap(); let out = rt.stdout();
129 let mut lock = out.lock();
130
131 rt.store()
132 .get_wiki(wiki_name)?
133 .ok_or_else(|| format_err!("No wiki '{}' found", wiki_name))?
134 .get_entry(&entryname)?
135 .ok_or_else(|| format_err!("Entry '{}' in wiki '{}' not found!", entryname, wiki_name))
136 .and_then(|entry| {
137 let id = entry.get_location().clone();
138 let prefix = if scmd.is_present("idof-full") {
139 format!("{}/", rt.store().path().display())
140 } else {
141 String::from("")
142 };
143
144 writeln!(lock, "{}{}", prefix, id).map_err(Error::from)
145 })
146}
147
148fn create(rt: &Runtime, wiki_name: &str) -> Result<()> {
149 let scmd = rt.cli().subcommand_matches("create").unwrap(); let name = String::from(scmd.value_of("create-name").unwrap()); let wiki = rt
153 .store()
154 .get_wiki(&wiki_name)?
155 .ok_or_else(|| format_err!("No wiki '{}' found", wiki_name))?;
156
157 let mut entry = wiki.create_entry(name)?;
158
159 if !scmd.is_present("create-noedit") {
160 if scmd.is_present("create-editheader") {
161 entry.edit_header_and_content(rt)?;
162 } else {
163 entry.edit_content(rt)?;
164 }
165 }
166
167 if let Err(e) = entry
168 .autolink(rt.store())
169 .context("Linking has failed. Trying to safe the entry now. Please investigate by hand if this succeeds.")
170 {
171 rt.store().update(&mut entry).context("Safed entry")?;
172 return Err(e).map_err(Error::from)
173 }
174
175 let id = entry.get_location();
176
177 if scmd.is_present("create-printid") {
178 let out = rt.stdout();
179 let mut lock = out.lock();
180
181 writeln!(lock, "{}", id)?;
182 }
183
184 rt.report_touched(&id).map_err(Error::from)
185}
186
187fn create_wiki(rt: &Runtime) -> Result<()> {
188 let scmd = rt.cli().subcommand_matches("create-wiki").unwrap(); let wiki_name = String::from(scmd.value_of("create-wiki-name").unwrap()); let (_, index) = rt.store().create_wiki(&wiki_name)?;
191
192 rt.report_touched(index.get_location()).map_err(Error::from)
193}
194
195fn show(rt: &Runtime, wiki_name: &str) -> Result<()> {
196 use filters::filter::Filter;
197
198 let scmd = rt.cli().subcommand_matches("show").unwrap(); struct NameFilter(Option<Vec<String>>);
201 impl Filter<String> for NameFilter {
202 fn filter(&self, e: &String) -> bool {
203 match self.0 {
204 Some(ref v) => v.contains(e),
205 None => false,
206 }
207 }
208 }
209
210 let namefilter = NameFilter(scmd
211 .values_of("show-name")
212 .map(|v| v.map(String::from).collect::<Vec<String>>()));
213
214 let wiki = rt
215 .store()
216 .get_wiki(&wiki_name)?
217 .ok_or_else(|| format_err!("No wiki '{}' found", wiki_name))?;
218
219 let out = rt.stdout();
220 let mut outlock = out.lock();
221
222 scmd.values_of("show-name")
223 .unwrap() .map(String::from)
225 .filter(|e| namefilter.filter(e))
226 .map(|name| {
227 let entry = wiki
228 .get_entry(&name)?
229 .ok_or_else(|| format_err!("No wiki entry '{}' found in wiki '{}'", name, wiki_name))?;
230
231 writeln!(outlock, "{}", entry.get_location())?;
232 writeln!(outlock, "{}", entry.get_content())?;
233
234 rt.report_touched(entry.get_location()).map_err(Error::from)
235 })
236 .collect::<Result<Vec<_>>>()
237 .map(|_| ())
238}
239
240fn delete(rt: &Runtime, wiki_name: &str) -> Result<()> {
241 use libimagentrylink::linkable::Linkable;
242
243 let scmd = rt.cli().subcommand_matches("delete").unwrap(); let name = String::from(scmd.value_of("delete-name").unwrap()); let unlink = !scmd.is_present("delete-no-remove-linkings");
246
247 let wiki = rt
248 .store()
249 .get_wiki(&wiki_name)?
250 .ok_or_else(|| format_err!("No wiki '{}' found", wiki_name))?;
251
252 if unlink {
253 wiki.get_entry(&name)?
254 .ok_or_else(|| format_err!("No wiki entry '{}' in '{}' found", name, wiki_name))?
255 .unlink(rt.store())?;
256 }
257
258 wiki.delete_entry(&name)
259}
260