Merge pull request #12 from mario-kr/impl_ui

Impl ui
This commit is contained in:
mario-kr 2016-06-30 21:02:23 +02:00 committed by GitHub
commit e702f049d0
12 changed files with 312 additions and 147 deletions

View file

@ -8,16 +8,19 @@ clap = "2.4.3"
glob = "0.2.11" glob = "0.2.11"
log = "0.3.6" log = "0.3.6"
semver = "0.2.3" semver = "0.2.3"
serde_json = "0.7.3"
task-hookrs = { git = "https://github.com/mario-kr/task-hookrs.git" }
toml = "0.1.28" toml = "0.1.28"
version = "2.0.1" version = "2.0.1"
task-hookrs = "0.1.0"
[dependencies.libimagstore]
path = "../libimagstore"
[dependencies.libimagrt] [dependencies.libimagrt]
path = "../libimagrt" path = "../libimagrt"
[dependencies.libimagstore]
path = "../libimagstore"
[dependencies.libimagtodo]
path = "../libimagtodo"
[dependencies.libimagutil] [dependencies.libimagutil]
path = "../libimagutil" path = "../libimagutil"

View file

@ -1,19 +1,28 @@
extern crate clap; extern crate clap;
extern crate glob; extern crate glob;
extern crate task_hookrs;
#[macro_use] extern crate log; #[macro_use] extern crate log;
extern crate serde_json;
extern crate semver; extern crate semver;
extern crate toml; extern crate toml;
#[macro_use] extern crate version; #[macro_use] extern crate version;
extern crate task_hookrs;
extern crate libimagrt; extern crate libimagrt;
extern crate libimagstore; extern crate libimagstore;
extern crate libimagutil; extern crate libimagutil;
extern crate libimagtodo;
use std::process::exit; use std::process::exit;
use std::process::{Command, Stdio}; use std::process::{Command, Stdio};
use std::io::stdin;
use std::io::BufRead;
use task_hookrs::import::{import_task, import_tasks};
use libimagrt::runtime::Runtime; use libimagrt::runtime::Runtime;
use libimagtodo::task::IntoTask;
use libimagutil::trace::trace_error;
mod ui; mod ui;
@ -24,7 +33,7 @@ fn main() {
let version = &version!()[..]; let version = &version!()[..];
let about = "Interface with taskwarrior"; let about = "Interface with taskwarrior";
let ui = build_ui(Runtime::get_default_cli_builder(name, version, about)); let ui = build_ui(Runtime::get_default_cli_builder(name, version, about));
let rt = { let rt = {
let rt = Runtime::new(ui); let rt = Runtime::new(ui);
if rt.is_ok() { if rt.is_ok() {
@ -36,57 +45,181 @@ fn main() {
} }
}; };
let scmd = rt.cli().subcommand_name(); let scmd = rt.cli().subcommand_name();
match scmd { match scmd {
Some("tw-hook") => { Some("tw-hook") => {
let subcmd = rt.cli().subcommand_matches("tw-hook").unwrap(); let subcmd = rt.cli().subcommand_matches("tw-hook").unwrap();
if subcmd.is_present("add") { if subcmd.is_present("add") {
println!("To be implemented"); let stdin = stdin();
// let mut stdin = stdin.lock();
// TODO @Kevin: import function aus task_hookrs benutzen, um let mut line = String::new();
// stdin auszulesen, und dann auf dem match stdin.read_line(&mut line) {
// task_hookrs::task::Task den Trait für die Ok(_) => { }
// Umwandlung aufrufen. Err(e) => {
// error!("{}", e);
return;
}
};
if let Ok(ttask) = import_task(&line.as_str()) {
let uuid = *ttask.uuid();
println!("{}", match serde_json::ser::to_string(&ttask) {
Ok(val) => val,
Err(e) => {
error!("{}", e);
return;
}
});
match ttask.into_filelockentry(rt.store()) {
Ok(val) => {
println!("Task {} stored in imag", uuid);
val
},
Err(e) => {
trace_error(&e);
error!("{}", e);
return;
}
};
}
else {
error!("No usable input");
return;
}
} }
else if subcmd.is_present("delete") { else if subcmd.is_present("delete") {
println!("To be implemented"); // The used hook is "on-modify". This hook gives two json-objects
// // per usage und wants one (the second one) back.
// Functionality to delete Entry in the store let mut counter = 0;
// let stdin = stdin();
let stdin = stdin.lock();
if let Ok(ttasks) = import_tasks(stdin) {
for ttask in ttasks {
if counter % 2 == 1 {
// Only every second task is needed, the first one is the
// task before the change, and the second one after
// the change. The (maybe modified) second one is
// expected by taskwarrior.
println!("{}", match serde_json::ser::to_string(&ttask) {
Ok(val) => val,
Err(e) => {
error!("{}", e);
return;
}
});
match ttask.status() {
&task_hookrs::status::TaskStatus::Deleted => {
match libimagtodo::delete::delete(rt.store(), *ttask.uuid()) {
Ok(_) => {
println!("Deleted task {}", *ttask.uuid());
}
Err(e) => {
trace_error(&e);
error!("{}", e);
return;
}
}
}
_ => {
}
} // end match ttask.status()
} // end if c % 2
counter += 1;
} // end for
} // end if let
else {
error!("No usable input");
}
} }
else { else {
// Should not be possible, as one argument is required via // Should not be possible, as one argument is required via
// ArgGroup // ArgGroup
panic!("Reached unreachable Code"); unreachable!();
} }
}, },
Some("exec") => { Some("exec") => {
let subcmd = rt.cli().subcommand_matches("exec").unwrap(); let subcmd = rt.cli().subcommand_matches("exec").unwrap();
let mut args = Vec::new(); let mut args = Vec::new();
if let Some(exec_string) = subcmd.values_of("command") { if let Some(exec_string) = subcmd.values_of("command") {
for e in exec_string { for e in exec_string {
args.push(e); args.push(e);
} }
let mut tw_process = Command::new("task").stdin(Stdio::null()).args(&args).spawn().unwrap_or_else(|e| { let tw_process = Command::new("task").stdin(Stdio::null()).args(&args).spawn().unwrap_or_else(|e| {
panic!("failed to execute taskwarrior: {}", e); panic!("failed to execute taskwarrior: {}", e);
}); });
let output = tw_process.wait_with_output().unwrap_or_else(|e| { let output = tw_process.wait_with_output().unwrap_or_else(|e| {
panic!("failed to unwrap output: {}", e); panic!("failed to unwrap output: {}", e);
}); });
let outstring = String::from_utf8(output.stdout).unwrap_or_else(|e| { let outstring = String::from_utf8(output.stdout).unwrap_or_else(|e| {
panic!("failed to ececute: {}", e); panic!("failed to ececute: {}", e);
}); });
println!("{}", outstring); println!("{}", outstring);
} else { } else {
panic!("faild to execute: You need to exec --command"); panic!("faild to execute: You need to exec --command");
} }
}, }
_ => panic!("Reached unreachable Code"), Some("list") => {
} let subcmd = rt.cli().subcommand_matches("list").unwrap();
let mut args = Vec::new();
} let verbose = subcmd.is_present("verbose");
let iter = match libimagtodo::read::get_todo_iterator(rt.store()) {
//let iter = match rt.store().retrieve_for_module("todo/taskwarrior") {
Err(e) => {
error!("{}", e);
return;
}
Ok(val) => val,
};
for task in iter {
match task {
Ok(val) => {
//let val = libimagtodo::task::Task::new(fle);
//println!("{:#?}", val.flentry);
let uuid = match val.flentry.get_header().read("todo.uuid") {
Ok(Some(u)) => u,
Ok(None) => continue,
Err(e) => {
error!("{}", e);
continue;
}
};
if verbose {
args.clear();
args.push(format!("uuid:{}", uuid));
args.push(format!("{}", "information"));
let tw_process = Command::new("task").stdin(Stdio::null()).args(&args).spawn()
.unwrap_or_else(|e| {
error!("{}", e);
panic!("failed");
});
let output = tw_process.wait_with_output().unwrap_or_else(|e| {
panic!("failed to unwrap output: {}", e);
});
let outstring = String::from_utf8(output.stdout).unwrap_or_else(|e| {
panic!("failed to ececute: {}", e);
});
println!("{}", outstring);
}
else {
println!("{}", match uuid {
toml::Value::String(s) => s,
_ => {
error!("Unexpected type for todo.uuid: {}", uuid);
continue;
},
});
}
}
Err(e) => {
error!("{}", e);
continue;
}
} // end match task
} // end for
}
_ => unimplemented!(),
} // end match scmd
} // end main

View file

@ -1,7 +1,7 @@
use clap::{Arg, App, ArgGroup, SubCommand}; use clap::{Arg, App, ArgGroup, SubCommand};
pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> { pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
app app
.subcommand(SubCommand::with_name("tw-hook") .subcommand(SubCommand::with_name("tw-hook")
.about("For use in a taskwarrior hook") .about("For use in a taskwarrior hook")
.version("0.1") .version("0.1")
@ -22,65 +22,78 @@ pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
.group(ArgGroup::with_name("taskwarrior hooks") .group(ArgGroup::with_name("taskwarrior hooks")
.args(&[ "add", .args(&[ "add",
"delete", "delete",
]) ])
.required(true)) .required(true))
) )
.subcommand(SubCommand::with_name("exec") .subcommand(SubCommand::with_name("exec")
.about("Send a command to taskwarrior") .about("Send a command to taskwarrior")
.version("0.1") .version("0.1")
.arg(Arg::with_name("command") .arg(Arg::with_name("command")
.long("command") .long("command")
.short("c") .short("c")
.takes_value(true) .takes_value(true)
.multiple(true) .multiple(true)
.required(true) .required(true)
.help("Args written in the string will be send directly to taskwarrior")) .help("Args written in the string will be send directly to taskwarrior")
)
)
) .subcommand(SubCommand::with_name("add")
.about("create a task")
.version("0.1")
.subcommand(SubCommand::with_name("add") .arg(Arg::with_name("description")
.about("create a task") .long("description")
.version("0.1") .short("d")
.takes_value(true)
.required(true)
.help("Name/Description of the new task")
)
.arg(Arg::with_name("description") .arg(Arg::with_name("priority")
.long("description") .long("priority")
.short("d") .short("p")
.takes_value(true) .takes_value(true)
.required(true) .required(false)
.help("Name/Description of the new task") .help("One of l, m, h for low, medium and high priority")
) )
.arg(Arg::with_name("priority") .arg(Arg::with_name("project")
.long("priority") .long("project")
.short("p") .takes_value(true)
.takes_value(true) .required(false)
.required(false) .help("Name of the project the task is related to")
.help("One of l, m, h for low, medium and high priority") )
)
.arg(Arg::with_name("project") .arg(Arg::with_name("due")
.long("project") .long("due")
.takes_value(true) .takes_value(true)
.required(false) .required(false)
.help("Name of the project the task is related to") .help("Due date of the new task")
) )
.arg(Arg::with_name("due") .arg(Arg::with_name("frequency")
.long("due") .long("frequency")
.takes_value(true) .short("f")
.required(false) .takes_value(true)
.help("Due date of the new task") .required(false)
) .help("Frequency of the recurrence of a task")
)
)
.arg(Arg::with_name("frequency") .subcommand(SubCommand::with_name("list")
.long("frequency") .about("List all tasks")
.short("f") .version("0.1")
.takes_value(true)
.required(false) .arg(Arg::with_name("verbose")
.help("Frequency of the recurrence of a task") .long("verbose")
) .short("v")
) .takes_value(false)
.required(false)
.help("Asks taskwarrior for all the details")
)
)
} }

View file

@ -5,7 +5,7 @@ authors = ["mario <mario-krehl@gmx.de>"]
[dependencies] [dependencies]
semver = "0.2" semver = "0.2"
task-hookrs = { git = "https://github.com/matthiasbeyer/task-hookrs.git" } task-hookrs = { git = "https://github.com/mario-kr/task-hookrs.git" }
uuid = "0.2.0" uuid = "0.2.0"
toml = "0.1.28" toml = "0.1.28"

View file

View file

@ -7,13 +7,13 @@ use module_path::ModuleEntryPath;
use error::{TodoError, TodoErrorKind}; use error::{TodoError, TodoErrorKind};
/// With the uuid we get the storeid and then we can delete the entry /// With the uuid we get the storeid and then we can delete the entry
pub fn deleteFunc(uuid: Uuid, store : &Store) -> Result<(),TodoError> { pub fn delete(store : &Store, uuid: Uuid) -> Result<(),TodoError> {
// With the uuid we get the storeid // With the uuid we get the storeid
let store_id = ModuleEntryPath::new(format!("taskwarrior/{}", uuid)).into_storeid(); let store_id = ModuleEntryPath::new(format!("taskwarrior/{}", uuid)).into_storeid();
// It deletes an entry // It deletes an entry
match store.delete(store_id) { match store.delete(store_id) {
Ok(val) => Ok(val), Ok(val) => Ok(val),
Err(e) => Err(TodoError::new(TodoErrorKind::StoreError, Some(Box::new(e)))), Err(e) => Err(TodoError::new(TodoErrorKind::StoreError, Some(Box::new(e)))),
} }
} }

View file

@ -1,8 +1,7 @@
use std::error::Error; use std::error::Error;
use std::clone::Clone; use std::clone::Clone;
use std::fmt::Error as FmtError; use std::fmt::Error as FmtError;
use std::fmt::{Debug, Display, Formatter}; use std::fmt::{Display, Formatter};
use std::fmt;
/// Enum of Error Types, as of now we have two: /// Enum of Error Types, as of now we have two:
/// * ConversionError: for Errors concerning conversion failures from task_hookrs::task::Task to /// * ConversionError: for Errors concerning conversion failures from task_hookrs::task::Task to

View file

@ -2,21 +2,14 @@ extern crate semver;
extern crate uuid; extern crate uuid;
extern crate toml; extern crate toml;
extern crate task_hookrs;
#[macro_use] extern crate libimagstore; #[macro_use] extern crate libimagstore;
extern crate task_hookrs;
module_entry_path_mod!("todo", "0.1.0"); module_entry_path_mod!("todo", "0.1.0");
pub mod error;
pub mod task;
pub mod delete; pub mod delete;
pub mod error;
pub mod read; pub mod read;
pub mod set; pub mod result;
pub mod add; pub mod task;
#[cfg(test)]
mod tests {
#[test]
fn it_works() {
}
}

View file

@ -1,17 +1,12 @@
use libimagstore::storeid::{StoreIdIterator, StoreId}; use libimagstore::storeid::{StoreIdIterator, StoreId};
use libimagstore::store::Store; use libimagstore::store::Store;
use error::{TodoError, TodoErrorKind}; use error::{TodoError, TodoErrorKind};
use task::Task; use task::Task;
use result::Result;
use std::result::Result as RResult; pub fn get_todo_iterator(store: &Store) -> Result<TaskIterator> {
pub type Result<T> = RResult<T, TodoError>; store.retrieve_for_module("todo/taskwarrior")
pub fn all_todos(store: &Store) -> Result<TaskIterator> {
store.retrieve_for_module("uuid")
.map(|iter| TaskIterator::new(store, iter)) .map(|iter| TaskIterator::new(store, iter))
.map_err(|e| TodoError::new(TodoErrorKind::StoreError, Some(Box::new(e)))) .map_err(|e| TodoError::new(TodoErrorKind::StoreError, Some(Box::new(e))))
} }
@ -23,10 +18,10 @@ trait FromStoreId {
impl<'a> FromStoreId for Task<'a> { impl<'a> FromStoreId for Task<'a> {
fn from_storeid<'b>(store: &'b Store, id: StoreId) -> Result<Task<'b>> { fn from_storeid<'b>(store: &'b Store, id: StoreId) -> Result<Task<'b>> {
match store.retrieve(id) { match store.retrieve(id) {
Err(e) => Err(TodoError::new(TodoErrorKind::StoreError, Some(Box::new(e)))), Err(e) => Err(TodoError::new(TodoErrorKind::StoreError, Some(Box::new(e)))),
Ok(c) => Ok(Task::new( c )), Ok(c) => Ok(Task::new( c )),
} }
} }
} }
@ -38,10 +33,10 @@ pub struct TaskIterator<'a> {
impl<'a> TaskIterator<'a> { impl<'a> TaskIterator<'a> {
pub fn new(store: &'a Store, iditer: StoreIdIterator) -> TaskIterator<'a> { pub fn new(store: &'a Store, iditer: StoreIdIterator) -> TaskIterator<'a> {
TaskIterator { TaskIterator {
store: store, store: store,
iditer: iditer, iditer: iditer,
} }
} }
} }
@ -49,8 +44,8 @@ impl<'a> Iterator for TaskIterator<'a> {
type Item = Result<Task<'a>>; type Item = Result<Task<'a>>;
fn next(&mut self) -> Option<Result<Task<'a>>> { fn next(&mut self) -> Option<Result<Task<'a>>> {
self.iditer self.iditer
.next() .next()
.map(|id| Task::from_storeid(self.store, id)) .map(|id| Task::from_storeid(self.store, id))
} }
} }

View file

@ -0,0 +1,5 @@
use error::TodoError;
use std::result::Result as RResult;
pub type Result<T> = RResult<T, TodoError>;

View file

View file

@ -1,4 +1,4 @@
use std::ops::Deref; use std::collections::BTreeMap;
use toml::Value; use toml::Value;
use task_hookrs::task::Task as TTask; use task_hookrs::task::Task as TTask;
@ -8,11 +8,12 @@ use libimagstore::storeid::IntoStoreId;
use module_path::ModuleEntryPath; use module_path::ModuleEntryPath;
use error::{TodoError, TodoErrorKind}; use error::{TodoError, TodoErrorKind};
use result::Result;
/// Task struct containing a `FileLockEntry` /// Task struct containing a `FileLockEntry`
#[derive(Debug)] #[derive(Debug)]
pub struct Task<'a> { pub struct Task<'a> {
flentry : FileLockEntry<'a>, pub flentry : FileLockEntry<'a>,
} }
impl<'a> Task<'a> { impl<'a> Task<'a> {
@ -42,20 +43,43 @@ pub trait IntoTask<'a> {
/// println!("Task with uuid: {}", task.flentry.get_header().get("todo.uuid")); /// println!("Task with uuid: {}", task.flentry.get_header().get("todo.uuid"));
/// } /// }
/// ``` /// ```
fn into_filelockentry(self, store : &'a Store) -> Result<Task<'a>, TodoError>; fn into_filelockentry(self, store : &'a Store) -> Result<Task<'a>>;
} }
impl<'a> IntoTask<'a> for TTask { impl<'a> IntoTask<'a> for TTask {
fn into_filelockentry(self, store : &'a Store) -> Result<Task<'a>, TodoError> { fn into_filelockentry(self, store : &'a Store) -> Result<Task<'a>> {
let uuid = self.uuid(); let uuid = self.uuid();
let store_id = ModuleEntryPath::new(format!("taskwarrior/{}", uuid)).into_storeid(); let store_id = ModuleEntryPath::new(format!("taskwarrior/{}", uuid)).into_storeid();
match store.retrieve(store_id) { match store.retrieve(store_id) {
Err(e) => Err(TodoError::new(TodoErrorKind::StoreError, Some(Box::new(e)))), Err(e) => {
Ok(mut fle) => { return Err(TodoError::new(TodoErrorKind::StoreError, Some(Box::new(e))))
match fle.get_header_mut().set("todo.uuid", Value::String(format!("{}", uuid))) {
Err(e) => Err(TodoError::new(TodoErrorKind::StoreError, Some(Box::new(e)))),
Ok(_) => Ok(Task { flentry : fle })
}
}, },
Ok(mut fle) => {
{
let mut header = fle.get_header_mut();
match header.read("todo") {
Ok(None) => {
match header.set("todo", Value::Table(BTreeMap::new())) {
Ok(_) => { },
Err(e) => {
return Err(TodoError::new(TodoErrorKind::StoreError, Some(Box::new(e))))
}
}
}
Ok(Some(_)) => { }
Err(e) => {
return Err(TodoError::new(TodoErrorKind::StoreError, Some(Box::new(e))))
}
}
match header.set("todo.uuid", Value::String(format!("{}",uuid))) {
Ok(_) => { },
Err(e) => {
return Err(TodoError::new(TodoErrorKind::StoreError, Some(Box::new(e))))
}
}
}
// If none of the errors above have returned the function, everything is fine
Ok(Task { flentry : fle } )
}
} }
} }
} }