From 8827f9c97812fc61cece28927f6500e67958be48 Mon Sep 17 00:00:00 2001 From: Paul Beckingham Date: Wed, 13 Jul 2011 23:53:57 -0400 Subject: [PATCH] TDB2 - Implemented CmdAdd.cpp and CmdLog.cpp using TDB2. - Implemented simple append writes in TDB2. - Modified CmdImport to accept and parse JSON. - Added more const-ness in DOM, Expression and Task, to allow TDB2::get_tasks to return a const vector ref, which is a Very Good Thing. - Corrected usage for the export command. - Implemented Task::urgency as a call to Task::urgency_c, which is a const overload to allow urgency calculations (without caching) for const Task objects. - Removed obolete code from TDB. - Added lots of diagnostic output for TDB2 - it's annoying, but will be gone soon. - Added mention in CmdHelp of the new and syntax elements. Needs more. - Added Command::filter overload which uses TDB2. Not in use yet. --- src/DOM.cpp | 8 +- src/DOM.h | 2 +- src/Expression.cpp | 2 +- src/Expression.h | 2 +- src/TDB.cpp | 50 ++--------- src/TDB2.cpp | 175 ++++++++++++++++++++++++++++++++----- src/TDB2.h | 10 +-- src/Task.cpp | 118 +++++++++++++------------ src/Task.h | 25 +++--- src/commands/CmdAdd.cpp | 15 +--- src/commands/CmdHelp.cpp | 9 ++ src/commands/CmdImport.cpp | 83 +++++++++++++++++- src/commands/CmdImport.h | 9 ++ src/commands/CmdLog.cpp | 13 +-- src/commands/Command.cpp | 42 +++++++++ src/commands/Command.h | 2 + src/en-US.h | 2 +- test/att.t.cpp | 6 +- 18 files changed, 400 insertions(+), 173 deletions(-) diff --git a/src/DOM.cpp b/src/DOM.cpp index 1b603ddf7..82333586e 100644 --- a/src/DOM.cpp +++ b/src/DOM.cpp @@ -203,7 +203,7 @@ const std::string DOM::get (const std::string& name) // recur // depends // -const std::string DOM::get (const std::string& name, Task& task) +const std::string DOM::get (const std::string& name, const Task& task) { // Cache test. /* @@ -232,7 +232,7 @@ const std::string DOM::get (const std::string& name, Task& task) n.getUntilEOS (attr); if (attr == "id") return format (task.id); - else if (attr == "urgency") return format (task.urgency (), 4, 3); + else if (attr == "urgency") return format (task.urgency_c (), 4, 3); else return task.get (attr); } } @@ -249,7 +249,7 @@ const std::string DOM::get (const std::string& name, Task& task) n.getUntilEOS (attr); if (attr == "id") return format (task.id); - else if (attr == "urgency") return format (task.urgency (), 4, 3); + else if (attr == "urgency") return format (task.urgency_c (), 4, 3); else return task.get (attr); } } @@ -258,7 +258,7 @@ const std::string DOM::get (const std::string& name, Task& task) // std::cout << "# DOM::get " << name << "\n"; if (name == "id") return format (task.id); - else if (name == "urgency") return format (task.urgency (), 4, 3); + else if (name == "urgency") return format (task.urgency_c (), 4, 3); else return task.get (name); // Delegate to the context-free version of DOM::get. diff --git a/src/DOM.h b/src/DOM.h index 5e2a19f7f..fa9fae4a1 100644 --- a/src/DOM.h +++ b/src/DOM.h @@ -39,7 +39,7 @@ public: ~DOM (); const std::string get (const std::string&); - const std::string get (const std::string&, Task&); + const std::string get (const std::string&, const Task&); void set (const std::string&, const std::string&); private: diff --git a/src/Expression.cpp b/src/Expression.cpp index 8c820b41b..e6b7aedff 100644 --- a/src/Expression.cpp +++ b/src/Expression.cpp @@ -66,7 +66,7 @@ Expression::~Expression () } //////////////////////////////////////////////////////////////////////////////// -bool Expression::eval (Task& task) +bool Expression::eval (const Task& task) { // If there are no elements in the filter, then all tasks pass. if (_args.size () == 0) diff --git a/src/Expression.h b/src/Expression.h index 56ebd075f..b972a15c3 100644 --- a/src/Expression.h +++ b/src/Expression.h @@ -40,7 +40,7 @@ class Expression public: Expression (Arguments&); ~Expression (); - bool eval (Task&); + bool eval (const Task&); private: void expand_sequence (); diff --git a/src/TDB.cpp b/src/TDB.cpp index 9c2ea298a..6812c77b1 100644 --- a/src/TDB.cpp +++ b/src/TDB.cpp @@ -317,41 +317,16 @@ int TDB::loadPending (std::vector & tasks) } // Now filter and return. -/* - if (filter.size ()) - { - foreach (task, mPending) - if (filter.pass (*task)) - tasks.push_back (*task); - } - else -*/ - { - foreach (task, mPending) - tasks.push_back (*task); - } + foreach (task, mPending) + tasks.push_back (*task); // Hand back any accumulated additions, if TDB::loadPending is being called // repeatedly. int fakeId = mId; -/* - if (filter.size ()) + foreach (task, mNew) { - foreach (task, mNew) - { - task->id = fakeId++; - if (filter.pass (*task)) - tasks.push_back (*task); - } - } - else -*/ - { - foreach (task, mNew) - { - task->id = fakeId++; - tasks.push_back (*task); - } + task->id = fakeId++; + tasks.push_back (*task); } } @@ -406,19 +381,8 @@ int TDB::loadCompleted (std::vector & tasks) } // Now filter and return. -/* - if (filter.size ()) - { - foreach (task, mCompleted) - if (filter.pass (*task)) - tasks.push_back (*task); - } - else -*/ - { - foreach (task, mCompleted) - tasks.push_back (*task); - } + foreach (task, mCompleted) + tasks.push_back (*task); } catch (std::string& e) diff --git a/src/TDB2.cpp b/src/TDB2.cpp index 0d42e1a0f..efd1ab0d9 100644 --- a/src/TDB2.cpp +++ b/src/TDB2.cpp @@ -25,6 +25,7 @@ // //////////////////////////////////////////////////////////////////////////////// +#include // TODO Remove. #include #include #include @@ -52,29 +53,37 @@ void TF2::target (const std::string& f) { _file = File (f); _read_only = ! _file.writable (); + + std::cout << "# TF2::target " << f << "\n"; } //////////////////////////////////////////////////////////////////////////////// const std::vector & TF2::get_tasks () { + std::cout << "# TF2::get_tasks\n"; + if (! _loaded_tasks) load_tasks (); - return _tasks /*+ _added_tasks*/; + return _tasks; } //////////////////////////////////////////////////////////////////////////////// const std::vector & TF2::get_lines () { + std::cout << "# TF2::get_lines\n"; + if (! _loaded_lines) load_lines (); - return _lines /*+ _added_lines*/; + return _lines; } //////////////////////////////////////////////////////////////////////////////// const std::string& TF2::get_contents () { + std::cout << "# TF2::get_contents\n"; + if (! _loaded_contents) load_contents (); @@ -84,13 +93,29 @@ const std::string& TF2::get_contents () //////////////////////////////////////////////////////////////////////////////// void TF2::add_task (const Task& task) { - _added_tasks.push_back (task); + std::cout << "# TF2::add_task\n"; + + _tasks.push_back (task); // For subsequent queries + _added_tasks.push_back (task); // For commit/synch _dirty = true; } //////////////////////////////////////////////////////////////////////////////// void TF2::modify_task (const Task& task) { + std::cout << "# TF2::modify_task\n"; + + // Modify in-place. + std::vector ::iterator i; + for (i = _tasks.begin (); i != _tasks.end (); ++i) + { + if (i->get ("uuid") == task.get ("uuid")) + { + *i = task; + break; + } + } + _modified_tasks.push_back (task); _dirty = true; } @@ -98,6 +123,8 @@ void TF2::modify_task (const Task& task) //////////////////////////////////////////////////////////////////////////////// void TF2::add_line (const std::string& line) { + std::cout << "# TF2::add_line\n"; + _added_lines.push_back (line); _dirty = true; } @@ -106,6 +133,7 @@ void TF2::add_line (const std::string& line) // This is so that synch.key can just overwrite and not grow. void TF2::clear_lines () { + std::cout << "# TF2::clear_lines\n"; _lines.clear (); _dirty = true; } @@ -114,6 +142,57 @@ void TF2::clear_lines () // Top-down recomposition. void TF2::commit () { + std::cout << "# TF2::commit " << _file.data << "\n"; + + // The _dirty flag indicates that the file needs to be written. + if (_dirty) + { + // Special case: added but no modified means just append to the file. + if (!_modified_tasks.size () && + (_added_tasks.size () || _added_lines.size ())) + { + if (_file.open ()) + { + if (context.config.getBoolean ("locking")) + _file.lock (); + + // Write out all the added tasks. + std::vector ::iterator task; + for (task = _added_tasks.begin (); + task != _added_tasks.end (); + ++task) + { + _file.append (task->composeF4 ()); + } + + _added_tasks.clear (); + + // Write out all the added lines. + std::vector ::iterator line; + for (line = _added_lines.begin (); + line != _added_lines.end (); + ++line) + { + _file.append (*line); + } + + _added_lines.clear (); + _file.close (); + } + } + else + { + // TODO _file.truncate (); + // TODO only write out _tasks, because any deltas have already been applied. + // TODO append _added_lines. + } + + _dirty = false; + } + + + // --------------------------- old implementation ------------------------- +/* // Load the lowest form, to allow if (_dirty) { @@ -154,24 +233,49 @@ void TF2::commit () _dirty = false; } +*/ } //////////////////////////////////////////////////////////////////////////////// void TF2::load_tasks () { + std::cout << "# TF2::load_tasks\n"; + if (! _loaded_lines) load_lines (); - std::vector ::iterator i; - for (i = _lines.begin (); i != _lines.end (); ++i) - _tasks.push_back (Task (*i)); + int line_number = 0; + try + { + std::vector ::iterator i; + for (i = _lines.begin (); i != _lines.end (); ++i) + { + ++line_number; + Task task (*i); +// TODO Find a way to number pending tasks, but not others. +// task.id = _id++; + _tasks.push_back (task); + } - _loaded_tasks = true; + _loaded_tasks = true; + } + + catch (std::string& e) + { +/* + std::stringstream s; + s << " in " << _file.data << " at line " << line_number; + throw e + s.str (); +*/ + throw e + format (" in {1} at line {2}", _file.data, line_number); + } } //////////////////////////////////////////////////////////////////////////////// void TF2::load_lines () { + std::cout << "# TF2::load_lines\n"; + if (! _loaded_contents) load_contents (); @@ -182,16 +286,17 @@ void TF2::load_lines () //////////////////////////////////////////////////////////////////////////////// void TF2::load_contents () { + std::cout << "# TF2::load_contents\n"; + _contents = ""; if (_file.open ()) { - if (_file.lock ()) - { - _file.read (_contents); - _loaded_contents = true; - } - // TODO Error handling? + if (context.config.getBoolean ("locking")) + _file.lock (); + + _file.read (_contents); + _loaded_contents = true; } // TODO Error handling? } @@ -209,7 +314,9 @@ void TF2::load_contents () //////////////////////////////////////////////////////////////////////////////// TDB2::TDB2 () : _location ("") +, _id (1) { + std::cout << "# TDB2::TDB2\n"; } //////////////////////////////////////////////////////////////////////////////// @@ -217,6 +324,7 @@ TDB2::TDB2 () // already called, if data is to be preserved. TDB2::~TDB2 () { + std::cout << "# TDB2::~TDB2\n"; } //////////////////////////////////////////////////////////////////////////////// @@ -224,6 +332,7 @@ TDB2::~TDB2 () // read. void TDB2::set_location (const std::string& location) { + std::cout << "# TDB2::set_location " << location << "\n"; _location = location; pending.target (location + "/pending.data"); @@ -234,35 +343,53 @@ void TDB2::set_location (const std::string& location) } //////////////////////////////////////////////////////////////////////////////// +// Add the new task to the appropriate file. void TDB2::add (const Task& task) { - // Use the raw string form for speed. + std::cout << "# TDB2::add\n"; + std::string status = task.get ("status"); - if (status == "completed" || status == "deleted") + if (status == "completed" || + status == "deleted") completed.add_task (task); else pending.add_task (task); + + backlog.add_task (task); } //////////////////////////////////////////////////////////////////////////////// void TDB2::modify (const Task& task) { - // TODO Handle pending vs completed/deleted + std::cout << "# TDB2::modify\n"; + + std::string status = task.get ("status"); + if (status == "completed" || + status == "deleted") + completed.modify_task (task); + else + pending.modify_task (task); + + backlog.modify_task (task); } //////////////////////////////////////////////////////////////////////////////// void TDB2::commit () { + dump (); + std::cout << "# TDB2::commit\n"; pending.commit (); completed.commit (); undo.commit (); backlog.commit (); synch_key.commit (); + dump (); } //////////////////////////////////////////////////////////////////////////////// int TDB2::gc () { + std::cout << "# TDB2::gc\n"; /* pending.load_tasks completed.load_tasks @@ -283,6 +410,12 @@ int TDB2::gc () return 0; } +//////////////////////////////////////////////////////////////////////////////// +int TDB2::next_id () +{ + return _id++; +} + //////////////////////////////////////////////////////////////////////////////// // // File RW State Tasks + - ~ lines + - Bytes @@ -304,7 +437,6 @@ void TDB2::dump () view.add (Column::factory ("string.right", "State")); view.add (Column::factory ("string.right", "Tasks")); view.add (Column::factory ("string.right", "+")); - view.add (Column::factory ("string.right", "-")); view.add (Column::factory ("string.right", "~")); view.add (Column::factory ("string.right", "Lines")); view.add (Column::factory ("string.right", "+")); @@ -329,11 +461,10 @@ void TDB2::dump_file (ViewText& view, const std::string& label, TF2& tf) view.set (row, 2, tf._dirty ? "dirty" : "clean"); view.set (row, 3, tf._loaded_tasks ? (format ((int)tf._tasks.size ())) : "-"); view.set (row, 4, (int)tf._added_tasks.size ()); - view.set (row, 5, (int)tf._removed_tasks.size ()); - view.set (row, 6, (int)tf._modified_tasks.size ()); - view.set (row, 7, tf._loaded_lines ? (format ((int)tf._lines.size ())) : "-"); - view.set (row, 8, (int)tf._added_lines.size ()); - view.set (row, 9, tf._loaded_contents ? (format ((int)tf._contents.size ())) : "-"); + view.set (row, 5, (int)tf._modified_tasks.size ()); + view.set (row, 6, tf._loaded_lines ? (format ((int)tf._lines.size ())) : "-"); + view.set (row, 7, (int)tf._added_lines.size ()); + view.set (row, 8, tf._loaded_contents ? (format ((int)tf._contents.size ())) : "-"); } //////////////////////////////////////////////////////////////////////////////// diff --git a/src/TDB2.h b/src/TDB2.h index edb5c89bb..332e16501 100644 --- a/src/TDB2.h +++ b/src/TDB2.h @@ -45,9 +45,9 @@ public: void target (const std::string&); - const std::vector & get_tasks (); + const std::vector & get_tasks (); const std::vector & get_lines (); - const std::string& get_contents (); + const std::string& get_contents (); void add_task (const Task&); void modify_task (const Task&); @@ -55,7 +55,6 @@ public: void clear_lines (); void commit (); -public: void load_tasks (); void load_lines (); void load_contents (); @@ -68,7 +67,6 @@ public: bool _loaded_contents; std::vector _tasks; std::vector _added_tasks; - std::vector _removed_tasks; std::vector _modified_tasks; std::vector _lines; std::vector _added_lines; @@ -87,7 +85,8 @@ public: void add (const Task&); void modify (const Task&); void commit (); - int gc (); + int gc (); + int next_id (); void dump (); void dump_file (ViewText&, const std::string&, TF2&); @@ -101,6 +100,7 @@ public: private: std::string _location; + int _id; }; diff --git a/src/Task.cpp b/src/Task.cpp index 9ef0aa969..4dd3c8ee3 100644 --- a/src/Task.cpp +++ b/src/Task.cpp @@ -697,7 +697,7 @@ void Task::getDependencies (std::vector & all) const } //////////////////////////////////////////////////////////////////////////////// -int Task::getTagCount () +int Task::getTagCount () const { std::vector tags; split (tags, get ("tags"), ','); @@ -706,7 +706,7 @@ int Task::getTagCount () } //////////////////////////////////////////////////////////////////////////////// -bool Task::hasTag (const std::string& tag) +bool Task::hasTag (const std::string& tag) const { std::vector tags; split (tags, get ("tags"), ','); @@ -1042,53 +1042,61 @@ int Task::determineVersion (const std::string& line) // // See rfc31-urgency.txt for full details. // +float Task::urgency_c () const +{ + float value = 0.0; + value += urgency_priority () * context.config.getReal ("urgency.priority.coefficient"); + value += urgency_project () * context.config.getReal ("urgency.project.coefficient"); + value += urgency_active () * context.config.getReal ("urgency.active.coefficient"); + value += urgency_waiting () * context.config.getReal ("urgency.waiting.coefficient"); + value += urgency_blocked () * context.config.getReal ("urgency.blocked.coefficient"); + value += urgency_annotations () * context.config.getReal ("urgency.annotations.coefficient"); + value += urgency_tags () * context.config.getReal ("urgency.tags.coefficient"); + value += urgency_next () * context.config.getReal ("urgency.next.coefficient"); + value += urgency_due () * context.config.getReal ("urgency.due.coefficient"); + value += urgency_blocking () * context.config.getReal ("urgency.blocking.coefficient"); + + // Tag- and project-specific coefficients. + std::vector all; + context.config.all (all); + + std::vector ::iterator var; + for (var = all.begin (); var != all.end (); ++var) + { + if (var->substr (0, 13) == "urgency.user.") + { + // urgency.user.project..coefficient + std::string::size_type end = std::string::npos; + if (var->substr (13, 8) == "project." && + (end = var->find (".coefficient")) != std::string::npos) + { + std::string project = var->substr (21, end - 21); + + if (get ("project").find (project) == 0) + value += context.config.getReal (*var); + } + + // urgency.user.tag..coefficient + if (var->substr (13, 4) == "tag." && + (end = var->find (".coefficient")) != std::string::npos) + { + std::string tag = var->substr (17, end - 17); + + if (hasTag (tag)) + value += context.config.getReal (*var); + } + } + } + + return value; +} + +//////////////////////////////////////////////////////////////////////////////// float Task::urgency () { if (recalc_urgency) { - urgency_value = 0.0; - urgency_value += urgency_priority () * context.config.getReal ("urgency.priority.coefficient"); - urgency_value += urgency_project () * context.config.getReal ("urgency.project.coefficient"); - urgency_value += urgency_active () * context.config.getReal ("urgency.active.coefficient"); - urgency_value += urgency_waiting () * context.config.getReal ("urgency.waiting.coefficient"); - urgency_value += urgency_blocked () * context.config.getReal ("urgency.blocked.coefficient"); - urgency_value += urgency_annotations () * context.config.getReal ("urgency.annotations.coefficient"); - urgency_value += urgency_tags () * context.config.getReal ("urgency.tags.coefficient"); - urgency_value += urgency_next () * context.config.getReal ("urgency.next.coefficient"); - urgency_value += urgency_due () * context.config.getReal ("urgency.due.coefficient"); - urgency_value += urgency_blocking () * context.config.getReal ("urgency.blocking.coefficient"); - - // Tag- and project-specific coefficients. - std::vector all; - context.config.all (all); - - std::vector ::iterator var; - for (var = all.begin (); var != all.end (); ++var) - { - if (var->substr (0, 13) == "urgency.user.") - { - // urgency.user.project..coefficient - std::string::size_type end = std::string::npos; - if (var->substr (13, 8) == "project." && - (end = var->find (".coefficient")) != std::string::npos) - { - std::string project = var->substr (21, end - 21); - - if (get ("project").find (project) == 0) - urgency_value += context.config.getReal (*var); - } - - // urgency.user.tag..coefficient - if (var->substr (13, 4) == "tag." && - (end = var->find (".coefficient")) != std::string::npos) - { - std::string tag = var->substr (17, end - 17); - - if (hasTag (tag)) - urgency_value += context.config.getReal (*var); - } - } - } + urgency_value = urgency_c (); // Return the sum of all terms. recalc_urgency = false; @@ -1098,7 +1106,7 @@ float Task::urgency () } //////////////////////////////////////////////////////////////////////////////// -float Task::urgency_priority () +float Task::urgency_priority () const { std::string value = get ("priority"); @@ -1110,7 +1118,7 @@ float Task::urgency_priority () } //////////////////////////////////////////////////////////////////////////////// -float Task::urgency_project () +float Task::urgency_project () const { if (has ("project")) return 1.0; @@ -1119,7 +1127,7 @@ float Task::urgency_project () } //////////////////////////////////////////////////////////////////////////////// -float Task::urgency_active () +float Task::urgency_active () const { if (has ("start")) return 1.0; @@ -1128,7 +1136,7 @@ float Task::urgency_active () } //////////////////////////////////////////////////////////////////////////////// -float Task::urgency_waiting () +float Task::urgency_waiting () const { if (get ("status") == "pending") return 1.0; @@ -1137,7 +1145,7 @@ float Task::urgency_waiting () } //////////////////////////////////////////////////////////////////////////////// -float Task::urgency_blocked () +float Task::urgency_blocked () const { if (has ("depends")) return 1.0; @@ -1146,7 +1154,7 @@ float Task::urgency_blocked () } //////////////////////////////////////////////////////////////////////////////// -float Task::urgency_annotations () +float Task::urgency_annotations () const { std::vector annos; getAnnotations (annos); @@ -1159,7 +1167,7 @@ float Task::urgency_annotations () } //////////////////////////////////////////////////////////////////////////////// -float Task::urgency_tags () +float Task::urgency_tags () const { switch (getTagCount ()) { @@ -1171,7 +1179,7 @@ float Task::urgency_tags () } //////////////////////////////////////////////////////////////////////////////// -float Task::urgency_next () +float Task::urgency_next () const { if (hasTag ("next")) return 1.0; @@ -1180,7 +1188,7 @@ float Task::urgency_next () } //////////////////////////////////////////////////////////////////////////////// -float Task::urgency_due () +float Task::urgency_due () const { if (has ("due")) { @@ -1216,7 +1224,7 @@ float Task::urgency_due () } //////////////////////////////////////////////////////////////////////////////// -float Task::urgency_blocking () +float Task::urgency_blocking () const { if (dependencyIsBlocking (*this)) return 1.0; diff --git a/src/Task.h b/src/Task.h index 8a69a9a57..d0ca35844 100644 --- a/src/Task.h +++ b/src/Task.h @@ -65,8 +65,8 @@ public: status getStatus () const; void setStatus (status); - int getTagCount (); - bool hasTag (const std::string&); + int getTagCount () const; + bool hasTag (const std::string&) const; void addTag (const std::string&); void addTags (const std::vector &); void getTags (std::vector&) const; @@ -87,22 +87,23 @@ public: void validate () const; + float urgency_c () const; float urgency (); private: int determineVersion (const std::string&); void legacyParse (const std::string&); - inline float urgency_priority (); - inline float urgency_project (); - inline float urgency_active (); - inline float urgency_waiting (); - inline float urgency_blocked (); - inline float urgency_annotations (); - inline float urgency_tags (); - inline float urgency_next (); - inline float urgency_due (); - inline float urgency_blocking (); + inline float urgency_priority () const; + inline float urgency_project () const; + inline float urgency_active () const; + inline float urgency_waiting () const; + inline float urgency_blocked () const; + inline float urgency_annotations () const; + inline float urgency_tags () const; + inline float urgency_next () const; + inline float urgency_due () const; + inline float urgency_blocking () const; }; #endif diff --git a/src/commands/CmdAdd.cpp b/src/commands/CmdAdd.cpp index 4c9e0fe7b..4356c0abd 100644 --- a/src/commands/CmdAdd.cpp +++ b/src/commands/CmdAdd.cpp @@ -51,12 +51,6 @@ int CmdAdd::execute (std::string& output) { int rc = 0; - // Must load pending to resolve dependencies, and to provide a new ID. - context.tdb.lock (context.config.getBoolean ("locking")); - - std::vector all; - context.tdb.loadPending (all); - // Every task needs a UUID. Task task; task.set ("uuid", uuid ()); @@ -68,17 +62,16 @@ int CmdAdd::execute (std::string& output) // Only valid tasks can be added. task.validate (); - - context.tdb.add (task); + context.tdb2.add (task); // TODO This should be a call in to feedback.cpp. +/* if (context.verbose ("new-id")) output = format (STRING_CMD_ADD_FEEDBACK, context.tdb.nextId ()) + "\n"; +*/ context.footnote (onProjectChange (task)); - - context.tdb.commit (); - context.tdb.unlock (); + context.tdb2.commit (); return rc; } diff --git a/src/commands/CmdHelp.cpp b/src/commands/CmdHelp.cpp index f4acd8053..f2ec3b120 100644 --- a/src/commands/CmdHelp.cpp +++ b/src/commands/CmdHelp.cpp @@ -125,6 +125,15 @@ int CmdHelp::execute (std::string& output) "or at http://taskwarrior.org" + "\n" + "\n" + + + "\n" + " Used to restrict the visible data.\n" + "\n" + + + "\n" + " Changes to apply to the filtered data.\n" + "\n" + + "ID is the numeric identifier displayed by the 'task list' command. " "You can specify multiple IDs for task commands, and multiple tasks " "will be affected. To specify multiple IDs make sure you use one " diff --git a/src/commands/CmdImport.cpp b/src/commands/CmdImport.cpp index 4b41157c0..8127465ac 100644 --- a/src/commands/CmdImport.cpp +++ b/src/commands/CmdImport.cpp @@ -25,9 +25,11 @@ // //////////////////////////////////////////////////////////////////////////////// +#include #include #include #include +#include #include #include #include @@ -35,6 +37,85 @@ extern Context context; +//////////////////////////////////////////////////////////////////////////////// +CmdImport::CmdImport () +{ + _keyword = "import"; + _usage = "task import [ ...]"; + _description = "Imports JSON files."; + _read_only = false; + _displays_id = false; +} + +//////////////////////////////////////////////////////////////////////////////// +int CmdImport::execute (std::string& output) +{ + int rc = 0; + + // Use the description as a file name. + Arguments words = context.args.extract_simple_words (); + if (! words.size ()) + throw std::string ("You must specify a file to import."); + + std::vector ::iterator word; + for (word = words.begin (); word != words.end (); ++word) + { + std::string file = word->_first; + std::cout << "Importing '" << file << "'\n"; + + std::string tmpfile = ""; + Uri uri (file); + uri.parse (); + + Transport* transport; + if ((transport = Transport::getTransport (uri)) != NULL) + { + std::string location (context.config.get ("data.location")); + tmpfile = location + "/import.data"; + transport->recv (tmpfile); + delete transport; + + file = tmpfile; + } + + // Load the file. + std::vector lines; + File::read (file, lines); + + std::vector ::iterator line; + for (line = lines.begin (); line != lines.end (); ++line) + { + std::string object = trimLeft ( + trimRight ( + trimRight ( + trim (*line), ","), + "]"), + "["); + + // Parse the whole thing. + json::value* root = json::parse (object); + std::cout << root->dump () + << "\n"; + +/* + // For each object element... + std::map ::iterator i; + for (i = ((std::map *)root)->begin (); + i != ((std::map *)root)->end (); + ++i) + { + Task task; + + // TODO Navigate each object. + } +*/ + } + } + + return rc; +} + +#ifdef OLD_STYLE //////////////////////////////////////////////////////////////////////////////// CmdImport::CmdImport () { @@ -1368,5 +1449,5 @@ int CmdImport::execute (std::string& output) */ return rc; } - +#endif //////////////////////////////////////////////////////////////////////////////// diff --git a/src/commands/CmdImport.h b/src/commands/CmdImport.h index 1ffc23e56..ac4e0ee21 100644 --- a/src/commands/CmdImport.h +++ b/src/commands/CmdImport.h @@ -31,6 +31,14 @@ #include #include +class CmdImport : public Command +{ +public: + CmdImport (); + int execute (std::string&); +}; + +/* class CmdImport : public Command { public: @@ -62,6 +70,7 @@ private: std::string CSV (const std::vector &); std::string YAML (const std::vector &); }; +*/ #endif //////////////////////////////////////////////////////////////////////////////// diff --git a/src/commands/CmdLog.cpp b/src/commands/CmdLog.cpp index 130cb8f87..e2c40b10e 100644 --- a/src/commands/CmdLog.cpp +++ b/src/commands/CmdLog.cpp @@ -51,12 +51,6 @@ int CmdLog::execute (std::string& output) { int rc = 0; - // Must load pending to resolve dependencies, and to provide a new ID. - context.tdb.lock (context.config.getBoolean ("locking")); - - std::vector all; - context.tdb.loadPending (all); - // Every task needs a UUID. Task task; task.set ("uuid", uuid ()); @@ -82,13 +76,10 @@ int CmdLog::execute (std::string& output) // Only valid tasks can be added. task.validate (); - - context.tdb.add (task); + context.tdb2.add (task); context.footnote (onProjectChange (task)); - - context.tdb.commit (); - context.tdb.unlock (); + context.tdb2.commit (); if (context.config.getBoolean ("echo.command")) output = std::string (STRING_CMD_LOG_LOGGED) + "\n"; diff --git a/src/commands/Command.cpp b/src/commands/Command.cpp index f6e58bfd7..d6848ac3a 100644 --- a/src/commands/Command.cpp +++ b/src/commands/Command.cpp @@ -283,6 +283,48 @@ void Command::filter (std::vector & input, std::vector & output) output = input; } +//////////////////////////////////////////////////////////////////////////////// +void Command::filter (std::vector & output) +{ + Timer timer ("Command::filter"); + + Arguments f; + if (read_only ()) + f = context.args.extract_read_only_filter (); + else + f = context.args.extract_write_filter (); + + if (f.size ()) + { + const std::vector & pending = context.tdb2.pending.get_tasks (); + const std::vector & completed = context.tdb2.completed.get_tasks (); // TODO Optional + + Expression e (f); + + output.clear (); + std::vector ::const_iterator task; + for (task = pending.begin (); task != pending.end (); ++task) + if (e.eval (*task)) + output.push_back (*task); + + for (task = completed.begin (); task != completed.end (); ++task) + if (e.eval (*task)) + output.push_back (*task); + } + else + { + const std::vector & pending = context.tdb2.pending.get_tasks (); + const std::vector & completed = context.tdb2.completed.get_tasks (); + + std::vector ::const_iterator task; + for (task = pending.begin (); task != pending.end (); ++task) + output.push_back (*task); + + for (task = completed.begin (); task != completed.end (); ++task) + output.push_back (*task); + } +} + //////////////////////////////////////////////////////////////////////////////// // Apply the modifications in arguments to the task. void Command::modify_task_description_replace (Task& task, Arguments& arguments) diff --git a/src/commands/Command.h b/src/commands/Command.h index 466999da1..f54a721b0 100644 --- a/src/commands/Command.h +++ b/src/commands/Command.h @@ -54,6 +54,8 @@ public: protected: void filter (std::vector &, std::vector &); + void filter (std::vector &); + void modify_task_description_replace (Task&, Arguments&); void modify_task_description_prepend (Task&, Arguments&); void modify_task_description_append (Task&, Arguments&); diff --git a/src/en-US.h b/src/en-US.h index 527203f96..2824c4593 100644 --- a/src/en-US.h +++ b/src/en-US.h @@ -182,7 +182,7 @@ #define STRING_CMD_IDS_USAGE_RANGE "Shows only the IDs of matching tasks, in the form of a range." #define STRING_CMD_IDS_USAGE_LIST "Shows only the IDs of matching tasks, in the form of a list." #define STRING_CMD_IDS_USAGE_ZSH "Shows the IDs and descriptions of matching tasks." -#define STRING_CMD_EXPORT_USAGE "Executes external commands and scripts" +#define STRING_CMD_EXPORT_USAGE "Exports tasks in JSON format." #define STRING_CMD_INFO_USAGE "Shows all data and metadata for specified tasks." #define STRING_CMD_INFO_BLOCKED "This task blocked by" #define STRING_CMD_INFO_BLOCKING "This task is blocking" diff --git a/test/att.t.cpp b/test/att.t.cpp index 593626f41..d92c234e8 100644 --- a/test/att.t.cpp +++ b/test/att.t.cpp @@ -84,11 +84,7 @@ int main (int argc, char** argv) a5.value ("\t\",[]:"); t.is (a5.composeF4 (), "name:\"&tab;&dquot;,&open;&close;:\"", "Att::composeF4 fully encoded \\t\",[]:"); - Att a6 ("name", 6); - t.is (a6.value_int (), 6, "Att::value_int get"); - a6.value_int (7); - t.is (a6.value_int (), 7, "Att::value_int set/get"); - t.is (a6.value (), "7", "Att::value 7"); + Att a6 ("name", 7); // Att::mod - straight comparisons. bool good = true;