Merge branch 'runtime-io-story'
This merge introduces the new runtime IO system, finally! Now, piping imag commands into eachother as well as using standard unix tools for piping is possible! Awesome! Signed-off-by: Matthias Beyer <mail@beyermatthias.de>
This commit is contained in:
commit
ecf4cead93
54 changed files with 1229 additions and 572 deletions
|
@ -45,10 +45,8 @@ extern crate libimagstore;
|
|||
extern crate libimagutil;
|
||||
|
||||
use std::io::Write;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use failure::Error;
|
||||
use failure::err_msg;
|
||||
|
||||
use libimagentryannotation::annotateable::*;
|
||||
use libimagentryannotation::annotation_fetcher::*;
|
||||
|
@ -56,10 +54,10 @@ use libimagentryedit::edit::*;
|
|||
use libimagerror::trace::MapErrTrace;
|
||||
use libimagerror::exit::ExitUnwrap;
|
||||
use libimagerror::io::ToExitCode;
|
||||
use libimagerror::errors::ErrorMsg as EM;
|
||||
use libimagrt::runtime::Runtime;
|
||||
use libimagrt::setup::generate_runtime_setup;
|
||||
use libimagstore::store::FileLockEntry;
|
||||
use libimagstore::storeid::IntoStoreId;
|
||||
|
||||
mod ui;
|
||||
|
||||
|
@ -91,89 +89,96 @@ fn main() {
|
|||
fn add(rt: &Runtime) {
|
||||
let scmd = rt.cli().subcommand_matches("add").unwrap(); // safed by main()
|
||||
let annotation_name = scmd.value_of("annotation_name").unwrap(); // safed by clap
|
||||
let entry_name = scmd
|
||||
.value_of("entry")
|
||||
.map(PathBuf::from)
|
||||
.map(|pb| pb.into_storeid().map_err_trace_exit_unwrap(1))
|
||||
.unwrap(); // safed by clap
|
||||
let ids = rt.ids::<::ui::PathProvider>().map_err_trace_exit_unwrap(1);
|
||||
|
||||
ids.into_iter().for_each(|id| {
|
||||
let _ = rt.store()
|
||||
.get(id.clone())
|
||||
.map_err_trace_exit_unwrap(1)
|
||||
.ok_or_else(|| EM::EntryNotFound(id.local_display_string()))
|
||||
.map_err(Error::from)
|
||||
.map_err_trace_exit_unwrap(1)
|
||||
.annotate(rt.store(), annotation_name)
|
||||
.map_err_trace_exit_unwrap(1)
|
||||
.edit_content(&rt)
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
})
|
||||
|
||||
let _ = rt.store()
|
||||
.get(entry_name)
|
||||
.map_err_trace_exit_unwrap(1)
|
||||
.ok_or_else(|| Error::from(err_msg("Entry does not exist".to_owned())))
|
||||
.map_err_trace_exit_unwrap(1)
|
||||
.annotate(rt.store(), annotation_name)
|
||||
.map_err_trace_exit_unwrap(1)
|
||||
.edit_content(&rt)
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
}
|
||||
|
||||
fn remove(rt: &Runtime) {
|
||||
let scmd = rt.cli().subcommand_matches("remove").unwrap(); // safed by main()
|
||||
let entry_name = scmd.value_of("entry").unwrap(); // safed by clap
|
||||
let annotation_name = scmd.value_of("annotation_name").unwrap(); // safed by clap
|
||||
let delete = scmd.is_present("delete-annotation");
|
||||
let ids = rt.ids::<::ui::PathProvider>().map_err_trace_exit_unwrap(1);
|
||||
|
||||
let mut entry = rt.store()
|
||||
.get(PathBuf::from(entry_name).into_storeid().map_err_trace_exit_unwrap(1))
|
||||
.map_err_trace_exit_unwrap(1)
|
||||
.ok_or_else(|| Error::from(err_msg("Entry does not exist".to_owned())))
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
ids.into_iter().for_each(|id| {
|
||||
let mut entry = rt.store()
|
||||
.get(id.clone())
|
||||
.map_err_trace_exit_unwrap(1)
|
||||
.ok_or_else(|| EM::EntryNotFound(id.local_display_string()))
|
||||
.map_err(Error::from)
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
|
||||
let annotation = entry
|
||||
.denotate(rt.store(), annotation_name)
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
let annotation = entry
|
||||
.denotate(rt.store(), annotation_name)
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
|
||||
if delete {
|
||||
debug!("Deleting annotation object");
|
||||
if let Some(an) = annotation {
|
||||
let loc = an.get_location().clone();
|
||||
drop(an);
|
||||
if delete {
|
||||
debug!("Deleting annotation object");
|
||||
if let Some(an) = annotation {
|
||||
let loc = an.get_location().clone();
|
||||
drop(an);
|
||||
|
||||
let _ = rt
|
||||
.store()
|
||||
.delete(loc)
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
let _ = rt
|
||||
.store()
|
||||
.delete(loc)
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
} else {
|
||||
warn!("Not having annotation object, cannot delete!");
|
||||
}
|
||||
} else {
|
||||
warn!("Not having annotation object, cannot delete!");
|
||||
debug!("Not deleting annotation object");
|
||||
}
|
||||
} else {
|
||||
debug!("Not deleting annotation object");
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
fn list(rt: &Runtime) {
|
||||
let scmd = rt.cli().subcommand_matches("list").unwrap(); // safed by clap
|
||||
let with_text = scmd.is_present("list-with-text");
|
||||
match scmd.value_of("entry").map(PathBuf::from) {
|
||||
Some(pb) => {
|
||||
let _ = rt
|
||||
.store()
|
||||
.get(pb.into_storeid().map_err_trace_exit_unwrap(1))
|
||||
.map_err_trace_exit_unwrap(1)
|
||||
.ok_or_else(|| Error::from(err_msg("Entry does not exist")))
|
||||
.map_err_trace_exit_unwrap(1)
|
||||
.annotations(rt.store())
|
||||
.map_err_trace_exit_unwrap(1)
|
||||
.enumerate()
|
||||
.map(|(i, a)| {
|
||||
list_annotation(&rt, i, a.map_err_trace_exit_unwrap(1), with_text)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
}
|
||||
let scmd = rt.cli().subcommand_matches("list").unwrap(); // safed by clap
|
||||
let with_text = scmd.is_present("list-with-text");
|
||||
let ids = rt.ids::<::ui::PathProvider>().map_err_trace_exit_unwrap(1);
|
||||
|
||||
None => {
|
||||
// show them all
|
||||
let _ = rt
|
||||
.store()
|
||||
.all_annotations()
|
||||
.map_err_trace_exit_unwrap(1)
|
||||
.enumerate()
|
||||
.map(|(i, a)| {
|
||||
list_annotation(&rt, i, a.map_err_trace_exit_unwrap(1), with_text)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
}
|
||||
if ids.len() != 0 {
|
||||
let _ = ids
|
||||
.into_iter()
|
||||
.for_each(|id| {
|
||||
let _ = rt
|
||||
.store()
|
||||
.get(id.clone())
|
||||
.map_err_trace_exit_unwrap(1)
|
||||
.ok_or_else(|| EM::EntryNotFound(id.local_display_string()))
|
||||
.map_err(Error::from)
|
||||
.map_err_trace_exit_unwrap(1)
|
||||
.annotations(rt.store())
|
||||
.map_err_trace_exit_unwrap(1)
|
||||
.enumerate()
|
||||
.map(|(i, a)| {
|
||||
list_annotation(&rt, i, a.map_err_trace_exit_unwrap(1), with_text)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
});
|
||||
} else { // ids.len() == 0
|
||||
// show them all
|
||||
let _ = rt
|
||||
.store()
|
||||
.all_annotations()
|
||||
.map_err_trace_exit_unwrap(1)
|
||||
.enumerate()
|
||||
.map(|(i, a)| {
|
||||
list_annotation(&rt, i, a.map_err_trace_exit_unwrap(1), with_text)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -17,7 +17,14 @@
|
|||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
//
|
||||
|
||||
use clap::{Arg, App, SubCommand};
|
||||
use std::path::PathBuf;
|
||||
|
||||
use clap::{Arg, ArgMatches, App, SubCommand};
|
||||
|
||||
use libimagstore::storeid::StoreId;
|
||||
use libimagstore::storeid::IntoStoreId;
|
||||
use libimagrt::runtime::IdPathProvider;
|
||||
use libimagerror::trace::MapErrTrace;
|
||||
|
||||
pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
|
||||
app
|
||||
|
@ -86,3 +93,56 @@ pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
|
|||
)
|
||||
}
|
||||
|
||||
pub struct PathProvider;
|
||||
impl IdPathProvider for PathProvider {
|
||||
fn get_ids(matches: &ArgMatches) -> Vec<StoreId> {
|
||||
match matches.subcommand() {
|
||||
("add", Some(subm)) => {
|
||||
subm.values_of("entry")
|
||||
.ok_or_else(|| {
|
||||
error!("No StoreId found");
|
||||
::std::process::exit(1)
|
||||
})
|
||||
.unwrap()
|
||||
.into_iter()
|
||||
.map(PathBuf::from)
|
||||
.map(|pb| pb.into_storeid())
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
.map_err_trace_exit_unwrap(1)
|
||||
},
|
||||
|
||||
("remove", Some(subm)) => {
|
||||
subm.values_of("entry")
|
||||
.ok_or_else(|| {
|
||||
error!("No StoreId found");
|
||||
::std::process::exit(1)
|
||||
})
|
||||
.unwrap()
|
||||
.into_iter()
|
||||
.map(PathBuf::from)
|
||||
.map(|pb| pb.into_storeid())
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
.map_err_trace_exit_unwrap(1)
|
||||
},
|
||||
|
||||
("list", Some(subm)) => {
|
||||
subm.values_of("entry")
|
||||
.ok_or_else(|| {
|
||||
error!("No StoreId found");
|
||||
::std::process::exit(1)
|
||||
})
|
||||
.unwrap()
|
||||
.into_iter()
|
||||
.map(PathBuf::from)
|
||||
.map(|pb| pb.into_storeid())
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
.map_err_trace_exit_unwrap(1)
|
||||
},
|
||||
|
||||
(other, _) => {
|
||||
error!("Not a known command: {}", other);
|
||||
::std::process::exit(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,13 +47,10 @@ use libimagerror::exit::ExitUnwrap;
|
|||
use libimagerror::io::ToExitCode;
|
||||
use libimagrt::runtime::Runtime;
|
||||
use libimagrt::setup::generate_runtime_setup;
|
||||
use libimagstore::storeid::IntoStoreId;
|
||||
|
||||
mod ui;
|
||||
|
||||
use std::io::Write;
|
||||
use std::io::Read;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use libimagentrycategory::store::CategoryStore;
|
||||
use libimagstore::storeid::StoreIdIterator;
|
||||
|
@ -93,29 +90,7 @@ fn main() {
|
|||
fn set(rt: &Runtime) {
|
||||
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 sids = match scmd.value_of("set-ids") {
|
||||
Some(path) => vec![PathBuf::from(path).into_storeid().map_err_trace_exit_unwrap(1)],
|
||||
None => if rt.cli().is_present("entries-from-stdin") {
|
||||
let stdin = rt.stdin().unwrap_or_else(|| {
|
||||
error!("Cannot get handle to stdin");
|
||||
::std::process::exit(1)
|
||||
});
|
||||
|
||||
let mut buf = String::new();
|
||||
let _ = stdin.lock().read_to_string(&mut buf).unwrap_or_else(|_| {
|
||||
error!("Failed to read from stdin");
|
||||
::std::process::exit(1)
|
||||
});
|
||||
|
||||
buf.lines()
|
||||
.map(PathBuf::from)
|
||||
.map(|p| p.into_storeid().map_err_trace_exit_unwrap(1))
|
||||
.collect()
|
||||
} else {
|
||||
error!("Something weird happened. I was not able to find the path of the entries to edit");
|
||||
::std::process::exit(1)
|
||||
}
|
||||
};
|
||||
let sids = rt.ids::<::ui::PathProvider>().map_err_trace_exit_unwrap(1);
|
||||
|
||||
StoreIdIterator::new(Box::new(sids.into_iter().map(Ok)))
|
||||
.into_get_iter(rt.store())
|
||||
|
@ -132,31 +107,7 @@ fn set(rt: &Runtime) {
|
|||
}
|
||||
|
||||
fn get(rt: &Runtime) {
|
||||
let scmd = rt.cli().subcommand_matches("get").unwrap(); // safed by main()
|
||||
let sids = match scmd.value_of("get-ids") {
|
||||
Some(path) => vec![PathBuf::from(path).into_storeid().map_err_trace_exit_unwrap(1)],
|
||||
None => if rt.cli().is_present("entries-from-stdin") {
|
||||
let stdin = rt.stdin().unwrap_or_else(|| {
|
||||
error!("Cannot get handle to stdin");
|
||||
::std::process::exit(1)
|
||||
});
|
||||
|
||||
let mut buf = String::new();
|
||||
let _ = stdin.lock().read_to_string(&mut buf).unwrap_or_else(|_| {
|
||||
error!("Failed to read from stdin");
|
||||
::std::process::exit(1)
|
||||
});
|
||||
|
||||
buf.lines()
|
||||
.map(PathBuf::from)
|
||||
.map(|p| p.into_storeid().map_err_trace_exit_unwrap(1))
|
||||
.collect()
|
||||
} else {
|
||||
error!("Something weird happened. I was not able to find the path of the entries to edit");
|
||||
::std::process::exit(1)
|
||||
}
|
||||
};
|
||||
|
||||
let sids = rt.ids::<::ui::PathProvider>().map_err_trace_exit_unwrap(1);
|
||||
let out = rt.stdout();
|
||||
let mut outlock = out.lock();
|
||||
|
||||
|
|
|
@ -17,7 +17,14 @@
|
|||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
//
|
||||
|
||||
use clap::{Arg, ArgGroup, App, SubCommand};
|
||||
use std::path::PathBuf;
|
||||
|
||||
use clap::{Arg, ArgMatches, App, SubCommand};
|
||||
|
||||
use libimagstore::storeid::StoreId;
|
||||
use libimagstore::storeid::IntoStoreId;
|
||||
use libimagrt::runtime::IdPathProvider;
|
||||
use libimagerror::trace::MapErrTrace;
|
||||
|
||||
pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
|
||||
app
|
||||
|
@ -79,17 +86,6 @@ pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
|
|||
.multiple(true)
|
||||
.help("The entries to set the category for")
|
||||
.value_name("ID"))
|
||||
.arg(Arg::with_name("entries-from-stdin")
|
||||
.long("ids-from-stdin")
|
||||
.short("I")
|
||||
.takes_value(false)
|
||||
.required(false)
|
||||
.multiple(false)
|
||||
.help("Read the ids for the entries from stdin"))
|
||||
|
||||
.group(ArgGroup::with_name("input-method")
|
||||
.args(&["set-ids", "entries-from-stdin"])
|
||||
.required(true))
|
||||
)
|
||||
|
||||
.subcommand(SubCommand::with_name("get")
|
||||
|
@ -102,17 +98,65 @@ pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
|
|||
.multiple(true)
|
||||
.help("The id of the Entry to get the category for")
|
||||
.value_name("ID"))
|
||||
.arg(Arg::with_name("entries-from-stdin")
|
||||
.long("ids-from-stdin")
|
||||
.short("I")
|
||||
.takes_value(false)
|
||||
.required(false)
|
||||
.multiple(false)
|
||||
.help("Read the ids for the entries from stdin"))
|
||||
|
||||
.group(ArgGroup::with_name("input-method")
|
||||
.args(&["get-ids", "entries-from-stdin"])
|
||||
.required(true))
|
||||
)
|
||||
}
|
||||
|
||||
pub struct PathProvider;
|
||||
impl IdPathProvider for PathProvider {
|
||||
fn get_ids(matches: &ArgMatches) -> Vec<StoreId> {
|
||||
match matches.subcommand() {
|
||||
("create-category", _) => {
|
||||
error!("Command does not get IDs as input");
|
||||
::std::process::exit(1)
|
||||
},
|
||||
|
||||
("delete-category", _) => {
|
||||
error!("Command does not get IDs as input");
|
||||
::std::process::exit(1)
|
||||
},
|
||||
|
||||
("list-categories", _) => {
|
||||
error!("Command does not get IDs as input");
|
||||
::std::process::exit(1)
|
||||
},
|
||||
|
||||
("list-category", _) => {
|
||||
error!("Command does not get IDs as input");
|
||||
::std::process::exit(1)
|
||||
},
|
||||
|
||||
("set", Some(subm)) => {
|
||||
subm.values_of("set-ids")
|
||||
.ok_or_else(|| {
|
||||
error!("No StoreId found");
|
||||
::std::process::exit(1)
|
||||
})
|
||||
.unwrap()
|
||||
.into_iter()
|
||||
.map(PathBuf::from)
|
||||
.map(|pb| pb.into_storeid())
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
.map_err_trace_exit_unwrap(1)
|
||||
},
|
||||
|
||||
("get", Some(subm)) => {
|
||||
subm.values_of("get-ids")
|
||||
.ok_or_else(|| {
|
||||
error!("No StoreId found");
|
||||
::std::process::exit(1)
|
||||
})
|
||||
.unwrap()
|
||||
.into_iter()
|
||||
.map(PathBuf::from)
|
||||
.map(|pb| pb.into_storeid())
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
.map_err_trace_exit_unwrap(1)
|
||||
},
|
||||
|
||||
(other, _) => {
|
||||
error!("Not a known command: {}", other);
|
||||
::std::process::exit(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,15 +41,11 @@ extern crate libimagerror;
|
|||
extern crate libimagstore;
|
||||
extern crate libimagutil;
|
||||
|
||||
use std::path::PathBuf;
|
||||
use std::io::Read;
|
||||
|
||||
use libimagerror::trace::MapErrTrace;
|
||||
use libimagerror::iter::TraceIterator;
|
||||
use libimagentryedit::edit::Edit;
|
||||
use libimagentryedit::edit::EditHeader;
|
||||
use libimagrt::setup::generate_runtime_setup;
|
||||
use libimagstore::storeid::IntoStoreId;
|
||||
use libimagstore::storeid::StoreIdIterator;
|
||||
use libimagstore::iter::get::StoreIdGetIteratorExtension;
|
||||
|
||||
|
@ -62,33 +58,11 @@ fn main() {
|
|||
"Edit store entries with $EDITOR",
|
||||
ui::build_ui);
|
||||
|
||||
let sids = match rt.cli().value_of("entry") {
|
||||
Some(path) => vec![PathBuf::from(path).into_storeid().map_err_trace_exit_unwrap(1)],
|
||||
None => if rt.cli().is_present("entries-from-stdin") {
|
||||
let stdin = rt.stdin().unwrap_or_else(|| {
|
||||
error!("Cannot get handle to stdin");
|
||||
::std::process::exit(1)
|
||||
});
|
||||
|
||||
let mut buf = String::new();
|
||||
let _ = stdin.lock().read_to_string(&mut buf).unwrap_or_else(|_| {
|
||||
error!("Failed to read from stdin");
|
||||
::std::process::exit(1)
|
||||
});
|
||||
|
||||
buf.lines()
|
||||
.map(PathBuf::from)
|
||||
.map(|p| p.into_storeid().map_err_trace_exit_unwrap(1))
|
||||
.collect()
|
||||
} else {
|
||||
error!("Something weird happened. I was not able to find the path of the entries to edit");
|
||||
::std::process::exit(1)
|
||||
}
|
||||
};
|
||||
|
||||
let edit_header = rt.cli().is_present("edit-header");
|
||||
let edit_header_only = rt.cli().is_present("edit-header-only");
|
||||
|
||||
let sids = rt.ids::<::ui::PathProvider>().map_err_trace_exit_unwrap(1);
|
||||
|
||||
StoreIdIterator::new(Box::new(sids.into_iter().map(Ok)))
|
||||
.into_get_iter(rt.store())
|
||||
.trace_unwrap_exit(1)
|
||||
|
|
|
@ -17,7 +17,14 @@
|
|||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
//
|
||||
|
||||
use clap::{Arg, ArgGroup, App};
|
||||
use std::path::PathBuf;
|
||||
|
||||
use clap::{Arg, ArgMatches, App};
|
||||
|
||||
use libimagstore::storeid::IntoStoreId;
|
||||
use libimagstore::storeid::StoreId;
|
||||
use libimagrt::runtime::IdPathProvider;
|
||||
use libimagerror::trace::MapErrTrace;
|
||||
|
||||
pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
|
||||
app
|
||||
|
@ -28,16 +35,6 @@ pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
|
|||
.multiple(true)
|
||||
.help("The entry/entries to edit")
|
||||
.value_name("ENTRY"))
|
||||
.arg(Arg::with_name("entries-from-stdin")
|
||||
.long("ids-from-stdin")
|
||||
.short("I")
|
||||
.takes_value(false)
|
||||
.required(false)
|
||||
.multiple(false)
|
||||
.help("The entry/entries are piped in via stdin"))
|
||||
.group(ArgGroup::with_name("input-method")
|
||||
.args(&["entry", "entries-from-stdin"])
|
||||
.required(true))
|
||||
|
||||
.arg(Arg::with_name("edit-header")
|
||||
.long("header")
|
||||
|
@ -55,3 +52,20 @@ pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
|
|||
.help("Only edit the header"))
|
||||
}
|
||||
|
||||
pub struct PathProvider;
|
||||
impl IdPathProvider for PathProvider {
|
||||
fn get_ids(matches: &ArgMatches) -> Vec<StoreId> {
|
||||
matches
|
||||
.values_of("entry")
|
||||
.ok_or_else(|| {
|
||||
error!("No StoreId found");
|
||||
::std::process::exit(1)
|
||||
})
|
||||
.unwrap()
|
||||
.into_iter()
|
||||
.map(PathBuf::from)
|
||||
.map(|pb| pb.into_storeid())
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
.map_err_trace_exit_unwrap(1)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,7 +45,6 @@ extern crate libimagstore;
|
|||
|
||||
use std::io::Write;
|
||||
use std::process::exit;
|
||||
use std::path::PathBuf;
|
||||
use std::str::FromStr;
|
||||
|
||||
use failure::Error;
|
||||
|
@ -58,7 +57,6 @@ use libimagrt::runtime::Runtime;
|
|||
use libimagerror::trace::MapErrTrace;
|
||||
use libimagerror::exit::ExitUnwrap;
|
||||
use libimagerror::io::ToExitCode;
|
||||
use libimagstore::storeid::IntoStoreId;
|
||||
|
||||
mod ui;
|
||||
|
||||
|
@ -88,13 +86,6 @@ fn main() {
|
|||
}
|
||||
|
||||
fn add(rt: &Runtime) {
|
||||
let scmd = rt.cli().subcommand_matches("add").unwrap(); // safed by main()
|
||||
|
||||
let entry_name = scmd.value_of("entry").unwrap(); // safed by clap
|
||||
let sid = PathBuf::from(entry_name)
|
||||
.into_storeid()
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
|
||||
let c = {
|
||||
let parse = |value: &str| -> (i64, i64, i64) {
|
||||
debug!("Parsing '{}' into degree, minute and second", value);
|
||||
|
@ -120,6 +111,8 @@ fn add(rt: &Runtime) {
|
|||
(*degree, *minute, *second)
|
||||
};
|
||||
|
||||
let scmd = rt.cli().subcommand_matches("add").unwrap(); // safed by main()
|
||||
|
||||
let long = parse(scmd.value_of("longitude").unwrap()); // unwrap safed by clap
|
||||
let lati = parse(scmd.value_of("latitude").unwrap()); // unwrap safed by clap
|
||||
|
||||
|
@ -129,70 +122,90 @@ fn add(rt: &Runtime) {
|
|||
Coordinates::new(long, lati)
|
||||
};
|
||||
|
||||
rt.store()
|
||||
.get(sid)
|
||||
rt.ids::<::ui::PathProvider>()
|
||||
.map_err_trace_exit_unwrap(1)
|
||||
.map(|mut entry| {
|
||||
let _ = entry.set_coordinates(c).map_err_trace_exit_unwrap(1);
|
||||
})
|
||||
.unwrap_or_else(|| {
|
||||
error!("No such entry: {}", entry_name);
|
||||
exit(1)
|
||||
.into_iter()
|
||||
.for_each(|id| {
|
||||
rt.store()
|
||||
.get(id.clone())
|
||||
.map_err_trace_exit_unwrap(1)
|
||||
.unwrap_or_else(|| { // if we have Ok(None)
|
||||
error!("No such entry: {}", id);
|
||||
exit(1)
|
||||
})
|
||||
.set_coordinates(c.clone())
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
|
||||
let _ = rt
|
||||
.report_touched(&id)
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
});
|
||||
}
|
||||
|
||||
fn remove(rt: &Runtime) {
|
||||
let scmd = rt.cli().subcommand_matches("remove").unwrap(); // safed by main()
|
||||
let print_removed = rt
|
||||
.cli()
|
||||
.subcommand_matches("remove")
|
||||
.unwrap()
|
||||
.is_present("print-removed"); // safed by main()
|
||||
|
||||
let entry_name = scmd.value_of("entry").unwrap(); // safed by clap
|
||||
let sid = PathBuf::from(entry_name)
|
||||
.into_storeid()
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
|
||||
let removed_value = rt
|
||||
.store()
|
||||
.get(sid)
|
||||
rt.ids::<::ui::PathProvider>()
|
||||
.map_err_trace_exit_unwrap(1)
|
||||
.unwrap_or_else(|| { // if we have Ok(None)
|
||||
error!("No such entry: {}", entry_name);
|
||||
exit(1)
|
||||
})
|
||||
.remove_coordinates()
|
||||
.map_err_trace_exit_unwrap(1) // The delete action failed
|
||||
.unwrap_or_else(|| { // if we have Ok(None)
|
||||
error!("Entry had no coordinates: {}", entry_name);
|
||||
exit(1)
|
||||
})
|
||||
.map_err_trace_exit_unwrap(1); // The parsing of the deleted values failed
|
||||
.into_iter()
|
||||
.for_each(|id| {
|
||||
let removed_value = rt
|
||||
.store()
|
||||
.get(id.clone())
|
||||
.map_err_trace_exit_unwrap(1)
|
||||
.unwrap_or_else(|| { // if we have Ok(None)
|
||||
error!("No such entry: {}", id);
|
||||
exit(1)
|
||||
})
|
||||
.remove_coordinates()
|
||||
.map_err_trace_exit_unwrap(1) // 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(1); // The parsing of the deleted values failed
|
||||
|
||||
if scmd.is_present("print-removed") {
|
||||
let _ = writeln!(rt.stdout(), "{}", removed_value).to_exit_code().unwrap_or_exit();
|
||||
}
|
||||
if print_removed {
|
||||
let _ = writeln!(rt.stdout(), "{}", removed_value).to_exit_code().unwrap_or_exit();
|
||||
}
|
||||
|
||||
let _ = rt
|
||||
.report_touched(&id)
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
});
|
||||
}
|
||||
|
||||
fn get(rt: &Runtime) {
|
||||
let scmd = rt.cli().subcommand_matches("get").unwrap(); // safed by main()
|
||||
|
||||
let entry_name = scmd.value_of("entry").unwrap(); // safed by clap
|
||||
let sid = PathBuf::from(entry_name)
|
||||
.into_storeid()
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
|
||||
let value = rt
|
||||
.store()
|
||||
.get(sid)
|
||||
let mut stdout = rt.stdout();
|
||||
rt.ids::<::ui::PathProvider>()
|
||||
.map_err_trace_exit_unwrap(1)
|
||||
.unwrap_or_else(|| { // if we have Ok(None)
|
||||
error!("No such entry: {}", entry_name);
|
||||
exit(1)
|
||||
})
|
||||
.get_coordinates()
|
||||
.map_err_trace_exit_unwrap(1) // The get action failed
|
||||
.unwrap_or_else(|| { // if we have Ok(None)
|
||||
error!("Entry has no coordinates: {}", entry_name);
|
||||
exit(1)
|
||||
});
|
||||
.into_iter()
|
||||
.for_each(|id| {
|
||||
let value = rt
|
||||
.store()
|
||||
.get(id.clone())
|
||||
.map_err_trace_exit_unwrap(1)
|
||||
.unwrap_or_else(|| { // if we have Ok(None)
|
||||
error!("No such entry: {}", id);
|
||||
exit(1)
|
||||
})
|
||||
.get_coordinates()
|
||||
.map_err_trace_exit_unwrap(1) // The get action failed
|
||||
.unwrap_or_else(|| { // if we have Ok(None)
|
||||
error!("Entry has no coordinates: {}", id);
|
||||
exit(1)
|
||||
});
|
||||
|
||||
let _ = writeln!(stdout, "{}", value).to_exit_code().unwrap_or_exit();
|
||||
|
||||
let _ = rt
|
||||
.report_touched(&id)
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
})
|
||||
|
||||
let _ = writeln!(rt.stdout(), "{}", value).to_exit_code().unwrap_or_exit();
|
||||
}
|
||||
|
||||
|
|
|
@ -17,7 +17,14 @@
|
|||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
//
|
||||
|
||||
use clap::{Arg, App, SubCommand};
|
||||
use std::path::PathBuf;
|
||||
|
||||
use clap::{Arg, ArgMatches, App, SubCommand};
|
||||
|
||||
use libimagstore::storeid::IntoStoreId;
|
||||
use libimagstore::storeid::StoreId;
|
||||
use libimagrt::runtime::IdPathProvider;
|
||||
use libimagerror::trace::MapErrTrace;
|
||||
|
||||
pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
|
||||
app
|
||||
|
@ -42,7 +49,7 @@ pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
|
|||
.index(1)
|
||||
.takes_value(true)
|
||||
.required(true)
|
||||
.multiple(false)
|
||||
.multiple(true)
|
||||
.help("The entry to add the latitude/longitude to")
|
||||
.value_name("ENTRY"))
|
||||
)
|
||||
|
@ -60,7 +67,7 @@ pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
|
|||
.index(1)
|
||||
.takes_value(true)
|
||||
.required(true)
|
||||
.multiple(false)
|
||||
.multiple(true)
|
||||
.help("The entry to remove the latitude/longitude from")
|
||||
.value_name("ENTRY"))
|
||||
)
|
||||
|
@ -72,7 +79,7 @@ pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
|
|||
.index(1)
|
||||
.takes_value(true)
|
||||
.required(true)
|
||||
.multiple(false)
|
||||
.multiple(true)
|
||||
.help("The entry to get the latitude/longitude from")
|
||||
.value_name("ENTRY"))
|
||||
.arg(Arg::with_name("format-json")
|
||||
|
@ -89,3 +96,57 @@ pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
|
|||
.help("Print as <key>=<value> pairs (2 lines, default)"))
|
||||
)
|
||||
}
|
||||
|
||||
pub struct PathProvider;
|
||||
impl IdPathProvider for PathProvider {
|
||||
fn get_ids(matches: &ArgMatches) -> Vec<StoreId> {
|
||||
match matches.subcommand() {
|
||||
("add", Some(subm)) => {
|
||||
subm.values_of("entry")
|
||||
.ok_or_else(|| {
|
||||
error!("No StoreId found");
|
||||
::std::process::exit(1)
|
||||
})
|
||||
.unwrap()
|
||||
.into_iter()
|
||||
.map(PathBuf::from)
|
||||
.map(|pb| pb.into_storeid())
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
.map_err_trace_exit_unwrap(1)
|
||||
},
|
||||
|
||||
("remove", Some(subm)) => {
|
||||
subm.values_of("entry")
|
||||
.ok_or_else(|| {
|
||||
error!("No StoreId found");
|
||||
::std::process::exit(1)
|
||||
})
|
||||
.unwrap()
|
||||
.into_iter()
|
||||
.map(PathBuf::from)
|
||||
.map(|pb| pb.into_storeid())
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
.map_err_trace_exit_unwrap(1)
|
||||
},
|
||||
|
||||
("get", Some(subm)) => {
|
||||
subm.values_of("get-ids")
|
||||
.ok_or_else(|| {
|
||||
error!("No StoreId found");
|
||||
::std::process::exit(1)
|
||||
})
|
||||
.unwrap()
|
||||
.into_iter()
|
||||
.map(PathBuf::from)
|
||||
.map(|pb| pb.into_storeid())
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
.map_err_trace_exit_unwrap(1)
|
||||
},
|
||||
|
||||
(other, _) => {
|
||||
error!("Not a known command: {}", other);
|
||||
::std::process::exit(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -122,5 +122,9 @@ fn show(rt: &Runtime, e: &Entry, re: &Regex, opts: &Options, count: &mut usize)
|
|||
let _ = writeln!(rt.stdout(), "").to_exit_code().unwrap_or_exit();
|
||||
*count += 1;
|
||||
}
|
||||
|
||||
let _ = rt
|
||||
.report_touched(e.get_location())
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
}
|
||||
|
||||
|
|
|
@ -53,6 +53,7 @@ use std::process::exit;
|
|||
|
||||
use filters::filter::Filter;
|
||||
|
||||
use libimagstore::storeid::StoreId;
|
||||
use libimagrt::setup::generate_runtime_setup;
|
||||
use libimagerror::trace::MapErrTrace;
|
||||
use libimagerror::iter::TraceIterator;
|
||||
|
@ -88,35 +89,50 @@ fn main() {
|
|||
id_filters::header_filter_lang::parse(&query)
|
||||
});
|
||||
|
||||
rt.store()
|
||||
.entries()
|
||||
.map_err_trace_exit_unwrap(1)
|
||||
.trace_unwrap_exit(1)
|
||||
.filter(|id| collection_filter.filter(id))
|
||||
.filter(|id| match query_filter.as_ref() {
|
||||
None => true,
|
||||
Some(qf) => {
|
||||
let entry = rt
|
||||
.store()
|
||||
.get(id.clone())
|
||||
.map_err_trace_exit_unwrap(1)
|
||||
.unwrap_or_else(|| {
|
||||
error!("Tried to get '{}', but it does not exist!", id);
|
||||
exit(1)
|
||||
});
|
||||
let iterator = if rt.ids_from_stdin() {
|
||||
debug!("Fetching IDs from stdin...");
|
||||
let ids = rt.ids::<::ui::PathProvider>().map_err_trace_exit_unwrap(1);
|
||||
Box::new(ids.into_iter().map(Ok))
|
||||
as Box<Iterator<Item = Result<StoreId, _>>>
|
||||
} else {
|
||||
Box::new(rt.store().entries().map_err_trace_exit_unwrap(1))
|
||||
as Box<Iterator<Item = Result<StoreId, _>>>
|
||||
}
|
||||
.trace_unwrap_exit(1)
|
||||
.filter(|id| collection_filter.filter(id))
|
||||
.filter(|id| match query_filter.as_ref() {
|
||||
None => true,
|
||||
Some(qf) => {
|
||||
let entry = rt
|
||||
.store()
|
||||
.get(id.clone())
|
||||
.map_err_trace_exit_unwrap(1)
|
||||
.unwrap_or_else(|| {
|
||||
error!("Tried to get '{}', but it does not exist!", id);
|
||||
exit(1)
|
||||
});
|
||||
|
||||
qf.filter(&entry)
|
||||
}
|
||||
})
|
||||
.map(|id| if print_storepath {
|
||||
id
|
||||
} else {
|
||||
id.without_base()
|
||||
})
|
||||
.for_each(|id| {
|
||||
let _ = writeln!(rt.stdout(), "{}", id.to_str().map_err_trace_exit_unwrap(1))
|
||||
qf.filter(&entry)
|
||||
}
|
||||
})
|
||||
.map(|id| if print_storepath {
|
||||
id
|
||||
} else {
|
||||
id.without_base()
|
||||
});
|
||||
|
||||
let mut stdout = rt.stdout();
|
||||
trace!("Got output: {:?}", stdout);
|
||||
|
||||
iterator.for_each(|id| {
|
||||
rt.report_touched(&id).map_err_trace_exit_unwrap(1);
|
||||
if !rt.output_is_pipe() {
|
||||
let id = id.to_str().map_err_trace_exit_unwrap(1);
|
||||
trace!("Writing to {:?}", stdout);
|
||||
let _ = writeln!(stdout, "{}", id)
|
||||
.to_exit_code()
|
||||
.unwrap_or_exit();
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -17,7 +17,10 @@
|
|||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
//
|
||||
|
||||
use clap::{Arg, App, SubCommand};
|
||||
use clap::{Arg, ArgMatches, App, SubCommand};
|
||||
|
||||
use libimagstore::storeid::StoreId;
|
||||
use libimagrt::runtime::IdPathProvider;
|
||||
|
||||
pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
|
||||
app
|
||||
|
@ -49,3 +52,10 @@ pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
|
|||
.after_help(include_str!("../static/language-doc.md"))
|
||||
}
|
||||
|
||||
pub struct PathProvider;
|
||||
impl IdPathProvider for PathProvider {
|
||||
fn get_ids(_matches: &ArgMatches) -> Vec<StoreId> {
|
||||
error!("imag-ids does not get IDs via CLI, only via stdin if applying a filter!");
|
||||
::std::process::exit(1)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -157,9 +157,12 @@ fn link_from_to<'a, I>(rt: &'a Runtime, from: &'a str, to: I)
|
|||
::std::process::exit(1);
|
||||
});
|
||||
|
||||
let _ = from_entry
|
||||
let iter = from_entry
|
||||
.add_external_link(rt.store(), url)
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
.map_err_trace_exit_unwrap(1)
|
||||
.into_iter();
|
||||
|
||||
let _ = rt.report_all_touched(iter).map_err_trace_exit_unwrap(1);
|
||||
} else {
|
||||
debug!("Linking internally: {:?} -> {:?}", from, entry);
|
||||
|
||||
|
@ -181,88 +184,91 @@ fn link_from_to<'a, I>(rt: &'a Runtime, from: &'a str, to: I)
|
|||
let _ = from_entry
|
||||
.add_internal_link(&mut to_entry)
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
|
||||
let _ = rt
|
||||
.report_touched(to_entry.get_location())
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
}
|
||||
|
||||
|
||||
info!("Ok: {} -> {}", from, entry);
|
||||
}
|
||||
|
||||
let _ = rt
|
||||
.report_touched(from_entry.get_location())
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
}
|
||||
|
||||
fn remove_linking(rt: &Runtime) {
|
||||
|
||||
fn get_from_entry<'a>(rt: &'a Runtime) -> Option<FileLockEntry<'a>> {
|
||||
rt.cli()
|
||||
.subcommand_matches("remove")
|
||||
.unwrap() // safe, we know there is an "remove" subcommand
|
||||
.value_of("from")
|
||||
.and_then(|from_name| {
|
||||
match get_entry_by_name(rt, from_name) {
|
||||
Err(e) => {
|
||||
debug!("We couldn't get the entry from name: '{:?}'", from_name);
|
||||
trace_error(&e); None
|
||||
},
|
||||
Ok(Some(e)) => Some(e),
|
||||
Ok(None) => None,
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
let mut from = match get_from_entry(&rt) {
|
||||
None => warn_exit("No 'from' entry", 1),
|
||||
Some(s) => s,
|
||||
};
|
||||
|
||||
rt.cli()
|
||||
let mut from = rt.cli()
|
||||
.subcommand_matches("remove")
|
||||
.unwrap()
|
||||
.values_of("to")
|
||||
.map(|values| {
|
||||
for (entry, value) in values.map(|v| (get_entry_by_name(rt, v), v)) {
|
||||
match entry {
|
||||
Err(e) => trace_error(&e),
|
||||
Ok(Some(mut to_entry)) => {
|
||||
let _ = to_entry
|
||||
.remove_internal_link(&mut from)
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
},
|
||||
Ok(None) => {
|
||||
// looks like this is not an entry, but a filesystem URI and therefor an
|
||||
// external link...?
|
||||
if PathBuf::from(value).is_file() {
|
||||
let url = Url::parse(value).unwrap_or_else(|e| {
|
||||
error!("Error parsing URL: {:?}", e);
|
||||
::std::process::exit(1);
|
||||
});
|
||||
from.remove_external_link(rt.store(), url).map_err_trace_exit_unwrap(1);
|
||||
info!("Ok: {}", value);
|
||||
} else {
|
||||
warn!("Entry not found: {:?}", value);
|
||||
}
|
||||
}
|
||||
.unwrap() // safe, we know there is an "remove" subcommand
|
||||
.value_of("from")
|
||||
.map(PathBuf::from)
|
||||
.map(|id| {
|
||||
rt.store()
|
||||
.get(id)
|
||||
.map_err_trace_exit_unwrap(1)
|
||||
.ok_or_else(|| warn_exit("No 'from' entry", 1))
|
||||
.unwrap() // safe by line above
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
rt.ids::<::ui::PathProvider>()
|
||||
.map_err_trace_exit_unwrap(1)
|
||||
.into_iter()
|
||||
.for_each(|id| match rt.store().get(id.clone()) {
|
||||
Err(e) => trace_error(&e),
|
||||
Ok(Some(mut to_entry)) => {
|
||||
let _ = to_entry
|
||||
.remove_internal_link(&mut from)
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
|
||||
let _ = rt
|
||||
.report_touched(to_entry.get_location())
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
},
|
||||
Ok(None) => {
|
||||
// looks like this is not an entry, but a filesystem URI and therefor an
|
||||
// external link...?
|
||||
if id.local().is_file() {
|
||||
let pb = id.local().to_str().unwrap_or_else(|| {
|
||||
warn!("Not StoreId and not a Path: {}", id);
|
||||
::std::process::exit(1);
|
||||
});
|
||||
let url = Url::parse(pb).unwrap_or_else(|e| {
|
||||
error!("Error parsing URL: {:?}", e);
|
||||
::std::process::exit(1);
|
||||
});
|
||||
from.remove_external_link(rt.store(), url).map_err_trace_exit_unwrap(1);
|
||||
info!("Ok: {}", id);
|
||||
} else {
|
||||
warn!("Entry not found: {:?}", id);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let _ = rt
|
||||
.report_touched(from.get_location())
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
}
|
||||
|
||||
fn unlink(rt: &Runtime) {
|
||||
use libimagerror::iter::TraceIterator;
|
||||
use libimagstore::iter::get::StoreIdGetIteratorExtension;
|
||||
rt.ids::<::ui::PathProvider>().map_err_trace_exit_unwrap(1).into_iter().for_each(|id| {
|
||||
rt.store()
|
||||
.get(id.clone())
|
||||
.map_err_trace_exit_unwrap(1)
|
||||
.unwrap_or_else(|| {
|
||||
warn!("No entry for {}", id);
|
||||
::std::process::exit(1)
|
||||
})
|
||||
.unlink(rt.store())
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
|
||||
let _ = rt
|
||||
.cli()
|
||||
.subcommand_matches("unlink")
|
||||
.unwrap() // checked in main()
|
||||
.values_of("from")
|
||||
.unwrap() // checked by clap
|
||||
.map(PathBuf::from)
|
||||
.collect::<Vec<PathBuf>>().into_iter() // for lifetime inference
|
||||
.map(StoreId::new_baseless)
|
||||
.into_get_iter(rt.store())
|
||||
.trace_unwrap_exit(1)
|
||||
.filter_map(|x| x)
|
||||
.map(|mut entry| entry.unlink(rt.store()))
|
||||
.trace_unwrap_exit(1)
|
||||
.collect::<Vec<_>>();
|
||||
let _ = rt
|
||||
.report_touched(&id)
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
});
|
||||
}
|
||||
|
||||
fn list_linkings(rt: &Runtime) {
|
||||
|
@ -276,8 +282,8 @@ fn list_linkings(rt: &Runtime) {
|
|||
let mut tab = ::prettytable::Table::new();
|
||||
tab.set_titles(row!["#", "Link"]);
|
||||
|
||||
for entry in cmd.values_of("entries").unwrap() { // safed by clap
|
||||
match rt.store().get(PathBuf::from(entry)) {
|
||||
rt.ids::<::ui::PathProvider>().map_err_trace_exit_unwrap(1).into_iter().for_each(|id| {
|
||||
match rt.store().get(id.clone()) {
|
||||
Ok(Some(entry)) => {
|
||||
for (i, link) in entry.get_internal_links().map_err_trace_exit_unwrap(1).enumerate() {
|
||||
let link = link
|
||||
|
@ -314,11 +320,20 @@ fn list_linkings(rt: &Runtime) {
|
|||
}
|
||||
})
|
||||
}
|
||||
|
||||
let _ = rt
|
||||
.report_touched(entry.get_location())
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
|
||||
},
|
||||
Ok(None) => warn!("Not found: {}", entry),
|
||||
Ok(None) => warn!("Not found: {}", id),
|
||||
Err(e) => trace_error(&e),
|
||||
}
|
||||
}
|
||||
|
||||
let _ = rt
|
||||
.report_touched(&id)
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
});
|
||||
|
||||
if !list_plain {
|
||||
let out = rt.stdout();
|
||||
|
|
|
@ -17,7 +17,15 @@
|
|||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
//
|
||||
|
||||
use clap::{Arg, App, SubCommand};
|
||||
use std::path::PathBuf;
|
||||
|
||||
use clap::{Arg, ArgMatches, App, SubCommand};
|
||||
|
||||
use libimagstore::storeid::StoreId;
|
||||
use libimagstore::storeid::IntoStoreId;
|
||||
use libimagrt::runtime::IdPathProvider;
|
||||
use libimagerror::trace::MapErrTrace;
|
||||
|
||||
|
||||
pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
|
||||
app
|
||||
|
@ -101,3 +109,74 @@ pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
|
|||
.requires("from")
|
||||
.value_name("ENTRIES"))
|
||||
}
|
||||
|
||||
/// PathProvider
|
||||
///
|
||||
/// This PathProvider does _not_ return the "from" value of the commandline call if no subcommand
|
||||
/// is given.
|
||||
///
|
||||
/// It has to be fetched by main() by hand.
|
||||
pub struct PathProvider;
|
||||
impl IdPathProvider for PathProvider {
|
||||
fn get_ids(matches: &ArgMatches) -> Vec<StoreId> {
|
||||
let ids = match matches.subcommand() {
|
||||
("remove", Some(subm)) => {
|
||||
let to = subm.values_of("to")
|
||||
.ok_or_else(|| {
|
||||
error!("No StoreId found");
|
||||
::std::process::exit(1)
|
||||
})
|
||||
.unwrap()
|
||||
.into_iter()
|
||||
.map(PathBuf::from)
|
||||
.map(|pb| pb.into_storeid())
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
Some(to)
|
||||
},
|
||||
|
||||
("unlink", Some(subm)) => {
|
||||
let ids = subm
|
||||
.values_of("from")
|
||||
.ok_or_else(|| {
|
||||
error!("No StoreId found");
|
||||
::std::process::exit(1)
|
||||
})
|
||||
.unwrap()
|
||||
.into_iter()
|
||||
.map(PathBuf::from)
|
||||
.map(|pb| pb.into_storeid())
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
|
||||
Some(ids)
|
||||
},
|
||||
|
||||
("list", Some(subm)) => {
|
||||
let ids = subm
|
||||
.values_of("entries")
|
||||
.ok_or_else(|| {
|
||||
error!("No StoreId found");
|
||||
::std::process::exit(1)
|
||||
})
|
||||
.unwrap()
|
||||
.into_iter()
|
||||
.map(PathBuf::from)
|
||||
.map(|pb| pb.into_storeid())
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
|
||||
Some(ids)
|
||||
},
|
||||
|
||||
_ => None,
|
||||
};
|
||||
|
||||
ids.unwrap_or_else(|| {
|
||||
matches.values_of("to")
|
||||
.unwrap()
|
||||
.map(|s| PathBuf::from(s).into_storeid().map_err_trace_exit_unwrap(1))
|
||||
.collect()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -129,6 +129,9 @@ fn main() {
|
|||
})
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
|
||||
let _ = rt.report_touched(&destname)
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
|
||||
// re-add links to moved entry
|
||||
relink(rt.store(), destname, &mut linked_entries);
|
||||
|
||||
|
|
|
@ -88,16 +88,20 @@ fn deref(rt: &Runtime) {
|
|||
.map_err_trace_exit_unwrap(1);
|
||||
|
||||
match rt.store().get(id.clone()).map_err_trace_exit_unwrap(1) {
|
||||
Some(entry) => entry
|
||||
.get_path()
|
||||
.map_err_trace_exit_unwrap(1)
|
||||
.to_str()
|
||||
.ok_or_else(|| {
|
||||
error!("Could not transform path into string!");
|
||||
exit(1)
|
||||
})
|
||||
.map(|s| info!("{}", s))
|
||||
.ok(), // safe here because we exited already in the error case
|
||||
Some(entry) => {
|
||||
entry
|
||||
.get_path()
|
||||
.map_err_trace_exit_unwrap(1)
|
||||
.to_str()
|
||||
.ok_or_else(|| {
|
||||
error!("Could not transform path into string!");
|
||||
exit(1)
|
||||
})
|
||||
.map(|s| info!("{}", s))
|
||||
.ok(); // safe here because we exited already in the error case
|
||||
|
||||
let _ = rt.report_touched(&id).map_err_trace_exit_unwrap(1);
|
||||
},
|
||||
None => {
|
||||
error!("No entry for id '{}' found", id);
|
||||
exit(1)
|
||||
|
|
|
@ -62,6 +62,8 @@ pub fn create(rt: &Runtime) {
|
|||
Entry::default_header())
|
||||
}
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
|
||||
let _ = rt.report_touched(&path).map_err_trace_exit_unwrap(1);
|
||||
}
|
||||
|
||||
fn create_from_cli_spec(rt: &Runtime, matches: &ArgMatches, path: &StoreId) -> Result<()> {
|
||||
|
|
|
@ -34,8 +34,11 @@ pub fn get(rt: &Runtime) {
|
|||
let path = StoreId::new(store, path).map_err_trace_exit_unwrap(1);
|
||||
debug!("path = {:?}", path);
|
||||
|
||||
let _ = match rt.store().get(path).map_err_trace_exit_unwrap(1) {
|
||||
Some(entry) => print_entry(rt, scmd, entry),
|
||||
let _ = match rt.store().get(path.clone()).map_err_trace_exit_unwrap(1) {
|
||||
Some(entry) => {
|
||||
print_entry(rt, scmd, entry);
|
||||
let _ = rt.report_touched(&path).map_err_trace_exit_unwrap(1);
|
||||
},
|
||||
None => info!("No entry found"),
|
||||
};
|
||||
}
|
||||
|
|
|
@ -42,11 +42,13 @@ pub fn retrieve(rt: &Runtime) {
|
|||
debug!("path = {:?}", path);
|
||||
|
||||
rt.store()
|
||||
.retrieve(path)
|
||||
.retrieve(path.clone())
|
||||
.map(|e| print_entry(rt, scmd, e))
|
||||
.map_dbg_str("No entry")
|
||||
.map_dbg(|e| format!("{:?}", e))
|
||||
.map_err_trace()
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
|
||||
let _ = rt.report_touched(&path).map_err_trace_exit_unwrap(1);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -36,16 +36,20 @@ pub fn update(rt: &Runtime) {
|
|||
let _ = rt.store()
|
||||
.retrieve(path)
|
||||
.map(|mut locked_e| {
|
||||
let e = locked_e.deref_mut();
|
||||
{
|
||||
let e = locked_e.deref_mut();
|
||||
|
||||
scmd.value_of("content")
|
||||
.map(|new_content| {
|
||||
*e.get_content_mut() = String::from(new_content);
|
||||
debug!("New content set");
|
||||
});
|
||||
scmd.value_of("content")
|
||||
.map(|new_content| {
|
||||
*e.get_content_mut() = String::from(new_content);
|
||||
debug!("New content set");
|
||||
});
|
||||
|
||||
*e.get_header_mut() = build_toml_header(scmd, e.get_header().clone());
|
||||
debug!("New header set");
|
||||
*e.get_header_mut() = build_toml_header(scmd, e.get_header().clone());
|
||||
debug!("New header set");
|
||||
}
|
||||
|
||||
let _ = rt.report_touched(locked_e.get_location()).map_err_trace_exit_unwrap(1);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -47,6 +47,7 @@ pub fn verify(rt: &Runtime) {
|
|||
};
|
||||
|
||||
info!("{: >6} | {: >14} | {:?}", verify, content_len, p.deref());
|
||||
let _ = rt.report_touched(fle.get_location()).map_err_trace_exit_unwrap(1);
|
||||
status
|
||||
});
|
||||
|
||||
|
|
|
@ -56,9 +56,7 @@ extern crate toml_query;
|
|||
#[cfg(test)]
|
||||
extern crate env_logger;
|
||||
|
||||
use std::path::PathBuf;
|
||||
use std::io::Write;
|
||||
use std::io::Read;
|
||||
|
||||
use libimagrt::runtime::Runtime;
|
||||
use libimagrt::setup::generate_runtime_setup;
|
||||
|
@ -84,30 +82,7 @@ fn main() {
|
|||
"Direct interface to the store. Use with great care!",
|
||||
build_ui);
|
||||
|
||||
let ids : Vec<PathBuf> = rt
|
||||
.cli()
|
||||
.values_of("id")
|
||||
.map(|vals| {
|
||||
vals.map(PathBuf::from).collect()
|
||||
}).unwrap_or_else(|| {
|
||||
if !rt.cli().is_present("ids-from-stdin") {
|
||||
error!("No ids");
|
||||
::std::process::exit(1)
|
||||
}
|
||||
|
||||
let stdin = rt.stdin().unwrap_or_else(|| {
|
||||
error!("Cannot get handle to stdin");
|
||||
::std::process::exit(1)
|
||||
});
|
||||
|
||||
let mut buf = String::new();
|
||||
let _ = stdin.lock().read_to_string(&mut buf).unwrap_or_else(|_| {
|
||||
error!("Failed to read from stdin");
|
||||
::std::process::exit(1)
|
||||
});
|
||||
|
||||
buf.lines().map(PathBuf::from).collect()
|
||||
});
|
||||
let ids = rt.ids::<::ui::PathProvider>().map_err_trace_exit_unwrap(1);
|
||||
|
||||
rt.cli()
|
||||
.subcommand_name()
|
||||
|
@ -116,14 +91,12 @@ fn main() {
|
|||
list(id, &rt)
|
||||
},
|
||||
"remove" => for id in ids {
|
||||
let id = PathBuf::from(id);
|
||||
let add = None;
|
||||
let rem = get_remove_tags(rt.cli());
|
||||
debug!("id = {:?}, add = {:?}, rem = {:?}", id, add, rem);
|
||||
alter(&rt, id, add, rem);
|
||||
},
|
||||
"add" => for id in ids {
|
||||
let id = PathBuf::from(id);
|
||||
let add = get_add_tags(rt.cli());
|
||||
let rem = None;
|
||||
debug!("id = {:?}, add = {:?}, rem = {:?}", id, add, rem);
|
||||
|
@ -139,11 +112,8 @@ fn main() {
|
|||
});
|
||||
}
|
||||
|
||||
fn alter(rt: &Runtime, id: PathBuf, add: Option<Vec<Tag>>, rem: Option<Vec<Tag>>) {
|
||||
let path = StoreId::new(Some(rt.store().path().clone()), id).map_err_trace_exit_unwrap(1);
|
||||
debug!("path = {:?}", path);
|
||||
|
||||
match rt.store().get(path) {
|
||||
fn alter(rt: &Runtime, path: StoreId, add: Option<Vec<Tag>>, rem: Option<Vec<Tag>>) {
|
||||
match rt.store().get(path.clone()) {
|
||||
Ok(Some(mut e)) => {
|
||||
debug!("Entry header now = {:?}", e.get_header());
|
||||
|
||||
|
@ -184,12 +154,13 @@ fn alter(rt: &Runtime, id: PathBuf, add: Option<Vec<Tag>>, rem: Option<Vec<Tag>>
|
|||
trace_error(&e);
|
||||
},
|
||||
}
|
||||
|
||||
let _ = rt
|
||||
.report_touched(&path)
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
}
|
||||
|
||||
fn list(id: PathBuf, rt: &Runtime) {
|
||||
let path = StoreId::new(Some(rt.store().path().clone()), id).map_err_trace_exit_unwrap(1);
|
||||
debug!("path = {:?}", path);
|
||||
|
||||
fn list(path: StoreId, rt: &Runtime) {
|
||||
let entry = match rt.store().get(path.clone()).map_err_trace_exit_unwrap(1) {
|
||||
Some(e) => e,
|
||||
None => warn_exit("No entry found.", 1),
|
||||
|
@ -233,6 +204,10 @@ fn list(id: PathBuf, rt: &Runtime) {
|
|||
.to_exit_code()
|
||||
.unwrap_or_exit();
|
||||
}
|
||||
|
||||
let _ = rt
|
||||
.report_touched(&path)
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
}
|
||||
|
||||
/// Get the tags which should be added from the commandline
|
||||
|
@ -330,7 +305,7 @@ mod tests {
|
|||
debug!("Add-tags: {:?}", add);
|
||||
|
||||
debug!("Altering things");
|
||||
alter(&rt, id.clone(), add, None);
|
||||
alter(&rt, StoreId::new_baseless(id.clone()).unwrap(), add, None);
|
||||
debug!("Altered");
|
||||
|
||||
let test_entry = rt.store().get(id).unwrap().unwrap();
|
||||
|
@ -365,7 +340,7 @@ mod tests {
|
|||
debug!("Rem-tags: {:?}", rem);
|
||||
|
||||
debug!("Altering things");
|
||||
alter(&rt, id.clone(), add, rem);
|
||||
alter(&rt, StoreId::new_baseless(id.clone()).unwrap(), add, rem);
|
||||
debug!("Altered");
|
||||
|
||||
let test_entry = rt.store().get(id).unwrap().unwrap();
|
||||
|
@ -393,7 +368,7 @@ mod tests {
|
|||
debug!("Rem-tags: {:?}", rem);
|
||||
|
||||
debug!("Altering things");
|
||||
alter(&rt, id.clone(), add, rem);
|
||||
alter(&rt, StoreId::new_baseless(id.clone()).unwrap(), add, rem);
|
||||
debug!("Altered");
|
||||
|
||||
let test_entry = rt.store().get(id).unwrap().unwrap();
|
||||
|
@ -421,7 +396,7 @@ mod tests {
|
|||
debug!("Rem-tags: {:?}", rem);
|
||||
|
||||
debug!("Altering things");
|
||||
alter(&rt, id.clone(), add, rem);
|
||||
alter(&rt, StoreId::new_baseless(id.clone()).unwrap(), add, rem);
|
||||
debug!("Altered");
|
||||
|
||||
let test_entry = rt.store().get(id).unwrap().unwrap();
|
||||
|
|
|
@ -17,8 +17,14 @@
|
|||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
//
|
||||
|
||||
use clap::{Arg, App, ArgGroup, SubCommand};
|
||||
use std::path::PathBuf;
|
||||
|
||||
use clap::{Arg, ArgMatches, ArgGroup, App, SubCommand};
|
||||
|
||||
use libimagstore::storeid::StoreId;
|
||||
use libimagstore::storeid::IntoStoreId;
|
||||
use libimagrt::runtime::IdPathProvider;
|
||||
use libimagerror::trace::MapErrTrace;
|
||||
use libimagentrytag::tag::is_tag;
|
||||
|
||||
pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
|
||||
|
@ -30,14 +36,6 @@ pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
|
|||
.value_name("ID")
|
||||
.help("Entry to use"))
|
||||
|
||||
.arg(Arg::with_name("ids-from-stdin")
|
||||
.long("ids-from-stdin")
|
||||
.short("I")
|
||||
.takes_value(false)
|
||||
.required(false)
|
||||
.multiple(false)
|
||||
.help("Read store ids to tag from stdin"))
|
||||
|
||||
.subcommand(SubCommand::with_name("add")
|
||||
.about("Add tags")
|
||||
.version("0.1")
|
||||
|
@ -104,3 +102,14 @@ pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
|
|||
)
|
||||
|
||||
}
|
||||
|
||||
pub struct PathProvider;
|
||||
impl IdPathProvider for PathProvider {
|
||||
fn get_ids(matches: &ArgMatches) -> Vec<StoreId> {
|
||||
matches.values_of("id")
|
||||
.unwrap()
|
||||
.map(|s| PathBuf::from(s).into_storeid().map_err_trace_exit_unwrap(1))
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -49,8 +49,6 @@ extern crate libimagutil;
|
|||
use std::str::FromStr;
|
||||
use std::collections::BTreeMap;
|
||||
use std::io::Write;
|
||||
use std::io::Read;
|
||||
use std::path::PathBuf;
|
||||
use std::process::Command;
|
||||
use std::process::exit;
|
||||
|
||||
|
@ -60,7 +58,6 @@ use failure::Error;
|
|||
use failure::err_msg;
|
||||
|
||||
use libimagrt::setup::generate_runtime_setup;
|
||||
use libimagrt::runtime::Runtime;
|
||||
use libimagerror::trace::MapErrTrace;
|
||||
use libimagerror::iter::TraceIterator;
|
||||
use libimagerror::io::ToExitCode;
|
||||
|
@ -68,8 +65,6 @@ use libimagerror::exit::ExitUnwrap;
|
|||
use libimagentryview::builtin::stdout::StdoutViewer;
|
||||
use libimagentryview::builtin::md::MarkdownViewer;
|
||||
use libimagentryview::viewer::Viewer;
|
||||
use libimagstore::storeid::IntoStoreId;
|
||||
use libimagstore::storeid::StoreIdIterator;
|
||||
use libimagstore::iter::get::StoreIdGetIteratorExtension;
|
||||
use libimagstore::store::FileLockEntry;
|
||||
|
||||
|
@ -83,19 +78,28 @@ fn main() {
|
|||
"View entries (readonly)",
|
||||
build_ui);
|
||||
|
||||
let entry_ids = entry_ids(&rt);
|
||||
let view_header = rt.cli().is_present("view-header");
|
||||
let hide_content = rt.cli().is_present("not-view-content");
|
||||
let entries = rt.ids::<::ui::PathProvider>()
|
||||
.map_err_trace_exit_unwrap(1)
|
||||
.into_iter()
|
||||
.map(Ok)
|
||||
.into_get_iter(rt.store())
|
||||
.trace_unwrap_exit(1)
|
||||
.map(|e| {
|
||||
e.ok_or_else(|| err_msg("Entry not found"))
|
||||
.map_err(Error::from)
|
||||
.map_err_trace_exit_unwrap(1)
|
||||
});
|
||||
|
||||
if rt.cli().is_present("in") {
|
||||
let files = entry_ids
|
||||
.into_get_iter(rt.store())
|
||||
.trace_unwrap_exit(1)
|
||||
.map(|e| {
|
||||
e.ok_or_else(|| err_msg("Entry not found"))
|
||||
.map_err_trace_exit_unwrap(1)
|
||||
let files = entries
|
||||
.map(|entry| {
|
||||
let tmpfile = create_tempfile_for(&entry, view_header, hide_content);
|
||||
rt.report_touched(entry.get_location())
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
tmpfile
|
||||
})
|
||||
.map(|entry| create_tempfile_for(&entry, view_header, hide_content))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let mut command = {
|
||||
|
@ -170,14 +174,6 @@ fn main() {
|
|||
|
||||
drop(files);
|
||||
} else {
|
||||
let iter = entry_ids
|
||||
.into_get_iter(rt.store())
|
||||
.map(|e| {
|
||||
e.map_err_trace_exit_unwrap(1)
|
||||
.ok_or_else(|| err_msg("Entry not found"))
|
||||
.map_err_trace_exit_unwrap(1)
|
||||
});
|
||||
|
||||
let out = rt.stdout();
|
||||
let mut outlock = out.lock();
|
||||
|
||||
|
@ -198,17 +194,22 @@ fn main() {
|
|||
let viewer = MarkdownViewer::new(&rt);
|
||||
let seperator = basesep.map(|s| build_seperator(s, sep_width));
|
||||
|
||||
for (n, entry) in iter.enumerate() {
|
||||
if n != 0 {
|
||||
seperator
|
||||
.as_ref()
|
||||
.map(|s| writeln!(outlock, "{}", s).to_exit_code().unwrap_or_exit());
|
||||
}
|
||||
entries
|
||||
.enumerate()
|
||||
.for_each(|(n, entry)| {
|
||||
if n != 0 {
|
||||
seperator
|
||||
.as_ref()
|
||||
.map(|s| writeln!(outlock, "{}", s).to_exit_code().unwrap_or_exit());
|
||||
}
|
||||
|
||||
viewer
|
||||
.view_entry(&entry, &mut outlock)
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
}
|
||||
viewer
|
||||
.view_entry(&entry, &mut outlock)
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
|
||||
rt.report_touched(entry.get_location())
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
});
|
||||
} else {
|
||||
let mut viewer = StdoutViewer::new(view_header, !hide_content);
|
||||
|
||||
|
@ -228,48 +229,22 @@ fn main() {
|
|||
}
|
||||
|
||||
let seperator = basesep.map(|s| build_seperator(s, sep_width));
|
||||
for (n, entry) in iter.enumerate() {
|
||||
if n != 0 {
|
||||
seperator
|
||||
.as_ref()
|
||||
.map(|s| writeln!(outlock, "{}", s).to_exit_code().unwrap_or_exit());
|
||||
}
|
||||
entries
|
||||
.enumerate()
|
||||
.for_each(|(n, entry)| {
|
||||
if n != 0 {
|
||||
seperator
|
||||
.as_ref()
|
||||
.map(|s| writeln!(outlock, "{}", s).to_exit_code().unwrap_or_exit());
|
||||
}
|
||||
|
||||
viewer
|
||||
.view_entry(&entry, &mut outlock)
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
viewer
|
||||
.view_entry(&entry, &mut outlock)
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
|
||||
fn entry_ids(rt: &Runtime) -> StoreIdIterator {
|
||||
match rt.cli().values_of("id") {
|
||||
Some(p) => {
|
||||
let pathes : Vec<String> = p.map(String::from).collect();
|
||||
let iter = pathes.into_iter().map(PathBuf::from).map(PathBuf::into_storeid);
|
||||
StoreIdIterator::new(Box::new(iter))
|
||||
},
|
||||
|
||||
None => if rt.cli().is_present("entries-from-stdin") {
|
||||
let stdin = rt.stdin().unwrap_or_else(|| {
|
||||
error!("Cannot get handle to stdin");
|
||||
::std::process::exit(1)
|
||||
});
|
||||
|
||||
let mut buf = String::new();
|
||||
let _ = stdin.lock().read_to_string(&mut buf).unwrap_or_else(|_| {
|
||||
error!("Failed to read from stdin");
|
||||
::std::process::exit(1)
|
||||
});
|
||||
|
||||
let lines : Vec<String> = buf.lines().map(String::from).collect();
|
||||
let iter = lines.into_iter().map(PathBuf::from).map(PathBuf::into_storeid);
|
||||
|
||||
StoreIdIterator::new(Box::new(iter))
|
||||
} else {
|
||||
error!("Something weird happened. I was not able to find the path of the entries to edit");
|
||||
::std::process::exit(1)
|
||||
rt.report_touched(entry.get_location())
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,17 +17,17 @@
|
|||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
//
|
||||
|
||||
use clap::{Arg, ArgGroup, App};
|
||||
use std::path::PathBuf;
|
||||
|
||||
use clap::{Arg, ArgMatches, App};
|
||||
|
||||
use libimagstore::storeid::StoreId;
|
||||
use libimagstore::storeid::IntoStoreId;
|
||||
use libimagrt::runtime::IdPathProvider;
|
||||
use libimagerror::trace::MapErrTrace;
|
||||
|
||||
pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
|
||||
app
|
||||
.arg(Arg::with_name("entries-from-stdin")
|
||||
.long("ids-from-stdin")
|
||||
.short("I")
|
||||
.required(false)
|
||||
.multiple(true)
|
||||
.help("The entry/entries are piped in via stdin"))
|
||||
|
||||
.arg(Arg::with_name("id")
|
||||
.index(1)
|
||||
.takes_value(true)
|
||||
|
@ -36,10 +36,6 @@ pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
|
|||
.help("View these entries at this store path")
|
||||
.value_name("IDs"))
|
||||
|
||||
.group(ArgGroup::with_name("input-method")
|
||||
.args(&["id", "entries-from-stdin"])
|
||||
.required(true))
|
||||
|
||||
.arg(Arg::with_name("autowrap")
|
||||
.long("autowrap")
|
||||
.short("w")
|
||||
|
@ -91,3 +87,13 @@ pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
|
|||
.help("View content. If no value is given, this fails. Possible viewers are configured via the config file."))
|
||||
|
||||
}
|
||||
|
||||
pub struct PathProvider;
|
||||
impl IdPathProvider for PathProvider {
|
||||
fn get_ids(matches: &ArgMatches) -> Vec<StoreId> {
|
||||
matches.values_of("id")
|
||||
.unwrap()
|
||||
.map(|s| PathBuf::from(s).into_storeid().map_err_trace_exit_unwrap(1))
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,8 +18,11 @@ build = "build.rs"
|
|||
[build-dependencies]
|
||||
clap = ">=2.16.1"
|
||||
libimagrt = { version = "0.9.0", path = "../../../lib/core/libimagrt" }
|
||||
libimagerror = { version = "0.9.0", path = "../../../lib/core/libimagerror" }
|
||||
libimagstore = { version = "0.9.0", path = "../../../lib/core/libimagstore" }
|
||||
libimagentrytag = { version = "0.9.0", path = "../../../lib/entry/libimagentrytag" }
|
||||
libimagutil = { version = "0.9.0", path = "../../../lib/etc/libimagutil" }
|
||||
log = "0.4.0"
|
||||
|
||||
[badges]
|
||||
travis-ci = { repository = "matthiasbeyer/imag" }
|
||||
|
@ -34,6 +37,7 @@ toml = "0.4"
|
|||
toml-query = "0.7"
|
||||
|
||||
libimagerror = { version = "0.9.0", path = "../../../lib/core/libimagerror" }
|
||||
libimagstore = { version = "0.9.0", path = "../../../lib/core/libimagstore" }
|
||||
|
||||
[dependencies.clap]
|
||||
version = "^2.29"
|
||||
|
|
|
@ -19,7 +19,11 @@
|
|||
|
||||
extern crate clap;
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
#[macro_use]
|
||||
extern crate libimagrt;
|
||||
extern crate libimagerror;
|
||||
extern crate libimagstore;
|
||||
extern crate libimagentrytag;
|
||||
extern crate libimagutil;
|
||||
|
||||
|
@ -45,6 +49,7 @@ mod toplevelbuildscript {
|
|||
macro_rules! gen_mods_buildui {
|
||||
($(($path:expr, $modulename:ident)$(,)*)*) => (
|
||||
$(
|
||||
#[allow(unused)]
|
||||
mod $modulename {
|
||||
include!($path);
|
||||
}
|
||||
|
|
|
@ -98,10 +98,18 @@ fn add(rt: &Runtime) {
|
|||
.ok_or_else(|| format_err!("No bookmark collection '{}' found", coll))
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
|
||||
let _ = rt
|
||||
.report_touched(collection.get_location())
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
|
||||
for url in scmd.values_of("urls").unwrap() { // unwrap saved by clap
|
||||
let _ = collection
|
||||
let new_ids = collection
|
||||
.add_link(rt.store(), BookmarkLink::from(url))
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
|
||||
let _ = rt
|
||||
.report_all_touched(new_ids.into_iter())
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
}
|
||||
|
||||
info!("Ready");
|
||||
|
@ -112,7 +120,8 @@ fn collection(rt: &Runtime) {
|
|||
|
||||
if scmd.is_present("add") { // adding a new collection
|
||||
let name = scmd.value_of("add").unwrap();
|
||||
if let Ok(_) = BookmarkCollectionStore::new(rt.store(), &name) {
|
||||
if let Ok(id) = BookmarkCollectionStore::new(rt.store(), &name) {
|
||||
let _ = rt.report_touched(id.get_location()).map_err_trace_exit_unwrap(1);
|
||||
info!("Created: {}", name);
|
||||
} else {
|
||||
warn!("Creating collection {} failed", name);
|
||||
|
@ -139,6 +148,10 @@ fn list(rt: &Runtime) {
|
|||
.ok_or_else(|| format_err!("No bookmark collection '{}' found", coll))
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
|
||||
let _ = rt
|
||||
.report_touched(collection.get_location())
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
|
||||
let links = collection.links(rt.store()).map_err_trace_exit_unwrap(1);
|
||||
debug!("Listing...");
|
||||
for (i, link) in links.enumerate() {
|
||||
|
@ -148,8 +161,6 @@ fn list(rt: &Runtime) {
|
|||
}
|
||||
};
|
||||
debug!("... ready with listing");
|
||||
|
||||
info!("Ready");
|
||||
}
|
||||
|
||||
fn remove(rt: &Runtime) {
|
||||
|
@ -161,10 +172,18 @@ fn remove(rt: &Runtime) {
|
|||
.ok_or_else(|| format_err!("No bookmark collection '{}' found", coll))
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
|
||||
let _ = rt
|
||||
.report_touched(collection.get_location())
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
|
||||
for url in scmd.values_of("urls").unwrap() { // enforced by clap
|
||||
collection
|
||||
let removed_links = collection
|
||||
.remove_link(rt.store(), BookmarkLink::from(url))
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
|
||||
let _ = rt
|
||||
.report_all_touched(removed_links.into_iter())
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
}
|
||||
|
||||
info!("Ready");
|
||||
|
|
|
@ -200,10 +200,13 @@ pub fn create(rt: &Runtime) {
|
|||
|
||||
if let Some(location) = location {
|
||||
if !scmd.is_present("dont-track") {
|
||||
rt.store()
|
||||
let entry = rt.store()
|
||||
.create_from_path(&location)
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
|
||||
let _ = rt.report_touched(entry.get_location())
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
|
||||
info!("Created entry in store");
|
||||
} else {
|
||||
info!("Not creating entry in store");
|
||||
|
|
|
@ -122,6 +122,11 @@ fn list(rt: &Runtime) {
|
|||
.trace_unwrap_exit(1)
|
||||
.map(|fle| fle.ok_or_else(|| Error::from(err_msg("StoreId not found".to_owned()))))
|
||||
.trace_unwrap_exit(1)
|
||||
.map(|fle| {
|
||||
let _ = rt.report_touched(fle.get_location())
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
fle
|
||||
})
|
||||
.map(|e| e.deser())
|
||||
.trace_unwrap_exit(1)
|
||||
.enumerate();
|
||||
|
@ -163,21 +168,30 @@ fn import(rt: &Runtime) {
|
|||
}
|
||||
|
||||
if path.is_file() {
|
||||
let _ = rt
|
||||
let entry = rt
|
||||
.store()
|
||||
.retrieve_from_path(&path)
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
|
||||
let _ = rt
|
||||
.report_touched(entry.get_location())
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
} else if path.is_dir() {
|
||||
for entry in WalkDir::new(path).min_depth(1).into_iter() {
|
||||
let entry = entry
|
||||
.map_err(Error::from)
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
|
||||
if entry.file_type().is_file() {
|
||||
let pb = PathBuf::from(entry.path());
|
||||
let _ = rt
|
||||
let fle = rt
|
||||
.store()
|
||||
.retrieve_from_path(&pb)
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
|
||||
let _ = rt
|
||||
.report_touched(fle.get_location())
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
info!("Imported: {}", entry.path().to_str().unwrap_or("<non UTF-8 path>"));
|
||||
} else {
|
||||
warn!("Ignoring non-file: {}", entry.path().to_str().unwrap_or("<non UTF-8 path>"));
|
||||
|
@ -216,6 +230,9 @@ fn show(rt: &Runtime) {
|
|||
.unwrap() // exited above
|
||||
.starts_with(&hash)
|
||||
{
|
||||
let _ = rt
|
||||
.report_touched(entry.get_location())
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
Some(deser)
|
||||
} else {
|
||||
None
|
||||
|
@ -270,6 +287,10 @@ fn find(rt: &Runtime) {
|
|||
|| card.fullname().iter().any(|a| str_contains_any(a, &grepstring));
|
||||
|
||||
if take {
|
||||
let _ = rt
|
||||
.report_touched(entry.get_location())
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
|
||||
// optimization so we don't have to parse again in the next step
|
||||
Some((entry, card))
|
||||
} else {
|
||||
|
|
|
@ -43,6 +43,8 @@ pub fn create(rt: &Runtime) {
|
|||
|
||||
let mut entry = create_entry(rt.store(), &diaryname, rt);
|
||||
|
||||
let _ = rt.report_touched(entry.get_location()).map_err_trace_exit_unwrap(1);
|
||||
|
||||
let res = if rt.cli().subcommand_matches("create").unwrap().is_present("no-edit") {
|
||||
debug!("Not editing new diary entry");
|
||||
Ok(())
|
||||
|
|
|
@ -66,6 +66,10 @@ pub fn delete(rt: &Runtime) {
|
|||
return;
|
||||
}
|
||||
|
||||
let _ = rt
|
||||
.report_touched(&to_del_location)
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
|
||||
let _ = rt
|
||||
.store()
|
||||
.delete(to_del_location)
|
||||
|
|
|
@ -54,6 +54,12 @@ pub fn list(rt: &Runtime) {
|
|||
ids.into_iter()
|
||||
.map(IntoStoreId::into_storeid)
|
||||
.trace_unwrap_exit(1)
|
||||
.for_each(|id| writeln!(rt.stdout(), "{}", id).to_exit_code().unwrap_or_exit());
|
||||
.for_each(|id| {
|
||||
let _ = rt
|
||||
.report_touched(&id)
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
|
||||
writeln!(rt.stdout(), "{}", id).to_exit_code().unwrap_or_exit()
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -41,6 +41,14 @@ pub fn view(rt: &Runtime) {
|
|||
::std::process::exit(1)
|
||||
}));
|
||||
|
||||
let entries = entries.map(|e| {
|
||||
let _ = rt
|
||||
.report_touched(e.get_location())
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
|
||||
e
|
||||
});
|
||||
|
||||
let out = rt.stdout();
|
||||
DV::new(hdr).view_entries(entries, &mut out.lock())
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
|
|
|
@ -152,7 +152,8 @@ fn create(rt: &Runtime) {
|
|||
|
||||
debug!("Builder = {:?}", hb);
|
||||
|
||||
hb.build(rt.store()).map_err_trace_exit_unwrap(1);
|
||||
let fle = hb.build(rt.store()).map_err_trace_exit_unwrap(1);
|
||||
let _ = rt.report_touched(fle.get_location()).map_err_trace_exit_unwrap(1);
|
||||
}
|
||||
|
||||
fn delete(rt: &Runtime) {
|
||||
|
@ -370,6 +371,13 @@ fn today(rt: &Runtime, future: bool) {
|
|||
{
|
||||
let mut v = vec![format!("{}", i)];
|
||||
let mut list = lister_fn(&e);
|
||||
|
||||
{
|
||||
let _ = rt
|
||||
.report_touched(e.get_location())
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
}
|
||||
|
||||
v.append(&mut list);
|
||||
table.add_row(v.iter().map(|s| Cell::new(s)).collect());
|
||||
empty = false;
|
||||
|
@ -426,6 +434,13 @@ fn list(rt: &Runtime) {
|
|||
.for_each(|(i, e)| {
|
||||
let mut v = vec![format!("{}", i)];
|
||||
let mut list = lister_fn(&e);
|
||||
|
||||
{
|
||||
let _ = rt
|
||||
.report_touched(e.get_location())
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
}
|
||||
|
||||
v.append(&mut list);
|
||||
table.add_row(v.iter().map(|s| Cell::new(s)).collect());
|
||||
empty = false;
|
||||
|
@ -443,7 +458,6 @@ fn show(rt: &Runtime) {
|
|||
.map(String::from)
|
||||
.unwrap(); // safe by clap
|
||||
|
||||
|
||||
fn instance_lister_fn(i: &FileLockEntry) -> Vec<String> {
|
||||
use libimagutil::date::date_to_string;
|
||||
use libimaghabit::instance::HabitInstance;
|
||||
|
@ -499,6 +513,13 @@ fn show(rt: &Runtime) {
|
|||
.for_each(|(i, e)| {
|
||||
let mut v = vec![format!("{}", i)];
|
||||
let mut instances = instance_lister_fn(&e);
|
||||
|
||||
{
|
||||
let _ = rt
|
||||
.report_touched(e.get_location())
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
}
|
||||
|
||||
v.append(&mut instances);
|
||||
table.add_row(v.iter().map(|s| Cell::new(s)).collect());
|
||||
empty = false;
|
||||
|
@ -555,6 +576,12 @@ fn done(rt: &Runtime) {
|
|||
next_instance_name);
|
||||
}
|
||||
|
||||
{
|
||||
let _ = rt
|
||||
.report_touched(r.get_location())
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
}
|
||||
|
||||
}
|
||||
info!("Done.");
|
||||
}
|
||||
|
|
|
@ -57,6 +57,7 @@ use libimagerror::trace::MapErrTrace;
|
|||
use libimagerror::io::ToExitCode;
|
||||
use libimagerror::exit::ExitUnwrap;
|
||||
use libimagerror::iter::TraceIterator;
|
||||
use libimagerror::exit::ExitCode;
|
||||
use libimagdiary::diary::Diary;
|
||||
use libimaglog::log::Log;
|
||||
use libimagstore::iter::get::StoreIdGetIteratorExtension;
|
||||
|
@ -156,7 +157,7 @@ fn show(rt: &Runtime) {
|
|||
.into_iter()
|
||||
.map(|(id, entry)| {
|
||||
debug!("Found entry: {:?}", entry);
|
||||
writeln!(rt.stdout(),
|
||||
let _ = writeln!(rt.stdout(),
|
||||
"{dname: >10} - {y: >4}-{m:0>2}-{d:0>2}T{H:0>2}:{M:0>2} - {text}",
|
||||
dname = id.diary_name(),
|
||||
y = id.year(),
|
||||
|
@ -165,9 +166,14 @@ fn show(rt: &Runtime) {
|
|||
H = id.hour(),
|
||||
M = id.minute(),
|
||||
text = entry.get_content())
|
||||
.to_exit_code()
|
||||
.to_exit_code()?;
|
||||
|
||||
let _ = rt
|
||||
.report_touched(entry.get_location())
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
Ok(())
|
||||
})
|
||||
.collect::<Result<Vec<()>, _>>()
|
||||
.collect::<Result<Vec<()>, ExitCode>>()
|
||||
.unwrap_or_exit();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -89,9 +89,11 @@ fn import_mail(rt: &Runtime) {
|
|||
let scmd = rt.cli().subcommand_matches("import-mail").unwrap();
|
||||
let path = scmd.value_of("path").unwrap(); // enforced by clap
|
||||
|
||||
let _ = Mail::import_from_path(rt.store(), path)
|
||||
.map_err_trace()
|
||||
.map_info_str("Ok");
|
||||
let mail = Mail::import_from_path(rt.store(), path)
|
||||
.map_info_str("Ok")
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
|
||||
let _ = rt.report_touched(mail.fle().get_location()).map_err_trace_exit_unwrap(1);
|
||||
}
|
||||
|
||||
fn list(rt: &Runtime) {
|
||||
|
@ -141,7 +143,9 @@ fn list(rt: &Runtime) {
|
|||
id = id,
|
||||
subj = subject,
|
||||
to = to
|
||||
).to_exit_code().unwrap_or_exit()
|
||||
).to_exit_code().unwrap_or_exit();
|
||||
|
||||
let _ = rt.report_touched(m.fle().get_location()).map_err_trace_exit_unwrap(1);
|
||||
}
|
||||
|
||||
let _ = rt.store()
|
||||
|
|
|
@ -109,6 +109,10 @@ fn create(rt: &Runtime) {
|
|||
.map_warn_err_str("Editing failed")
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
}
|
||||
|
||||
let _ = rt
|
||||
.report_touched(note.get_location())
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
}
|
||||
|
||||
fn delete(rt: &Runtime) {
|
||||
|
@ -129,6 +133,10 @@ fn edit(rt: &Runtime) {
|
|||
.edit_content(rt)
|
||||
.map_warn_err_str("Editing failed")
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
|
||||
let _ = rt
|
||||
.report_touched(note.get_location())
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
})
|
||||
.unwrap_or_else(|| {
|
||||
error!("Cannot find note with name '{}'", name);
|
||||
|
@ -156,9 +164,13 @@ fn list(rt: &Runtime) {
|
|||
.iter()
|
||||
.for_each(|note| {
|
||||
let name = note.get_name().map_err_trace_exit_unwrap(1);
|
||||
writeln!(rt.stdout(), "{}", name)
|
||||
let _ = writeln!(rt.stdout(), "{}", name)
|
||||
.to_exit_code()
|
||||
.unwrap_or_exit()
|
||||
.unwrap_or_exit();
|
||||
|
||||
let _ = rt
|
||||
.report_touched(note.get_location())
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -81,11 +81,16 @@ pub fn cont(rt: &Runtime) -> i32 {
|
|||
|
||||
acc.and_then(|_| {
|
||||
// create a new tracking with the same tag
|
||||
tracking
|
||||
let val = tracking
|
||||
.get_timetrack_tag()
|
||||
.and_then(|tag| rt.store().create_timetracking_now(&tag))
|
||||
.map(|_| 0)
|
||||
.map_err_trace()
|
||||
.map_err_trace();
|
||||
|
||||
let _ = rt.report_touched(tracking.get_location())
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
|
||||
val
|
||||
})
|
||||
})
|
||||
},
|
||||
|
|
|
@ -103,6 +103,9 @@ pub fn day(rt: &Runtime) -> i32 {
|
|||
let end = e.get_end_datetime()?;
|
||||
debug!(" -> end = {:?}", end);
|
||||
|
||||
let _ = rt.report_touched(e.get_location())
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
|
||||
Ok((tag, start, end))
|
||||
})
|
||||
.trace_unwrap_exit(1)
|
||||
|
|
|
@ -162,6 +162,9 @@ pub fn list_impl(rt: &Runtime,
|
|||
.collect();
|
||||
tab.add_row(Row::new(cells));
|
||||
|
||||
let _ = rt.report_touched(e.get_location())
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
|
||||
Ok(tab)
|
||||
})
|
||||
})
|
||||
|
|
|
@ -118,6 +118,9 @@ pub fn month(rt: &Runtime) -> i32 {
|
|||
let end = e.get_end_datetime()?;
|
||||
debug!(" -> end = {:?}", end);
|
||||
|
||||
let _ = rt.report_touched(e.get_location())
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
|
||||
Ok((tag, start, end))
|
||||
})
|
||||
.trace_unwrap_exit(1)
|
||||
|
|
|
@ -24,9 +24,9 @@ use failure::Error;
|
|||
|
||||
use libimagrt::runtime::Runtime;
|
||||
use libimagerror::trace::trace_error;
|
||||
use libimagerror::trace::MapErrTrace;
|
||||
use libimagtimetrack::tag::TimeTrackingTag;
|
||||
use libimagtimetrack::timetrackingstore::TimeTrackStore;
|
||||
use libimagerror::trace::MapErrTrace;
|
||||
|
||||
pub fn start(rt: &Runtime) -> i32 {
|
||||
let (_, cmd) = rt.cli().subcommand();
|
||||
|
@ -49,11 +49,18 @@ pub fn start(rt: &Runtime) -> i32 {
|
|||
.map(String::from)
|
||||
.map(TimeTrackingTag::from)
|
||||
.fold(0, |acc, ttt| {
|
||||
rt.store()
|
||||
.create_timetracking_at(&start, &ttt)
|
||||
.map_err_trace()
|
||||
.map(|_| acc)
|
||||
.unwrap_or(1)
|
||||
match rt.store().create_timetracking_at(&start, &ttt) {
|
||||
Err(e) => {
|
||||
trace_error(&e);
|
||||
1
|
||||
},
|
||||
Ok(entry) => {
|
||||
let _ = rt.report_touched(entry.get_location())
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
|
||||
acc
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -34,7 +34,6 @@ use libimagtimetrack::timetrackingstore::*;
|
|||
use libimagtimetrack::iter::filter::has_end_time;
|
||||
use libimagtimetrack::iter::filter::has_one_of_tags;
|
||||
use libimagutil::warn_result::*;
|
||||
use libimagutil::debug_result::*;
|
||||
|
||||
pub fn stop(rt: &Runtime) -> i32 {
|
||||
let (_, cmd) = rt.cli().subcommand();
|
||||
|
@ -92,10 +91,18 @@ pub fn stop(rt: &Runtime) -> i32 {
|
|||
// for each of these timetrackings, end them
|
||||
// for each result, print the backtrace (if any)
|
||||
.fold(0, |acc, mut elem| {
|
||||
elem.set_end_datetime(stop_time.clone())
|
||||
.map_dbg(|e| format!("Setting end time worked: {:?}", e))
|
||||
.map(|_| acc)
|
||||
.map_err_trace_exit_unwrap(1)
|
||||
match elem.set_end_datetime(stop_time.clone()) {
|
||||
Err(e) => {
|
||||
trace_error(&e);
|
||||
1
|
||||
}
|
||||
Ok(_) => {
|
||||
format!("Setting end time worked: {:?}", elem);
|
||||
let _ = rt.report_touched(elem.get_location())
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
acc
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -81,12 +81,16 @@ pub fn track(rt: &Runtime) -> i32 {
|
|||
.unwrap() // enforced by clap
|
||||
.map(String::from)
|
||||
.map(TimeTrackingTag::from)
|
||||
.fold(0, |acc, ttt| {
|
||||
rt.store()
|
||||
.create_timetracking(&start, &stop, &ttt)
|
||||
.map_err_trace()
|
||||
.map(|_| acc)
|
||||
.unwrap_or(1)
|
||||
.fold(0, |acc, ttt| match rt.store().create_timetracking(&start, &stop, &ttt) {
|
||||
Err(e) => {
|
||||
trace_error(&e);
|
||||
1
|
||||
},
|
||||
Ok(entry) => {
|
||||
let _ = rt.report_touched(entry.get_location())
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
acc
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -116,6 +116,9 @@ pub fn week(rt: &Runtime) -> i32 {
|
|||
let end = e.get_end_datetime()?;
|
||||
debug!(" -> end = {:?}", end);
|
||||
|
||||
let _ = rt.report_touched(e.get_location())
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
|
||||
Ok((tag, start, end))
|
||||
})
|
||||
.trace_unwrap_exit(1)
|
||||
|
|
|
@ -116,6 +116,9 @@ pub fn year(rt: &Runtime) -> i32 {
|
|||
let end = e.get_end_datetime()?;
|
||||
debug!(" -> end = {:?}", end);
|
||||
|
||||
let _ = rt.report_touched(e.get_location())
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
|
||||
Ok((tag, start, end))
|
||||
})
|
||||
.trace_unwrap_exit(1)
|
||||
|
|
|
@ -170,19 +170,28 @@ fn create(rt: &Runtime, wiki_name: &str) {
|
|||
.map_warn_err_str("Safed entry")
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
|
||||
let id = entry.get_location();
|
||||
|
||||
if scmd.is_present("create-printid") {
|
||||
let out = rt.stdout();
|
||||
let mut lock = out.lock();
|
||||
let id = entry.get_location();
|
||||
|
||||
writeln!(lock, "{}", id).to_exit_code().unwrap_or_exit()
|
||||
}
|
||||
|
||||
let _ = rt
|
||||
.report_touched(&id)
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
}
|
||||
|
||||
fn create_wiki(rt: &Runtime) {
|
||||
let scmd = rt.cli().subcommand_matches("create-wiki").unwrap(); // safed by clap
|
||||
let wiki_name = String::from(scmd.value_of("create-wiki-name").unwrap()); // safe by clap
|
||||
let _ = rt.store().create_wiki(&wiki_name).map_err_trace_exit_unwrap(1);
|
||||
let scmd = rt.cli().subcommand_matches("create-wiki").unwrap(); // safed by clap
|
||||
let wiki_name = String::from(scmd.value_of("create-wiki-name").unwrap()); // safe by clap
|
||||
let (_, index) = rt.store().create_wiki(&wiki_name).map_err_trace_exit_unwrap(1);
|
||||
|
||||
let _ = rt
|
||||
.report_touched(index.get_location())
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
}
|
||||
|
||||
fn show(rt: &Runtime, wiki_name: &str) {
|
||||
|
@ -239,6 +248,10 @@ fn show(rt: &Runtime, wiki_name: &str) {
|
|||
writeln!(outlock, "{}", entry.get_content())
|
||||
.to_exit_code()
|
||||
.unwrap_or_exit();
|
||||
|
||||
let _ = rt
|
||||
.report_touched(entry.get_location())
|
||||
.map_err_trace_exit_unwrap(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -104,3 +104,14 @@ Commandline interfaces should also provide a flag "-I" (that's a big i) which
|
|||
marks that the store IDs shall be read from stdin and are not passed via the
|
||||
commandline.
|
||||
|
||||
|
||||
### IO
|
||||
|
||||
There are minor restrictions how imag tools should do IO. A good rule of thumb
|
||||
is (but most certainly only applicable when programming an imag tool in Rust):
|
||||
use `libimagrt` to do IO of any kind.
|
||||
|
||||
For more information, or if not using Rust as programming language: the
|
||||
documentation of `libimagrt` describes how IO should happen (which output
|
||||
stream to use, how input should be done).
|
||||
|
||||
|
|
|
@ -9,6 +9,82 @@ It also contains the store object and creates it from configuration.
|
|||
the `libimagrt::runtime::Runtime` object is the first complex object that comes
|
||||
to live in a imag binary.
|
||||
|
||||
|
||||
### IO with libimagrt
|
||||
|
||||
libimagrt also provides IO primitives which should be used by all imag tools and
|
||||
libraries:
|
||||
|
||||
The IO story in imag is pretty easy. As imag is mainly a CLI tool, IO is either
|
||||
`stdout` or `stderr` and `stdin`.
|
||||
|
||||
|
||||
#### Output
|
||||
|
||||
libimagrt provides getters for an output stream for "normal" output, like
|
||||
logging, status information, etc. It also provides an output for "touched
|
||||
entries".
|
||||
|
||||
Whenever an imag tool touches an entry in any way (either reading or writing),
|
||||
it should report this to libimagrt. libimagrt then does "the right thing" which
|
||||
is printing it to stdout or swallowing the output.
|
||||
Normal output (logging, status information, explicitely queried information)
|
||||
goes to the right sink automatically, that is:
|
||||
|
||||
* If the user provides the appropriate flags, normal output goes to `stderr` and
|
||||
"touched entries" go to `stdout`. This allows a user to 'chain' imag calls.
|
||||
* If the user does not provide these flags, normal output goes to `stdout` (for
|
||||
piping to other tools, e.g. `grep`) and "touched entries" are not printed.
|
||||
|
||||
* `stdin` can be used for reading store-ids which shall be processed by an imag
|
||||
tool. For example `imag-tag` can receive a list of entries to add tags to via
|
||||
`stdin` like this: `echo some/entry some/other | imag tag -I add sometag`.
|
||||
|
||||
With these two settings in place, calls to imag can be chained and mixed with
|
||||
external tools pretty easily:
|
||||
|
||||
```
|
||||
imag -O ids where 'some.header == 1' | \
|
||||
imag -I -O tag add foo | \
|
||||
imag -I -O category set bar | \
|
||||
fzf | \
|
||||
imag -I tag add baz
|
||||
```
|
||||
|
||||
The first line gets all imag entries where `some.header` equals `1`. The touched
|
||||
entries are printed to `stdout` (`-O`).
|
||||
The second line tags all entries which are passed via `stdin` (`-I`) with `foo`
|
||||
and prints them to `stdout` (`-O`)
|
||||
The third line sets the category for all entries which are passed via `stdin`
|
||||
with `bar` and prints them to `stdout`.
|
||||
The fourth line calls the `fzf` program and lets the user select one entry
|
||||
and the last line reads that entry via `stdin` and tags it with `baz`.
|
||||
|
||||
Automatically detecting the appropriate input/output settings is possible, but
|
||||
hidden behind a environment-flag, as it is considered experimental.
|
||||
To test this, set `IMAG_IO_EXPERIMENTAL=1` in your environment.
|
||||
Note that `stdin` may be detected as "store id stream" when it is actually not.
|
||||
`libimagrt` can take care of this when passing `--interactive`.
|
||||
|
||||
|
||||
#### Input
|
||||
|
||||
`libimagrt` also provides primitives for input. As documented in the paragraph
|
||||
on "Output", imag tools may get store ids passed via `stdin`.
|
||||
Hence, imag tools may/can not interactive when passing store ids via `stdin`.
|
||||
`libimagrt` provides functionality to query data from the user. These functions
|
||||
automatically fail if the user passes store-ids via `stdin`.
|
||||
|
||||
The next paragraph documents the details of this and may be skipped.
|
||||
|
||||
The user tells imag that `stdin` contains store-ids by setting the `-I`
|
||||
(`--ids-in`) flag on the commandline. If that flag is given, the interactive
|
||||
functionality of libimagrt automatically returns an `Err(_)` which can be used
|
||||
to tell the user what happened and exit the program accordingly.
|
||||
The user may also provide `--interactive` to tell imag via libimagrt that
|
||||
`stdin` is indeed not a stream of store-ids even if a pipe is detected.
|
||||
|
||||
|
||||
### Long-term TODO
|
||||
|
||||
- [ ] Merge with `libimagstore`
|
||||
|
|
|
@ -23,6 +23,8 @@ use std::env;
|
|||
use std::process::exit;
|
||||
use std::io::Stdin;
|
||||
use std::sync::Arc;
|
||||
use std::io::StdoutLock;
|
||||
use std::borrow::Borrow;
|
||||
|
||||
pub use clap::App;
|
||||
use clap::AppSettings;
|
||||
|
@ -42,9 +44,11 @@ use io::OutputProxy;
|
|||
use libimagerror::errors::ErrorMsg as EM;
|
||||
use libimagerror::trace::*;
|
||||
use libimagstore::store::Store;
|
||||
use libimagstore::storeid::StoreId;
|
||||
use libimagstore::file_abstraction::InMemoryFileAbstraction;
|
||||
use libimagutil::debug_result::DebugResult;
|
||||
use spec::CliSpec;
|
||||
use atty;
|
||||
|
||||
/// The Runtime object
|
||||
///
|
||||
|
@ -55,6 +59,9 @@ pub struct Runtime<'a> {
|
|||
configuration: Option<Value>,
|
||||
cli_matches: ArgMatches<'a>,
|
||||
store: Store,
|
||||
|
||||
has_output_pipe: bool,
|
||||
has_input_pipe: bool,
|
||||
}
|
||||
|
||||
impl<'a> Runtime<'a> {
|
||||
|
@ -137,11 +144,20 @@ impl<'a> Runtime<'a> {
|
|||
Store::new(storepath, &config)
|
||||
};
|
||||
|
||||
let has_output_pipe = !atty::is(atty::Stream::Stdout);
|
||||
let has_input_pipe = !atty::is(atty::Stream::Stdin);
|
||||
|
||||
debug!("has output pipe = {}", has_output_pipe);
|
||||
debug!("has input pipe = {}", has_input_pipe);
|
||||
|
||||
store_result.map(|store| Runtime {
|
||||
cli_matches: matches,
|
||||
configuration: config,
|
||||
rtp: rtp,
|
||||
store: store,
|
||||
|
||||
has_output_pipe,
|
||||
has_input_pipe,
|
||||
})
|
||||
.context(err_msg("Cannot instantiate runtime"))
|
||||
.map_err(Error::from)
|
||||
|
@ -373,6 +389,33 @@ impl<'a> Runtime<'a> {
|
|||
&self.cli_matches
|
||||
}
|
||||
|
||||
pub fn ids_from_stdin(&self) -> bool {
|
||||
self.has_input_pipe
|
||||
}
|
||||
|
||||
pub fn ids<T: IdPathProvider>(&self) -> Result<Vec<StoreId>> {
|
||||
use std::io::Read;
|
||||
|
||||
if self.has_input_pipe {
|
||||
trace!("Getting IDs from stdin...");
|
||||
let stdin = ::std::io::stdin();
|
||||
let mut lock = stdin.lock();
|
||||
|
||||
let mut buf = String::new();
|
||||
lock.read_to_string(&mut buf)
|
||||
.map_err(Error::from)
|
||||
.and_then(|_| {
|
||||
trace!("Got IDs = {}", buf);
|
||||
buf.lines()
|
||||
.map(PathBuf::from)
|
||||
.map(|id| StoreId::new_baseless(id).map_err(Error::from))
|
||||
.collect()
|
||||
})
|
||||
} else {
|
||||
Ok(T::get_ids(self.cli()))
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the configuration object
|
||||
pub fn config(&self) -> Option<&Value> {
|
||||
self.configuration.as_ref()
|
||||
|
@ -414,8 +457,16 @@ impl<'a> Runtime<'a> {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn output_is_pipe(&self) -> bool {
|
||||
self.has_output_pipe
|
||||
}
|
||||
|
||||
pub fn stdout(&self) -> OutputProxy {
|
||||
OutputProxy::Out(::std::io::stdout())
|
||||
if self.output_is_pipe() {
|
||||
OutputProxy::Err(::std::io::stderr())
|
||||
} else {
|
||||
OutputProxy::Out(::std::io::stdout())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn stderr(&self) -> OutputProxy {
|
||||
|
@ -423,7 +474,11 @@ impl<'a> Runtime<'a> {
|
|||
}
|
||||
|
||||
pub fn stdin(&self) -> Option<Stdin> {
|
||||
Some(::std::io::stdin())
|
||||
if self.has_input_pipe {
|
||||
None
|
||||
} else {
|
||||
Some(::std::io::stdin())
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper for handling subcommands which are not available.
|
||||
|
@ -504,6 +559,71 @@ impl<'a> Runtime<'a> {
|
|||
.context(EM::IO)
|
||||
.map_err(Error::from)
|
||||
}
|
||||
|
||||
pub fn report_touched(&self, id: &StoreId) -> Result<()> {
|
||||
let out = ::std::io::stdout();
|
||||
let mut lock = out.lock();
|
||||
|
||||
self.report_touched_id(id, &mut lock)
|
||||
}
|
||||
|
||||
pub fn report_all_touched<ID, I>(&self, ids: I) -> Result<()>
|
||||
where ID: Borrow<StoreId> + Sized,
|
||||
I: Iterator<Item = ID>
|
||||
{
|
||||
let out = ::std::io::stdout();
|
||||
let mut lock = out.lock();
|
||||
|
||||
for id in ids {
|
||||
self.report_touched_id(id.borrow(), &mut lock)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn report_touched_id(&self, id: &StoreId, output: &mut StdoutLock) -> Result<()> {
|
||||
use std::io::Write;
|
||||
|
||||
if self.output_is_pipe() {
|
||||
trace!("Reporting: {} to {:?}", id, output);
|
||||
writeln!(output, "{}", id)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// A trait for the path provider functionality
|
||||
///
|
||||
/// This trait can be implement on a type so that it can provide IDs when given a ArgMatches
|
||||
/// object.
|
||||
///
|
||||
/// It can be used with Runtime::ids() and libimagrt handles "stdin-provides-ids" cases
|
||||
/// automatically:
|
||||
///
|
||||
/// ```ignore
|
||||
/// runtime.ids::<PathProvider>()?.iter().for_each(|id| /* ... */)
|
||||
/// ```
|
||||
///
|
||||
/// libimagrt does not call the PathProvider if the ids are provided by piping to stdin.
|
||||
///
|
||||
///
|
||||
/// # Passed arguments
|
||||
///
|
||||
/// The arguments which are passed into the IdPathProvider::get_ids() function are the _top level
|
||||
/// ArgMatches_. Traversing might be required in the implementation of the ::get_ids() function.
|
||||
///
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// In case of error, the IdPathProvider::get_ids() function should exit the application
|
||||
/// with the appropriate error message(s).
|
||||
///
|
||||
/// On success, the StoreId objects to operate on are returned from the ArgMatches.
|
||||
///
|
||||
pub trait IdPathProvider {
|
||||
fn get_ids(matches: &ArgMatches) -> Vec<StoreId>;
|
||||
}
|
||||
|
||||
/// Exported for the `imag` command, you probably do not want to use that.
|
||||
|
|
|
@ -34,6 +34,7 @@ use libimagstore::store::Store;
|
|||
use libimagstore::store::Entry;
|
||||
use libimagstore::store::FileLockEntry;
|
||||
use libimagstore::storeid::IntoStoreId;
|
||||
use libimagstore::storeid::StoreId;
|
||||
use libimagentrylink::external::ExternalLinker;
|
||||
use libimagentrylink::external::iter::UrlIter;
|
||||
use libimagentrylink::internal::InternalLinker;
|
||||
|
@ -76,10 +77,10 @@ impl<'a> BookmarkCollectionStore<'a> for Store {
|
|||
|
||||
pub trait BookmarkCollection : Sized + InternalLinker + ExternalLinker {
|
||||
fn links<'a>(&self, store: &'a Store) -> Result<UrlIter<'a>>;
|
||||
fn link_entries(&self) -> Result<Vec<StoreLink>>;
|
||||
fn add_link(&mut self, store: &Store, l: Link) -> Result<()>;
|
||||
fn link_entries(&self) -> Result<Vec<StoreLink>>;
|
||||
fn add_link(&mut self, store: &Store, l: Link) -> Result<Vec<StoreId>>;
|
||||
fn get_links_matching<'a>(&self, store: &'a Store, r: Regex) -> Result<LinksMatchingRegexIter<'a>>;
|
||||
fn remove_link(&mut self, store: &Store, l: Link) -> Result<()>;
|
||||
fn remove_link(&mut self, store: &Store, l: Link) -> Result<Vec<StoreId>>;
|
||||
}
|
||||
|
||||
impl BookmarkCollection for Entry {
|
||||
|
@ -93,7 +94,7 @@ impl BookmarkCollection for Entry {
|
|||
self.get_internal_links().map(|v| v.filter(|id| is_external_link_storeid(id)).collect())
|
||||
}
|
||||
|
||||
fn add_link(&mut self, store: &Store, l: Link) -> Result<()> {
|
||||
fn add_link(&mut self, store: &Store, l: Link) -> Result<Vec<StoreId>> {
|
||||
use link::IntoUrl;
|
||||
l.into_url().and_then(|url| self.add_external_link(store, url))
|
||||
}
|
||||
|
@ -103,7 +104,7 @@ impl BookmarkCollection for Entry {
|
|||
self.get_external_links(store).map(|iter| iter.matching_regex(r))
|
||||
}
|
||||
|
||||
fn remove_link(&mut self, store: &Store, l: Link) -> Result<()> {
|
||||
fn remove_link(&mut self, store: &Store, l: Link) -> Result<Vec<StoreId>> {
|
||||
use link::IntoUrl;
|
||||
l.into_url().and_then(|url| self.remove_external_link(store, url))
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
//
|
||||
|
||||
use libimagstore::store::FileLockEntry;
|
||||
use libimagstore::store::Store;
|
||||
use libimagstore::storeid::StoreId;
|
||||
use libimagstore::storeid::IntoStoreId;
|
||||
|
@ -30,10 +31,10 @@ pub trait WikiStore {
|
|||
fn get_wiki<'a, 'b>(&'a self, name: &'b str) -> Result<Option<Wiki<'a, 'b>>>;
|
||||
|
||||
fn create_wiki<'a, 'b>(&'a self, name: &'b str)
|
||||
-> Result<Wiki<'a, 'b>>;
|
||||
-> Result<(Wiki<'a, 'b>, FileLockEntry<'a>)>;
|
||||
|
||||
fn retrieve_wiki<'a, 'b>(&'a self, name: &'b str)
|
||||
-> Result<Wiki<'a, 'b>>;
|
||||
-> Result<(Wiki<'a, 'b>, FileLockEntry<'a>)>;
|
||||
|
||||
}
|
||||
|
||||
|
@ -59,20 +60,23 @@ impl WikiStore for Store {
|
|||
/// Ob success, an empty Wiki entry with the name `index` is created inside the wiki. Later, new
|
||||
/// entries are automatically linked to this entry.
|
||||
///
|
||||
fn create_wiki<'a, 'b>(&'a self, name: &'b str) -> Result<Wiki<'a, 'b>> {
|
||||
fn create_wiki<'a, 'b>(&'a self, name: &'b str) -> Result<(Wiki<'a, 'b>, FileLockEntry<'a>)> {
|
||||
debug!("Trying to get wiki '{}'", name);
|
||||
|
||||
let wiki = Wiki::new(self, name);
|
||||
let _ = wiki.create_index_page()?;
|
||||
Ok(wiki)
|
||||
let index = wiki.create_index_page()?;
|
||||
Ok((wiki, index))
|
||||
}
|
||||
|
||||
fn retrieve_wiki<'a, 'b>(&'a self, name: &'b str)
|
||||
-> Result<Wiki<'a, 'b>>
|
||||
-> Result<(Wiki<'a, 'b>, FileLockEntry<'a>)>
|
||||
{
|
||||
match self.get_wiki(name)? {
|
||||
None => self.create_wiki(name),
|
||||
Some(wiki) => Ok(wiki),
|
||||
Some(wiki) => {
|
||||
let index = wiki.get_index_page()?;
|
||||
Ok((wiki, index))
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@ use libimagstore::storeid::StoreIdIteratorWithStore;
|
|||
use libimagentrylink::internal::InternalLinker;
|
||||
|
||||
use failure::Fallible as Result;
|
||||
use failure::Error;
|
||||
use failure::err_msg;
|
||||
|
||||
pub struct Wiki<'a, 'b>(&'a Store, &'b str);
|
||||
|
@ -56,6 +57,16 @@ impl<'a, 'b> Wiki<'a, 'b> {
|
|||
self.0.create(sid)
|
||||
}
|
||||
|
||||
pub(crate) fn get_index_page(&self) -> Result<FileLockEntry<'a>> {
|
||||
let path = PathBuf::from(format!("{}/index", self.1));
|
||||
let sid = ::module_path::ModuleEntryPath::new(path).into_storeid()?;
|
||||
|
||||
self.0
|
||||
.get(sid)
|
||||
.map_err(Error::from)?
|
||||
.ok_or_else(|| Error::from(err_msg("Missing index")))
|
||||
}
|
||||
|
||||
pub fn get_entry<EN: AsRef<str>>(&self, entry_name: EN) -> Result<Option<FileLockEntry<'a>>> {
|
||||
let path = PathBuf::from(format!("{}/{}", self.1, entry_name.as_ref()));
|
||||
let sid = ::module_path::ModuleEntryPath::new(path).into_storeid()?;
|
||||
|
|
|
@ -108,13 +108,13 @@ pub trait ExternalLinker : InternalLinker {
|
|||
fn get_external_links<'a>(&self, store: &'a Store) -> Result<UrlIter<'a>>;
|
||||
|
||||
/// Set the external links for the implementor object
|
||||
fn set_external_links(&mut self, store: &Store, links: Vec<Url>) -> Result<()>;
|
||||
fn set_external_links(&mut self, store: &Store, links: Vec<Url>) -> Result<Vec<StoreId>>;
|
||||
|
||||
/// Add an external link to the implementor object
|
||||
fn add_external_link(&mut self, store: &Store, link: Url) -> Result<()>;
|
||||
fn add_external_link(&mut self, store: &Store, link: Url) -> Result<Vec<StoreId>>;
|
||||
|
||||
/// Remove an external link from the implementor object
|
||||
fn remove_external_link(&mut self, store: &Store, link: Url) -> Result<()>;
|
||||
fn remove_external_link(&mut self, store: &Store, link: Url) -> Result<Vec<StoreId>>;
|
||||
|
||||
}
|
||||
|
||||
|
@ -322,13 +322,20 @@ impl ExternalLinker for Entry {
|
|||
}
|
||||
|
||||
/// Set the external links for the implementor object
|
||||
fn set_external_links(&mut self, store: &Store, links: Vec<Url>) -> Result<()> {
|
||||
///
|
||||
/// # Return Value
|
||||
///
|
||||
/// Returns the StoreIds which were newly created for the new external links, if there are more
|
||||
/// external links than before.
|
||||
/// If there are less external links than before, an empty vec![] is returned.
|
||||
///
|
||||
fn set_external_links(&mut self, store: &Store, links: Vec<Url>) -> Result<Vec<StoreId>> {
|
||||
// Take all the links, generate a SHA sum out of each one, filter out the already existing
|
||||
// store entries and store the other URIs in the header of one FileLockEntry each, in
|
||||
// the path /link/external/<SHA of the URL>
|
||||
|
||||
debug!("Iterating {} links = {:?}", links.len(), links);
|
||||
for link in links { // for all links
|
||||
links.into_iter().map(|link| {
|
||||
let hash = hex::encode(Sha1::digest(&link.as_str().as_bytes()));
|
||||
let file_id =
|
||||
ModuleEntryPath::new(format!("external/{}", hash)).into_storeid()
|
||||
|
@ -341,6 +348,8 @@ impl ExternalLinker for Entry {
|
|||
debug!("Hash = '{:?}'", hash);
|
||||
debug!("StoreId = '{:?}'", file_id);
|
||||
|
||||
let link_already_exists = store.get(file_id.clone())?.is_some();
|
||||
|
||||
// retrieve the file from the store, which implicitely creates the entry if it does not
|
||||
// exist
|
||||
let mut file = store
|
||||
|
@ -375,13 +384,27 @@ impl ExternalLinker for Entry {
|
|||
// then add an internal link to the new file or return an error if this fails
|
||||
let _ = self.add_internal_link(file.deref_mut())?;
|
||||
debug!("Error adding internal link");
|
||||
}
|
||||
debug!("Ready iterating");
|
||||
Ok(())
|
||||
|
||||
Ok((link_already_exists, file_id))
|
||||
})
|
||||
.filter_map(|res| match res {
|
||||
Ok((exists, entry)) => if exists { Some(Ok(entry)) } else { None },
|
||||
Err(e) => Some(Err(e))
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Add an external link to the implementor object
|
||||
fn add_external_link(&mut self, store: &Store, link: Url) -> Result<()> {
|
||||
///
|
||||
/// # Return Value
|
||||
///
|
||||
/// (See ExternalLinker::set_external_links())
|
||||
///
|
||||
/// Returns the StoreIds which were newly created for the new external links, if there are more
|
||||
/// external links than before.
|
||||
/// If there are less external links than before, an empty vec![] is returned.
|
||||
///
|
||||
fn add_external_link(&mut self, store: &Store, link: Url) -> Result<Vec<StoreId>> {
|
||||
// get external links, add this one, save them
|
||||
debug!("Getting links");
|
||||
self.get_external_links(store)
|
||||
|
@ -396,7 +419,16 @@ impl ExternalLinker for Entry {
|
|||
}
|
||||
|
||||
/// Remove an external link from the implementor object
|
||||
fn remove_external_link(&mut self, store: &Store, link: Url) -> Result<()> {
|
||||
///
|
||||
/// # Return Value
|
||||
///
|
||||
/// (See ExternalLinker::set_external_links())
|
||||
///
|
||||
/// Returns the StoreIds which were newly created for the new external links, if there are more
|
||||
/// external links than before.
|
||||
/// If there are less external links than before, an empty vec![] is returned.
|
||||
///
|
||||
fn remove_external_link(&mut self, store: &Store, link: Url) -> Result<Vec<StoreId>> {
|
||||
// get external links, remove this one, save them
|
||||
self.get_external_links(store)
|
||||
.and_then(|links| {
|
||||
|
|
Loading…
Reference in a new issue