diff --git a/bin/core/imag-mv/Cargo.toml b/bin/core/imag-mv/Cargo.toml index 8dd5e0d2..41df6adc 100644 --- a/bin/core/imag-mv/Cargo.toml +++ b/bin/core/imag-mv/Cargo.toml @@ -21,6 +21,7 @@ maintenance = { status = "actively-developed" } [dependencies] log = "0.4.6" +failure = "0.1.5" libimagrt = { version = "0.10.0", path = "../../../lib/core/libimagrt" } libimagerror = { version = "0.10.0", path = "../../../lib/core/libimagerror" } @@ -32,3 +33,10 @@ version = "2.33.0" default-features = false features = ["color", "suggestions", "wrap_help"] +[lib] +name = "libimagmvcmd" +path = "src/lib.rs" + +[[bin]] +name = "imag-mv" +path = "src/bin.rs" diff --git a/bin/core/imag-mv/src/bin.rs b/bin/core/imag-mv/src/bin.rs new file mode 100644 index 00000000..36285798 --- /dev/null +++ b/bin/core/imag-mv/src/bin.rs @@ -0,0 +1,39 @@ +// +// imag - the personal information management suite for the commandline +// Copyright (C) 2015-2019 Matthias Beyer and contributors +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; version +// 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +// + +#![forbid(unsafe_code)] + +#![deny( + non_camel_case_types, + non_snake_case, + path_statements, + trivial_numeric_casts, + unstable_features, + unused_allocation, + unused_import_braces, + unused_imports, + unused_must_use, + unused_mut, + unused_qualifications, + while_true, +)] + +#[macro_use] extern crate libimagrt; + +simple_imag_application_binary!(libimagmvcmd, ImagMv); diff --git a/bin/core/imag-mv/src/lib.rs b/bin/core/imag-mv/src/lib.rs new file mode 100644 index 00000000..4107e7b3 --- /dev/null +++ b/bin/core/imag-mv/src/lib.rs @@ -0,0 +1,181 @@ +// +// imag - the personal information management suite for the commandline +// Copyright (C) 2015-2019 Matthias Beyer and contributors +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; version +// 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +// + +#![forbid(unsafe_code)] + +#![deny( + non_camel_case_types, + non_snake_case, + path_statements, + trivial_numeric_casts, + unstable_features, + unused_allocation, + unused_import_braces, + unused_imports, + unused_must_use, + unused_mut, + unused_qualifications, + while_true, +)] + +#[macro_use] extern crate log; +extern crate clap; +extern crate failure; + +extern crate libimagrt; +extern crate libimagstore; +extern crate libimagerror; +extern crate libimagentrylink; + +use std::process::exit; + +mod ui; + +use std::path::PathBuf; +use std::result::Result as RResult; + +use libimagrt::runtime::Runtime; +use libimagrt::application::ImagApplication; +use libimagerror::trace::MapErrTrace; +use libimagerror::iter::TraceIterator; +use libimagerror::exit::ExitUnwrap; +use libimagstore::storeid::StoreId; +use libimagstore::store::Store; +use libimagstore::store::FileLockEntry; +use libimagentrylink::linkable::Linkable; +use libimagstore::iter::get::StoreIdGetIteratorExtension; + +use failure::Fallible as Result; +use clap::App; + + +/// Marker enum for implementing ImagApplication on +/// +/// This is used by binaries crates to execute business logic +/// or to build a CLI completion. +pub enum ImagMv {} +impl ImagApplication for ImagMv { + fn run(rt: Runtime) -> Result<()> { + let sourcename = rt + .cli() + .value_of("source") + .map(PathBuf::from) + .map(StoreId::new) + .unwrap() // unwrap safe by clap + .map_err_trace_exit_unwrap(); + + let destname = rt + .cli() + .value_of("dest") + .map(PathBuf::from) + .map(StoreId::new) + .unwrap() // unwrap safe by clap + .map_err_trace_exit_unwrap(); + + // remove links to entry, and re-add them later + let mut linked_entries = { + rt.store() + .get(sourcename.clone()) + .map_err_trace_exit_unwrap() + .unwrap_or_else(|| { + error!("Funny things happened: Entry moved to destination did not fail, but entry does not exist"); + exit(1) + }) + .links() + .map_err_trace_exit_unwrap() + .map(|link| Ok(link.get_store_id().clone()) as RResult<_, _>) + .into_get_iter(rt.store()) + .trace_unwrap_exit() + .map(|e| { + e.unwrap_or_else(|| { + error!("Linked entry does not exist"); + exit(1) + }) + }) + .collect::>() + }; + + { // remove links to linked entries from source + let mut entry = rt + .store() + .get(sourcename.clone()) + .map_err_trace_exit_unwrap() + .unwrap_or_else(|| { + error!("Source Entry does not exist"); + exit(1) + }); + + for link in linked_entries.iter_mut() { + let _ = entry.remove_link(link).map_err_trace_exit_unwrap(); + } + } + + let _ = rt + .store() + .move_by_id(sourcename.clone(), destname.clone()) + .map_err(|e| { // on error, re-add links + debug!("Re-adding links to source entry because moving failed"); + relink(rt.store(), sourcename.clone(), &mut linked_entries); + e + }) + .map_err_trace_exit_unwrap(); + + let _ = rt.report_touched(&destname).unwrap_or_exit(); + + // re-add links to moved entry + relink(rt.store(), destname, &mut linked_entries); + + info!("Ok."); + + Ok(()) + } + + fn build_cli<'a>(app: App<'a, 'a>) -> App<'a, 'a> { + ui::build_ui(app) + } + + fn name() -> &'static str { + env!("CARGO_PKG_NAME") + } + + fn description() -> &'static str { + "Move things around in the store" + } + + fn version() -> &'static str { + env!("CARGO_PKG_VERSION") + } +} + + + +fn relink<'a>(store: &'a Store, target: StoreId, linked_entries: &mut Vec>) { + let mut entry = store + .get(target) + .map_err_trace_exit_unwrap() + .unwrap_or_else(|| { + error!("Funny things happened: Entry moved to destination did not fail, but entry does not exist"); + exit(1) + }); + + + for mut link in linked_entries { + let _ = entry.add_link(&mut link).map_err_trace_exit_unwrap(); + } +} diff --git a/bin/core/imag-mv/src/main.rs b/bin/core/imag-mv/src/main.rs deleted file mode 100644 index 27393279..00000000 --- a/bin/core/imag-mv/src/main.rs +++ /dev/null @@ -1,156 +0,0 @@ -// -// imag - the personal information management suite for the commandline -// Copyright (C) 2015-2019 Matthias Beyer and contributors -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; version -// 2.1 of the License. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -// - -#![forbid(unsafe_code)] - -#![deny( - non_camel_case_types, - non_snake_case, - path_statements, - trivial_numeric_casts, - unstable_features, - unused_allocation, - unused_import_braces, - unused_imports, - unused_must_use, - unused_mut, - unused_qualifications, - while_true, -)] - -#[macro_use] extern crate log; -extern crate clap; - -#[macro_use] extern crate libimagrt; -extern crate libimagstore; -extern crate libimagerror; -extern crate libimagentrylink; - -use std::process::exit; - -mod ui; -use crate::ui::build_ui; - -use std::path::PathBuf; - -use libimagrt::setup::generate_runtime_setup; -use libimagerror::trace::MapErrTrace; -use libimagerror::iter::TraceIterator; -use libimagerror::exit::ExitUnwrap; -use libimagstore::storeid::StoreId; -use libimagstore::store::Store; -use libimagstore::store::FileLockEntry; -use libimagentrylink::linkable::Linkable; -use libimagstore::iter::get::StoreIdGetIteratorExtension; - -fn main() { - let version = make_imag_version!(); - let rt = generate_runtime_setup("imag-mv", - &version, - "Move things around in the store", - build_ui); - - debug!("mv"); - - let sourcename = rt - .cli() - .value_of("source") - .map(PathBuf::from) - .map(StoreId::new) - .unwrap() // unwrap safe by clap - .map_err_trace_exit_unwrap(); - - let destname = rt - .cli() - .value_of("dest") - .map(PathBuf::from) - .map(StoreId::new) - .unwrap() // unwrap safe by clap - .map_err_trace_exit_unwrap(); - - // remove links to entry, and re-add them later - let mut linked_entries = { - rt.store() - .get(sourcename.clone()) - .map_err_trace_exit_unwrap() - .unwrap_or_else(|| { - error!("Funny things happened: Entry moved to destination did not fail, but entry does not exist"); - exit(1) - }) - .links() - .map_err_trace_exit_unwrap() - .map(|link| Ok(link.get_store_id().clone()) as Result<_, _>) - .into_get_iter(rt.store()) - .trace_unwrap_exit() - .map(|e| { - e.unwrap_or_else(|| { - error!("Linked entry does not exist"); - exit(1) - }) - }) - .collect::>() - }; - - { // remove links to linked entries from source - let mut entry = rt - .store() - .get(sourcename.clone()) - .map_err_trace_exit_unwrap() - .unwrap_or_else(|| { - error!("Source Entry does not exist"); - exit(1) - }); - - for link in linked_entries.iter_mut() { - entry.remove_link(link).map_err_trace_exit_unwrap(); - } - } - - rt - .store() - .move_by_id(sourcename.clone(), destname.clone()) - .map_err(|e| { // on error, re-add links - debug!("Re-adding links to source entry because moving failed"); - relink(rt.store(), sourcename.clone(), &mut linked_entries); - e - }) - .map_err_trace_exit_unwrap(); - - rt.report_touched(&destname).unwrap_or_exit(); - - // re-add links to moved entry - relink(rt.store(), destname, &mut linked_entries); - - info!("Ok."); -} - -fn relink<'a>(store: &'a Store, target: StoreId, linked_entries: &mut Vec>) { - let mut entry = store - .get(target) - .map_err_trace_exit_unwrap() - .unwrap_or_else(|| { - error!("Funny things happened: Entry moved to destination did not fail, but entry does not exist"); - exit(1) - }); - - - for mut link in linked_entries { - entry.add_link(&mut link).map_err_trace_exit_unwrap(); - } -}