libimagcategorycmd/
lib.rs1#![forbid(unsafe_code)]
21
22#![deny(
23 non_camel_case_types,
24 non_snake_case,
25 path_statements,
26 trivial_numeric_casts,
27 unstable_features,
28 unused_allocation,
29 unused_import_braces,
30 unused_imports,
31 unused_must_use,
32 unused_mut,
33 unused_qualifications,
34 while_true,
35)]
36
37extern crate clap;
38#[macro_use]
39extern crate log;
40#[macro_use]
41extern crate failure;
42extern crate resiter;
43
44extern crate libimagentrycategory;
45extern crate libimagerror;
46extern crate libimagrt;
47extern crate libimagstore;
48extern crate libimaginteraction;
49
50use failure::Fallible as Result;
51use resiter::Map;
52use clap::App;
53
54use libimagrt::runtime::Runtime;
55use libimagrt::iter::ReportTouchedResultEntry;
56use libimagrt::application::ImagApplication;
57
58mod ui;
59
60use std::io::Write;
61
62use failure::err_msg;
63use failure::Error;
64use resiter::AndThen;
65use resiter::IterInnerOkOrElse;
66
67use libimagentrycategory::store::CategoryStore;
68use libimagstore::iter::get::StoreIdGetIteratorExtension;
69use libimagentrycategory::entry::EntryCategory;
70use libimagentrycategory::category::Category;
71
72pub enum ImagCategory {}
77impl ImagApplication for ImagCategory {
78 fn run(rt: Runtime) -> Result<()> {
79 match rt.cli().subcommand_name().ok_or_else(|| err_msg("No subcommand called"))? {
80 "set" => set(&rt),
81 "get" => get(&rt),
82 "list-category" => list_category(&rt),
83 "create-category" => create_category(&rt),
84 "delete-category" => delete_category(&rt),
85 "list-categories" => list_categories(&rt),
86 other => {
87 debug!("Unknown command");
88 if rt.handle_unknown_subcommand("imag-category", other, rt.cli())?.success() {
89 Ok(())
90 } else {
91 Err(err_msg("Failed to handle unknown subcommand"))
92 }
93 },
94 }
95 }
96
97 fn build_cli<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
98 ui::build_ui(app)
99 }
100
101 fn name() -> &'static str {
102 env!("CARGO_PKG_NAME")
103 }
104
105 fn description() -> &'static str {
106 "Add a category to entries and manage categories"
107 }
108
109 fn version() -> &'static str {
110 env!("CARGO_PKG_VERSION")
111 }
112}
113
114
115fn set(rt: &Runtime) -> Result<()> {
116 let scmd = rt.cli().subcommand_matches("set").unwrap(); let name = scmd.value_of("set-name").map(String::from).unwrap(); rt.ids::<crate::ui::PathProvider>()?
119 .ok_or_else(|| err_msg("No ids supplied"))?
120 .into_iter()
121 .map(Ok)
122 .into_get_iter(rt.store())
123 .map_inner_ok_or_else(|| err_msg("Did not find one entry"))
124 .and_then_ok(|mut e| e.set_category_checked(rt.store(), &name).map(|_| e))
125 .map_report_touched(&rt)
126 .map_ok(|_| ())
127 .collect()
128}
129
130fn get(rt: &Runtime) -> Result<()> {
131 let out = rt.stdout();
132 let mut outlock = out.lock();
133 rt.ids::<crate::ui::PathProvider>()?
134 .ok_or_else(|| err_msg("No ids supplied"))?
135 .into_iter()
136 .map(Ok)
137 .into_get_iter(rt.store())
138 .map_inner_ok_or_else(|| err_msg("Did not find one entry"))
139 .map_report_touched(&rt)
140 .and_then_ok(|e| e.get_category())
141 .and_then_ok(|n| writeln!(outlock, "{}", n).map_err(Error::from))
142 .collect()
143}
144
145fn list_category(rt: &Runtime) -> Result<()> {
146 let scmd = rt.cli().subcommand_matches("list-category").unwrap(); let name = scmd.value_of("list-category-name").map(String::from).unwrap(); if let Some(category) = rt.store().get_category_by_name(&name)? {
150 let out = rt.stdout();
151 let mut outlock = out.lock();
152
153 category
154 .get_entries(rt.store())?
155 .map_report_touched(&rt)
156 .map(|entry| writeln!(outlock, "{}", entry?.get_location()).map_err(Error::from))
157 .collect()
158 } else {
159 Err(format_err!("No category named '{}'", name))
160 }
161}
162
163fn create_category(rt: &Runtime) -> Result<()> {
164 let scmd = rt.cli().subcommand_matches("create-category").unwrap(); let name = scmd.value_of("create-category-name").map(String::from).unwrap(); rt.store()
167 .create_category(&name)
168 .and_then(|e| rt.report_touched(e.get_location()))
169}
170
171fn delete_category(rt: &Runtime) -> Result<()> {
172 use libimaginteraction::ask::ask_bool;
173
174 let scmd = rt.cli().subcommand_matches("delete-category").unwrap(); let name = scmd.value_of("delete-category-name").map(String::from).unwrap(); let ques = format!("Do you really want to delete category '{}' and remove links to all categorized enties?", name);
177
178 let mut input = rt.stdin().ok_or_else(|| err_msg("No input stream. Cannot ask for permission"))?;
179 let mut output = rt.stdout();
180 let answer = ask_bool(&ques, Some(false), &mut input, &mut output)?;
181
182 if answer {
183 info!("Deleting category '{}'", name);
184 rt.store().delete_category(&name)
185 } else {
186 info!("Not doing anything");
187 Ok(())
188 }
189}
190
191fn list_categories(rt: &Runtime) -> Result<()> {
192 let out = rt.stdout();
193 let mut outlock = out.lock();
194
195 rt.store()
196 .all_category_names()?
197 .and_then_ok(|n| writeln!(outlock, "{}", n).map_err(Error::from))
198 .collect()
199}
200