1#![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] extern crate log;
39#[macro_use] extern crate failure;
40
41extern crate libimagentrygps;
42extern crate libimagrt;
43extern crate libimagutil;
44extern crate libimagerror;
45extern crate libimagstore;
46
47use std::io::Write;
48use std::str::FromStr;
49
50use failure::Error;
51use failure::Fallible as Result;
52use failure::err_msg;
53use clap::App;
54
55use libimagstore::storeid::StoreId;
56use libimagentrygps::types::*;
57use libimagentrygps::entry::*;
58use libimagrt::application::ImagApplication;
59use libimagrt::runtime::Runtime;
60
61mod ui;
62
63pub enum ImagGps {}
68impl ImagApplication for ImagGps {
69 fn run(rt: Runtime) -> Result<()> {
70 match rt.cli().subcommand_name().ok_or_else(|| err_msg("No subcommand called"))? {
71 "add" => add(&rt),
72 "remove" => remove(&rt),
73 "get" => get(&rt),
74 other => {
75 debug!("Unknown command");
76 if rt.handle_unknown_subcommand("imag-gps", other, rt.cli())
77 .map_err(Error::from)?
78 .success()
79 {
80 Ok(())
81 } else {
82 Err(format_err!("Subcommand failed"))
83 }
84 }
85 }
86 }
87
88 fn build_cli<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
89 ui::build_ui(app)
90 }
91
92 fn name() -> &'static str {
93 env!("CARGO_PKG_NAME")
94 }
95
96 fn description() -> &'static str {
97 "Add GPS coordinates to entries"
98 }
99
100 fn version() -> &'static str {
101 env!("CARGO_PKG_VERSION")
102 }
103}
104
105fn rt_get_ids(rt: &Runtime) -> Result<Vec<StoreId>> {
106 rt
107 .ids::<crate::ui::PathProvider>()?
108 .ok_or_else(|| err_msg("No ids supplied"))
109}
110
111fn add(rt: &Runtime) -> Result<()> {
112 let c = {
113 let parse = |value: &str| -> Result<(i64, i64, i64)> {
114 debug!("Parsing '{}' into degree, minute and second", value);
115 let ary = value.split('.')
116 .map(|v| {debug!("Parsing = {}", v); v})
117 .map(FromStr::from_str)
118 .map(|elem| elem.or_else(|_| Err(err_msg("Error while converting number"))))
119 .collect::<Result<Vec<i64>>>()?;
120
121 let degree = ary.get(0).ok_or_else(|| err_msg("Degree missing. This value is required."))?;
122 let minute = ary.get(1).ok_or_else(|| err_msg("Degree missing. This value is required."))?;
123 let second = ary.get(2).unwrap_or(&0);
124
125 Ok((*degree, *minute, *second))
126 };
127
128 let scmd = rt.cli().subcommand_matches("add").unwrap(); let long = parse(scmd.value_of("longitude").unwrap())?; let lati = parse(scmd.value_of("latitude").unwrap())?; let long = GPSValue::new(long.0, long.1, long.2);
134 let lati = GPSValue::new(lati.0, lati.1, lati.2);
135
136 Coordinates::new(long, lati)
137 };
138
139 rt_get_ids(&rt)?
140 .into_iter()
141 .map(|id| {
142 rt.store()
143 .get(id.clone())?
144 .ok_or_else(|| format_err!("No such entry: {}", id))?
145 .set_coordinates(c.clone())?;
146
147 rt.report_touched(&id)
148 })
149 .collect()
150}
151
152fn remove(rt: &Runtime) -> Result<()> {
153 let print_removed = rt
154 .cli()
155 .subcommand_matches("remove")
156 .unwrap()
157 .is_present("print-removed"); rt_get_ids(&rt)?
160 .into_iter()
161 .map(|id| {
162 let removed_value : Coordinates = rt
163 .store()
164 .get(id.clone())?
165 .ok_or_else(|| format_err!("No such entry: {}", id))?
166 .remove_coordinates()?
167 .ok_or_else(|| format_err!("Entry had no coordinates: {}", id))??;
168
169 if print_removed {
170 writeln!(rt.stdout(), "{}", removed_value)?;
171 }
172
173 rt.report_touched(&id)
174 })
175 .collect()
176}
177
178fn get(rt: &Runtime) -> Result<()> {
179 let mut stdout = rt.stdout();
180
181 rt_get_ids(&rt)?
182 .into_iter()
183 .map(|id| {
184 let value = rt
185 .store()
186 .get(id.clone())?
187 .ok_or_else(|| { format_err!("No such entry: {}", id)
189 })?
190 .get_coordinates()?
191 .ok_or_else(|| { format_err!("Entry has no coordinates: {}", id)
193 })?;
194
195 writeln!(stdout, "{}", value)?;
196
197 rt.report_touched(&id)
198 })
199 .collect()
200}
201