Merge branch 'noexit' into master
This merge includes the first batch of "no-exit()-call" patches. With this patchset, we do not exit() anywhere in the core binaries anymore, but propagate errors up to the main() function, where they are returned. Signed-off-by: Matthias Beyer <mail@beyermatthias.de>
This commit is contained in:
commit
cc6a833ab6
42 changed files with 1223 additions and 1652 deletions
|
@ -53,17 +53,15 @@ use std::io::Write;
|
||||||
|
|
||||||
use failure::Error;
|
use failure::Error;
|
||||||
use failure::Fallible as Result;
|
use failure::Fallible as Result;
|
||||||
|
use failure::ResultExt;
|
||||||
|
use failure::err_msg;
|
||||||
use toml_query::read::TomlValueReadTypeExt;
|
use toml_query::read::TomlValueReadTypeExt;
|
||||||
use clap::App;
|
use clap::App;
|
||||||
|
|
||||||
use libimagentryannotation::annotateable::*;
|
use libimagentryannotation::annotateable::*;
|
||||||
use libimagentryannotation::annotation_fetcher::*;
|
use libimagentryannotation::annotation_fetcher::*;
|
||||||
use libimagentryedit::edit::*;
|
use libimagentryedit::edit::*;
|
||||||
use libimagerror::trace::MapErrTrace;
|
|
||||||
use libimagerror::exit::ExitUnwrap;
|
|
||||||
use libimagerror::io::ToExitCode;
|
|
||||||
use libimagerror::errors::ErrorMsg as EM;
|
use libimagerror::errors::ErrorMsg as EM;
|
||||||
use libimagerror::iter::TraceIterator;
|
|
||||||
use libimagrt::runtime::Runtime;
|
use libimagrt::runtime::Runtime;
|
||||||
use libimagrt::application::ImagApplication;
|
use libimagrt::application::ImagApplication;
|
||||||
use libimagstore::store::FileLockEntry;
|
use libimagstore::store::FileLockEntry;
|
||||||
|
@ -75,24 +73,21 @@ mod ui;
|
||||||
pub enum ImagAnnotate {}
|
pub enum ImagAnnotate {}
|
||||||
impl ImagApplication for ImagAnnotate {
|
impl ImagApplication for ImagAnnotate {
|
||||||
fn run(rt: Runtime) -> Result<()> {
|
fn run(rt: Runtime) -> Result<()> {
|
||||||
if let Some(name) = rt.cli().subcommand_name() {
|
match rt.cli().subcommand_name().ok_or_else(|| err_msg("No command called"))? {
|
||||||
match name {
|
|
||||||
"add" => add(&rt),
|
"add" => add(&rt),
|
||||||
"remove" => remove(&rt),
|
"remove" => remove(&rt),
|
||||||
"list" => list(&rt),
|
"list" => list(&rt),
|
||||||
other => {
|
other => {
|
||||||
debug!("Unknown command");
|
debug!("Unknown command");
|
||||||
let _ = rt.handle_unknown_subcommand("imag-annotation", other, rt.cli())
|
if rt.handle_unknown_subcommand("imag-annotation", other, rt.cli())?.success() {
|
||||||
.map_err_trace_exit_unwrap()
|
Ok(())
|
||||||
.code()
|
} else {
|
||||||
.map(::std::process::exit);
|
Err(err_msg("Failed to handle unknown subcommand"))
|
||||||
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn build_cli<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
|
fn build_cli<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
|
||||||
ui::build_ui(app)
|
ui::build_ui(app)
|
||||||
}
|
}
|
||||||
|
@ -110,82 +105,62 @@ impl ImagApplication for ImagAnnotate {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add(rt: &Runtime) {
|
fn add(rt: &Runtime) -> Result<()> {
|
||||||
let scmd = rt.cli().subcommand_matches("add").unwrap(); // safed by main()
|
let scmd = rt.cli().subcommand_matches("add").unwrap(); // safed by main()
|
||||||
let mut ids = rt
|
let mut ids = rt
|
||||||
.ids::<crate::ui::PathProvider>()
|
.ids::<crate::ui::PathProvider>()
|
||||||
.map_err_trace_exit_unwrap()
|
.context("No StoreId supplied")?
|
||||||
.unwrap_or_else(|| {
|
.ok_or_else(|| err_msg("No ids supplied"))?
|
||||||
error!("No StoreId supplied");
|
|
||||||
::std::process::exit(1);
|
|
||||||
})
|
|
||||||
.into_iter();
|
.into_iter();
|
||||||
|
|
||||||
if let Some(first) = ids.next() {
|
if let Some(first) = ids.next() {
|
||||||
let mut annotation = rt.store()
|
let mut annotation = rt.store()
|
||||||
.get(first.clone())
|
.get(first.clone())?
|
||||||
.map_err_trace_exit_unwrap()
|
.ok_or_else(|| EM::EntryNotFound(first.local_display_string()))?
|
||||||
.ok_or_else(|| EM::EntryNotFound(first.local_display_string()))
|
.annotate(rt.store())?;
|
||||||
.map_err(Error::from)
|
|
||||||
.map_err_trace_exit_unwrap()
|
|
||||||
.annotate(rt.store())
|
|
||||||
.map_err_trace_exit_unwrap();
|
|
||||||
|
|
||||||
annotation.edit_content(&rt).map_err_trace_exit_unwrap();
|
annotation.edit_content(&rt)?;
|
||||||
|
|
||||||
for id in ids {
|
for id in ids {
|
||||||
let mut entry = rt.store().get(id.clone())
|
let mut entry = rt.store().get(id.clone())?
|
||||||
.map_err_trace_exit_unwrap()
|
.ok_or_else(|| format_err!("Not found: {}", id.local_display_string()))?;
|
||||||
.ok_or_else(|| format_err!("Not found: {}", id.local_display_string()))
|
|
||||||
.map_err_trace_exit_unwrap();
|
|
||||||
|
|
||||||
entry.add_link(&mut annotation).map_err_trace_exit_unwrap();
|
entry.add_link(&mut annotation)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if !scmd.is_present("dont-print-name") {
|
if !scmd.is_present("dont-print-name") {
|
||||||
if let Some(annotation_id) = annotation
|
if let Some(annotation_id) = annotation
|
||||||
.get_header()
|
.get_header()
|
||||||
.read_string("annotation.name")
|
.read_string("annotation.name")?
|
||||||
.map_err(Error::from)
|
|
||||||
.map_err_trace_exit_unwrap()
|
|
||||||
{
|
{
|
||||||
writeln!(rt.stdout(), "Name of the annotation: {}", annotation_id)
|
writeln!(rt.stdout(), "Name of the annotation: {}", annotation_id)?;
|
||||||
.to_exit_code()
|
|
||||||
.unwrap_or_exit();
|
|
||||||
} else {
|
} else {
|
||||||
error!("Unnamed annotation: {:?}", annotation.get_location());
|
Err(format_err!("Unnamed annotation: {:?}", annotation.get_location()))
|
||||||
error!("This is most likely a BUG, please report!");
|
.context("This is most likely a BUG, please report!")?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
debug!("No entries to annotate");
|
debug!("No entries to annotate");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove(rt: &Runtime) {
|
fn remove(rt: &Runtime) -> Result<()> {
|
||||||
let scmd = rt.cli().subcommand_matches("remove").unwrap(); // safed by main()
|
let scmd = rt.cli().subcommand_matches("remove").unwrap(); // safed by main()
|
||||||
let annotation_name = scmd.value_of("annotation_name").unwrap(); // safed by clap
|
let annotation_name = scmd.value_of("annotation_name").unwrap(); // safed by clap
|
||||||
let delete = scmd.is_present("delete-annotation");
|
let delete = scmd.is_present("delete-annotation");
|
||||||
let ids = rt
|
|
||||||
.ids::<crate::ui::PathProvider>()
|
|
||||||
.map_err_trace_exit_unwrap()
|
|
||||||
.unwrap_or_else(|| {
|
|
||||||
error!("No ids supplied");
|
|
||||||
::std::process::exit(1);
|
|
||||||
})
|
|
||||||
.into_iter();
|
|
||||||
|
|
||||||
ids.for_each(|id| {
|
rt.ids::<crate::ui::PathProvider>()
|
||||||
|
.context("No ids supplied")?
|
||||||
|
.ok_or_else(|| err_msg("No ids supplied"))?
|
||||||
|
.into_iter()
|
||||||
|
.map(|id| {
|
||||||
let mut entry = rt.store()
|
let mut entry = rt.store()
|
||||||
.get(id.clone())
|
.get(id.clone())?
|
||||||
.map_err_trace_exit_unwrap()
|
.ok_or_else(|| EM::EntryNotFound(id.local_display_string()))?;
|
||||||
.ok_or_else(|| EM::EntryNotFound(id.local_display_string()))
|
|
||||||
.map_err(Error::from)
|
|
||||||
.map_err_trace_exit_unwrap();
|
|
||||||
|
|
||||||
let annotation = entry
|
let annotation = entry.denotate(rt.store(), annotation_name)?;
|
||||||
.denotate(rt.store(), annotation_name)
|
|
||||||
.map_err_trace_exit_unwrap();
|
|
||||||
|
|
||||||
if delete {
|
if delete {
|
||||||
debug!("Deleting annotation object");
|
debug!("Deleting annotation object");
|
||||||
|
@ -193,66 +168,56 @@ fn remove(rt: &Runtime) {
|
||||||
let loc = an.get_location().clone();
|
let loc = an.get_location().clone();
|
||||||
drop(an);
|
drop(an);
|
||||||
|
|
||||||
rt
|
rt.store().delete(loc)?;
|
||||||
.store()
|
|
||||||
.delete(loc)
|
|
||||||
.map_err_trace_exit_unwrap();
|
|
||||||
} else {
|
} else {
|
||||||
warn!("Not having annotation object, cannot delete!");
|
warn!("Not having annotation object, cannot delete!");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
debug!("Not deleting annotation object");
|
debug!("Not deleting annotation object");
|
||||||
}
|
}
|
||||||
})
|
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn list(rt: &Runtime) {
|
fn list(rt: &Runtime) -> Result<()> {
|
||||||
let scmd = rt.cli().subcommand_matches("list").unwrap(); // safed by clap
|
let scmd = rt.cli().subcommand_matches("list").unwrap(); // safed by clap
|
||||||
let with_text = scmd.is_present("list-with-text");
|
let with_text = scmd.is_present("list-with-text");
|
||||||
let ids = rt
|
let ids = rt
|
||||||
.ids::<crate::ui::PathProvider>()
|
.ids::<crate::ui::PathProvider>()
|
||||||
.map_err_trace_exit_unwrap()
|
.context("No ids supplied")?
|
||||||
.unwrap_or_else(|| {
|
.ok_or_else(|| err_msg("No ids supplied"))?;
|
||||||
error!("No ids supplied");
|
|
||||||
::std::process::exit(1);
|
|
||||||
})
|
|
||||||
.into_iter();
|
|
||||||
|
|
||||||
if ids.len() != 0 {
|
if ids.len() != 0 {
|
||||||
ids
|
ids.into_iter()
|
||||||
.for_each(|id| {
|
.map(|id| -> Result<_> {
|
||||||
rt
|
let lds = id.local_display_string();
|
||||||
.store()
|
Ok(rt.store()
|
||||||
.get(id.clone())
|
.get(id)?
|
||||||
.map_err_trace_exit_unwrap()
|
.ok_or_else(|| EM::EntryNotFound(lds))?
|
||||||
.ok_or_else(|| EM::EntryNotFound(id.local_display_string()))
|
.annotations()?
|
||||||
.map_err(Error::from)
|
|
||||||
.map_err_trace_exit_unwrap()
|
|
||||||
.annotations()
|
|
||||||
.map_err_trace_exit_unwrap()
|
|
||||||
.into_get_iter(rt.store())
|
.into_get_iter(rt.store())
|
||||||
.trace_unwrap_exit()
|
.map(|el| el.and_then(|o| o.ok_or_else(|| format_err!("Cannot find entry"))))
|
||||||
.map(|opt| opt.ok_or_else(|| format_err!("Cannot find entry")))
|
|
||||||
.trace_unwrap_exit()
|
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.for_each(|(i, entry)| list_annotation(&rt, i, entry, with_text));
|
.map(|(i, entry)| entry.and_then(|e| list_annotation(&rt, i, e, with_text)))
|
||||||
});
|
.collect())
|
||||||
|
})
|
||||||
|
.flatten()
|
||||||
|
.collect()
|
||||||
} else { // ids.len() == 0
|
} else { // ids.len() == 0
|
||||||
// show them all
|
// show them all
|
||||||
rt.store()
|
rt.store()
|
||||||
.all_annotations()
|
.all_annotations()?
|
||||||
.map_err_trace_exit_unwrap()
|
|
||||||
.into_get_iter()
|
.into_get_iter()
|
||||||
.trace_unwrap_exit()
|
.map(|el| el.and_then(|opt| opt.ok_or_else(|| format_err!("Cannot find entry"))))
|
||||||
.map(|opt| opt.ok_or_else(|| format_err!("Cannot find entry")))
|
|
||||||
.trace_unwrap_exit()
|
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.for_each(|(i, entry)| list_annotation(&rt, i, entry, with_text));
|
.map(|(i, entry)| entry.and_then(|e| list_annotation(&rt, i, e, with_text)))
|
||||||
|
.collect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn list_annotation<'a>(rt: &Runtime, i: usize, a: FileLockEntry<'a>, with_text: bool) {
|
fn list_annotation<'a>(rt: &Runtime, i: usize, a: FileLockEntry<'a>, with_text: bool) -> Result<()> {
|
||||||
if with_text {
|
if with_text {
|
||||||
writeln!(rt.stdout(),
|
writeln!(rt.stdout(),
|
||||||
"--- {i: >5} | {id}\n{text}\n\n",
|
"--- {i: >5} | {id}\n{text}\n\n",
|
||||||
|
@ -261,8 +226,6 @@ fn list_annotation<'a>(rt: &Runtime, i: usize, a: FileLockEntry<'a>, with_text:
|
||||||
text = a.get_content())
|
text = a.get_content())
|
||||||
} else {
|
} else {
|
||||||
writeln!(rt.stdout(), "{: >5} | {}", i, a.get_location())
|
writeln!(rt.stdout(), "{: >5} | {}", i, a.get_location())
|
||||||
}
|
}.map_err(Error::from)
|
||||||
.to_exit_code()
|
|
||||||
.unwrap_or_exit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@ log = "0.4.6"
|
||||||
toml = "0.5.1"
|
toml = "0.5.1"
|
||||||
toml-query = "0.9.2"
|
toml-query = "0.9.2"
|
||||||
failure = "0.1.5"
|
failure = "0.1.5"
|
||||||
|
resiter = "0.3.0"
|
||||||
|
|
||||||
libimagstore = { version = "0.10.0", path = "../../../lib/core/libimagstore" }
|
libimagstore = { version = "0.10.0", path = "../../../lib/core/libimagstore" }
|
||||||
libimagrt = { version = "0.10.0", path = "../../../lib/core/libimagrt" }
|
libimagrt = { version = "0.10.0", path = "../../../lib/core/libimagrt" }
|
||||||
|
|
|
@ -39,6 +39,7 @@ extern crate clap;
|
||||||
extern crate log;
|
extern crate log;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate failure;
|
extern crate failure;
|
||||||
|
extern crate resiter;
|
||||||
|
|
||||||
extern crate libimagentrycategory;
|
extern crate libimagentrycategory;
|
||||||
extern crate libimagerror;
|
extern crate libimagerror;
|
||||||
|
@ -50,19 +51,20 @@ use failure::Fallible as Result;
|
||||||
use clap::App;
|
use clap::App;
|
||||||
|
|
||||||
use libimagerror::trace::MapErrTrace;
|
use libimagerror::trace::MapErrTrace;
|
||||||
use libimagerror::exit::ExitUnwrap;
|
|
||||||
use libimagerror::io::ToExitCode;
|
|
||||||
use libimagrt::runtime::Runtime;
|
use libimagrt::runtime::Runtime;
|
||||||
use libimagrt::application::ImagApplication;
|
use libimagrt::application::ImagApplication;
|
||||||
|
use libimagerror::iter::IterInnerOkOrElse;
|
||||||
|
|
||||||
mod ui;
|
mod ui;
|
||||||
|
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
|
||||||
|
use failure::err_msg;
|
||||||
|
use failure::Error;
|
||||||
|
use resiter::AndThen;
|
||||||
|
|
||||||
use libimagentrycategory::store::CategoryStore;
|
use libimagentrycategory::store::CategoryStore;
|
||||||
use libimagstore::storeid::StoreIdIterator;
|
|
||||||
use libimagstore::iter::get::StoreIdGetIteratorExtension;
|
use libimagstore::iter::get::StoreIdGetIteratorExtension;
|
||||||
use libimagerror::iter::TraceIterator;
|
|
||||||
use libimagentrycategory::entry::EntryCategory;
|
use libimagentrycategory::entry::EntryCategory;
|
||||||
use libimagentrycategory::category::Category;
|
use libimagentrycategory::category::Category;
|
||||||
|
|
||||||
|
@ -73,8 +75,7 @@ use libimagentrycategory::category::Category;
|
||||||
pub enum ImagCategory {}
|
pub enum ImagCategory {}
|
||||||
impl ImagApplication for ImagCategory {
|
impl ImagApplication for ImagCategory {
|
||||||
fn run(rt: Runtime) -> Result<()> {
|
fn run(rt: Runtime) -> Result<()> {
|
||||||
if let Some(name) = rt.cli().subcommand_name() {
|
match rt.cli().subcommand_name().ok_or_else(|| err_msg("No subcommand called"))? {
|
||||||
match name {
|
|
||||||
"set" => set(&rt),
|
"set" => set(&rt),
|
||||||
"get" => get(&rt),
|
"get" => get(&rt),
|
||||||
"list-category" => list_category(&rt),
|
"list-category" => list_category(&rt),
|
||||||
|
@ -83,17 +84,15 @@ impl ImagApplication for ImagCategory {
|
||||||
"list-categories" => list_categories(&rt),
|
"list-categories" => list_categories(&rt),
|
||||||
other => {
|
other => {
|
||||||
debug!("Unknown command");
|
debug!("Unknown command");
|
||||||
let _ = rt.handle_unknown_subcommand("imag-category", other, rt.cli())
|
if rt.handle_unknown_subcommand("imag-category", other, rt.cli())?.success() {
|
||||||
.map_err_trace_exit_unwrap()
|
Ok(())
|
||||||
.code()
|
} else {
|
||||||
.map(::std::process::exit);
|
Err(err_msg("Failed to handle unknown subcommand"))
|
||||||
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn build_cli<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
|
fn build_cli<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
|
||||||
ui::build_ui(app)
|
ui::build_ui(app)
|
||||||
}
|
}
|
||||||
|
@ -112,125 +111,84 @@ impl ImagApplication for ImagCategory {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn set(rt: &Runtime) {
|
fn set(rt: &Runtime) -> Result<()> {
|
||||||
let scmd = rt.cli().subcommand_matches("set").unwrap(); // safed by main()
|
let scmd = rt.cli().subcommand_matches("set").unwrap(); // safed by main()
|
||||||
let name = scmd.value_of("set-name").map(String::from).unwrap(); // safed by clap
|
let name = scmd.value_of("set-name").map(String::from).unwrap(); // safed by clap
|
||||||
let sids = rt
|
rt.ids::<crate::ui::PathProvider>()?
|
||||||
.ids::<crate::ui::PathProvider>()
|
.ok_or_else(|| err_msg("No ids supplied"))?
|
||||||
.map_err_trace_exit_unwrap()
|
.into_iter()
|
||||||
.unwrap_or_else(|| {
|
.map(Ok)
|
||||||
error!("No ids supplied");
|
|
||||||
::std::process::exit(1);
|
|
||||||
})
|
|
||||||
.into_iter();
|
|
||||||
|
|
||||||
StoreIdIterator::new(Box::new(sids.map(Ok)))
|
|
||||||
.into_get_iter(rt.store())
|
.into_get_iter(rt.store())
|
||||||
.trace_unwrap_exit()
|
.map_inner_ok_or_else(|| err_msg("Did not find one entry"))
|
||||||
.map(|o| o.unwrap_or_else(|| {
|
.and_then_ok(|mut e| e.set_category_checked(rt.store(), &name))
|
||||||
error!("Did not find one entry");
|
.collect()
|
||||||
::std::process::exit(1)
|
|
||||||
}))
|
|
||||||
.for_each(|mut entry| {
|
|
||||||
entry
|
|
||||||
.set_category_checked(rt.store(), &name)
|
|
||||||
.map_err_trace_exit_unwrap();
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get(rt: &Runtime) {
|
fn get(rt: &Runtime) -> Result<()> {
|
||||||
let out = rt.stdout();
|
let out = rt.stdout();
|
||||||
let mut outlock = out.lock();
|
let mut outlock = out.lock();
|
||||||
let sids = rt
|
rt.ids::<crate::ui::PathProvider>()?
|
||||||
.ids::<crate::ui::PathProvider>()
|
.ok_or_else(|| err_msg("No ids supplied"))?
|
||||||
.map_err_trace_exit_unwrap()
|
.into_iter()
|
||||||
.unwrap_or_else(|| {
|
.map(Ok)
|
||||||
error!("No ids supplied");
|
|
||||||
::std::process::exit(1);
|
|
||||||
})
|
|
||||||
.into_iter();
|
|
||||||
|
|
||||||
StoreIdIterator::new(Box::new(sids.map(Ok)))
|
|
||||||
.into_get_iter(rt.store())
|
.into_get_iter(rt.store())
|
||||||
.trace_unwrap_exit()
|
.map(|el| el.and_then(|o| o.ok_or_else(|| err_msg("Did not find one entry"))))
|
||||||
.map(|o| o.unwrap_or_else(|| {
|
.map(|entry| entry.and_then(|e| e.get_category()))
|
||||||
error!("Did not find one entry");
|
.map(|name| name.and_then(|n| writeln!(outlock, "{}", n).map_err(Error::from)))
|
||||||
::std::process::exit(1)
|
.collect()
|
||||||
}))
|
|
||||||
.map(|entry| entry.get_category().map_err_trace_exit_unwrap())
|
|
||||||
.for_each(|name| {
|
|
||||||
writeln!(outlock, "{}", name).to_exit_code().unwrap_or_exit();
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn list_category(rt: &Runtime) {
|
fn list_category(rt: &Runtime) -> Result<()> {
|
||||||
let scmd = rt.cli().subcommand_matches("list-category").unwrap(); // safed by main()
|
let scmd = rt.cli().subcommand_matches("list-category").unwrap(); // safed by main()
|
||||||
let name = scmd.value_of("list-category-name").map(String::from).unwrap(); // safed by clap
|
let name = scmd.value_of("list-category-name").map(String::from).unwrap(); // safed by clap
|
||||||
|
|
||||||
if let Some(category) = rt.store().get_category_by_name(&name).map_err_trace_exit_unwrap() {
|
if let Some(category) = rt.store().get_category_by_name(&name)? {
|
||||||
let out = rt.stdout();
|
let out = rt.stdout();
|
||||||
let mut outlock = out.lock();
|
let mut outlock = out.lock();
|
||||||
|
|
||||||
category
|
category
|
||||||
.get_entries(rt.store())
|
.get_entries(rt.store())
|
||||||
.map_err_trace_exit_unwrap()
|
.map_err_trace_exit_unwrap()
|
||||||
.for_each(|entry| {
|
.map(|entry| writeln!(outlock, "{}", entry?.get_location()).map_err(Error::from))
|
||||||
writeln!(outlock, "{}", entry.map_err_trace_exit_unwrap().get_location())
|
.collect()
|
||||||
.to_exit_code()
|
|
||||||
.unwrap_or_exit();
|
|
||||||
})
|
|
||||||
} else {
|
} else {
|
||||||
info!("No category named '{}'", name);
|
Err(format_err!("No category named '{}'", name))
|
||||||
::std::process::exit(1)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_category(rt: &Runtime) {
|
fn create_category(rt: &Runtime) -> Result<()> {
|
||||||
let scmd = rt.cli().subcommand_matches("create-category").unwrap(); // safed by main()
|
let scmd = rt.cli().subcommand_matches("create-category").unwrap(); // safed by main()
|
||||||
let name = scmd.value_of("create-category-name").map(String::from).unwrap(); // safed by clap
|
let name = scmd.value_of("create-category-name").map(String::from).unwrap(); // safed by clap
|
||||||
|
rt.store().create_category(&name).map(|_| ())
|
||||||
let _ = rt
|
|
||||||
.store()
|
|
||||||
.create_category(&name)
|
|
||||||
.map_err_trace_exit_unwrap();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn delete_category(rt: &Runtime) {
|
fn delete_category(rt: &Runtime) -> Result<()> {
|
||||||
use libimaginteraction::ask::ask_bool;
|
use libimaginteraction::ask::ask_bool;
|
||||||
|
|
||||||
let scmd = rt.cli().subcommand_matches("delete-category").unwrap(); // safed by main()
|
let scmd = rt.cli().subcommand_matches("delete-category").unwrap(); // safed by main()
|
||||||
let name = scmd.value_of("delete-category-name").map(String::from).unwrap(); // safed by clap
|
let name = scmd.value_of("delete-category-name").map(String::from).unwrap(); // safed by clap
|
||||||
let ques = format!("Do you really want to delete category '{}' and remove links to all categorized enties?", name);
|
let ques = format!("Do you really want to delete category '{}' and remove links to all categorized enties?", name);
|
||||||
|
|
||||||
let mut input = rt.stdin().unwrap_or_else(|| {
|
let mut input = rt.stdin().ok_or_else(|| err_msg("No input stream. Cannot ask for permission"))?;
|
||||||
error!("No input stream. Cannot ask for permission");
|
|
||||||
::std::process::exit(1)
|
|
||||||
});
|
|
||||||
let mut output = rt.stdout();
|
let mut output = rt.stdout();
|
||||||
let answer = ask_bool(&ques, Some(false), &mut input, &mut output).map_err_trace_exit_unwrap();
|
let answer = ask_bool(&ques, Some(false), &mut input, &mut output)?;
|
||||||
|
|
||||||
if answer {
|
if answer {
|
||||||
info!("Deleting category '{}'", name);
|
info!("Deleting category '{}'", name);
|
||||||
rt
|
rt.store().delete_category(&name).map(|_| ())
|
||||||
.store()
|
|
||||||
.delete_category(&name)
|
|
||||||
.map_err_trace_exit_unwrap();
|
|
||||||
} else {
|
} else {
|
||||||
info!("Not doing anything");
|
info!("Not doing anything");
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn list_categories(rt: &Runtime) {
|
fn list_categories(rt: &Runtime) -> Result<()> {
|
||||||
let out = rt.stdout();
|
let out = rt.stdout();
|
||||||
let mut outlock = out.lock();
|
let mut outlock = out.lock();
|
||||||
|
|
||||||
rt.store()
|
rt.store()
|
||||||
.all_category_names()
|
.all_category_names()?
|
||||||
.map_err_trace_exit_unwrap()
|
.map(|name| name.and_then(|n| writeln!(outlock, "{}", n).map_err(Error::from)))
|
||||||
.for_each(|name| {
|
.collect()
|
||||||
writeln!(outlock, "{}", name.map_err_trace_exit_unwrap())
|
|
||||||
.to_exit_code()
|
|
||||||
.unwrap_or_exit();
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,21 +36,19 @@
|
||||||
|
|
||||||
extern crate clap;
|
extern crate clap;
|
||||||
extern crate failure;
|
extern crate failure;
|
||||||
#[macro_use] extern crate log;
|
|
||||||
|
|
||||||
extern crate libimagerror;
|
extern crate libimagerror;
|
||||||
extern crate libimagrt;
|
extern crate libimagrt;
|
||||||
extern crate libimagstore;
|
extern crate libimagstore;
|
||||||
|
|
||||||
use failure::Fallible as Result;
|
use failure::Fallible as Result;
|
||||||
|
use failure::err_msg;
|
||||||
use clap::App;
|
use clap::App;
|
||||||
|
|
||||||
use libimagrt::runtime::Runtime;
|
use libimagrt::runtime::Runtime;
|
||||||
use libimagrt::application::ImagApplication;
|
use libimagrt::application::ImagApplication;
|
||||||
use libimagerror::trace::MapErrTrace;
|
|
||||||
use libimagstore::iter::create::StoreIdCreateIteratorExtension;
|
use libimagstore::iter::create::StoreIdCreateIteratorExtension;
|
||||||
use libimagstore::iter::retrieve::StoreIdRetrieveIteratorExtension;
|
use libimagstore::iter::retrieve::StoreIdRetrieveIteratorExtension;
|
||||||
use libimagerror::exit::ExitUnwrap;
|
|
||||||
|
|
||||||
mod ui;
|
mod ui;
|
||||||
|
|
||||||
|
@ -60,30 +58,17 @@ pub enum ImagCreate {}
|
||||||
impl ImagApplication for ImagCreate {
|
impl ImagApplication for ImagCreate {
|
||||||
fn run(rt: Runtime) -> Result<()> {
|
fn run(rt: Runtime) -> Result<()> {
|
||||||
let force = rt.cli().is_present("force");
|
let force = rt.cli().is_present("force");
|
||||||
debug!("Detected force = {}", force);
|
|
||||||
|
|
||||||
let ids = rt.ids::<crate::ui::PathProvider>()
|
let ids = rt.ids::<crate::ui::PathProvider>()?
|
||||||
.map_err_trace_exit_unwrap()
|
.ok_or_else(|| err_msg("No ids supplied"))?
|
||||||
.unwrap_or_else(|| {
|
|
||||||
error!("No ids supplied");
|
|
||||||
::std::process::exit(1);
|
|
||||||
})
|
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|id| { debug!("id = {}", id); id })
|
|
||||||
.map(Ok);
|
.map(Ok);
|
||||||
|
|
||||||
if force {
|
if force {
|
||||||
ids.into_retrieve_iter(rt.store()).collect::<Result<Vec<_>>>()
|
ids.into_retrieve_iter(rt.store()).collect::<Result<Vec<_>>>()
|
||||||
} else {
|
} else {
|
||||||
ids.into_create_iter(rt.store()).collect::<Result<Vec<_>>>()
|
ids.into_create_iter(rt.store()).collect::<Result<Vec<_>>>()
|
||||||
}.map_err_trace_exit_unwrap()
|
}.map(|_| ())
|
||||||
.into_iter()
|
|
||||||
.for_each(|el| {
|
|
||||||
rt.report_touched(el.get_location()).unwrap_or_exit();
|
|
||||||
trace!("Entry = {}", el.get_location());
|
|
||||||
});
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_cli<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
|
fn build_cli<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
|
||||||
|
|
|
@ -19,6 +19,7 @@ toml = "0.5.1"
|
||||||
toml-query = "0.9.2"
|
toml-query = "0.9.2"
|
||||||
indicatif = "0.12.0"
|
indicatif = "0.12.0"
|
||||||
failure = "0.1.5"
|
failure = "0.1.5"
|
||||||
|
resiter = "0.3.0"
|
||||||
|
|
||||||
libimagstore = { version = "0.10.0", path = "../../../lib/core/libimagstore" }
|
libimagstore = { version = "0.10.0", path = "../../../lib/core/libimagstore" }
|
||||||
libimagrt = { version = "0.10.0", path = "../../../lib/core/libimagrt" }
|
libimagrt = { version = "0.10.0", path = "../../../lib/core/libimagrt" }
|
||||||
|
|
|
@ -39,6 +39,7 @@ extern crate toml;
|
||||||
extern crate toml_query;
|
extern crate toml_query;
|
||||||
extern crate indicatif;
|
extern crate indicatif;
|
||||||
extern crate failure;
|
extern crate failure;
|
||||||
|
extern crate resiter;
|
||||||
#[macro_use] extern crate log;
|
#[macro_use] extern crate log;
|
||||||
|
|
||||||
extern crate libimagrt;
|
extern crate libimagrt;
|
||||||
|
@ -50,20 +51,18 @@ use std::io::Write;
|
||||||
|
|
||||||
use libimagrt::runtime::Runtime;
|
use libimagrt::runtime::Runtime;
|
||||||
use libimagrt::application::ImagApplication;
|
use libimagrt::application::ImagApplication;
|
||||||
use libimagerror::trace::MapErrTrace;
|
|
||||||
use libimagerror::io::ToExitCode;
|
|
||||||
use libimagerror::exit::ExitUnwrap;
|
|
||||||
use libimagstore::store::FileLockEntry;
|
use libimagstore::store::FileLockEntry;
|
||||||
use libimagstore::storeid::StoreId;
|
use libimagstore::storeid::StoreId;
|
||||||
use libimagentrylink::linkable::Linkable;
|
use libimagentrylink::linkable::Linkable;
|
||||||
|
use libimagerror::iter::IterInnerOkOrElse;
|
||||||
|
|
||||||
use toml::Value;
|
use toml::Value;
|
||||||
use toml_query::read::TomlValueReadExt;
|
use toml_query::read::TomlValueReadExt;
|
||||||
use indicatif::{ProgressBar, ProgressStyle};
|
use indicatif::{ProgressBar, ProgressStyle};
|
||||||
use failure::Fallible as Result;
|
use failure::Fallible as Result;
|
||||||
use failure::Error;
|
|
||||||
use failure::err_msg;
|
use failure::err_msg;
|
||||||
use clap::App;
|
use clap::App;
|
||||||
|
use resiter::AndThen;
|
||||||
|
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
|
@ -106,20 +105,6 @@ impl Diagnostic {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! do_write {
|
|
||||||
($dest:ident, $pattern:tt) => {
|
|
||||||
let _ = writeln!($dest, $pattern)
|
|
||||||
.to_exit_code()
|
|
||||||
.unwrap_or_exit();
|
|
||||||
};
|
|
||||||
|
|
||||||
($dest:ident, $pattern:tt, $( $args:expr ),*) => {
|
|
||||||
let _ = writeln!($dest, $pattern, $( $args ),*)
|
|
||||||
.to_exit_code()
|
|
||||||
.unwrap_or_exit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Marker enum for implementing ImagApplication on
|
/// Marker enum for implementing ImagApplication on
|
||||||
///
|
///
|
||||||
/// This is used by binaries crates to execute business logic
|
/// This is used by binaries crates to execute business logic
|
||||||
|
@ -127,8 +112,8 @@ macro_rules! do_write {
|
||||||
pub enum ImagDiagnostics {}
|
pub enum ImagDiagnostics {}
|
||||||
impl ImagApplication for ImagDiagnostics {
|
impl ImagApplication for ImagDiagnostics {
|
||||||
fn run(rt: Runtime) -> Result<()> {
|
fn run(rt: Runtime) -> Result<()> {
|
||||||
let template = get_config(&rt, "rt.progressbar_style");
|
let template = get_config(&rt, "rt.progressbar_style")?;
|
||||||
let tick_chars = get_config(&rt, "rt.progressticker_chars");
|
let tick_chars = get_config(&rt, "rt.progressticker_chars")?;
|
||||||
let verbose = rt.cli().is_present("more-output");
|
let verbose = rt.cli().is_present("more-output");
|
||||||
|
|
||||||
let style = if let Some(tick_chars) = tick_chars {
|
let style = if let Some(tick_chars) = tick_chars {
|
||||||
|
@ -143,22 +128,16 @@ impl ImagApplication for ImagDiagnostics {
|
||||||
spinner.set_message("Accumulating data");
|
spinner.set_message("Accumulating data");
|
||||||
|
|
||||||
let diags = rt.store()
|
let diags = rt.store()
|
||||||
.entries()
|
.entries()?
|
||||||
.map_err_trace_exit_unwrap()
|
|
||||||
.into_get_iter()
|
.into_get_iter()
|
||||||
.map(|e| {
|
.map_inner_ok_or_else(|| err_msg("Unable to get entry"))
|
||||||
e.map_err_trace_exit_unwrap()
|
.and_then_ok(|e| {
|
||||||
.ok_or_else(|| Error::from(err_msg("Unable to get entry".to_owned())))
|
|
||||||
.map_err_trace_exit_unwrap()
|
|
||||||
})
|
|
||||||
.map(|e| {
|
|
||||||
let diag = Diagnostic::for_entry(&e);
|
let diag = Diagnostic::for_entry(&e);
|
||||||
debug!("Diagnostic for '{:?}' = {:?}", e.get_location(), diag);
|
debug!("Diagnostic for '{:?}' = {:?}", e.get_location(), diag);
|
||||||
drop(e);
|
drop(e);
|
||||||
diag
|
diag
|
||||||
})
|
})
|
||||||
.collect::<Result<Vec<_>>>()
|
.collect::<Result<Vec<_>>>()?;
|
||||||
.map_err_trace_exit_unwrap();
|
|
||||||
|
|
||||||
spinner.finish();
|
spinner.finish();
|
||||||
let n = diags.len();
|
let n = diags.len();
|
||||||
|
@ -220,38 +199,37 @@ impl ImagApplication for ImagDiagnostics {
|
||||||
|
|
||||||
let mut out = rt.stdout();
|
let mut out = rt.stdout();
|
||||||
|
|
||||||
do_write!(out, "imag version {}", { env!("CARGO_PKG_VERSION") });
|
write!(out, "imag version {}", { env!("CARGO_PKG_VERSION") })?;
|
||||||
do_write!(out, "");
|
write!(out, "")?;
|
||||||
do_write!(out, "{} entries", n);
|
write!(out, "{} entries", n)?;
|
||||||
|
|
||||||
for (k, v) in version_counts {
|
for (k, v) in version_counts {
|
||||||
do_write!(out, "{} entries with store version '{}'", v, k);
|
write!(out, "{} entries with store version '{}'", v, k)?;
|
||||||
}
|
}
|
||||||
if n != 0 {
|
if n != 0 {
|
||||||
do_write!(out, "{} header sections in the average entry", sum_header_sections / n);
|
write!(out, "{} header sections in the average entry", sum_header_sections / n)?;
|
||||||
do_write!(out, "{} average content bytecount", sum_bytecount_content / n);
|
write!(out, "{} average content bytecount", sum_bytecount_content / n)?;
|
||||||
do_write!(out, "{} average overall bytecount", sum_overall_byte_size / n);
|
write!(out, "{} average overall bytecount", sum_overall_byte_size / n)?;
|
||||||
|
|
||||||
if let Some((num, path)) = max_overall_byte_size {
|
if let Some((num, path)) = max_overall_byte_size {
|
||||||
do_write!(out, "Largest Entry ({} bytes): {}", num, path.local_display_string());
|
write!(out, "Largest Entry ({} bytes): {}", num, path.local_display_string())?;
|
||||||
}
|
}
|
||||||
|
|
||||||
do_write!(out, "{} average internal link count per entry", num_links / n);
|
write!(out, "{} average internal link count per entry", num_links / n)?;
|
||||||
|
|
||||||
if let Some((num, path)) = max_links {
|
if let Some((num, path)) = max_links {
|
||||||
do_write!(out, "Entry with most internal links ({}): {}",
|
write!(out, "Entry with most internal links ({}): {}",
|
||||||
num,
|
num,
|
||||||
path.local_display_string());
|
path.local_display_string())?;
|
||||||
}
|
}
|
||||||
do_write!(out, "{} verified entries", verified_count);
|
write!(out, "{} verified entries", verified_count)?;
|
||||||
do_write!(out, "{} unverified entries", unverified_count);
|
write!(out, "{} unverified entries", unverified_count)?;
|
||||||
if verbose {
|
if verbose {
|
||||||
for unve in unverified_entries.iter() {
|
for unve in unverified_entries.iter() {
|
||||||
do_write!(out, "Unverified: {}", unve);
|
write!(out, "Unverified: {}", unve)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -272,17 +250,12 @@ impl ImagApplication for ImagDiagnostics {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_config(rt: &Runtime, s: &'static str) -> Option<String> {
|
fn get_config(rt: &Runtime, s: &'static str) -> Result<Option<String>> {
|
||||||
rt.config().and_then(|cfg| {
|
let cfg = rt.config().ok_or_else(|| err_msg("No configuration"))?;
|
||||||
cfg.read(s)
|
|
||||||
.map_err(Error::from)
|
match cfg.read(s)? {
|
||||||
.map_err_trace_exit_unwrap()
|
Some(&Value::String(ref s)) => Ok(Some(s.to_owned())),
|
||||||
.map(|opt| match opt {
|
Some(_) => Err(err_msg("Config type wrong: 'rt.progressbar_style' should be a string")),
|
||||||
&Value::String(ref s) => s.to_owned(),
|
None => Ok(None),
|
||||||
_ => {
|
|
||||||
error!("Config type wrong: 'rt.progressbar_style' should be a string");
|
|
||||||
::std::process::exit(1)
|
|
||||||
}
|
}
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,7 @@ version = "3.0.0"
|
||||||
toml = "0.5.1"
|
toml = "0.5.1"
|
||||||
toml-query = "0.9.2"
|
toml-query = "0.9.2"
|
||||||
failure = "0.1.5"
|
failure = "0.1.5"
|
||||||
|
resiter = "0.3.0"
|
||||||
|
|
||||||
libimagstore = { version = "0.10.0", path = "../../../lib/core/libimagstore" }
|
libimagstore = { version = "0.10.0", path = "../../../lib/core/libimagstore" }
|
||||||
libimagrt = { version = "0.10.0", path = "../../../lib/core/libimagrt" }
|
libimagrt = { version = "0.10.0", path = "../../../lib/core/libimagrt" }
|
||||||
|
|
|
@ -37,6 +37,7 @@
|
||||||
extern crate clap;
|
extern crate clap;
|
||||||
#[macro_use] extern crate log;
|
#[macro_use] extern crate log;
|
||||||
extern crate failure;
|
extern crate failure;
|
||||||
|
extern crate resiter;
|
||||||
|
|
||||||
extern crate libimagentryedit;
|
extern crate libimagentryedit;
|
||||||
extern crate libimagerror;
|
extern crate libimagerror;
|
||||||
|
@ -44,16 +45,16 @@ extern crate libimagrt;
|
||||||
extern crate libimagstore;
|
extern crate libimagstore;
|
||||||
extern crate libimagutil;
|
extern crate libimagutil;
|
||||||
|
|
||||||
use libimagerror::trace::MapErrTrace;
|
|
||||||
use libimagerror::iter::TraceIterator;
|
|
||||||
use libimagentryedit::edit::Edit;
|
use libimagentryedit::edit::Edit;
|
||||||
use libimagentryedit::edit::EditHeader;
|
use libimagentryedit::edit::EditHeader;
|
||||||
use libimagrt::runtime::Runtime;
|
use libimagrt::runtime::Runtime;
|
||||||
use libimagrt::application::ImagApplication;
|
use libimagrt::application::ImagApplication;
|
||||||
use libimagstore::storeid::StoreIdIterator;
|
|
||||||
use libimagstore::iter::get::StoreIdGetIteratorExtension;
|
use libimagstore::iter::get::StoreIdGetIteratorExtension;
|
||||||
|
use libimagerror::iter::IterInnerOkOrElse;
|
||||||
|
|
||||||
use failure::Fallible as Result;
|
use failure::Fallible as Result;
|
||||||
|
use failure::err_msg;
|
||||||
|
use resiter::AndThen;
|
||||||
use clap::App;
|
use clap::App;
|
||||||
|
|
||||||
mod ui;
|
mod ui;
|
||||||
|
@ -68,39 +69,23 @@ impl ImagApplication for ImagEdit {
|
||||||
let edit_header = rt.cli().is_present("edit-header");
|
let edit_header = rt.cli().is_present("edit-header");
|
||||||
let edit_header_only = rt.cli().is_present("edit-header-only");
|
let edit_header_only = rt.cli().is_present("edit-header-only");
|
||||||
|
|
||||||
let sids = rt
|
rt.ids::<crate::ui::PathProvider>()?
|
||||||
.ids::<crate::ui::PathProvider>()
|
.ok_or_else(|| err_msg("No ids supplied"))?
|
||||||
.map_err_trace_exit_unwrap()
|
.into_iter()
|
||||||
.unwrap_or_else(|| {
|
.map(Ok)
|
||||||
error!("No ids supplied");
|
|
||||||
::std::process::exit(1);
|
|
||||||
})
|
|
||||||
.into_iter();
|
|
||||||
|
|
||||||
StoreIdIterator::new(Box::new(sids.into_iter().map(Ok)))
|
|
||||||
.into_get_iter(rt.store())
|
.into_get_iter(rt.store())
|
||||||
.trace_unwrap_exit()
|
.map_inner_ok_or_else(|| err_msg("Did not find one entry"))
|
||||||
.map(|o| o.unwrap_or_else(|| {
|
.inspect(|e| debug!("Editing = {:?}", e))
|
||||||
error!("Did not find one entry");
|
.and_then_ok(|mut entry| {
|
||||||
::std::process::exit(1)
|
|
||||||
}))
|
|
||||||
.for_each(|mut entry| {
|
|
||||||
if edit_header {
|
if edit_header {
|
||||||
let _ = entry
|
entry.edit_header_and_content(&rt)
|
||||||
.edit_header_and_content(&rt)
|
|
||||||
.map_err_trace_exit_unwrap();
|
|
||||||
} else if edit_header_only {
|
} else if edit_header_only {
|
||||||
let _ = entry
|
entry.edit_header(&rt)
|
||||||
.edit_header(&rt)
|
|
||||||
.map_err_trace_exit_unwrap();
|
|
||||||
} else {
|
} else {
|
||||||
let _ = entry
|
entry.edit_content(&rt)
|
||||||
.edit_content(&rt)
|
|
||||||
.map_err_trace_exit_unwrap();
|
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
|
.collect()
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_cli<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
|
fn build_cli<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
|
||||||
|
|
|
@ -38,12 +38,11 @@ extern crate clap;
|
||||||
#[macro_use] extern crate log;
|
#[macro_use] extern crate log;
|
||||||
extern crate toml;
|
extern crate toml;
|
||||||
extern crate toml_query;
|
extern crate toml_query;
|
||||||
extern crate failure;
|
#[macro_use] extern crate failure;
|
||||||
|
|
||||||
extern crate libimagrt;
|
extern crate libimagrt;
|
||||||
extern crate libimagerror;
|
extern crate libimagerror;
|
||||||
|
|
||||||
use std::io::Write;
|
|
||||||
use std::io::ErrorKind;
|
use std::io::ErrorKind;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
|
|
||||||
|
@ -51,9 +50,9 @@ use toml::Value;
|
||||||
use toml_query::read::TomlValueReadExt;
|
use toml_query::read::TomlValueReadExt;
|
||||||
use clap::App;
|
use clap::App;
|
||||||
use failure::Fallible as Result;
|
use failure::Fallible as Result;
|
||||||
|
use failure::ResultExt;
|
||||||
|
use failure::err_msg;
|
||||||
|
|
||||||
use libimagerror::exit::ExitUnwrap;
|
|
||||||
use libimagerror::io::ToExitCode;
|
|
||||||
use libimagrt::runtime::Runtime;
|
use libimagrt::runtime::Runtime;
|
||||||
use libimagrt::application::ImagApplication;
|
use libimagrt::application::ImagApplication;
|
||||||
|
|
||||||
|
@ -68,29 +67,19 @@ impl ImagApplication for ImagGit {
|
||||||
fn run(rt: Runtime) -> Result<()> {
|
fn run(rt: Runtime) -> Result<()> {
|
||||||
let execute_in_store = rt
|
let execute_in_store = rt
|
||||||
.config()
|
.config()
|
||||||
.unwrap_or_else(|| {
|
.ok_or_else(|| err_msg("No configuration. Please use git yourself, not via imag-git"))
|
||||||
error!("No configuration. Please use git yourself, not via imag-git");
|
.context("Won't continue without configuration.")
|
||||||
error!("Won't continue without configuration.");
|
?
|
||||||
::std::process::exit(1);
|
|
||||||
})
|
|
||||||
.read("git.execute_in_store")
|
.read("git.execute_in_store")
|
||||||
.unwrap_or_else(|e| {
|
.context("Failed to read config setting 'git.execute_in_store'")
|
||||||
error!("Failed to read config setting 'git.execute_in_store'");
|
?
|
||||||
error!("-> {:?}", e);
|
.ok_or_else(|| err_msg("Missing config setting 'git.execute_in_store'"))
|
||||||
::std::process::exit(1)
|
?;
|
||||||
})
|
|
||||||
.unwrap_or_else(|| {
|
|
||||||
error!("Missing config setting 'git.execute_in_store'");
|
|
||||||
::std::process::exit(1)
|
|
||||||
});
|
|
||||||
|
|
||||||
let execute_in_store = match *execute_in_store {
|
let execute_in_store = match *execute_in_store {
|
||||||
Value::Boolean(b) => b,
|
Value::Boolean(b) => Ok(b),
|
||||||
_ => {
|
_ => Err(err_msg("Type error: 'git.execute_in_store' is not a boolean!")),
|
||||||
error!("Type error: 'git.execute_in_store' is not a boolean!");
|
}?;
|
||||||
::std::process::exit(1)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let execpath = if execute_in_store {
|
let execpath = if execute_in_store {
|
||||||
rt.store().path().to_str()
|
rt.store().path().to_str()
|
||||||
|
@ -98,11 +87,7 @@ impl ImagApplication for ImagGit {
|
||||||
rt.rtp().to_str()
|
rt.rtp().to_str()
|
||||||
}
|
}
|
||||||
.map(String::from)
|
.map(String::from)
|
||||||
.unwrap_or_else(|| {
|
.ok_or_else(|| format_err!("Cannot parse to string: {:?}", rt.store().path()))?;
|
||||||
error!("Cannot parse to string: {:?}", rt.store().path());
|
|
||||||
::std::process::exit(1)
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
let mut command = Command::new("git");
|
let mut command = Command::new("git");
|
||||||
command
|
command
|
||||||
|
@ -120,8 +105,7 @@ impl ImagApplication for ImagGit {
|
||||||
debug!("Adding args = {:?}", args);
|
debug!("Adding args = {:?}", args);
|
||||||
command.args(&args);
|
command.args(&args);
|
||||||
|
|
||||||
match rt.cli().subcommand() {
|
if let (external, Some(ext_m)) = rt.cli().subcommand() {
|
||||||
(external, Some(ext_m)) => {
|
|
||||||
command.arg(external);
|
command.arg(external);
|
||||||
let args = ext_m
|
let args = ext_m
|
||||||
.values_of("")
|
.values_of("")
|
||||||
|
@ -130,54 +114,31 @@ impl ImagApplication for ImagGit {
|
||||||
|
|
||||||
debug!("Adding subcommand '{}' and args = {:?}", external, args);
|
debug!("Adding subcommand '{}' and args = {:?}", external, args);
|
||||||
command.args(&args);
|
command.args(&args);
|
||||||
},
|
|
||||||
_ => {},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut out = rt.stdout();
|
|
||||||
|
|
||||||
debug!("Calling: {:?}", command);
|
debug!("Calling: {:?}", command);
|
||||||
|
|
||||||
match command.spawn().and_then(|mut c| c.wait()) {
|
match command.spawn().and_then(|mut c| c.wait()) {
|
||||||
Ok(exit_status) => {
|
Ok(exit_status) => {
|
||||||
if !exit_status.success() {
|
if !exit_status.success() {
|
||||||
debug!("git exited with non-zero exit code: {:?}", exit_status);
|
debug!("git exited with non-zero exit code: {:?}", exit_status);
|
||||||
let mut err = rt.stderr();
|
Err(format_err!("git exited with non-zero exit code: {:?}", exit_status))
|
||||||
writeln!(err, "git exited with non-zero exit code")
|
} else {
|
||||||
.to_exit_code()
|
|
||||||
.unwrap_or_exit();
|
|
||||||
::std::process::exit(exit_status.code().unwrap_or(1));
|
|
||||||
}
|
|
||||||
debug!("Successful exit!");
|
debug!("Successful exit!");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
debug!("Error calling git");
|
debug!("Error calling git");
|
||||||
match e.kind() {
|
Err(match e.kind() {
|
||||||
ErrorKind::NotFound => {
|
ErrorKind::NotFound => err_msg("Cannot find 'git' executable"),
|
||||||
let _ = writeln!(out, "Cannot find 'git' executable")
|
ErrorKind::PermissionDenied => err_msg("No permission to execute: 'git'"),
|
||||||
.to_exit_code()
|
_ => format_err!("Error spawning: {:?}", e),
|
||||||
.unwrap_or_exit();
|
})
|
||||||
::std::process::exit(1);
|
|
||||||
},
|
|
||||||
ErrorKind::PermissionDenied => {
|
|
||||||
let _ = writeln!(out, "No permission to execute: 'git'")
|
|
||||||
.to_exit_code()
|
|
||||||
.unwrap_or_exit();
|
|
||||||
::std::process::exit(1);
|
|
||||||
},
|
|
||||||
_ => {
|
|
||||||
let _ = writeln!(out, "Error spawning: {:?}", e)
|
|
||||||
.to_exit_code()
|
|
||||||
.unwrap_or_exit();
|
|
||||||
::std::process::exit(1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn build_cli<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
|
fn build_cli<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
|
||||||
ui::build_ui(app)
|
ui::build_ui(app)
|
||||||
|
|
|
@ -45,12 +45,11 @@ extern crate libimagerror;
|
||||||
extern crate libimagstore;
|
extern crate libimagstore;
|
||||||
|
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::process::exit;
|
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
use failure::Error;
|
||||||
use failure::err_msg;
|
|
||||||
use failure::Fallible as Result;
|
use failure::Fallible as Result;
|
||||||
|
use failure::err_msg;
|
||||||
use clap::App;
|
use clap::App;
|
||||||
|
|
||||||
use libimagstore::storeid::StoreId;
|
use libimagstore::storeid::StoreId;
|
||||||
|
@ -58,9 +57,6 @@ use libimagentrygps::types::*;
|
||||||
use libimagentrygps::entry::*;
|
use libimagentrygps::entry::*;
|
||||||
use libimagrt::application::ImagApplication;
|
use libimagrt::application::ImagApplication;
|
||||||
use libimagrt::runtime::Runtime;
|
use libimagrt::runtime::Runtime;
|
||||||
use libimagerror::trace::MapErrTrace;
|
|
||||||
use libimagerror::exit::ExitUnwrap;
|
|
||||||
use libimagerror::io::ToExitCode;
|
|
||||||
|
|
||||||
mod ui;
|
mod ui;
|
||||||
|
|
||||||
|
@ -71,22 +67,22 @@ mod ui;
|
||||||
pub enum ImagGps {}
|
pub enum ImagGps {}
|
||||||
impl ImagApplication for ImagGps {
|
impl ImagApplication for ImagGps {
|
||||||
fn run(rt: Runtime) -> Result<()> {
|
fn run(rt: Runtime) -> Result<()> {
|
||||||
if let Some(name) = rt.cli().subcommand_name() {
|
match rt.cli().subcommand_name().ok_or_else(|| err_msg("No subcommand called"))? {
|
||||||
match name {
|
|
||||||
"add" => add(&rt),
|
"add" => add(&rt),
|
||||||
"remove" => remove(&rt),
|
"remove" => remove(&rt),
|
||||||
"get" => get(&rt),
|
"get" => get(&rt),
|
||||||
other => {
|
other => {
|
||||||
debug!("Unknown command");
|
debug!("Unknown command");
|
||||||
let _ = rt.handle_unknown_subcommand("imag-gps", other, rt.cli())
|
if rt.handle_unknown_subcommand("imag-gps", other, rt.cli())
|
||||||
.map_err_trace_exit_unwrap()
|
.map_err(Error::from)?
|
||||||
.code()
|
.success()
|
||||||
.map(::std::process::exit);
|
{
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(format_err!("Subcommand failed"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_cli<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
|
fn build_cli<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
|
||||||
|
@ -106,46 +102,33 @@ impl ImagApplication for ImagGps {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rt_get_ids(rt: &Runtime) -> Vec<StoreId> {
|
fn rt_get_ids(rt: &Runtime) -> Result<Vec<StoreId>> {
|
||||||
rt
|
rt
|
||||||
.ids::<crate::ui::PathProvider>()
|
.ids::<crate::ui::PathProvider>()?
|
||||||
.map_err_trace_exit_unwrap()
|
.ok_or_else(|| err_msg("No ids supplied"))
|
||||||
.unwrap_or_else(|| {
|
|
||||||
error!("No ids supplied");
|
|
||||||
::std::process::exit(1);
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add(rt: &Runtime) {
|
fn add(rt: &Runtime) -> Result<()> {
|
||||||
let c = {
|
let c = {
|
||||||
let parse = |value: &str| -> (i64, i64, i64) {
|
let parse = |value: &str| -> Result<(i64, i64, i64)> {
|
||||||
debug!("Parsing '{}' into degree, minute and second", value);
|
debug!("Parsing '{}' into degree, minute and second", value);
|
||||||
let ary = value.split('.')
|
let ary = value.split('.')
|
||||||
.map(|v| {debug!("Parsing = {}", v); v})
|
.map(|v| {debug!("Parsing = {}", v); v})
|
||||||
.map(FromStr::from_str)
|
.map(FromStr::from_str)
|
||||||
.map(|elem| {
|
.map(|elem| elem.or_else(|_| Err(err_msg("Error while converting number"))))
|
||||||
elem.or_else(|_| Err(err_msg("Error while converting number")))
|
.collect::<Result<Vec<i64>>>()?;
|
||||||
.map_err_trace_exit_unwrap()
|
|
||||||
})
|
|
||||||
.collect::<Vec<i64>>();
|
|
||||||
|
|
||||||
let degree = ary.get(0).unwrap_or_else(|| {
|
let degree = ary.get(0).ok_or_else(|| err_msg("Degree missing. This value is required."))?;
|
||||||
error!("Degree missing. This value is required.");
|
let minute = ary.get(1).ok_or_else(|| err_msg("Degree missing. This value is required."))?;
|
||||||
exit(1)
|
|
||||||
});
|
|
||||||
let minute = ary.get(1).unwrap_or_else(|| {
|
|
||||||
error!("Degree missing. This value is required.");
|
|
||||||
exit(1)
|
|
||||||
});
|
|
||||||
let second = ary.get(2).unwrap_or(&0);
|
let second = ary.get(2).unwrap_or(&0);
|
||||||
|
|
||||||
(*degree, *minute, *second)
|
Ok((*degree, *minute, *second))
|
||||||
};
|
};
|
||||||
|
|
||||||
let scmd = rt.cli().subcommand_matches("add").unwrap(); // safed by main()
|
let scmd = rt.cli().subcommand_matches("add").unwrap(); // safed by main()
|
||||||
|
|
||||||
let long = parse(scmd.value_of("longitude").unwrap()); // unwrap safed by clap
|
let long = parse(scmd.value_of("longitude").unwrap())?; // unwrap safed by clap
|
||||||
let lati = parse(scmd.value_of("latitude").unwrap()); // unwrap safed by clap
|
let lati = parse(scmd.value_of("latitude").unwrap())?; // unwrap safed by clap
|
||||||
|
|
||||||
let long = GPSValue::new(long.0, long.1, long.2);
|
let long = GPSValue::new(long.0, long.1, long.2);
|
||||||
let lati = GPSValue::new(lati.0, lati.1, lati.2);
|
let lati = GPSValue::new(lati.0, lati.1, lati.2);
|
||||||
|
@ -153,82 +136,66 @@ fn add(rt: &Runtime) {
|
||||||
Coordinates::new(long, lati)
|
Coordinates::new(long, lati)
|
||||||
};
|
};
|
||||||
|
|
||||||
rt_get_ids(&rt)
|
rt_get_ids(&rt)?
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.for_each(|id| {
|
.map(|id| {
|
||||||
rt.store()
|
rt.store()
|
||||||
.get(id.clone())
|
.get(id.clone())?
|
||||||
.map_err_trace_exit_unwrap()
|
.ok_or_else(|| format_err!("No such entry: {}", id))?
|
||||||
.unwrap_or_else(|| { // if we have Ok(None)
|
.set_coordinates(c.clone())?;
|
||||||
error!("No such entry: {}", id);
|
|
||||||
exit(1)
|
|
||||||
})
|
|
||||||
.set_coordinates(c.clone())
|
|
||||||
.map_err_trace_exit_unwrap();
|
|
||||||
|
|
||||||
rt.report_touched(&id).unwrap_or_exit();
|
rt.report_touched(&id).map_err(Error::from)
|
||||||
});
|
})
|
||||||
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove(rt: &Runtime) {
|
fn remove(rt: &Runtime) -> Result<()> {
|
||||||
let print_removed = rt
|
let print_removed = rt
|
||||||
.cli()
|
.cli()
|
||||||
.subcommand_matches("remove")
|
.subcommand_matches("remove")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.is_present("print-removed"); // safed by main()
|
.is_present("print-removed"); // safed by main()
|
||||||
|
|
||||||
rt_get_ids(&rt)
|
rt_get_ids(&rt)?
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.for_each(|id| {
|
.map(|id| {
|
||||||
let removed_value = rt
|
let removed_value : Coordinates = rt
|
||||||
.store()
|
.store()
|
||||||
.get(id.clone())
|
.get(id.clone())?
|
||||||
.map_err_trace_exit_unwrap()
|
.ok_or_else(|| format_err!("No such entry: {}", id))?
|
||||||
.unwrap_or_else(|| { // if we have Ok(None)
|
.remove_coordinates()?
|
||||||
error!("No such entry: {}", id);
|
.ok_or_else(|| format_err!("Entry had no coordinates: {}", id))??;
|
||||||
exit(1)
|
|
||||||
})
|
|
||||||
.remove_coordinates()
|
|
||||||
.map_err_trace_exit_unwrap() // The delete action failed
|
|
||||||
.unwrap_or_else(|| { // if we have Ok(None)
|
|
||||||
error!("Entry had no coordinates: {}", id);
|
|
||||||
exit(1)
|
|
||||||
})
|
|
||||||
.map_err_trace_exit_unwrap(); // The parsing of the deleted values failed
|
|
||||||
|
|
||||||
if print_removed {
|
if print_removed {
|
||||||
writeln!(rt.stdout(), "{}", removed_value).to_exit_code().unwrap_or_exit();
|
writeln!(rt.stdout(), "{}", removed_value)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
rt.report_touched(&id).unwrap_or_exit();
|
rt.report_touched(&id).map_err(Error::from)
|
||||||
});
|
})
|
||||||
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get(rt: &Runtime) {
|
fn get(rt: &Runtime) -> Result<()> {
|
||||||
let mut stdout = rt.stdout();
|
let mut stdout = rt.stdout();
|
||||||
|
|
||||||
rt_get_ids(&rt)
|
rt_get_ids(&rt)?
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.for_each(|id| {
|
.map(|id| {
|
||||||
let value = rt
|
let value = rt
|
||||||
.store()
|
.store()
|
||||||
.get(id.clone())
|
.get(id.clone())?
|
||||||
.map_err_trace_exit_unwrap()
|
.ok_or_else(|| { // if we have Ok(None)
|
||||||
.unwrap_or_else(|| { // if we have Ok(None)
|
format_err!("No such entry: {}", id)
|
||||||
error!("No such entry: {}", id);
|
})?
|
||||||
exit(1)
|
.get_coordinates()?
|
||||||
|
.ok_or_else(|| { // if we have Ok(None)
|
||||||
|
format_err!("Entry has no coordinates: {}", id)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
writeln!(stdout, "{}", value)?;
|
||||||
|
|
||||||
|
rt.report_touched(&id).map_err(Error::from)
|
||||||
})
|
})
|
||||||
.get_coordinates()
|
.collect()
|
||||||
.map_err_trace_exit_unwrap() // The get action failed
|
|
||||||
.unwrap_or_else(|| { // if we have Ok(None)
|
|
||||||
error!("Entry has no coordinates: {}", id);
|
|
||||||
exit(1)
|
|
||||||
});
|
|
||||||
|
|
||||||
writeln!(stdout, "{}", value).to_exit_code().unwrap_or_exit();
|
|
||||||
|
|
||||||
rt.report_touched(&id).unwrap_or_exit();
|
|
||||||
})
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@ maintenance = { status = "actively-developed" }
|
||||||
log = "0.4.6"
|
log = "0.4.6"
|
||||||
regex = "1.1.7"
|
regex = "1.1.7"
|
||||||
failure = "0.1.5"
|
failure = "0.1.5"
|
||||||
|
resiter = "0.3.0"
|
||||||
|
|
||||||
libimagstore = { version = "0.10.0", path = "../../../lib/core/libimagstore" }
|
libimagstore = { version = "0.10.0", path = "../../../lib/core/libimagstore" }
|
||||||
libimagrt = { version = "0.10.0", path = "../../../lib/core/libimagrt" }
|
libimagrt = { version = "0.10.0", path = "../../../lib/core/libimagrt" }
|
||||||
|
|
|
@ -35,9 +35,10 @@
|
||||||
)]
|
)]
|
||||||
|
|
||||||
#[macro_use] extern crate log;
|
#[macro_use] extern crate log;
|
||||||
|
#[macro_use] extern crate failure;
|
||||||
extern crate clap;
|
extern crate clap;
|
||||||
extern crate regex;
|
extern crate regex;
|
||||||
extern crate failure;
|
extern crate resiter;
|
||||||
|
|
||||||
extern crate libimagstore;
|
extern crate libimagstore;
|
||||||
extern crate libimagrt;
|
extern crate libimagrt;
|
||||||
|
@ -46,15 +47,17 @@ extern crate libimagerror;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use failure::Fallible as Result;
|
|
||||||
use clap::App;
|
use clap::App;
|
||||||
|
use failure::Error;
|
||||||
|
use failure::Fallible as Result;
|
||||||
|
use failure::err_msg;
|
||||||
|
use resiter::AndThen;
|
||||||
|
|
||||||
use libimagrt::runtime::Runtime;
|
use libimagrt::runtime::Runtime;
|
||||||
use libimagrt::application::ImagApplication;
|
use libimagrt::application::ImagApplication;
|
||||||
use libimagstore::store::Entry;
|
use libimagstore::store::Entry;
|
||||||
use libimagerror::trace::MapErrTrace;
|
use libimagerror::iter::IterInnerOkOrElse;
|
||||||
use libimagerror::exit::ExitUnwrap;
|
|
||||||
use libimagerror::io::ToExitCode;
|
|
||||||
|
|
||||||
mod ui;
|
mod ui;
|
||||||
|
|
||||||
|
@ -82,34 +85,32 @@ impl ImagApplication for ImagGrep {
|
||||||
.value_of("pattern")
|
.value_of("pattern")
|
||||||
.map(Regex::new)
|
.map(Regex::new)
|
||||||
.unwrap() // ensured by clap
|
.unwrap() // ensured by clap
|
||||||
.unwrap_or_else(|e| {
|
.map_err(|e| format_err!("Regex building error: {:?}", e))?;
|
||||||
error!("Regex building error: {:?}", e);
|
|
||||||
::std::process::exit(1)
|
|
||||||
});
|
|
||||||
|
|
||||||
let overall_count = rt
|
let overall_count = rt
|
||||||
.store()
|
.store()
|
||||||
.entries()
|
.entries()?
|
||||||
.map_err_trace_exit_unwrap()
|
|
||||||
.into_get_iter()
|
.into_get_iter()
|
||||||
.filter_map(|res| res.map_err_trace_exit_unwrap())
|
.map_inner_ok_or_else(|| err_msg("Entry from entries missing"))
|
||||||
.filter_map(|entry| if pattern.is_match(entry.get_content()) {
|
.and_then_ok(|entry| {
|
||||||
show(&rt, &entry, &pattern, &opts, &mut count);
|
if pattern.is_match(entry.get_content()) {
|
||||||
Some(())
|
debug!("Matched: {}", entry.get_location());
|
||||||
|
show(&rt, &entry, &pattern, &opts, &mut count)
|
||||||
} else {
|
} else {
|
||||||
None
|
debug!("Not matched: {}", entry.get_location());
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.count();
|
.collect::<Result<Vec<_>>>()?
|
||||||
|
.len();
|
||||||
|
|
||||||
if opts.count {
|
if opts.count {
|
||||||
writeln!(rt.stdout(), "{}", count).to_exit_code().unwrap_or_exit();
|
writeln!(rt.stdout(), "{}", count)?;
|
||||||
} else if !opts.files_with_matches {
|
} else if !opts.files_with_matches {
|
||||||
writeln!(rt.stdout(), "Processed {} files, {} matches, {} nonmatches",
|
writeln!(rt.stdout(), "Processed {} files, {} matches, {} nonmatches",
|
||||||
overall_count,
|
overall_count,
|
||||||
count,
|
count,
|
||||||
overall_count - count)
|
overall_count - count)?;
|
||||||
.to_exit_code()
|
|
||||||
.unwrap_or_exit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -130,27 +131,28 @@ impl ImagApplication for ImagGrep {
|
||||||
fn version() -> &'static str {
|
fn version() -> &'static str {
|
||||||
env!("CARGO_PKG_VERSION")
|
env!("CARGO_PKG_VERSION")
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn show(rt: &Runtime, e: &Entry, re: &Regex, opts: &Options, count: &mut usize) {
|
fn show(rt: &Runtime, e: &Entry, re: &Regex, opts: &Options, count: &mut usize) -> Result<()> {
|
||||||
if opts.files_with_matches {
|
if opts.files_with_matches {
|
||||||
writeln!(rt.stdout(), "{}", e.get_location()).to_exit_code().unwrap_or_exit();
|
writeln!(rt.stdout(), "{}", e.get_location())?;
|
||||||
} else if opts.count {
|
} else if opts.count {
|
||||||
*count += 1;
|
*count += 1;
|
||||||
} else {
|
} else {
|
||||||
writeln!(rt.stdout(), "{}:", e.get_location()).to_exit_code().unwrap_or_exit();
|
writeln!(rt.stdout(), "{}:", e.get_location())?;
|
||||||
for capture in re.captures_iter(e.get_content()) {
|
for capture in re.captures_iter(e.get_content()) {
|
||||||
for mtch in capture.iter() {
|
for mtch in capture.iter() {
|
||||||
if let Some(m) = mtch {
|
if let Some(m) = mtch {
|
||||||
writeln!(rt.stdout(), " '{}'", m.as_str()).to_exit_code().unwrap_or_exit();
|
writeln!(rt.stdout(), " '{}'", m.as_str())?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
writeln!(rt.stdout()).to_exit_code().unwrap_or_exit();
|
writeln!(rt.stdout())?;
|
||||||
*count += 1;
|
*count += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
rt.report_touched(e.get_location()).unwrap_or_exit();
|
rt.report_touched(e.get_location()).map_err(Error::from)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,7 @@ toml = "0.5.1"
|
||||||
toml-query = "0.9.2"
|
toml-query = "0.9.2"
|
||||||
filters = "0.3.0"
|
filters = "0.3.0"
|
||||||
failure = "0.1.5"
|
failure = "0.1.5"
|
||||||
|
resiter = "0.3.0"
|
||||||
|
|
||||||
libimagstore = { version = "0.10.0", path = "../../../lib/core/libimagstore" }
|
libimagstore = { version = "0.10.0", path = "../../../lib/core/libimagstore" }
|
||||||
libimagrt = { version = "0.10.0", path = "../../../lib/core/libimagrt" }
|
libimagrt = { version = "0.10.0", path = "../../../lib/core/libimagrt" }
|
||||||
|
|
|
@ -34,10 +34,11 @@
|
||||||
|
|
||||||
extern crate clap;
|
extern crate clap;
|
||||||
#[macro_use] extern crate log;
|
#[macro_use] extern crate log;
|
||||||
|
#[macro_use] extern crate failure;
|
||||||
extern crate toml;
|
extern crate toml;
|
||||||
extern crate toml_query;
|
extern crate toml_query;
|
||||||
extern crate filters;
|
extern crate filters;
|
||||||
extern crate failure;
|
extern crate resiter;
|
||||||
|
|
||||||
extern crate libimagentryedit;
|
extern crate libimagentryedit;
|
||||||
extern crate libimagerror;
|
extern crate libimagerror;
|
||||||
|
@ -52,18 +53,17 @@ use std::string::ToString;
|
||||||
use clap::{App, ArgMatches};
|
use clap::{App, ArgMatches};
|
||||||
use filters::filter::Filter;
|
use filters::filter::Filter;
|
||||||
use toml::Value;
|
use toml::Value;
|
||||||
use failure::{Fallible as Result, Error};
|
use failure::Error;
|
||||||
|
use failure::Fallible as Result;
|
||||||
|
use failure::err_msg;
|
||||||
|
use resiter::FilterMap;
|
||||||
|
use resiter::AndThen;
|
||||||
|
|
||||||
use libimagerror::exit::ExitCode;
|
|
||||||
use libimagerror::exit::ExitUnwrap;
|
|
||||||
use libimagerror::io::ToExitCode;
|
|
||||||
use libimagerror::iter::TraceIterator;
|
|
||||||
use libimagerror::trace::MapErrTrace;
|
|
||||||
use libimagrt::runtime::Runtime;
|
use libimagrt::runtime::Runtime;
|
||||||
use libimagrt::application::ImagApplication;
|
use libimagrt::application::ImagApplication;
|
||||||
use libimagstore::iter::get::StoreIdGetIteratorExtension;
|
use libimagstore::iter::get::StoreIdGetIteratorExtension;
|
||||||
use libimagstore::store::FileLockEntry;
|
use libimagstore::store::FileLockEntry;
|
||||||
use libimagstore::storeid::StoreIdIterator;
|
use libimagerror::iter::IterInnerOkOrElse;
|
||||||
|
|
||||||
use toml_query::read::TomlValueReadExt;
|
use toml_query::read::TomlValueReadExt;
|
||||||
use toml_query::read::TomlValueReadTypeExt;
|
use toml_query::read::TomlValueReadTypeExt;
|
||||||
|
@ -85,22 +85,16 @@ impl ImagApplication for ImagHeader {
|
||||||
trace!("list_output_with_ids = {:?}", list_output_with_ids );
|
trace!("list_output_with_ids = {:?}", list_output_with_ids );
|
||||||
trace!("list_output_with_ids_fmt = {:?}", list_output_with_ids_fmt);
|
trace!("list_output_with_ids_fmt = {:?}", list_output_with_ids_fmt);
|
||||||
|
|
||||||
let sids = rt
|
let iter = rt
|
||||||
.ids::<crate::ui::PathProvider>()
|
.ids::<crate::ui::PathProvider>()?
|
||||||
.map_err_trace_exit_unwrap()
|
.ok_or_else(|| err_msg("No ids supplied"))?
|
||||||
.unwrap_or_else(|| {
|
.into_iter()
|
||||||
error!("No ids supplied");
|
.map(Ok)
|
||||||
::std::process::exit(1);
|
|
||||||
})
|
|
||||||
.into_iter();
|
|
||||||
|
|
||||||
let iter = StoreIdIterator::new(Box::new(sids.map(Ok)))
|
|
||||||
.into_get_iter(rt.store())
|
.into_get_iter(rt.store())
|
||||||
.trace_unwrap_exit()
|
.map_inner_ok_or_else(|| err_msg("Did not find one entry"));
|
||||||
.filter_map(|x| x);
|
|
||||||
|
|
||||||
match rt.cli().subcommand() {
|
match rt.cli().subcommand() {
|
||||||
("read", Some(mtch)) => ::std::process::exit(read(&rt, mtch, iter)),
|
("read", Some(mtch)) => read(&rt, mtch, iter),
|
||||||
("has", Some(mtch)) => has(&rt, mtch, iter),
|
("has", Some(mtch)) => has(&rt, mtch, iter),
|
||||||
("hasnt", Some(mtch)) => hasnt(&rt, mtch, iter),
|
("hasnt", Some(mtch)) => hasnt(&rt, mtch, iter),
|
||||||
("int", Some(mtch)) => int(&rt, mtch, iter),
|
("int", Some(mtch)) => int(&rt, mtch, iter),
|
||||||
|
@ -109,16 +103,16 @@ impl ImagApplication for ImagHeader {
|
||||||
("bool", Some(mtch)) => boolean(&rt, mtch, iter),
|
("bool", Some(mtch)) => boolean(&rt, mtch, iter),
|
||||||
(other, _mtchs) => {
|
(other, _mtchs) => {
|
||||||
debug!("Unknown command");
|
debug!("Unknown command");
|
||||||
::std::process::exit({
|
if rt.handle_unknown_subcommand("imag-header", other, rt.cli())
|
||||||
rt.handle_unknown_subcommand("imag-header", other, rt.cli())
|
.map_err(Error::from)?
|
||||||
.map_err_trace_exit_unwrap()
|
.success()
|
||||||
.code()
|
{
|
||||||
.unwrap_or(1)
|
|
||||||
});
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(format_err!("Subcommand failed"))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_cli<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
|
fn build_cli<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
|
||||||
|
@ -138,21 +132,20 @@ impl ImagApplication for ImagHeader {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read<'a, 'e, I>(rt: &Runtime, mtch: &ArgMatches<'a>, iter: I) -> i32
|
fn read<'a, 'e, I>(rt: &Runtime, mtch: &ArgMatches<'a>, iter: I) -> Result<()>
|
||||||
where I: Iterator<Item = FileLockEntry<'e>>
|
where I: Iterator<Item = Result<FileLockEntry<'e>>>
|
||||||
{
|
{
|
||||||
debug!("Processing headers: reading value");
|
debug!("Processing headers: reading value");
|
||||||
let header_path = get_header_path(mtch, "header-value-path");
|
let header_path = get_header_path(mtch, "header-value-path");
|
||||||
let mut output = rt.stdout();
|
let mut output = rt.stdout();
|
||||||
trace!("Got output: {:?}", output);
|
trace!("Got output: {:?}", output);
|
||||||
|
|
||||||
iter.fold(0, |accu, entry| {
|
iter.and_then_ok(|entry| {
|
||||||
trace!("Processing headers: working on {:?}", entry.get_location());
|
trace!("Processing headers: working on {:?}", entry.get_location());
|
||||||
entry.get_header()
|
entry.get_header()
|
||||||
.read(header_path)
|
.read(header_path)?
|
||||||
.map_err(Error::from)
|
.ok_or_else(|| format_err!("Value not present for entry {} at {}", entry.get_location(), header_path))
|
||||||
.map_err_trace_exit_unwrap()
|
.and_then(|value| {
|
||||||
.map(|value| {
|
|
||||||
trace!("Processing headers: Got value {:?}", value);
|
trace!("Processing headers: Got value {:?}", value);
|
||||||
|
|
||||||
let string_representation = match value {
|
let string_representation = match value {
|
||||||
|
@ -164,65 +157,56 @@ fn read<'a, 'e, I>(rt: &Runtime, mtch: &ArgMatches<'a>, iter: I) -> i32
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(repr) = string_representation {
|
if let Some(repr) = string_representation {
|
||||||
writeln!(output, "{}", repr)
|
writeln!(output, "{}", repr)?;
|
||||||
} else {
|
} else {
|
||||||
writeln!(output, "{}", value)
|
writeln!(output, "{}", value)?;
|
||||||
}
|
}
|
||||||
.to_exit_code()
|
Ok(())
|
||||||
.map(|_| accu)
|
|
||||||
.unwrap_or_else(ExitCode::code)
|
|
||||||
})
|
|
||||||
.unwrap_or_else(|| {
|
|
||||||
// if value not present and configured
|
|
||||||
error!("Value not present for entry {} at {}", entry.get_location(), header_path);
|
|
||||||
1
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
.collect::<Result<()>>()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn has<'a, 'e, I>(rt: &Runtime, mtch: &ArgMatches<'a>, iter: I)
|
fn has<'a, 'e, I>(rt: &Runtime, mtch: &ArgMatches<'a>, iter: I) -> Result<()>
|
||||||
where I: Iterator<Item = FileLockEntry<'e>>
|
where I: Iterator<Item = Result<FileLockEntry<'e>>>
|
||||||
{
|
{
|
||||||
debug!("Processing headers: has value");
|
debug!("Processing headers: has value");
|
||||||
let header_path = get_header_path(mtch, "header-value-path");
|
let header_path = get_header_path(mtch, "header-value-path");
|
||||||
let mut output = rt.stdout();
|
let mut output = rt.stdout();
|
||||||
|
|
||||||
iter.for_each(|entry| {
|
iter.and_then_ok(|entry| {
|
||||||
trace!("Processing headers: working on {:?}", entry.get_location());
|
trace!("Processing headers: working on {:?}", entry.get_location());
|
||||||
if entry.get_header()
|
if let Some(_) = entry.get_header().read(header_path)? {
|
||||||
.read(header_path)
|
|
||||||
.map_err(Error::from)
|
|
||||||
.map_err_trace_exit_unwrap()
|
|
||||||
.is_some()
|
|
||||||
{
|
|
||||||
rt.report_touched(entry.get_location()).unwrap_or_exit();
|
|
||||||
if !rt.output_is_pipe() {
|
if !rt.output_is_pipe() {
|
||||||
writeln!(output, "{}", entry.get_location()).to_exit_code().unwrap_or_exit();
|
writeln!(output, "{}", entry.get_location())?;
|
||||||
}
|
}
|
||||||
|
rt.report_touched(entry.get_location()).map_err(Error::from)
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
.collect::<Result<()>>()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn hasnt<'a, 'e, I>(rt: &Runtime, mtch: &ArgMatches<'a>, iter: I)
|
fn hasnt<'a, 'e, I>(rt: &Runtime, mtch: &ArgMatches<'a>, iter: I) -> Result<()>
|
||||||
where I: Iterator<Item = FileLockEntry<'e>>
|
where I: Iterator<Item = Result<FileLockEntry<'e>>>
|
||||||
{
|
{
|
||||||
debug!("Processing headers: hasnt value");
|
debug!("Processing headers: hasnt value");
|
||||||
let header_path = get_header_path(mtch, "header-value-path");
|
let header_path = get_header_path(mtch, "header-value-path");
|
||||||
let mut output = rt.stdout();
|
let mut output = rt.stdout();
|
||||||
|
|
||||||
iter.for_each(|entry| {
|
iter.and_then_ok(|entry| {
|
||||||
trace!("Processing headers: working on {:?}", entry.get_location());
|
trace!("Processing headers: working on {:?}", entry.get_location());
|
||||||
if entry.get_header()
|
if let Some(_) = entry.get_header().read(header_path)? {
|
||||||
.read(header_path)
|
Ok(())
|
||||||
.map_err(Error::from)
|
} else {
|
||||||
.map_err_trace_exit_unwrap()
|
|
||||||
.is_none() {
|
|
||||||
rt.report_touched(entry.get_location()).unwrap_or_exit();
|
|
||||||
if !rt.output_is_pipe() {
|
if !rt.output_is_pipe() {
|
||||||
writeln!(output, "{}", entry.get_location()).to_exit_code().unwrap_or_exit();
|
writeln!(output, "{}", entry.get_location())?;
|
||||||
}
|
}
|
||||||
|
rt.report_touched(entry.get_location()).map_err(Error::from)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! implement_compare {
|
macro_rules! implement_compare {
|
||||||
|
@ -238,8 +222,8 @@ macro_rules! implement_compare {
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn int<'a, 'e, I>(rt: &Runtime, mtch: &ArgMatches<'a>, iter: I)
|
fn int<'a, 'e, I>(rt: &Runtime, mtch: &ArgMatches<'a>, iter: I) -> Result<()>
|
||||||
where I: Iterator<Item = FileLockEntry<'e>>
|
where I: Iterator<Item = Result<FileLockEntry<'e>>>
|
||||||
{
|
{
|
||||||
debug!("Processing headers: int value");
|
debug!("Processing headers: int value");
|
||||||
let header_path = get_header_path(mtch, "header-value-path");
|
let header_path = get_header_path(mtch, "header-value-path");
|
||||||
|
@ -264,20 +248,20 @@ fn int<'a, 'e, I>(rt: &Runtime, mtch: &ArgMatches<'a>, iter: I)
|
||||||
implement_compare!(mtch, "header-int-gte", i64, |cmp| *i >= cmp)
|
implement_compare!(mtch, "header-int-gte", i64, |cmp| *i >= cmp)
|
||||||
});
|
});
|
||||||
|
|
||||||
iter.filter(|entry| if let Some(hdr) = entry.get_header()
|
iter.and_then_ok(|entry| {
|
||||||
.read_int(header_path)
|
if let Some(hdr) = entry.get_header().read_int(header_path)? {
|
||||||
.map_err(Error::from)
|
Ok((filter.filter(&hdr), entry))
|
||||||
.map_err_trace_exit_unwrap()
|
|
||||||
{
|
|
||||||
filter.filter(&hdr)
|
|
||||||
} else {
|
} else {
|
||||||
false
|
Ok((false, entry))
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.for_each(|entry| rt.report_touched(entry.get_location()).unwrap_or_exit())
|
.filter_map_ok(|(b, e)| if b { Some(e) } else { None })
|
||||||
|
.and_then_ok(|entry| rt.report_touched(entry.get_location()).map_err(Error::from))
|
||||||
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn float<'a, 'e, I>(rt: &Runtime, mtch: &ArgMatches<'a>, iter: I)
|
fn float<'a, 'e, I>(rt: &Runtime, mtch: &ArgMatches<'a>, iter: I) -> Result<()>
|
||||||
where I: Iterator<Item = FileLockEntry<'e>>
|
where I: Iterator<Item = Result<FileLockEntry<'e>>>
|
||||||
{
|
{
|
||||||
debug!("Processing headers: float value");
|
debug!("Processing headers: float value");
|
||||||
let header_path = get_header_path(mtch, "header-value-path");
|
let header_path = get_header_path(mtch, "header-value-path");
|
||||||
|
@ -302,20 +286,20 @@ fn float<'a, 'e, I>(rt: &Runtime, mtch: &ArgMatches<'a>, iter: I)
|
||||||
implement_compare!(mtch, "header-float-gte", f64, |cmp| *i >= cmp)
|
implement_compare!(mtch, "header-float-gte", f64, |cmp| *i >= cmp)
|
||||||
});
|
});
|
||||||
|
|
||||||
iter.filter(|entry| if let Some(hdr) = entry.get_header()
|
iter.and_then_ok(|entry| {
|
||||||
.read_float(header_path)
|
if let Some(hdr) = entry.get_header().read_float(header_path)? {
|
||||||
.map_err(Error::from)
|
Ok((filter.filter(&hdr), entry))
|
||||||
.map_err_trace_exit_unwrap()
|
|
||||||
{
|
|
||||||
filter.filter(&hdr)
|
|
||||||
} else {
|
} else {
|
||||||
false
|
Ok((false, entry))
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.for_each(|entry| rt.report_touched(entry.get_location()).unwrap_or_exit())
|
.filter_map_ok(|(b, e)| if b { Some(e) } else { None })
|
||||||
|
.and_then_ok(|entry| rt.report_touched(entry.get_location()).map_err(Error::from))
|
||||||
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn string<'a, 'e, I>(rt: &Runtime, mtch: &ArgMatches<'a>, iter: I)
|
fn string<'a, 'e, I>(rt: &Runtime, mtch: &ArgMatches<'a>, iter: I) -> Result<()>
|
||||||
where I: Iterator<Item = FileLockEntry<'e>>
|
where I: Iterator<Item = Result<FileLockEntry<'e>>>
|
||||||
{
|
{
|
||||||
debug!("Processing headers: string value");
|
debug!("Processing headers: string value");
|
||||||
let header_path = get_header_path(mtch, "header-value-path");
|
let header_path = get_header_path(mtch, "header-value-path");
|
||||||
|
@ -328,20 +312,20 @@ fn string<'a, 'e, I>(rt: &Runtime, mtch: &ArgMatches<'a>, iter: I)
|
||||||
implement_compare!(mtch, "header-string-neq", String, |cmp| *i != cmp)
|
implement_compare!(mtch, "header-string-neq", String, |cmp| *i != cmp)
|
||||||
});
|
});
|
||||||
|
|
||||||
iter.filter(|entry| if let Some(hdr) = entry.get_header()
|
iter.and_then_ok(|entry| {
|
||||||
.read_string(header_path)
|
if let Some(hdr) = entry.get_header().read_string(header_path)? {
|
||||||
.map_err(Error::from)
|
Ok((filter.filter(&hdr), entry))
|
||||||
.map_err_trace_exit_unwrap()
|
|
||||||
{
|
|
||||||
filter.filter(&hdr)
|
|
||||||
} else {
|
} else {
|
||||||
false
|
Ok((false, entry))
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.for_each(|entry| rt.report_touched(entry.get_location()).unwrap_or_exit())
|
.filter_map_ok(|(b, e)| if b { Some(e) } else { None })
|
||||||
|
.and_then_ok(|entry| rt.report_touched(entry.get_location()).map_err(Error::from))
|
||||||
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn boolean<'a, 'e, I>(rt: &Runtime, mtch: &ArgMatches<'a>, iter: I)
|
fn boolean<'a, 'e, I>(rt: &Runtime, mtch: &ArgMatches<'a>, iter: I) -> Result<()>
|
||||||
where I: Iterator<Item = FileLockEntry<'e>>
|
where I: Iterator<Item = Result<FileLockEntry<'e>>>
|
||||||
{
|
{
|
||||||
debug!("Processing headers: bool value");
|
debug!("Processing headers: bool value");
|
||||||
let header_path = get_header_path(mtch, "header-value-path");
|
let header_path = get_header_path(mtch, "header-value-path");
|
||||||
|
@ -350,16 +334,16 @@ fn boolean<'a, 'e, I>(rt: &Runtime, mtch: &ArgMatches<'a>, iter: I)
|
||||||
.and(|i: &bool| -> bool { *i })
|
.and(|i: &bool| -> bool { *i })
|
||||||
.and(|i: &bool| -> bool { *i });
|
.and(|i: &bool| -> bool { *i });
|
||||||
|
|
||||||
iter.filter(|entry| if let Some(hdr) = entry.get_header()
|
iter.and_then_ok(|entry| {
|
||||||
.read_bool(header_path)
|
if let Some(hdr) = entry.get_header().read_bool(header_path)? {
|
||||||
.map_err(Error::from)
|
Ok((filter.filter(&hdr), entry))
|
||||||
.map_err_trace_exit_unwrap()
|
|
||||||
{
|
|
||||||
filter.filter(&hdr)
|
|
||||||
} else {
|
} else {
|
||||||
false
|
Ok((false, entry))
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.for_each(|entry| rt.report_touched(entry.get_location()).unwrap_or_exit())
|
.filter_map_ok(|(b, e)| if b { Some(e) } else { None })
|
||||||
|
.and_then_ok(|entry| rt.report_touched(entry.get_location()).map_err(Error::from))
|
||||||
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -51,12 +51,12 @@ extern crate libimagstore;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
|
||||||
use filters::filter::Filter;
|
use filters::filter::Filter;
|
||||||
|
use failure::Fallible as Result;
|
||||||
|
use failure::Error;
|
||||||
|
use failure::err_msg;
|
||||||
|
|
||||||
use libimagstore::storeid::StoreId;
|
use libimagstore::storeid::StoreId;
|
||||||
use libimagrt::setup::generate_runtime_setup;
|
use libimagrt::setup::generate_runtime_setup;
|
||||||
use libimagerror::trace::MapErrTrace;
|
|
||||||
use libimagerror::exit::ExitUnwrap;
|
|
||||||
use libimagerror::io::ToExitCode;
|
|
||||||
|
|
||||||
mod ui;
|
mod ui;
|
||||||
|
|
||||||
|
@ -83,7 +83,7 @@ impl<'a, A> Filter<StoreId> for IsInCollectionsFilter<'a, A>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn main() {
|
fn main() -> Result<()> {
|
||||||
let version = make_imag_version!();
|
let version = make_imag_version!();
|
||||||
let rt = generate_runtime_setup("imag-id-in-collection",
|
let rt = generate_runtime_setup("imag-id-in-collection",
|
||||||
&version,
|
&version,
|
||||||
|
@ -99,22 +99,19 @@ fn main() {
|
||||||
let mut stdout = rt.stdout();
|
let mut stdout = rt.stdout();
|
||||||
trace!("Got output: {:?}", stdout);
|
trace!("Got output: {:?}", stdout);
|
||||||
|
|
||||||
|
rt.ids::<crate::ui::PathProvider>()?
|
||||||
rt.ids::<crate::ui::PathProvider>()
|
.ok_or_else(|| err_msg("No ids supplied"))?
|
||||||
.map_err_trace_exit_unwrap()
|
|
||||||
.unwrap_or_else(|| {
|
|
||||||
error!("No ids supplied");
|
|
||||||
::std::process::exit(1);
|
|
||||||
})
|
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|id| collection_filter.filter(id))
|
.filter(|id| collection_filter.filter(id))
|
||||||
.for_each(|id| {
|
.map(|id| {
|
||||||
rt.report_touched(&id).unwrap_or_exit();
|
|
||||||
if !rt.output_is_pipe() {
|
if !rt.output_is_pipe() {
|
||||||
let id = id.to_str().map_err_trace_exit_unwrap();
|
let id = id.to_str()?;
|
||||||
trace!("Writing to {:?}", stdout);
|
trace!("Writing to {:?}", stdout);
|
||||||
writeln!(stdout, "{}", id).to_exit_code().unwrap_or_exit();
|
writeln!(stdout, "{}", id)?;
|
||||||
}
|
}
|
||||||
})
|
|
||||||
|
rt.report_touched(&id).map_err(Error::from)
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@ log = "0.4.6"
|
||||||
toml = "0.5.1"
|
toml = "0.5.1"
|
||||||
toml-query = "0.9.2"
|
toml-query = "0.9.2"
|
||||||
failure = "0.1.5"
|
failure = "0.1.5"
|
||||||
|
resiter = "0.3.0"
|
||||||
|
|
||||||
libimagstore = { version = "0.10.0", path = "../../../lib/core/libimagstore" }
|
libimagstore = { version = "0.10.0", path = "../../../lib/core/libimagstore" }
|
||||||
libimagrt = { version = "0.10.0", path = "../../../lib/core/libimagrt" }
|
libimagrt = { version = "0.10.0", path = "../../../lib/core/libimagrt" }
|
||||||
|
|
|
@ -39,6 +39,7 @@ extern crate clap;
|
||||||
extern crate toml;
|
extern crate toml;
|
||||||
extern crate toml_query;
|
extern crate toml_query;
|
||||||
#[macro_use] extern crate failure;
|
#[macro_use] extern crate failure;
|
||||||
|
extern crate resiter;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
extern crate env_logger;
|
extern crate env_logger;
|
||||||
|
@ -48,18 +49,17 @@ extern crate libimagstore;
|
||||||
extern crate libimagrt;
|
extern crate libimagrt;
|
||||||
|
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::result::Result as RResult;
|
|
||||||
|
|
||||||
use failure::Fallible as Result;
|
use failure::Fallible as Result;
|
||||||
|
use failure::err_msg;
|
||||||
|
use failure::Error;
|
||||||
|
use resiter::Map;
|
||||||
|
use resiter::AndThen;
|
||||||
use clap::App;
|
use clap::App;
|
||||||
|
|
||||||
use libimagstore::storeid::StoreId;
|
use libimagstore::storeid::StoreId;
|
||||||
use libimagrt::runtime::Runtime;
|
use libimagrt::runtime::Runtime;
|
||||||
use libimagrt::application::ImagApplication;
|
use libimagrt::application::ImagApplication;
|
||||||
use libimagerror::trace::MapErrTrace;
|
|
||||||
use libimagerror::iter::TraceIterator;
|
|
||||||
use libimagerror::exit::ExitUnwrap;
|
|
||||||
use libimagerror::io::ToExitCode;
|
|
||||||
|
|
||||||
mod ui;
|
mod ui;
|
||||||
|
|
||||||
|
@ -72,48 +72,42 @@ impl ImagApplication for ImagIds {
|
||||||
fn run(rt: Runtime) -> Result<()> {
|
fn run(rt: Runtime) -> Result<()> {
|
||||||
let print_storepath = rt.cli().is_present("print-storepath");
|
let print_storepath = rt.cli().is_present("print-storepath");
|
||||||
|
|
||||||
let iterator = if rt.ids_from_stdin() {
|
|
||||||
debug!("Fetching IDs from stdin...");
|
|
||||||
let ids = rt
|
|
||||||
.ids::<crate::ui::PathProvider>()
|
|
||||||
.map_err_trace_exit_unwrap()
|
|
||||||
.unwrap_or_else(|| {
|
|
||||||
error!("No ids supplied");
|
|
||||||
::std::process::exit(1);
|
|
||||||
});
|
|
||||||
Box::new(ids.into_iter().map(Ok))
|
|
||||||
as Box<dyn Iterator<Item = RResult<StoreId, _>>>
|
|
||||||
} else {
|
|
||||||
Box::new(rt.store().entries().map_err_trace_exit_unwrap())
|
|
||||||
as Box<dyn Iterator<Item = RResult<StoreId, _>>>
|
|
||||||
}
|
|
||||||
.trace_unwrap_exit()
|
|
||||||
.map(|id| if print_storepath {
|
|
||||||
(Some(rt.store().path()), id)
|
|
||||||
} else {
|
|
||||||
(None, id)
|
|
||||||
});
|
|
||||||
|
|
||||||
let mut stdout = rt.stdout();
|
let mut stdout = rt.stdout();
|
||||||
trace!("Got output: {:?}", stdout);
|
trace!("Got output: {:?}", stdout);
|
||||||
|
|
||||||
iterator.for_each(|(storepath, id)| {
|
let mut process = |iter: &mut dyn Iterator<Item = Result<StoreId>>| -> Result<()> {
|
||||||
rt.report_touched(&id).unwrap_or_exit();
|
iter.map_ok(|id| if print_storepath {
|
||||||
|
(Some(rt.store().path()), id)
|
||||||
|
} else {
|
||||||
|
(None, id)
|
||||||
|
}).and_then_ok(|(storepath, id)| {
|
||||||
if !rt.output_is_pipe() {
|
if !rt.output_is_pipe() {
|
||||||
let id = id.to_str().map_err_trace_exit_unwrap();
|
let id = id.to_str()?;
|
||||||
trace!("Writing to {:?}", stdout);
|
trace!("Writing to {:?}", stdout);
|
||||||
|
|
||||||
let result = if let Some(store) = storepath {
|
if let Some(store) = storepath {
|
||||||
writeln!(stdout, "{}/{}", store.display(), id)
|
writeln!(stdout, "{}/{}", store.display(), id)?;
|
||||||
} else {
|
} else {
|
||||||
writeln!(stdout, "{}", id)
|
writeln!(stdout, "{}", id)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rt.report_touched(&id).map_err(Error::from)
|
||||||
|
})
|
||||||
|
.collect::<Result<()>>()
|
||||||
};
|
};
|
||||||
|
|
||||||
result.to_exit_code().unwrap_or_exit();
|
if rt.ids_from_stdin() {
|
||||||
}
|
debug!("Fetching IDs from stdin...");
|
||||||
});
|
let mut iter = rt.ids::<crate::ui::PathProvider>()?
|
||||||
|
.ok_or_else(|| err_msg("No ids supplied"))?
|
||||||
|
.into_iter()
|
||||||
|
.map(Ok);
|
||||||
|
|
||||||
Ok(())
|
process(&mut iter)
|
||||||
|
} else {
|
||||||
|
process(&mut rt.store().entries()?)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_cli<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
|
fn build_cli<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
|
||||||
|
|
|
@ -41,6 +41,5 @@ extern crate libimaginitcmd;
|
||||||
|
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
libimaginitcmd::imag_init();
|
libimaginitcmd::imag_init()
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,8 @@
|
||||||
)]
|
)]
|
||||||
|
|
||||||
extern crate clap;
|
extern crate clap;
|
||||||
extern crate failure;
|
#[macro_use] extern crate failure;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
extern crate toml;
|
extern crate toml;
|
||||||
|
|
||||||
|
@ -50,12 +51,14 @@ use std::path::PathBuf;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
|
|
||||||
use libimagerror::exit::ExitUnwrap;
|
use failure::Fallible as Result;
|
||||||
use libimagerror::io::ToExitCode;
|
use failure::ResultExt;
|
||||||
|
use failure::Error;
|
||||||
|
use failure::err_msg;
|
||||||
|
|
||||||
use libimagrt::runtime::Runtime;
|
use libimagrt::runtime::Runtime;
|
||||||
use libimagrt::application::ImagApplication;
|
use libimagrt::application::ImagApplication;
|
||||||
|
|
||||||
use failure::Fallible as Result;
|
|
||||||
use clap::App;
|
use clap::App;
|
||||||
|
|
||||||
const CONFIGURATION_STR : &str = include_str!("../imagrc.toml");
|
const CONFIGURATION_STR : &str = include_str!("../imagrc.toml");
|
||||||
|
@ -100,7 +103,7 @@ impl ImagApplication for ImagInit {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn imag_init() {
|
pub fn imag_init() -> Result<()> {
|
||||||
let version = make_imag_version!();
|
let version = make_imag_version!();
|
||||||
let app = ui::build_ui(Runtime::get_default_cli_builder(
|
let app = ui::build_ui(Runtime::get_default_cli_builder(
|
||||||
"imag-init",
|
"imag-init",
|
||||||
|
@ -109,35 +112,27 @@ pub fn imag_init() {
|
||||||
let matches = app.get_matches();
|
let matches = app.get_matches();
|
||||||
let mut out = ::std::io::stdout();
|
let mut out = ::std::io::stdout();
|
||||||
|
|
||||||
let path = matches
|
let path = if let Some(p) = matches.value_of("path") {
|
||||||
.value_of("path")
|
PathBuf::from(String::from(p))
|
||||||
.map(String::from)
|
} else {
|
||||||
.map(PathBuf::from)
|
|
||||||
.unwrap_or_else(|| {
|
|
||||||
::std::env::var("HOME")
|
::std::env::var("HOME")
|
||||||
|
.map_err(Error::from)
|
||||||
.map(PathBuf::from)
|
.map(PathBuf::from)
|
||||||
.map(|mut p| { p.push(".imag"); p })
|
.map(|mut p| { p.push(".imag"); p })
|
||||||
.map(|path| if path.exists() {
|
.and_then(|path| if path.exists() {
|
||||||
writeln!(out, "Path '{:?}' already exists!", path)
|
Err(format_err!("Cannot continue: Path '{}' already exists", path.display()))
|
||||||
.to_exit_code()
|
|
||||||
.unwrap_or_exit();
|
|
||||||
writeln!(out, "Cannot continue.")
|
|
||||||
.to_exit_code()
|
|
||||||
.unwrap_or_exit();
|
|
||||||
::std::process::exit(1)
|
|
||||||
} else {
|
} else {
|
||||||
path
|
Ok(path)
|
||||||
})
|
})
|
||||||
.expect("Failed to retrieve/build path for imag directory.")
|
.map_err(|_| err_msg("Failed to retrieve/build path for imag directory."))?
|
||||||
});
|
};
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut store_path = path.clone();
|
let mut store_path = path.clone();
|
||||||
store_path.push("store");
|
store_path.push("store");
|
||||||
println!("Creating {}", store_path.display());
|
println!("Creating {}", store_path.display());
|
||||||
|
|
||||||
::std::fs::create_dir_all(store_path)
|
::std::fs::create_dir_all(store_path).context("Failed to create directory")?;
|
||||||
.expect("Failed to create directory");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let config_path = {
|
let config_path = {
|
||||||
|
@ -146,11 +141,12 @@ pub fn imag_init() {
|
||||||
config_path
|
config_path
|
||||||
};
|
};
|
||||||
|
|
||||||
OpenOptions::new()
|
let _ = OpenOptions::new()
|
||||||
.write(true)
|
.write(true)
|
||||||
.create(true)
|
.create(true)
|
||||||
.open(config_path)
|
.open(config_path)
|
||||||
.map(|mut f| {
|
.map_err(Error::from)
|
||||||
|
.and_then(|mut f| {
|
||||||
let content = if matches.is_present("devel") {
|
let content = if matches.is_present("devel") {
|
||||||
get_config_devel()
|
get_config_devel()
|
||||||
} else {
|
} else {
|
||||||
|
@ -158,33 +154,34 @@ pub fn imag_init() {
|
||||||
};
|
};
|
||||||
|
|
||||||
f.write_all(content.as_bytes())
|
f.write_all(content.as_bytes())
|
||||||
.expect("Failed to write complete config to file");
|
.context("Failed to write complete config to file")
|
||||||
|
.map_err(Error::from)
|
||||||
})
|
})
|
||||||
.expect("Failed to open new configuration file");
|
.context("Failed to open new configuration file")?;
|
||||||
|
|
||||||
if find_command("git").is_some() && !matches.is_present("nogit") {
|
if find_command("git").is_some() && !matches.is_present("nogit") {
|
||||||
// we initialize a git repository
|
// we initialize a git repository
|
||||||
writeln!(out, "Going to initialize a git repository in the imag directory...")
|
writeln!(out, "Going to initialize a git repository in the imag directory...")?;
|
||||||
.to_exit_code()
|
|
||||||
.unwrap_or_exit();
|
|
||||||
|
|
||||||
let gitignore_path = {
|
let gitignore_path = {
|
||||||
let mut gitignore_path = path.clone();
|
let mut gitignore_path = path.clone();
|
||||||
gitignore_path.push(".gitignore");
|
gitignore_path.push(".gitignore");
|
||||||
gitignore_path.to_str().map(String::from).expect("Cannot convert path to string")
|
gitignore_path.to_str().map(String::from)
|
||||||
};
|
}.ok_or_else(|| err_msg("Cannot convert path to string"))?;
|
||||||
|
|
||||||
OpenOptions::new()
|
let _ = OpenOptions::new()
|
||||||
.write(true)
|
.write(true)
|
||||||
.create(true)
|
.create(true)
|
||||||
.open(gitignore_path.clone())
|
.open(gitignore_path.clone())
|
||||||
.map(|mut f| {
|
.map_err(Error::from)
|
||||||
|
.and_then(|mut f| {
|
||||||
f.write_all(GITIGNORE_STR.as_bytes())
|
f.write_all(GITIGNORE_STR.as_bytes())
|
||||||
.expect("Failed to write complete gitignore to file");
|
.context("Failed to write complete gitignore to file")
|
||||||
|
.map_err(Error::from)
|
||||||
})
|
})
|
||||||
.expect("Failed to open new configuration file");
|
.context("Failed to open new configuration file")?;
|
||||||
|
|
||||||
let path_str = path.to_str().map(String::from).expect("Cannot convert path to string");
|
let path_str = path.to_str().map(String::from).ok_or_else(|| err_msg("Cannot convert path to string"))?;
|
||||||
let worktree = format!("--work-tree={}", path_str);
|
let worktree = format!("--work-tree={}", path_str);
|
||||||
let gitdir = format!("--git-dir={}/.git", path_str);
|
let gitdir = format!("--git-dir={}/.git", path_str);
|
||||||
|
|
||||||
|
@ -192,20 +189,16 @@ pub fn imag_init() {
|
||||||
let output = Command::new("git")
|
let output = Command::new("git")
|
||||||
.args(&[&worktree, &gitdir, "--no-pager", "init"])
|
.args(&[&worktree, &gitdir, "--no-pager", "init"])
|
||||||
.output()
|
.output()
|
||||||
.expect("Calling 'git init' failed");
|
.context("Calling 'git init' failed")?;
|
||||||
|
|
||||||
if output.status.success() {
|
if output.status.success() {
|
||||||
writeln!(out, "{}", String::from_utf8(output.stdout).expect("No UTF-8 output"))
|
writeln!(out, "{}", String::from_utf8(output.stdout).expect("No UTF-8 output"))?;
|
||||||
.to_exit_code()
|
writeln!(out, "'git {} {} --no-pager init' succeeded", worktree, gitdir)?;
|
||||||
.unwrap_or_exit();
|
|
||||||
writeln!(out, "'git {} {} --no-pager init' succeeded", worktree, gitdir)
|
|
||||||
.to_exit_code()
|
|
||||||
.unwrap_or_exit();
|
|
||||||
} else {
|
} else {
|
||||||
writeln!(out, "{}", String::from_utf8(output.stderr).expect("No UTF-8 output"))
|
writeln!(out, "{}", String::from_utf8(output.stderr).expect("No UTF-8 output"))?;
|
||||||
.to_exit_code()
|
if !output.status.success() {
|
||||||
.unwrap_or_exit();
|
return Err(err_msg("Failed to execute git command"));
|
||||||
::std::process::exit(output.status.code().unwrap_or(1));
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -213,19 +206,16 @@ pub fn imag_init() {
|
||||||
let output = Command::new("git")
|
let output = Command::new("git")
|
||||||
.args(&[&worktree, &gitdir, "--no-pager", "add", &gitignore_path])
|
.args(&[&worktree, &gitdir, "--no-pager", "add", &gitignore_path])
|
||||||
.output()
|
.output()
|
||||||
.expect("Calling 'git add' failed");
|
.context("Calling 'git add' failed")?;
|
||||||
|
|
||||||
if output.status.success() {
|
if output.status.success() {
|
||||||
writeln!(out, "{}", String::from_utf8(output.stdout).expect("No UTF-8 output"))
|
writeln!(out, "{}", String::from_utf8(output.stdout).expect("No UTF-8 output"))?;
|
||||||
.to_exit_code()
|
writeln!(out, "'git {} {} --no-pager add {}' succeeded", worktree, gitdir, gitignore_path)?;
|
||||||
.unwrap_or_exit();
|
|
||||||
writeln!(out, "'git {} {} --no-pager add {}' succeeded", worktree, gitdir, gitignore_path)
|
|
||||||
.to_exit_code()
|
|
||||||
.unwrap_or_exit();
|
|
||||||
} else {
|
} else {
|
||||||
writeln!(out, "{}", String::from_utf8(output.stderr).expect("No UTF-8 output"))
|
writeln!(out, "{}", String::from_utf8(output.stderr).expect("No UTF-8 output"))?;
|
||||||
.to_exit_code()
|
if !output.status.success() {
|
||||||
.unwrap_or_exit();
|
return Err(err_msg("Failed to execute git command"));
|
||||||
::std::process::exit(output.status.code().unwrap_or(1));
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -233,34 +223,24 @@ pub fn imag_init() {
|
||||||
let output = Command::new("git")
|
let output = Command::new("git")
|
||||||
.args(&[&worktree, &gitdir, "--no-pager", "commit", &gitignore_path, "-m", "'Initial import'"])
|
.args(&[&worktree, &gitdir, "--no-pager", "commit", &gitignore_path, "-m", "'Initial import'"])
|
||||||
.output()
|
.output()
|
||||||
.expect("Calling 'git commit' failed");
|
.context("Calling 'git commit' failed")?;
|
||||||
if output.status.success() {
|
if output.status.success() {
|
||||||
writeln!(out, "{}", String::from_utf8(output.stdout).expect("No UTF-8 output"))
|
writeln!(out, "{}", String::from_utf8(output.stdout).expect("No UTF-8 output"))?;
|
||||||
.to_exit_code()
|
writeln!(out, "'git {} {} --no-pager commit {} -m 'Initial import'' succeeded", worktree, gitdir, gitignore_path)?;
|
||||||
.unwrap_or_exit();
|
|
||||||
writeln!(out, "'git {} {} --no-pager commit {} -m 'Initial import'' succeeded", worktree, gitdir, gitignore_path)
|
|
||||||
.to_exit_code()
|
|
||||||
.unwrap_or_exit();
|
|
||||||
} else {
|
} else {
|
||||||
writeln!(out, "{}", String::from_utf8(output.stderr).expect("No UTF-8 output"))
|
writeln!(out, "{}", String::from_utf8(output.stderr).expect("No UTF-8 output"))?;
|
||||||
.to_exit_code()
|
if !output.status.success() {
|
||||||
.unwrap_or_exit();
|
return Err(err_msg("Failed to execute git command"));
|
||||||
::std::process::exit(output.status.code().unwrap_or(1));
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
writeln!(out, "git stuff finished!")
|
writeln!(out, "git stuff finished!")?;
|
||||||
.to_exit_code()
|
|
||||||
.unwrap_or_exit();
|
|
||||||
} else {
|
} else {
|
||||||
writeln!(out, "No git repository will be initialized")
|
writeln!(out, "No git repository will be initialized")?;
|
||||||
.to_exit_code()
|
|
||||||
.unwrap_or_exit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
writeln!(out, "Ready. Have fun with imag!")
|
writeln!(out, "Ready. Have fun with imag!").map_err(Error::from)
|
||||||
.to_exit_code()
|
|
||||||
.unwrap_or_exit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_config() -> String {
|
fn get_config() -> String {
|
||||||
|
|
|
@ -37,7 +37,7 @@
|
||||||
#[macro_use] extern crate log;
|
#[macro_use] extern crate log;
|
||||||
extern crate clap;
|
extern crate clap;
|
||||||
extern crate url;
|
extern crate url;
|
||||||
extern crate failure;
|
#[macro_use] extern crate failure;
|
||||||
#[macro_use] extern crate prettytable;
|
#[macro_use] extern crate prettytable;
|
||||||
#[cfg(test)] extern crate toml;
|
#[cfg(test)] extern crate toml;
|
||||||
#[cfg(test)] extern crate toml_query;
|
#[cfg(test)] extern crate toml_query;
|
||||||
|
@ -65,18 +65,14 @@ use failure::err_msg;
|
||||||
use libimagentryurl::linker::UrlLinker;
|
use libimagentryurl::linker::UrlLinker;
|
||||||
use libimagentrylink::linkable::Linkable;
|
use libimagentrylink::linkable::Linkable;
|
||||||
use libimagentrylink::storecheck::StoreLinkConsistentExt;
|
use libimagentrylink::storecheck::StoreLinkConsistentExt;
|
||||||
use libimagerror::trace::{MapErrTrace, trace_error};
|
|
||||||
use libimagerror::exit::ExitUnwrap;
|
|
||||||
use libimagerror::io::ToExitCode;
|
|
||||||
use libimagrt::runtime::Runtime;
|
use libimagrt::runtime::Runtime;
|
||||||
use libimagrt::application::ImagApplication;
|
use libimagrt::application::ImagApplication;
|
||||||
use libimagstore::store::FileLockEntry;
|
use libimagstore::store::FileLockEntry;
|
||||||
use libimagstore::storeid::StoreId;
|
use libimagstore::storeid::StoreId;
|
||||||
use libimagutil::warn_exit::warn_exit;
|
|
||||||
use libimagutil::warn_result::*;
|
|
||||||
|
|
||||||
use url::Url;
|
use url::Url;
|
||||||
use failure::Fallible as Result;
|
use failure::Fallible as Result;
|
||||||
|
use failure::Error;
|
||||||
use clap::App;
|
use clap::App;
|
||||||
|
|
||||||
mod ui;
|
mod ui;
|
||||||
|
@ -89,46 +85,31 @@ pub enum ImagLink {}
|
||||||
impl ImagApplication for ImagLink {
|
impl ImagApplication for ImagLink {
|
||||||
fn run(rt: Runtime) -> Result<()> {
|
fn run(rt: Runtime) -> Result<()> {
|
||||||
if rt.cli().is_present("check-consistency") {
|
if rt.cli().is_present("check-consistency") {
|
||||||
let exit_code = match rt.store().check_link_consistency() {
|
rt.store().check_link_consistency()?;
|
||||||
Ok(_) => {
|
|
||||||
info!("Store is consistent");
|
info!("Store is consistent");
|
||||||
0
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
trace_error(&e);
|
|
||||||
1
|
|
||||||
}
|
|
||||||
};
|
|
||||||
::std::process::exit(exit_code);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let _ = rt.cli()
|
if let Some(name) = rt.cli().subcommand_name() {
|
||||||
.subcommand_name()
|
|
||||||
.map(|name| {
|
|
||||||
match name {
|
match name {
|
||||||
"remove" => remove_linking(&rt),
|
"remove" => remove_linking(&rt),
|
||||||
"unlink" => unlink(&rt),
|
"unlink" => unlink(&rt),
|
||||||
"list" => list_linkings(&rt),
|
"list" => list_linkings(&rt),
|
||||||
other => {
|
other => {
|
||||||
debug!("Unknown command");
|
debug!("Unknown command");
|
||||||
let _ = rt.handle_unknown_subcommand("imag-link", other, rt.cli())
|
if rt.handle_unknown_subcommand("imag-link", other, rt.cli())?.success() {
|
||||||
.map_err_trace_exit_unwrap()
|
Ok(())
|
||||||
.code()
|
} else {
|
||||||
.map(::std::process::exit);
|
Err(format_err!("Subcommand failed"))
|
||||||
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
})
|
|
||||||
.or_else(|| {
|
|
||||||
if let (Some(from), Some(to)) = (rt.cli().value_of("from"), rt.cli().values_of("to")) {
|
|
||||||
Some(link_from_to(&rt, from, to))
|
|
||||||
} else {
|
} else {
|
||||||
warn_exit("No commandline call", 1)
|
if let (Some(from), Some(to)) = (rt.cli().value_of("from"), rt.cli().values_of("to")) {
|
||||||
|
link_from_to(&rt, from, to)
|
||||||
|
} else {
|
||||||
|
Err(err_msg("No commandline call"))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
|
||||||
.ok_or_else(|| err_msg("No commandline call".to_owned()))
|
|
||||||
.map_err_trace_exit_unwrap();
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_cli<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
|
fn build_cli<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
|
||||||
|
@ -156,144 +137,103 @@ fn get_entry_by_name<'a>(rt: &'a Runtime, name: &str) -> Result<Option<FileLockE
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
fn link_from_to<'a, I>(rt: &'a Runtime, from: &'a str, to: I)
|
fn link_from_to<'a, I>(rt: &'a Runtime, from: &'a str, to: I) -> Result<()>
|
||||||
where I: Iterator<Item = &'a str>
|
where I: Iterator<Item = &'a str>
|
||||||
{
|
{
|
||||||
let mut from_entry = match get_entry_by_name(rt, from).map_err_trace_exit_unwrap() {
|
let mut from_entry = get_entry_by_name(rt, from)?.ok_or_else(|| err_msg("No 'from' entry"))?;
|
||||||
Some(e) => e,
|
|
||||||
None => {
|
|
||||||
debug!("No 'from' entry");
|
|
||||||
warn_exit("No 'from' entry", 1)
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
for entry in to {
|
for entry in to {
|
||||||
debug!("Handling 'to' entry: {:?}", entry);
|
debug!("Handling 'to' entry: {:?}", entry);
|
||||||
if rt.store().get(PathBuf::from(entry)).map_err_trace_exit_unwrap().is_none() {
|
if rt.store().get(PathBuf::from(entry))?.is_none() {
|
||||||
debug!("Linking externally: {:?} -> {:?}", from, entry);
|
debug!("Linking externally: {:?} -> {:?}", from, entry);
|
||||||
let url = Url::parse(entry).unwrap_or_else(|e| {
|
let url = Url::parse(entry).map_err(|e| format_err!("Error parsing URL: {:?}", e))?;
|
||||||
error!("Error parsing URL: {:?}", e);
|
|
||||||
::std::process::exit(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
let iter = from_entry
|
let iter = from_entry
|
||||||
.add_url(rt.store(), url)
|
.add_url(rt.store(), url)?
|
||||||
.map_err_trace_exit_unwrap()
|
|
||||||
.into_iter();
|
.into_iter();
|
||||||
|
|
||||||
rt.report_all_touched(iter).unwrap_or_exit();
|
rt.report_all_touched(iter)?;
|
||||||
} else {
|
} else {
|
||||||
debug!("Linking internally: {:?} -> {:?}", from, entry);
|
debug!("Linking internally: {:?} -> {:?}", from, entry);
|
||||||
|
|
||||||
let from_id = StoreId::new(PathBuf::from(from)).map_err_trace_exit_unwrap();
|
let from_id = StoreId::new(PathBuf::from(from))?;
|
||||||
let entr_id = StoreId::new(PathBuf::from(entry)).map_err_trace_exit_unwrap();
|
let entr_id = StoreId::new(PathBuf::from(entry))?;
|
||||||
|
|
||||||
if from_id == entr_id {
|
if from_id == entr_id {
|
||||||
error!("Cannot link entry with itself. Exiting");
|
return Err(err_msg("Cannot link entry with itself. Exiting"))
|
||||||
::std::process::exit(1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut to_entry = match rt.store().get(entr_id).map_err_trace_exit_unwrap() {
|
let mut to_entry = rt
|
||||||
Some(e) => e,
|
.store()
|
||||||
None => {
|
.get(entr_id)?
|
||||||
warn!("No 'to' entry: {}", entry);
|
.ok_or_else(|| format_err!("No 'to' entry: {}", entry))?;
|
||||||
::std::process::exit(1)
|
|
||||||
},
|
|
||||||
};
|
|
||||||
from_entry
|
|
||||||
.add_link(&mut to_entry)
|
|
||||||
.map_err_trace_exit_unwrap();
|
|
||||||
|
|
||||||
rt.report_touched(to_entry.get_location()).unwrap_or_exit();
|
from_entry.add_link(&mut to_entry)?;
|
||||||
|
|
||||||
|
rt.report_touched(to_entry.get_location())?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
info!("Ok: {} -> {}", from, entry);
|
info!("Ok: {} -> {}", from, entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
rt.report_touched(from_entry.get_location()).unwrap_or_exit();
|
rt.report_touched(from_entry.get_location()).map_err(Error::from)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove_linking(rt: &Runtime) {
|
fn remove_linking(rt: &Runtime) -> Result<()> {
|
||||||
let mut from = rt.cli()
|
let mut from : FileLockEntry = rt.cli()
|
||||||
.subcommand_matches("remove")
|
.subcommand_matches("remove")
|
||||||
.unwrap() // safe, we know there is an "remove" subcommand
|
.unwrap() // safe, we know there is an "remove" subcommand
|
||||||
.value_of("from")
|
.value_of("from")
|
||||||
.map(PathBuf::from)
|
.map(PathBuf::from)
|
||||||
.map(|id| {
|
.and_then(|id| rt.store().get(id).transpose())
|
||||||
rt.store()
|
.ok_or_else(|| err_msg("No 'from' entry"))??;
|
||||||
.get(id)
|
|
||||||
.map_err_trace_exit_unwrap()
|
|
||||||
.ok_or_else(|| warn_exit("No 'from' entry", 1))
|
|
||||||
.unwrap() // safe by line above
|
|
||||||
})
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
rt
|
rt
|
||||||
.ids::<crate::ui::PathProvider>()
|
.ids::<crate::ui::PathProvider>()?
|
||||||
.map_err_trace_exit_unwrap()
|
.ok_or_else(|| err_msg("No ids supplied"))?
|
||||||
.unwrap_or_else(|| {
|
|
||||||
error!("No ids supplied");
|
|
||||||
::std::process::exit(1);
|
|
||||||
})
|
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.for_each(|id| match rt.store().get(id.clone()) {
|
.map(|id| match rt.store().get(id.clone())? {
|
||||||
Err(e) => trace_error(&e),
|
Some(mut to_entry) => {
|
||||||
Ok(Some(mut to_entry)) => {
|
to_entry.remove_link(&mut from)?;
|
||||||
to_entry
|
rt.report_touched(to_entry.get_location()).map_err(Error::from)
|
||||||
.remove_link(&mut from)
|
|
||||||
.map_err_trace_exit_unwrap();
|
|
||||||
|
|
||||||
rt.report_touched(to_entry.get_location()).unwrap_or_exit();
|
|
||||||
},
|
},
|
||||||
Ok(None) => {
|
|
||||||
|
None => {
|
||||||
// looks like this is not an entry, but a filesystem URI and therefor an
|
// looks like this is not an entry, but a filesystem URI and therefor an
|
||||||
// external link...?
|
// external link...?
|
||||||
if id.local().is_file() {
|
if id.local().is_file() {
|
||||||
let pb = id.local().to_str().unwrap_or_else(|| {
|
let pb = id.local().to_str().ok_or_else(|| format_err!("Not StoreId and not a Path: {}", id))?;
|
||||||
warn!("Not StoreId and not a Path: {}", id);
|
let url = Url::parse(pb).map_err(|e| format_err!("Error parsing URL: {:?}", e))?;
|
||||||
::std::process::exit(1);
|
from.remove_url(rt.store(), url)?;
|
||||||
});
|
|
||||||
let url = Url::parse(pb).unwrap_or_else(|e| {
|
|
||||||
error!("Error parsing URL: {:?}", e);
|
|
||||||
::std::process::exit(1);
|
|
||||||
});
|
|
||||||
from.remove_url(rt.store(), url).map_err_trace_exit_unwrap();
|
|
||||||
info!("Ok: {}", id);
|
info!("Ok: {}", id);
|
||||||
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
warn!("Entry not found: {:?}", id);
|
Err(format_err!("Entry not found: {:?}", id))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
|
.collect::<Result<Vec<_>>>()?;
|
||||||
|
|
||||||
rt.report_touched(from.get_location()).unwrap_or_exit();
|
rt.report_touched(from.get_location()).map_err(Error::from)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unlink(rt: &Runtime) {
|
fn unlink(rt: &Runtime) -> Result<()> {
|
||||||
rt
|
rt
|
||||||
.ids::<crate::ui::PathProvider>()
|
.ids::<crate::ui::PathProvider>()?
|
||||||
.map_err_trace_exit_unwrap()
|
.ok_or_else(|| err_msg("No ids supplied"))?
|
||||||
.unwrap_or_else(|| {
|
|
||||||
error!("No ids supplied");
|
|
||||||
::std::process::exit(1);
|
|
||||||
})
|
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.for_each(|id| {
|
.map(|id| {
|
||||||
rt.store()
|
rt.store()
|
||||||
.get(id.clone())
|
.get(id.clone())?
|
||||||
.map_err_trace_exit_unwrap()
|
.ok_or_else(|| format_err!("No entry for {}", id))?
|
||||||
.unwrap_or_else(|| {
|
.unlink(rt.store())?;
|
||||||
warn!("No entry for {}", id);
|
|
||||||
::std::process::exit(1)
|
|
||||||
})
|
|
||||||
.unlink(rt.store())
|
|
||||||
.map_err_trace_exit_unwrap();
|
|
||||||
|
|
||||||
rt.report_touched(&id).unwrap_or_exit();
|
rt.report_touched(&id).map_err(Error::from)
|
||||||
});
|
})
|
||||||
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn list_linkings(rt: &Runtime) {
|
fn list_linkings(rt: &Runtime) -> Result<()> {
|
||||||
let cmd = rt.cli()
|
let cmd = rt.cli()
|
||||||
.subcommand_matches("list")
|
.subcommand_matches("list")
|
||||||
.unwrap(); // safed by clap
|
.unwrap(); // safed by clap
|
||||||
|
@ -304,70 +244,50 @@ fn list_linkings(rt: &Runtime) {
|
||||||
let mut tab = ::prettytable::Table::new();
|
let mut tab = ::prettytable::Table::new();
|
||||||
tab.set_titles(row!["#", "Link"]);
|
tab.set_titles(row!["#", "Link"]);
|
||||||
|
|
||||||
rt
|
rt.ids::<crate::ui::PathProvider>()?
|
||||||
.ids::<crate::ui::PathProvider>()
|
.ok_or_else(|| err_msg("No ids supplied"))?
|
||||||
.map_err_trace_exit_unwrap()
|
|
||||||
.unwrap_or_else(|| {
|
|
||||||
error!("No ids supplied");
|
|
||||||
::std::process::exit(1);
|
|
||||||
})
|
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.for_each(|id| {
|
.map(|id| {
|
||||||
match rt.store().get(id.clone()) {
|
let entry = rt.store().get(id.clone())?.ok_or_else(|| format_err!("Not found: {}", id))?;
|
||||||
Ok(Some(entry)) => {
|
|
||||||
for (i, link) in entry.links().map_err_trace_exit_unwrap().enumerate() {
|
for (i, link) in entry.links()?.enumerate() {
|
||||||
let link = link
|
let link = link.to_str()?;
|
||||||
.to_str()
|
|
||||||
.map_warn_err(|e| format!("Failed to convert StoreId to string: {:?}", e))
|
|
||||||
.ok();
|
|
||||||
|
|
||||||
if let Some(link) = link {
|
|
||||||
if list_plain {
|
if list_plain {
|
||||||
writeln!(rt.stdout(), "{: <3}: {}", i, link)
|
writeln!(rt.stdout(), "{: <3}: {}", i, link)?;
|
||||||
.to_exit_code()
|
|
||||||
.unwrap_or_exit();
|
|
||||||
} else {
|
} else {
|
||||||
tab.add_row(row![i, link]);
|
tab.add_row(row![i, link]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if list_externals {
|
if list_externals {
|
||||||
entry.get_urls(rt.store())
|
entry.get_urls(rt.store())?
|
||||||
.map_err_trace_exit_unwrap()
|
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.for_each(|(i, link)| {
|
.map(|(i, link)| {
|
||||||
let link = link
|
let link = link?.into_string();
|
||||||
.map_err_trace_exit_unwrap()
|
|
||||||
.into_string();
|
|
||||||
|
|
||||||
if list_plain {
|
if list_plain {
|
||||||
writeln!(rt.stdout(), "{: <3}: {}", i, link)
|
writeln!(rt.stdout(), "{: <3}: {}", i, link)?;
|
||||||
.to_exit_code()
|
|
||||||
.unwrap_or_exit();
|
|
||||||
} else {
|
} else {
|
||||||
tab.add_row(row![i, link]);
|
tab.add_row(row![i, link]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
})
|
})
|
||||||
|
.collect::<Result<Vec<_>>>()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
rt.report_touched(entry.get_location()).unwrap_or_exit();
|
rt.report_touched(entry.get_location()).map_err(Error::from)
|
||||||
|
})
|
||||||
},
|
.collect::<Result<Vec<_>>>()?;
|
||||||
Ok(None) => warn!("Not found: {}", id),
|
|
||||||
Err(e) => trace_error(&e),
|
|
||||||
}
|
|
||||||
|
|
||||||
rt.report_touched(&id).unwrap_or_exit();
|
|
||||||
});
|
|
||||||
|
|
||||||
if !list_plain {
|
if !list_plain {
|
||||||
let out = rt.stdout();
|
let out = rt.stdout();
|
||||||
let mut lock = out.lock();
|
let mut lock = out.lock();
|
||||||
tab.print(&mut lock)
|
tab.print(&mut lock)?;
|
||||||
.to_exit_code()
|
|
||||||
.unwrap_or_exit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -449,7 +369,7 @@ mod tests {
|
||||||
|
|
||||||
debug!("Entries created");
|
debug!("Entries created");
|
||||||
|
|
||||||
link_from_to(&rt, "test1", vec!["test2"].into_iter());
|
link_from_to(&rt, "test1", vec!["test2"].into_iter()).unwrap();
|
||||||
|
|
||||||
debug!("Linking done");
|
debug!("Linking done");
|
||||||
|
|
||||||
|
@ -480,7 +400,7 @@ mod tests {
|
||||||
|
|
||||||
debug!("Test entries created");
|
debug!("Test entries created");
|
||||||
|
|
||||||
link_from_to(&rt, "test1", vec!["test2"].into_iter());
|
link_from_to(&rt, "test1", vec!["test2"].into_iter()).unwrap();
|
||||||
|
|
||||||
debug!("Linking done");
|
debug!("Linking done");
|
||||||
|
|
||||||
|
@ -509,8 +429,8 @@ mod tests {
|
||||||
|
|
||||||
debug!("Test entries created");
|
debug!("Test entries created");
|
||||||
|
|
||||||
link_from_to(&rt, "test1", vec!["test2"].into_iter());
|
link_from_to(&rt, "test1", vec!["test2"].into_iter()).unwrap();
|
||||||
link_from_to(&rt, "test1", vec!["test2"].into_iter());
|
link_from_to(&rt, "test1", vec!["test2"].into_iter()).unwrap();
|
||||||
|
|
||||||
debug!("Linking done");
|
debug!("Linking done");
|
||||||
|
|
||||||
|
@ -540,8 +460,8 @@ mod tests {
|
||||||
|
|
||||||
debug!("Test entries created");
|
debug!("Test entries created");
|
||||||
|
|
||||||
link_from_to(&rt, "test1", vec!["test2", "test3"].into_iter());
|
link_from_to(&rt, "test1", vec!["test2", "test3"].into_iter()).unwrap();
|
||||||
link_from_to(&rt, "test1", vec!["test2", "test3"].into_iter());
|
link_from_to(&rt, "test1", vec!["test2", "test3"].into_iter()).unwrap();
|
||||||
|
|
||||||
debug!("Linking done");
|
debug!("Linking done");
|
||||||
|
|
||||||
|
@ -576,14 +496,14 @@ mod tests {
|
||||||
|
|
||||||
debug!("Test entries created");
|
debug!("Test entries created");
|
||||||
|
|
||||||
link_from_to(&rt, "test1", vec!["test2"].into_iter());
|
link_from_to(&rt, "test1", vec!["test2"].into_iter()).unwrap();
|
||||||
|
|
||||||
debug!("Linking done");
|
debug!("Linking done");
|
||||||
|
|
||||||
let rt = reset_test_runtime(vec!["remove", "test1", "test2"], rt)
|
let rt = reset_test_runtime(vec!["remove", "test1", "test2"], rt)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
remove_linking(&rt);
|
remove_linking(&rt).unwrap();
|
||||||
|
|
||||||
debug!("Linking removed");
|
debug!("Linking removed");
|
||||||
|
|
||||||
|
@ -613,14 +533,14 @@ mod tests {
|
||||||
|
|
||||||
debug!("Test entries created");
|
debug!("Test entries created");
|
||||||
|
|
||||||
link_from_to(&rt, "test1", vec!["test2", "test3"].into_iter());
|
link_from_to(&rt, "test1", vec!["test2", "test3"].into_iter()).unwrap();
|
||||||
|
|
||||||
debug!("linking done");
|
debug!("linking done");
|
||||||
|
|
||||||
let rt = reset_test_runtime(vec!["remove", "test1", "test2", "test3"], rt)
|
let rt = reset_test_runtime(vec!["remove", "test1", "test2", "test3"], rt)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
remove_linking(&rt);
|
remove_linking(&rt).unwrap();
|
||||||
|
|
||||||
debug!("linking removed");
|
debug!("linking removed");
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@ maintenance = { status = "actively-developed" }
|
||||||
[dependencies]
|
[dependencies]
|
||||||
log = "0.4.6"
|
log = "0.4.6"
|
||||||
failure = "0.1.5"
|
failure = "0.1.5"
|
||||||
|
resiter = "0.3.0"
|
||||||
|
|
||||||
libimagstore = { version = "0.10.0", path = "../../../lib/core/libimagstore" }
|
libimagstore = { version = "0.10.0", path = "../../../lib/core/libimagstore" }
|
||||||
libimagrt = { version = "0.10.0", path = "../../../lib/core/libimagrt" }
|
libimagrt = { version = "0.10.0", path = "../../../lib/core/libimagrt" }
|
||||||
|
|
|
@ -37,6 +37,7 @@
|
||||||
extern crate clap;
|
extern crate clap;
|
||||||
#[macro_use] extern crate log;
|
#[macro_use] extern crate log;
|
||||||
extern crate failure;
|
extern crate failure;
|
||||||
|
extern crate resiter;
|
||||||
|
|
||||||
extern crate libimagerror;
|
extern crate libimagerror;
|
||||||
extern crate libimagrt;
|
extern crate libimagrt;
|
||||||
|
@ -47,13 +48,14 @@ use std::io::Write;
|
||||||
use failure::Error;
|
use failure::Error;
|
||||||
use failure::err_msg;
|
use failure::err_msg;
|
||||||
use failure::Fallible as Result;
|
use failure::Fallible as Result;
|
||||||
|
use resiter::AndThen;
|
||||||
|
use resiter::Map;
|
||||||
use clap::App;
|
use clap::App;
|
||||||
|
|
||||||
use libimagerror::trace::MapErrTrace;
|
|
||||||
use libimagerror::iter::TraceIterator;
|
|
||||||
use libimagrt::runtime::Runtime;
|
use libimagrt::runtime::Runtime;
|
||||||
use libimagrt::application::ImagApplication;
|
use libimagrt::application::ImagApplication;
|
||||||
use libimagstore::iter::get::StoreIdGetIteratorExtension;
|
use libimagstore::iter::get::StoreIdGetIteratorExtension;
|
||||||
|
use crate::libimagerror::iter::IterInnerOkOrElse;
|
||||||
|
|
||||||
mod ui;
|
mod ui;
|
||||||
|
|
||||||
|
@ -69,40 +71,32 @@ impl ImagApplication for ImagMarkdown {
|
||||||
let mut outlock = out.lock();
|
let mut outlock = out.lock();
|
||||||
|
|
||||||
let iter = rt
|
let iter = rt
|
||||||
.ids::<crate::ui::PathProvider>()
|
.ids::<crate::ui::PathProvider>()?
|
||||||
.map_err_trace_exit_unwrap()
|
.ok_or_else(|| err_msg("No ids supplied"))?
|
||||||
.unwrap_or_else(|| {
|
|
||||||
error!("No ids supplied");
|
|
||||||
::std::process::exit(1);
|
|
||||||
})
|
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(Ok)
|
.map(Ok)
|
||||||
.into_get_iter(rt.store())
|
.into_get_iter(rt.store())
|
||||||
.trace_unwrap_exit()
|
.map_inner_ok_or_else(|| err_msg("Entry does not exist but is in store. This is a BUG, please report!"));
|
||||||
.map(|ofle| ofle.ok_or_else(|| {
|
|
||||||
err_msg("Entry does not exist but is in store. This is a BUG, please report!")
|
|
||||||
}))
|
|
||||||
.trace_unwrap_exit();
|
|
||||||
|
|
||||||
if only_links {
|
if only_links {
|
||||||
iter.map(|fle| libimagentrymarkdown::link::extract_links(fle.get_content()))
|
debug!("Printing only links");
|
||||||
.for_each(|links| {
|
iter.map_ok(|fle| libimagentrymarkdown::link::extract_links(fle.get_content()))
|
||||||
links.iter().for_each(|link| {
|
.and_then_ok(|links| {
|
||||||
writeln!(outlock, "{title}: {link}", title = link.title, link = link.link)
|
links.iter()
|
||||||
.map_err(Error::from)
|
.map(|link| {
|
||||||
.map_err_trace_exit_unwrap();
|
writeln!(outlock, "{title}: {link}", title = link.title, link = link.link).map_err(Error::from)
|
||||||
})
|
})
|
||||||
|
.collect()
|
||||||
})
|
})
|
||||||
|
.collect()
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
iter.map(|fle| libimagentrymarkdown::html::to_html(fle.get_content()))
|
iter.and_then_ok(|fle| libimagentrymarkdown::html::to_html(fle.get_content()))
|
||||||
.trace_unwrap_exit()
|
.and_then_ok(|html| {
|
||||||
.for_each(|html| {
|
writeln!(outlock, "{}", html).map_err(Error::from).map_err(Error::from)
|
||||||
writeln!(outlock, "{}", html).map_err(Error::from).map_err_trace_exit_unwrap();
|
|
||||||
})
|
})
|
||||||
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_cli<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
|
fn build_cli<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
|
||||||
|
|
|
@ -35,33 +35,29 @@
|
||||||
)]
|
)]
|
||||||
|
|
||||||
#[macro_use] extern crate log;
|
#[macro_use] extern crate log;
|
||||||
|
#[macro_use] extern crate failure;
|
||||||
extern crate clap;
|
extern crate clap;
|
||||||
extern crate failure;
|
|
||||||
|
|
||||||
extern crate libimagrt;
|
extern crate libimagrt;
|
||||||
extern crate libimagstore;
|
extern crate libimagstore;
|
||||||
extern crate libimagerror;
|
extern crate libimagerror;
|
||||||
extern crate libimagentrylink;
|
extern crate libimagentrylink;
|
||||||
|
|
||||||
use std::process::exit;
|
|
||||||
|
|
||||||
mod ui;
|
mod ui;
|
||||||
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::result::Result as RResult;
|
|
||||||
|
|
||||||
use libimagrt::runtime::Runtime;
|
use libimagrt::runtime::Runtime;
|
||||||
use libimagrt::application::ImagApplication;
|
use libimagrt::application::ImagApplication;
|
||||||
use libimagerror::trace::MapErrTrace;
|
|
||||||
use libimagerror::iter::TraceIterator;
|
|
||||||
use libimagerror::exit::ExitUnwrap;
|
|
||||||
use libimagstore::storeid::StoreId;
|
use libimagstore::storeid::StoreId;
|
||||||
use libimagstore::store::Store;
|
use libimagstore::store::Store;
|
||||||
use libimagstore::store::FileLockEntry;
|
use libimagstore::store::FileLockEntry;
|
||||||
use libimagentrylink::linkable::Linkable;
|
use libimagentrylink::linkable::Linkable;
|
||||||
use libimagstore::iter::get::StoreIdGetIteratorExtension;
|
use libimagstore::iter::get::StoreIdGetIteratorExtension;
|
||||||
|
use libimagerror::iter::IterInnerOkOrElse;
|
||||||
|
|
||||||
use failure::Fallible as Result;
|
use failure::Fallible as Result;
|
||||||
|
use failure::err_msg;
|
||||||
use clap::App;
|
use clap::App;
|
||||||
|
|
||||||
|
|
||||||
|
@ -77,72 +73,50 @@ impl ImagApplication for ImagMv {
|
||||||
.value_of("source")
|
.value_of("source")
|
||||||
.map(PathBuf::from)
|
.map(PathBuf::from)
|
||||||
.map(StoreId::new)
|
.map(StoreId::new)
|
||||||
.unwrap() // unwrap safe by clap
|
.unwrap()?; // unwrap safe by clap
|
||||||
.map_err_trace_exit_unwrap();
|
|
||||||
|
|
||||||
let destname = rt
|
let destname = rt
|
||||||
.cli()
|
.cli()
|
||||||
.value_of("dest")
|
.value_of("dest")
|
||||||
.map(PathBuf::from)
|
.map(PathBuf::from)
|
||||||
.map(StoreId::new)
|
.map(StoreId::new)
|
||||||
.unwrap() // unwrap safe by clap
|
.unwrap()?; // unwrap safe by clap
|
||||||
.map_err_trace_exit_unwrap();
|
|
||||||
|
|
||||||
// remove links to entry, and re-add them later
|
// remove links to entry, and re-add them later
|
||||||
let mut linked_entries = {
|
let mut linked_entries = rt.store()
|
||||||
rt.store()
|
.get(sourcename.clone())?
|
||||||
.get(sourcename.clone())
|
.ok_or_else(|| format_err!("Entry does not exist: {}", sourcename))?
|
||||||
.map_err_trace_exit_unwrap()
|
.links()?
|
||||||
.unwrap_or_else(|| {
|
.map(|link| link.get_store_id().clone())
|
||||||
error!("Funny things happened: Entry moved to destination did not fail, but entry does not exist");
|
.map(Ok)
|
||||||
exit(1)
|
|
||||||
})
|
|
||||||
.links()
|
|
||||||
.map_err_trace_exit_unwrap()
|
|
||||||
.map(|link| Ok(link.get_store_id().clone()) as RResult<_, _>)
|
|
||||||
.into_get_iter(rt.store())
|
.into_get_iter(rt.store())
|
||||||
.trace_unwrap_exit()
|
.map_inner_ok_or_else(|| err_msg("Linked entry does not exist"))
|
||||||
.map(|e| {
|
.collect::<Result<Vec<_>>>()?;
|
||||||
e.unwrap_or_else(|| {
|
|
||||||
error!("Linked entry does not exist");
|
|
||||||
exit(1)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
};
|
|
||||||
|
|
||||||
{ // remove links to linked entries from source
|
{ // remove links to linked entries from source
|
||||||
let mut entry = rt
|
let mut entry = rt
|
||||||
.store()
|
.store()
|
||||||
.get(sourcename.clone())
|
.get(sourcename.clone())?
|
||||||
.map_err_trace_exit_unwrap()
|
.ok_or_else(|| err_msg("Source Entry does not exist"))?;
|
||||||
.unwrap_or_else(|| {
|
|
||||||
error!("Source Entry does not exist");
|
|
||||||
exit(1)
|
|
||||||
});
|
|
||||||
|
|
||||||
for link in linked_entries.iter_mut() {
|
for link in linked_entries.iter_mut() {
|
||||||
let _ = entry.remove_link(link).map_err_trace_exit_unwrap();
|
entry.remove_link(link)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let _ = rt
|
if let Err(e) = rt.store().move_by_id(sourcename.clone(), destname.clone()) {
|
||||||
.store()
|
|
||||||
.move_by_id(sourcename.clone(), destname.clone())
|
|
||||||
.map_err(|e| { // on error, re-add links
|
|
||||||
debug!("Re-adding links to source entry because moving failed");
|
debug!("Re-adding links to source entry because moving failed");
|
||||||
relink(rt.store(), sourcename.clone(), &mut linked_entries);
|
relink(rt.store(), sourcename.clone(), &mut linked_entries)?;
|
||||||
e
|
|
||||||
})
|
|
||||||
.map_err_trace_exit_unwrap();
|
|
||||||
|
|
||||||
let _ = rt.report_touched(&destname).unwrap_or_exit();
|
return Err(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
rt.report_touched(&destname)?;
|
||||||
|
|
||||||
// re-add links to moved entry
|
// re-add links to moved entry
|
||||||
relink(rt.store(), destname, &mut linked_entries);
|
relink(rt.store(), destname, &mut linked_entries)?;
|
||||||
|
|
||||||
info!("Ok.");
|
info!("Ok.");
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,17 +139,15 @@ impl ImagApplication for ImagMv {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
fn relink<'a>(store: &'a Store, target: StoreId, linked_entries: &mut Vec<FileLockEntry<'a>>) {
|
fn relink<'a>(store: &'a Store, target: StoreId, linked_entries: &mut Vec<FileLockEntry<'a>>) -> Result<()> {
|
||||||
let mut entry = store
|
let mut entry = store
|
||||||
.get(target)
|
.get(target)?
|
||||||
.map_err_trace_exit_unwrap()
|
.ok_or_else(|| err_msg("Funny things happened: Entry moved to destination did not fail, but entry does not exist"))?;
|
||||||
.unwrap_or_else(|| {
|
|
||||||
error!("Funny things happened: Entry moved to destination did not fail, but entry does not exist");
|
|
||||||
exit(1)
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
for mut link in linked_entries {
|
for mut link in linked_entries {
|
||||||
let _ = entry.add_link(&mut link).map_err_trace_exit_unwrap();
|
let _ = entry.add_link(&mut link)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -47,22 +47,20 @@ extern crate libimagutil;
|
||||||
|
|
||||||
mod ui;
|
mod ui;
|
||||||
|
|
||||||
use std::process::exit;
|
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
|
||||||
use failure::Error;
|
|
||||||
use failure::Fallible as Result;
|
use failure::Fallible as Result;
|
||||||
|
use failure::Error;
|
||||||
|
use failure::err_msg;
|
||||||
use clap::App;
|
use clap::App;
|
||||||
|
|
||||||
use libimagerror::trace::MapErrTrace;
|
|
||||||
use libimagerror::exit::ExitUnwrap;
|
|
||||||
use libimagrt::application::ImagApplication;
|
use libimagrt::application::ImagApplication;
|
||||||
use libimagrt::runtime::Runtime;
|
use libimagrt::runtime::Runtime;
|
||||||
use libimagentryref::reference::Ref;
|
use libimagentryref::reference::Ref;
|
||||||
use libimagentryref::reference::MutRef;
|
|
||||||
use libimagentryref::reference::RefFassade;
|
use libimagentryref::reference::RefFassade;
|
||||||
use libimagentryref::hasher::default::DefaultHasher;
|
use libimagentryref::hasher::default::DefaultHasher;
|
||||||
use libimagentryref::util::get_ref_config;
|
use libimagentryref::util::get_ref_config;
|
||||||
|
use libimagentryref::reference::MutRef;
|
||||||
|
|
||||||
/// Marker enum for implementing ImagApplication on
|
/// Marker enum for implementing ImagApplication on
|
||||||
///
|
///
|
||||||
|
@ -80,16 +78,17 @@ impl ImagApplication for ImagRef {
|
||||||
"list-dead" => list_dead(&rt),
|
"list-dead" => list_dead(&rt),
|
||||||
other => {
|
other => {
|
||||||
debug!("Unknown command");
|
debug!("Unknown command");
|
||||||
let _ = rt.handle_unknown_subcommand("imag-ref", other, rt.cli())
|
if rt.handle_unknown_subcommand("imag-ref", other, rt.cli())?.success() {
|
||||||
.map_err_trace_exit_unwrap()
|
Ok(())
|
||||||
.code()
|
} else {
|
||||||
.map(::std::process::exit);
|
Err(format_err!("Subcommand failed"))
|
||||||
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
};
|
} else {
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn build_cli<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
|
fn build_cli<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
|
||||||
ui::build_ui(app)
|
ui::build_ui(app)
|
||||||
|
@ -108,23 +107,18 @@ impl ImagApplication for ImagRef {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deref(rt: &Runtime) {
|
fn deref(rt: &Runtime) -> Result<()> {
|
||||||
let cmd = rt.cli().subcommand_matches("deref").unwrap();
|
let cmd = rt.cli().subcommand_matches("deref").unwrap();
|
||||||
let basepath = cmd.value_of("override-basepath");
|
let basepath = cmd.value_of("override-basepath");
|
||||||
let cfg = get_ref_config(&rt, "imag-ref").map_err_trace_exit_unwrap();
|
let cfg = get_ref_config(&rt, "imag-ref")?;
|
||||||
let out = rt.stdout();
|
let out = rt.stdout();
|
||||||
let mut outlock = out.lock();
|
let mut outlock = out.lock();
|
||||||
|
|
||||||
rt
|
rt.ids::<::ui::PathProvider>()?
|
||||||
.ids::<::ui::PathProvider>()
|
.ok_or_else(|| err_msg("No ids supplied"))?
|
||||||
.map_err_trace_exit_unwrap()
|
|
||||||
.unwrap_or_else(|| {
|
|
||||||
error!("No ids supplied");
|
|
||||||
::std::process::exit(1);
|
|
||||||
})
|
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.for_each(|id| {
|
.map(|id| {
|
||||||
match rt.store().get(id.clone()).map_err_trace_exit_unwrap() {
|
match rt.store().get(id.clone())? {
|
||||||
Some(entry) => {
|
Some(entry) => {
|
||||||
let r_entry = entry.as_ref_with_hasher::<DefaultHasher>();
|
let r_entry = entry.as_ref_with_hasher::<DefaultHasher>();
|
||||||
|
|
||||||
|
@ -132,89 +126,63 @@ fn deref(rt: &Runtime) {
|
||||||
r_entry.get_path_with_basepath_setting(&cfg, alternative_basepath)
|
r_entry.get_path_with_basepath_setting(&cfg, alternative_basepath)
|
||||||
} else {
|
} else {
|
||||||
r_entry.get_path(&cfg)
|
r_entry.get_path(&cfg)
|
||||||
}
|
}?
|
||||||
.map_err_trace_exit_unwrap()
|
|
||||||
.to_str()
|
.to_str()
|
||||||
.ok_or_else(|| ::libimagerror::errors::ErrorMsg::UTF8Error)
|
.ok_or_else(|| Error::from(::libimagerror::errors::ErrorMsg::UTF8Error))
|
||||||
.map_err(Error::from)
|
.and_then(|s| writeln!(outlock, "{}", s).map_err(Error::from))?;
|
||||||
.and_then(|s| writeln!(outlock, "{}", s).map_err(Error::from))
|
|
||||||
.map_err_trace_exit_unwrap();
|
|
||||||
|
|
||||||
rt.report_touched(&id).unwrap_or_exit();
|
rt.report_touched(&id).map_err(Error::from)
|
||||||
},
|
|
||||||
None => {
|
|
||||||
error!("No entry for id '{}' found", id);
|
|
||||||
exit(1)
|
|
||||||
},
|
},
|
||||||
|
None => Err(format_err!("No entry for id '{}' found", id))
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove(rt: &Runtime) {
|
fn remove(rt: &Runtime) -> Result<()> {
|
||||||
use libimaginteraction::ask::ask_bool;
|
use libimaginteraction::ask::ask_bool;
|
||||||
|
|
||||||
let cmd = rt.cli().subcommand_matches("remove").unwrap();
|
let cmd = rt.cli().subcommand_matches("remove").unwrap();
|
||||||
let yes = cmd.is_present("yes");
|
let yes = cmd.is_present("yes");
|
||||||
|
let mut input = rt.stdin().ok_or_else(|| err_msg("No input stream. Cannot ask for permission"))?;
|
||||||
let mut input = rt.stdin().unwrap_or_else(|| {
|
|
||||||
error!("No input stream. Cannot ask for permission");
|
|
||||||
exit(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
let mut output = rt.stdout();
|
let mut output = rt.stdout();
|
||||||
|
|
||||||
rt
|
rt.ids::<::ui::PathProvider>()?
|
||||||
.ids::<::ui::PathProvider>()
|
.ok_or_else(|| err_msg("No ids supplied"))?
|
||||||
.map_err_trace_exit_unwrap()
|
|
||||||
.unwrap_or_else(|| {
|
|
||||||
error!("No ids supplied");
|
|
||||||
::std::process::exit(1);
|
|
||||||
})
|
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.for_each(|id| {
|
.map(|id| {
|
||||||
match rt.store().get(id.clone()).map_err_trace_exit_unwrap() {
|
match rt.store().get(id.clone())? {
|
||||||
|
None => Err(format_err!("No entry for id '{}' found", id)),
|
||||||
Some(mut entry) => {
|
Some(mut entry) => {
|
||||||
if yes ||
|
if yes || ask_bool(&format!("Delete ref from entry '{}'", id), None, &mut input, &mut output)? {
|
||||||
ask_bool(&format!("Delete ref from entry '{}'", id), None, &mut input, &mut output)
|
entry.as_ref_with_hasher_mut::<DefaultHasher>().remove_ref()
|
||||||
.map_err_trace_exit_unwrap()
|
|
||||||
{
|
|
||||||
entry.as_ref_with_hasher_mut::<DefaultHasher>()
|
|
||||||
.remove_ref()
|
|
||||||
.map_err_trace_exit_unwrap();
|
|
||||||
} else {
|
} else {
|
||||||
info!("Aborted");
|
info!("Aborted");
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
None => {
|
|
||||||
error!("No entry for id '{}' found", id);
|
|
||||||
exit(1)
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn list_dead(rt: &Runtime) {
|
fn list_dead(rt: &Runtime) -> Result<()> {
|
||||||
let cfg = get_ref_config(&rt, "imag-ref").map_err_trace_exit_unwrap();
|
let cfg = get_ref_config(&rt, "imag-ref")?;
|
||||||
let cmd = rt.cli().subcommand_matches("list-dead").unwrap(); // safe by main()
|
let cmd = rt.cli().subcommand_matches("list-dead").unwrap(); // safe by main()
|
||||||
let list_path = cmd.is_present("list-dead-pathes");
|
let list_path = cmd.is_present("list-dead-pathes");
|
||||||
let list_id = cmd.is_present("list-dead-ids");
|
let list_id = cmd.is_present("list-dead-ids");
|
||||||
let mut output = rt.stdout();
|
let mut output = rt.stdout();
|
||||||
|
|
||||||
rt
|
rt.ids::<crate::ui::PathProvider>()?
|
||||||
.ids::<crate::ui::PathProvider>()
|
.ok_or_else(|| err_msg("No ids supplied"))?
|
||||||
.map_err_trace_exit_unwrap()
|
|
||||||
.unwrap_or_else(|| {
|
|
||||||
error!("No ids supplied");
|
|
||||||
::std::process::exit(1);
|
|
||||||
})
|
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.for_each(|id| {
|
.map(|id| {
|
||||||
match rt.store().get(id.clone()).map_err_trace_exit_unwrap() {
|
match rt.store().get(id.clone())? {
|
||||||
Some(entry) => {
|
Some(entry) => {
|
||||||
let entry_ref = entry.as_ref_with_hasher::<DefaultHasher>();
|
let entry_ref = entry.as_ref_with_hasher::<DefaultHasher>();
|
||||||
|
|
||||||
if entry_ref.is_ref().map_err_trace_exit_unwrap() { // we only care if the entry is a ref
|
if entry_ref.is_ref()? { // we only care if the entry is a ref
|
||||||
let entry_path = entry_ref.get_path(&cfg).map_err_trace_exit_unwrap();
|
let entry_path = entry_ref.get_path(&cfg)?;
|
||||||
|
|
||||||
if !entry_path.exists() {
|
if !entry_path.exists() {
|
||||||
if list_id {
|
if list_id {
|
||||||
|
@ -223,24 +191,24 @@ fn list_dead(rt: &Runtime) {
|
||||||
writeln!(output, "{}", entry_path.display())
|
writeln!(output, "{}", entry_path.display())
|
||||||
} else {
|
} else {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}?;
|
||||||
.map_err(Error::from)
|
|
||||||
.map_err_trace_exit_unwrap();
|
|
||||||
|
|
||||||
rt.report_touched(entry.get_location()).unwrap_or_exit();
|
rt.report_touched(entry.get_location()).map_err(Error::from)
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
None => {
|
None => Err(format_err!("Does not exist: {}", id.local().display())),
|
||||||
error!("Does not exist: {}", id.local().display());
|
|
||||||
exit(1)
|
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
});
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create(_rt: &Runtime) {
|
fn create(_rt: &Runtime) -> Result<()> {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@ maintenance = { status = "actively-developed" }
|
||||||
log = "0.4.6"
|
log = "0.4.6"
|
||||||
toml = "0.5.1"
|
toml = "0.5.1"
|
||||||
failure = "0.1.5"
|
failure = "0.1.5"
|
||||||
|
resiter = "0.3.0"
|
||||||
|
|
||||||
libimagstore = { version = "0.10.0", path = "../../../lib/core/libimagstore", features = ["verify"] }
|
libimagstore = { version = "0.10.0", path = "../../../lib/core/libimagstore", features = ["verify"] }
|
||||||
libimagrt = { version = "0.10.0", path = "../../../lib/core/libimagrt" }
|
libimagrt = { version = "0.10.0", path = "../../../lib/core/libimagrt" }
|
||||||
|
|
|
@ -17,34 +17,32 @@
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
//
|
//
|
||||||
|
|
||||||
|
use std::ops::DerefMut;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::io::stdin;
|
use std::io::stdin;
|
||||||
use std::fs::OpenOptions;
|
use std::fs::OpenOptions;
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
use std::ops::DerefMut;
|
|
||||||
|
|
||||||
use clap::ArgMatches;
|
use clap::ArgMatches;
|
||||||
use toml::Value;
|
use toml::Value;
|
||||||
use failure::Fallible as Result;
|
use failure::Fallible as Result;
|
||||||
|
use failure::Error;
|
||||||
use failure::err_msg;
|
use failure::err_msg;
|
||||||
|
|
||||||
use libimagrt::runtime::Runtime;
|
use libimagrt::runtime::Runtime;
|
||||||
use libimagstore::store::Entry;
|
use libimagstore::store::Entry;
|
||||||
use libimagstore::storeid::StoreId;
|
use libimagstore::storeid::StoreId;
|
||||||
use libimagerror::trace::MapErrTrace;
|
|
||||||
use libimagerror::exit::ExitUnwrap;
|
|
||||||
use libimagutil::debug_result::*;
|
|
||||||
|
|
||||||
use crate::util::build_toml_header;
|
use crate::util::build_toml_header;
|
||||||
|
|
||||||
pub fn create(rt: &Runtime) {
|
pub fn create(rt: &Runtime) -> Result<()> {
|
||||||
let scmd = rt.cli().subcommand_matches("create").unwrap();
|
let scmd = rt.cli().subcommand_matches("create").unwrap();
|
||||||
debug!("Found 'create' subcommand...");
|
debug!("Found 'create' subcommand...");
|
||||||
|
|
||||||
// unwrap is safe as value is required
|
// unwrap is safe as value is required
|
||||||
let path = scmd.value_of("path").unwrap();
|
let path = scmd.value_of("path").unwrap();
|
||||||
let path = PathBuf::from(path);
|
let path = PathBuf::from(path);
|
||||||
let path = StoreId::new(path).map_err_trace_exit_unwrap();
|
let path = StoreId::new(path)?;
|
||||||
|
|
||||||
debug!("path = {:?}", path);
|
debug!("path = {:?}", path);
|
||||||
|
|
||||||
|
@ -55,15 +53,13 @@ pub fn create(rt: &Runtime) {
|
||||||
.or_else(|_| create_with_content_and_header(rt,
|
.or_else(|_| create_with_content_and_header(rt,
|
||||||
&path,
|
&path,
|
||||||
String::new(),
|
String::new(),
|
||||||
Entry::default_header()))
|
Entry::default_header()))?;
|
||||||
} else {
|
} else {
|
||||||
debug!("Creating entry");
|
debug!("Creating entry");
|
||||||
create_with_content_and_header(rt, &path, String::new(),
|
create_with_content_and_header(rt, &path, String::new(), Entry::default_header())?;
|
||||||
Entry::default_header())
|
|
||||||
}
|
}
|
||||||
.map_err_trace_exit_unwrap();
|
|
||||||
|
|
||||||
rt.report_touched(&path).unwrap_or_exit();
|
rt.report_touched(&path).map_err(Error::from)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_from_cli_spec(rt: &Runtime, matches: &ArgMatches, path: &StoreId) -> Result<()> {
|
fn create_from_cli_spec(rt: &Runtime, matches: &ArgMatches, path: &StoreId) -> Result<()> {
|
||||||
|
@ -99,19 +95,13 @@ fn create_from_source(rt: &Runtime, matches: &ArgMatches, path: &StoreId) -> Res
|
||||||
debug!("Content with len = {}", content.len());
|
debug!("Content with len = {}", content.len());
|
||||||
|
|
||||||
Entry::from_str(path.clone(), &content[..])
|
Entry::from_str(path.clone(), &content[..])
|
||||||
.map_dbg_err(|e| format!("Error building entry: {:?}", e))
|
|
||||||
.and_then(|new_e| {
|
.and_then(|new_e| {
|
||||||
let r = rt.store()
|
rt.store()
|
||||||
.create(path.clone())
|
.create(path.clone())
|
||||||
.map_dbg_err(|e| format!("Error in Store::create(): {:?}", e))
|
|
||||||
.map(|mut old_e| {
|
.map(|mut old_e| {
|
||||||
*old_e.deref_mut() = new_e;
|
*old_e.deref_mut() = new_e;
|
||||||
});
|
|
||||||
|
|
||||||
debug!("Entry build");
|
|
||||||
r
|
|
||||||
})
|
})
|
||||||
.map_dbg_err(|e| format!("Error storing entry: {:?}", e))
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_with_content_and_header(rt: &Runtime,
|
fn create_with_content_and_header(rt: &Runtime,
|
||||||
|
@ -122,7 +112,6 @@ fn create_with_content_and_header(rt: &Runtime,
|
||||||
debug!("Creating entry with content at {:?}", path);
|
debug!("Creating entry with content at {:?}", path);
|
||||||
rt.store()
|
rt.store()
|
||||||
.create(path.clone())
|
.create(path.clone())
|
||||||
.map_dbg_err(|e| format!("Error in Store::create(): {:?}", e))
|
|
||||||
.map(|mut element| {
|
.map(|mut element| {
|
||||||
{
|
{
|
||||||
let e_content = element.get_content_mut();
|
let e_content = element.get_content_mut();
|
||||||
|
@ -177,7 +166,7 @@ mod tests {
|
||||||
let test_name = "test_create_simple";
|
let test_name = "test_create_simple";
|
||||||
let rt = generate_test_runtime(vec!["create", "test_create_simple"]).unwrap();
|
let rt = generate_test_runtime(vec!["create", "test_create_simple"]).unwrap();
|
||||||
|
|
||||||
create(&rt);
|
create(&rt).unwrap();
|
||||||
|
|
||||||
let e = rt.store().get(PathBuf::from(test_name));
|
let e = rt.store().get(PathBuf::from(test_name));
|
||||||
assert!(e.is_ok());
|
assert!(e.is_ok());
|
||||||
|
|
|
@ -19,22 +19,19 @@
|
||||||
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use libimagrt::runtime::Runtime;
|
use failure::Fallible as Result;
|
||||||
use libimagerror::trace::MapErrTrace;
|
|
||||||
use libimagstore::storeid::StoreId;
|
|
||||||
use libimagutil::warn_result::*;
|
|
||||||
|
|
||||||
pub fn delete(rt: &Runtime) {
|
use libimagrt::runtime::Runtime;
|
||||||
|
use libimagstore::storeid::StoreId;
|
||||||
|
|
||||||
|
pub fn delete(rt: &Runtime) -> Result<()> {
|
||||||
let scmd = rt.cli().subcommand_matches("delete").unwrap();
|
let scmd = rt.cli().subcommand_matches("delete").unwrap();
|
||||||
let id = scmd.value_of("id").unwrap(); // safe by clap
|
let id = scmd.value_of("id").unwrap(); // safe by clap
|
||||||
let path = PathBuf::from(id);
|
let path = PathBuf::from(id);
|
||||||
let path = StoreId::new(path).map_err_trace_exit_unwrap();
|
let path = StoreId::new(path)?;
|
||||||
debug!("Deleting file at {:?}", id);
|
debug!("Deleting file at {:?}", id);
|
||||||
|
|
||||||
rt.store()
|
rt.store().delete(path)
|
||||||
.delete(path)
|
|
||||||
.map_warn_err(|e| format!("Error: {:?}", e))
|
|
||||||
.map_err_trace_exit_unwrap();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -59,11 +56,11 @@ mod tests {
|
||||||
let test_name = "test_create_simple";
|
let test_name = "test_create_simple";
|
||||||
let rt = generate_test_runtime(vec!["create", "test_create_simple"]).unwrap();
|
let rt = generate_test_runtime(vec!["create", "test_create_simple"]).unwrap();
|
||||||
|
|
||||||
create(&rt);
|
create(&rt).unwrap();
|
||||||
|
|
||||||
let rt = reset_test_runtime(vec!["delete", "test_create_simple"], rt).unwrap();
|
let rt = reset_test_runtime(vec!["delete", "test_create_simple"], rt).unwrap();
|
||||||
|
|
||||||
delete(&rt);
|
delete(&rt).unwrap();
|
||||||
|
|
||||||
let e = rt.store().get(PathBuf::from(test_name));
|
let e = rt.store().get(PathBuf::from(test_name));
|
||||||
assert!(e.is_ok());
|
assert!(e.is_ok());
|
||||||
|
|
|
@ -19,27 +19,29 @@
|
||||||
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
use failure::Fallible as Result;
|
||||||
|
use failure::Error;
|
||||||
|
use failure::err_msg;
|
||||||
|
|
||||||
use libimagrt::runtime::Runtime;
|
use libimagrt::runtime::Runtime;
|
||||||
use libimagerror::trace::MapErrTrace;
|
|
||||||
use libimagerror::exit::ExitUnwrap;
|
|
||||||
use libimagstore::storeid::StoreId;
|
use libimagstore::storeid::StoreId;
|
||||||
|
|
||||||
use crate::retrieve::print_entry;
|
use crate::retrieve::print_entry;
|
||||||
|
|
||||||
pub fn get(rt: &Runtime) {
|
pub fn get(rt: &Runtime) -> Result<()> {
|
||||||
let scmd = rt.cli().subcommand_matches("get").unwrap();
|
let scmd = rt.cli().subcommand_matches("get").unwrap();
|
||||||
|
|
||||||
let id = scmd.value_of("id").unwrap(); // safe by clap
|
let id = scmd.value_of("id").unwrap(); // safe by clap
|
||||||
let path = PathBuf::from(id);
|
let path = PathBuf::from(id);
|
||||||
let path = StoreId::new(path).map_err_trace_exit_unwrap();
|
let path = StoreId::new(path)?;
|
||||||
debug!("path = {:?}", path);
|
debug!("path = {:?}", path);
|
||||||
|
|
||||||
match rt.store().get(path.clone()).map_err_trace_exit_unwrap() {
|
match rt.store().get(path.clone())? {
|
||||||
|
None => Err(err_msg("No entry found")),
|
||||||
Some(entry) => {
|
Some(entry) => {
|
||||||
print_entry(rt, scmd, entry);
|
print_entry(rt, scmd, entry)?;
|
||||||
rt.report_touched(&path).unwrap_or_exit();
|
rt.report_touched(&path).map_err(Error::from)
|
||||||
},
|
},
|
||||||
None => info!("No entry found"),
|
}
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,8 +37,9 @@
|
||||||
extern crate clap;
|
extern crate clap;
|
||||||
#[macro_use] extern crate log;
|
#[macro_use] extern crate log;
|
||||||
extern crate toml;
|
extern crate toml;
|
||||||
|
extern crate resiter;
|
||||||
#[cfg(test)] extern crate toml_query;
|
#[cfg(test)] extern crate toml_query;
|
||||||
extern crate failure;
|
#[macro_use] extern crate failure;
|
||||||
|
|
||||||
extern crate libimagrt;
|
extern crate libimagrt;
|
||||||
extern crate libimagstore;
|
extern crate libimagstore;
|
||||||
|
@ -53,7 +54,9 @@ extern crate libimagutil;
|
||||||
|
|
||||||
use libimagrt::application::ImagApplication;
|
use libimagrt::application::ImagApplication;
|
||||||
use libimagrt::runtime::Runtime;
|
use libimagrt::runtime::Runtime;
|
||||||
use libimagerror::trace::MapErrTrace;
|
|
||||||
|
use failure::Fallible as Result;
|
||||||
|
use failure::err_msg;
|
||||||
|
|
||||||
mod create;
|
mod create;
|
||||||
mod delete;
|
mod delete;
|
||||||
|
@ -66,7 +69,6 @@ mod util;
|
||||||
|
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
|
||||||
use failure::Fallible as Result;
|
|
||||||
use clap::App;
|
use clap::App;
|
||||||
|
|
||||||
use crate::create::create;
|
use crate::create::create;
|
||||||
|
@ -83,9 +85,7 @@ use crate::verify::verify;
|
||||||
pub enum ImagStore {}
|
pub enum ImagStore {}
|
||||||
impl ImagApplication for ImagStore {
|
impl ImagApplication for ImagStore {
|
||||||
fn run(rt: Runtime) -> Result<()> {
|
fn run(rt: Runtime) -> Result<()> {
|
||||||
let command = rt.cli().subcommand_name().map(String::from);
|
if let Some(command) = rt.cli().subcommand_name() {
|
||||||
|
|
||||||
if let Some(command) = command {
|
|
||||||
debug!("Call: {}", command);
|
debug!("Call: {}", command);
|
||||||
match command.deref() {
|
match command.deref() {
|
||||||
"create" => create(&rt),
|
"create" => create(&rt),
|
||||||
|
@ -96,17 +96,16 @@ impl ImagApplication for ImagStore {
|
||||||
"verify" => verify(&rt),
|
"verify" => verify(&rt),
|
||||||
other => {
|
other => {
|
||||||
debug!("Unknown command");
|
debug!("Unknown command");
|
||||||
let _ = rt.handle_unknown_subcommand("imag-store", other, rt.cli())
|
if rt.handle_unknown_subcommand("imag-store", other, rt.cli())?.success() {
|
||||||
.map_err_trace_exit_unwrap()
|
|
||||||
.code()
|
|
||||||
.map(::std::process::exit);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
debug!("No command");
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(format_err!("Subcommand failed"))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Err(err_msg("No command"))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_cli<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
|
fn build_cli<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
|
||||||
|
|
|
@ -20,41 +20,32 @@
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
|
||||||
|
use failure::Fallible as Result;
|
||||||
|
use failure::Error;
|
||||||
use clap::ArgMatches;
|
use clap::ArgMatches;
|
||||||
|
|
||||||
use libimagstore::store::FileLockEntry;
|
use libimagstore::store::FileLockEntry;
|
||||||
use libimagstore::storeid::StoreId;
|
use libimagstore::storeid::StoreId;
|
||||||
use libimagrt::runtime::Runtime;
|
use libimagrt::runtime::Runtime;
|
||||||
use libimagerror::trace::MapErrTrace;
|
|
||||||
use libimagerror::io::ToExitCode;
|
|
||||||
use libimagerror::exit::ExitUnwrap;
|
|
||||||
use libimagutil::debug_result::*;
|
|
||||||
|
|
||||||
pub fn retrieve(rt: &Runtime) {
|
pub fn retrieve(rt: &Runtime) -> Result<()> {
|
||||||
if let Some(scmd) = rt.cli().subcommand_matches("retrieve") {
|
let scmd = rt.cli().subcommand_matches("retrieve").unwrap();
|
||||||
// unwrap() is safe as arg is required
|
|
||||||
let id = scmd.value_of("id").unwrap();
|
let id = scmd.value_of("id").unwrap();
|
||||||
let path = PathBuf::from(id);
|
let path = PathBuf::from(id);
|
||||||
let path = StoreId::new(path).map_err_trace_exit_unwrap();
|
let path = StoreId::new(path)?;
|
||||||
debug!("path = {:?}", path);
|
debug!("path = {:?}", path);
|
||||||
|
|
||||||
rt.store()
|
rt.store()
|
||||||
.retrieve(path.clone())
|
.retrieve(path.clone())
|
||||||
.map(|e| print_entry(rt, scmd, e))
|
.and_then(|e| print_entry(rt, scmd, e))?;
|
||||||
.map_dbg_str("No entry")
|
|
||||||
.map_dbg(|e| format!("{:?}", e))
|
|
||||||
.map_err_trace_exit_unwrap();
|
|
||||||
|
|
||||||
rt.report_touched(&path).unwrap_or_exit();
|
rt.report_touched(&path).map_err(Error::from)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn print_entry(rt: &Runtime, scmd: &ArgMatches, e: FileLockEntry) {
|
pub fn print_entry(rt: &Runtime, scmd: &ArgMatches, e: FileLockEntry) -> Result<()> {
|
||||||
if do_print_raw(scmd) {
|
if do_print_raw(scmd) {
|
||||||
debug!("Printing raw content...");
|
debug!("Printing raw content...");
|
||||||
writeln!(rt.stdout(), "{}", e.to_str().map_err_trace_exit_unwrap())
|
writeln!(rt.stdout(), "{}", e.to_str()?)?;
|
||||||
.to_exit_code()
|
|
||||||
.unwrap_or_exit();
|
|
||||||
} else if do_filter(scmd) {
|
} else if do_filter(scmd) {
|
||||||
debug!("Filtering...");
|
debug!("Filtering...");
|
||||||
warn!("Filtering via header specs is currently now supported.");
|
warn!("Filtering via header specs is currently now supported.");
|
||||||
|
@ -71,20 +62,17 @@ pub fn print_entry(rt: &Runtime, scmd: &ArgMatches, e: FileLockEntry) {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
} else {
|
} else {
|
||||||
debug!("Printing header as TOML...");
|
debug!("Printing header as TOML...");
|
||||||
writeln!(rt.stdout(), "{}", e.get_header())
|
writeln!(rt.stdout(), "{}", e.get_header())?;
|
||||||
.to_exit_code()
|
|
||||||
.unwrap_or_exit();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if do_print_content(scmd) {
|
if do_print_content(scmd) {
|
||||||
debug!("Printing content...");
|
debug!("Printing content...");
|
||||||
writeln!(rt.stdout(), "{}", e.get_content())
|
writeln!(rt.stdout(), "{}", e.get_content())?;
|
||||||
.to_exit_code()
|
}
|
||||||
.unwrap_or_exit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn do_print_header(m: &ArgMatches) -> bool {
|
fn do_print_header(m: &ArgMatches) -> bool {
|
||||||
|
|
|
@ -20,22 +20,23 @@
|
||||||
use std::ops::DerefMut;
|
use std::ops::DerefMut;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
use failure::Fallible as Result;
|
||||||
|
use failure::Error;
|
||||||
|
|
||||||
use libimagrt::runtime::Runtime;
|
use libimagrt::runtime::Runtime;
|
||||||
use libimagerror::trace::MapErrTrace;
|
|
||||||
use libimagerror::exit::ExitUnwrap;
|
|
||||||
use libimagstore::storeid::StoreId;
|
use libimagstore::storeid::StoreId;
|
||||||
|
|
||||||
use crate::util::build_toml_header;
|
use crate::util::build_toml_header;
|
||||||
|
|
||||||
pub fn update(rt: &Runtime) {
|
pub fn update(rt: &Runtime) -> Result<()> {
|
||||||
let scmd = rt.cli().subcommand_matches("update").unwrap();
|
let scmd = rt.cli().subcommand_matches("update").unwrap();
|
||||||
let id = scmd.value_of("id").unwrap(); // Safe by clap
|
let id = scmd.value_of("id").unwrap(); // Safe by clap
|
||||||
let path = PathBuf::from(id);
|
let path = PathBuf::from(id);
|
||||||
let path = StoreId::new(path).map_err_trace_exit_unwrap();
|
let path = StoreId::new(path)?;
|
||||||
|
|
||||||
let _ = rt.store()
|
rt.store()
|
||||||
.retrieve(path)
|
.retrieve(path)
|
||||||
.map(|mut locked_e| {
|
.and_then(|mut locked_e| {
|
||||||
{
|
{
|
||||||
let e = locked_e.deref_mut();
|
let e = locked_e.deref_mut();
|
||||||
|
|
||||||
|
@ -48,7 +49,7 @@ pub fn update(rt: &Runtime) {
|
||||||
debug!("New header set");
|
debug!("New header set");
|
||||||
}
|
}
|
||||||
|
|
||||||
rt.report_touched(locked_e.get_location()).unwrap_or_exit();
|
rt.report_touched(locked_e.get_location()).map_err(Error::from)
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,26 +19,25 @@
|
||||||
|
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
|
||||||
|
use failure::Fallible as Result;
|
||||||
|
use failure::err_msg;
|
||||||
|
use resiter::AndThen;
|
||||||
|
|
||||||
use libimagrt::runtime::Runtime;
|
use libimagrt::runtime::Runtime;
|
||||||
use libimagutil::warn_exit::warn_exit;
|
use libimagerror::iter::IterInnerOkOrElse;
|
||||||
use libimagerror::trace::MapErrTrace;
|
|
||||||
use libimagerror::exit::ExitUnwrap;
|
|
||||||
use libimagerror::iter::TraceIterator;
|
|
||||||
|
|
||||||
/// Verify the store.
|
/// Verify the store.
|
||||||
///
|
///
|
||||||
/// This function is not intended to be called by normal programs but only by `imag-store`.
|
/// This function is not intended to be called by normal programs but only by `imag-store`.
|
||||||
pub fn verify(rt: &Runtime) {
|
pub fn verify(rt: &Runtime) -> Result<()> {
|
||||||
info!("Header | Content length | Path");
|
info!("Header | Content length | Path");
|
||||||
info!("-------+----------------+-----");
|
info!("-------+----------------+-----");
|
||||||
let result = rt
|
let result = rt
|
||||||
.store()
|
.store()
|
||||||
.entries()
|
.entries()?
|
||||||
.map_err_trace_exit_unwrap()
|
|
||||||
.into_get_iter()
|
.into_get_iter()
|
||||||
.trace_unwrap_exit()
|
.map_inner_ok_or_else(|| err_msg("Did not find one entry"))
|
||||||
.filter_map(|x| x)
|
.and_then_ok(|fle| {
|
||||||
.all(|fle| {
|
|
||||||
let p = fle.get_location();
|
let p = fle.get_location();
|
||||||
let content_len = fle.get_content().len();
|
let content_len = fle.get_content().len();
|
||||||
let (verify, status) = if fle.verify().is_ok() {
|
let (verify, status) = if fle.verify().is_ok() {
|
||||||
|
@ -48,14 +47,18 @@ pub fn verify(rt: &Runtime) {
|
||||||
};
|
};
|
||||||
|
|
||||||
info!("{: >6} | {: >14} | {:?}", verify, content_len, p.deref());
|
info!("{: >6} | {: >14} | {:?}", verify, content_len, p.deref());
|
||||||
rt.report_touched(fle.get_location()).unwrap_or_exit();
|
rt.report_touched(fle.get_location())?;
|
||||||
status
|
Ok(status)
|
||||||
});
|
})
|
||||||
|
.collect::<Result<Vec<_>>>()?
|
||||||
|
.iter()
|
||||||
|
.all(|x| *x);
|
||||||
|
|
||||||
if result {
|
if result {
|
||||||
info!("Store seems to be fine");
|
info!("Store seems to be fine");
|
||||||
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
warn_exit("Store seems to be broken somehow", 1);
|
Err(err_msg("Store seems to be broken somehow"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,7 @@ extern crate clap;
|
||||||
#[macro_use] extern crate log;
|
#[macro_use] extern crate log;
|
||||||
|
|
||||||
#[cfg(test)] extern crate toml;
|
#[cfg(test)] extern crate toml;
|
||||||
extern crate failure;
|
#[macro_use] extern crate failure;
|
||||||
|
|
||||||
extern crate libimagstore;
|
extern crate libimagstore;
|
||||||
extern crate libimagrt;
|
extern crate libimagrt;
|
||||||
|
@ -60,19 +60,17 @@ extern crate env_logger;
|
||||||
|
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
|
||||||
|
use failure::Fallible as Result;
|
||||||
|
use failure::Error;
|
||||||
|
use failure::err_msg;
|
||||||
|
|
||||||
use libimagrt::runtime::Runtime;
|
use libimagrt::runtime::Runtime;
|
||||||
use libimagrt::application::ImagApplication;
|
use libimagrt::application::ImagApplication;
|
||||||
use libimagentrytag::tagable::Tagable;
|
use libimagentrytag::tagable::Tagable;
|
||||||
use libimagentrytag::tag::Tag;
|
use libimagentrytag::tag::Tag;
|
||||||
use libimagerror::trace::trace_error;
|
|
||||||
use libimagerror::trace::MapErrTrace;
|
|
||||||
use libimagerror::io::ToExitCode;
|
|
||||||
use libimagerror::exit::ExitUnwrap;
|
|
||||||
use libimagstore::storeid::StoreId;
|
use libimagstore::storeid::StoreId;
|
||||||
use libimagutil::warn_exit::warn_exit;
|
|
||||||
|
|
||||||
use clap::{App, ArgMatches};
|
use clap::{App, ArgMatches};
|
||||||
use failure::Fallible as Result;
|
|
||||||
|
|
||||||
mod ui;
|
mod ui;
|
||||||
|
|
||||||
|
@ -84,44 +82,41 @@ mod ui;
|
||||||
pub enum ImagTag {}
|
pub enum ImagTag {}
|
||||||
impl ImagApplication for ImagTag {
|
impl ImagApplication for ImagTag {
|
||||||
fn run(rt: Runtime) -> Result<()> {
|
fn run(rt: Runtime) -> Result<()> {
|
||||||
let ids = rt
|
let ids = rt.ids::<crate::ui::PathProvider>()?
|
||||||
.ids::<crate::ui::PathProvider>()
|
.ok_or_else(|| err_msg("No ids supplied"))?
|
||||||
.map_err_trace_exit_unwrap()
|
|
||||||
.unwrap_or_else(|| {
|
|
||||||
error!("No ids supplied");
|
|
||||||
::std::process::exit(1);
|
|
||||||
})
|
|
||||||
.into_iter();
|
.into_iter();
|
||||||
|
|
||||||
if let Some(name) = rt.cli().subcommand_name() {
|
if let Some(name) = rt.cli().subcommand_name() {
|
||||||
match name {
|
match name {
|
||||||
"list" => for id in ids {
|
"list" => ids.into_iter().map(|id| list(id, &rt)).collect(),
|
||||||
list(id, &rt)
|
|
||||||
},
|
"remove" => ids.into_iter().map(|id| {
|
||||||
"remove" => for id in ids {
|
|
||||||
let add = None;
|
let add = None;
|
||||||
let rem = get_remove_tags(rt.cli());
|
let rem = get_remove_tags(rt.cli())?;
|
||||||
debug!("id = {:?}, add = {:?}, rem = {:?}", id, add, rem);
|
debug!("id = {:?}, add = {:?}, rem = {:?}", id, add, rem);
|
||||||
alter(&rt, id, add, rem);
|
alter(&rt, id, add, rem)
|
||||||
},
|
}).collect(),
|
||||||
"add" => for id in ids {
|
|
||||||
let add = get_add_tags(rt.cli());
|
"add" => ids.into_iter().map(|id| {
|
||||||
|
let add = get_add_tags(rt.cli())?;
|
||||||
let rem = None;
|
let rem = None;
|
||||||
debug!("id = {:?}, add = {:?}, rem = {:?}", id, add, rem);
|
debug!("id = {:?}, add = {:?}, rem = {:?}", id, add, rem);
|
||||||
alter(&rt, id, add, rem);
|
alter(&rt, id, add, rem)
|
||||||
},
|
}).collect(),
|
||||||
|
|
||||||
other => {
|
other => {
|
||||||
debug!("Unknown command");
|
debug!("Unknown command");
|
||||||
let _ = rt.handle_unknown_subcommand("imag-tag", other, rt.cli())
|
if rt.handle_unknown_subcommand("imag-tag", other, rt.cli())?.success() {
|
||||||
.map_err_trace_exit_unwrap()
|
Ok(())
|
||||||
.code()
|
} else {
|
||||||
.map(::std::process::exit);
|
Err(format_err!("Subcommand failed"))
|
||||||
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn build_cli<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
|
fn build_cli<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
|
||||||
ui::build_ui(app)
|
ui::build_ui(app)
|
||||||
|
@ -140,60 +135,43 @@ impl ImagApplication for ImagTag {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn alter(rt: &Runtime, path: StoreId, add: Option<Vec<Tag>>, rem: Option<Vec<Tag>>) {
|
fn alter(rt: &Runtime, path: StoreId, add: Option<Vec<Tag>>, rem: Option<Vec<Tag>>) -> Result<()> {
|
||||||
match rt.store().get(path.clone()) {
|
match rt.store().get(path.clone())? {
|
||||||
Ok(Some(mut e)) => {
|
Some(mut e) => {
|
||||||
debug!("Entry header now = {:?}", e.get_header());
|
debug!("Entry header now = {:?}", e.get_header());
|
||||||
|
|
||||||
if let Some(tags) = add {
|
if let Some(tags) = add {
|
||||||
debug!("Adding tags = '{:?}'", tags);
|
debug!("Adding tags = '{:?}'", tags);
|
||||||
for tag in tags {
|
tags.into_iter().map(|tag| {
|
||||||
debug!("Adding tag '{:?}'", tag);
|
debug!("Adding tag '{:?}'", tag);
|
||||||
if let Err(e) = e.add_tag(tag) {
|
e.add_tag(tag)
|
||||||
trace_error(&e);
|
}).collect::<Result<Vec<_>>>()?;
|
||||||
} else {
|
|
||||||
debug!("Adding tag worked");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} // it is okay to ignore a None here
|
} // it is okay to ignore a None here
|
||||||
|
|
||||||
debug!("Entry header now = {:?}", e.get_header());
|
debug!("Entry header now = {:?}", e.get_header());
|
||||||
|
|
||||||
if let Some(tags) = rem {
|
if let Some(tags) = rem {
|
||||||
debug!("Removing tags = '{:?}'", tags);
|
debug!("Removing tags = '{:?}'", tags);
|
||||||
for tag in tags {
|
tags.into_iter().map(|tag| {
|
||||||
debug!("Removing tag '{:?}'", tag);
|
debug!("Removing tag '{:?}'", tag);
|
||||||
if let Err(e) = e.remove_tag(tag) {
|
e.remove_tag(tag)
|
||||||
trace_error(&e);
|
}).collect::<Result<Vec<_>>>()?;
|
||||||
}
|
|
||||||
}
|
|
||||||
} // it is okay to ignore a None here
|
} // it is okay to ignore a None here
|
||||||
|
|
||||||
debug!("Entry header now = {:?}", e.get_header());
|
debug!("Entry header now = {:?}", e.get_header());
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
Ok(None) => {
|
None => {
|
||||||
info!("No entry found.");
|
info!("No entry found.");
|
||||||
},
|
},
|
||||||
|
|
||||||
Err(e) => {
|
|
||||||
info!("No entry.");
|
|
||||||
trace_error(&e);
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rt.report_touched(&path).unwrap_or_exit();
|
rt.report_touched(&path).map_err(Error::from)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn list(path: StoreId, rt: &Runtime) {
|
fn list(path: StoreId, rt: &Runtime) -> Result<()> {
|
||||||
let entry = match rt.store().get(path.clone()).map_err_trace_exit_unwrap() {
|
let entry = rt.store().get(path.clone())?.ok_or_else(|| err_msg("No entry found"))?;
|
||||||
Some(e) => e,
|
|
||||||
None => warn_exit("No entry found.", 1),
|
|
||||||
};
|
|
||||||
|
|
||||||
let scmd = rt.cli().subcommand_matches("list").unwrap(); // safe, we checked in main()
|
let scmd = rt.cli().subcommand_matches("list").unwrap(); // safe, we checked in main()
|
||||||
|
|
||||||
let json_out = scmd.is_present("json");
|
let json_out = scmd.is_present("json");
|
||||||
let line_out = scmd.is_present("linewise");
|
let line_out = scmd.is_present("linewise");
|
||||||
let sepp_out = scmd.is_present("sep");
|
let sepp_out = scmd.is_present("sep");
|
||||||
|
@ -204,7 +182,7 @@ fn list(path: StoreId, rt: &Runtime) {
|
||||||
comm_out = true;
|
comm_out = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
let tags = entry.get_tags().map_err_trace_exit_unwrap();
|
let tags = entry.get_tags()?;
|
||||||
|
|
||||||
if json_out {
|
if json_out {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
|
@ -212,53 +190,44 @@ fn list(path: StoreId, rt: &Runtime) {
|
||||||
|
|
||||||
if line_out {
|
if line_out {
|
||||||
for tag in &tags {
|
for tag in &tags {
|
||||||
writeln!(rt.stdout(), "{}", tag)
|
writeln!(rt.stdout(), "{}", tag)?;
|
||||||
.to_exit_code()
|
|
||||||
.unwrap_or_exit();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if sepp_out {
|
if sepp_out {
|
||||||
let sepp = scmd.value_of("sep").unwrap(); // we checked before
|
let sepp = scmd.value_of("sep").unwrap(); // we checked before
|
||||||
writeln!(rt.stdout(), "{}", tags.join(sepp))
|
writeln!(rt.stdout(), "{}", tags.join(sepp))?;
|
||||||
.to_exit_code()
|
|
||||||
.unwrap_or_exit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if comm_out {
|
if comm_out {
|
||||||
writeln!(rt.stdout(), "{}", tags.join(", "))
|
writeln!(rt.stdout(), "{}", tags.join(", "))?;
|
||||||
.to_exit_code()
|
|
||||||
.unwrap_or_exit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rt.report_touched(&path).unwrap_or_exit();
|
rt.report_touched(&path).map_err(Error::from)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the tags which should be added from the commandline
|
/// Get the tags which should be added from the commandline
|
||||||
///
|
///
|
||||||
/// Returns none if the argument was not specified
|
/// Returns none if the argument was not specified
|
||||||
fn get_add_tags(matches: &ArgMatches) -> Option<Vec<Tag>> {
|
fn get_add_tags(matches: &ArgMatches) -> Result<Option<Vec<Tag>>> {
|
||||||
retrieve_tags(matches, "add", "add-tags")
|
retrieve_tags(matches, "add", "add-tags")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the tags which should be removed from the commandline
|
/// Get the tags which should be removed from the commandline
|
||||||
///
|
///
|
||||||
/// Returns none if the argument was not specified
|
/// Returns none if the argument was not specified
|
||||||
fn get_remove_tags(matches: &ArgMatches) -> Option<Vec<Tag>> {
|
fn get_remove_tags(matches: &ArgMatches) -> Result<Option<Vec<Tag>>> {
|
||||||
retrieve_tags(matches, "remove", "remove-tags")
|
retrieve_tags(matches, "remove", "remove-tags")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn retrieve_tags(m: &ArgMatches, s: &'static str, v: &'static str) -> Option<Vec<Tag>> {
|
fn retrieve_tags(m: &ArgMatches, s: &'static str, v: &'static str) -> Result<Option<Vec<Tag>>> {
|
||||||
Some(m
|
Ok(Some(m
|
||||||
.subcommand_matches(s)
|
.subcommand_matches(s)
|
||||||
.unwrap_or_else(|| {
|
.ok_or_else(|| format_err!("Expected subcommand '{}', but was not specified", s))?
|
||||||
error!("Expected subcommand '{}', but was not specified", s);
|
|
||||||
::std::process::exit(1)
|
|
||||||
})
|
|
||||||
.values_of(v)
|
.values_of(v)
|
||||||
.unwrap() // enforced by clap
|
.unwrap() // enforced by clap
|
||||||
.map(String::from)
|
.map(String::from)
|
||||||
.collect())
|
.collect()))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -314,7 +283,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_tag_add_adds_tag() {
|
fn test_tag_add_adds_tag() -> Result<()> {
|
||||||
setup_logging();
|
setup_logging();
|
||||||
debug!("Generating runtime");
|
debug!("Generating runtime");
|
||||||
let name = "test-tag-add-adds-tags";
|
let name = "test-tag-add-adds-tags";
|
||||||
|
@ -325,11 +294,11 @@ mod tests {
|
||||||
let id = PathBuf::from(String::from(name));
|
let id = PathBuf::from(String::from(name));
|
||||||
|
|
||||||
debug!("Getting 'add' tags");
|
debug!("Getting 'add' tags");
|
||||||
let add = get_add_tags(rt.cli());
|
let add = get_add_tags(rt.cli())?;
|
||||||
debug!("Add-tags: {:?}", add);
|
debug!("Add-tags: {:?}", add);
|
||||||
|
|
||||||
debug!("Altering things");
|
debug!("Altering things");
|
||||||
alter(&rt, StoreId::new(id.clone()).unwrap(), add, None);
|
alter(&rt, StoreId::new(id.clone()).unwrap(), add, None)?;
|
||||||
debug!("Altered");
|
debug!("Altered");
|
||||||
|
|
||||||
let test_entry = rt.store().get(id).unwrap().unwrap();
|
let test_entry = rt.store().get(id).unwrap().unwrap();
|
||||||
|
@ -343,10 +312,11 @@ mod tests {
|
||||||
|
|
||||||
assert_ne!(*test_tags, tags_toml_value(vec![]));
|
assert_ne!(*test_tags, tags_toml_value(vec![]));
|
||||||
assert_eq!(*test_tags, tags_toml_value(vec!["foo"]));
|
assert_eq!(*test_tags, tags_toml_value(vec!["foo"]));
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_tag_remove_removes_tag() {
|
fn test_tag_remove_removes_tag() -> Result<()> {
|
||||||
setup_logging();
|
setup_logging();
|
||||||
debug!("Generating runtime");
|
debug!("Generating runtime");
|
||||||
let name = "test-tag-remove-removes-tag";
|
let name = "test-tag-remove-removes-tag";
|
||||||
|
@ -360,21 +330,22 @@ mod tests {
|
||||||
let add = Some(vec![ "foo".to_owned() ]);
|
let add = Some(vec![ "foo".to_owned() ]);
|
||||||
|
|
||||||
debug!("Getting 'remove' tags");
|
debug!("Getting 'remove' tags");
|
||||||
let rem = get_remove_tags(rt.cli());
|
let rem = get_remove_tags(rt.cli())?;
|
||||||
debug!("Rem-tags: {:?}", rem);
|
debug!("Rem-tags: {:?}", rem);
|
||||||
|
|
||||||
debug!("Altering things");
|
debug!("Altering things");
|
||||||
alter(&rt, StoreId::new(id.clone()).unwrap(), add, rem);
|
alter(&rt, StoreId::new(id.clone()).unwrap(), add, rem)?;
|
||||||
debug!("Altered");
|
debug!("Altered");
|
||||||
|
|
||||||
let test_entry = rt.store().get(id).unwrap().unwrap();
|
let test_entry = rt.store().get(id).unwrap().unwrap();
|
||||||
let test_tags = get_entry_tags(&test_entry).unwrap().unwrap();
|
let test_tags = get_entry_tags(&test_entry).unwrap().unwrap();
|
||||||
|
|
||||||
assert_eq!(*test_tags, tags_toml_value(vec![]));
|
assert_eq!(*test_tags, tags_toml_value(vec![]));
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_tag_remove_removes_only_to_remove_tag() {
|
fn test_tag_remove_removes_only_to_remove_tag() -> Result<()> {
|
||||||
setup_logging();
|
setup_logging();
|
||||||
debug!("Generating runtime");
|
debug!("Generating runtime");
|
||||||
let name = "test-tag-remove-removes-only-to-remove-tag-doesnt-crash-on-nonexistent-tag";
|
let name = "test-tag-remove-removes-only-to-remove-tag-doesnt-crash-on-nonexistent-tag";
|
||||||
|
@ -388,21 +359,22 @@ mod tests {
|
||||||
let add = Some(vec![ "foo".to_owned(), "bar".to_owned() ]);
|
let add = Some(vec![ "foo".to_owned(), "bar".to_owned() ]);
|
||||||
|
|
||||||
debug!("Getting 'remove' tags");
|
debug!("Getting 'remove' tags");
|
||||||
let rem = get_remove_tags(rt.cli());
|
let rem = get_remove_tags(rt.cli())?;
|
||||||
debug!("Rem-tags: {:?}", rem);
|
debug!("Rem-tags: {:?}", rem);
|
||||||
|
|
||||||
debug!("Altering things");
|
debug!("Altering things");
|
||||||
alter(&rt, StoreId::new(id.clone()).unwrap(), add, rem);
|
alter(&rt, StoreId::new(id.clone()).unwrap(), add, rem)?;
|
||||||
debug!("Altered");
|
debug!("Altered");
|
||||||
|
|
||||||
let test_entry = rt.store().get(id).unwrap().unwrap();
|
let test_entry = rt.store().get(id).unwrap().unwrap();
|
||||||
let test_tags = get_entry_tags(&test_entry).unwrap().unwrap();
|
let test_tags = get_entry_tags(&test_entry).unwrap().unwrap();
|
||||||
|
|
||||||
assert_eq!(*test_tags, tags_toml_value(vec!["bar"]));
|
assert_eq!(*test_tags, tags_toml_value(vec!["bar"]));
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_tag_remove_removes_but_doesnt_crash_on_nonexistent_tag() {
|
fn test_tag_remove_removes_but_doesnt_crash_on_nonexistent_tag() -> Result<()> {
|
||||||
setup_logging();
|
setup_logging();
|
||||||
debug!("Generating runtime");
|
debug!("Generating runtime");
|
||||||
let name = "test-tag-remove-removes-but-doesnt-crash-on-nonexistent-tag";
|
let name = "test-tag-remove-removes-but-doesnt-crash-on-nonexistent-tag";
|
||||||
|
@ -416,17 +388,18 @@ mod tests {
|
||||||
let add = Some(vec![ "foo".to_owned() ]);
|
let add = Some(vec![ "foo".to_owned() ]);
|
||||||
|
|
||||||
debug!("Getting 'remove' tags");
|
debug!("Getting 'remove' tags");
|
||||||
let rem = get_remove_tags(rt.cli());
|
let rem = get_remove_tags(rt.cli())?;
|
||||||
debug!("Rem-tags: {:?}", rem);
|
debug!("Rem-tags: {:?}", rem);
|
||||||
|
|
||||||
debug!("Altering things");
|
debug!("Altering things");
|
||||||
alter(&rt, StoreId::new(id.clone()).unwrap(), add, rem);
|
alter(&rt, StoreId::new(id.clone()).unwrap(), add, rem)?;
|
||||||
debug!("Altered");
|
debug!("Altered");
|
||||||
|
|
||||||
let test_entry = rt.store().get(id).unwrap().unwrap();
|
let test_entry = rt.store().get(id).unwrap().unwrap();
|
||||||
let test_tags = get_entry_tags(&test_entry).unwrap().unwrap();
|
let test_tags = get_entry_tags(&test_entry).unwrap().unwrap();
|
||||||
|
|
||||||
assert_eq!(*test_tags, tags_toml_value(vec![]));
|
assert_eq!(*test_tags, tags_toml_value(vec![]));
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@ toml-query = "0.9.2"
|
||||||
handlebars = "2"
|
handlebars = "2"
|
||||||
tempfile = "3.0.9"
|
tempfile = "3.0.9"
|
||||||
failure = "0.1.5"
|
failure = "0.1.5"
|
||||||
|
resiter = "0.3.0"
|
||||||
|
|
||||||
libimagstore = { version = "0.10.0", path = "../../../lib/core/libimagstore" }
|
libimagstore = { version = "0.10.0", path = "../../../lib/core/libimagstore" }
|
||||||
libimagrt = { version = "0.10.0", path = "../../../lib/core/libimagrt" }
|
libimagrt = { version = "0.10.0", path = "../../../lib/core/libimagrt" }
|
||||||
|
|
|
@ -40,7 +40,8 @@ extern crate handlebars;
|
||||||
extern crate tempfile;
|
extern crate tempfile;
|
||||||
extern crate toml;
|
extern crate toml;
|
||||||
extern crate toml_query;
|
extern crate toml_query;
|
||||||
extern crate failure;
|
#[macro_use] extern crate failure;
|
||||||
|
extern crate resiter;
|
||||||
|
|
||||||
extern crate libimagentryview;
|
extern crate libimagentryview;
|
||||||
extern crate libimagerror;
|
extern crate libimagerror;
|
||||||
|
@ -52,26 +53,23 @@ use std::str::FromStr;
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
use std::process::exit;
|
|
||||||
|
|
||||||
use handlebars::Handlebars;
|
use handlebars::Handlebars;
|
||||||
use toml_query::read::TomlValueReadTypeExt;
|
use toml_query::read::TomlValueReadTypeExt;
|
||||||
use failure::Error;
|
use failure::Error;
|
||||||
use failure::err_msg;
|
use failure::err_msg;
|
||||||
use failure::Fallible as Result;
|
use failure::Fallible as Result;
|
||||||
|
use resiter::AndThen;
|
||||||
use clap::App;
|
use clap::App;
|
||||||
|
|
||||||
use libimagrt::runtime::Runtime;
|
use libimagrt::runtime::Runtime;
|
||||||
use libimagrt::application::ImagApplication;
|
use libimagrt::application::ImagApplication;
|
||||||
use libimagerror::trace::MapErrTrace;
|
|
||||||
use libimagerror::iter::TraceIterator;
|
|
||||||
use libimagerror::io::ToExitCode;
|
|
||||||
use libimagerror::exit::ExitUnwrap;
|
|
||||||
use libimagentryview::builtin::stdout::StdoutViewer;
|
use libimagentryview::builtin::stdout::StdoutViewer;
|
||||||
use libimagentryview::builtin::md::MarkdownViewer;
|
use libimagentryview::builtin::md::MarkdownViewer;
|
||||||
use libimagentryview::viewer::Viewer;
|
use libimagentryview::viewer::Viewer;
|
||||||
use libimagstore::iter::get::StoreIdGetIteratorExtension;
|
use libimagstore::iter::get::StoreIdGetIteratorExtension;
|
||||||
use libimagstore::store::FileLockEntry;
|
use libimagstore::store::FileLockEntry;
|
||||||
|
use libimagerror::iter::IterInnerOkOrElse;
|
||||||
|
|
||||||
mod ui;
|
mod ui;
|
||||||
|
|
||||||
|
@ -85,61 +83,42 @@ impl ImagApplication for ImagView {
|
||||||
let view_header = rt.cli().is_present("view-header");
|
let view_header = rt.cli().is_present("view-header");
|
||||||
let hide_content = rt.cli().is_present("not-view-content");
|
let hide_content = rt.cli().is_present("not-view-content");
|
||||||
let entries = rt
|
let entries = rt
|
||||||
.ids::<::ui::PathProvider>()
|
.ids::<::ui::PathProvider>()?
|
||||||
.map_err_trace_exit_unwrap()
|
.ok_or_else(|| err_msg("No ids supplied"))?
|
||||||
.unwrap_or_else(|| {
|
|
||||||
error!("No ids supplied");
|
|
||||||
::std::process::exit(1);
|
|
||||||
})
|
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(Ok)
|
.map(Ok)
|
||||||
.into_get_iter(rt.store())
|
.into_get_iter(rt.store())
|
||||||
.trace_unwrap_exit()
|
.map_inner_ok_or_else(|| err_msg("Entry not found, please report this as a bug"));
|
||||||
.map(|e| {
|
|
||||||
e.ok_or_else(|| err_msg("Entry not found"))
|
|
||||||
.map_err(Error::from)
|
|
||||||
.map_err_trace_exit_unwrap()
|
|
||||||
});
|
|
||||||
|
|
||||||
if rt.cli().is_present("in") {
|
if rt.cli().is_present("in") {
|
||||||
let files = entries
|
let files = entries
|
||||||
.map(|entry| {
|
.and_then_ok(|entry| {
|
||||||
let tmpfile = create_tempfile_for(&entry, view_header, hide_content);
|
let tmpfile = create_tempfile_for(&entry, view_header, hide_content)?;
|
||||||
rt.report_touched(entry.get_location()).unwrap_or_exit();
|
rt.report_touched(entry.get_location())?;
|
||||||
tmpfile
|
Ok(tmpfile)
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Result<Vec<_>>>()?;
|
||||||
|
|
||||||
let mut command = {
|
let mut command = {
|
||||||
let viewer = rt
|
let viewer = rt
|
||||||
.cli()
|
.cli()
|
||||||
.value_of("in")
|
.value_of("in")
|
||||||
.ok_or_else(|| Error::from(err_msg("No viewer given")))
|
.ok_or_else(|| err_msg("No viewer given"))?;
|
||||||
.map_err_trace_exit_unwrap();
|
|
||||||
|
|
||||||
let config = rt
|
let config = rt
|
||||||
.config()
|
.config()
|
||||||
.ok_or_else(|| Error::from(err_msg("No configuration, cannot continue")))
|
.ok_or_else(|| err_msg("No configuration, cannot continue"))?;
|
||||||
.map_err_trace_exit_unwrap();
|
|
||||||
|
|
||||||
let query = format!("view.viewers.{}", viewer);
|
let query = format!("view.viewers.{}", viewer);
|
||||||
|
|
||||||
let viewer_template = config
|
let viewer_template = config
|
||||||
.read_string(&query)
|
.read_string(&query)?
|
||||||
.map_err(Error::from)
|
.ok_or_else(|| format_err!("Cannot find '{}' in config", query))?;
|
||||||
.map_err_trace_exit_unwrap()
|
|
||||||
.unwrap_or_else(|| {
|
|
||||||
error!("Cannot find '{}' in config", query);
|
|
||||||
exit(1)
|
|
||||||
});
|
|
||||||
|
|
||||||
let mut handlebars = Handlebars::new();
|
let mut handlebars = Handlebars::new();
|
||||||
handlebars.register_escape_fn(::handlebars::no_escape);
|
handlebars.register_escape_fn(::handlebars::no_escape);
|
||||||
|
|
||||||
let _ = handlebars
|
handlebars.register_template_string("template", viewer_template)?;
|
||||||
.register_template_string("template", viewer_template)
|
|
||||||
.map_err(Error::from)
|
|
||||||
.map_err_trace_exit_unwrap();
|
|
||||||
|
|
||||||
let mut data = BTreeMap::new();
|
let mut data = BTreeMap::new();
|
||||||
|
|
||||||
|
@ -151,15 +130,9 @@ impl ImagApplication for ImagView {
|
||||||
|
|
||||||
data.insert("entries", file_paths);
|
data.insert("entries", file_paths);
|
||||||
|
|
||||||
let call = handlebars
|
let call = handlebars .render("template", &data)?;
|
||||||
.render("template", &data)
|
|
||||||
.map_err(Error::from)
|
|
||||||
.map_err_trace_exit_unwrap();
|
|
||||||
let mut elems = call.split_whitespace();
|
let mut elems = call.split_whitespace();
|
||||||
let command_string = elems
|
let command_string = elems.next().ok_or_else(|| err_msg("No command"))?;
|
||||||
.next()
|
|
||||||
.ok_or_else(|| Error::from(err_msg("No command")))
|
|
||||||
.map_err_trace_exit_unwrap();
|
|
||||||
let mut cmd = Command::new(command_string);
|
let mut cmd = Command::new(command_string);
|
||||||
|
|
||||||
for arg in elems {
|
for arg in elems {
|
||||||
|
@ -172,15 +145,14 @@ impl ImagApplication for ImagView {
|
||||||
debug!("Calling: {:?}", command);
|
debug!("Calling: {:?}", command);
|
||||||
|
|
||||||
if !command
|
if !command
|
||||||
.status()
|
.status()?
|
||||||
.map_err(Error::from)
|
|
||||||
.map_err_trace_exit_unwrap()
|
|
||||||
.success()
|
.success()
|
||||||
{
|
{
|
||||||
exit(1)
|
return Err(err_msg("Failed to execute command"))
|
||||||
}
|
}
|
||||||
|
|
||||||
drop(files);
|
drop(files);
|
||||||
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
let out = rt.stdout();
|
let out = rt.stdout();
|
||||||
let mut outlock = out.lock();
|
let mut outlock = out.lock();
|
||||||
|
@ -202,32 +174,30 @@ impl ImagApplication for ImagView {
|
||||||
let viewer = MarkdownViewer::new(&rt);
|
let viewer = MarkdownViewer::new(&rt);
|
||||||
let seperator = basesep.map(|s| build_seperator(s, sep_width));
|
let seperator = basesep.map(|s| build_seperator(s, sep_width));
|
||||||
|
|
||||||
entries
|
let mut i = 0; // poor mans enumerate()
|
||||||
.enumerate()
|
|
||||||
.for_each(|(n, entry)| {
|
entries.and_then_ok(|entry| {
|
||||||
if n != 0 {
|
if i != 0 {
|
||||||
seperator
|
if let Some(s) = seperator.as_ref() {
|
||||||
.as_ref()
|
writeln!(outlock, "{}", s)?;
|
||||||
.map(|s| writeln!(outlock, "{}", s).to_exit_code().unwrap_or_exit());
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Err(e) = viewer.view_entry(&entry, &mut outlock) {
|
viewer.view_entry(&entry, &mut outlock)?;
|
||||||
handle_error(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
rt.report_touched(entry.get_location()).unwrap_or_exit();
|
i += 1;
|
||||||
});
|
rt.report_touched(entry.get_location()).map_err(Error::from)
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
} else {
|
} else {
|
||||||
let mut viewer = StdoutViewer::new(view_header, !hide_content);
|
let mut viewer = StdoutViewer::new(view_header, !hide_content);
|
||||||
|
|
||||||
if rt.cli().occurrences_of("autowrap") != 0 {
|
if rt.cli().occurrences_of("autowrap") != 0 {
|
||||||
let width = rt.cli().value_of("autowrap").unwrap(); // ensured by clap
|
let width = rt.cli().value_of("autowrap").unwrap(); // ensured by clap
|
||||||
let width = usize::from_str(width).unwrap_or_else(|e| {
|
let width = usize::from_str(width).map_err(|_| {
|
||||||
error!("Failed to parse argument to number: autowrap = {:?}",
|
format_err!("Failed to parse argument to number: autowrap = {:?}",
|
||||||
rt.cli().value_of("autowrap").map(String::from));
|
rt.cli().value_of("autowrap").map(String::from))
|
||||||
error!("-> {:?}", e);
|
})?;
|
||||||
::std::process::exit(1)
|
|
||||||
});
|
|
||||||
|
|
||||||
// Copying this value over, so that the seperator has the right len as well
|
// Copying this value over, so that the seperator has the right len as well
|
||||||
sep_width = width;
|
sep_width = width;
|
||||||
|
@ -236,25 +206,22 @@ impl ImagApplication for ImagView {
|
||||||
}
|
}
|
||||||
|
|
||||||
let seperator = basesep.map(|s| build_seperator(s, sep_width));
|
let seperator = basesep.map(|s| build_seperator(s, sep_width));
|
||||||
entries
|
let mut i = 0; // poor mans enumerate()
|
||||||
.enumerate()
|
entries.and_then_ok(|entry| {
|
||||||
.for_each(|(n, entry)| {
|
if i != 0 {
|
||||||
if n != 0 {
|
if let Some(s) = seperator.as_ref() {
|
||||||
seperator
|
writeln!(outlock, "{}", s)?;
|
||||||
.as_ref()
|
|
||||||
.map(|s| writeln!(outlock, "{}", s).to_exit_code().unwrap_or_exit());
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Err(e) = viewer.view_entry(&entry, &mut outlock) {
|
|
||||||
handle_error(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
rt.report_touched(entry.get_location()).unwrap_or_exit();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
viewer.view_entry(&entry, &mut outlock)?;
|
||||||
|
|
||||||
|
i += 1;
|
||||||
|
rt.report_touched(entry.get_location()).map_err(Error::from)
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_cli<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
|
fn build_cli<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
|
||||||
|
@ -275,41 +242,25 @@ impl ImagApplication for ImagView {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_tempfile_for<'a>(entry: &FileLockEntry<'a>, view_header: bool, hide_content: bool)
|
fn create_tempfile_for<'a>(entry: &FileLockEntry<'a>, view_header: bool, hide_content: bool)
|
||||||
-> (tempfile::NamedTempFile, String)
|
-> Result<(tempfile::NamedTempFile, String)>
|
||||||
{
|
{
|
||||||
let mut tmpfile = tempfile::NamedTempFile::new()
|
let mut tmpfile = tempfile::NamedTempFile::new()?;
|
||||||
.map_err(Error::from)
|
|
||||||
.map_err_trace_exit_unwrap();
|
|
||||||
|
|
||||||
if view_header {
|
if view_header {
|
||||||
let hdr = toml::ser::to_string_pretty(entry.get_header())
|
let hdr = toml::ser::to_string_pretty(entry.get_header())?;
|
||||||
.map_err(Error::from)
|
let _ = tmpfile.write(format!("---\n{}---\n", hdr).as_bytes())?;
|
||||||
.map_err_trace_exit_unwrap();
|
|
||||||
let _ = tmpfile.write(format!("---\n{}---\n", hdr).as_bytes())
|
|
||||||
.map_err(Error::from)
|
|
||||||
.map_err_trace_exit_unwrap();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if !hide_content {
|
if !hide_content {
|
||||||
let _ = tmpfile.write(entry.get_content().as_bytes())
|
let _ = tmpfile.write(entry.get_content().as_bytes())?;
|
||||||
.map_err(Error::from)
|
|
||||||
.map_err_trace_exit_unwrap();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let file_path = tmpfile
|
let file_path = tmpfile
|
||||||
.path()
|
.path()
|
||||||
.to_str()
|
.to_str()
|
||||||
.map(String::from)
|
.map(String::from)
|
||||||
.ok_or_else(|| Error::from(err_msg("Cannot build path")))
|
.ok_or_else(|| Error::from(err_msg("Cannot build path")))?;
|
||||||
.map_err_trace_exit_unwrap();
|
|
||||||
|
|
||||||
(tmpfile, file_path)
|
Ok((tmpfile, file_path))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_error(e: ::libimagentryview::error::Error) {
|
|
||||||
use libimagentryview::error::Error;
|
|
||||||
match e {
|
|
||||||
Error::Io(e) => Err(e).to_exit_code().unwrap_or_exit(),
|
|
||||||
Error::Other(e) => Err(e).map_err_trace_exit_unwrap()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -20,7 +20,6 @@ libimagerror = { version = "0.10.0", path = "../../../lib/core/libimagerror"
|
||||||
libimagstore = { version = "0.10.0", path = "../../../lib/core/libimagstore" }
|
libimagstore = { version = "0.10.0", path = "../../../lib/core/libimagstore" }
|
||||||
libimagentrytag = { version = "0.10.0", path = "../../../lib/entry/libimagentrytag" }
|
libimagentrytag = { version = "0.10.0", path = "../../../lib/entry/libimagentrytag" }
|
||||||
libimagutil = { version = "0.10.0", path = "../../../lib/etc/libimagutil" }
|
libimagutil = { version = "0.10.0", path = "../../../lib/etc/libimagutil" }
|
||||||
failure = "0.1.5"
|
|
||||||
log = "0.4.6"
|
log = "0.4.6"
|
||||||
|
|
||||||
# Build time dependencies for cli completion
|
# Build time dependencies for cli completion
|
||||||
|
@ -61,6 +60,7 @@ walkdir = "2.2.8"
|
||||||
log = "0.4.6"
|
log = "0.4.6"
|
||||||
toml = "0.5.1"
|
toml = "0.5.1"
|
||||||
toml-query = "0.9.2"
|
toml-query = "0.9.2"
|
||||||
|
failure = "0.1.5"
|
||||||
|
|
||||||
libimagerror = { version = "0.10.0", path = "../../../lib/core/libimagerror" }
|
libimagerror = { version = "0.10.0", path = "../../../lib/core/libimagerror" }
|
||||||
libimagstore = { version = "0.10.0", path = "../../../lib/core/libimagstore" }
|
libimagstore = { version = "0.10.0", path = "../../../lib/core/libimagstore" }
|
||||||
|
|
|
@ -36,6 +36,7 @@
|
||||||
|
|
||||||
extern crate clap;
|
extern crate clap;
|
||||||
#[macro_use] extern crate log;
|
#[macro_use] extern crate log;
|
||||||
|
#[macro_use] extern crate failure;
|
||||||
extern crate walkdir;
|
extern crate walkdir;
|
||||||
extern crate toml;
|
extern crate toml;
|
||||||
extern crate toml_query;
|
extern crate toml_query;
|
||||||
|
@ -44,11 +45,10 @@ extern crate toml_query;
|
||||||
extern crate libimagerror;
|
extern crate libimagerror;
|
||||||
|
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::process::exit;
|
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
use std::process::Stdio;
|
use std::process::Stdio;
|
||||||
use std::io::ErrorKind;
|
use std::io::ErrorKind;
|
||||||
use std::io::{stdout, Stdout, Write};
|
use std::io::{stdout, Write};
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
@ -56,12 +56,13 @@ use walkdir::WalkDir;
|
||||||
use clap::{Arg, ArgMatches, AppSettings, SubCommand};
|
use clap::{Arg, ArgMatches, AppSettings, SubCommand};
|
||||||
use toml::Value;
|
use toml::Value;
|
||||||
use toml_query::read::TomlValueReadExt;
|
use toml_query::read::TomlValueReadExt;
|
||||||
|
use failure::Error;
|
||||||
|
use failure::ResultExt;
|
||||||
|
use failure::err_msg;
|
||||||
|
use failure::Fallible as Result;
|
||||||
|
|
||||||
use libimagrt::runtime::Runtime;
|
use libimagrt::runtime::Runtime;
|
||||||
use libimagrt::spec::CliSpec;
|
use libimagrt::spec::CliSpec;
|
||||||
use libimagerror::io::ToExitCode;
|
|
||||||
use libimagerror::exit::ExitUnwrap;
|
|
||||||
use libimagerror::trace::trace_error;
|
|
||||||
use libimagrt::configuration::InternalConfiguration;
|
use libimagrt::configuration::InternalConfiguration;
|
||||||
|
|
||||||
/// Returns the helptext, putting the Strings in cmds as possible
|
/// Returns the helptext, putting the Strings in cmds as possible
|
||||||
|
@ -107,16 +108,8 @@ fn help_text(cmds: Vec<String>) -> String {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the list of imag-* executables found in $PATH
|
/// Returns the list of imag-* executables found in $PATH
|
||||||
fn get_commands(out: &mut Stdout) -> Vec<String> {
|
fn get_commands() -> Result<Vec<String>> {
|
||||||
let mut v = match env::var("PATH") {
|
let mut v = env::var("PATH")?
|
||||||
Err(e) => {
|
|
||||||
writeln!(out, "PATH error: {:?}", e)
|
|
||||||
.to_exit_code()
|
|
||||||
.unwrap_or_exit();
|
|
||||||
exit(1)
|
|
||||||
},
|
|
||||||
|
|
||||||
Ok(path) => path
|
|
||||||
.split(':')
|
.split(':')
|
||||||
.flat_map(|elem| {
|
.flat_map(|elem| {
|
||||||
WalkDir::new(elem)
|
WalkDir::new(elem)
|
||||||
|
@ -126,7 +119,7 @@ fn get_commands(out: &mut Stdout) -> Vec<String> {
|
||||||
Ok(ref p) => p.file_name().to_str().map_or(false, |f| f.starts_with("imag-")),
|
Ok(ref p) => p.file_name().to_str().map_or(false, |f| f.starts_with("imag-")),
|
||||||
Err(_) => false,
|
Err(_) => false,
|
||||||
})
|
})
|
||||||
.filter_map(Result::ok)
|
.filter_map(|r| r.ok())
|
||||||
.filter_map(|path| path
|
.filter_map(|path| path
|
||||||
.file_name()
|
.file_name()
|
||||||
.to_str()
|
.to_str()
|
||||||
|
@ -140,21 +133,19 @@ fn get_commands(out: &mut Stdout) -> Vec<String> {
|
||||||
} else {
|
} else {
|
||||||
true
|
true
|
||||||
})
|
})
|
||||||
.collect::<Vec<String>>()
|
.collect::<Vec<String>>();
|
||||||
};
|
|
||||||
|
|
||||||
v.sort();
|
v.sort();
|
||||||
v
|
Ok(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn main() {
|
fn main() -> Result<()> {
|
||||||
// Initialize the Runtime and build the CLI
|
// Initialize the Runtime and build the CLI
|
||||||
let appname = "imag";
|
let appname = "imag";
|
||||||
let version = make_imag_version!();
|
let version = make_imag_version!();
|
||||||
let about = "imag - the PIM suite for the commandline";
|
let about = "imag - the PIM suite for the commandline";
|
||||||
let mut out = stdout();
|
let commands = get_commands()?;
|
||||||
let commands = get_commands(&mut out);
|
|
||||||
let helptext = help_text(commands.clone());
|
let helptext = help_text(commands.clone());
|
||||||
let mut app = Runtime::get_default_cli_builder(appname, &version, about)
|
let mut app = Runtime::get_default_cli_builder(appname, &version, about)
|
||||||
.settings(&[AppSettings::AllowExternalSubcommands, AppSettings::ArgRequiredElseHelp])
|
.settings(&[AppSettings::AllowExternalSubcommands, AppSettings::ArgRequiredElseHelp])
|
||||||
|
@ -175,39 +166,24 @@ fn main() {
|
||||||
|
|
||||||
let long_help = {
|
let long_help = {
|
||||||
let mut v = vec![];
|
let mut v = vec![];
|
||||||
if let Err(e) = app.write_long_help(&mut v) {
|
app.write_long_help(&mut v)?;
|
||||||
eprintln!("Error: {:?}", e);
|
String::from_utf8(v).map_err(|_| err_msg("UTF8 Error"))?
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
String::from_utf8(v).unwrap_or_else(|_| { eprintln!("UTF8 Error"); exit(1) })
|
|
||||||
};
|
};
|
||||||
{
|
|
||||||
let print_help = app.clone().get_matches().subcommand_name().map(|h| h == "help").unwrap_or(false);
|
let print_help = app.clone().get_matches().subcommand_name().map(|h| h == "help").unwrap_or(false);
|
||||||
if print_help {
|
|
||||||
writeln!(out, "{}", long_help)
|
|
||||||
.to_exit_code()
|
|
||||||
.unwrap_or_exit();
|
|
||||||
exit(0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
let mut out = stdout();
|
||||||
|
if print_help {
|
||||||
|
writeln!(out, "{}", long_help).map_err(Error::from)
|
||||||
|
} else {
|
||||||
let enable_logging = app.enable_logging();
|
let enable_logging = app.enable_logging();
|
||||||
let matches = app.matches();
|
let matches = app.matches();
|
||||||
|
|
||||||
let rtp = ::libimagrt::runtime::get_rtp_match(&matches)
|
let rtp = ::libimagrt::runtime::get_rtp_match(&matches)?;
|
||||||
.unwrap_or_else(|e| {
|
|
||||||
trace_error(&e);
|
|
||||||
exit(1)
|
|
||||||
});
|
|
||||||
let configpath = matches
|
let configpath = matches
|
||||||
.value_of("config")
|
.value_of("config")
|
||||||
.map_or_else(|| rtp.clone(), PathBuf::from);
|
.map_or_else(|| rtp.clone(), PathBuf::from);
|
||||||
debug!("Config path = {:?}", configpath);
|
debug!("Config path = {:?}", configpath);
|
||||||
let config = ::libimagrt::configuration::fetch_config(&configpath)
|
let config = ::libimagrt::configuration::fetch_config(&configpath)?;
|
||||||
.unwrap_or_else(|e| {
|
|
||||||
trace_error(&e);
|
|
||||||
exit(1)
|
|
||||||
});
|
|
||||||
|
|
||||||
if enable_logging {
|
if enable_logging {
|
||||||
Runtime::init_logger(&matches, config.as_ref())
|
Runtime::init_logger(&matches, config.as_ref())
|
||||||
|
@ -219,12 +195,8 @@ fn main() {
|
||||||
|
|
||||||
if matches.is_present("version") {
|
if matches.is_present("version") {
|
||||||
debug!("Showing version");
|
debug!("Showing version");
|
||||||
writeln!(out, "imag {}", env!("CARGO_PKG_VERSION"))
|
writeln!(out, "imag {}", env!("CARGO_PKG_VERSION")).map_err(Error::from)
|
||||||
.to_exit_code()
|
} else {
|
||||||
.unwrap_or_exit();
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if matches.is_present("versions") {
|
if matches.is_present("versions") {
|
||||||
debug!("Showing versions");
|
debug!("Showing versions");
|
||||||
commands
|
commands
|
||||||
|
@ -245,29 +217,14 @@ fn main() {
|
||||||
Err(e) => format!("Failed calling imag-{} -> {:?}", command, e),
|
Err(e) => format!("Failed calling imag-{} -> {:?}", command, e),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.fold((), |_, line| {
|
.fold(Ok(()), |_, line| {
|
||||||
// The amount of newlines may differ depending on the subprocess
|
// The amount of newlines may differ depending on the subprocess
|
||||||
writeln!(out, "{}", line.trim())
|
writeln!(out, "{}", line.trim()).map_err(Error::from)
|
||||||
.to_exit_code()
|
})
|
||||||
.unwrap_or_exit();
|
} else {
|
||||||
});
|
let aliases = fetch_aliases(config.as_ref())
|
||||||
|
.map_err(Error::from)
|
||||||
exit(0);
|
.context("Error while fetching aliases from configuration file")?;
|
||||||
}
|
|
||||||
|
|
||||||
let aliases = match fetch_aliases(config.as_ref()) {
|
|
||||||
Ok(aliases) => aliases,
|
|
||||||
Err(e) => {
|
|
||||||
writeln!(out, "Error while fetching aliases from configuration file")
|
|
||||||
.to_exit_code()
|
|
||||||
.unwrap_or_exit();
|
|
||||||
debug!("Error = {:?}", e);
|
|
||||||
writeln!(out, "Aborting")
|
|
||||||
.to_exit_code()
|
|
||||||
.unwrap_or_exit();
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Matches any subcommand given, except calling for example 'imag --versions', as this option
|
// Matches any subcommand given, except calling for example 'imag --versions', as this option
|
||||||
// does not exit. There's nothing to do in such a case
|
// does not exit. There's nothing to do in such a case
|
||||||
|
@ -297,52 +254,43 @@ fn main() {
|
||||||
.spawn()
|
.spawn()
|
||||||
.and_then(|mut c| c.wait())
|
.and_then(|mut c| c.wait())
|
||||||
{
|
{
|
||||||
Ok(exit_status) => {
|
Ok(exit_status) => if !exit_status.success() {
|
||||||
if !exit_status.success() {
|
|
||||||
debug!("imag-{} exited with non-zero exit code: {:?}", subcommand, exit_status);
|
debug!("imag-{} exited with non-zero exit code: {:?}", subcommand, exit_status);
|
||||||
eprintln!("imag-{} exited with non-zero exit code", subcommand);
|
Err(format_err!("imag-{} exited with non-zero exit code", subcommand))
|
||||||
exit(exit_status.code().unwrap_or(1));
|
} else {
|
||||||
}
|
|
||||||
debug!("Successful exit!");
|
debug!("Successful exit!");
|
||||||
|
Ok(())
|
||||||
},
|
},
|
||||||
|
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
debug!("Error calling the subcommand");
|
debug!("Error calling the subcommand");
|
||||||
match e.kind() {
|
match e.kind() {
|
||||||
ErrorKind::NotFound => {
|
ErrorKind::NotFound => {
|
||||||
writeln!(out, "No such command: 'imag-{}'", subcommand)
|
writeln!(out, "No such command: 'imag-{}'", subcommand)?;
|
||||||
.to_exit_code()
|
writeln!(out, "See 'imag --help' for available subcommands").map_err(Error::from)
|
||||||
.unwrap_or_exit();
|
|
||||||
writeln!(out, "See 'imag --help' for available subcommands")
|
|
||||||
.to_exit_code()
|
|
||||||
.unwrap_or_exit();
|
|
||||||
exit(1);
|
|
||||||
},
|
},
|
||||||
ErrorKind::PermissionDenied => {
|
ErrorKind::PermissionDenied => {
|
||||||
writeln!(out, "No permission to execute: 'imag-{}'", subcommand)
|
writeln!(out, "No permission to execute: 'imag-{}'", subcommand).map_err(Error::from)
|
||||||
.to_exit_code()
|
|
||||||
.unwrap_or_exit();
|
|
||||||
exit(1);
|
|
||||||
},
|
},
|
||||||
_ => {
|
_ => writeln!(out, "Error spawning: {:?}", e).map_err(Error::from),
|
||||||
writeln!(out, "Error spawning: {:?}", e)
|
|
||||||
.to_exit_code()
|
|
||||||
.unwrap_or_exit();
|
|
||||||
exit(1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fetch_aliases(config: Option<&Value>) -> Result<BTreeMap<String, String>, String> {
|
fn fetch_aliases(config: Option<&Value>) -> Result<BTreeMap<String, String>> {
|
||||||
let cfg = config.ok_or_else(|| String::from("No configuration found"))?;
|
let cfg = config.ok_or_else(|| err_msg("No configuration found"))?;
|
||||||
let value = cfg
|
let value = cfg
|
||||||
.read("imag.aliases")
|
.read("imag.aliases")
|
||||||
.map_err(|_| String::from("Reading from config failed"));
|
.map_err(|_| err_msg("Reading from config failed"))?;
|
||||||
|
|
||||||
match value? {
|
match value {
|
||||||
None => Ok(BTreeMap::new()),
|
None => Ok(BTreeMap::new()),
|
||||||
Some(&Value::Table(ref tbl)) => {
|
Some(&Value::Table(ref tbl)) => {
|
||||||
let mut alias_mappings = BTreeMap::new();
|
let mut alias_mappings = BTreeMap::new();
|
||||||
|
@ -359,7 +307,7 @@ fn fetch_aliases(config: Option<&Value>) -> Result<BTreeMap<String, String>, Str
|
||||||
alias_mappings.insert(s.clone(), k.clone());
|
alias_mappings.insert(s.clone(), k.clone());
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
let e = format!("Not all values are a String in 'imag.aliases.{}'", k);
|
let e = format_err!("Not all values are a String in 'imag.aliases.{}'", k);
|
||||||
return Err(e);
|
return Err(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -367,7 +315,7 @@ fn fetch_aliases(config: Option<&Value>) -> Result<BTreeMap<String, String>, Str
|
||||||
},
|
},
|
||||||
|
|
||||||
_ => {
|
_ => {
|
||||||
let msg = format!("Type Error: 'imag.aliases.{}' is not a table or string", k);
|
let msg = format_err!("Type Error: 'imag.aliases.{}' is not a table or string", k);
|
||||||
return Err(msg);
|
return Err(msg);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -376,7 +324,7 @@ fn fetch_aliases(config: Option<&Value>) -> Result<BTreeMap<String, String>, Str
|
||||||
Ok(alias_mappings)
|
Ok(alias_mappings)
|
||||||
},
|
},
|
||||||
|
|
||||||
Some(_) => Err(String::from("Type Error: 'imag.aliases' is not a table")),
|
Some(_) => Err(err_msg("Type Error: 'imag.aliases' is not a table")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,10 @@
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
//
|
//
|
||||||
|
|
||||||
|
use std::error::Error;
|
||||||
|
use std::fmt::{Formatter, Display};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct ExitCode(i32);
|
pub struct ExitCode(i32);
|
||||||
|
|
||||||
impl From<i32> for ExitCode {
|
impl From<i32> for ExitCode {
|
||||||
|
@ -31,6 +35,26 @@ impl ExitCode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Display for ExitCode {
|
||||||
|
fn fmt(&self, f: &mut Formatter) -> Result<(), std::fmt::Error> {
|
||||||
|
write!(f, "ExitCode {}", self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Error for ExitCode {
|
||||||
|
fn description(&self) -> &str {
|
||||||
|
"ExitCode"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cause(&self) -> Option<&dyn Error> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn source(&self) -> Option<&(dyn Error + 'static)> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub trait ExitUnwrap<T> {
|
pub trait ExitUnwrap<T> {
|
||||||
fn unwrap_or_exit(self) -> T;
|
fn unwrap_or_exit(self) -> T;
|
||||||
}
|
}
|
||||||
|
|
|
@ -128,3 +128,49 @@ impl<I, T> TraceIterator<T> for I where
|
||||||
I: Iterator<Item = Result<T, Error>>
|
I: Iterator<Item = Result<T, Error>>
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
|
||||||
|
/// Extension trait for doing
|
||||||
|
///
|
||||||
|
/// ```ignore
|
||||||
|
/// Iterator<Item = Result<Option<T>, E>> -> Iterator<Item = Result<T, E>>
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
pub trait IterInnerOkOrElse<T, E, F>
|
||||||
|
where T: Sized,
|
||||||
|
E: Sized,
|
||||||
|
Self: Iterator<Item = Result<Option<T>, E>> + Sized,
|
||||||
|
F: Fn() -> E,
|
||||||
|
{
|
||||||
|
fn map_inner_ok_or_else(self, f: F) -> IterInnerOkOrElseImpl<Self, T, E, F>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct IterInnerOkOrElseImpl<I, T, E, F>(I, F)
|
||||||
|
where I: Iterator<Item = Result<Option<T>, E>> + Sized,
|
||||||
|
T: Sized,
|
||||||
|
E: Sized,
|
||||||
|
F: Fn() -> E;
|
||||||
|
|
||||||
|
impl<I, T, E, F> IterInnerOkOrElse<T, E, F> for I
|
||||||
|
where I: Iterator<Item = Result<Option<T>, E>> + Sized,
|
||||||
|
T: Sized,
|
||||||
|
E: Sized,
|
||||||
|
F: Fn() -> E,
|
||||||
|
{
|
||||||
|
fn map_inner_ok_or_else(self, f: F) -> IterInnerOkOrElseImpl<I, T, E, F> {
|
||||||
|
IterInnerOkOrElseImpl(self, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I, T, E, F> Iterator for IterInnerOkOrElseImpl<I, T, E, F>
|
||||||
|
where I: Iterator<Item = Result<Option<T>, E>> + Sized,
|
||||||
|
T: Sized,
|
||||||
|
E: Sized,
|
||||||
|
F: Fn() -> E,
|
||||||
|
{
|
||||||
|
type Item = Result<T, E>;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
self.0.next().map(|e| e.and_then(|opt| opt.ok_or_else(|| (self.1)())))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -44,6 +44,7 @@ pub mod errors;
|
||||||
pub mod exit;
|
pub mod exit;
|
||||||
pub mod io;
|
pub mod io;
|
||||||
pub mod iter;
|
pub mod iter;
|
||||||
|
pub mod result;
|
||||||
pub mod str;
|
pub mod str;
|
||||||
pub mod trace;
|
pub mod trace;
|
||||||
|
|
||||||
|
|
38
lib/core/libimagerror/src/result.rs
Normal file
38
lib/core/libimagerror/src/result.rs
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
//
|
||||||
|
// imag - the personal information management suite for the commandline
|
||||||
|
// Copyright (C) 2015-2019 the imag contributors
|
||||||
|
//
|
||||||
|
// This library is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU Lesser General Public
|
||||||
|
// License as published by the Free Software Foundation; version
|
||||||
|
// 2.1 of the License.
|
||||||
|
//
|
||||||
|
// This library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public
|
||||||
|
// License along with this library; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
//
|
||||||
|
|
||||||
|
/// Extension trait for doing `Result<Option<T>, E> -> Result<T, E>`
|
||||||
|
pub trait ResultOptionExt<T, E, F>
|
||||||
|
where T: Sized,
|
||||||
|
E: Sized,
|
||||||
|
F: FnOnce() -> E
|
||||||
|
{
|
||||||
|
fn inner_ok_or_else(self, f: F) -> Result<T, E>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, E, F> ResultOptionExt<T, E, F> for Result<Option<T>, E>
|
||||||
|
where T: Sized,
|
||||||
|
E: Sized,
|
||||||
|
F: FnOnce() -> E
|
||||||
|
{
|
||||||
|
fn inner_ok_or_else(self, f: F) -> Result<T, E> {
|
||||||
|
self.and_then(|opt| opt.ok_or_else(f))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue