diff --git a/bin/core/imag-annotate/Cargo.toml b/bin/core/imag-annotate/Cargo.toml index 1d3d9ce0..63cdc07c 100644 --- a/bin/core/imag-annotate/Cargo.toml +++ b/bin/core/imag-annotate/Cargo.toml @@ -39,3 +39,10 @@ version = "2.33.0" default-features = false features = ["color", "suggestions", "wrap_help"] +[lib] +name = "libimagannotatecmd" +path = "src/lib.rs" + +[[bin]] +name = "imag-annotate" +path = "src/bin.rs" diff --git a/bin/core/imag-annotate/src/bin.rs b/bin/core/imag-annotate/src/bin.rs new file mode 100644 index 00000000..cae358af --- /dev/null +++ b/bin/core/imag-annotate/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!(libimagannotatecmd, ImagAnnotate); diff --git a/bin/core/imag-annotate/src/main.rs b/bin/core/imag-annotate/src/lib.rs similarity index 87% rename from bin/core/imag-annotate/src/main.rs rename to bin/core/imag-annotate/src/lib.rs index d1d269bd..e2501985 100644 --- a/bin/core/imag-annotate/src/main.rs +++ b/bin/core/imag-annotate/src/lib.rs @@ -44,7 +44,7 @@ extern crate toml_query; extern crate libimagentryannotation; extern crate libimagentryedit; extern crate libimagerror; -#[macro_use] extern crate libimagrt; +extern crate libimagrt; extern crate libimagstore; extern crate libimagutil; extern crate libimagentrylink; @@ -52,7 +52,9 @@ extern crate libimagentrylink; use std::io::Write; use failure::Error; +use failure::Fallible as Result; use toml_query::read::TomlValueReadTypeExt; +use clap::App; use libimagentryannotation::annotateable::*; use libimagentryannotation::annotation_fetcher::*; @@ -63,33 +65,48 @@ use libimagerror::io::ToExitCode; use libimagerror::errors::ErrorMsg as EM; use libimagerror::iter::TraceIterator; use libimagrt::runtime::Runtime; -use libimagrt::setup::generate_runtime_setup; +use libimagrt::application::ImagApplication; use libimagstore::store::FileLockEntry; use libimagstore::iter::get::StoreIdGetIteratorExtension; use libimagentrylink::linkable::Linkable; mod ui; -fn main() { - let version = make_imag_version!(); - let rt = generate_runtime_setup("imag-annotation", - &version, - "Add annotations to entries", - ui::build_ui); - - if let Some(name) = rt.cli().subcommand_name() { - match name { - "add" => add(&rt), - "remove" => remove(&rt), - "list" => list(&rt), - other => { - debug!("Unknown command"); - let _ = rt.handle_unknown_subcommand("imag-annotation", other, rt.cli()) - .map_err_trace_exit_unwrap() - .code() - .map(::std::process::exit); - }, +pub enum ImagAnnotate {} +impl ImagApplication for ImagAnnotate { + fn run(rt: Runtime) -> Result<()> { + if let Some(name) = rt.cli().subcommand_name() { + match name { + "add" => add(&rt), + "remove" => remove(&rt), + "list" => list(&rt), + other => { + debug!("Unknown command"); + let _ = rt.handle_unknown_subcommand("imag-annotation", other, rt.cli()) + .map_err_trace_exit_unwrap() + .code() + .map(::std::process::exit); + }, + } } + + 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 { + "Add annotations to entries" + } + + fn version() -> &'static str { + env!("CARGO_PKG_VERSION") } } diff --git a/bin/core/imag-category/Cargo.toml b/bin/core/imag-category/Cargo.toml index 6294a3c6..afc09fbb 100644 --- a/bin/core/imag-category/Cargo.toml +++ b/bin/core/imag-category/Cargo.toml @@ -36,3 +36,10 @@ version = "2.33.0" default-features = false features = ["color", "suggestions", "wrap_help"] +[lib] +name = "libimagcategorycmd" +path = "src/lib.rs" + +[[bin]] +name = "imag-category" +path = "src/bin.rs" diff --git a/bin/core/imag-category/src/bin.rs b/bin/core/imag-category/src/bin.rs new file mode 100644 index 00000000..e3120cae --- /dev/null +++ b/bin/core/imag-category/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!(libimagcategorycmd, ImagCategory); diff --git a/bin/core/imag-category/src/main.rs b/bin/core/imag-category/src/lib.rs similarity index 79% rename from bin/core/imag-category/src/main.rs rename to bin/core/imag-category/src/lib.rs index 44a87c12..a40bd632 100644 --- a/bin/core/imag-category/src/main.rs +++ b/bin/core/imag-category/src/lib.rs @@ -42,15 +42,18 @@ extern crate failure; extern crate libimagentrycategory; extern crate libimagerror; -#[macro_use] extern crate libimagrt; +extern crate libimagrt; extern crate libimagstore; extern crate libimaginteraction; +use failure::Fallible as Result; +use clap::App; + use libimagerror::trace::MapErrTrace; use libimagerror::exit::ExitUnwrap; use libimagerror::io::ToExitCode; use libimagrt::runtime::Runtime; -use libimagrt::setup::generate_runtime_setup; +use libimagrt::application::ImagApplication; mod ui; @@ -63,32 +66,52 @@ use libimagerror::iter::TraceIterator; use libimagentrycategory::entry::EntryCategory; use libimagentrycategory::category::Category; -fn main() { - let version = make_imag_version!(); - let rt = generate_runtime_setup("imag-category", - &version, - "Add a category to entries and manage categories", - ui::build_ui); - - if let Some(name) = rt.cli().subcommand_name() { - match name { - "set" => set(&rt), - "get" => get(&rt), - "list-category" => list_category(&rt), - "create-category" => create_category(&rt), - "delete-category" => delete_category(&rt), - "list-categories" => list_categories(&rt), - other => { - debug!("Unknown command"); - let _ = rt.handle_unknown_subcommand("imag-category", other, rt.cli()) - .map_err_trace_exit_unwrap() - .code() - .map(::std::process::exit); - }, +/// Marker enum for implementing ImagApplication on +/// +/// This is used by binaries crates to execute business logic +/// or to build a CLI completion. +pub enum ImagCategory {} +impl ImagApplication for ImagCategory { + fn run(rt: Runtime) -> Result<()> { + if let Some(name) = rt.cli().subcommand_name() { + match name { + "set" => set(&rt), + "get" => get(&rt), + "list-category" => list_category(&rt), + "create-category" => create_category(&rt), + "delete-category" => delete_category(&rt), + "list-categories" => list_categories(&rt), + other => { + debug!("Unknown command"); + let _ = rt.handle_unknown_subcommand("imag-category", other, rt.cli()) + .map_err_trace_exit_unwrap() + .code() + .map(::std::process::exit); + }, + } } + + 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 { + "Add a category to entries and manage categories" + } + + fn version() -> &'static str { + env!("CARGO_PKG_VERSION") } } + 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 diff --git a/bin/core/imag-create/Cargo.toml b/bin/core/imag-create/Cargo.toml index 4aac3d4f..fca9dedc 100644 --- a/bin/core/imag-create/Cargo.toml +++ b/bin/core/imag-create/Cargo.toml @@ -27,3 +27,10 @@ version = "2.33.0" default-features = false features = ["suggestions", "color", "wrap_help"] +[lib] +name = "libimagcreatecmd" +path = "src/lib.rs" + +[[bin]] +name = "imag-create" +path = "src/bin.rs" diff --git a/bin/core/imag-create/src/bin.rs b/bin/core/imag-create/src/bin.rs new file mode 100644 index 00000000..4f38c625 --- /dev/null +++ b/bin/core/imag-create/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!(libimagcreatecmd, ImagCreate); diff --git a/bin/core/imag-create/src/lib.rs b/bin/core/imag-create/src/lib.rs new file mode 100644 index 00000000..aca33344 --- /dev/null +++ b/bin/core/imag-create/src/lib.rs @@ -0,0 +1,105 @@ +// +// 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, +)] + +extern crate clap; +extern crate failure; +#[macro_use] extern crate log; + +extern crate libimagerror; +extern crate libimagrt; +extern crate libimagstore; + +use failure::Fallible as Result; +use clap::App; + +use libimagrt::runtime::Runtime; +use libimagrt::application::ImagApplication; +use libimagerror::trace::MapErrTrace; +use libimagstore::iter::create::StoreIdCreateIteratorExtension; +use libimagstore::iter::retrieve::StoreIdRetrieveIteratorExtension; +use libimagerror::exit::ExitUnwrap; + +mod ui; + + + +pub enum ImagCreate {} +impl ImagApplication for ImagCreate { + fn run(rt: Runtime) -> Result<()> { + let force = rt.cli().is_present("force"); + debug!("Detected force = {}", force); + + let ids = rt.ids::() + .map_err_trace_exit_unwrap() + .unwrap_or_else(|| { + error!("No ids supplied"); + ::std::process::exit(1); + }) + .into_iter() + .map(|id| { debug!("id = {}", id); id }) + .map(Ok); + + if force { + ids.into_retrieve_iter(rt.store()).collect::>>() + } else { + ids.into_create_iter(rt.store()).collect::>>() + }.map_err_trace_exit_unwrap() + .into_iter() + .for_each(|el| { + rt.report_touched(el.get_location()).unwrap_or_exit(); + trace!("Entry = {}", el.get_location()); + }); + + Ok(()) + } + + fn build_cli<'a>(app: App<'a, 'a>) -> App<'a, 'a> { + ui::build_ui(app) + } + + fn name() -> &'static str { + env!("CARGO_PKG_NAME") + } + + fn description() -> &'static str { + "Plumbing tool to create entries" + } + + fn version() -> &'static str { + env!("CARGO_PKG_VERSION") + } +} + diff --git a/bin/core/imag-create/src/main.rs b/bin/core/imag-create/src/main.rs deleted file mode 100644 index 54208981..00000000 --- a/bin/core/imag-create/src/main.rs +++ /dev/null @@ -1,84 +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 -// - -//#![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, -//)] - -extern crate clap; -extern crate failure; -#[macro_use] extern crate log; - -extern crate libimagerror; -#[macro_use] extern crate libimagrt; -extern crate libimagstore; - -use failure::Fallible as Result; - -use libimagerror::trace::MapErrTrace; -use libimagrt::setup::generate_runtime_setup; -use libimagstore::iter::create::StoreIdCreateIteratorExtension; -use libimagstore::iter::retrieve::StoreIdRetrieveIteratorExtension; -use libimagerror::exit::ExitUnwrap; - -mod ui; - -fn main() { - let version = make_imag_version!(); - let rt = generate_runtime_setup("imag-create", - &version, - "Plumbing tool creating entries", - ui::build_ui); - - let force = rt.cli().is_present("force"); - debug!("Detected force = {}", force); - - let ids = rt.ids::() - .map_err_trace_exit_unwrap() - .unwrap_or_else(|| { - error!("No ids supplied"); - ::std::process::exit(1); - }) - .into_iter() - .map(|id| { debug!("id = {}", id); id }) - .map(Ok); - - if force { - ids.into_retrieve_iter(rt.store()).collect::>>() - } else { - ids.into_create_iter(rt.store()).collect::>>() - }.map_err_trace_exit_unwrap() - .into_iter() - .for_each(|el| { - rt.report_touched(el.get_location()).unwrap_or_exit(); - trace!("Entry = {}", el.get_location()); - }); -} - diff --git a/bin/core/imag-diagnostics/Cargo.toml b/bin/core/imag-diagnostics/Cargo.toml index 97ec6047..d0c1b102 100644 --- a/bin/core/imag-diagnostics/Cargo.toml +++ b/bin/core/imag-diagnostics/Cargo.toml @@ -30,3 +30,10 @@ version = "2.33.0" default-features = false features = ["suggestions", "color", "wrap_help"] +[lib] +name = "libimagdiagnosticscmd" +path = "src/lib.rs" + +[[bin]] +name = "imag-diagnostics" +path = "src/bin.rs" diff --git a/bin/core/imag-diagnostics/src/bin.rs b/bin/core/imag-diagnostics/src/bin.rs new file mode 100644 index 00000000..351163f6 --- /dev/null +++ b/bin/core/imag-diagnostics/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!(libimagdiagnosticscmd, ImagDiagnostics); diff --git a/bin/core/imag-diagnostics/src/lib.rs b/bin/core/imag-diagnostics/src/lib.rs new file mode 100644 index 00000000..1118630f --- /dev/null +++ b/bin/core/imag-diagnostics/src/lib.rs @@ -0,0 +1,288 @@ +// +// 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, +)] + +extern crate clap; +extern crate toml; +extern crate toml_query; +extern crate indicatif; +extern crate failure; +#[macro_use] extern crate log; + +extern crate libimagrt; +extern crate libimagerror; +extern crate libimagentrylink; +extern crate libimagstore; + +use std::io::Write; + +use libimagrt::runtime::Runtime; +use libimagrt::application::ImagApplication; +use libimagerror::trace::MapErrTrace; +use libimagerror::io::ToExitCode; +use libimagerror::exit::ExitUnwrap; +use libimagstore::store::FileLockEntry; +use libimagstore::storeid::StoreId; +use libimagentrylink::linkable::Linkable; + +use toml::Value; +use toml_query::read::TomlValueReadExt; +use indicatif::{ProgressBar, ProgressStyle}; +use failure::Fallible as Result; +use failure::Error; +use failure::err_msg; +use clap::App; + +use std::collections::BTreeMap; + +mod ui; + +#[derive(Debug)] +struct Diagnostic { + pub id: StoreId, + pub entry_store_version: String, + pub header_sections: usize, + pub bytecount_content: usize, + pub overall_byte_size: usize, + pub verified: bool, + pub num_links: usize, +} + +impl Diagnostic { + + fn for_entry<'a>(entry: &FileLockEntry<'a>) -> Result { + Ok(Diagnostic { + id: entry.get_location().clone(), + entry_store_version: entry + .get_header() + .read("imag.version") + .map(|opt| match opt { + Some(&Value::String(ref s)) => s.clone(), + Some(_) => "Non-String type in 'imag.version'".to_owned(), + None => "No version".to_owned(), + }) + .unwrap_or("Error reading version".to_owned()), + header_sections: match entry.get_header() { + &Value::Table(ref map) => map.keys().count(), + _ => 0 + }, + bytecount_content: entry.get_content().as_str().len(), + overall_byte_size: entry.to_str()?.as_str().len(), + verified: entry.verify().is_ok(), + num_links: entry.links().map(Iterator::count).unwrap_or(0), + }) + } +} + +macro_rules! do_write { + ($dest:ident, $pattern:tt) => { + let _ = writeln!($dest, $pattern) + .to_exit_code() + .unwrap_or_exit(); + }; + + ($dest:ident, $pattern:tt, $( $args:expr ),*) => { + let _ = writeln!($dest, $pattern, $( $args ),*) + .to_exit_code() + .unwrap_or_exit(); + } +} + +/// Marker enum for implementing ImagApplication on +/// +/// This is used by binaries crates to execute business logic +/// or to build a CLI completion. +pub enum ImagDiagnostics {} +impl ImagApplication for ImagDiagnostics { + fn run(rt: Runtime) -> Result<()> { + let template = get_config(&rt, "rt.progressbar_style"); + let tick_chars = get_config(&rt, "rt.progressticker_chars"); + let verbose = rt.cli().is_present("more-output"); + + let style = if let Some(tick_chars) = tick_chars { + ProgressStyle::default_spinner().tick_chars(&tick_chars) + } else { + ProgressStyle::default_spinner() + }; + + let spinner = ProgressBar::new_spinner(); + spinner.enable_steady_tick(100); + spinner.set_style(style); + spinner.set_message("Accumulating data"); + + let diags = rt.store() + .entries() + .map_err_trace_exit_unwrap() + .into_get_iter() + .map(|e| { + e.map_err_trace_exit_unwrap() + .ok_or_else(|| Error::from(err_msg("Unable to get entry".to_owned()))) + .map_err_trace_exit_unwrap() + }) + .map(|e| { + let diag = Diagnostic::for_entry(&e); + debug!("Diagnostic for '{:?}' = {:?}", e.get_location(), diag); + drop(e); + diag + }) + .collect::>>() + .map_err_trace_exit_unwrap(); + + spinner.finish(); + let n = diags.len(); + let progress = ProgressBar::new(n as u64); + let style = if let Some(template) = template { + ProgressStyle::default_bar().template(&template) + } else { + ProgressStyle::default_bar() + }; + progress.set_style(style); + progress.set_message("Calculating stats"); + + let mut version_counts : BTreeMap = BTreeMap::new(); + let mut sum_header_sections = 0; + let mut sum_bytecount_content = 0; + let mut sum_overall_byte_size = 0; + let mut max_overall_byte_size : Option<(usize, StoreId)> = None; + let mut verified_count = 0; + let mut unverified_count = 0; + let mut unverified_entries = vec![]; + let mut num_links = 0; + let mut max_links : Option<(usize, StoreId)> = None; + + for diag in diags.iter() { + sum_header_sections += diag.header_sections; + sum_bytecount_content += diag.bytecount_content; + sum_overall_byte_size += diag.overall_byte_size; + match max_overall_byte_size { + None => max_overall_byte_size = Some((diag.num_links, diag.id.clone())), + Some((num, _)) => if num < diag.overall_byte_size { + max_overall_byte_size = Some((diag.overall_byte_size, diag.id.clone())); + } + } + + let n = version_counts.get(&diag.entry_store_version).map(Clone::clone).unwrap_or(0); + version_counts.insert(diag.entry_store_version.clone(), n+1); + + if diag.verified { + verified_count += 1; + } else { + unverified_count += 1; + if verbose { + unverified_entries.push(diag.id.clone()); + } + } + + num_links += diag.num_links; + match max_links { + None => max_links = Some((diag.num_links, diag.id.clone())), + Some((num, _)) => if num < diag.num_links { + max_links = Some((diag.num_links, diag.id.clone())); + } + } + + progress.inc(1); + } + + progress.finish(); + + let mut out = rt.stdout(); + + do_write!(out, "imag version {}", { env!("CARGO_PKG_VERSION") }); + do_write!(out, ""); + do_write!(out, "{} entries", n); + + for (k, v) in version_counts { + do_write!(out, "{} entries with store version '{}'", v, k); + } + if n != 0 { + do_write!(out, "{} header sections in the average entry", sum_header_sections / n); + do_write!(out, "{} average content bytecount", sum_bytecount_content / n); + do_write!(out, "{} average overall bytecount", sum_overall_byte_size / n); + + if let Some((num, path)) = max_overall_byte_size { + do_write!(out, "Largest Entry ({} bytes): {}", num, path.local_display_string()); + } + + do_write!(out, "{} average internal link count per entry", num_links / n); + + if let Some((num, path)) = max_links { + do_write!(out, "Entry with most internal links ({}): {}", + num, + path.local_display_string()); + } + do_write!(out, "{} verified entries", verified_count); + do_write!(out, "{} unverified entries", unverified_count); + if verbose { + for unve in unverified_entries.iter() { + do_write!(out, "Unverified: {}", unve); + } + } + } + + 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 { + "Print diagnostics about imag and the imag store" + } + + fn version() -> &'static str { + env!("CARGO_PKG_VERSION") + } +} + +fn get_config(rt: &Runtime, s: &'static str) -> Option { + rt.config().and_then(|cfg| { + cfg.read(s) + .map_err(Error::from) + .map_err_trace_exit_unwrap() + .map(|opt| match opt { + &Value::String(ref s) => s.to_owned(), + _ => { + error!("Config type wrong: 'rt.progressbar_style' should be a string"); + ::std::process::exit(1) + } + }) + }) +} diff --git a/bin/core/imag-diagnostics/src/main.rs b/bin/core/imag-diagnostics/src/main.rs deleted file mode 100644 index 3a1f6806..00000000 --- a/bin/core/imag-diagnostics/src/main.rs +++ /dev/null @@ -1,269 +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, -)] - -extern crate clap; -extern crate toml; -extern crate toml_query; -extern crate indicatif; -extern crate failure; -#[macro_use] extern crate log; - -#[macro_use] extern crate libimagrt; -extern crate libimagerror; -extern crate libimagentrylink; -extern crate libimagstore; - -use std::io::Write; - -use libimagrt::runtime::Runtime; -use libimagrt::setup::generate_runtime_setup; -use libimagerror::trace::MapErrTrace; -use libimagerror::io::ToExitCode; -use libimagerror::exit::ExitUnwrap; -use libimagstore::store::FileLockEntry; -use libimagstore::storeid::StoreId; -use libimagentrylink::linkable::Linkable; - -use toml::Value; -use toml_query::read::TomlValueReadExt; -use indicatif::{ProgressBar, ProgressStyle}; -use failure::Fallible as Result; -use failure::Error; -use failure::err_msg; - -use std::collections::BTreeMap; - -mod ui; - -#[derive(Debug)] -struct Diagnostic { - pub id: StoreId, - pub entry_store_version: String, - pub header_sections: usize, - pub bytecount_content: usize, - pub overall_byte_size: usize, - pub verified: bool, - pub num_links: usize, -} - -impl Diagnostic { - - fn for_entry<'a>(entry: &FileLockEntry<'a>) -> Result { - Ok(Diagnostic { - id: entry.get_location().clone(), - entry_store_version: entry - .get_header() - .read("imag.version") - .map(|opt| match opt { - Some(&Value::String(ref s)) => s.clone(), - Some(_) => "Non-String type in 'imag.version'".to_owned(), - None => "No version".to_owned(), - }) - .unwrap_or_else(|_| "Error reading version".to_owned()), - header_sections: match entry.get_header() { - Value::Table(ref map) => map.keys().count(), - _ => 0 - }, - bytecount_content: entry.get_content().as_str().len(), - overall_byte_size: entry.to_str()?.as_str().len(), - verified: entry.verify().is_ok(), - num_links: entry.links().map(Iterator::count).unwrap_or(0), - }) - } -} - -macro_rules! do_write { - ($dest:ident, $pattern:tt) => { - let _ = writeln!($dest, $pattern) - .to_exit_code() - .unwrap_or_exit(); - }; - - ($dest:ident, $pattern:tt, $( $args:expr ),*) => { - let _ = writeln!($dest, $pattern, $( $args ),*) - .to_exit_code() - .unwrap_or_exit(); - } -} - -fn main() { - let version = make_imag_version!(); - let rt = generate_runtime_setup("imag-diagnostics", - &version, - "Print diagnostics about imag and the imag store", - ui::build_ui); - - let template = get_config(&rt, "rt.progressbar_style"); - let tick_chars = get_config(&rt, "rt.progressticker_chars"); - let verbose = rt.cli().is_present("more-output"); - - let style = if let Some(tick_chars) = tick_chars { - ProgressStyle::default_spinner().tick_chars(&tick_chars) - } else { - ProgressStyle::default_spinner() - }; - - let spinner = ProgressBar::new_spinner(); - spinner.enable_steady_tick(100); - spinner.set_style(style); - spinner.set_message("Accumulating data"); - - let diags = rt.store() - .entries() - .map_err_trace_exit_unwrap() - .into_get_iter() - .map(|e| { - e.map_err_trace_exit_unwrap() - .ok_or_else(|| err_msg("Unable to get entry".to_owned())) - .map_err_trace_exit_unwrap() - }) - .map(|e| { - let diag = Diagnostic::for_entry(&e); - debug!("Diagnostic for '{:?}' = {:?}", e.get_location(), diag); - drop(e); - diag - }) - .collect::>>() - .map_err_trace_exit_unwrap(); - - spinner.finish(); - let n = diags.len(); - let progress = ProgressBar::new(n as u64); - let style = if let Some(template) = template { - ProgressStyle::default_bar().template(&template) - } else { - ProgressStyle::default_bar() - }; - progress.set_style(style); - progress.set_message("Calculating stats"); - - let mut version_counts : BTreeMap = BTreeMap::new(); - let mut sum_header_sections = 0; - let mut sum_bytecount_content = 0; - let mut sum_overall_byte_size = 0; - let mut max_overall_byte_size : Option<(usize, StoreId)> = None; - let mut verified_count = 0; - let mut unverified_count = 0; - let mut unverified_entries = vec![]; - let mut num_links = 0; - let mut max_links : Option<(usize, StoreId)> = None; - - for diag in diags.iter() { - sum_header_sections += diag.header_sections; - sum_bytecount_content += diag.bytecount_content; - sum_overall_byte_size += diag.overall_byte_size; - match max_overall_byte_size { - None => max_overall_byte_size = Some((diag.num_links, diag.id.clone())), - Some((num, _)) => if num < diag.overall_byte_size { - max_overall_byte_size = Some((diag.overall_byte_size, diag.id.clone())); - } - } - - let n = version_counts.get(&diag.entry_store_version).map(Clone::clone).unwrap_or(0); - version_counts.insert(diag.entry_store_version.clone(), n+1); - - if diag.verified { - verified_count += 1; - } else { - unverified_count += 1; - if verbose { - unverified_entries.push(diag.id.clone()); - } - } - - num_links += diag.num_links; - match max_links { - None => max_links = Some((diag.num_links, diag.id.clone())), - Some((num, _)) => if num < diag.num_links { - max_links = Some((diag.num_links, diag.id.clone())); - } - } - - progress.inc(1); - } - - progress.finish(); - - let mut out = rt.stdout(); - - do_write!(out, "imag version {}", { env!("CARGO_PKG_VERSION") }); - do_write!(out, ""); - do_write!(out, "{} entries", n); - - for (k, v) in version_counts { - do_write!(out, "{} entries with store version '{}'", v, k); - } - if n != 0 { - do_write!(out, "{} header sections in the average entry", sum_header_sections / n); - do_write!(out, "{} average content bytecount", sum_bytecount_content / n); - do_write!(out, "{} average overall bytecount", sum_overall_byte_size / n); - - if let Some((num, path)) = max_overall_byte_size { - do_write!(out, "Largest Entry ({} bytes): {}", num, path.local_display_string()); - } - - do_write!(out, "{} average internal link count per entry", num_links / n); - - if let Some((num, path)) = max_links { - do_write!(out, "Entry with most internal links ({}): {}", - num, - path.local_display_string()); - } - do_write!(out, "{} verified entries", verified_count); - do_write!(out, "{} unverified entries", unverified_count); - if verbose { - for unve in unverified_entries.iter() { - do_write!(out, "Unverified: {}", unve); - } - } - } -} - -fn get_config(rt: &Runtime, s: &'static str) -> Option { - rt.config().and_then(|cfg| { - cfg.read(s) - .map_err(Error::from) - .map_err_trace_exit_unwrap() - .map(|opt| match opt { - Value::String(ref s) => s.to_owned(), - _ => { - error!("Config type wrong: 'rt.progressbar_style' should be a string"); - ::std::process::exit(1) - } - }) - }) -} - diff --git a/bin/core/imag-edit/Cargo.toml b/bin/core/imag-edit/Cargo.toml index b329e17f..6dc9a67d 100644 --- a/bin/core/imag-edit/Cargo.toml +++ b/bin/core/imag-edit/Cargo.toml @@ -49,3 +49,10 @@ path = "../../../lib/core/libimagrt" default-features = false features = ["testing"] +[lib] +name = "libimageditcmd" +path = "src/lib.rs" + +[[bin]] +name = "imag-edit" +path = "src/bin.rs" diff --git a/bin/core/imag-edit/src/bin.rs b/bin/core/imag-edit/src/bin.rs new file mode 100644 index 00000000..b0002164 --- /dev/null +++ b/bin/core/imag-edit/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!(libimageditcmd, ImagEdit); diff --git a/bin/core/imag-edit/src/lib.rs b/bin/core/imag-edit/src/lib.rs new file mode 100644 index 00000000..7d515c6d --- /dev/null +++ b/bin/core/imag-edit/src/lib.rs @@ -0,0 +1,121 @@ +// +// 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, +)] + +extern crate clap; +#[macro_use] extern crate log; +extern crate failure; + +extern crate libimagentryedit; +extern crate libimagerror; +extern crate libimagrt; +extern crate libimagstore; +extern crate libimagutil; + +use libimagerror::trace::MapErrTrace; +use libimagerror::iter::TraceIterator; +use libimagentryedit::edit::Edit; +use libimagentryedit::edit::EditHeader; +use libimagrt::runtime::Runtime; +use libimagrt::application::ImagApplication; +use libimagstore::storeid::StoreIdIterator; +use libimagstore::iter::get::StoreIdGetIteratorExtension; + +use failure::Fallible as Result; +use clap::App; + +mod ui; + +/// Marker enum for implementing ImagApplication on +/// +/// This is used by binaries crates to execute business logic +/// or to build a CLI completion. +pub enum ImagEdit {} +impl ImagApplication for ImagEdit { + fn run(rt: Runtime) -> Result<()> { + let edit_header = rt.cli().is_present("edit-header"); + let edit_header_only = rt.cli().is_present("edit-header-only"); + + let sids = rt + .ids::() + .map_err_trace_exit_unwrap() + .unwrap_or_else(|| { + error!("No ids supplied"); + ::std::process::exit(1); + }) + .into_iter(); + + StoreIdIterator::new(Box::new(sids.into_iter().map(Ok))) + .into_get_iter(rt.store()) + .trace_unwrap_exit() + .map(|o| o.unwrap_or_else(|| { + error!("Did not find one entry"); + ::std::process::exit(1) + })) + .for_each(|mut entry| { + if edit_header { + let _ = entry + .edit_header_and_content(&rt) + .map_err_trace_exit_unwrap(); + } else if edit_header_only { + let _ = entry + .edit_header(&rt) + .map_err_trace_exit_unwrap(); + } else { + let _ = entry + .edit_content(&rt) + .map_err_trace_exit_unwrap(); + } + }); + + 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 { + "Edit store entries with $EDITOR" + } + + fn version() -> &'static str { + env!("CARGO_PKG_VERSION") + } +} diff --git a/bin/core/imag-edit/src/main.rs b/bin/core/imag-edit/src/main.rs deleted file mode 100644 index 3e758d7c..00000000 --- a/bin/core/imag-edit/src/main.rs +++ /dev/null @@ -1,99 +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, -)] - -extern crate clap; -#[macro_use] extern crate log; -extern crate failure; - -extern crate libimagentryedit; -extern crate libimagerror; -#[macro_use] extern crate libimagrt; -extern crate libimagstore; -extern crate libimagutil; - -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::StoreIdIterator; -use libimagstore::iter::get::StoreIdGetIteratorExtension; - -mod ui; - -fn main() { - let version = make_imag_version!(); - let rt = generate_runtime_setup("imag-edit", - &version, - "Edit store entries with $EDITOR", - ui::build_ui); - - let edit_header = rt.cli().is_present("edit-header"); - let edit_header_only = rt.cli().is_present("edit-header-only"); - - let sids = rt - .ids::() - .map_err_trace_exit_unwrap() - .unwrap_or_else(|| { - error!("No ids supplied"); - ::std::process::exit(1); - }) - .into_iter(); - - StoreIdIterator::new(Box::new(sids.map(Ok))) - .into_get_iter(rt.store()) - .trace_unwrap_exit() - .map(|o| o.unwrap_or_else(|| { - error!("Did not find one entry"); - ::std::process::exit(1) - })) - .for_each(|mut entry| { - if edit_header { - entry - .edit_header_and_content(&rt) - .map_err_trace_exit_unwrap(); - } else if edit_header_only { - entry - .edit_header(&rt) - .map_err_trace_exit_unwrap(); - } else { - entry - .edit_content(&rt) - .map_err_trace_exit_unwrap(); - } - }); -} - diff --git a/bin/core/imag-git/Cargo.toml b/bin/core/imag-git/Cargo.toml index 278b387b..168e04ce 100644 --- a/bin/core/imag-git/Cargo.toml +++ b/bin/core/imag-git/Cargo.toml @@ -23,6 +23,7 @@ maintenance = { status = "actively-developed" } log = "0.4.6" toml = "0.5.1" toml-query = "0.9.2" +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 = "libimaggitcmd" +path = "src/lib.rs" + +[[bin]] +name = "imag-git" +path = "src/bin.rs" diff --git a/bin/core/imag-git/src/bin.rs b/bin/core/imag-git/src/bin.rs new file mode 100644 index 00000000..759a3a3a --- /dev/null +++ b/bin/core/imag-git/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!(libimaggitcmd, ImagGit); diff --git a/bin/core/imag-git/src/lib.rs b/bin/core/imag-git/src/lib.rs new file mode 100644 index 00000000..b5b7d5e7 --- /dev/null +++ b/bin/core/imag-git/src/lib.rs @@ -0,0 +1,197 @@ +// +// 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, +)] + +extern crate clap; +#[macro_use] extern crate log; +extern crate toml; +extern crate toml_query; +extern crate failure; + +extern crate libimagrt; +extern crate libimagerror; + +use std::io::Write; +use std::io::ErrorKind; +use std::process::Command; + +use toml::Value; +use toml_query::read::TomlValueReadExt; +use clap::App; +use failure::Fallible as Result; + +use libimagerror::exit::ExitUnwrap; +use libimagerror::io::ToExitCode; +use libimagrt::runtime::Runtime; +use libimagrt::application::ImagApplication; + +mod ui; + +/// Marker enum for implementing ImagApplication on +/// +/// This is used by binaries crates to execute business logic +/// or to build a CLI completion. +pub enum ImagGit {} +impl ImagApplication for ImagGit { + fn run(rt: Runtime) -> Result<()> { + let execute_in_store = rt + .config() + .unwrap_or_else(|| { + error!("No configuration. Please use git yourself, not via imag-git"); + error!("Won't continue without configuration."); + ::std::process::exit(1); + }) + .read("git.execute_in_store") + .unwrap_or_else(|e| { + error!("Failed to read config setting 'git.execute_in_store'"); + error!("-> {:?}", e); + ::std::process::exit(1) + }) + .unwrap_or_else(|| { + error!("Missing config setting 'git.execute_in_store'"); + ::std::process::exit(1) + }); + + let execute_in_store = match *execute_in_store { + Value::Boolean(b) => b, + _ => { + error!("Type error: 'git.execute_in_store' is not a boolean!"); + ::std::process::exit(1) + } + }; + + let execpath = if execute_in_store { + rt.store().path().to_str() + } else { + rt.rtp().to_str() + } + .map(String::from) + .unwrap_or_else(|| { + error!("Cannot parse to string: {:?}", rt.store().path()); + ::std::process::exit(1) + }); + + + let mut command = Command::new("git"); + command + .stdin(::std::process::Stdio::inherit()) + .stdout(::std::process::Stdio::inherit()) + .stderr(::std::process::Stdio::inherit()) + .arg("-C").arg(&execpath); + + let args = rt + .cli() + .values_of("") + .map(|vs| vs.map(String::from).collect()) + .unwrap_or_else(|| vec![]); + + debug!("Adding args = {:?}", args); + command.args(&args); + + match rt.cli().subcommand() { + (external, Some(ext_m)) => { + command.arg(external); + let args = ext_m + .values_of("") + .map(|vs| vs.map(String::from).collect()) + .unwrap_or_else(|| vec![]); + + debug!("Adding subcommand '{}' and args = {:?}", external, args); + command.args(&args); + }, + _ => {}, + } + + let mut out = rt.stdout(); + + debug!("Calling: {:?}", command); + + match command.spawn().and_then(|mut c| c.wait()) { + Ok(exit_status) => { + if !exit_status.success() { + debug!("git exited with non-zero exit code: {:?}", exit_status); + let mut err = rt.stderr(); + writeln!(err, "git exited with non-zero exit code") + .to_exit_code() + .unwrap_or_exit(); + ::std::process::exit(exit_status.code().unwrap_or(1)); + } + debug!("Successful exit!"); + }, + + Err(e) => { + debug!("Error calling git"); + match e.kind() { + ErrorKind::NotFound => { + let _ = writeln!(out, "Cannot find 'git' executable") + .to_exit_code() + .unwrap_or_exit(); + ::std::process::exit(1); + }, + ErrorKind::PermissionDenied => { + let _ = writeln!(out, "No permission to execute: 'git'") + .to_exit_code() + .unwrap_or_exit(); + ::std::process::exit(1); + }, + _ => { + let _ = writeln!(out, "Error spawning: {:?}", e) + .to_exit_code() + .unwrap_or_exit(); + ::std::process::exit(1); + } + } + } + } + + Ok(()) + } + + fn build_cli<'a>(app: App<'a, 'a>) -> App<'a, 'a> { + ui::build_ui(app) + } + + fn name() -> &'static str { + env!("CARGO_PKG_NAME") + } + + fn description() -> &'static str { + "Helper to call git in the store" + } + + fn version() -> &'static str { + env!("CARGO_PKG_VERSION") + } +} diff --git a/bin/core/imag-git/src/main.rs b/bin/core/imag-git/src/main.rs deleted file mode 100644 index d1370ab1..00000000 --- a/bin/core/imag-git/src/main.rs +++ /dev/null @@ -1,171 +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, -)] - -extern crate clap; -#[macro_use] extern crate log; -extern crate toml; -extern crate toml_query; - -#[macro_use] extern crate libimagrt; -extern crate libimagerror; - -use std::io::Write; -use std::io::ErrorKind; -use std::process::Command; - -use toml::Value; -use toml_query::read::TomlValueReadExt; - -use libimagerror::exit::ExitUnwrap; -use libimagerror::io::ToExitCode; -use libimagrt::setup::generate_runtime_setup; - -mod ui; - -fn main() { - let version = make_imag_version!(); - let rt = generate_runtime_setup("imag-git", - &version, - "Helper to call git in the store", - ui::build_ui); - - let execute_in_store = rt - .config() - .unwrap_or_else(|| { - error!("No configuration. Please use git yourself, not via imag-git"); - error!("Won't continue without configuration."); - ::std::process::exit(1); - }) - .read("git.execute_in_store") - .unwrap_or_else(|e| { - error!("Failed to read config setting 'git.execute_in_store'"); - error!("-> {:?}", e); - ::std::process::exit(1) - }) - .unwrap_or_else(|| { - error!("Missing config setting 'git.execute_in_store'"); - ::std::process::exit(1) - }); - - let execute_in_store = match *execute_in_store { - Value::Boolean(b) => b, - _ => { - error!("Type error: 'git.execute_in_store' is not a boolean!"); - ::std::process::exit(1) - } - }; - - let execpath = if execute_in_store { - rt.store().path().to_str() - } else { - rt.rtp().to_str() - } - .map(String::from) - .unwrap_or_else(|| { - error!("Cannot parse to string: {:?}", rt.store().path()); - ::std::process::exit(1) - }); - - - let mut command = Command::new("git"); - command - .stdin(::std::process::Stdio::inherit()) - .stdout(::std::process::Stdio::inherit()) - .stderr(::std::process::Stdio::inherit()) - .arg("-C").arg(&execpath); - - let args = rt - .cli() - .values_of("") - .map(|vs| vs.map(String::from).collect()) - .unwrap_or_else(|| vec![]); - - debug!("Adding args = {:?}", args); - command.args(&args); - - if let (external, Some(ext_m)) = rt.cli().subcommand() { - command.arg(external); - let args = ext_m - .values_of("") - .map(|vs| vs.map(String::from).collect()) - .unwrap_or_else(|| vec![]); - - debug!("Adding subcommand '{}' and args = {:?}", external, args); - command.args(&args); - } - let mut out = rt.stdout(); - - debug!("Calling: {:?}", command); - - match command.spawn().and_then(|mut c| c.wait()) { - Ok(exit_status) => { - if !exit_status.success() { - debug!("git exited with non-zero exit code: {:?}", exit_status); - let mut err = rt.stderr(); - writeln!(err, "git exited with non-zero exit code") - .to_exit_code() - .unwrap_or_exit(); - ::std::process::exit(exit_status.code().unwrap_or(1)); - } - debug!("Successful exit!"); - }, - - Err(e) => { - debug!("Error calling git"); - match e.kind() { - ErrorKind::NotFound => { - writeln!(out, "Cannot find 'git' executable") - .to_exit_code() - .unwrap_or_exit(); - ::std::process::exit(1); - }, - ErrorKind::PermissionDenied => { - writeln!(out, "No permission to execute: 'git'") - .to_exit_code() - .unwrap_or_exit(); - ::std::process::exit(1); - }, - _ => { - writeln!(out, "Error spawning: {:?}", e) - .to_exit_code() - .unwrap_or_exit(); - ::std::process::exit(1); - } - } - } - } -} - diff --git a/bin/core/imag-gps/Cargo.toml b/bin/core/imag-gps/Cargo.toml index cb7247fc..5c197e7d 100644 --- a/bin/core/imag-gps/Cargo.toml +++ b/bin/core/imag-gps/Cargo.toml @@ -43,3 +43,10 @@ path = "../../../lib/etc/libimagutil" default-features = false features = ["testing"] +[lib] +name = "libimaggpscmd" +path = "src/lib.rs" + +[[bin]] +name = "imag-gps" +path = "src/bin.rs" diff --git a/bin/core/imag-gps/src/bin.rs b/bin/core/imag-gps/src/bin.rs new file mode 100644 index 00000000..60be43b2 --- /dev/null +++ b/bin/core/imag-gps/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!(libimaggpscmd, ImagGps); diff --git a/bin/core/imag-gps/src/main.rs b/bin/core/imag-gps/src/lib.rs similarity index 82% rename from bin/core/imag-gps/src/main.rs rename to bin/core/imag-gps/src/lib.rs index 80ef51b8..6b5ae542 100644 --- a/bin/core/imag-gps/src/main.rs +++ b/bin/core/imag-gps/src/lib.rs @@ -39,7 +39,7 @@ extern crate clap; #[macro_use] extern crate failure; extern crate libimagentrygps; -#[macro_use] extern crate libimagrt; +extern crate libimagrt; extern crate libimagutil; extern crate libimagerror; extern crate libimagstore; @@ -50,11 +50,13 @@ use std::str::FromStr; use failure::err_msg; +use failure::Fallible as Result; +use clap::App; use libimagstore::storeid::StoreId; use libimagentrygps::types::*; use libimagentrygps::entry::*; -use libimagrt::setup::generate_runtime_setup; +use libimagrt::application::ImagApplication; use libimagrt::runtime::Runtime; use libimagerror::trace::MapErrTrace; use libimagerror::exit::ExitUnwrap; @@ -62,26 +64,45 @@ use libimagerror::io::ToExitCode; mod ui; -fn main() { - let version = make_imag_version!(); - let rt = generate_runtime_setup("imag-gps", - &version, - "Add GPS coordinates to entries", - ui::build_ui); - - if let Some(name) = rt.cli().subcommand_name() { - match name { - "add" => add(&rt), - "remove" => remove(&rt), - "get" => get(&rt), - other => { - debug!("Unknown command"); - let _ = rt.handle_unknown_subcommand("imag-gps", other, rt.cli()) - .map_err_trace_exit_unwrap() - .code() - .map(::std::process::exit); +/// Marker enum for implementing ImagApplication on +/// +/// This is used by binaries crates to execute business logic +/// or to build a CLI completion. +pub enum ImagGps {} +impl ImagApplication for ImagGps { + fn run(rt: Runtime) -> Result<()> { + if let Some(name) = rt.cli().subcommand_name() { + match name { + "add" => add(&rt), + "remove" => remove(&rt), + "get" => get(&rt), + other => { + debug!("Unknown command"); + let _ = rt.handle_unknown_subcommand("imag-gps", other, rt.cli()) + .map_err_trace_exit_unwrap() + .code() + .map(::std::process::exit); + } } } + + 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 { + "Add GPS coordinates to entries" + } + + fn version() -> &'static str { + env!("CARGO_PKG_VERSION") } } diff --git a/bin/core/imag-grep/Cargo.toml b/bin/core/imag-grep/Cargo.toml index c95c85b4..a923a902 100644 --- a/bin/core/imag-grep/Cargo.toml +++ b/bin/core/imag-grep/Cargo.toml @@ -22,6 +22,7 @@ maintenance = { status = "actively-developed" } [dependencies] log = "0.4.6" regex = "1.1.7" +failure = "0.1.5" libimagstore = { version = "0.10.0", path = "../../../lib/core/libimagstore" } libimagrt = { version = "0.10.0", path = "../../../lib/core/libimagrt" } @@ -32,3 +33,10 @@ version = "2.33.0" default-features = false features = ["color", "suggestions", "wrap_help"] +[lib] +name = "libimaggrepcmd" +path = "src/lib.rs" + +[[bin]] +name = "imag-grep" +path = "src/bin.rs" diff --git a/bin/core/imag-grep/src/bin.rs b/bin/core/imag-grep/src/bin.rs new file mode 100644 index 00000000..aacc4628 --- /dev/null +++ b/bin/core/imag-grep/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!(libimaggrepcmd, ImagGrep); diff --git a/bin/core/imag-grep/src/main.rs b/bin/core/imag-grep/src/lib.rs similarity index 53% rename from bin/core/imag-grep/src/main.rs rename to bin/core/imag-grep/src/lib.rs index a7b1a1f3..f7a4a2d1 100644 --- a/bin/core/imag-grep/src/main.rs +++ b/bin/core/imag-grep/src/lib.rs @@ -37,17 +37,20 @@ #[macro_use] extern crate log; extern crate clap; extern crate regex; +extern crate failure; extern crate libimagstore; -#[macro_use] extern crate libimagrt; +extern crate libimagrt; extern crate libimagerror; use std::io::Write; use regex::Regex; +use failure::Fallible as Result; +use clap::App; use libimagrt::runtime::Runtime; -use libimagrt::setup::generate_runtime_setup; +use libimagrt::application::ImagApplication; use libimagstore::store::Entry; use libimagerror::trace::MapErrTrace; use libimagerror::exit::ExitUnwrap; @@ -60,53 +63,72 @@ struct Options { count: bool, } -fn main() { - let version = make_imag_version!(); - let rt = generate_runtime_setup("imag-grep", - &version, - "grep through entries text", - ui::build_ui); +/// Marker enum for implementing ImagApplication on +/// +/// This is used by binaries crates to execute business logic +/// or to build a CLI completion. +pub enum ImagGrep {} +impl ImagApplication for ImagGrep { + fn run(rt: Runtime) -> Result<()> { + let opts = Options { + files_with_matches : rt.cli().is_present("files-with-matches"), + count : rt.cli().is_present("count"), + }; - let opts = Options { - files_with_matches : rt.cli().is_present("files-with-matches"), - count : rt.cli().is_present("count"), - }; + let mut count : usize = 0; - let mut count : usize = 0; + let pattern = rt + .cli() + .value_of("pattern") + .map(Regex::new) + .unwrap() // ensured by clap + .unwrap_or_else(|e| { + error!("Regex building error: {:?}", e); + ::std::process::exit(1) + }); - let pattern = rt - .cli() - .value_of("pattern") - .map(Regex::new) - .unwrap() // ensured by clap - .unwrap_or_else(|e| { - error!("Regex building error: {:?}", e); - ::std::process::exit(1) - }); + let overall_count = rt + .store() + .entries() + .map_err_trace_exit_unwrap() + .into_get_iter() + .filter_map(|res| res.map_err_trace_exit_unwrap()) + .filter_map(|entry| if pattern.is_match(entry.get_content()) { + show(&rt, &entry, &pattern, &opts, &mut count); + Some(()) + } else { + None + }) + .count(); - let overall_count = rt - .store() - .entries() - .map_err_trace_exit_unwrap() - .into_get_iter() - .filter_map(|res| res.map_err_trace_exit_unwrap()) - .filter_map(|entry| if pattern.is_match(entry.get_content()) { - show(&rt, &entry, &pattern, &opts, &mut count); - Some(()) - } else { - None - }) - .count(); + if opts.count { + writeln!(rt.stdout(), "{}", count).to_exit_code().unwrap_or_exit(); + } else if !opts.files_with_matches { + writeln!(rt.stdout(), "Processed {} files, {} matches, {} nonmatches", + overall_count, + count, + overall_count - count) + .to_exit_code() + .unwrap_or_exit(); + } - if opts.count { - writeln!(rt.stdout(), "{}", count).to_exit_code().unwrap_or_exit(); - } else if !opts.files_with_matches { - writeln!(rt.stdout(), "Processed {} files, {} matches, {} nonmatches", - overall_count, - count, - overall_count - count) - .to_exit_code() - .unwrap_or_exit(); + 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 { + "grep through entries text" + } + + fn version() -> &'static str { + env!("CARGO_PKG_VERSION") } } diff --git a/bin/core/imag-header/Cargo.toml b/bin/core/imag-header/Cargo.toml index e36c05ac..7caf2292 100644 --- a/bin/core/imag-header/Cargo.toml +++ b/bin/core/imag-header/Cargo.toml @@ -45,3 +45,10 @@ path = "../../../lib/core/libimagrt" default-features = false features = ["testing"] +[lib] +name = "libimagheadercmd" +path = "src/lib.rs" + +[[bin]] +name = "imag-header" +path = "src/bin.rs" diff --git a/bin/core/imag-header/src/bin.rs b/bin/core/imag-header/src/bin.rs new file mode 100644 index 00000000..532520e6 --- /dev/null +++ b/bin/core/imag-header/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!(libimagheadercmd, ImagHeader); diff --git a/bin/core/imag-header/src/main.rs b/bin/core/imag-header/src/lib.rs similarity index 81% rename from bin/core/imag-header/src/main.rs rename to bin/core/imag-header/src/lib.rs index 1366726c..a8918fe8 100644 --- a/bin/core/imag-header/src/main.rs +++ b/bin/core/imag-header/src/lib.rs @@ -41,7 +41,7 @@ extern crate failure; extern crate libimagentryedit; extern crate libimagerror; -#[macro_use] extern crate libimagrt; +extern crate libimagrt; extern crate libimagstore; extern crate libimagutil; @@ -49,10 +49,10 @@ use std::io::Write; use std::str::FromStr; use std::string::ToString; -use clap::ArgMatches; +use clap::{App, ArgMatches}; use filters::filter::Filter; -use failure::Error; use toml::Value; +use failure::{Fallible as Result, Error}; use libimagerror::exit::ExitCode; use libimagerror::exit::ExitUnwrap; @@ -60,7 +60,7 @@ use libimagerror::io::ToExitCode; use libimagerror::iter::TraceIterator; use libimagerror::trace::MapErrTrace; use libimagrt::runtime::Runtime; -use libimagrt::setup::generate_runtime_setup; +use libimagrt::application::ImagApplication; use libimagstore::iter::get::StoreIdGetIteratorExtension; use libimagstore::store::FileLockEntry; use libimagstore::storeid::StoreIdIterator; @@ -68,55 +68,73 @@ use libimagstore::storeid::StoreIdIterator; use toml_query::read::TomlValueReadExt; use toml_query::read::TomlValueReadTypeExt; - mod ui; const EPS_CMP: f64 = 1e-10; -fn main() { - let version = make_imag_version!(); - let rt = generate_runtime_setup("imag-header", - &version, - "Plumbing tool for reading/writing structured data in entries", - ui::build_ui); +/// Marker enum for implementing ImagApplication on +/// +/// This is used by binaries crates to execute business logic +/// or to build a CLI completion. +pub enum ImagHeader {} +impl ImagApplication for ImagHeader { + fn run(rt: Runtime) -> Result<()> { + let list_output_with_ids = rt.cli().is_present("list-id"); + let list_output_with_ids_fmt = rt.cli().value_of("list-id-format"); - let list_output_with_ids = rt.cli().is_present("list-id"); - let list_output_with_ids_fmt = rt.cli().value_of("list-id-format"); + trace!("list_output_with_ids = {:?}", list_output_with_ids ); + trace!("list_output_with_ids_fmt = {:?}", list_output_with_ids_fmt); - trace!("list_output_with_ids = {:?}", list_output_with_ids ); - trace!("list_output_with_ids_fmt = {:?}", list_output_with_ids_fmt); + let sids = rt + .ids::() + .map_err_trace_exit_unwrap() + .unwrap_or_else(|| { + error!("No ids supplied"); + ::std::process::exit(1); + }) + .into_iter(); - let sids = rt - .ids::() - .map_err_trace_exit_unwrap() - .unwrap_or_else(|| { - error!("No ids supplied"); - ::std::process::exit(1); - }) - .into_iter(); + let iter = StoreIdIterator::new(Box::new(sids.map(Ok))) + .into_get_iter(rt.store()) + .trace_unwrap_exit() + .filter_map(|x| x); - let iter = StoreIdIterator::new(Box::new(sids.map(Ok))) - .into_get_iter(rt.store()) - .trace_unwrap_exit() - .filter_map(|x| x); + match rt.cli().subcommand() { + ("read", Some(mtch)) => ::std::process::exit(read(&rt, mtch, iter)), + ("has", Some(mtch)) => has(&rt, mtch, iter), + ("hasnt", Some(mtch)) => hasnt(&rt, mtch, iter), + ("int", Some(mtch)) => int(&rt, mtch, iter), + ("float", Some(mtch)) => float(&rt, mtch, iter), + ("string", Some(mtch)) => string(&rt, mtch, iter), + ("bool", Some(mtch)) => boolean(&rt, mtch, iter), + (other, _mtchs) => { + debug!("Unknown command"); + ::std::process::exit({ + rt.handle_unknown_subcommand("imag-header", other, rt.cli()) + .map_err_trace_exit_unwrap() + .code() + .unwrap_or(1) + }); + }, + }; - match rt.cli().subcommand() { - ("read", Some(mtch)) => ::std::process::exit(read(&rt, mtch, iter)), - ("has", Some(mtch)) => has(&rt, mtch, iter), - ("hasnt", Some(mtch)) => hasnt(&rt, mtch, iter), - ("int", Some(mtch)) => int(&rt, mtch, iter), - ("float", Some(mtch)) => float(&rt, mtch, iter), - ("string", Some(mtch)) => string(&rt, mtch, iter), - ("bool", Some(mtch)) => boolean(&rt, mtch, iter), - (other, _mtchs) => { - debug!("Unknown command"); - ::std::process::exit({ - rt.handle_unknown_subcommand("imag-header", other, rt.cli()) - .map_err_trace_exit_unwrap() - .code() - .unwrap_or(1) - }); - }, + 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 { + "Plumbing tool for reading/writing structured data in entries" + } + + fn version() -> &'static str { + env!("CARGO_PKG_VERSION") } } diff --git a/bin/core/imag-ids/Cargo.toml b/bin/core/imag-ids/Cargo.toml index 3282c375..8f6afe96 100644 --- a/bin/core/imag-ids/Cargo.toml +++ b/bin/core/imag-ids/Cargo.toml @@ -37,3 +37,10 @@ features = ["color", "suggestions", "wrap_help"] [dev-dependencies] env_logger = "0.7" +[lib] +name = "libimagidscmd" +path = "src/lib.rs" + +[[bin]] +name = "imag-ids" +path = "src/bin.rs" diff --git a/bin/core/imag-ids/src/bin.rs b/bin/core/imag-ids/src/bin.rs new file mode 100644 index 00000000..ca472b77 --- /dev/null +++ b/bin/core/imag-ids/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!(libimagidscmd, ImagIds); diff --git a/bin/core/imag-ids/src/lib.rs b/bin/core/imag-ids/src/lib.rs new file mode 100644 index 00000000..bb0e08a8 --- /dev/null +++ b/bin/core/imag-ids/src/lib.rs @@ -0,0 +1,134 @@ +// +// 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, +)] + +extern crate clap; +#[macro_use] extern crate log; +extern crate toml; +extern crate toml_query; +#[macro_use] extern crate failure; + +#[cfg(test)] +extern crate env_logger; + +extern crate libimagerror; +extern crate libimagstore; +extern crate libimagrt; + +use std::io::Write; +use std::result::Result as RResult; + +use failure::Fallible as Result; +use clap::App; + +use libimagstore::storeid::StoreId; +use libimagrt::runtime::Runtime; +use libimagrt::application::ImagApplication; +use libimagerror::trace::MapErrTrace; +use libimagerror::iter::TraceIterator; +use libimagerror::exit::ExitUnwrap; +use libimagerror::io::ToExitCode; + +mod ui; + +/// Marker enum for implementing ImagApplication on +/// +/// This is used by binaries crates to execute business logic +/// or to build a CLI completion. +pub enum ImagIds {} +impl ImagApplication for ImagIds { + fn run(rt: Runtime) -> Result<()> { + let print_storepath = rt.cli().is_present("print-storepath"); + + let iterator = if rt.ids_from_stdin() { + debug!("Fetching IDs from stdin..."); + let ids = rt + .ids::() + .map_err_trace_exit_unwrap() + .unwrap_or_else(|| { + error!("No ids supplied"); + ::std::process::exit(1); + }); + Box::new(ids.into_iter().map(Ok)) + as Box>> + } else { + Box::new(rt.store().entries().map_err_trace_exit_unwrap()) + as Box>> + } + .trace_unwrap_exit() + .map(|id| if print_storepath { + (Some(rt.store().path()), id) + } else { + (None, id) + }); + + let mut stdout = rt.stdout(); + trace!("Got output: {:?}", stdout); + + iterator.for_each(|(storepath, id)| { + rt.report_touched(&id).unwrap_or_exit(); + if !rt.output_is_pipe() { + let id = id.to_str().map_err_trace_exit_unwrap(); + trace!("Writing to {:?}", stdout); + + let result = if let Some(store) = storepath { + writeln!(stdout, "{}/{}", store.display(), id) + } else { + writeln!(stdout, "{}", id) + }; + + result.to_exit_code().unwrap_or_exit(); + } + }); + + 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 { + "print all ids" + } + + fn version() -> &'static str { + env!("CARGO_PKG_VERSION") + } +} diff --git a/bin/core/imag-ids/src/main.rs b/bin/core/imag-ids/src/main.rs deleted file mode 100644 index 8c8222bd..00000000 --- a/bin/core/imag-ids/src/main.rs +++ /dev/null @@ -1,113 +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, -)] - -extern crate clap; -#[macro_use] extern crate log; -extern crate toml; -extern crate toml_query; -#[macro_use] extern crate failure; - -#[cfg(test)] -extern crate env_logger; - -extern crate libimagerror; -extern crate libimagstore; -#[macro_use] extern crate libimagrt; - -use std::io::Write; - -use libimagstore::storeid::StoreId; -use libimagrt::setup::generate_runtime_setup; -use libimagerror::trace::MapErrTrace; -use libimagerror::iter::TraceIterator; -use libimagerror::exit::ExitUnwrap; -use libimagerror::io::ToExitCode; - -mod ui; - -use crate::ui::build_ui; - -fn main() { - let version = make_imag_version!(); - let rt = generate_runtime_setup("imag-ids", - &version, - "print all ids", - build_ui); - - let print_storepath = rt.cli().is_present("print-storepath"); - - let iterator = if rt.ids_from_stdin() { - debug!("Fetching IDs from stdin..."); - let ids = rt - .ids::() - .map_err_trace_exit_unwrap() - .unwrap_or_else(|| { - error!("No ids supplied"); - ::std::process::exit(1); - }); - Box::new(ids.into_iter().map(Ok)) - as Box>> - } else { - Box::new(rt.store().entries().map_err_trace_exit_unwrap()) - as Box>> - } - .trace_unwrap_exit() - .map(|id| if print_storepath { - (Some(rt.store().path()), id) - } else { - (None, id) - }); - - let mut stdout = rt.stdout(); - trace!("Got output: {:?}", stdout); - - iterator.for_each(|(storepath, id)| { - rt.report_touched(&id).unwrap_or_exit(); - if !rt.output_is_pipe() { - let id = id.to_str().map_err_trace_exit_unwrap(); - trace!("Writing to {:?}", stdout); - - let result = if let Some(store) = storepath { - writeln!(stdout, "{}/{}", store.display(), id) - } else { - writeln!(stdout, "{}", id) - }; - - result.to_exit_code().unwrap_or_exit(); - } - }) -} - diff --git a/bin/core/imag-init/Cargo.toml b/bin/core/imag-init/Cargo.toml index 9701794c..cf68ef8c 100644 --- a/bin/core/imag-init/Cargo.toml +++ b/bin/core/imag-init/Cargo.toml @@ -20,6 +20,8 @@ is-it-maintained-open-issues = { repository = "matthiasbeyer/imag" } maintenance = { status = "actively-developed" } [dependencies] +failure = "0.1.5" + libimagerror = { version = "0.10.0", path = "../../../lib/core/libimagerror" } libimagrt = { version = "0.10.0", path = "../../../lib/core/libimagrt" } @@ -31,3 +33,10 @@ features = ["color", "suggestions", "wrap_help"] [dev-dependencies] toml = "0.5.1" +[lib] +name = "libimaginitcmd" +path = "src/lib.rs" + +[[bin]] +name = "imag-init" +path = "src/bin.rs" diff --git a/bin/core/imag-init/src/bin.rs b/bin/core/imag-init/src/bin.rs new file mode 100644 index 00000000..aea6ebc3 --- /dev/null +++ b/bin/core/imag-init/src/bin.rs @@ -0,0 +1,46 @@ +// +// 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, +)] + +extern crate failure; +use failure::Fallible as Result; + +extern crate libimaginitcmd; + + +fn main() -> Result<()> { + libimaginitcmd::imag_init(); + Ok(()) +} diff --git a/bin/core/imag-init/src/main.rs b/bin/core/imag-init/src/lib.rs similarity index 91% rename from bin/core/imag-init/src/main.rs rename to bin/core/imag-init/src/lib.rs index 5935a812..e2033e3d 100644 --- a/bin/core/imag-init/src/main.rs +++ b/bin/core/imag-init/src/lib.rs @@ -35,7 +35,7 @@ )] extern crate clap; - +extern crate failure; #[cfg(test)] extern crate toml; @@ -53,6 +53,10 @@ use std::process::Command; use libimagerror::exit::ExitUnwrap; use libimagerror::io::ToExitCode; use libimagrt::runtime::Runtime; +use libimagrt::application::ImagApplication; + +use failure::Fallible as Result; +use clap::App; const CONFIGURATION_STR : &str = include_str!("../imagrc.toml"); @@ -69,7 +73,34 @@ const GITIGNORE_STR : &str = r#" imagrc.toml "#; -fn main() { +/// Marker enum for implementing ImagApplication on +/// +/// This is used by binaries crates to execute business logic +/// or to build a CLI completion. +pub enum ImagInit {} +impl ImagApplication for ImagInit { + fn run(_rt: Runtime) -> Result<()> { + panic!("imag-init needs to be run as a seperate binary, or we'll need to figure something out here!"); + } + + 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 { + "Intialize the imag store" + } + + fn version() -> &'static str { + env!("CARGO_PKG_VERSION") + } +} + +pub fn imag_init() { let version = make_imag_version!(); let app = ui::build_ui(Runtime::get_default_cli_builder( "imag-init", diff --git a/bin/core/imag-link/Cargo.toml b/bin/core/imag-link/Cargo.toml index 5b98906e..50ef9d95 100644 --- a/bin/core/imag-link/Cargo.toml +++ b/bin/core/imag-link/Cargo.toml @@ -54,4 +54,10 @@ path = "../../../lib/core/libimagrt" default-features = false features = ["testing"] +[lib] +name = "libimaglinkcmd" +path = "src/lib.rs" +[[bin]] +name = "imag-link" +path = "src/bin.rs" diff --git a/bin/core/imag-link/src/bin.rs b/bin/core/imag-link/src/bin.rs new file mode 100644 index 00000000..1bcebf1d --- /dev/null +++ b/bin/core/imag-link/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!(libimaglinkcmd, ImagLink); diff --git a/bin/core/imag-link/src/main.rs b/bin/core/imag-link/src/lib.rs similarity index 89% rename from bin/core/imag-link/src/main.rs rename to bin/core/imag-link/src/lib.rs index 7e451a83..47851127 100644 --- a/bin/core/imag-link/src/main.rs +++ b/bin/core/imag-link/src/lib.rs @@ -45,7 +45,7 @@ extern crate failure; extern crate libimagentrylink; extern crate libimagentryurl; -#[macro_use] extern crate libimagrt; +extern crate libimagrt; extern crate libimagstore; extern crate libimagerror; @@ -69,7 +69,7 @@ use libimagerror::trace::{MapErrTrace, trace_error}; use libimagerror::exit::ExitUnwrap; use libimagerror::io::ToExitCode; use libimagrt::runtime::Runtime; -use libimagrt::setup::generate_runtime_setup; +use libimagrt::application::ImagApplication; use libimagstore::store::FileLockEntry; use libimagstore::storeid::StoreId; use libimagutil::warn_exit::warn_exit; @@ -77,57 +77,75 @@ use libimagutil::warn_result::*; use url::Url; use failure::Fallible as Result; +use clap::App; mod ui; -use crate::ui::build_ui; +/// Marker enum for implementing ImagApplication on +/// +/// This is used by binaries crates to execute business logic +/// or to build a CLI completion. +pub enum ImagLink {} +impl ImagApplication for ImagLink { + fn run(rt: Runtime) -> Result<()> { + if rt.cli().is_present("check-consistency") { + let exit_code = match rt.store().check_link_consistency() { + Ok(_) => { + info!("Store is consistent"); + 0 + } + Err(e) => { + trace_error(&e); + 1 + } + }; + ::std::process::exit(exit_code); + } -fn main() { - let version = make_imag_version!(); - let rt = generate_runtime_setup("imag-link", - &version, - "Link entries", - build_ui); - if rt.cli().is_present("check-consistency") { - let exit_code = match rt.store().check_link_consistency() { - Ok(_) => { - info!("Store is consistent"); - 0 - } - Err(e) => { - trace_error(&e); - 1 - } - }; - ::std::process::exit(exit_code); + let _ = rt.cli() + .subcommand_name() + .map(|name| { + match name { + "remove" => remove_linking(&rt), + "unlink" => unlink(&rt), + "list" => list_linkings(&rt), + other => { + debug!("Unknown command"); + let _ = rt.handle_unknown_subcommand("imag-link", other, rt.cli()) + .map_err_trace_exit_unwrap() + .code() + .map(::std::process::exit); + }, + } + }) + .or_else(|| { + if let (Some(from), Some(to)) = (rt.cli().value_of("from"), rt.cli().values_of("to")) { + Some(link_from_to(&rt, from, to)) + } else { + warn_exit("No commandline call", 1) + } + }) + .ok_or_else(|| err_msg("No commandline call".to_owned())) + .map_err_trace_exit_unwrap(); + + Ok(()) } - rt.cli() - .subcommand_name() - .map(|name| { - match name { - "remove" => remove_linking(&rt), - "unlink" => unlink(&rt), - "list" => list_linkings(&rt), - other => { - debug!("Unknown command"); - let _ = rt.handle_unknown_subcommand("imag-link", other, rt.cli()) - .map_err_trace_exit_unwrap() - .code() - .map(::std::process::exit); - }, - } - }) - .or_else(|| { - if let (Some(from), Some(to)) = (rt.cli().value_of("from"), rt.cli().values_of("to")) { - link_from_to(&rt, from, to); - Some(()) - } else { - warn_exit("No commandline call", 1) - } - }) - .ok_or_else(|| err_msg("No commandline call".to_owned())) - .map_err_trace_exit_unwrap(); + 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 { + "Link entries" + } + + fn version() -> &'static str { + env!("CARGO_PKG_VERSION") + } } fn get_entry_by_name<'a>(rt: &'a Runtime, name: &str) -> Result>> { @@ -378,6 +396,7 @@ mod tests { modulename mock; version env!("CARGO_PKG_VERSION"); with help "imag-link mocking app"; + with ui builder function crate::ui::build_ui; } use self::mock::generate_test_runtime; use self::mock::reset_test_runtime; diff --git a/bin/core/imag-markdown/Cargo.toml b/bin/core/imag-markdown/Cargo.toml index a4575b91..e35d431a 100644 --- a/bin/core/imag-markdown/Cargo.toml +++ b/bin/core/imag-markdown/Cargo.toml @@ -34,3 +34,10 @@ version = "2.33.0" default-features = false features = ["color", "suggestions", "wrap_help"] +[lib] +name = "libimagmarkdowncmd" +path = "src/lib.rs" + +[[bin]] +name = "imag-markdown" +path = "src/bin.rs" diff --git a/bin/core/imag-markdown/src/bin.rs b/bin/core/imag-markdown/src/bin.rs new file mode 100644 index 00000000..66ddbd3c --- /dev/null +++ b/bin/core/imag-markdown/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!(libimagmarkdowncmd, ImagMarkdown); diff --git a/bin/core/imag-markdown/src/lib.rs b/bin/core/imag-markdown/src/lib.rs new file mode 100644 index 00000000..2250fe41 --- /dev/null +++ b/bin/core/imag-markdown/src/lib.rs @@ -0,0 +1,123 @@ +// +// 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, +)] + +extern crate clap; +#[macro_use] extern crate log; +extern crate failure; + +extern crate libimagerror; +extern crate libimagrt; +extern crate libimagstore; + +use std::io::Write; + +use failure::Error; +use failure::err_msg; +use failure::Fallible as Result; +use clap::App; + +use libimagerror::trace::MapErrTrace; +use libimagerror::iter::TraceIterator; +use libimagrt::runtime::Runtime; +use libimagrt::application::ImagApplication; +use libimagstore::iter::get::StoreIdGetIteratorExtension; + +mod ui; + +/// Marker enum for implementing ImagApplication on +/// +/// This is used by binaries crates to execute business logic +/// or to build a CLI completion. +pub enum ImagMarkdown {} +impl ImagApplication for ImagMarkdown { + fn run(rt: Runtime) -> Result<()> { + let only_links = rt.cli().is_present("links"); + let out = rt.stdout(); + let mut outlock = out.lock(); + + let iter = rt + .ids::() + .map_err_trace_exit_unwrap() + .unwrap_or_else(|| { + error!("No ids supplied"); + ::std::process::exit(1); + }) + .into_iter() + .map(Ok) + .into_get_iter(rt.store()) + .trace_unwrap_exit() + .map(|ofle| ofle.ok_or_else(|| { + err_msg("Entry does not exist but is in store. This is a BUG, please report!") + })) + .trace_unwrap_exit(); + + if only_links { + iter.map(|fle| libimagentrymarkdown::link::extract_links(fle.get_content())) + .for_each(|links| { + links.iter().for_each(|link| { + writeln!(outlock, "{title}: {link}", title = link.title, link = link.link) + .map_err(Error::from) + .map_err_trace_exit_unwrap(); + }) + }) + + } else { + iter.map(|fle| libimagentrymarkdown::html::to_html(fle.get_content())) + .trace_unwrap_exit() + .for_each(|html| { + writeln!(outlock, "{}", html).map_err(Error::from).map_err_trace_exit_unwrap(); + }) + } + + 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 { + "Print one or more imag entries after processing them with a markdown parser" + } + + fn version() -> &'static str { + env!("CARGO_PKG_VERSION") + } +} diff --git a/bin/core/imag-markdown/src/main.rs b/bin/core/imag-markdown/src/main.rs deleted file mode 100644 index f3c1029b..00000000 --- a/bin/core/imag-markdown/src/main.rs +++ /dev/null @@ -1,102 +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, -)] - -extern crate clap; -#[macro_use] extern crate log; -extern crate failure; - -extern crate libimagerror; -#[macro_use] extern crate libimagrt; -extern crate libimagstore; - -use std::io::Write; - -use failure::Error; -use failure::err_msg; - -use libimagerror::trace::MapErrTrace; -use libimagerror::iter::TraceIterator; -use libimagrt::setup::generate_runtime_setup; -use libimagstore::iter::get::StoreIdGetIteratorExtension; - -mod ui; - -fn main() { - let version = make_imag_version!(); - let rt = generate_runtime_setup("imag-markdown", - &version, - "Print one or more imag entries after processing them with a markdown parser", - ui::build_ui); - - let only_links = rt.cli().is_present("links"); - let out = rt.stdout(); - let mut outlock = out.lock(); - - let iter = rt - .ids::() - .map_err_trace_exit_unwrap() - .unwrap_or_else(|| { - error!("No ids supplied"); - ::std::process::exit(1); - }) - .into_iter() - .map(Ok) - .into_get_iter(rt.store()) - .trace_unwrap_exit() - .map(|ofle| ofle.ok_or_else(|| { - err_msg("Entry does not exist but is in store. This is a BUG, please report!") - })) - .trace_unwrap_exit(); - - if only_links { - iter.map(|fle| libimagentrymarkdown::link::extract_links(fle.get_content())) - .for_each(|links| { - links.iter().for_each(|link| { - writeln!(outlock, "{title}: {link}", title = link.title, link = link.link) - .map_err(Error::from) - .map_err_trace_exit_unwrap(); - }) - }) - - } else { - iter.map(|fle| libimagentrymarkdown::html::to_html(fle.get_content())) - .trace_unwrap_exit() - .for_each(|html| { - writeln!(outlock, "{}", html).map_err(Error::from).map_err_trace_exit_unwrap(); - }) - } -} - 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(); - } -} diff --git a/bin/core/imag-ref/Cargo.toml b/bin/core/imag-ref/Cargo.toml index 5333054a..a0223e0c 100644 --- a/bin/core/imag-ref/Cargo.toml +++ b/bin/core/imag-ref/Cargo.toml @@ -35,3 +35,10 @@ version = "2.33.0" default-features = false features = ["color", "suggestions", "wrap_help"] +[lib] +name = "libimagrefcmd" +path = "src/lib.rs" + +[[bin]] +name = "imag-ref" +path = "src/bin.rs" diff --git a/bin/core/imag-ref/src/bin.rs b/bin/core/imag-ref/src/bin.rs new file mode 100644 index 00000000..721f3477 --- /dev/null +++ b/bin/core/imag-ref/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!(libimagrefcmd, ImagRef); diff --git a/bin/core/imag-ref/src/main.rs b/bin/core/imag-ref/src/lib.rs similarity index 83% rename from bin/core/imag-ref/src/main.rs rename to bin/core/imag-ref/src/lib.rs index 585c69f4..7cbcb251 100644 --- a/bin/core/imag-ref/src/main.rs +++ b/bin/core/imag-ref/src/lib.rs @@ -39,23 +39,24 @@ extern crate clap; #[macro_use] extern crate failure; extern crate libimagstore; -#[macro_use] extern crate libimagrt; +extern crate libimagrt; extern crate libimagentryref; extern crate libimagerror; extern crate libimaginteraction; extern crate libimagutil; mod ui; -use crate::ui::build_ui; use std::process::exit; use std::io::Write; use failure::Error; +use failure::Fallible as Result; +use clap::App; use libimagerror::trace::MapErrTrace; use libimagerror::exit::ExitUnwrap; -use libimagrt::setup::generate_runtime_setup; +use libimagrt::application::ImagApplication; use libimagrt::runtime::Runtime; use libimagentryref::reference::Ref; use libimagentryref::reference::MutRef; @@ -63,27 +64,47 @@ use libimagentryref::reference::RefFassade; use libimagentryref::hasher::default::DefaultHasher; use libimagentryref::util::get_ref_config; -fn main() { - let version = make_imag_version!(); - let rt = generate_runtime_setup("imag-ref", - &version, - "Reference files outside of the store", - build_ui); - if let Some(name) = rt.cli().subcommand_name() { - debug!("Call: {}", name); - match name { - "deref" => deref(&rt), - "create" => create(&rt), - "remove" => remove(&rt), - "list-dead" => list_dead(&rt), - other => { - debug!("Unknown command"); - let _ = rt.handle_unknown_subcommand("imag-ref", other, rt.cli()) - .map_err_trace_exit_unwrap() - .code() - .map(::std::process::exit); - }, +/// Marker enum for implementing ImagApplication on +/// +/// This is used by binaries crates to execute business logic +/// or to build a CLI completion. +pub enum ImagRef {} +impl ImagApplication for ImagRef { + fn run(rt: Runtime) -> Result<()> { + if let Some(name) = rt.cli().subcommand_name() { + debug!("Call: {}", name); + match name { + "deref" => deref(&rt), + "create" => create(&rt), + "remove" => remove(&rt), + "list-dead" => list_dead(&rt), + other => { + debug!("Unknown command"); + let _ = rt.handle_unknown_subcommand("imag-ref", other, rt.cli()) + .map_err_trace_exit_unwrap() + .code() + .map(::std::process::exit); + }, + } }; + + 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 { + "Reference files outside of the store" + } + + fn version() -> &'static str { + env!("CARGO_PKG_VERSION") } } diff --git a/bin/core/imag-store/Cargo.toml b/bin/core/imag-store/Cargo.toml index 89b02275..a964363c 100644 --- a/bin/core/imag-store/Cargo.toml +++ b/bin/core/imag-store/Cargo.toml @@ -52,3 +52,10 @@ path = "../../../lib/core/libimagrt" default-features = false features = ["testing"] +[lib] +name = "libimagstorecmd" +path = "src/lib.rs" + +[[bin]] +name = "imag-store" +path = "src/bin.rs" diff --git a/bin/core/imag-store/src/bin.rs b/bin/core/imag-store/src/bin.rs new file mode 100644 index 00000000..841df91b --- /dev/null +++ b/bin/core/imag-store/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!(libimagstorecmd, ImagStore); diff --git a/bin/core/imag-store/src/create.rs b/bin/core/imag-store/src/create.rs index 0384310f..c4a8ad14 100644 --- a/bin/core/imag-store/src/create.rs +++ b/bin/core/imag-store/src/create.rs @@ -168,6 +168,7 @@ mod tests { modulename mock; version env!("CARGO_PKG_VERSION"); with help "imag-store mocking app"; + with ui builder function crate::ui::build_ui; } use self::mock::generate_test_runtime; diff --git a/bin/core/imag-store/src/delete.rs b/bin/core/imag-store/src/delete.rs index b6189414..e361d535 100644 --- a/bin/core/imag-store/src/delete.rs +++ b/bin/core/imag-store/src/delete.rs @@ -49,6 +49,7 @@ mod tests { modulename mock; version env!("CARGO_PKG_VERSION"); with help "imag-store mocking app"; + with ui builder function crate::ui::build_ui; } use self::mock::generate_test_runtime; use self::mock::reset_test_runtime; diff --git a/bin/core/imag-store/src/main.rs b/bin/core/imag-store/src/lib.rs similarity index 52% rename from bin/core/imag-store/src/main.rs rename to bin/core/imag-store/src/lib.rs index 6ba6ad98..1936ecef 100644 --- a/bin/core/imag-store/src/main.rs +++ b/bin/core/imag-store/src/lib.rs @@ -40,7 +40,7 @@ extern crate toml; #[cfg(test)] extern crate toml_query; extern crate failure; -#[macro_use] extern crate libimagrt; +extern crate libimagrt; extern crate libimagstore; extern crate libimagerror; @@ -51,7 +51,8 @@ extern crate libimagutil; #[cfg(not(test))] extern crate libimagutil; -use libimagrt::setup::generate_runtime_setup; +use libimagrt::application::ImagApplication; +use libimagrt::runtime::Runtime; use libimagerror::trace::MapErrTrace; mod create; @@ -65,42 +66,62 @@ mod util; use std::ops::Deref; +use failure::Fallible as Result; +use clap::App; + use crate::create::create; use crate::delete::delete; use crate::get::get; use crate::retrieve::retrieve; -use crate::ui::build_ui; use crate::update::update; use crate::verify::verify; -fn main() { - let version = make_imag_version!(); - let rt = generate_runtime_setup("imag-store", - &version, - "Direct interface to the store. Use with great care!", - build_ui); +/// Marker enum for implementing ImagApplication on +/// +/// This is used by binaries crates to execute business logic +/// or to build a CLI completion. +pub enum ImagStore {} +impl ImagApplication for ImagStore { + fn run(rt: Runtime) -> Result<()> { + let command = rt.cli().subcommand_name().map(String::from); - let command = rt.cli().subcommand_name().map(String::from); + if let Some(command) = command { + debug!("Call: {}", command); + match command.deref() { + "create" => create(&rt), + "delete" => delete(&rt), + "get" => get(&rt), + "retrieve" => retrieve(&rt), + "update" => update(&rt), + "verify" => verify(&rt), + other => { + debug!("Unknown command"); + let _ = rt.handle_unknown_subcommand("imag-store", other, rt.cli()) + .map_err_trace_exit_unwrap() + .code() + .map(::std::process::exit); + }, + }; + } else { + debug!("No command"); + } - if let Some(command) = command { - debug!("Call: {}", command); - match command.deref() { - "create" => create(&rt), - "delete" => delete(&rt), - "get" => get(&rt), - "retrieve" => retrieve(&rt), - "update" => update(&rt), - "verify" => verify(&rt), - other => { - debug!("Unknown command"); - let _ = rt.handle_unknown_subcommand("imag-store", other, rt.cli()) - .map_err_trace_exit_unwrap() - .code() - .map(::std::process::exit); - }, - }; - } else { - debug!("No command"); + 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 { + "Direct interface to the store. Use with great care!" + } + + fn version() -> &'static str { + env!("CARGO_PKG_VERSION") } } - diff --git a/bin/core/imag-tag/Cargo.toml b/bin/core/imag-tag/Cargo.toml index 43cd6a8c..bafc7b0b 100644 --- a/bin/core/imag-tag/Cargo.toml +++ b/bin/core/imag-tag/Cargo.toml @@ -51,3 +51,10 @@ path = "../../../lib/core/libimagrt" default-features = false features = ["testing"] +[lib] +name = "libimagtagcmd" +path = "src/lib.rs" + +[[bin]] +name = "imag-tag" +path = "src/bin.rs" diff --git a/bin/core/imag-tag/src/bin.rs b/bin/core/imag-tag/src/bin.rs new file mode 100644 index 00000000..aca06ce2 --- /dev/null +++ b/bin/core/imag-tag/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!(libimagtagcmd, ImagTag); diff --git a/bin/core/imag-tag/src/main.rs b/bin/core/imag-tag/src/lib.rs similarity index 84% rename from bin/core/imag-tag/src/main.rs rename to bin/core/imag-tag/src/lib.rs index 30eb37e2..2e917884 100644 --- a/bin/core/imag-tag/src/main.rs +++ b/bin/core/imag-tag/src/lib.rs @@ -41,7 +41,7 @@ extern crate clap; extern crate failure; extern crate libimagstore; -#[macro_use] extern crate libimagrt; +extern crate libimagrt; extern crate libimagentrytag; extern crate libimagerror; @@ -61,7 +61,7 @@ extern crate env_logger; use std::io::Write; use libimagrt::runtime::Runtime; -use libimagrt::setup::generate_runtime_setup; +use libimagrt::application::ImagApplication; use libimagentrytag::tagable::Tagable; use libimagentrytag::tag::Tag; use libimagerror::trace::trace_error; @@ -71,53 +71,72 @@ use libimagerror::exit::ExitUnwrap; use libimagstore::storeid::StoreId; use libimagutil::warn_exit::warn_exit; -use clap::ArgMatches; +use clap::{App, ArgMatches}; +use failure::Fallible as Result; mod ui; -use crate::ui::build_ui; -fn main() { - let version = make_imag_version!(); - let rt = generate_runtime_setup("imag-tag", - &version, - "Direct interface to the store. Use with great care!", - build_ui); +/// Marker enum for implementing ImagApplication on +/// +/// This is used by binaries crates to execute business logic +/// or to build a CLI completion. +pub enum ImagTag {} +impl ImagApplication for ImagTag { + fn run(rt: Runtime) -> Result<()> { + let ids = rt + .ids::() + .map_err_trace_exit_unwrap() + .unwrap_or_else(|| { + error!("No ids supplied"); + ::std::process::exit(1); + }) + .into_iter(); - let ids = rt - .ids::() - .map_err_trace_exit_unwrap() - .unwrap_or_else(|| { - error!("No ids supplied"); - ::std::process::exit(1); - }) - .into_iter(); - - if let Some(name) = rt.cli().subcommand_name() { - match name { - "list" => for id in ids { - list(id, &rt) - }, - "remove" => for id in ids { - 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 add = get_add_tags(rt.cli()); - let rem = None; - debug!("id = {:?}, add = {:?}, rem = {:?}", id, add, rem); - alter(&rt, id, add, rem); - }, - other => { - debug!("Unknown command"); - let _ = rt.handle_unknown_subcommand("imag-tag", other, rt.cli()) - .map_err_trace_exit_unwrap() - .code() - .map(::std::process::exit); - }, + if let Some(name) = rt.cli().subcommand_name() { + match name { + "list" => for id in ids { + list(id, &rt) + }, + "remove" => for id in ids { + 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 add = get_add_tags(rt.cli()); + let rem = None; + debug!("id = {:?}, add = {:?}, rem = {:?}", id, add, rem); + alter(&rt, id, add, rem); + }, + other => { + debug!("Unknown command"); + let _ = rt.handle_unknown_subcommand("imag-tag", other, rt.cli()) + .map_err_trace_exit_unwrap() + .code() + .map(::std::process::exit); + }, + } } + + 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 { + "Manage tags of entries" + } + + fn version() -> &'static str { + env!("CARGO_PKG_VERSION") } } @@ -263,6 +282,7 @@ mod tests { modulename mock; version env!("CARGO_PKG_VERSION"); with help "imag-tag mocking app"; + with ui builder function crate::ui::build_ui; } use self::mock::generate_test_runtime; diff --git a/bin/core/imag-view/Cargo.toml b/bin/core/imag-view/Cargo.toml index e89905d3..0525afec 100644 --- a/bin/core/imag-view/Cargo.toml +++ b/bin/core/imag-view/Cargo.toml @@ -41,3 +41,10 @@ version = "2.33.0" default-features = false features = ["color", "suggestions", "wrap_help"] +[lib] +name = "libimagviewcmd" +path = "src/lib.rs" + +[[bin]] +name = "imag-view" +path = "src/bin.rs" diff --git a/bin/core/imag-view/src/bin.rs b/bin/core/imag-view/src/bin.rs new file mode 100644 index 00000000..ce5803f9 --- /dev/null +++ b/bin/core/imag-view/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!(libimagviewcmd, ImagView); diff --git a/bin/core/imag-view/src/lib.rs b/bin/core/imag-view/src/lib.rs new file mode 100644 index 00000000..7e9127cc --- /dev/null +++ b/bin/core/imag-view/src/lib.rs @@ -0,0 +1,315 @@ +// +// 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, +)] + +extern crate clap; +#[macro_use] extern crate log; +extern crate handlebars; +extern crate tempfile; +extern crate toml; +extern crate toml_query; +extern crate failure; + +extern crate libimagentryview; +extern crate libimagerror; +extern crate libimagrt; +extern crate libimagstore; +extern crate libimagutil; + +use std::str::FromStr; +use std::collections::BTreeMap; +use std::io::Write; +use std::process::Command; +use std::process::exit; + +use handlebars::Handlebars; +use toml_query::read::TomlValueReadTypeExt; +use failure::Error; +use failure::err_msg; +use failure::Fallible as Result; +use clap::App; + +use libimagrt::runtime::Runtime; +use libimagrt::application::ImagApplication; +use libimagerror::trace::MapErrTrace; +use libimagerror::iter::TraceIterator; +use libimagerror::io::ToExitCode; +use libimagerror::exit::ExitUnwrap; +use libimagentryview::builtin::stdout::StdoutViewer; +use libimagentryview::builtin::md::MarkdownViewer; +use libimagentryview::viewer::Viewer; +use libimagstore::iter::get::StoreIdGetIteratorExtension; +use libimagstore::store::FileLockEntry; + +mod ui; + +/// Marker enum for implementing ImagApplication on +/// +/// This is used by binaries crates to execute business logic +/// or to build a CLI completion. +pub enum ImagView {} +impl ImagApplication for ImagView { + fn run(rt: Runtime) -> Result<()> { + 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() + .unwrap_or_else(|| { + error!("No ids supplied"); + ::std::process::exit(1); + }) + .into_iter() + .map(Ok) + .into_get_iter(rt.store()) + .trace_unwrap_exit() + .map(|e| { + e.ok_or_else(|| err_msg("Entry not found")) + .map_err(Error::from) + .map_err_trace_exit_unwrap() + }); + + if rt.cli().is_present("in") { + let files = entries + .map(|entry| { + let tmpfile = create_tempfile_for(&entry, view_header, hide_content); + rt.report_touched(entry.get_location()).unwrap_or_exit(); + tmpfile + }) + .collect::>(); + + let mut command = { + let viewer = rt + .cli() + .value_of("in") + .ok_or_else(|| Error::from(err_msg("No viewer given"))) + .map_err_trace_exit_unwrap(); + + let config = rt + .config() + .ok_or_else(|| Error::from(err_msg("No configuration, cannot continue"))) + .map_err_trace_exit_unwrap(); + + let query = format!("view.viewers.{}", viewer); + + let viewer_template = config + .read_string(&query) + .map_err(Error::from) + .map_err_trace_exit_unwrap() + .unwrap_or_else(|| { + error!("Cannot find '{}' in config", query); + exit(1) + }); + + let mut handlebars = Handlebars::new(); + handlebars.register_escape_fn(::handlebars::no_escape); + + let _ = handlebars + .register_template_string("template", viewer_template) + .map_err(Error::from) + .map_err_trace_exit_unwrap(); + + let mut data = BTreeMap::new(); + + let file_paths = files + .iter() + .map(|&(_, ref path)| path.clone()) + .collect::>() + .join(" "); + + data.insert("entries", file_paths); + + let call = handlebars + .render("template", &data) + .map_err(Error::from) + .map_err_trace_exit_unwrap(); + let mut elems = call.split_whitespace(); + let command_string = elems + .next() + .ok_or_else(|| Error::from(err_msg("No command"))) + .map_err_trace_exit_unwrap(); + let mut cmd = Command::new(command_string); + + for arg in elems { + cmd.arg(arg); + } + + cmd + }; + + debug!("Calling: {:?}", command); + + if !command + .status() + .map_err(Error::from) + .map_err_trace_exit_unwrap() + .success() + { + exit(1) + } + + drop(files); + } else { + let out = rt.stdout(); + let mut outlock = out.lock(); + + let basesep = if rt.cli().occurrences_of("seperator") != 0 { // checker for default value + rt.cli().value_of("seperator").map(String::from) + } else { + None + }; + + let mut sep_width = 80; // base width, automatically overridden by wrap width + + // Helper to build the seperator with a base string `sep` and a `width` + let build_seperator = |sep: String, width: usize| -> String { + sep.repeat(width / sep.len()) + }; + + if rt.cli().is_present("compile-md") { + let viewer = MarkdownViewer::new(&rt); + let seperator = basesep.map(|s| build_seperator(s, sep_width)); + + entries + .enumerate() + .for_each(|(n, entry)| { + if n != 0 { + seperator + .as_ref() + .map(|s| writeln!(outlock, "{}", s).to_exit_code().unwrap_or_exit()); + } + + if let Err(e) = viewer.view_entry(&entry, &mut outlock) { + handle_error(e); + } + + rt.report_touched(entry.get_location()).unwrap_or_exit(); + }); + } else { + let mut viewer = StdoutViewer::new(view_header, !hide_content); + + if rt.cli().occurrences_of("autowrap") != 0 { + let width = rt.cli().value_of("autowrap").unwrap(); // ensured by clap + let width = usize::from_str(width).unwrap_or_else(|e| { + error!("Failed to parse argument to number: autowrap = {:?}", + rt.cli().value_of("autowrap").map(String::from)); + error!("-> {:?}", e); + ::std::process::exit(1) + }); + + // Copying this value over, so that the seperator has the right len as well + sep_width = width; + + viewer.wrap_at(width); + } + + let seperator = basesep.map(|s| build_seperator(s, sep_width)); + entries + .enumerate() + .for_each(|(n, entry)| { + if n != 0 { + seperator + .as_ref() + .map(|s| writeln!(outlock, "{}", s).to_exit_code().unwrap_or_exit()); + } + + if let Err(e) = viewer.view_entry(&entry, &mut outlock) { + handle_error(e); + } + + rt.report_touched(entry.get_location()).unwrap_or_exit(); + }); + } + } + + Ok(()) + } + + 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 { + "View entries (readonly)" + } + + fn version() -> &'static str { + env!("CARGO_PKG_VERSION") + } +} + +fn create_tempfile_for<'a>(entry: &FileLockEntry<'a>, view_header: bool, hide_content: bool) + -> (tempfile::NamedTempFile, String) +{ + let mut tmpfile = tempfile::NamedTempFile::new() + .map_err(Error::from) + .map_err_trace_exit_unwrap(); + + if view_header { + let hdr = toml::ser::to_string_pretty(entry.get_header()) + .map_err(Error::from) + .map_err_trace_exit_unwrap(); + let _ = tmpfile.write(format!("---\n{}---\n", hdr).as_bytes()) + .map_err(Error::from) + .map_err_trace_exit_unwrap(); + } + + if !hide_content { + let _ = tmpfile.write(entry.get_content().as_bytes()) + .map_err(Error::from) + .map_err_trace_exit_unwrap(); + } + + let file_path = tmpfile + .path() + .to_str() + .map(String::from) + .ok_or_else(|| Error::from(err_msg("Cannot build path"))) + .map_err_trace_exit_unwrap(); + + (tmpfile, file_path) +} + +fn handle_error(e: ::libimagentryview::error::Error) { + use libimagentryview::error::Error; + match e { + Error::Io(e) => Err(e).to_exit_code().unwrap_or_exit(), + Error::Other(e) => Err(e).map_err_trace_exit_unwrap() + } +} diff --git a/bin/core/imag-view/src/main.rs b/bin/core/imag-view/src/main.rs deleted file mode 100644 index cb35f0d0..00000000 --- a/bin/core/imag-view/src/main.rs +++ /dev/null @@ -1,293 +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, -)] - -extern crate clap; -#[macro_use] extern crate log; -extern crate handlebars; -extern crate tempfile; -extern crate toml; -extern crate toml_query; -extern crate failure; - -extern crate libimagentryview; -extern crate libimagerror; -#[macro_use] extern crate libimagrt; -extern crate libimagstore; -extern crate libimagutil; - -use std::str::FromStr; -use std::collections::BTreeMap; -use std::io::Write; -use std::process::Command; -use std::process::exit; - -use handlebars::Handlebars; -use toml_query::read::TomlValueReadTypeExt; -use failure::Error; -use failure::err_msg; - -use libimagrt::setup::generate_runtime_setup; -use libimagerror::trace::MapErrTrace; -use libimagerror::iter::TraceIterator; -use libimagerror::io::ToExitCode; -use libimagerror::exit::ExitUnwrap; -use libimagentryview::builtin::stdout::StdoutViewer; -use libimagentryview::builtin::md::MarkdownViewer; -use libimagentryview::viewer::Viewer; -use libimagstore::iter::get::StoreIdGetIteratorExtension; -use libimagstore::store::FileLockEntry; - -mod ui; -use crate::ui::build_ui; - -fn main() { - let version = make_imag_version!(); - let rt = generate_runtime_setup( "imag-view", - &version, - "View entries (readonly)", - build_ui); - - 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() - .unwrap_or_else(|| { - error!("No ids supplied"); - ::std::process::exit(1); - }) - .into_iter() - .map(Ok) - .into_get_iter(rt.store()) - .trace_unwrap_exit() - .map(|e| { - e.ok_or_else(|| err_msg("Entry not found")) - .map_err(Error::from) - .map_err_trace_exit_unwrap() - }); - - if rt.cli().is_present("in") { - let files = entries - .map(|entry| { - let tmpfile = create_tempfile_for(&entry, view_header, hide_content); - rt.report_touched(entry.get_location()).unwrap_or_exit(); - tmpfile - }) - .collect::>(); - - let mut command = { - let viewer = rt - .cli() - .value_of("in") - .ok_or_else(|| err_msg("No viewer given")) - .map_err_trace_exit_unwrap(); - - let config = rt - .config() - .ok_or_else(|| err_msg("No configuration, cannot continue")) - .map_err_trace_exit_unwrap(); - - let query = format!("view.viewers.{}", viewer); - - let viewer_template = config - .read_string(&query) - .map_err(Error::from) - .map_err_trace_exit_unwrap() - .unwrap_or_else(|| { - error!("Cannot find '{}' in config", query); - exit(1) - }); - - let mut handlebars = Handlebars::new(); - handlebars.register_escape_fn(::handlebars::no_escape); - - handlebars - .register_template_string("template", viewer_template) - .map_err(Error::from) - .map_err_trace_exit_unwrap(); - - let mut data = BTreeMap::new(); - - let file_paths = files - .iter() - .map(|&(_, ref path)| path.clone()) - .collect::>() - .join(" "); - - data.insert("entries", file_paths); - - let call = handlebars - .render("template", &data) - .map_err(Error::from) - .map_err_trace_exit_unwrap(); - let mut elems = call.split_whitespace(); - let command_string = elems - .next() - .ok_or_else(|| err_msg("No command")) - .map_err_trace_exit_unwrap(); - let mut cmd = Command::new(command_string); - - for arg in elems { - cmd.arg(arg); - } - - cmd - }; - - debug!("Calling: {:?}", command); - - if !command - .status() - .map_err(Error::from) - .map_err_trace_exit_unwrap() - .success() - { - exit(1) - } - - drop(files); - } else { - let out = rt.stdout(); - let mut outlock = out.lock(); - - let basesep = if rt.cli().occurrences_of("seperator") != 0 { // checker for default value - rt.cli().value_of("seperator").map(String::from) - } else { - None - }; - - let mut sep_width = 80; // base width, automatically overridden by wrap width - - // Helper to build the seperator with a base string `sep` and a `width` - let build_seperator = |sep: String, width: usize| -> String { - sep.repeat(width / sep.len()) - }; - - if rt.cli().is_present("compile-md") { - let viewer = MarkdownViewer::new(&rt); - let seperator = basesep.map(|s| build_seperator(s, sep_width)); - - entries - .enumerate() - .for_each(|(n, entry)| { - if n != 0 { - if let Some(s) = seperator - .as_ref() { writeln!(outlock, "{}", s).to_exit_code().unwrap_or_exit() } - } - - if let Err(e) = viewer.view_entry(&entry, &mut outlock) { - handle_error(e); - } - - rt.report_touched(entry.get_location()).unwrap_or_exit(); - }); - } else { - let mut viewer = StdoutViewer::new(view_header, !hide_content); - - if rt.cli().occurrences_of("autowrap") != 0 { - let width = rt.cli().value_of("autowrap").unwrap(); // ensured by clap - let width = usize::from_str(width).unwrap_or_else(|e| { - error!("Failed to parse argument to number: autowrap = {:?}", - rt.cli().value_of("autowrap").map(String::from)); - error!("-> {:?}", e); - ::std::process::exit(1) - }); - - // Copying this value over, so that the seperator has the right len as well - sep_width = width; - - viewer.wrap_at(width); - } - - let seperator = basesep.map(|s| build_seperator(s, sep_width)); - entries - .enumerate() - .for_each(|(n, entry)| { - if n != 0 { - if let Some(s) = seperator - .as_ref() { writeln!(outlock, "{}", s).to_exit_code().unwrap_or_exit() } - } - - if let Err(e) = viewer.view_entry(&entry, &mut outlock) { - handle_error(e); - } - - rt.report_touched(entry.get_location()).unwrap_or_exit(); - }); - } - } -} - -fn create_tempfile_for<'a>(entry: &FileLockEntry<'a>, view_header: bool, hide_content: bool) - -> (tempfile::NamedTempFile, String) -{ - let mut tmpfile = tempfile::NamedTempFile::new() - .map_err(Error::from) - .map_err_trace_exit_unwrap(); - - if view_header { - let hdr = toml::ser::to_string_pretty(entry.get_header()) - .map_err(Error::from) - .map_err_trace_exit_unwrap(); - let _ = tmpfile.write(format!("---\n{}---\n", hdr).as_bytes()) - .map_err(Error::from) - .map_err_trace_exit_unwrap(); - } - - if !hide_content { - let _ = tmpfile.write(entry.get_content().as_bytes()) - .map_err(Error::from) - .map_err_trace_exit_unwrap(); - } - - let file_path = tmpfile - .path() - .to_str() - .map(String::from) - .ok_or_else(|| err_msg("Cannot build path")) - .map_err_trace_exit_unwrap(); - - (tmpfile, file_path) -} - -fn handle_error(e: ::libimagentryview::error::Error) { - use libimagentryview::error::Error; - match e { - Error::Io(e) => Err(e).to_exit_code().unwrap_or_exit(), - Error::Other(e) => Err(e).map_err_trace_exit_unwrap() - } -} - diff --git a/bin/core/imag/Cargo.toml b/bin/core/imag/Cargo.toml index c3a6df66..4c7df6dc 100644 --- a/bin/core/imag/Cargo.toml +++ b/bin/core/imag/Cargo.toml @@ -23,6 +23,33 @@ libimagutil = { version = "0.10.0", path = "../../../lib/etc/libimagutil" } failure = "0.1.5" log = "0.4.6" +# Build time dependencies for cli completion +imag-annotate = { optional = true, path = "../imag-annotate" } +imag-create = { optional = true, path = "../imag-create" } +imag-diagnostics = { optional = true, path = "../imag-diagnostics" } +imag-edit = { optional = true, path = "../imag-edit" } +imag-gps = { optional = true, path = "../imag-gps" } +imag-grep = { optional = true, path = "../imag-grep" } +imag-ids = { optional = true, path = "../imag-ids" } +imag-init = { optional = true, path = "../imag-init" } +imag-link = { optional = true, path = "../imag-link" } +imag-mv = { optional = true, path = "../imag-mv" } +imag-ref = { optional = true, path = "../imag-ref" } +imag-store = { optional = true, path = "../imag-store" } +imag-tag = { optional = true, path = "../imag-tag" } +imag-view = { optional = true, path = "../imag-view" } +imag-bookmark = { optional = true, path = "../../domain/imag-bookmark" } +imag-calendar = { optional = true, path = "../../domain/imag-calendar" } +imag-contact = { optional = true, path = "../../domain/imag-contact" } +imag-diary = { optional = true, path = "../../domain/imag-diary" } +imag-habit = { optional = true, path = "../../domain/imag-habit" } +imag-log = { optional = true, path = "../../domain/imag-log" } +imag-mail = { optional = true, path = "../../domain/imag-mail" } +imag-notes = { optional = true, path = "../../domain/imag-notes" } +imag-timetrack = { optional = true, path = "../../domain/imag-timetrack" } +imag-todo = { optional = true, path = "../../domain/imag-todo" } +imag-wiki = { optional = true, path = "../../domain/imag-wiki" } + [badges] travis-ci = { repository = "matthiasbeyer/imag" } is-it-maintained-issue-resolution = { repository = "matthiasbeyer/imag" } @@ -48,3 +75,59 @@ version = "0.10.0" path = "../../../lib/core/libimagrt" features = ["pub_logging_initialization"] +[features] +default = [ "cc-all" ] + +# Features for enabling cli completion files for individual subcommands +cc-all = [ + "cc-imag-annotate", + "cc-imag-create", + "cc-imag-diagnostics", + "cc-imag-edit", + "cc-imag-gps", + "cc-imag-grep", + "cc-imag-ids", + "cc-imag-init", + "cc-imag-link", + "cc-imag-mv", + "cc-imag-ref", + "cc-imag-store", + "cc-imag-tag", + "cc-imag-view", + "cc-imag-bookmark", + "cc-imag-calendar", + "cc-imag-contact", + "cc-imag-diary", + "cc-imag-habit", + "cc-imag-log", + "cc-imag-mail", + "cc-imag-notes", + "cc-imag-timetrack", + "cc-imag-todo", + "cc-imag-wiki", +] +cc-imag-annotate = [ "imag-annotate" ] +cc-imag-create = [ "imag-create" ] +cc-imag-diagnostics = [ "imag-diagnostics" ] +cc-imag-edit = [ "imag-edit" ] +cc-imag-gps = [ "imag-gps" ] +cc-imag-grep = [ "imag-grep" ] +cc-imag-ids = [ "imag-ids" ] +cc-imag-init = [ "imag-init" ] +cc-imag-link = [ "imag-link" ] +cc-imag-mv = [ "imag-mv" ] +cc-imag-ref = [ "imag-ref" ] +cc-imag-store = [ "imag-store" ] +cc-imag-tag = [ "imag-tag" ] +cc-imag-view = [ "imag-view" ] +cc-imag-bookmark = [ "imag-bookmark" ] +cc-imag-calendar = [ "imag-calendar" ] +cc-imag-contact = [ "imag-contact" ] +cc-imag-diary = [ "imag-diary" ] +cc-imag-habit = [ "imag-habit" ] +cc-imag-log = [ "imag-log" ] +cc-imag-mail = [ "imag-mail" ] +cc-imag-notes = [ "imag-notes" ] +cc-imag-timetrack = [ "imag-timetrack" ] +cc-imag-todo = [ "imag-todo" ] +cc-imag-wiki = [ "imag-wiki" ] \ No newline at end of file diff --git a/bin/core/imag/build.rs b/bin/core/imag/build.rs new file mode 100644 index 00000000..c7675ff2 --- /dev/null +++ b/bin/core/imag/build.rs @@ -0,0 +1,164 @@ +// +// 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 +// + +extern crate clap; +extern crate libimagrt; +extern crate libimagentrytag; +extern crate libimagutil; + +use clap::Shell; +use libimagrt::runtime::Runtime; + +#[allow(unused_imports)] +use libimagrt::application::ImagApplication; + +#[cfg(feature = "cc-imag-annotate")] +extern crate libimagannotatecmd; +#[cfg(feature = "cc-imag-create")] +extern crate libimagcreatecmd; +#[cfg(feature = "cc-imag-diagnostics")] +extern crate libimagdiagnosticscmd; +#[cfg(feature = "cc-imag-edit")] +extern crate libimageditcmd; +#[cfg(feature = "cc-imag-gps")] +extern crate libimaggpscmd; +#[cfg(feature = "cc-imag-grep")] +extern crate libimaggrepcmd; +#[cfg(feature = "cc-imag-ids")] +extern crate libimagidscmd; +#[cfg(feature = "cc-imag-init")] +extern crate libimaginitcmd; +#[cfg(feature = "cc-imag-link")] +extern crate libimaglinkcmd; +#[cfg(feature = "cc-imag-mv")] +extern crate libimagmvcmd; +#[cfg(feature = "cc-imag-ref")] +extern crate libimagrefcmd; +#[cfg(feature = "cc-imag-store")] +extern crate libimagstorecmd; +#[cfg(feature = "cc-imag-tag")] +extern crate libimagtagcmd; +#[cfg(feature = "cc-imag-view")] +extern crate libimagviewcmd; +#[cfg(feature = "cc-imag-bookmark")] +extern crate libimagbookmarkfrontend; +#[cfg(feature = "cc-imag-calendar")] +extern crate libimagcalendarfrontend; +#[cfg(feature = "cc-imag-contact")] +extern crate libimagcontactfrontend; +#[cfg(feature = "cc-imag-diary")] +extern crate libimagdiaryfrontend; +#[cfg(feature = "cc-imag-habit")] +extern crate libimaghabitfrontend; +#[cfg(feature = "cc-imag-log")] +extern crate libimaglogfrontend; +#[cfg(feature = "cc-imag-mail")] +extern crate libimagmailfrontend; +#[cfg(feature = "cc-imag-notes")] +extern crate libimagnotesfrontend; +#[cfg(feature = "cc-imag-timetrack")] +extern crate libimagtimetrackfrontend; +#[cfg(feature = "cc-imag-todo")] +extern crate libimagtodofrontend; + +/// This macro reduces boilerplate code. +/// +/// For example: `build_subcommand!("counter", libbinimagcounter, ImagCounter)` +/// will result in the following code: +/// ```ignore +/// ImagCounter::build_cli(Runtime::get_default_cli_builder( +/// "counter", +/// "abc", +/// "counter")) +/// ``` +/// As for the `"abc"` part, it does not matter +/// which version the subcommand is getting here, as the +/// output of this script is a completion script, which +/// does not contain information about the version at all. +#[allow(unused_macros)] +macro_rules! build_subcommand { + ($name:expr, $lib:ident, $implementor:ident) => ( + $lib::$implementor::build_cli(Runtime::get_default_cli_builder($name, "abc", $name)) + ) +} + +fn main() { + // Make the `imag`-App... + let app = Runtime::get_default_cli_builder( + "imag", + "abc", + "imag"); + + // and add all the subapps as subcommands. + // TODO: This feels tedious, can we automate this? + #[cfg(feature = "cc-imag-annotate")] + let app = app.subcommand(build_subcommand!("annotate", libimagannotatecmd, ImagAnnotate)); + #[cfg(feature = "cc-imag-create")] + let app = app.subcommand(build_subcommand!("create", libimagcreatecmd, ImagCreate)); + #[cfg(feature = "cc-imag-diagnostics")] + let app = app.subcommand(build_subcommand!("diagnostics", libimagdiagnosticscmd, ImagDiagnostics)); + #[cfg(feature = "cc-imag-edit")] + let app = app.subcommand(build_subcommand!("edit", libimageditcmd, ImagEdit)); + #[cfg(feature = "cc-imag-gps")] + let app = app.subcommand(build_subcommand!("gps", libimaggpscmd, ImagGps)); + #[cfg(feature = "cc-imag-grep")] + let app = app.subcommand(build_subcommand!("grep", libimaggrepcmd, ImagGrep)); + #[cfg(feature = "cc-imag-ids")] + let app = app.subcommand(build_subcommand!("ids", libimagidscmd, ImagIds)); + #[cfg(feature = "cc-imag-init")] + let app = app.subcommand(build_subcommand!("init", libimaginitcmd, ImagInit)); + #[cfg(feature = "cc-imag-link")] + let app = app.subcommand(build_subcommand!("link", libimaglinkcmd, ImagLink)); + #[cfg(feature = "cc-imag-mv")] + let app = app.subcommand(build_subcommand!("mv", libimagmvcmd, ImagMv)); + #[cfg(feature = "cc-imag-ref")] + let app = app.subcommand(build_subcommand!("ref", libimagrefcmd, ImagRef)); + #[cfg(feature = "cc-imag-store")] + let app = app.subcommand(build_subcommand!("store", libimagstorecmd, ImagStore)); + #[cfg(feature = "cc-imag-tag")] + let app = app.subcommand(build_subcommand!("tag", libimagtagcmd, ImagTag)); + #[cfg(feature = "cc-imag-view")] + let app = app.subcommand(build_subcommand!("view", libimagviewcmd, ImagView)); + #[cfg(feature = "cc-imag-bookmark")] + let app = app.subcommand(build_subcommand!("bookmark", libimagbookmarkfrontend, ImagBookmark)); + #[cfg(feature = "cc-imag-calendar")] + let app = app.subcommand(build_subcommand!("calendar", libimagcalendarfrontend, ImagCalendar)); + #[cfg(feature = "cc-imag-contact")] + let app = app.subcommand(build_subcommand!("contact", libimagcontactfrontend, ImagContact)); + #[cfg(feature = "cc-imag-diary")] + let app = app.subcommand(build_subcommand!("diary", libimagdiaryfrontend, ImagDiary)); + #[cfg(feature = "cc-imag-habit")] + let app = app.subcommand(build_subcommand!("habit", libimaghabitfrontend, ImagHabit)); + #[cfg(feature = "cc-imag-log")] + let app = app.subcommand(build_subcommand!("log", libimaglogfrontend, ImagLog)); + #[cfg(feature = "cc-imag-mail")] + let app = app.subcommand(build_subcommand!("mail", libimagmailfrontend, ImagMail)); + #[cfg(feature = "cc-imag-notes")] + let app = app.subcommand(build_subcommand!("notes", libimagnotesfrontend, ImagNotes)); + #[cfg(feature = "cc-imag-timetrack")] + let app = app.subcommand(build_subcommand!("timetrack", libimagtimetrackfrontend, ImagTimetrack)); + #[cfg(feature = "cc-imag-todo")] + let app = app.subcommand(build_subcommand!("todo", libimagtodofrontend, ImagTodo)); + + let mut app = app; + // Actually generates the completion files + app.gen_completions("imag", Shell::Bash, "../../../target/"); + app.gen_completions("imag", Shell::Fish, "../../../target/"); + app.gen_completions("imag", Shell::Zsh, "../../../target/"); +} diff --git a/bin/domain/imag-bookmark/Cargo.toml b/bin/domain/imag-bookmark/Cargo.toml index d9cea246..b66a6f69 100644 --- a/bin/domain/imag-bookmark/Cargo.toml +++ b/bin/domain/imag-bookmark/Cargo.toml @@ -36,3 +36,10 @@ version = "2.33.0" default-features = false features = ["color", "suggestions", "wrap_help"] +[lib] +name = "libimagbookmarkfrontend" +path = "src/lib.rs" + +[[bin]] +name = "imag-bookmark" +path = "src/bin.rs" diff --git a/bin/domain/imag-bookmark/src/bin.rs b/bin/domain/imag-bookmark/src/bin.rs new file mode 100644 index 00000000..7497bd96 --- /dev/null +++ b/bin/domain/imag-bookmark/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!(libimagbookmarkfrontend, ImagBookmark); diff --git a/bin/domain/imag-bookmark/src/main.rs b/bin/domain/imag-bookmark/src/lib.rs similarity index 82% rename from bin/domain/imag-bookmark/src/main.rs rename to bin/domain/imag-bookmark/src/lib.rs index a932f381..bfa08b10 100644 --- a/bin/domain/imag-bookmark/src/main.rs +++ b/bin/domain/imag-bookmark/src/lib.rs @@ -41,7 +41,7 @@ extern crate toml_query; #[macro_use] extern crate failure; extern crate libimagbookmark; -#[macro_use] extern crate libimagrt; +extern crate libimagrt; extern crate libimagerror; extern crate libimagutil; extern crate libimagentrylink; @@ -52,9 +52,11 @@ use std::ops::DerefMut; use toml_query::read::TomlValueReadTypeExt; use failure::Error; +use failure::Fallible as Result; +use clap::App; use libimagrt::runtime::Runtime; -use libimagrt::setup::generate_runtime_setup; +use libimagrt::application::ImagApplication; use libimagbookmark::collection::BookmarkCollection; use libimagbookmark::collection::BookmarkCollectionStore; use libimagbookmark::link::Link as BookmarkLink; @@ -64,33 +66,49 @@ use libimagerror::exit::ExitUnwrap; use libimagutil::debug_result::DebugResult; use libimagentrylink::linkable::Linkable; - mod ui; -use crate::ui::build_ui; - -fn main() { - let version = make_imag_version!(); - let rt = generate_runtime_setup("imag-bookmark", - &version, - "Bookmark collection tool", - build_ui); - - if let Some(name) = rt.cli().subcommand_name() { - debug!("Call {}", name); - match name { - "add" => add(&rt), - "collection" => collection(&rt), - "list" => list(&rt), - "remove" => remove(&rt), - other => { - debug!("Unknown command"); - let _ = rt.handle_unknown_subcommand("imag-bookmark", other, rt.cli()) - .map_err_trace_exit_unwrap() - .code() - .map(::std::process::exit); - }, +/// Marker enum for implementing ImagApplication on +/// +/// This is used by binaries crates to execute business logic +/// or to build a CLI completion. +pub enum ImagBookmark {} +impl ImagApplication for ImagBookmark { + fn run(rt: Runtime) -> Result<()> { + if let Some(name) = rt.cli().subcommand_name() { + debug!("Call {}", name); + match name { + "add" => add(&rt), + "collection" => collection(&rt), + "list" => list(&rt), + "remove" => remove(&rt), + other => { + debug!("Unknown command"); + let _ = rt.handle_unknown_subcommand("imag-bookmark", other, rt.cli()) + .map_err_trace_exit_unwrap() + .code() + .map(::std::process::exit); + }, + } } + + 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 { + "Bookmark collection tool" + } + + fn version() -> &'static str { + env!("CARGO_PKG_VERSION") } } diff --git a/bin/domain/imag-calendar/Cargo.toml b/bin/domain/imag-calendar/Cargo.toml index 192a7402..ccc4e09d 100644 --- a/bin/domain/imag-calendar/Cargo.toml +++ b/bin/domain/imag-calendar/Cargo.toml @@ -48,3 +48,10 @@ version = "0.9.2" default-features = false features = ["typed"] +[lib] +name = "libimagcalendarfrontend" +path = "src/lib.rs" + +[[bin]] +name = "imag-calendar" +path = "src/bin.rs" \ No newline at end of file diff --git a/bin/domain/imag-calendar/src/bin.rs b/bin/domain/imag-calendar/src/bin.rs new file mode 100644 index 00000000..c164a412 --- /dev/null +++ b/bin/domain/imag-calendar/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!(libimagcalendarfrontend, ImagCalendar); diff --git a/bin/domain/imag-calendar/src/main.rs b/bin/domain/imag-calendar/src/lib.rs similarity index 90% rename from bin/domain/imag-calendar/src/main.rs rename to bin/domain/imag-calendar/src/lib.rs index c87d77d0..bb18e06b 100644 --- a/bin/domain/imag-calendar/src/main.rs +++ b/bin/domain/imag-calendar/src/lib.rs @@ -43,7 +43,7 @@ extern crate handlebars; extern crate chrono; extern crate kairos; -#[macro_use] extern crate libimagrt; +extern crate libimagrt; extern crate libimagcalendar; extern crate libimagerror; extern crate libimagstore; @@ -61,6 +61,7 @@ use toml_query::read::TomlValueReadExt; use walkdir::DirEntry; use walkdir::WalkDir; use vobject::icalendar::Event; +use clap::App; use libimagcalendar::store::EventStore; use libimagerror::io::ToExitCode; @@ -68,35 +69,53 @@ use libimagerror::exit::ExitUnwrap; use libimagerror::iter::TraceIterator; use libimagerror::trace::MapErrTrace; use libimagrt::runtime::Runtime; -use libimagrt::setup::generate_runtime_setup; +use libimagrt::application::ImagApplication; mod filters; mod ui; mod util; -fn main() { - let version = make_imag_version!(); - let rt = generate_runtime_setup("imag-calendar", - &version, - "Calendar management tool", - crate::ui::build_ui); +/// Marker enum for implementing ImagApplication on +/// +/// This is used by binary crates to execute business logic or to +/// build a CLI completion. +pub enum ImagCalendar {} +impl ImagApplication for ImagCalendar { + fn run(rt: Runtime) -> Result<()> { + if let Some(name) = rt.cli().subcommand_name() { + debug!("Call {}", name); + match name { + "import" => import(&rt), + "list" => list(&rt), + "show" => show(&rt), + other => { + warn!("Right now, only the 'import' command is available"); + debug!("Unknown command"); + let _ = rt.handle_unknown_subcommand("imag-calendar", other, rt.cli()) + .map_err_trace_exit_unwrap() + .code() + .map(::std::process::exit); + }, + } + } + Ok(()) + } - if let Some(name) = rt.cli().subcommand_name() { - debug!("Call {}", name); - match name { - "import" => import(&rt), - "list" => list(&rt), - "show" => show(&rt), - other => { - warn!("Right now, only the 'import' command is available"); - debug!("Unknown command"); - let _ = rt.handle_unknown_subcommand("imag-calendar", other, rt.cli()) - .map_err_trace_exit_unwrap() - .code() - .map(::std::process::exit); - }, - } + 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 { + "Calendar management tool" + } + + fn version() -> &'static str { + env!("CARGO_PKG_VERSION") } } diff --git a/bin/domain/imag-contact/Cargo.toml b/bin/domain/imag-contact/Cargo.toml index 6f3db11e..6260fbb8 100644 --- a/bin/domain/imag-contact/Cargo.toml +++ b/bin/domain/imag-contact/Cargo.toml @@ -47,3 +47,11 @@ features = ["color", "suggestions", "wrap_help"] version = "0.9.2" default-features = false features = ["typed"] + +[lib] +name = "libimagcontactfrontend" +path = "src/lib.rs" + +[[bin]] +name = "imag-contact" +path = "src/bin.rs" diff --git a/bin/domain/imag-contact/src/bin.rs b/bin/domain/imag-contact/src/bin.rs new file mode 100644 index 00000000..77857900 --- /dev/null +++ b/bin/domain/imag-contact/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!(libimagcontactfrontend, ImagContact); diff --git a/bin/domain/imag-contact/src/main.rs b/bin/domain/imag-contact/src/lib.rs similarity index 88% rename from bin/domain/imag-contact/src/main.rs rename to bin/domain/imag-contact/src/lib.rs index ac96198b..0285f128 100644 --- a/bin/domain/imag-contact/src/main.rs +++ b/bin/domain/imag-contact/src/lib.rs @@ -47,7 +47,7 @@ extern crate serde_json; extern crate libimagcontact; extern crate libimagstore; -#[macro_use] extern crate libimagrt; +extern crate libimagrt; extern crate libimagerror; extern crate libimagutil; extern crate libimaginteraction; @@ -59,16 +59,17 @@ use std::path::PathBuf; use std::io::Write; use handlebars::Handlebars; -use clap::ArgMatches; +use clap::{App, ArgMatches}; use toml_query::read::TomlValueReadExt; use toml_query::read::TomlValueReadTypeExt; use toml_query::read::Partial; use walkdir::WalkDir; use failure::Error; use failure::err_msg; +use failure::Fallible as Result; use libimagrt::runtime::Runtime; -use libimagrt::setup::generate_runtime_setup; +use libimagrt::application::ImagApplication; use libimagerror::trace::MapErrTrace; use libimagerror::io::ToExitCode; use libimagerror::exit::ExitUnwrap; @@ -82,36 +83,53 @@ mod util; mod create; mod edit; -use crate::ui::build_ui; use crate::util::build_data_object_for_handlebars; use crate::create::create; use crate::edit::edit; -fn main() { - let version = make_imag_version!(); - let rt = generate_runtime_setup("imag-contact", - &version, - "Contact management tool", - build_ui); - - - if let Some(name) = rt.cli().subcommand_name() { - debug!("Call {}", name); - match name { - "list" => list(&rt), - "import" => import(&rt), - "show" => show(&rt), - "edit" => edit(&rt), - "find" => find(&rt), - "create" => create(&rt), - other => { - debug!("Unknown command"); - let _ = rt.handle_unknown_subcommand("imag-contact", other, rt.cli()) - .map_err_trace_exit_unwrap() - .code() - .map(::std::process::exit); - }, +/// Marker enum for implementing ImagApplication on +/// +/// This is used by binaries crates to execute business logic +/// or to build a CLI completion. +pub enum ImagContact {} +impl ImagApplication for ImagContact { + fn run(rt: Runtime) -> Result<()> { + if let Some(name) = rt.cli().subcommand_name() { + debug!("Call {}", name); + match name { + "list" => list(&rt), + "import" => import(&rt), + "show" => show(&rt), + "edit" => edit(&rt), + "find" => find(&rt), + "create" => create(&rt), + other => { + debug!("Unknown command"); + let _ = rt.handle_unknown_subcommand("imag-contact", other, rt.cli()) + .map_err_trace_exit_unwrap() + .code() + .map(::std::process::exit); + }, + } } + + 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 { + "Contact management tool" + } + + fn version() -> &'static str { + env!("CARGO_PKG_VERSION") } } diff --git a/bin/domain/imag-diary/Cargo.toml b/bin/domain/imag-diary/Cargo.toml index 9c506110..e46a36f3 100644 --- a/bin/domain/imag-diary/Cargo.toml +++ b/bin/domain/imag-diary/Cargo.toml @@ -42,3 +42,10 @@ version = "2.33.0" default-features = false features = ["color", "suggestions", "wrap_help"] +[lib] +name = "libimagdiaryfrontend" +path = "src/lib.rs" + +[[bin]] +name = "imag-diary" +path = "src/bin.rs" diff --git a/bin/domain/imag-diary/src/bin.rs b/bin/domain/imag-diary/src/bin.rs new file mode 100644 index 00000000..f9ac3e5e --- /dev/null +++ b/bin/domain/imag-diary/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!(libimagdiaryfrontend, ImagDiary); diff --git a/bin/domain/imag-diary/src/main.rs b/bin/domain/imag-diary/src/lib.rs similarity index 63% rename from bin/domain/imag-diary/src/main.rs rename to bin/domain/imag-diary/src/lib.rs index bc1c9a1f..23629dc9 100644 --- a/bin/domain/imag-diary/src/main.rs +++ b/bin/domain/imag-diary/src/lib.rs @@ -47,18 +47,20 @@ extern crate libimagentryedit; extern crate libimagentryview; extern crate libimagerror; extern crate libimaginteraction; -#[macro_use] extern crate libimagrt; +extern crate libimagrt; extern crate libimagstore; extern crate libimagtimeui; extern crate libimagutil; use std::io::Write; -use libimagrt::setup::generate_runtime_setup; use libimagrt::runtime::Runtime; +use libimagrt::application::ImagApplication; use libimagerror::trace::MapErrTrace; use itertools::Itertools; +use clap::App; +use failure::Fallible as Result; mod create; mod delete; @@ -72,29 +74,48 @@ use crate::delete::delete; use crate::list::list; use crate::view::view; -fn main() { - let version = make_imag_version!(); - let rt = generate_runtime_setup("imag-diary", - &version, - "Personal Diary/Diaries", - ui::build_ui); - - if let Some(name) = rt.cli().subcommand_name() { - debug!("Call {}", name); - match name { - "diaries" => diaries(&rt), - "create" => create(&rt), - "delete" => delete(&rt), - "list" => list(&rt), - "view" => view(&rt), - other => { - debug!("Unknown command"); - let _ = rt.handle_unknown_subcommand("imag-diary", other, rt.cli()) - .map_err_trace_exit_unwrap() - .code() - .map(::std::process::exit); - }, +/// Marker enum for implementing ImagApplication on +/// +/// This is used by binaries crates to execute business logic +/// or to build a CLI completion. +pub enum ImagDiary {} +impl ImagApplication for ImagDiary { + fn run(rt: Runtime) -> Result<()> { + if let Some(name) = rt.cli().subcommand_name() { + debug!("Call {}", name); + match name { + "diaries" => diaries(&rt), + "create" => create(&rt), + "delete" => delete(&rt), + "list" => list(&rt), + "view" => view(&rt), + other => { + debug!("Unknown command"); + let _ = rt.handle_unknown_subcommand("imag-diary", other, rt.cli()) + .map_err_trace_exit_unwrap() + .code() + .map(::std::process::exit); + }, + } } + + 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 { + "Personal Diary/Diaries" + } + + fn version() -> &'static str { + env!("CARGO_PKG_VERSION") } } diff --git a/bin/domain/imag-habit/Cargo.toml b/bin/domain/imag-habit/Cargo.toml index c4e6b80b..a796c2e6 100644 --- a/bin/domain/imag-habit/Cargo.toml +++ b/bin/domain/imag-habit/Cargo.toml @@ -42,3 +42,10 @@ version = "2.33.0" default-features = false features = ["color", "suggestions", "wrap_help"] +[lib] +name = "libimaghabitfrontend" +path = "src/lib.rs" + +[[bin]] +name = "imag-habit" +path = "src/bin.rs" diff --git a/bin/domain/imag-habit/src/bin.rs b/bin/domain/imag-habit/src/bin.rs new file mode 100644 index 00000000..af996417 --- /dev/null +++ b/bin/domain/imag-habit/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!(libimaghabitfrontend, ImagHabit); diff --git a/bin/domain/imag-habit/src/main.rs b/bin/domain/imag-habit/src/lib.rs similarity index 92% rename from bin/domain/imag-habit/src/main.rs rename to bin/domain/imag-habit/src/lib.rs index 34c44959..86fa3b3d 100644 --- a/bin/domain/imag-habit/src/main.rs +++ b/bin/domain/imag-habit/src/lib.rs @@ -45,7 +45,7 @@ extern crate prettytable; extern crate libimaghabit; extern crate libimagstore; -#[macro_use] extern crate libimagrt; +extern crate libimagrt; extern crate libimagerror; extern crate libimagutil; extern crate libimaginteraction; @@ -57,9 +57,11 @@ use prettytable::Table; use prettytable::Cell; use prettytable::Row; use failure::Error; +use failure::Fallible as Result; +use clap::App; use libimagrt::runtime::Runtime; -use libimagrt::setup::generate_runtime_setup; +use libimagrt::application::ImagApplication; use libimagerror::trace::{MapErrTrace, trace_error}; use libimagerror::iter::TraceIterator; use libimagerror::exit::ExitUnwrap; @@ -75,37 +77,55 @@ use libimagutil::debug_result::DebugResult; mod ui; -fn main() { - let version = make_imag_version!(); - let rt = generate_runtime_setup("imag-habit", - &version, - "Habit tracking tool", - ui::build_ui); +/// Marker enum for implementing ImagApplication on +/// +/// This is used by binaries crates to execute business logic +/// or to build a CLI completion. +pub enum ImagHabit {} +impl ImagApplication for ImagHabit { + fn run(rt: Runtime) -> Result<()> { + rt + .cli() + .subcommand_name() + .map(|name| { + debug!("Call {}", name); + match name { + "create" => create(&rt), + "delete" => delete(&rt), + "list" => list(&rt), + "today" => today(&rt, false), + "status" => today(&rt, true), + "show" => show(&rt), + "done" => done(&rt), + other => { + debug!("Unknown command"); + let _ = rt.handle_unknown_subcommand("imag-habit", other, rt.cli()) + .map_err_trace_exit_unwrap() + .code() + .map(::std::process::exit); + }, + } + }) + .unwrap_or_else(|| today(&rt, true)); + Ok(()) + } - rt - .cli() - .subcommand_name() - .map(|name| { - debug!("Call {}", name); - match name { - "create" => create(&rt), - "delete" => delete(&rt), - "list" => list(&rt), - "today" => today(&rt, false), - "status" => today(&rt, true), - "show" => show(&rt), - "done" => done(&rt), - other => { - debug!("Unknown command"); - let _ = rt.handle_unknown_subcommand("imag-habit", other, rt.cli()) - .map_err_trace_exit_unwrap() - .code() - .map(::std::process::exit); - }, - } - }) - .unwrap_or_else(|| today(&rt, true)); + 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 { + "Habit tracking tool" + } + + fn version() -> &'static str { + env!("CARGO_PKG_VERSION") + } } fn create(rt: &Runtime) { diff --git a/bin/domain/imag-log/Cargo.toml b/bin/domain/imag-log/Cargo.toml index 80b96eb4..5466caab 100644 --- a/bin/domain/imag-log/Cargo.toml +++ b/bin/domain/imag-log/Cargo.toml @@ -39,3 +39,10 @@ version = "2.33.0" default-features = false features = ["color", "suggestions", "wrap_help"] +[lib] +name = "libimaglogfrontend" +path = "src/lib.rs" + +[[bin]] +name = "imag-log" +path = "src/bin.rs" diff --git a/bin/domain/imag-log/src/bin.rs b/bin/domain/imag-log/src/bin.rs new file mode 100644 index 00000000..b7e96de1 --- /dev/null +++ b/bin/domain/imag-log/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!(libimaglogfrontend, ImagLog); diff --git a/bin/domain/imag-log/src/main.rs b/bin/domain/imag-log/src/lib.rs similarity index 80% rename from bin/domain/imag-log/src/main.rs rename to bin/domain/imag-log/src/lib.rs index 85164ab9..338a482d 100644 --- a/bin/domain/imag-log/src/main.rs +++ b/bin/domain/imag-log/src/lib.rs @@ -44,7 +44,7 @@ extern crate failure; extern crate textwrap; extern crate libimaglog; -#[macro_use] extern crate libimagrt; +extern crate libimagrt; extern crate libimagstore; extern crate libimagerror; extern crate libimagdiary; @@ -56,9 +56,10 @@ use std::str::FromStr; use failure::Error; use failure::err_msg; +use failure::Fallible as Result; +use libimagrt::application::ImagApplication; use libimagrt::runtime::Runtime; -use libimagrt::setup::generate_runtime_setup; use libimagerror::trace::MapErrTrace; use libimagerror::io::ToExitCode; use libimagerror::exit::ExitUnwrap; @@ -70,50 +71,70 @@ use libimaglog::log::Log; use libimagstore::iter::get::StoreIdGetIteratorExtension; use libimagstore::store::FileLockEntry; +use clap::App; + mod ui; -use crate::ui::build_ui; use toml::Value; use itertools::Itertools; -fn main() { - let version = make_imag_version!(); - let rt = generate_runtime_setup("imag-log", - &version, - "Overlay to imag-diary to 'log' single lines of text", - build_ui); +/// Marker enum for implementing ImagApplication on +/// +/// This is used by binaries crates to execute business logic +/// or to build a CLI completion. +pub enum ImagLog {} +impl ImagApplication for ImagLog { + fn run(rt: Runtime) -> Result<()> { + if let Some(scmd) = rt.cli().subcommand_name() { + match scmd { + "show" => show(&rt), + other => { + debug!("Unknown command"); + let _ = rt.handle_unknown_subcommand("imag-log", other, rt.cli()) + .map_err_trace_exit_unwrap() + .code() + .map(::std::process::exit); + }, + } + } else { + let text = get_log_text(&rt); + let diary_name = rt.cli() + .value_of("diaryname") + .map(String::from) + .unwrap_or_else(|| get_diary_name(&rt)); + debug!("Writing to '{}': {}", diary_name, text); + + rt + .store() + .new_entry_now(&diary_name) + .map(|mut fle| { + fle.make_log_entry().map_err_trace_exit_unwrap(); + *fle.get_content_mut() = text; + fle + }) + .map(|fle| rt.report_touched(fle.get_location()).unwrap_or_exit()) + .map_err_trace_exit_unwrap(); - if let Some(scmd) = rt.cli() .subcommand_name() { - match scmd { - "show" => show(&rt), - other => { - debug!("Unknown command"); - let _ = rt.handle_unknown_subcommand("imag-log", other, rt.cli()) - .map_err_trace_exit_unwrap() - .code() - .map(::std::process::exit); - }, } - } else { - let text = get_log_text(&rt); - let diary_name = rt.cli() - .value_of("diaryname") - .map(String::from) - .unwrap_or_else(|| get_diary_name(&rt)); - debug!("Writing to '{}': {}", diary_name, text); + Ok(()) + } - rt - .store() - .new_entry_now(&diary_name) - .map(|mut fle| { - fle.make_log_entry().map_err_trace_exit_unwrap(); - *fle.get_content_mut() = text; - fle - }) - .map(|fle| rt.report_touched(fle.get_location()).unwrap_or_exit()) - .map_err_trace_exit_unwrap(); + 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 { + "Overlay to imag-diary to 'log' single lines of text" + } + + fn version() -> &'static str { + env!("CARGO_PKG_VERSION") } } @@ -203,7 +224,7 @@ fn show(rt: &Runtime) { .unwrap_or_exit(); Ok(()) }) - .collect::, ExitCode>>() + .collect::, ExitCode>>() .unwrap_or_exit(); } diff --git a/bin/domain/imag-mail/Cargo.toml b/bin/domain/imag-mail/Cargo.toml index 52e42fa2..0c1afed6 100644 --- a/bin/domain/imag-mail/Cargo.toml +++ b/bin/domain/imag-mail/Cargo.toml @@ -41,3 +41,10 @@ version = "0.9.2" default-features = false features = ["typed"] +[lib] +name = "libimagmailfrontend" +path = "src/lib.rs" + +[[bin]] +name = "imag-mail" +path = "src/bin.rs" diff --git a/bin/domain/imag-mail/src/bin.rs b/bin/domain/imag-mail/src/bin.rs new file mode 100644 index 00000000..bba7972b --- /dev/null +++ b/bin/domain/imag-mail/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!(libimagmailfrontend, ImagMail); diff --git a/bin/domain/imag-mail/src/main.rs b/bin/domain/imag-mail/src/lib.rs similarity index 85% rename from bin/domain/imag-mail/src/main.rs rename to bin/domain/imag-mail/src/lib.rs index 98baf7d1..d30062eb 100644 --- a/bin/domain/imag-mail/src/main.rs +++ b/bin/domain/imag-mail/src/lib.rs @@ -40,7 +40,7 @@ extern crate clap; extern crate toml_query; #[macro_use] extern crate indoc; -#[macro_use] extern crate libimagrt; +extern crate libimagrt; extern crate libimagmail; extern crate libimagerror; extern crate libimagstore; @@ -52,6 +52,7 @@ use std::path::PathBuf; use failure::Fallible as Result; use toml_query::read::TomlValueReadTypeExt; +use clap::App; use libimagerror::trace::{MapErrTrace, trace_error}; use libimagerror::iter::TraceIterator; @@ -63,7 +64,7 @@ use libimagmail::util; use libimagentryref::reference::{Ref, RefFassade}; use libimagentryref::util::get_ref_config; use libimagrt::runtime::Runtime; -use libimagrt::setup::generate_runtime_setup; +use libimagrt::application::ImagApplication; use libimagutil::info_result::*; use libimagstore::store::FileLockEntry; use libimagstore::storeid::StoreIdIterator; @@ -71,32 +72,52 @@ use libimagstore::iter::get::StoreIdGetIteratorExtension; mod ui; -use crate::ui::build_ui; +/// Marker enum for implementing ImagApplication on +/// +/// This is used by binaries crates to execute business logic +/// or to build a CLI completion. +pub enum ImagMail {} +impl ImagApplication for ImagMail { + fn run(rt: Runtime) -> Result<()> { -fn main() { - let version = make_imag_version!(); - let rt = generate_runtime_setup("imag-mail", - &version, - "Mail collection tool", - build_ui); + if let Some(name) = rt.cli().subcommand_name() { - if let Some(name) = rt.cli().subcommand_name() { - debug!("Call {}", name); - match name { - "import-mail" => import_mail(&rt), - "list" => list(&rt), - "mail-store" => mail_store(&rt), - other => { - debug!("Unknown command"); - let _ = rt.handle_unknown_subcommand("imag-mail", other, rt.cli()) - .map_err_trace_exit_unwrap() - .code() - .map(::std::process::exit); + debug!("Call {}", name); + match name { + "import-mail" => import_mail(&rt), + "list" => list(&rt), + "mail-store" => mail_store(&rt), + other => { + debug!("Unknown command"); + let _ = rt.handle_unknown_subcommand("imag-mail", other, rt.cli()) + .map_err_trace_exit_unwrap() + .code() + .map(::std::process::exit); + } + } } - } + + 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 { + "Mail collection tool" + } + + fn version() -> &'static str { + env!("CARGO_PKG_VERSION") } } + fn import_mail(rt: &Runtime) { let collection_name = get_ref_collection_name(rt).map_err_trace_exit_unwrap(); let refconfig = get_ref_config(rt, "imag-mail").map_err_trace_exit_unwrap(); diff --git a/bin/domain/imag-notes/Cargo.toml b/bin/domain/imag-notes/Cargo.toml index 20193d86..90d15f90 100644 --- a/bin/domain/imag-notes/Cargo.toml +++ b/bin/domain/imag-notes/Cargo.toml @@ -22,6 +22,7 @@ maintenance = { status = "actively-developed" } [dependencies] log = "0.4.6" itertools = "0.8.0" +failure = "0.1.5" libimagrt = { version = "0.10.0", path = "../../../lib/core/libimagrt" } libimagerror = { version = "0.10.0", path = "../../../lib/core/libimagerror" } @@ -35,3 +36,10 @@ version = "2.33.0" default-features = false features = ["color", "suggestions", "wrap_help"] +[lib] +name = "libimagnotesfrontend" +path = "src/lib.rs" + +[[bin]] +name = "imag-notes" +path = "src/bin.rs" diff --git a/bin/domain/imag-notes/src/bin.rs b/bin/domain/imag-notes/src/bin.rs new file mode 100644 index 00000000..2de11de7 --- /dev/null +++ b/bin/domain/imag-notes/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!(libimagnotesfrontend, ImagNotes); diff --git a/bin/domain/imag-notes/src/main.rs b/bin/domain/imag-notes/src/lib.rs similarity index 74% rename from bin/domain/imag-notes/src/main.rs rename to bin/domain/imag-notes/src/lib.rs index 86ebd65a..a62d299b 100644 --- a/bin/domain/imag-notes/src/main.rs +++ b/bin/domain/imag-notes/src/lib.rs @@ -37,9 +37,10 @@ extern crate clap; #[macro_use] extern crate log; extern crate itertools; +extern crate failure; extern crate libimagnotes; -#[macro_use] extern crate libimagrt; +extern crate libimagrt; extern crate libimagentryedit; extern crate libimagerror; extern crate libimagutil; @@ -49,10 +50,12 @@ use std::io::Write; use std::process::exit; use itertools::Itertools; +use clap::App; +use failure::Fallible as Result; use libimagentryedit::edit::Edit; use libimagrt::runtime::Runtime; -use libimagrt::setup::generate_runtime_setup; +use libimagrt::application::ImagApplication; use libimagstore::iter::get::StoreIdGetIteratorExtension; use libimagnotes::note::Note; use libimagnotes::notestore::*; @@ -65,30 +68,49 @@ use libimagutil::warn_result::WarnResult; mod ui; -use crate::ui::build_ui; -fn main() { - let version = make_imag_version!(); - let rt = generate_runtime_setup("imag-notes", - &version, - "Note taking helper", - build_ui); +/// Marker enum for implementing ImagApplication on +/// +/// This is used by binaries crates to execute business logic +/// or to build a CLI completion. +pub enum ImagNotes {} +impl ImagApplication for ImagNotes { + fn run(rt: Runtime) -> Result<()> { + if let Some(name) = rt.cli().subcommand_name() { - if let Some(name) = rt.cli().subcommand_name() { - debug!("Call: {}", name); - match name { - "create" => create(&rt), - "delete" => delete(&rt), - "edit" => edit(&rt), - "list" => list(&rt), - other => { - debug!("Unknown command"); - let _ = rt.handle_unknown_subcommand("imag-notes", other, rt.cli()) - .map_err_trace_exit_unwrap() - .code() - .map(::std::process::exit); - }, - }; + debug!("Call: {}", name); + match name { + "create" => create(&rt), + "delete" => delete(&rt), + "edit" => edit(&rt), + "list" => list(&rt), + other => { + debug!("Unknown command"); + let _ = rt.handle_unknown_subcommand("imag-notes", other, rt.cli()) + .map_err_trace_exit_unwrap() + .code() + .map(::std::process::exit); + }, + }; + } + + 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 { + "Note taking helper" + } + + fn version() -> &'static str { + env!("CARGO_PKG_VERSION") } } diff --git a/bin/domain/imag-timetrack/Cargo.toml b/bin/domain/imag-timetrack/Cargo.toml index 1f023946..88408449 100644 --- a/bin/domain/imag-timetrack/Cargo.toml +++ b/bin/domain/imag-timetrack/Cargo.toml @@ -39,3 +39,10 @@ version = "2.33.0" default-features = false features = ["color", "suggestions", "wrap_help"] +[lib] +name = "libimagtimetrackfrontend" +path = "src/lib.rs" + +[[bin]] +name = "imag-timetrack" +path = "src/bin.rs" diff --git a/bin/domain/imag-timetrack/src/bin.rs b/bin/domain/imag-timetrack/src/bin.rs new file mode 100644 index 00000000..e9feb5f8 --- /dev/null +++ b/bin/domain/imag-timetrack/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!(libimagtimetrackfrontend, ImagTimetrack); diff --git a/bin/domain/imag-timetrack/src/lib.rs b/bin/domain/imag-timetrack/src/lib.rs new file mode 100644 index 00000000..6b94477f --- /dev/null +++ b/bin/domain/imag-timetrack/src/lib.rs @@ -0,0 +1,137 @@ +// +// 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 chrono; +extern crate filters; +extern crate itertools; +extern crate prettytable; +extern crate kairos; +extern crate failure; + +extern crate libimagerror; +extern crate libimagstore; +extern crate libimagrt; +extern crate libimagtimetrack; +extern crate libimagutil; + +mod cont; +mod day; +mod list; +mod month; +mod shell; +mod start; +mod stop; +mod track; +mod ui; +mod week; +mod year; + +use crate::cont::cont; +use crate::day::day; +use crate::list::{list, list_impl}; +use crate::month::month; +use crate::shell::shell; +use crate::start::start; +use crate::stop::stop; +use crate::track::track; +use crate::week::week; +use crate::year::year; + +use clap::App; +use failure::Fallible as Result; + +use libimagrt::runtime::Runtime; +use libimagrt::application::ImagApplication; +use libimagerror::trace::MapErrTrace; + +/// Marker enum for implementing ImagApplication on +/// +/// This is used by binaries crates to execute business logic +/// or to build a CLI completion. +pub enum ImagTimetrack {} +impl ImagApplication for ImagTimetrack { + fn run(rt: Runtime) -> Result<()> { + let command = rt.cli().subcommand_name(); + let retval = if let Some(command) = command { + debug!("Call: {}", command); + match command { + "continue" => cont(&rt), + "day" => day(&rt), + "list" => list(&rt), + "month" => month(&rt), + "shell" => shell(&rt), + "start" => start(&rt), + "stop" => stop(&rt), + "track" => track(&rt), + "week" => week(&rt), + "year" => year(&rt), + other => { + debug!("Unknown command"); + rt.handle_unknown_subcommand("imag-timetrack", other, rt.cli()) + .map_err_trace_exit_unwrap() + .code() + .unwrap_or(0) + }, + } + } else { + let start = ::chrono::offset::Local::today().naive_local().and_hms(0, 0, 0); + let end = ::chrono::offset::Local::today().naive_local().and_hms(23, 59, 59); + list_impl(&rt, Some(start), Some(end), false, false) + }; + + ::std::process::exit(retval); + } + + 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 { + "Time tracking module" + } + + fn version() -> &'static str { + env!("CARGO_PKG_VERSION") + } +} diff --git a/bin/domain/imag-timetrack/src/main.rs b/bin/domain/imag-timetrack/src/main.rs deleted file mode 100644 index 1c06e845..00000000 --- a/bin/domain/imag-timetrack/src/main.rs +++ /dev/null @@ -1,117 +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; -extern crate chrono; -extern crate filters; -extern crate itertools; -extern crate prettytable; -extern crate kairos; -extern crate failure; - -extern crate libimagerror; -extern crate libimagstore; -#[macro_use] extern crate libimagrt; -extern crate libimagtimetrack; -extern crate libimagutil; - -mod cont; -mod day; -mod list; -mod month; -mod shell; -mod start; -mod stop; -mod track; -mod ui; -mod week; -mod year; - -use crate::cont::cont; -use crate::day::day; -use crate::list::{list, list_impl}; -use crate::month::month; -use crate::shell::shell; -use crate::start::start; -use crate::stop::stop; -use crate::track::track; -use crate::ui::build_ui; -use crate::week::week; -use crate::year::year; - -use libimagrt::setup::generate_runtime_setup; -use libimagerror::trace::MapErrTrace; - -fn main() { - let version = make_imag_version!(); - let rt = generate_runtime_setup("imag-timetrack", - &version, - "Time tracking module", - build_ui); - - let command = rt.cli().subcommand_name(); - let retval = if let Some(command) = command { - debug!("Call: {}", command); - match command { - "continue" => cont(&rt), - "day" => day(&rt), - "list" => list(&rt), - "month" => month(&rt), - "shell" => shell(&rt), - "start" => start(&rt), - "stop" => stop(&rt), - "track" => track(&rt), - "week" => week(&rt), - "year" => year(&rt), - other => { - debug!("Unknown command"); - rt.handle_unknown_subcommand("imag-timetrack", other, rt.cli()) - .map_err_trace_exit_unwrap() - .code() - .unwrap_or(0) - }, - } - } else { - let start = ::chrono::offset::Local::today().naive_local().and_hms(0, 0, 0); - let end = ::chrono::offset::Local::today().naive_local().and_hms(23, 59, 59); - list_impl(&rt, Some(start), Some(end), false, false) - }; - - ::std::process::exit(retval); -} diff --git a/bin/domain/imag-todo/Cargo.toml b/bin/domain/imag-todo/Cargo.toml index 136025cf..12a2719a 100644 --- a/bin/domain/imag-todo/Cargo.toml +++ b/bin/domain/imag-todo/Cargo.toml @@ -35,3 +35,10 @@ version = "2.33.0" default-features = false features = ["color", "suggestions", "wrap_help"] +[lib] +name = "libimagtodofrontend" +path = "src/lib.rs" + +[[bin]] +name = "imag-todo" +path = "src/bin.rs" diff --git a/bin/domain/imag-todo/src/bin.rs b/bin/domain/imag-todo/src/bin.rs new file mode 100644 index 00000000..a2181dca --- /dev/null +++ b/bin/domain/imag-todo/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!(libimagtodofrontend, ImagTodo); diff --git a/bin/domain/imag-todo/src/main.rs b/bin/domain/imag-todo/src/lib.rs similarity index 81% rename from bin/domain/imag-todo/src/main.rs rename to bin/domain/imag-todo/src/lib.rs index 36537ea9..16f42262 100644 --- a/bin/domain/imag-todo/src/main.rs +++ b/bin/domain/imag-todo/src/lib.rs @@ -41,7 +41,7 @@ extern crate toml_query; #[macro_use] extern crate is_match; extern crate failure; -#[macro_use] extern crate libimagrt; +extern crate libimagrt; extern crate libimagerror; extern crate libimagtodo; @@ -49,9 +49,11 @@ use std::process::{Command, Stdio}; use std::io::stdin; use std::io::Write; use failure::Error; +use failure::Fallible as Result; +use clap::App; use libimagrt::runtime::Runtime; -use libimagrt::setup::generate_runtime_setup; +use libimagrt::application::ImagApplication; use libimagtodo::taskstore::TaskStore; use libimagerror::trace::{MapErrTrace, trace_error}; use libimagerror::iter::TraceIterator; @@ -60,29 +62,47 @@ use libimagerror::io::ToExitCode; mod ui; -use crate::ui::build_ui; -fn main() { - let version = make_imag_version!(); - let rt = generate_runtime_setup("imag-todo", - &version, - "Interface with taskwarrior", - build_ui); +/// Marker enum for implementing ImagApplication on +/// +/// This is used by binaries crates to execute business logic +/// or to build a CLI completion. +pub enum ImagTodo {} +impl ImagApplication for ImagTodo { + fn run(rt: Runtime) -> Result<()> { + match rt.cli().subcommand_name() { + Some("tw-hook") => tw_hook(&rt), + Some("list") => list(&rt), + Some(other) => { + debug!("Unknown command"); + let _ = rt.handle_unknown_subcommand("imag-todo", other, rt.cli()) + .map_err_trace_exit_unwrap() + .code() + .map(::std::process::exit); + } + None => { + warn!("No command"); + }, + }; - match rt.cli().subcommand_name() { - Some("tw-hook") => tw_hook(&rt), - Some("list") => list(&rt), - Some(other) => { - debug!("Unknown command"); - let _ = rt.handle_unknown_subcommand("imag-todo", other, rt.cli()) - .map_err_trace_exit_unwrap() - .code() - .map(::std::process::exit); - } - None => { - warn!("No command"); - }, - } // end match scmd -} // end main + 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 { + "Interface with taskwarrior" + } + + fn version() -> &'static str { + env!("CARGO_PKG_VERSION") + } +} fn tw_hook(rt: &Runtime) { let subcmd = rt.cli().subcommand_matches("tw-hook").unwrap(); diff --git a/bin/domain/imag-wiki/Cargo.toml b/bin/domain/imag-wiki/Cargo.toml index 123eeb90..eca68017 100644 --- a/bin/domain/imag-wiki/Cargo.toml +++ b/bin/domain/imag-wiki/Cargo.toml @@ -21,6 +21,7 @@ toml-query = "0.9.2" is-match = "0.1.0" regex = "1.1.7" filters = "0.3.0" +failure = "0.1.5" libimagentryedit = { version = "0.10.0", path = "../../../lib/entry/libimagentryedit" } libimagentrylink = { version = "0.10.0", path = "../../../lib/entry/libimagentrylink" } @@ -31,3 +32,10 @@ libimagstore = { version = "0.10.0", path = "../../../lib/core/libimagst libimagwiki = { version = "0.10.0", path = "../../../lib/domain/libimagwiki" } libimagutil = { version = "0.10.0", path = "../../../lib/etc/libimagutil" } +[lib] +name = "libimagwikifrontend" +path = "src/lib.rs" + +[[bin]] +name = "imag-wiki" +path = "src/bin.rs" diff --git a/bin/domain/imag-wiki/src/bin.rs b/bin/domain/imag-wiki/src/bin.rs new file mode 100644 index 00000000..ae6b391d --- /dev/null +++ b/bin/domain/imag-wiki/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!(libimagwikifrontend, ImagWiki); diff --git a/bin/domain/imag-wiki/src/main.rs b/bin/domain/imag-wiki/src/lib.rs similarity index 82% rename from bin/domain/imag-wiki/src/main.rs rename to bin/domain/imag-wiki/src/lib.rs index 8a25776f..f541c14f 100644 --- a/bin/domain/imag-wiki/src/main.rs +++ b/bin/domain/imag-wiki/src/lib.rs @@ -23,8 +23,9 @@ extern crate clap; extern crate regex; extern crate filters; #[macro_use] extern crate log; +extern crate failure; -#[macro_use] extern crate libimagrt; +extern crate libimagrt; extern crate libimagerror; extern crate libimagstore; extern crate libimagwiki; @@ -33,9 +34,11 @@ extern crate libimagentrylink; extern crate libimagutil; use std::io::Write; +use failure::Fallible as Result; +use clap::App; use libimagrt::runtime::Runtime; -use libimagrt::setup::generate_runtime_setup; +use libimagrt::application::ImagApplication; use libimagerror::iter::TraceIterator; use libimagerror::trace::MapErrTrace; use libimagerror::exit::ExitUnwrap; @@ -44,36 +47,55 @@ use libimagwiki::store::WikiStore; use libimagentryedit::edit::{Edit, EditHeader}; mod ui; -use crate::ui::build_ui; -fn main() { - let version = make_imag_version!(); - let rt = generate_runtime_setup("imag-wiki", - &version, - "Personal wiki", - build_ui); +/// Marker enum for implementing ImagApplication on +/// +/// This is used by binaries crates to execute business logic +/// or to build a CLI completion. +pub enum ImagWiki {} +impl ImagApplication for ImagWiki { + fn run(rt: Runtime) -> Result<()> { + let wiki_name = rt.cli().value_of("wikiname").unwrap_or("default"); + trace!("wiki_name = {}", wiki_name); + trace!("calling = {:?}", rt.cli().subcommand_name()); - let wiki_name = rt.cli().value_of("wikiname").unwrap_or("default"); - trace!("wiki_name = {}", wiki_name); - trace!("calling = {:?}", rt.cli().subcommand_name()); + match rt.cli().subcommand_name() { + Some("list") => list(&rt, wiki_name), + Some("idof") => idof(&rt, wiki_name), + Some("create") => create(&rt, wiki_name), + Some("create-wiki") => create_wiki(&rt), + Some("show") => show(&rt, wiki_name), + Some("delete") => delete(&rt, wiki_name), + Some(other) => { + debug!("Unknown command"); + let _ = rt.handle_unknown_subcommand("imag-wiki", other, rt.cli()) + .map_err_trace_exit_unwrap() + .code() + .map(std::process::exit); + } + None => warn!("No command"), + } // end match scmd + + 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 { + "Personal wiki" + } + + fn version() -> &'static str { + env!("CARGO_PKG_VERSION") + } +} - match rt.cli().subcommand_name() { - Some("list") => list(&rt, wiki_name), - Some("idof") => idof(&rt, wiki_name), - Some("create") => create(&rt, wiki_name), - Some("create-wiki") => create_wiki(&rt), - Some("show") => show(&rt, wiki_name), - Some("delete") => delete(&rt, wiki_name), - Some(other) => { - debug!("Unknown command"); - let _ = rt.handle_unknown_subcommand("imag-wiki", other, rt.cli()) - .map_err_trace_exit_unwrap() - .code() - .map(std::process::exit); - } - None => warn!("No command"), - } // end match scmd -} // end main fn list(rt: &Runtime, wiki_name: &str) { let scmd = rt.cli().subcommand_matches("list").unwrap(); // safed by clap diff --git a/lib/core/libimagrt/src/application.rs b/lib/core/libimagrt/src/application.rs new file mode 100644 index 00000000..74ad4b68 --- /dev/null +++ b/lib/core/libimagrt/src/application.rs @@ -0,0 +1,70 @@ +// +// 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 +// + +use runtime::Runtime; +use clap::App; +use failure::Fallible as Result; + +pub trait ImagApplication { + fn run(rt: Runtime) -> Result<()>; + fn build_cli<'a>(app: App<'a, 'a>) -> App<'a, 'a>; + fn name() -> &'static str; + fn version() -> &'static str; + fn description() -> &'static str; +} + + +#[macro_export] +macro_rules! simple_imag_application_binary { + ($application_library:ident, $application_implementor:ident) => { + extern crate libimagerror; + extern crate failure; + extern crate $application_library; + + use failure::{Error, Fallible as Result}; + + fn main() { + use libimagerror::trace::MapErrTrace; + use libimagrt::application::ImagApplication; + use libimagrt::setup::generate_runtime_setup; + use $application_library::$application_implementor; + + let version = make_imag_version!(); + let rt = generate_runtime_setup($application_implementor::name(), + &version, + $application_implementor::description(), + $application_implementor::build_cli); + + // The error context must have a 'static lifetime + // Therefore, the easiest, safe, but hacky way to achieve this + // is to allocate a string, which is then forgotten to + // leak memory and return it's contents as a &'static str + // Because this is the very end of the application and only + // happens once, it should have no impact whatsoever + let error_context: &'static str = Box::leak( + format!("Failed to run {}", $application_implementor::name()) + .into_boxed_str() + ); + $application_implementor::run(rt) + .map_err(|e| e.context(error_context)) + .map_err(Error::from) + .map_err_trace_exit_unwrap(); + } + }; +} diff --git a/lib/core/libimagrt/src/lib.rs b/lib/core/libimagrt/src/lib.rs index ebe8f4fc..f9d349c0 100644 --- a/lib/core/libimagrt/src/lib.rs +++ b/lib/core/libimagrt/src/lib.rs @@ -55,6 +55,7 @@ extern crate libimagutil; extern crate libimagerror; extern crate libimaginteraction; +pub mod application; pub mod configuration; pub mod logger; pub mod io; diff --git a/lib/etc/libimagutil/src/testing.rs b/lib/etc/libimagutil/src/testing.rs index beab21a6..feee2a11 100644 --- a/lib/etc/libimagutil/src/testing.rs +++ b/lib/etc/libimagutil/src/testing.rs @@ -45,6 +45,7 @@ macro_rules! make_mock_app { modulename $module:ident; version $version:expr; with help $help:expr; + with ui builder function $buildui:path; }=> { mod $module { use clap::{App, ArgMatches}; @@ -64,7 +65,7 @@ macro_rules! make_mock_app { fn new(args: Vec<&'static str>) -> Self { MockLinkApp { args: args, - inner: ::build_ui(Runtime::get_default_cli_builder($appname, $version, $help)), + inner: ($buildui)(Runtime::get_default_cli_builder($appname, $version, $help)), } } }