From d408aed8441facb8e1edfaff9fb2760e991f9aff Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Thu, 4 Feb 2016 13:53:39 +0100 Subject: [PATCH 01/19] libimagtag: init --- libimagtag/Cargo.toml | 6 ++++++ libimagtag/src/lib.rs | 3 +++ 2 files changed, 9 insertions(+) create mode 100644 libimagtag/Cargo.toml create mode 100644 libimagtag/src/lib.rs diff --git a/libimagtag/Cargo.toml b/libimagtag/Cargo.toml new file mode 100644 index 00000000..260112b5 --- /dev/null +++ b/libimagtag/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "libimagtag" +version = "0.1.0" +authors = ["Matthias Beyer "] + +[dependencies] diff --git a/libimagtag/src/lib.rs b/libimagtag/src/lib.rs new file mode 100644 index 00000000..a93251b6 --- /dev/null +++ b/libimagtag/src/lib.rs @@ -0,0 +1,3 @@ +#[test] +fn it_works() { +} From 38c492c36223dd0d06ea2541bc3aa9fa0ef1fe7f Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Thu, 4 Feb 2016 13:54:15 +0100 Subject: [PATCH 02/19] Add dependencies --- libimagtag/Cargo.toml | 6 ++++++ libimagtag/src/lib.rs | 5 ++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/libimagtag/Cargo.toml b/libimagtag/Cargo.toml index 260112b5..88c2ed44 100644 --- a/libimagtag/Cargo.toml +++ b/libimagtag/Cargo.toml @@ -4,3 +4,9 @@ version = "0.1.0" authors = ["Matthias Beyer "] [dependencies] +regex = "0.1.47" +toml = "0.1.25" + +[dependencies.libimagstore] +path = "../libimagstore" + diff --git a/libimagtag/src/lib.rs b/libimagtag/src/lib.rs index a93251b6..029dc609 100644 --- a/libimagtag/src/lib.rs +++ b/libimagtag/src/lib.rs @@ -1,3 +1,2 @@ -#[test] -fn it_works() { -} +extern crate regex; +extern crate toml; From fd204ee05e6de5806ab4ae01819d8bcd52f981fa Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Thu, 4 Feb 2016 14:01:33 +0100 Subject: [PATCH 03/19] Add initial module structure --- libimagtag/src/add.rs | 0 libimagtag/src/check.rs | 0 libimagtag/src/error.rs | 0 libimagtag/src/lib.rs | 10 ++++++++++ libimagtag/src/remove.rs | 0 libimagtag/src/result.rs | 0 libimagtag/src/tag.rs | 1 + libimagtag/src/util.rs | 5 +++++ 8 files changed, 16 insertions(+) create mode 100644 libimagtag/src/add.rs create mode 100644 libimagtag/src/check.rs create mode 100644 libimagtag/src/error.rs create mode 100644 libimagtag/src/remove.rs create mode 100644 libimagtag/src/result.rs create mode 100644 libimagtag/src/tag.rs create mode 100644 libimagtag/src/util.rs diff --git a/libimagtag/src/add.rs b/libimagtag/src/add.rs new file mode 100644 index 00000000..e69de29b diff --git a/libimagtag/src/check.rs b/libimagtag/src/check.rs new file mode 100644 index 00000000..e69de29b diff --git a/libimagtag/src/error.rs b/libimagtag/src/error.rs new file mode 100644 index 00000000..e69de29b diff --git a/libimagtag/src/lib.rs b/libimagtag/src/lib.rs index 029dc609..252f6f68 100644 --- a/libimagtag/src/lib.rs +++ b/libimagtag/src/lib.rs @@ -1,2 +1,12 @@ extern crate regex; extern crate toml; + +extern crate libimagstore; + +pub mod add; +pub mod check; +pub mod error; +pub mod remove; +pub mod result; +pub mod tag; +pub mod util; diff --git a/libimagtag/src/remove.rs b/libimagtag/src/remove.rs new file mode 100644 index 00000000..e69de29b diff --git a/libimagtag/src/result.rs b/libimagtag/src/result.rs new file mode 100644 index 00000000..e69de29b diff --git a/libimagtag/src/tag.rs b/libimagtag/src/tag.rs new file mode 100644 index 00000000..cba2322e --- /dev/null +++ b/libimagtag/src/tag.rs @@ -0,0 +1 @@ +pub type Tag = String; diff --git a/libimagtag/src/util.rs b/libimagtag/src/util.rs new file mode 100644 index 00000000..caa32539 --- /dev/null +++ b/libimagtag/src/util.rs @@ -0,0 +1,5 @@ +use regex::Regex; + +pub fn is_tag(s: &String) -> bool { + Regex::new("^[a-zA-Z]([a-zA-Z0-9_-]*)$").unwrap().captures(&s[..]).is_some() +} From 15b1adbc206973b1ae4e8236cc8c1f90ef370ef8 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Thu, 4 Feb 2016 14:05:30 +0100 Subject: [PATCH 04/19] Add error type implementation --- libimagtag/src/error.rs | 63 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/libimagtag/src/error.rs b/libimagtag/src/error.rs index e69de29b..321ecf1a 100644 --- a/libimagtag/src/error.rs +++ b/libimagtag/src/error.rs @@ -0,0 +1,63 @@ +use std::error::Error; +use std::fmt::Error as FmtError; +use std::clone::Clone; +use std::fmt::{Debug, Display, Formatter}; +use std::fmt; + +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum TagErrorKind { +} + +fn tag_error_type_as_str(e: &TagErrorKind) -> &'static str { + match e { + _ => "", + } +} + +impl Display for TagErrorKind { + + fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> { + try!(write!(fmt, "{}", tag_error_type_as_str(self))); + Ok(()) + } + +} + +#[derive(Debug)] +pub struct TagError { + kind: TagErrorKind, + cause: Option>, +} + +impl TagError { + + pub fn new(errtype: TagErrorKind, cause: Option>) -> TagError { + TagError { + kind: errtype, + cause: cause, + } + } + +} + +impl Display for TagError { + + fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> { + try!(write!(fmt, "[{}]", tag_error_type_as_str(&self.kind.clone()))); + Ok(()) + } + +} + +impl Error for TagError { + + fn description(&self) -> &str { + tag_error_type_as_str(&self.kind.clone()) + } + + fn cause(&self) -> Option<&Error> { + self.cause.as_ref().map(|e| &**e) + } + +} + From 5512e2c86cef1b7589de49f6cb9792555f95e9de Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Thu, 4 Feb 2016 14:05:37 +0100 Subject: [PATCH 05/19] Add result type --- libimagtag/src/result.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libimagtag/src/result.rs b/libimagtag/src/result.rs index e69de29b..a01166ca 100644 --- a/libimagtag/src/result.rs +++ b/libimagtag/src/result.rs @@ -0,0 +1,6 @@ +use std::result::Result as RResult; + +use error::TagError; + +pub type Result = RResult; + From 78ae968ee996540703d76ffb398029f27b84e312 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 12 Feb 2016 19:24:55 +0100 Subject: [PATCH 06/19] Add add::add_tag() --- libimagtag/src/add.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/libimagtag/src/add.rs b/libimagtag/src/add.rs index e69de29b..e891a1ce 100644 --- a/libimagtag/src/add.rs +++ b/libimagtag/src/add.rs @@ -0,0 +1,8 @@ +use libimagstore::store::Entry; + +use result::Result; +use tag::Tag; +pub fn add_tag(e: &mut Entry, t: &Tag) -> Result<()> { + + unimplemented!() +} From 028f8676a056706d5556f9a53bf9257e7d091298 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 12 Feb 2016 19:25:25 +0100 Subject: [PATCH 07/19] Add remove::remove_tag() --- libimagtag/src/remove.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/libimagtag/src/remove.rs b/libimagtag/src/remove.rs index e69de29b..9aef862d 100644 --- a/libimagtag/src/remove.rs +++ b/libimagtag/src/remove.rs @@ -0,0 +1,9 @@ + +use libimagstore::store::Entry; + +use result::Result; +use tag::Tag; + +pub fn remove_tag(e: &Entry, t: &Tag) -> Result<()> { + unimplemented!() +} From 31b966b9b435cf1e56b30330dc7e091933852fad Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 12 Feb 2016 19:28:20 +0100 Subject: [PATCH 08/19] Add check::has_tag{,s}() --- libimagtag/src/check.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/libimagtag/src/check.rs b/libimagtag/src/check.rs index e69de29b..473df2e4 100644 --- a/libimagtag/src/check.rs +++ b/libimagtag/src/check.rs @@ -0,0 +1,14 @@ + +use libimagstore::store::Entry; + +use result::Result; +use tag::Tag; + +pub fn has_tag(e: &Entry, t: &Tag) -> Result { + unimplemented!() +} + +pub fn has_tags(e: &Entry, ts: &Vec) -> Result { + unimplemented!() +} + From f4e7969039cb86cc0e1787fe6dc1d5f969334b09 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Sun, 14 Feb 2016 19:59:34 +0100 Subject: [PATCH 09/19] Implement: check::has_tag{,s}() --- libimagtag/src/check.rs | 45 +++++++++++++++++++++++++++++++++++++---- libimagtag/src/error.rs | 5 ++++- 2 files changed, 45 insertions(+), 5 deletions(-) diff --git a/libimagtag/src/check.rs b/libimagtag/src/check.rs index 473df2e4..ecc092dc 100644 --- a/libimagtag/src/check.rs +++ b/libimagtag/src/check.rs @@ -1,14 +1,51 @@ +use toml::Value; -use libimagstore::store::Entry; +use libimagstore::store::{Entry, EntryHeader}; use result::Result; use tag::Tag; +use error::{TagError, TagErrorKind}; pub fn has_tag(e: &Entry, t: &Tag) -> Result { - unimplemented!() + header_has_tag(e.get_header(), t) } -pub fn has_tags(e: &Entry, ts: &Vec) -> Result { - unimplemented!() +pub fn has_tags(e: &Entry, tags: &Vec) -> Result { + let hdr = e.get_header(); + let mut result = true; + + for tag in tags { + let check = header_has_tag(hdr, tag); + if check.is_err() { + return Err(check.err().unwrap()); + } + let check = check.unwrap(); + + result = result && check; + } + + Ok(result) +} + +fn header_has_tag(head: &EntryHeader, t: &Tag) -> Result { + let tags = head.read("imag.tags"); + if tags.is_err() { + let kind = TagErrorKind::HeaderReadError; + return Err(TagError::new(kind, Some(Box::new(tags.err().unwrap())))); + } + let tags = tags.unwrap(); + + if !tags.iter().all(|t| match t { &Value::String(_) => true, _ => false }) { + return Err(TagError::new(TagErrorKind::TagTypeError, None)); + } + + Ok(tags + .iter() + .any(|tag| { + match tag { + &Value::String(ref s) => { s == t }, + _ => unreachable!() + } + })) } diff --git a/libimagtag/src/error.rs b/libimagtag/src/error.rs index 321ecf1a..58615a6a 100644 --- a/libimagtag/src/error.rs +++ b/libimagtag/src/error.rs @@ -6,11 +6,14 @@ use std::fmt; #[derive(Clone, Copy, Debug, PartialEq)] pub enum TagErrorKind { + TagTypeError, + HeaderReadError, } fn tag_error_type_as_str(e: &TagErrorKind) -> &'static str { match e { - _ => "", + &TagErrorKind::TagTypeError => "Entry Header Tag Type wrong", + &TagErrorKind::HeaderReadError => "Error while reading entry header", } } From a2898dcc467bcaf1097b40b168056f865637c009 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Sun, 14 Feb 2016 20:09:51 +0100 Subject: [PATCH 10/19] Implement: remove::remove_tag() --- libimagtag/src/remove.rs | 46 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/libimagtag/src/remove.rs b/libimagtag/src/remove.rs index 9aef862d..084cee93 100644 --- a/libimagtag/src/remove.rs +++ b/libimagtag/src/remove.rs @@ -1,9 +1,51 @@ +use toml::Value; use libimagstore::store::Entry; use result::Result; use tag::Tag; +use error::{TagError, TagErrorKind}; -pub fn remove_tag(e: &Entry, t: &Tag) -> Result<()> { - unimplemented!() +pub fn remove_tag(e: &mut Entry, t: &Tag) -> Result<()> { + let tags = e.get_header().read("imag.tags"); + if tags.is_err() { + let kind = TagErrorKind::HeaderReadError; + return Err(TagError::new(kind, Some(Box::new(tags.err().unwrap())))); + } + let tags = tags.unwrap(); + + if !tags.iter().all(|t| match t { &Value::String(_) => true, _ => false }) { + return Err(TagError::new(TagErrorKind::TagTypeError, None)); + } + + if tags.is_none() { + return Ok(()); + } + let tags = tags.unwrap(); + + if !match tags { Value::Array(_) => true, _ => false } { + return Err(TagError::new(TagErrorKind::TagTypeError, None)); + } + + match tags { + Value::Array(tag_array) => { + let new_tags = tag_array.iter() + .map(|tag| { + match tag { + &Value::String(ref s) => s, + _ => unreachable!(), + } + }) + .filter(|tag| tag.clone() != t) + .map(|tag| Value::String(t.clone())) + .collect(); + + e.get_header_mut() + .set("imag.tags", Value::Array(new_tags)) + .map_err(|e| TagError::new(TagErrorKind::TagTypeError, Some(Box::new(e)))) + .map(|_| ()) + }, + + _ => unreachable!(), + } } From 1ca9597ad62a92beaca11d4b945787ff02bf6dd6 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Sun, 14 Feb 2016 20:15:03 +0100 Subject: [PATCH 11/19] Implement: add::add_tag() --- libimagtag/src/add.rs | 39 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/libimagtag/src/add.rs b/libimagtag/src/add.rs index e891a1ce..ebfaa257 100644 --- a/libimagtag/src/add.rs +++ b/libimagtag/src/add.rs @@ -1,8 +1,43 @@ +use toml::Value; + use libimagstore::store::Entry; use result::Result; use tag::Tag; -pub fn add_tag(e: &mut Entry, t: &Tag) -> Result<()> { +use error::{TagError, TagErrorKind}; - unimplemented!() +pub fn add_tag(e: &mut Entry, t: &Tag) -> Result<()> { + let tags = e.get_header().read("imag.tags"); + if tags.is_err() { + let kind = TagErrorKind::HeaderReadError; + return Err(TagError::new(kind, Some(Box::new(tags.err().unwrap())))); + } + let tags = tags.unwrap(); + + if !tags.iter().all(|t| match t { &Value::String(_) => true, _ => false }) { + return Err(TagError::new(TagErrorKind::TagTypeError, None)); + } + + if tags.is_none() { + return Ok(()); + } + let tags = tags.unwrap(); + + if !match tags { Value::Array(_) => true, _ => false } { + return Err(TagError::new(TagErrorKind::TagTypeError, None)); + } + + match tags { + Value::Array(tag_array) => { + let mut new_tags = tag_array.clone(); + new_tags.push(Value::String(t.clone())); + + e.get_header_mut() + .set("imag.tags", Value::Array(new_tags)) + .map_err(|e| TagError::new(TagErrorKind::TagTypeError, Some(Box::new(e)))) + .map(|_| ()) + }, + + _ => unreachable!(), + } } From 5c92624989f893d875c57b0173137c92dfea55bb Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Mon, 15 Feb 2016 14:03:56 +0100 Subject: [PATCH 12/19] Refactor everything into one trait --- libimagtag/src/add.rs | 33 -------- libimagtag/src/check.rs | 37 -------- libimagtag/src/error.rs | 2 + libimagtag/src/lib.rs | 4 +- libimagtag/src/remove.rs | 41 --------- libimagtag/src/tagable.rs | 173 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 176 insertions(+), 114 deletions(-) create mode 100644 libimagtag/src/tagable.rs diff --git a/libimagtag/src/add.rs b/libimagtag/src/add.rs index ebfaa257..40749957 100644 --- a/libimagtag/src/add.rs +++ b/libimagtag/src/add.rs @@ -7,37 +7,4 @@ use tag::Tag; use error::{TagError, TagErrorKind}; pub fn add_tag(e: &mut Entry, t: &Tag) -> Result<()> { - let tags = e.get_header().read("imag.tags"); - if tags.is_err() { - let kind = TagErrorKind::HeaderReadError; - return Err(TagError::new(kind, Some(Box::new(tags.err().unwrap())))); - } - let tags = tags.unwrap(); - - if !tags.iter().all(|t| match t { &Value::String(_) => true, _ => false }) { - return Err(TagError::new(TagErrorKind::TagTypeError, None)); - } - - if tags.is_none() { - return Ok(()); - } - let tags = tags.unwrap(); - - if !match tags { Value::Array(_) => true, _ => false } { - return Err(TagError::new(TagErrorKind::TagTypeError, None)); - } - - match tags { - Value::Array(tag_array) => { - let mut new_tags = tag_array.clone(); - new_tags.push(Value::String(t.clone())); - - e.get_header_mut() - .set("imag.tags", Value::Array(new_tags)) - .map_err(|e| TagError::new(TagErrorKind::TagTypeError, Some(Box::new(e)))) - .map(|_| ()) - }, - - _ => unreachable!(), - } } diff --git a/libimagtag/src/check.rs b/libimagtag/src/check.rs index ecc092dc..7c98e745 100644 --- a/libimagtag/src/check.rs +++ b/libimagtag/src/check.rs @@ -7,45 +7,8 @@ use tag::Tag; use error::{TagError, TagErrorKind}; pub fn has_tag(e: &Entry, t: &Tag) -> Result { - header_has_tag(e.get_header(), t) } pub fn has_tags(e: &Entry, tags: &Vec) -> Result { - let hdr = e.get_header(); - let mut result = true; - - for tag in tags { - let check = header_has_tag(hdr, tag); - if check.is_err() { - return Err(check.err().unwrap()); - } - let check = check.unwrap(); - - result = result && check; - } - - Ok(result) -} - -fn header_has_tag(head: &EntryHeader, t: &Tag) -> Result { - let tags = head.read("imag.tags"); - if tags.is_err() { - let kind = TagErrorKind::HeaderReadError; - return Err(TagError::new(kind, Some(Box::new(tags.err().unwrap())))); - } - let tags = tags.unwrap(); - - if !tags.iter().all(|t| match t { &Value::String(_) => true, _ => false }) { - return Err(TagError::new(TagErrorKind::TagTypeError, None)); - } - - Ok(tags - .iter() - .any(|tag| { - match tag { - &Value::String(ref s) => { s == t }, - _ => unreachable!() - } - })) } diff --git a/libimagtag/src/error.rs b/libimagtag/src/error.rs index 58615a6a..dcd36426 100644 --- a/libimagtag/src/error.rs +++ b/libimagtag/src/error.rs @@ -8,12 +8,14 @@ use std::fmt; pub enum TagErrorKind { TagTypeError, HeaderReadError, + HeaderWriteError, } fn tag_error_type_as_str(e: &TagErrorKind) -> &'static str { match e { &TagErrorKind::TagTypeError => "Entry Header Tag Type wrong", &TagErrorKind::HeaderReadError => "Error while reading entry header", + &TagErrorKind::HeaderWriteError=> "Error while writing entry header", } } diff --git a/libimagtag/src/lib.rs b/libimagtag/src/lib.rs index 252f6f68..ad9e5e7b 100644 --- a/libimagtag/src/lib.rs +++ b/libimagtag/src/lib.rs @@ -3,10 +3,8 @@ extern crate toml; extern crate libimagstore; -pub mod add; -pub mod check; pub mod error; -pub mod remove; pub mod result; pub mod tag; +pub mod tagable; pub mod util; diff --git a/libimagtag/src/remove.rs b/libimagtag/src/remove.rs index 084cee93..42e02719 100644 --- a/libimagtag/src/remove.rs +++ b/libimagtag/src/remove.rs @@ -7,45 +7,4 @@ use tag::Tag; use error::{TagError, TagErrorKind}; pub fn remove_tag(e: &mut Entry, t: &Tag) -> Result<()> { - let tags = e.get_header().read("imag.tags"); - if tags.is_err() { - let kind = TagErrorKind::HeaderReadError; - return Err(TagError::new(kind, Some(Box::new(tags.err().unwrap())))); - } - let tags = tags.unwrap(); - - if !tags.iter().all(|t| match t { &Value::String(_) => true, _ => false }) { - return Err(TagError::new(TagErrorKind::TagTypeError, None)); - } - - if tags.is_none() { - return Ok(()); - } - let tags = tags.unwrap(); - - if !match tags { Value::Array(_) => true, _ => false } { - return Err(TagError::new(TagErrorKind::TagTypeError, None)); - } - - match tags { - Value::Array(tag_array) => { - let new_tags = tag_array.iter() - .map(|tag| { - match tag { - &Value::String(ref s) => s, - _ => unreachable!(), - } - }) - .filter(|tag| tag.clone() != t) - .map(|tag| Value::String(t.clone())) - .collect(); - - e.get_header_mut() - .set("imag.tags", Value::Array(new_tags)) - .map_err(|e| TagError::new(TagErrorKind::TagTypeError, Some(Box::new(e)))) - .map(|_| ()) - }, - - _ => unreachable!(), - } } diff --git a/libimagtag/src/tagable.rs b/libimagtag/src/tagable.rs new file mode 100644 index 00000000..a5c76c8d --- /dev/null +++ b/libimagtag/src/tagable.rs @@ -0,0 +1,173 @@ +use libimagstore::store::{Entry, EntryHeader}; + +use error::{TagError, TagErrorKind}; +use result::Result; +use tag::Tag; + +use toml::Value; + +pub trait Tagable { + + fn get_tags(&self) -> Result>; + fn set_tags(&mut self, ts: Vec) -> Result<()>; + + fn add_tag(&mut self, t: Tag) -> Result<()>; + fn remove_tag(&mut self, t: Tag) -> Result<()>; + + fn has_tag(&self, t: &Tag) -> Result; + fn has_tags(&self, ts: &Vec) -> Result; + +} + +impl Tagable for EntryHeader { + + fn get_tags(&self) -> Result> { + let tags = self.read("imag.tags"); + if tags.is_err() { + let kind = TagErrorKind::HeaderReadError; + return Err(TagError::new(kind, Some(Box::new(tags.err().unwrap())))); + } + let tags = tags.unwrap(); + + match tags { + Some(Value::Array(tags)) => { + if !tags.iter().all(|t| match t { &Value::String(_) => true, _ => false }) { + return Err(TagError::new(TagErrorKind::TagTypeError, None)); + } + + Ok(tags.iter() + .cloned() + .map(|t| { + match t { + Value::String(s) => s, + _ => unreachable!(), + } + }) + .collect()) + }, + None => Ok(vec![]), + _ => Err(TagError::new(TagErrorKind::TagTypeError, None)), + } + } + + fn set_tags(&mut self, ts: Vec) -> Result<()> { + let a = ts.iter().map(|t| Value::String(t.clone())).collect(); + self.set("imag.tags", Value::Array(a)) + .map(|_| ()) + .map_err(|e| TagError::new(TagErrorKind::HeaderWriteError, Some(Box::new(e)))) + } + + fn add_tag(&mut self, t: Tag) -> Result<()> { + let tags = self.read("imag.tags"); + if tags.is_err() { + let kind = TagErrorKind::HeaderReadError; + return Err(TagError::new(kind, Some(Box::new(tags.err().unwrap())))); + } + let tags = tags.unwrap(); + + if !tags.iter().all(|t| match t { &Value::String(_) => true, _ => false }) { + return Err(TagError::new(TagErrorKind::TagTypeError, None)); + } + + if tags.is_none() { + return Ok(()); + } + let tags = tags.unwrap(); + + if !match tags { Value::Array(_) => true, _ => false } { + return Err(TagError::new(TagErrorKind::TagTypeError, None)); + } + + match tags { + Value::Array(tag_array) => { + let mut new_tags = tag_array.clone(); + new_tags.push(Value::String(t.clone())); + + self.set("imag.tags", Value::Array(new_tags)) + .map_err(|e| TagError::new(TagErrorKind::TagTypeError, Some(Box::new(e)))) + .map(|_| ()) + }, + + _ => unreachable!(), + } + } + + fn remove_tag(&mut self, t: Tag) -> Result<()> { + let tags = self.read("imag.tags"); + if tags.is_err() { + let kind = TagErrorKind::HeaderReadError; + return Err(TagError::new(kind, Some(Box::new(tags.err().unwrap())))); + } + let tags = tags.unwrap(); + + if !tags.iter().all(|t| match t { &Value::String(_) => true, _ => false }) { + return Err(TagError::new(TagErrorKind::TagTypeError, None)); + } + + if tags.is_none() { + return Ok(()); + } + let tags = tags.unwrap(); + + if !match tags { Value::Array(_) => true, _ => false } { + return Err(TagError::new(TagErrorKind::TagTypeError, None)); + } + + match tags { + Value::Array(tag_array) => { + let mut tag_array = tag_array.clone(); + tag_array.retain(|tag| { + match tag { + &Value::String(ref s) => s.clone() != t, + _ => unreachable!(), + } + }); + + self.set("imag.tags", Value::Array(tag_array)) + .map_err(|e| TagError::new(TagErrorKind::TagTypeError, Some(Box::new(e)))) + .map(|_| ()) + }, + + _ => unreachable!(), + } + } + + fn has_tag(&self, t: &Tag) -> Result { + let tags = self.read("imag.tags"); + if tags.is_err() { + let kind = TagErrorKind::HeaderReadError; + return Err(TagError::new(kind, Some(Box::new(tags.err().unwrap())))); + } + let tags = tags.unwrap(); + + if !tags.iter().all(|t| match t { &Value::String(_) => true, _ => false }) { + return Err(TagError::new(TagErrorKind::TagTypeError, None)); + } + + Ok(tags + .iter() + .any(|tag| { + match tag { + &Value::String(ref s) => { s == t }, + _ => unreachable!() + } + })) + } + + fn has_tags(&self, tags: &Vec) -> Result { + let mut result = true; + for tag in tags { + let check = self.has_tag(tag); + if check.is_err() { + return Err(check.err().unwrap()); + } + let check = check.unwrap(); + + result = result && check; + } + + Ok(result) + } + +} + From 386ba39e94a2414d5c181554220b8d2d5621da1b Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Mon, 15 Feb 2016 14:06:08 +0100 Subject: [PATCH 13/19] Reimplement add_tag() with get_tags()/set_tags() --- libimagtag/src/tagable.rs | 38 ++++++-------------------------------- 1 file changed, 6 insertions(+), 32 deletions(-) diff --git a/libimagtag/src/tagable.rs b/libimagtag/src/tagable.rs index a5c76c8d..6d91fa15 100644 --- a/libimagtag/src/tagable.rs +++ b/libimagtag/src/tagable.rs @@ -58,38 +58,12 @@ impl Tagable for EntryHeader { } fn add_tag(&mut self, t: Tag) -> Result<()> { - let tags = self.read("imag.tags"); - if tags.is_err() { - let kind = TagErrorKind::HeaderReadError; - return Err(TagError::new(kind, Some(Box::new(tags.err().unwrap())))); - } - let tags = tags.unwrap(); - - if !tags.iter().all(|t| match t { &Value::String(_) => true, _ => false }) { - return Err(TagError::new(TagErrorKind::TagTypeError, None)); - } - - if tags.is_none() { - return Ok(()); - } - let tags = tags.unwrap(); - - if !match tags { Value::Array(_) => true, _ => false } { - return Err(TagError::new(TagErrorKind::TagTypeError, None)); - } - - match tags { - Value::Array(tag_array) => { - let mut new_tags = tag_array.clone(); - new_tags.push(Value::String(t.clone())); - - self.set("imag.tags", Value::Array(new_tags)) - .map_err(|e| TagError::new(TagErrorKind::TagTypeError, Some(Box::new(e)))) - .map(|_| ()) - }, - - _ => unreachable!(), - } + self.get_tags() + .map(|mut tags| { + tags.push(t); + self.set_tags(tags) + }) + .map(|_| ()) } fn remove_tag(&mut self, t: Tag) -> Result<()> { From b3960bbf9550bfcff64b33172b3a41caa6b21990 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Mon, 15 Feb 2016 14:07:10 +0100 Subject: [PATCH 14/19] Reimplement remove_tag() with get_tags()/set_tags() --- libimagtag/src/tagable.rs | 43 ++++++--------------------------------- 1 file changed, 6 insertions(+), 37 deletions(-) diff --git a/libimagtag/src/tagable.rs b/libimagtag/src/tagable.rs index 6d91fa15..1ad7da7e 100644 --- a/libimagtag/src/tagable.rs +++ b/libimagtag/src/tagable.rs @@ -67,43 +67,12 @@ impl Tagable for EntryHeader { } fn remove_tag(&mut self, t: Tag) -> Result<()> { - let tags = self.read("imag.tags"); - if tags.is_err() { - let kind = TagErrorKind::HeaderReadError; - return Err(TagError::new(kind, Some(Box::new(tags.err().unwrap())))); - } - let tags = tags.unwrap(); - - if !tags.iter().all(|t| match t { &Value::String(_) => true, _ => false }) { - return Err(TagError::new(TagErrorKind::TagTypeError, None)); - } - - if tags.is_none() { - return Ok(()); - } - let tags = tags.unwrap(); - - if !match tags { Value::Array(_) => true, _ => false } { - return Err(TagError::new(TagErrorKind::TagTypeError, None)); - } - - match tags { - Value::Array(tag_array) => { - let mut tag_array = tag_array.clone(); - tag_array.retain(|tag| { - match tag { - &Value::String(ref s) => s.clone() != t, - _ => unreachable!(), - } - }); - - self.set("imag.tags", Value::Array(tag_array)) - .map_err(|e| TagError::new(TagErrorKind::TagTypeError, Some(Box::new(e)))) - .map(|_| ()) - }, - - _ => unreachable!(), - } + self.get_tags() + .map(|mut tags| { + tags.retain(|tag| tag.clone() != t); + self.set_tags(tags) + }) + .map(|_| ()) } fn has_tag(&self, t: &Tag) -> Result { From 5adc8504beacb6b3564685c398b9b3d90a5938fc Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Mon, 15 Feb 2016 14:09:11 +0100 Subject: [PATCH 15/19] Impl Tagable for Entry for convenience --- libimagtag/src/tagable.rs | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/libimagtag/src/tagable.rs b/libimagtag/src/tagable.rs index 1ad7da7e..3eca3856 100644 --- a/libimagtag/src/tagable.rs +++ b/libimagtag/src/tagable.rs @@ -114,3 +114,30 @@ impl Tagable for EntryHeader { } +impl Tagable for Entry { + + fn get_tags(&self) -> Result> { + self.get_header().get_tags() + } + + fn set_tags(&mut self, ts: Vec) -> Result<()> { + self.get_header_mut().set_tags(ts) + } + + fn add_tag(&mut self, t: Tag) -> Result<()> { + self.get_header_mut().add_tag(t) + } + + fn remove_tag(&mut self, t: Tag) -> Result<()> { + self.get_header_mut().remove_tag(t) + } + + fn has_tag(&self, t: &Tag) -> Result { + self.get_header().has_tag(t) + } + + fn has_tags(&self, ts: &Vec) -> Result { + self.get_header().has_tags(ts) + } + +} From 687aa34c07924b5f8d1efa4722033d2bd33074bc Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Sun, 21 Feb 2016 19:07:30 +0100 Subject: [PATCH 16/19] Remove old files --- libimagtag/src/add.rs | 10 ---------- libimagtag/src/check.rs | 14 -------------- libimagtag/src/remove.rs | 10 ---------- 3 files changed, 34 deletions(-) delete mode 100644 libimagtag/src/add.rs delete mode 100644 libimagtag/src/check.rs delete mode 100644 libimagtag/src/remove.rs diff --git a/libimagtag/src/add.rs b/libimagtag/src/add.rs deleted file mode 100644 index 40749957..00000000 --- a/libimagtag/src/add.rs +++ /dev/null @@ -1,10 +0,0 @@ -use toml::Value; - -use libimagstore::store::Entry; - -use result::Result; -use tag::Tag; -use error::{TagError, TagErrorKind}; - -pub fn add_tag(e: &mut Entry, t: &Tag) -> Result<()> { -} diff --git a/libimagtag/src/check.rs b/libimagtag/src/check.rs deleted file mode 100644 index 7c98e745..00000000 --- a/libimagtag/src/check.rs +++ /dev/null @@ -1,14 +0,0 @@ -use toml::Value; - -use libimagstore::store::{Entry, EntryHeader}; - -use result::Result; -use tag::Tag; -use error::{TagError, TagErrorKind}; - -pub fn has_tag(e: &Entry, t: &Tag) -> Result { -} - -pub fn has_tags(e: &Entry, tags: &Vec) -> Result { -} - diff --git a/libimagtag/src/remove.rs b/libimagtag/src/remove.rs deleted file mode 100644 index 42e02719..00000000 --- a/libimagtag/src/remove.rs +++ /dev/null @@ -1,10 +0,0 @@ -use toml::Value; - -use libimagstore::store::Entry; - -use result::Result; -use tag::Tag; -use error::{TagError, TagErrorKind}; - -pub fn remove_tag(e: &mut Entry, t: &Tag) -> Result<()> { -} From f0424e9e60384d01d4c8b2797051d48c15c39e98 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Sun, 21 Feb 2016 19:17:36 +0100 Subject: [PATCH 17/19] Add dep: log = 0.3.5 --- libimagtag/Cargo.toml | 1 + libimagtag/src/lib.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/libimagtag/Cargo.toml b/libimagtag/Cargo.toml index 88c2ed44..001efb43 100644 --- a/libimagtag/Cargo.toml +++ b/libimagtag/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" authors = ["Matthias Beyer "] [dependencies] +log = "0.3.5" regex = "0.1.47" toml = "0.1.25" diff --git a/libimagtag/src/lib.rs b/libimagtag/src/lib.rs index ad9e5e7b..2db44143 100644 --- a/libimagtag/src/lib.rs +++ b/libimagtag/src/lib.rs @@ -1,3 +1,4 @@ +#[macro_use] extern crate log; extern crate regex; extern crate toml; From 38ca44d10d6d87a3d18fafff84322d77e1d5fd89 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Sun, 21 Feb 2016 19:18:38 +0100 Subject: [PATCH 18/19] Add is_tag() checks --- libimagtag/src/error.rs | 8 +++++--- libimagtag/src/tagable.rs | 22 ++++++++++++++++++++++ 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/libimagtag/src/error.rs b/libimagtag/src/error.rs index dcd36426..ed15e283 100644 --- a/libimagtag/src/error.rs +++ b/libimagtag/src/error.rs @@ -9,13 +9,15 @@ pub enum TagErrorKind { TagTypeError, HeaderReadError, HeaderWriteError, + NotATag, } fn tag_error_type_as_str(e: &TagErrorKind) -> &'static str { match e { - &TagErrorKind::TagTypeError => "Entry Header Tag Type wrong", - &TagErrorKind::HeaderReadError => "Error while reading entry header", - &TagErrorKind::HeaderWriteError=> "Error while writing entry header", + &TagErrorKind::TagTypeError => "Entry Header Tag Type wrong", + &TagErrorKind::HeaderReadError => "Error while reading entry header", + &TagErrorKind::HeaderWriteError => "Error while writing entry header", + &TagErrorKind::NotATag => "String is not a tag", } } diff --git a/libimagtag/src/tagable.rs b/libimagtag/src/tagable.rs index 3eca3856..f38f49d6 100644 --- a/libimagtag/src/tagable.rs +++ b/libimagtag/src/tagable.rs @@ -3,6 +3,7 @@ use libimagstore::store::{Entry, EntryHeader}; use error::{TagError, TagErrorKind}; use result::Result; use tag::Tag; +use util::is_tag; use toml::Value; @@ -34,6 +35,12 @@ impl Tagable for EntryHeader { if !tags.iter().all(|t| match t { &Value::String(_) => true, _ => false }) { return Err(TagError::new(TagErrorKind::TagTypeError, None)); } + if tags.iter().any(|t| match t { + &Value::String(ref s) => !is_tag(&s), + _ => unreachable!()}) + { + return Err(TagError::new(TagErrorKind::NotATag, None)); + } Ok(tags.iter() .cloned() @@ -51,6 +58,11 @@ impl Tagable for EntryHeader { } fn set_tags(&mut self, ts: Vec) -> Result<()> { + if ts.iter().any(|tag| !is_tag(tag)) { + debug!("Not a tag: '{}'", ts.iter().filter(|t| !is_tag(t)).next().unwrap()); + return Err(TagError::new(TagErrorKind::NotATag, None)); + } + let a = ts.iter().map(|t| Value::String(t.clone())).collect(); self.set("imag.tags", Value::Array(a)) .map(|_| ()) @@ -58,6 +70,11 @@ impl Tagable for EntryHeader { } fn add_tag(&mut self, t: Tag) -> Result<()> { + if !is_tag(&t) { + debug!("Not a tag: '{}'", t); + return Err(TagError::new(TagErrorKind::NotATag, None)); + } + self.get_tags() .map(|mut tags| { tags.push(t); @@ -67,6 +84,11 @@ impl Tagable for EntryHeader { } fn remove_tag(&mut self, t: Tag) -> Result<()> { + if !is_tag(&t) { + debug!("Not a tag: '{}'", t); + return Err(TagError::new(TagErrorKind::NotATag, None)); + } + self.get_tags() .map(|mut tags| { tags.retain(|tag| tag.clone() != t); From 3d54431acf13cffe954a33c0d98c3e2a655ce2cb Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Tue, 23 Feb 2016 11:02:59 +0100 Subject: [PATCH 19/19] Add UI helpers for tagging --- libimagtag/Cargo.toml | 1 + libimagtag/src/lib.rs | 3 ++ libimagtag/src/ui.rs | 70 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 74 insertions(+) create mode 100644 libimagtag/src/ui.rs diff --git a/libimagtag/Cargo.toml b/libimagtag/Cargo.toml index 001efb43..0fd71402 100644 --- a/libimagtag/Cargo.toml +++ b/libimagtag/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" authors = ["Matthias Beyer "] [dependencies] +clap = "2.1.1" log = "0.3.5" regex = "0.1.47" toml = "0.1.25" diff --git a/libimagtag/src/lib.rs b/libimagtag/src/lib.rs index 2db44143..f4d1c543 100644 --- a/libimagtag/src/lib.rs +++ b/libimagtag/src/lib.rs @@ -1,3 +1,4 @@ +extern crate clap; #[macro_use] extern crate log; extern crate regex; extern crate toml; @@ -9,3 +10,5 @@ pub mod result; pub mod tag; pub mod tagable; pub mod util; +pub mod ui; + diff --git a/libimagtag/src/ui.rs b/libimagtag/src/ui.rs new file mode 100644 index 00000000..e889e224 --- /dev/null +++ b/libimagtag/src/ui.rs @@ -0,0 +1,70 @@ +use clap::{Arg, ArgMatches, App, SubCommand}; + +use tag::Tag; + +/// Generates a clap::SubCommand to be integrated in the commandline-ui builder for building a +/// "tags --add foo --remove bar" subcommand to do tagging action. +pub fn tag_subcommand<'a, 'b>() -> App<'a, 'b> { + SubCommand::with_name("tags") + .author("Matthias Beyer ") + .version("0.1") + .about("Add or remove tags") + + .arg(Arg::with_name("add-tags") + .short("a") + .long("add") + .takes_value(true) + .multiple(true) + .help("Add tags, seperated by comma or by specifying multiple times")) + + .arg(Arg::with_name("remove-tags") + .short("r") + .long("remove") + .takes_value(true) + .multiple(true) + .help("Remove tags, seperated by comma or by specifying multiple times")) +} + +/// Generates a clap::Arg which can be integrated into the commandline-ui builder for building a +/// "-t" or "--tags" argument which takes values for tagging actions (add, remove) +pub fn tag_argument<'a, 'b>() -> Arg<'a, 'b> { + Arg::with_name("specify-tags") + .short("t") + .long("tags") + .takes_value(true) + .multiple(true) + .help("Add or remove tags, prefixed by '+' (for adding) or '-' (for removing)") +} + +/// Get the tags which should be added from the commandline +/// +/// Returns none if the argument was not specified +pub fn get_add_tags(matches: &ArgMatches) -> Option> { + extract_tags(matches, "add-tags", '+') +} + +/// Get the tags which should be removed from the commandline +/// +/// Returns none if the argument was not specified +pub fn get_remove_tags(matches: &ArgMatches) -> Option> { + extract_tags(matches, "remove-tags", '-') +} + +fn extract_tags(matches: &ArgMatches, specifier: &str, specchar: char) -> Option> { + if let Some(submatch) = matches.subcommand_matches("tags") { + submatch.values_of(specifier) + .map(|values| values.map(String::from).collect()) + } else { + matches.values_of("specify-tags") + .map(|argmatches| { + argmatches + .map(String::from) + .filter(|s| s.chars().next() == Some(specchar)) + .map(|s| { + String::from(s.split_at(1).1) + }) + .collect() + }) + } +} +