From 5898b64e80c6e05eea0c9904ccccf9721509089f Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Mon, 15 Feb 2016 14:33:30 +0100 Subject: [PATCH 1/8] imag-tag: init --- imag-tag/Cargo.toml | 24 ++++++++++++++++++++++++ imag-tag/src/main.rs | 14 ++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 imag-tag/Cargo.toml create mode 100644 imag-tag/src/main.rs diff --git a/imag-tag/Cargo.toml b/imag-tag/Cargo.toml new file mode 100644 index 00000000..522a2397 --- /dev/null +++ b/imag-tag/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "imag-tag" +version = "0.1.0" +authors = ["Matthias Beyer "] + +[dependencies] +clap = "1.5.5" +log = "0.3.5" +version = "2.0.1" +semver = "0.2.1" +toml = "0.1.25" + +[dependencies.libimagstore] +path = "../libimagstore" + +[dependencies.libimagrt] +path = "../libimagrt" + +[dependencies.libimagutil] +path = "../libimagutil" + +[dependencies.libimagtag] +path = "../libimagtag" + diff --git a/imag-tag/src/main.rs b/imag-tag/src/main.rs new file mode 100644 index 00000000..5b1d3c53 --- /dev/null +++ b/imag-tag/src/main.rs @@ -0,0 +1,14 @@ +extern crate clap; +#[macro_use] extern crate log; +extern crate semver; +extern crate toml; +#[macro_use] extern crate version; + +extern crate libimagstore; +extern crate libimagrt; +extern crate libimagtag; +extern crate libimagutil; + +fn main() { + println!("Hello, world!"); +} From d0a12c2fb0d7dfc18730c062b830a856b50a5564 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Mon, 15 Feb 2016 14:42:20 +0100 Subject: [PATCH 2/8] Add interface specification --- imag-tag/src/main.rs | 2 ++ imag-tag/src/ui.rs | 66 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 imag-tag/src/ui.rs diff --git a/imag-tag/src/main.rs b/imag-tag/src/main.rs index 5b1d3c53..70fd892b 100644 --- a/imag-tag/src/main.rs +++ b/imag-tag/src/main.rs @@ -9,6 +9,8 @@ extern crate libimagrt; extern crate libimagtag; extern crate libimagutil; +mod ui; + fn main() { println!("Hello, world!"); } diff --git a/imag-tag/src/ui.rs b/imag-tag/src/ui.rs new file mode 100644 index 00000000..88c3df4d --- /dev/null +++ b/imag-tag/src/ui.rs @@ -0,0 +1,66 @@ +use clap::{Arg, App, SubCommand}; + +pub fn build_ui<'a>(app: App<'a, 'a, 'a, 'a, 'a, 'a>) -> App<'a, 'a, 'a, 'a, 'a, 'a> { + app.arg(Arg::with_name("id") + .long("id") + .short("i") + .takes_value(true) + .required(true) + .help("Use this entry")) + + .arg(Arg::with_name("add") + .long("add") + .short("a") + .takes_value(true) + .required(false) + .multiple(true) + .help("Add this tag")) + + .arg(Arg::with_name("remove") + .long("remove") + .short("r") + .takes_value(true) + .required(false) + .multiple(true) + .help("Remove this tag")) + + .arg(Arg::with_name("set") + .long("set") + .short("s") + .takes_value(true) + .required(false) + .multiple(true) + .help("Set these tags")) + + .subcommand(SubCommand::with_name("list") + .about("List tags (default)") + .version("0.1") + .arg(Arg::with_name("json") + .long("json") + .short("j") + .takes_value(false) + .required(false) + .help("List as JSON")) + .arg(Arg::with_name("linewise") + .long("linewise") + .short("l") + .takes_value(false) + .required(false) + .help("One tag per line")) + .arg(Arg::with_name("commasep") + .long("comma") + .short("c") + .takes_value(false) + .required(false) + .help("Commaseperated (default)")) + .arg(Arg::with_name("sep") + .long("sep") + .short("s") + .takes_value(true) + .required(false) + .help("Seperated by string")) + ) + +} + + From 966cedb4a7e5137697b99e64ce5b013d07c04773 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Mon, 15 Feb 2016 16:56:36 +0100 Subject: [PATCH 3/8] Impl Tagable for FileLockEntry for more convenience --- libimagtag/src/tagable.rs | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/libimagtag/src/tagable.rs b/libimagtag/src/tagable.rs index f38f49d6..70eaec02 100644 --- a/libimagtag/src/tagable.rs +++ b/libimagtag/src/tagable.rs @@ -1,4 +1,7 @@ -use libimagstore::store::{Entry, EntryHeader}; +use std::ops::Deref; +use std::ops::DerefMut; + +use libimagstore::store::{Entry, EntryHeader, FileLockEntry}; use error::{TagError, TagErrorKind}; use result::Result; @@ -163,3 +166,32 @@ impl Tagable for Entry { } } + +impl<'a> Tagable for FileLockEntry<'a> { + + fn get_tags(&self) -> Result> { + self.deref().get_tags() + } + + fn set_tags(&mut self, ts: Vec) -> Result<()> { + self.deref_mut().set_tags(ts) + } + + fn add_tag(&mut self, t: Tag) -> Result<()> { + self.deref_mut().add_tag(t) + } + + fn remove_tag(&mut self, t: Tag) -> Result<()> { + self.deref_mut().remove_tag(t) + } + + fn has_tag(&self, t: &Tag) -> Result { + self.deref().has_tag(t) + } + + fn has_tags(&self, ts: &Vec) -> Result { + self.deref().has_tags(ts) + } + +} + From d8d7dae4882a5d9ced2957e7a5e47c442a78a37b Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Mon, 15 Feb 2016 17:16:44 +0100 Subject: [PATCH 4/8] Add build_entry_path(), Copy of imag-store/src/util/build_entry_path() --- imag-tag/src/util.rs | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 imag-tag/src/util.rs diff --git a/imag-tag/src/util.rs b/imag-tag/src/util.rs new file mode 100644 index 00000000..b33e045d --- /dev/null +++ b/imag-tag/src/util.rs @@ -0,0 +1,36 @@ +use std::path::PathBuf; + +use semver::Version; + +use libimagrt::runtime::Runtime; + +pub fn build_entry_path(rt: &Runtime, path_elem: &str) -> PathBuf { + debug!("Checking path element for version"); + { + let contains_version = { + path_elem.split("~") + .last() + .map(|version| Version::parse(version).is_ok()) + .unwrap_or(false) + }; + + if !contains_version { + debug!("Version cannot be parsed inside {:?}", path_elem); + warn!("Path does not contain version. Will panic now!"); + panic!("No version in path"); + } + } + debug!("Version checking succeeded"); + + debug!("Building path from {:?}", path_elem); + let mut path = rt.store().path().clone(); + + if path_elem.chars().next() == Some('/') { + path.push(&path_elem[1..path_elem.len()]); + } else { + path.push(path_elem); + } + + path +} + From 1aa70462a083749ba3d78dda1b9d41eae3db8a30 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Mon, 15 Feb 2016 17:16:53 +0100 Subject: [PATCH 5/8] Implement main() --- imag-tag/src/main.rs | 150 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 149 insertions(+), 1 deletion(-) diff --git a/imag-tag/src/main.rs b/imag-tag/src/main.rs index 70fd892b..e45479b3 100644 --- a/imag-tag/src/main.rs +++ b/imag-tag/src/main.rs @@ -9,8 +9,156 @@ extern crate libimagrt; extern crate libimagtag; extern crate libimagutil; +use std::process::exit; + +use libimagrt::runtime::Runtime; +use libimagtag::tagable::Tagable; + mod ui; +mod util; + +use ui::build_ui; +use util::build_entry_path; + +use libimagutil::trace::trace_error; fn main() { - println!("Hello, world!"); + let name = "imag-store"; + let version = &version!()[..]; + let about = "Direct interface to the store. Use with great care!"; + let ui = build_ui(Runtime::get_default_cli_builder(name, version, about)); + let rt = { + let rt = Runtime::new(ui); + if rt.is_ok() { + rt.unwrap() + } else { + println!("Could not set up Runtime"); + println!("{:?}", rt.err().unwrap()); + exit(1); + } + }; + + rt.init_logger(); + + debug!("Hello. Logging was just enabled"); + debug!("I already set up the Runtime object and build the commandline interface parser."); + debug!("Lets get rollin' ..."); + + let id = rt.cli().value_of("id").unwrap(); // enforced by clap + rt.cli() + .subcommand_name() + .map_or_else( + || { + let add = rt.cli().value_of("add"); + let rem = rt.cli().value_of("remove"); + let set = rt.cli().value_of("set"); + + alter(&rt, id, add, rem, set); + }, + |name| { + debug!("Call: {}", name); + match name { + "list" => list(id, &rt), + _ => { + warn!("Unknown command"); + // More error handling + }, + }; + }); } + +fn alter(rt: &Runtime, id: &str, add: Option<&str>, rem: Option<&str>, set: Option<&str>) { + let path = build_entry_path(rt, id); + debug!("path = {:?}", path); + rt.store() + // "id" must be present, enforced via clap spec + .retrieve(path) + .map(|mut e| { + add.map(|tags| { + let tags = tags.split(","); + for tag in tags { + info!("Adding tag '{}'", tag); + e.add_tag(String::from(tag)).map_err(|e| trace_error(&e)); + } + }); + + rem.map(|tags| { + let tags = tags.split(","); + for tag in tags { + info!("Removing tag '{}'", tag); + e.remove_tag(String::from(tag)).map_err(|e| trace_error(&e)); + } + }); + + set.map(|tags| { + info!("Setting tags '{}'", tags); + let tags = tags.split(",").map(String::from).collect(); + e.set_tags(tags); + }); + }) + .map_err(|e| { + info!("No entry."); + debug!("{}", e); + }); +} + +fn list(id: &str, rt: &Runtime) { + let path = build_entry_path(rt, id); + debug!("path = {:?}", path); + + let entry = rt.store().retrieve(path.clone()); + if entry.is_err() { + debug!("Could not retrieve '{:?}' => {:?}", id, path); + warn!("Could not retrieve entry '{}'", id); + trace_error(&entry.err().unwrap()); + exit(1); + } + let entry = entry.unwrap(); + + let scmd = rt.cli().subcommand_matches("list").unwrap(); // safe, we checked in main() + + let json_out = scmd.is_present("json"); + let line_out = scmd.is_present("linewise"); + let sepp_out = scmd.is_present("sep"); + let mut comm_out = scmd.is_present("commasep"); + + let flags = vec![json_out, line_out, comm_out, sepp_out]; + + if flags.iter().filter(|x| **x).count() > 1 { + // More than one flag passed + info!("Cannot do more than one thing"); + exit(1); + } + + if !flags.iter().any(|v| *v) { + // None of the flags passed, go to default + comm_out = true; + } + + let tags = entry.get_tags(); + if tags.is_err() { + trace_error(&tags.err().unwrap()); + exit(1); + } + let tags = tags.unwrap(); + + if json_out { + unimplemented!() + } + + if line_out { + for tag in &tags { + println!("{}", tag); + } + } + + if sepp_out { + let sepp = scmd.value_of("sep").unwrap(); // we checked before + println!("{}", tags.join(sepp)); + } + + if comm_out { + println!("{}", tags.join(", ")); + } +} + From 6cdc5093c46120c86c916d93e343c31bd20211eb Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Mon, 29 Feb 2016 15:34:34 +0100 Subject: [PATCH 6/8] fixup deps --- imag-tag/Cargo.toml | 2 +- imag-tag/src/ui.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/imag-tag/Cargo.toml b/imag-tag/Cargo.toml index 522a2397..d5946ba0 100644 --- a/imag-tag/Cargo.toml +++ b/imag-tag/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" authors = ["Matthias Beyer "] [dependencies] -clap = "1.5.5" +clap = "2.1.1" log = "0.3.5" version = "2.0.1" semver = "0.2.1" diff --git a/imag-tag/src/ui.rs b/imag-tag/src/ui.rs index 88c3df4d..6c90774b 100644 --- a/imag-tag/src/ui.rs +++ b/imag-tag/src/ui.rs @@ -1,6 +1,6 @@ use clap::{Arg, App, SubCommand}; -pub fn build_ui<'a>(app: App<'a, 'a, 'a, 'a, 'a, 'a>) -> App<'a, 'a, 'a, 'a, 'a, 'a> { +pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> { app.arg(Arg::with_name("id") .long("id") .short("i") From b5f97a83c9ea417ba72f4ac19163df42102d6036 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Sun, 6 Mar 2016 18:52:01 +0100 Subject: [PATCH 7/8] Add ArgGroup for output options --- imag-tag/src/main.rs | 10 +--------- imag-tag/src/ui.rs | 11 ++++++++++- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/imag-tag/src/main.rs b/imag-tag/src/main.rs index e45479b3..9b04b7de 100644 --- a/imag-tag/src/main.rs +++ b/imag-tag/src/main.rs @@ -122,15 +122,7 @@ fn list(id: &str, rt: &Runtime) { let sepp_out = scmd.is_present("sep"); let mut comm_out = scmd.is_present("commasep"); - let flags = vec![json_out, line_out, comm_out, sepp_out]; - - if flags.iter().filter(|x| **x).count() > 1 { - // More than one flag passed - info!("Cannot do more than one thing"); - exit(1); - } - - if !flags.iter().any(|v| *v) { + if !vec![json_out, line_out, comm_out, sepp_out].iter().any(|v| *v) { // None of the flags passed, go to default comm_out = true; } diff --git a/imag-tag/src/ui.rs b/imag-tag/src/ui.rs index 6c90774b..4f78bf1f 100644 --- a/imag-tag/src/ui.rs +++ b/imag-tag/src/ui.rs @@ -1,4 +1,4 @@ -use clap::{Arg, App, SubCommand}; +use clap::{Arg, App, ArgGroup, SubCommand}; pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> { app.arg(Arg::with_name("id") @@ -59,6 +59,15 @@ pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> { .takes_value(true) .required(false) .help("Seperated by string")) + + .group(ArgGroup::with_name("list-group") + .args(&[ + "json", + "linewise", + "commasep", + "sep", + ]) + .required(true)) ) } From 4c6f30096566305ee4632b474128d1596b338d0c Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Sun, 6 Mar 2016 18:53:10 +0100 Subject: [PATCH 8/8] Remove warnings: Unused result -> use trace_error() --- imag-tag/src/main.rs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/imag-tag/src/main.rs b/imag-tag/src/main.rs index 9b04b7de..87b9919d 100644 --- a/imag-tag/src/main.rs +++ b/imag-tag/src/main.rs @@ -78,7 +78,9 @@ fn alter(rt: &Runtime, id: &str, add: Option<&str>, rem: Option<&str>, set: Opti let tags = tags.split(","); for tag in tags { info!("Adding tag '{}'", tag); - e.add_tag(String::from(tag)).map_err(|e| trace_error(&e)); + if let Err(e) = e.add_tag(String::from(tag)) { + trace_error(&e); + } } }); @@ -86,20 +88,25 @@ fn alter(rt: &Runtime, id: &str, add: Option<&str>, rem: Option<&str>, set: Opti let tags = tags.split(","); for tag in tags { info!("Removing tag '{}'", tag); - e.remove_tag(String::from(tag)).map_err(|e| trace_error(&e)); + if let Err(e) = e.remove_tag(String::from(tag)) { + trace_error(&e); + } } }); set.map(|tags| { info!("Setting tags '{}'", tags); let tags = tags.split(",").map(String::from).collect(); - e.set_tags(tags); + if let Err(e) = e.set_tags(tags) { + trace_error(&e); + } }); }) .map_err(|e| { info!("No entry."); - debug!("{}", e); - }); + trace_error(&e); + }) + .ok(); } fn list(id: &str, rt: &Runtime) {