diff options
Diffstat (limited to 'bin/domain')
-rw-r--r-- | bin/domain/imag-wiki/Cargo.toml | 36 | ||||
l--------- | bin/domain/imag-wiki/README.md | 1 | ||||
-rw-r--r-- | bin/domain/imag-wiki/src/main.rs | 274 | ||||
-rw-r--r-- | bin/domain/imag-wiki/src/ui.rs | 170 |
4 files changed, 481 insertions, 0 deletions
diff --git a/bin/domain/imag-wiki/Cargo.toml b/bin/domain/imag-wiki/Cargo.toml new file mode 100644 index 00000000..edd591b2 --- /dev/null +++ b/bin/domain/imag-wiki/Cargo.toml @@ -0,0 +1,36 @@ +[package] +name = "imag-wiki" +version = "0.7.0" +authors = ["Matthias Beyer <mail@beyermatthias.de>"] + +description = "Part of the imag core distribution: imag-wiki command" + +keywords = ["imag", "PIM", "personal", "information", "management"] +readme = "../../../README.md" +license = "LGPL-2.1" + +documentation = "https://matthiasbeyer.github.io/imag/imag_documentation/index.html" +repository = "https://github.com/matthiasbeyer/imag" +homepage = "http://imag-pim.org" + +build = "../../../build.rs" + +[dependencies] +clap = ">=2.17" +log = "0.3" +toml = "0.4" +toml-query = "0.6" +is-match = "0.1" +version = "2.0.1" +regex = "0.2" +filters = "0.2" + +libimagentryedit = { version = "0.7.0", path = "../../../lib/entry/libimagentryedit" } +libimagentrylink = { version = "0.7.0", path = "../../../lib/entry/libimagentrylink" } +libimagentrymarkdown = { version = "0.7.0", path = "../../../lib/entry/libimagentrymarkdown" } +libimagerror = { version = "0.7.0", path = "../../../lib/core/libimagerror" } +libimagrt = { version = "0.7.0", path = "../../../lib/core/libimagrt" } +libimagstore = { version = "0.7.0", path = "../../../lib/core/libimagstore" } +libimagwiki = { version = "0.7.0", path = "../../../lib/domain/libimagwiki" } +libimagutil = { version = "0.7.0", path = "../../../lib/etc/libimagutil" } + diff --git a/bin/domain/imag-wiki/README.md b/bin/domain/imag-wiki/README.md new file mode 120000 index 00000000..c6f30017 --- /dev/null +++ b/bin/domain/imag-wiki/README.md @@ -0,0 +1 @@ +../../../doc/src/04020-module-wiki.md
\ No newline at end of file diff --git a/bin/domain/imag-wiki/src/main.rs b/bin/domain/imag-wiki/src/main.rs new file mode 100644 index 00000000..5c393bca --- /dev/null +++ b/bin/domain/imag-wiki/src/main.rs @@ -0,0 +1,274 @@ +// +// imag - the personal information management suite for the commandline +// Copyright (C) 2015-2018 Matthias Beyer <mail@beyermatthias.de> 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 regex; +extern crate filters; +#[macro_use] extern crate log; + +#[macro_use] extern crate libimagrt; +extern crate libimagerror; +extern crate libimagstore; +extern crate libimagwiki; +extern crate libimagentryedit; +extern crate libimagentrylink; +extern crate libimagutil; + +use std::io::Write; + +use libimagrt::runtime::Runtime; +use libimagrt::setup::generate_runtime_setup; +use libimagerror::trace::MapErrTrace; +use libimagerror::exit::ExitUnwrap; +use libimagerror::io::ToExitCode; +use libimagwiki::store::WikiStore; +use libimagentryedit::edit::{Edit, EditHeader}; + +mod ui; +use ui::build_ui; + +fn main() { + let version = make_imag_version!(); + let rt = generate_runtime_setup("imag-wiki", + &version, + "Personal wiki", + build_ui); + + let wiki_name = rt.cli().value_of("wikiname").unwrap_or("default"); + + match rt.cli().subcommand_name() { + Some("ids") => ids(&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(1) + .code() + .map(std::process::exit); + } + None => warn!("No command"), + } // end match scmd +} // end main + +fn ids(rt: &Runtime, wiki_name: &str) { + let scmd = rt.cli().subcommand_matches("ids").unwrap(); // safed by clap + let prefix = if scmd.is_present("ids-full") { + format!("{}/", rt.store().path().display()) + } else { + String::from("") + }; + + let out = rt.stdout(); + let mut outlock = out.lock(); + + rt.store() + .get_wiki(wiki_name) + .map_err_trace_exit_unwrap(1) + .unwrap_or_else(|| { + error!("No wiki '{}' found", wiki_name); + ::std::process::exit(1) + }) + .all_ids() + .map_err_trace_exit_unwrap(1) + .for_each(|id| { + let _ = writeln!(outlock, "{}{}", prefix, id) + .to_exit_code() + .unwrap_or_exit(); + }); +} + +fn idof(rt: &Runtime, wiki_name: &str) { + let scmd = rt.cli().subcommand_matches("idof").unwrap(); // safed by clap + + let entryname = scmd + .value_of("idof-name") + .map(String::from) + .unwrap(); // safed by clap + + let out = rt.stdout(); + let mut lock = out.lock(); + + let _ = rt.store() + .get_wiki(wiki_name) + .map_err_trace_exit_unwrap(1) + .unwrap_or_else(|| { + error!("No wiki '{}' found", wiki_name); + ::std::process::exit(1) + }) + .get_entry(&entryname) + .map_err_trace_exit_unwrap(1) + .map(|entry| { + let id = entry.get_location().clone(); + let prefix = if scmd.is_present("idof-full") { + format!("{}/", rt.store().path().display()) + } else { + String::from("") + }; + + writeln!(lock, "{}{}", prefix, id).to_exit_code().unwrap_or_exit() + }) + .unwrap_or_else(|| { + error!("Entry '{}' in wiki '{}' not found!", entryname, wiki_name); + ::std::process::exit(1) + }); +} + +fn create(rt: &Runtime, wiki_name: &str) { + use libimagwiki::entry::WikiEntry; + use libimagutil::warn_result::WarnResult; + + let scmd = rt.cli().subcommand_matches("create").unwrap(); // safed by clap + let name = String::from(scmd.value_of("create-name").unwrap()); // safe by clap + + let wiki = rt + .store() + .get_wiki(&wiki_name) + .map_err_trace_exit_unwrap(1) + .unwrap_or_else(|| { + error!("No wiki '{}' found", wiki_name); + ::std::process::exit(1) + }); + + let mut entry = wiki.create_entry(name).map_err_trace_exit_unwrap(1); + + if !scmd.is_present("create-noedit") { + if scmd.is_present("create-editheader") { + let _ = entry.edit_header_and_content(rt).map_err_trace_exit_unwrap(1); + } else { + let _ = entry.edit_content(rt).map_err_trace_exit_unwrap(1); + } + } + + let _ = entry.autolink(rt.store()) + .map_warn_err_str("Linking has failed. Trying to safe the entry now. Please investigate by hand if this succeeds.") + .map_err(|e| { + let _ = rt.store().update(&mut entry).map_err_trace_exit_unwrap(1); + e + }) + .map_warn_err_str("Safed entry") + .map_err_trace_exit_unwrap(1); + + if scmd.is_present("create-printid") { + let out = rt.stdout(); + let mut lock = out.lock(); + let id = entry.get_location(); + + writeln!(lock, "{}", id).to_exit_code().unwrap_or_exit() + } +} + +fn create_wiki(rt: &Runtime) { + let scmd = rt.cli().subcommand_matches("create-wiki").unwrap(); // safed by clap + let wiki_name = String::from(scmd.value_of("create-wiki-name").unwrap()); // safe by clap + let _ = rt.store().create_wiki(&wiki_name).map_err_trace_exit_unwrap(1); +} + +fn show(rt: &Runtime, wiki_name: &str) { + use filters::filter::Filter; + + let scmd = rt.cli().subcommand_matches("show").unwrap(); // safed by clap + + struct NameFilter(Option<Vec<String>>); + impl Filter<String> for NameFilter { + fn filter(&self, e: &String) -> bool { + match self.0 { + Some(ref v) => v.contains(e), + None => false, + } + } + } + + let namefilter = NameFilter(scmd + .values_of("show-name") + .map(|v| v.map(String::from).collect::<Vec<String>>())); + + let names = scmd + .values_of("show-name") + .unwrap() // safe by clap + .map(String::from) + .filter(|e| namefilter.filter(e)) + .collect::<Vec<_>>(); + + let wiki = rt + .store() + .get_wiki(&wiki_name) + .map_err_trace_exit_unwrap(1) + .unwrap_or_else(|| { + error!("No wiki '{}' found", wiki_name); + ::std::process::exit(1) + }); + + let out = rt.stdout(); + let mut outlock = out.lock(); + + for name in names { + let entry = wiki + .get_entry(&name) + .map_err_trace_exit_unwrap(1) + .unwrap_or_else(|| { + error!("No wiki entry '{}' found in wiki '{}'", name, wiki_name); + ::std::process::exit(1) + }); + + writeln!(outlock, "{}", entry.get_location()) + .to_exit_code() + .unwrap_or_exit(); + + writeln!(outlock, "{}", entry.get_content()) + .to_exit_code() + .unwrap_or_exit(); + } +} + +fn delete(rt: &Runtime, wiki_name: &str) { + use libimagentrylink::internal::InternalLinker; + + let scmd = rt.cli().subcommand_matches("delete").unwrap(); // safed by clap + let name = String::from(scmd.value_of("delete-name").unwrap()); // safe by clap + let unlink = !scmd.is_present("delete-no-remove-linkings"); + + let wiki = rt + .store() + .get_wiki(&wiki_name) + .map_err_trace_exit_unwrap(1) + .unwrap_or_else(|| { + error!("No wiki '{}' found", wiki_name); + ::std::process::exit(1) + }); + + if unlink { + wiki.get_entry(&name) + .map_err_trace_exit_unwrap(1) + .unwrap_or_else(|| { + error!("No wiki entry '{}' in '{}' found", name, wiki_name); + ::std::process::exit(1) + }) + .unlink(rt.store()) + .map_err_trace_exit_unwrap(1); + } + + let _ = wiki + .delete_entry(&name) + .map_err_trace_exit_unwrap(1); +} + diff --git a/bin/domain/imag-wiki/src/ui.rs b/bin/domain/imag-wiki/src/ui.rs new file mode 100644 index 00000000..17b0edc0 --- /dev/null +++ b/bin/domain/imag-wiki/src/ui.rs @@ -0,0 +1,170 @@ +// +// imag - the personal information management suite for the commandline +// Copyright (C) 2015-2018 Matthias Beyer <mail@beyermatthias.de> 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 clap::{Arg, App, SubCommand}; + +pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> { + app + .arg(Arg::with_name("wikiname") + .long("wiki") + .short("w") + .takes_value(true) + .required(false) + .multiple(false) + .value_name("WIKI") + .help("Name of the wiki to use. Defaults to 'default'")) + + .subcommand(SubCommand::with_name("ids") + .about("List all ids in this wiki") + .version("0.1") + + .arg(Arg::with_name("ids-full") + .long("full") + .takes_value(false) + .required(false) + .multiple(false) + .help("Print full filepath"))) + + .subcommand(SubCommand::with_name("idof") + .about("List id of an entry in this wiki, if it exists") + .version("0.1") + + .arg(Arg::with_name("idof-full") + .long("full") + .takes_value(false) + .required(false) + .multiple(false) + .help("Print full filepath")) + + .arg(Arg::with_name("idof-name") + .index(1) + .takes_value(true) + .required(true) + .multiple(false) + .value_name("NAME") + .help("Add the entry under this name. The name must be unique, namespaces ('foo/bar') are allowed.")) + ) + + .subcommand(SubCommand::with_name("create-wiki") + .about("Create wiki") + .version("0.1") + .arg(Arg::with_name("create-wiki-name") + .index(1) + .takes_value(true) + .required(true) + .multiple(false) + .value_name("NAME") + .help("Name of the wiki")) + + .arg(Arg::with_name("create-wiki-noedit") + .long("no-edit") + .short("E") + .takes_value(false) + .required(false) + .multiple(false) + .help("Do not call the editor on the newly created entry.") + .conflicts_with("create-wiki-editheader")) + + .arg(Arg::with_name("create-wiki-editheader") + .long("header") + .takes_value(false) + .required(false) + .multiple(false) + .help("Do edit header when editing main page entry.") + .conflicts_with("create-wiki-noedit")) + + .arg(Arg::with_name("create-wiki-printid") + .long("print-id") + .short("I") + .takes_value(false) + .required(false) + .multiple(false) + .help("Print the store id after creating")) + ) + + .subcommand(SubCommand::with_name("create") + .about("Add wiki entry") + .version("0.1") + + .arg(Arg::with_name("create-name") + .index(1) + .takes_value(true) + .required(true) + .multiple(false) + .help("Name of the page.")) + + .arg(Arg::with_name("create-noedit") + .long("no-edit") + .short("E") + .takes_value(false) + .required(false) + .multiple(false) + .help("Do not call the editor on the newly created entry.") + .conflicts_with("create-editheader")) + + .arg(Arg::with_name("create-editheader") + .long("header") + .takes_value(false) + .required(false) + .multiple(false) + .help("Do edit header when editing entry.") + .conflicts_with("create-noedit")) + + .arg(Arg::with_name("create-printid") + .long("print-id") + .short("I") + .takes_value(false) + .required(false) + .multiple(false) + .help("Print the store id after creating")) + ) + + .subcommand(SubCommand::with_name("show") + .about("Show wiki entry/entries") + .version("0.1") + + .arg(Arg::with_name("show-name") + .index(1) + .takes_value(true) + .required(true) + .multiple(true) + .help("Name of the entry/entries to show (if not passed, all are shown).")) + ) + + + .subcommand(SubCommand::with_name("delete") + .about("Delete wiki entry") + .version("0.1") + .arg(Arg::with_name("delete-name") + .index(1) + .takes_value(true) + .required(true) + .multiple(false) + .value_name("NAME") + .help("Delete the entry under this name. The name must be unique, namespaces ('foo/bar') are allowed.")) + + .arg(Arg::with_name("delete-no-remove-linkings") + .long("no-remove-links") + .takes_value(false) + .required(false) + .multiple(false) + .help("Do not remote links. WARNING: This leaves the store in an inconsistent state.")) + ) + +} |