From bfb19e0a64266c65d331011540fead055f2b8847 Mon Sep 17 00:00:00 2001 From: Paul Beckingham Date: Tue, 13 May 2014 16:23:50 -0400 Subject: [PATCH 01/28] Hooks - Gutted the Hooks object. - Commented out on-launch and on-exit triggers. --- src/Context.cpp | 5 +- src/Hooks.cpp | 138 +----------------------------------------------- src/Hooks.h | 32 ----------- 3 files changed, 5 insertions(+), 170 deletions(-) diff --git a/src/Context.cpp b/src/Context.cpp index 3a9f48211..7a2e21c8d 100644 --- a/src/Context.cpp +++ b/src/Context.cpp @@ -221,10 +221,12 @@ int Context::initialize (int argc, const char** argv) // Initialize the database. tdb2.set_location (data_dir); +/* // Hook system init, plus post-start event occurring at the first possible // moment after hook initialization. hooks.initialize (); hooks.trigger ("on-launch"); +*/ } catch (const std::string& message) @@ -384,8 +386,9 @@ int Context::run () std::cerr << colorizeError (*e) << "\n"; else std::cerr << *e << "\n"; - +/* hooks.trigger ("on-exit"); +*/ return rc; } diff --git a/src/Hooks.cpp b/src/Hooks.cpp index 55eda25e5..0609b826e 100644 --- a/src/Hooks.cpp +++ b/src/Hooks.cpp @@ -25,68 +25,14 @@ //////////////////////////////////////////////////////////////////////////////// #include -#include -#include #include #include -#include -#include -#include extern Context context; -//////////////////////////////////////////////////////////////////////////////// -Hook::Hook () -: _event ("") -, _file ("") -, _function ("") -{ -} - -//////////////////////////////////////////////////////////////////////////////// -Hook::Hook (const std::string& e, const std::string& f, const std::string& fn) -: _event (e) -, _file (f) -, _function (fn) -{ -} - -//////////////////////////////////////////////////////////////////////////////// -Hook::Hook (const Hook& other) -{ - _event = other._event; - _file = other._file; - _function = other._function; -} - -//////////////////////////////////////////////////////////////////////////////// -Hook& Hook::operator= (const Hook& other) -{ - if (this != &other) - { - _event = other._event; - _file = other._file; - _function = other._function; - } - - return *this; -} - //////////////////////////////////////////////////////////////////////////////// Hooks::Hooks () { - // New 2.x hooks. - _validTaskEvents.push_back ("on-task-add"); // Unimplemented - _validTaskEvents.push_back ("on-task-modify"); // Unimplemented - _validTaskEvents.push_back ("on-task-complete"); // Unimplemented - _validTaskEvents.push_back ("on-task-delete"); // Unimplemented - - _validProgramEvents.push_back ("on-launch"); - _validProgramEvents.push_back ("on-exit"); - _validProgramEvents.push_back ("on-file-read"); // Unimplemented - _validProgramEvents.push_back ("on-file-write"); // Unimplemented - _validProgramEvents.push_back ("on-synch"); // Unimplemented - _validProgramEvents.push_back ("on-gc"); // Unimplemented } //////////////////////////////////////////////////////////////////////////////// @@ -94,87 +40,5 @@ Hooks::~Hooks () { } -//////////////////////////////////////////////////////////////////////////////// -// Enumerate all hooks, and tell API about the script files it must load in -// order to call them. Note that API will perform a deferred read, which means -// that if it isn't called, a script will not be loaded. -void Hooks::initialize () -{ - // Allow a master switch to turn the whole thing off. - bool big_red_switch = context.config.getBoolean ("extensions"); - if (big_red_switch) - { - Config::const_iterator it; - for (it = context.config.begin (); it != context.config.end (); ++it) - { - std::string type; - std::string name; - std::string value; - - // "." - Nibbler n (it->first); - if (n.getUntil ('.', type) && - type == "hook" && - n.skip ('.') && - n.getUntilEOS (name)) - { - Nibbler n (it->second); - - // : [, ...] - while (!n.depleted ()) - { - std::string file; - std::string function; - if (n.getUntil (':', file) && - n.skip (':') && - n.getUntil (',', function)) - { - context.debug (std::string ("Event '") + name + "' hooked by " + file + ", function " + function); - Hook h (name, Path::expand (file), function); - _all.push_back (h); - - (void) n.skip (','); - } - else - ; // Was: throw std::string (format ("Malformed hook definition '{1}'.", it->first)); - } - } - } - } - else - context.debug ("Hooks::initialize --> off"); -} - -//////////////////////////////////////////////////////////////////////////////// -// Program hooks. -bool Hooks::trigger (const std::string& event) -{ - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -// Task hooks. -bool Hooks::trigger (const std::string& event, Task& task) -{ - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -bool Hooks::validProgramEvent (const std::string& event) -{ - if (std::find (_validProgramEvents.begin (), _validProgramEvents.end (), event) != _validProgramEvents.end ()) - return true; - - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -bool Hooks::validTaskEvent (const std::string& event) -{ - if (std::find (_validTaskEvents.begin (), _validTaskEvents.end (), event) != _validTaskEvents.end ()) - return true; - - return false; -} - +// TODO Time the hook runs. //////////////////////////////////////////////////////////////////////////////// diff --git a/src/Hooks.h b/src/Hooks.h index 02b67adec..6103fffab 100644 --- a/src/Hooks.h +++ b/src/Hooks.h @@ -27,25 +27,6 @@ #ifndef INCLUDED_HOOKS #define INCLUDED_HOOKS -#include -#include - -// Hook class representing a single hook, which is just a three-way map. -class Hook -{ -public: - Hook (); - Hook (const std::string&, const std::string&, const std::string&); - Hook (const Hook&); - Hook& operator= (const Hook&); - -public: - std::string _event; - std::string _file; - std::string _function; -}; - -// Hooks class for managing the loading and calling of hook functions. class Hooks { public: @@ -54,20 +35,7 @@ public: Hooks (const Hooks&); // Deliberately unimplemented Hooks& operator= (const Hooks&); // Deliberately unimplemented - void initialize (); - - bool trigger (const std::string&); // Program - bool trigger (const std::string&, Task&); // Task - private: - bool validProgramEvent (const std::string&); - bool validTaskEvent (const std::string&); - -private: - std::vector _all; // All current hooks. - - std::vector _validProgramEvents; - std::vector _validTaskEvents; }; #endif From 6cff8d9ff6a9c25b7874f3751de64c7c920648de Mon Sep 17 00:00:00 2001 From: Paul Beckingham Date: Tue, 13 May 2014 16:31:27 -0400 Subject: [PATCH 02/28] Hooks - Added ::initialize method. --- src/Context.cpp | 6 +----- src/Hooks.cpp | 6 ++++++ src/Hooks.h | 2 ++ 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/Context.cpp b/src/Context.cpp index 7a2e21c8d..86b24bc52 100644 --- a/src/Context.cpp +++ b/src/Context.cpp @@ -221,12 +221,8 @@ int Context::initialize (int argc, const char** argv) // Initialize the database. tdb2.set_location (data_dir); -/* - // Hook system init, plus post-start event occurring at the first possible - // moment after hook initialization. + // First opportunity to run a hook script. hooks.initialize (); - hooks.trigger ("on-launch"); -*/ } catch (const std::string& message) diff --git a/src/Hooks.cpp b/src/Hooks.cpp index 0609b826e..7bf981439 100644 --- a/src/Hooks.cpp +++ b/src/Hooks.cpp @@ -40,5 +40,11 @@ Hooks::~Hooks () { } +//////////////////////////////////////////////////////////////////////////////// +void Hooks::initialize () +{ + // TODO Scan /hooks +} + // TODO Time the hook runs. //////////////////////////////////////////////////////////////////////////////// diff --git a/src/Hooks.h b/src/Hooks.h index 6103fffab..8ce5954a9 100644 --- a/src/Hooks.h +++ b/src/Hooks.h @@ -35,6 +35,8 @@ public: Hooks (const Hooks&); // Deliberately unimplemented Hooks& operator= (const Hooks&); // Deliberately unimplemented + void initialize (); + private: }; From 39c476134f08f87424e15361a9c918a3a5823a6d Mon Sep 17 00:00:00 2001 From: Paul Beckingham Date: Tue, 13 May 2014 16:34:23 -0400 Subject: [PATCH 03/28] Hooks - Added ::onLaunch. --- src/Context.cpp | 1 + src/Hooks.cpp | 5 +++++ src/Hooks.h | 2 ++ 3 files changed, 8 insertions(+) diff --git a/src/Context.cpp b/src/Context.cpp index 86b24bc52..786a6e98e 100644 --- a/src/Context.cpp +++ b/src/Context.cpp @@ -223,6 +223,7 @@ int Context::initialize (int argc, const char** argv) // First opportunity to run a hook script. hooks.initialize (); + hooks.onLaunch (); } catch (const std::string& message) diff --git a/src/Hooks.cpp b/src/Hooks.cpp index 7bf981439..0879d614e 100644 --- a/src/Hooks.cpp +++ b/src/Hooks.cpp @@ -46,5 +46,10 @@ void Hooks::initialize () // TODO Scan /hooks } +//////////////////////////////////////////////////////////////////////////////// +void Hooks::onLaunch () +{ +} + // TODO Time the hook runs. //////////////////////////////////////////////////////////////////////////////// diff --git a/src/Hooks.h b/src/Hooks.h index 8ce5954a9..0af94d765 100644 --- a/src/Hooks.h +++ b/src/Hooks.h @@ -37,6 +37,8 @@ public: void initialize (); + void onLaunch (); + private: }; From d12c519380ecfa9a56fca9933f7a88c0d1a8b5f9 Mon Sep 17 00:00:00 2001 From: Paul Beckingham Date: Tue, 13 May 2014 16:48:26 -0400 Subject: [PATCH 04/28] Hooks - Added ::onExit. --- src/Hooks.cpp | 16 ++++++++++++++++ src/Hooks.h | 1 + 2 files changed, 17 insertions(+) diff --git a/src/Hooks.cpp b/src/Hooks.cpp index 0879d614e..dc74d586f 100644 --- a/src/Hooks.cpp +++ b/src/Hooks.cpp @@ -49,6 +49,22 @@ void Hooks::initialize () //////////////////////////////////////////////////////////////////////////////// void Hooks::onLaunch () { + context.timer_hooks.start (); + + // TODO Call all launch hook scripts. + // TODO Non-zero exit status terminates launch. + + context.timer_hooks.stop (); +} + +//////////////////////////////////////////////////////////////////////////////// +void Hooks::onExit () +{ + context.timer_hooks.start (); + + // TODO Call all exit hook scripts. + + context.timer_hooks.stop (); } // TODO Time the hook runs. diff --git a/src/Hooks.h b/src/Hooks.h index 0af94d765..28d5b6d65 100644 --- a/src/Hooks.h +++ b/src/Hooks.h @@ -38,6 +38,7 @@ public: void initialize (); void onLaunch (); + void onExit (); private: }; From 7bf2b4039edbf8663a386e84f3d54f224c54094e Mon Sep 17 00:00:00 2001 From: Paul Beckingham Date: Tue, 13 May 2014 16:49:10 -0400 Subject: [PATCH 05/28] Context - Added a hook timer. --- src/Context.cpp | 4 +++- src/Context.h | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Context.cpp b/src/Context.cpp index 786a6e98e..1f83d7169 100644 --- a/src/Context.cpp +++ b/src/Context.cpp @@ -316,13 +316,15 @@ int Context::run () << " commit:" << timer_commit.total () << " sort:" << timer_sort.total () << " render:" << timer_render.total () + << " hooks:" << timer_hooks.total () << " total:" << (timer_init.total () + timer_load.total () + timer_gc.total () + timer_filter.total () + timer_commit.total () + timer_sort.total () + - timer_render.total ()) + timer_render.total () + + timer_hooks.total ()) << "\n"; debug (s.str ()); } diff --git a/src/Context.h b/src/Context.h index 905b7f187..28af481ec 100644 --- a/src/Context.h +++ b/src/Context.h @@ -120,6 +120,7 @@ public: Timer timer_commit; Timer timer_sort; Timer timer_render; + Timer timer_hooks; }; #endif From cc112aeec7f59bb234e36af2b42206b9eeed400f Mon Sep 17 00:00:00 2001 From: Paul Beckingham Date: Tue, 13 May 2014 16:49:29 -0400 Subject: [PATCH 06/28] Context - Relocated the hooks.onExit call to a location where it can still influence output. --- src/Context.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Context.cpp b/src/Context.cpp index 1f83d7169..7285a8e8a 100644 --- a/src/Context.cpp +++ b/src/Context.cpp @@ -296,6 +296,7 @@ int Context::run () try { rc = dispatch (output); + hooks.onExit (); std::stringstream s; s << "Perf " @@ -385,9 +386,7 @@ int Context::run () std::cerr << colorizeError (*e) << "\n"; else std::cerr << *e << "\n"; -/* - hooks.trigger ("on-exit"); -*/ + return rc; } From 12a2012f20fccfdef0980500217766872c24a5d0 Mon Sep 17 00:00:00 2001 From: Paul Beckingham Date: Tue, 13 May 2014 17:12:30 -0400 Subject: [PATCH 07/28] Hooks - Scans /hooks for files on initialize. --- src/Hooks.cpp | 5 ++++- src/Hooks.h | 4 ++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/Hooks.cpp b/src/Hooks.cpp index dc74d586f..237c8250d 100644 --- a/src/Hooks.cpp +++ b/src/Hooks.cpp @@ -43,7 +43,10 @@ Hooks::~Hooks () //////////////////////////////////////////////////////////////////////////////// void Hooks::initialize () { - // TODO Scan /hooks + // Scan /hooks + Directory d (context.config.get ("data.location")); + if (d.cd ("hooks")) + _scripts = d.list (); } //////////////////////////////////////////////////////////////////////////////// diff --git a/src/Hooks.h b/src/Hooks.h index 28d5b6d65..a8c5cc764 100644 --- a/src/Hooks.h +++ b/src/Hooks.h @@ -27,6 +27,9 @@ #ifndef INCLUDED_HOOKS #define INCLUDED_HOOKS +#include +#include + class Hooks { public: @@ -41,6 +44,7 @@ public: void onExit (); private: + std::vector _scripts; }; #endif From 446fd88b8bfa4a153f6591379e507a4bcdd9e3e9 Mon Sep 17 00:00:00 2001 From: Paul Beckingham Date: Tue, 13 May 2014 17:13:07 -0400 Subject: [PATCH 08/28] Config - When creating , also creates the hook subdirectory. --- src/Config.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Config.cpp b/src/Config.cpp index 390522203..131494fe7 100644 --- a/src/Config.cpp +++ b/src/Config.cpp @@ -566,6 +566,9 @@ void Config::createDefaultData (const std::string& data) throw std::string ("Error: rc.data.location does not exist - exiting according to rc.exit.on.missing.db setting."); d.create (); + + d += "hooks"; + d.create (); } } From f1451b2670787cb9695dd4f3ad119d14c4208439 Mon Sep 17 00:00:00 2001 From: Paul Beckingham Date: Tue, 13 May 2014 18:58:15 -0400 Subject: [PATCH 09/28] Hooks - Enumerates installed hook scripts and sorts it, thus defining the execution sequence. --- src/Hooks.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/Hooks.cpp b/src/Hooks.cpp index 237c8250d..6f1d0d2b6 100644 --- a/src/Hooks.cpp +++ b/src/Hooks.cpp @@ -25,6 +25,7 @@ //////////////////////////////////////////////////////////////////////////////// #include +#include #include #include @@ -45,8 +46,13 @@ void Hooks::initialize () { // Scan /hooks Directory d (context.config.get ("data.location")); - if (d.cd ("hooks")) + d += "hooks"; + if (d.is_directory () && + d.readable ()) + { _scripts = d.list (); + std::sort (_scripts.begin (), _scripts.end ()); + } } //////////////////////////////////////////////////////////////////////////////// @@ -70,5 +76,4 @@ void Hooks::onExit () context.timer_hooks.stop (); } -// TODO Time the hook runs. //////////////////////////////////////////////////////////////////////////////// From ff52a2ab595a10b52f965693e23e9616509695ae Mon Sep 17 00:00:00 2001 From: Paul Beckingham Date: Tue, 13 May 2014 18:58:57 -0400 Subject: [PATCH 10/28] Hooks - Defined the interface for ::onLaunch and ::onExit. --- src/Hooks.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/Hooks.cpp b/src/Hooks.cpp index 6f1d0d2b6..abde14f47 100644 --- a/src/Hooks.cpp +++ b/src/Hooks.cpp @@ -56,6 +56,13 @@ void Hooks::initialize () } //////////////////////////////////////////////////////////////////////////////// +// Occurs when: On launch, after data structures are initiliazed, before +// data is loaded. +// Data fed to stdin: None +// Exit code: 0: Success, proceed +// !0: Failure, terminate +// Output handled: 0: context.footnote () +// !0: context.error () void Hooks::onLaunch () { context.timer_hooks.start (); @@ -67,6 +74,13 @@ void Hooks::onLaunch () } //////////////////////////////////////////////////////////////////////////////// +// Occurs when: On exit, after processing is complete, before output is +// displayed. +// Data fed to stdin: None +// Exit code: 0: Success +// !0: Failure +// Output handled: 0: context.footnote () +// !0: context.error () void Hooks::onExit () { context.timer_hooks.start (); From 2f5435c50fab7ba29322be18b6008dcffbfd5197 Mon Sep 17 00:00:00 2001 From: Paul Beckingham Date: Tue, 13 May 2014 21:49:56 -0400 Subject: [PATCH 11/28] Hooks - Added ::onModify. - Stubbed out functionality in all three hook methods. --- src/Hooks.cpp | 76 +++++++++++++++++++++++++++++++++++++++++++++++++-- src/Hooks.h | 1 + 2 files changed, 74 insertions(+), 3 deletions(-) diff --git a/src/Hooks.cpp b/src/Hooks.cpp index abde14f47..bf23ac8c8 100644 --- a/src/Hooks.cpp +++ b/src/Hooks.cpp @@ -67,8 +67,25 @@ void Hooks::onLaunch () { context.timer_hooks.start (); - // TODO Call all launch hook scripts. - // TODO Non-zero exit status terminates launch. + std::vector ::iterator i; + for (i = _scripts.begin (); i != _scripts.end (); ++i) + { + if (i->substr (0, 9) == "on-launch") + { + File script (*i); + if (script.executable ()) + { + // TODO Call all launch hook scripts. + + // TODO On zero status: + // - all stdout --> context.footnote + + // TODO On non-zero status: + // - all stdout --> context.error + // - throw std::string ("Hook termination"); + } + } + } context.timer_hooks.stop (); } @@ -85,7 +102,60 @@ void Hooks::onExit () { context.timer_hooks.start (); - // TODO Call all exit hook scripts. + std::vector ::iterator i; + for (i = _scripts.begin (); i != _scripts.end (); ++i) + { + if (i->substr (0, 7) == "on-exit") + { + File script (*i); + if (script.executable ()) + { + // TODO Call all exit hook scripts. + + // TODO On zero status: + // - all stdout --> context.footnote + + // TODO On non-zero status: + // - all stdout --> context.error + } + } + } + + context.timer_hooks.stop (); +} + +//////////////////////////////////////////////////////////////////////////////// +// Occurs when: A task is modified, before it is committed. +// Data fed to stdin: before JSON +// after JSON +// Exit code: 0: Success +// !0: Failure +// Output handled: 0: modified after JSON +// context.footnote () +// !0: context.error () +void Hooks::onModify (const Task& before, const Task& after) +{ + context.timer_hooks.start (); + + std::vector ::iterator i; + for (i = _scripts.begin (); i != _scripts.end (); ++i) + { + if (i->substr (0, 7) == "on-modify") + { + File script (*i); + if (script.executable ()) + { + // TODO Call all modify hook scripts. + + // TODO On zero status: + // - first line is modified JSON + // - remaining lines --> context.footnote + + // TODO On non-zero status: + // - all stdout --> context.error + } + } + } context.timer_hooks.stop (); } diff --git a/src/Hooks.h b/src/Hooks.h index a8c5cc764..f9d55948a 100644 --- a/src/Hooks.h +++ b/src/Hooks.h @@ -42,6 +42,7 @@ public: void onLaunch (); void onExit (); + void onModify (const Task&, const Task&); private: std::vector _scripts; From 631e4176c75e195bfe1a322507bbcff90bbfe10c Mon Sep 17 00:00:00 2001 From: Paul Beckingham Date: Tue, 13 May 2014 22:04:35 -0400 Subject: [PATCH 12/28] Hooks - Added ::onAdd. --- src/Hooks.cpp | 47 +++++++++++++++++++++++++++++++++++++++++------ src/Hooks.h | 3 ++- 2 files changed, 43 insertions(+), 7 deletions(-) diff --git a/src/Hooks.cpp b/src/Hooks.cpp index bf23ac8c8..87601d6ab 100644 --- a/src/Hooks.cpp +++ b/src/Hooks.cpp @@ -125,22 +125,57 @@ void Hooks::onExit () } //////////////////////////////////////////////////////////////////////////////// -// Occurs when: A task is modified, before it is committed. -// Data fed to stdin: before JSON -// after JSON +// Occurs when: A task is created, before it is committed. +// Data fed to stdin: task JSON // Exit code: 0: Success // !0: Failure -// Output handled: 0: modified after JSON +// Output handled: 0: modified JSON // context.footnote () // !0: context.error () -void Hooks::onModify (const Task& before, const Task& after) +void Hooks::onAdd (Task& after) { context.timer_hooks.start (); std::vector ::iterator i; for (i = _scripts.begin (); i != _scripts.end (); ++i) { - if (i->substr (0, 7) == "on-modify") + if (i->substr (0, 6) == "on-add") + { + File script (*i); + if (script.executable ()) + { + // TODO Call all modify hook scripts. + + // TODO On zero status: + // - first line is modified JSON + // - remaining lines --> context.footnote + + // TODO On non-zero status: + // - all stdout --> context.error + } + } + } + + context.timer_hooks.stop (); +} + +//////////////////////////////////////////////////////////////////////////////// +// Occurs when: A task is modified, before it is committed. +// Data fed to stdin: before JSON +// after JSON +// Exit code: 0: Success +// !0: Failure +// Output handled: 0: modified after JSON +// context.footnote () +// !0: context.error () +void Hooks::onModify (const Task& before, Task& after) +{ + context.timer_hooks.start (); + + std::vector ::iterator i; + for (i = _scripts.begin (); i != _scripts.end (); ++i) + { + if (i->substr (0, 9) == "on-modify") { File script (*i); if (script.executable ()) diff --git a/src/Hooks.h b/src/Hooks.h index f9d55948a..d77d1b64f 100644 --- a/src/Hooks.h +++ b/src/Hooks.h @@ -42,7 +42,8 @@ public: void onLaunch (); void onExit (); - void onModify (const Task&, const Task&); + void onAdd (Task&); + void onModify (const Task&, Task&); private: std::vector _scripts; From 68436d0d50b10e0c10c8fa875bfc9e5f81e0c212 Mon Sep 17 00:00:00 2001 From: Paul Beckingham Date: Tue, 13 May 2014 22:06:19 -0400 Subject: [PATCH 13/28] TDB2 - Integrated hooks to TF2::add_task and TF2::modify_task. --- src/TDB2.cpp | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/TDB2.cpp b/src/TDB2.cpp index 475e86568..a6428d250 100644 --- a/src/TDB2.cpp +++ b/src/TDB2.cpp @@ -134,10 +134,13 @@ bool TF2::get (const std::string& uuid, Task& task) //////////////////////////////////////////////////////////////////////////////// void TF2::add_task (const Task& task) { - _tasks.push_back (task); // For subsequent queries - _added_tasks.push_back (task); // For commit/synch + Task hookTask (task); + context.hooks.onAdd (hookTask); -/* TODO handle 'add' and 'log'. + _tasks.push_back (hookTask); // For subsequent queries + _added_tasks.push_back (hookTask); // For commit/synch + +/* TODO handle 'add' and 'log'? int id = context.tdb2.next_id (); _I2U[id] = task.get ("uuid"); _U2I[task.get ("uuid")] = id; @@ -156,9 +159,13 @@ bool TF2::modify_task (const Task& task) { if (i->get ("uuid") == uuid) { - *i = task; - _modified_tasks.push_back (task); + Task hookTask (task); + context.hooks.onModify (*i, hookTask); + + *i = hookTask; + _modified_tasks.push_back (hookTask); _dirty = true; + return true; } } From d30fb54a62310a4127537880b96e10bd086b177e Mon Sep 17 00:00:00 2001 From: Paul Beckingham Date: Wed, 14 May 2014 00:03:02 -0400 Subject: [PATCH 14/28] Hooks - Implemented ::execute to run a command, feed it input, read it's output and return the exit status. --- src/Hooks.cpp | 39 ++++++++++++++++++++++++++++++++++++++- src/Hooks.h | 3 +++ 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/src/Hooks.cpp b/src/Hooks.cpp index 87601d6ab..ca2671b10 100644 --- a/src/Hooks.cpp +++ b/src/Hooks.cpp @@ -24,10 +24,13 @@ // //////////////////////////////////////////////////////////////////////////////// +#include // TODO Remove #include #include +#include #include #include +#include extern Context context; @@ -61,7 +64,7 @@ void Hooks::initialize () // Data fed to stdin: None // Exit code: 0: Success, proceed // !0: Failure, terminate -// Output handled: 0: context.footnote () +// Output handled: 0: context.header () // !0: context.error () void Hooks::onLaunch () { @@ -196,3 +199,37 @@ void Hooks::onModify (const Task& before, Task& after) } //////////////////////////////////////////////////////////////////////////////// +int Hooks::execute ( + const std::string& command, + const std::string& input, + std::string& output) +{ + FILE* fp = popen (command.c_str (), "r+"); + if (fp) + { + // Write input to fp. + if (input != "") + { + fputs (input.c_str (), fp); + fflush (fp); + } + + // Read output from fp. + output = ""; + char* line = NULL; + size_t len = 0; + while (getline (&line, &len, fp) != -1) + { + output += line; + free (line); + line = NULL; + } + + fflush (fp); + return pclose (fp); + } + + return -1; +} + +//////////////////////////////////////////////////////////////////////////////// diff --git a/src/Hooks.h b/src/Hooks.h index d77d1b64f..6ed630f86 100644 --- a/src/Hooks.h +++ b/src/Hooks.h @@ -45,6 +45,9 @@ public: void onAdd (Task&); void onModify (const Task&, Task&); +private: + int execute (const std::string&, const std::string&, std::string&); + private: std::vector _scripts; }; From ad1dc807eab245be2f813ea533139b3862fe9cbf Mon Sep 17 00:00:00 2001 From: Paul Beckingham Date: Wed, 14 May 2014 00:03:56 -0400 Subject: [PATCH 15/28] Context - Added special integer catch handler for hook terminations. --- src/Context.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Context.cpp b/src/Context.cpp index 7285a8e8a..6cc592bea 100644 --- a/src/Context.cpp +++ b/src/Context.cpp @@ -232,6 +232,12 @@ int Context::initialize (int argc, const char** argv) rc = 2; } + catch (int) + { + // Hooks can terminate processing by throwing integers. + rc = 4; + } + catch (...) { error (STRING_UNKNOWN_ERROR); From 398bec3dbe81170c576eae136e3d6450905f5403 Mon Sep 17 00:00:00 2001 From: Paul Beckingham Date: Wed, 14 May 2014 00:04:51 -0400 Subject: [PATCH 16/28] Hooks - Implemented ::onLaunch. --- src/Hooks.cpp | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/src/Hooks.cpp b/src/Hooks.cpp index ca2671b10..8495d0a30 100644 --- a/src/Hooks.cpp +++ b/src/Hooks.cpp @@ -73,19 +73,30 @@ void Hooks::onLaunch () std::vector ::iterator i; for (i = _scripts.begin (); i != _scripts.end (); ++i) { - if (i->substr (0, 9) == "on-launch") + if (i->find ("/on-launch") != std::string::npos) { File script (*i); if (script.executable ()) { - // TODO Call all launch hook scripts. + std::string output; + int status = execute (*i, "", output); - // TODO On zero status: - // - all stdout --> context.footnote + std::vector lines; + split (lines, output, '\n'); + std::vector ::iterator line; - // TODO On non-zero status: - // - all stdout --> context.error - // - throw std::string ("Hook termination"); + if (status == 0) + { + for (line = lines.begin (); line != lines.end (); ++line) + context.header (*line); + } + else + { + for (line = lines.begin (); line != lines.end (); ++line) + context.error (*line); + + throw 0; // This is how hooks silently terminate processing. + } } } } From 8f14d83955bfe03393065ed731792a783460e0b8 Mon Sep 17 00:00:00 2001 From: Paul Beckingham Date: Wed, 14 May 2014 00:05:22 -0400 Subject: [PATCH 17/28] Hooks - Implemented ::onExit. --- src/Hooks.cpp | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/Hooks.cpp b/src/Hooks.cpp index 8495d0a30..1884e9100 100644 --- a/src/Hooks.cpp +++ b/src/Hooks.cpp @@ -119,18 +119,23 @@ void Hooks::onExit () std::vector ::iterator i; for (i = _scripts.begin (); i != _scripts.end (); ++i) { - if (i->substr (0, 7) == "on-exit") + if (i->find ("/on-exit") != std::string::npos) { File script (*i); if (script.executable ()) { - // TODO Call all exit hook scripts. + std::string output; + int status = execute (*i, "", output); - // TODO On zero status: - // - all stdout --> context.footnote + std::vector lines; + split (lines, output, '\n'); + std::vector ::iterator line; - // TODO On non-zero status: - // - all stdout --> context.error + for (line = lines.begin (); line != lines.end (); ++line) + if (status == 0) + context.footnote (*line); + else + context.error (*line); } } } From 0bb3be73daf39302835be096bd28a1f5524d59ff Mon Sep 17 00:00:00 2001 From: Paul Beckingham Date: Wed, 14 May 2014 00:05:47 -0400 Subject: [PATCH 18/28] Hooks - Implemented ::onAdd. --- src/Hooks.cpp | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/src/Hooks.cpp b/src/Hooks.cpp index 1884e9100..aadf1e355 100644 --- a/src/Hooks.cpp +++ b/src/Hooks.cpp @@ -158,19 +158,31 @@ void Hooks::onAdd (Task& after) std::vector ::iterator i; for (i = _scripts.begin (); i != _scripts.end (); ++i) { - if (i->substr (0, 6) == "on-add") + if (i->find ("/on-add") != std::string::npos) { File script (*i); if (script.executable ()) { - // TODO Call all modify hook scripts. + std::string input = after.composeJSON (); + std::string output; + int status = execute (*i, input, output); - // TODO On zero status: - // - first line is modified JSON - // - remaining lines --> context.footnote + std::vector lines; + split (lines, output, '\n'); + std::vector ::iterator line; - // TODO On non-zero status: - // - all stdout --> context.error + if (status == 0) + { + for (line = lines.begin (); line != lines.end (); ++line) + context.header (*line); + } + else + { + for (line = lines.begin (); line != lines.end (); ++line) + context.error (*line); + + throw 0; // This is how hooks silently terminate processing. + } } } } From dee6f3a7133fd10fde97d1a5ba20c8bad3aae1d6 Mon Sep 17 00:00:00 2001 From: Paul Beckingham Date: Wed, 14 May 2014 00:11:13 -0400 Subject: [PATCH 19/28] Hooks - Implemented ::onModify. --- src/Hooks.cpp | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/src/Hooks.cpp b/src/Hooks.cpp index aadf1e355..5bbb2309a 100644 --- a/src/Hooks.cpp +++ b/src/Hooks.cpp @@ -174,7 +174,7 @@ void Hooks::onAdd (Task& after) if (status == 0) { for (line = lines.begin (); line != lines.end (); ++line) - context.header (*line); + context.footnote (*line); } else { @@ -206,19 +206,35 @@ void Hooks::onModify (const Task& before, Task& after) std::vector ::iterator i; for (i = _scripts.begin (); i != _scripts.end (); ++i) { - if (i->substr (0, 9) == "on-modify") + if (i->find ("/on-modify") != std::string::npos) { File script (*i); if (script.executable ()) { - // TODO Call all modify hook scripts. + std::string afterJSON = after.composeJSON (); + std::string input = before.composeJSON () + + "\n" + + afterJSON; + std::string output; + int status = execute (*i, input, output); - // TODO On zero status: - // - first line is modified JSON - // - remaining lines --> context.footnote + std::vector lines; + split (lines, output, '\n'); + std::vector ::iterator line; - // TODO On non-zero status: - // - all stdout --> context.error + if (status == 0) + { + after = Task (afterJSON); + for (line = lines.begin (); line != lines.end (); ++line) + context.footnote (*line); + } + else + { + for (line = lines.begin (); line != lines.end (); ++line) + context.error (*line); + + throw 0; // This is how hooks silently terminate processing. + } } } } From c86853fd038c24c63ef0518cd289f860cc025ede Mon Sep 17 00:00:00 2001 From: Paul Beckingham Date: Wed, 14 May 2014 17:45:42 -0400 Subject: [PATCH 20/28] Hooks - Added helper method ::scripts to filter by event and accessibility. --- src/Hooks.cpp | 18 ++++++++++++++++++ src/Hooks.h | 1 + 2 files changed, 19 insertions(+) diff --git a/src/Hooks.cpp b/src/Hooks.cpp index 5bbb2309a..c42481543 100644 --- a/src/Hooks.cpp +++ b/src/Hooks.cpp @@ -242,6 +242,24 @@ void Hooks::onModify (const Task& before, Task& after) context.timer_hooks.stop (); } +//////////////////////////////////////////////////////////////////////////////// +std::vector Hooks::scripts (const std::string& event) +{ + std::vector matching; + std::vector ::iterator i; + for (i = _scripts.begin (); i != _scripts.end (); ++i) + { + if (i->find ("/" + event) != std::string::npos) + { + File script (*i); + if (script.executable ()) + matching.push_back (*i); + } + } + + return matching; +} + //////////////////////////////////////////////////////////////////////////////// int Hooks::execute ( const std::string& command, diff --git a/src/Hooks.h b/src/Hooks.h index 6ed630f86..d6501da84 100644 --- a/src/Hooks.h +++ b/src/Hooks.h @@ -46,6 +46,7 @@ public: void onModify (const Task&, Task&); private: + std::vector scripts (const std::string&); int execute (const std::string&, const std::string&, std::string&); private: From 8c36392fb082afe30616c133a2b1d2c2a71c7e0c Mon Sep 17 00:00:00 2001 From: Paul Beckingham Date: Wed, 14 May 2014 17:47:15 -0400 Subject: [PATCH 21/28] Hooks - Added diagnostics for debugging. --- src/Hooks.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Hooks.cpp b/src/Hooks.cpp index c42481543..db336dbf9 100644 --- a/src/Hooks.cpp +++ b/src/Hooks.cpp @@ -266,6 +266,8 @@ int Hooks::execute ( const std::string& input, std::string& output) { + context.debug ("Hooks::execute " + command); + FILE* fp = popen (command.c_str (), "r+"); if (fp) { From 3f2df5a3b6b817c1acbd1066455fb4b1fe85bf3e Mon Sep 17 00:00:00 2001 From: Paul Beckingham Date: Wed, 14 May 2014 20:10:37 -0400 Subject: [PATCH 22/28] Hooks - Added example hook scripts. --- scripts/CMakeLists.txt | 2 +- scripts/hooks/on-add | 23 +++++++++++++++++++++++ scripts/hooks/on-exit | 22 ++++++++++++++++++++++ scripts/hooks/on-launch | 22 ++++++++++++++++++++++ scripts/hooks/on-modify | 25 +++++++++++++++++++++++++ 5 files changed, 93 insertions(+), 1 deletion(-) create mode 100755 scripts/hooks/on-add create mode 100755 scripts/hooks/on-exit create mode 100755 scripts/hooks/on-launch create mode 100755 scripts/hooks/on-modify diff --git a/scripts/CMakeLists.txt b/scripts/CMakeLists.txt index 9de02dc8c..edc8e2eb5 100644 --- a/scripts/CMakeLists.txt +++ b/scripts/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required (VERSION 2.8) -install (DIRECTORY bash fish vim zsh +install (DIRECTORY bash fish vim zsh hooks DESTINATION ${TASK_DOCDIR}/scripts) install (DIRECTORY add-ons DESTINATION ${TASK_DOCDIR}/scripts diff --git a/scripts/hooks/on-add b/scripts/hooks/on-add new file mode 100755 index 000000000..3c0ce92e1 --- /dev/null +++ b/scripts/hooks/on-add @@ -0,0 +1,23 @@ +#!/bin/bash + +# Input: +# - New task JSON. +read new_task + +# Processing goes here. + +# Output: +# - Any line of JSON emitted is added as a new task. +# - Any non-JSON emitted is displayed as a message. +echo on-add + +# Exit: +# - 0 Means accept $new_task if JSON is not emitted. +# - 0 Means accept all JSON as new tasks. If UUID matches $new_task, use this +# JSON instead of $new_task. If UUID does not match $new_task, then these +# are additional tasks. +# - 0 Means all non-JSON becomes footnote entries. +# - 1 Means all non-JSON becomes error entries. +# - 1 Means reject $new_task. +exit 0 + diff --git a/scripts/hooks/on-exit b/scripts/hooks/on-exit new file mode 100755 index 000000000..7a7db78d5 --- /dev/null +++ b/scripts/hooks/on-exit @@ -0,0 +1,22 @@ +#!/bin/bash + +# Input: +# - None + +# Processing goes here. + +# Output: +# - Any line of JSON emitted is added as a new task. +# - Any non-JSON emitted is displayed as a message. +echo on-exit + +# Exit: +# - 0 Means accept $new_task if JSON is not emitted. +# - 0 Means accept all JSON as new tasks. If UUID matches $new_task, use this +# JSON instead of $new_task. If UUID does not match $new_task, then these +# are additional tasks. +# - 0 Means all non-JSON becomes footnote entries. +# - 1 Means all non-JSON becomes error entries. +# - 1 Means reject $new_task. +exit 0 + diff --git a/scripts/hooks/on-launch b/scripts/hooks/on-launch new file mode 100755 index 000000000..ed5ccf94a --- /dev/null +++ b/scripts/hooks/on-launch @@ -0,0 +1,22 @@ +#!/bin/bash + +# Input: +# - None + +# Processing goes here. + +# Output: +# - Any line of JSON emitted is added as a new task. +# - Any non-JSON emitted is displayed as a message. +echo on-launch + +# Exit: +# - 0 Means accept $new_task if JSON is not emitted. +# - 0 Means accept all JSON as new tasks. If UUID matches $new_task, use this +# JSON instead of $new_task. If UUID does not match $new_task, then these +# are additional tasks. +# - 0 Means all non-JSON becomes footnote entries. +# - 1 Means all non-JSON becomes error entries. +# - 1 Means reject $new_task. +exit 0 + diff --git a/scripts/hooks/on-modify b/scripts/hooks/on-modify new file mode 100755 index 000000000..8107f93ab --- /dev/null +++ b/scripts/hooks/on-modify @@ -0,0 +1,25 @@ +#!/bin/bash + +# Input: +# - Original task JSON +# - Modified task JSON +read original_task +read modified_task + +# Processing goes here. + +# Output: +# - Any line of JSON emitted is added as a new task. +# - Any non-JSON emitted is displayed as a message. +echo on-modify + +# Exit: +# - 0 Means accept $new_task if JSON is not emitted. +# - 0 Means accept all JSON as new tasks. If UUID matches $new_task, use this +# JSON instead of $new_task. If UUID does not match $new_task, then these +# are additional tasks. +# - 0 Means all non-JSON becomes footnote entries. +# - 1 Means all non-JSON becomes error entries. +# - 1 Means reject $new_task. +exit 0 + From 0b6e94280e0752ff953c7d7721ea583b6d3cc8bd Mon Sep 17 00:00:00 2001 From: Paul Beckingham Date: Wed, 14 May 2014 21:43:03 -0400 Subject: [PATCH 23/28] Hooks - Debug diagnostics now include exit status of hook script. --- src/Hooks.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Hooks.cpp b/src/Hooks.cpp index db336dbf9..c2e56b345 100644 --- a/src/Hooks.cpp +++ b/src/Hooks.cpp @@ -266,8 +266,7 @@ int Hooks::execute ( const std::string& input, std::string& output) { - context.debug ("Hooks::execute " + command); - + int status = -1; FILE* fp = popen (command.c_str (), "r+"); if (fp) { @@ -290,10 +289,11 @@ int Hooks::execute ( } fflush (fp); - return pclose (fp); + status = pclose (fp); + context.debug (format ("Hooks::execute {1} (status {2})", command, status)); } - return -1; + return status; } //////////////////////////////////////////////////////////////////////////////// From b1c0e67581d6ea4522b57bcb90a2130c373e5563 Mon Sep 17 00:00:00 2001 From: Paul Beckingham Date: Wed, 14 May 2014 21:44:22 -0400 Subject: [PATCH 24/28] Hooks - ::onModify now conforms to design. --- src/Hooks.cpp | 42 ++++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/src/Hooks.cpp b/src/Hooks.cpp index c2e56b345..020ae1464 100644 --- a/src/Hooks.cpp +++ b/src/Hooks.cpp @@ -70,35 +70,37 @@ void Hooks::onLaunch () { context.timer_hooks.start (); + std::vector matchingScripts = scripts ("on-launch"); std::vector ::iterator i; - for (i = _scripts.begin (); i != _scripts.end (); ++i) + for (i = matchingScripts.begin (); i != matchingScripts.end (); ++i) { - if (i->find ("/on-launch") != std::string::npos) + std::string output; + int status = execute (*i, "", output); + + std::vector lines; + split (lines, output, '\n'); + std::vector ::iterator line; + + if (status == 0) { - File script (*i); - if (script.executable ()) + for (line = lines.begin (); line != lines.end (); ++line) { - std::string output; - int status = execute (*i, "", output); - - std::vector lines; - split (lines, output, '\n'); - std::vector ::iterator line; - - if (status == 0) + if (line->length () && (*line)[0] == '{') { - for (line = lines.begin (); line != lines.end (); ++line) - context.header (*line); + Task newTask (*line); + context.tdb2.add (newTask); } else - { - for (line = lines.begin (); line != lines.end (); ++line) - context.error (*line); - - throw 0; // This is how hooks silently terminate processing. - } + context.header (*line); } } + else + { + for (line = lines.begin (); line != lines.end (); ++line) + context.error (*line); + + throw 0; // This is how hooks silently terminate processing. + } } context.timer_hooks.stop (); From 0d2bc005275dbc6cfb4d4af8ea953987f280a320 Mon Sep 17 00:00:00 2001 From: Paul Beckingham Date: Wed, 14 May 2014 22:10:40 -0400 Subject: [PATCH 25/28] Hooks - ::onExit now comforms to design. --- src/Hooks.cpp | 39 +++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/src/Hooks.cpp b/src/Hooks.cpp index 020ae1464..da14e0dfc 100644 --- a/src/Hooks.cpp +++ b/src/Hooks.cpp @@ -118,28 +118,35 @@ void Hooks::onExit () { context.timer_hooks.start (); + std::vector matchingScripts = scripts ("on-exit"); std::vector ::iterator i; - for (i = _scripts.begin (); i != _scripts.end (); ++i) + for (i = matchingScripts.begin (); i != matchingScripts.end (); ++i) { - if (i->find ("/on-exit") != std::string::npos) + std::string output; + int status = execute (*i, "", output); + + std::vector lines; + split (lines, output, '\n'); + std::vector ::iterator line; + + if (status == 0) { - File script (*i); - if (script.executable ()) + for (line = lines.begin (); line != lines.end (); ++line) { - std::string output; - int status = execute (*i, "", output); - - std::vector lines; - split (lines, output, '\n'); - std::vector ::iterator line; - - for (line = lines.begin (); line != lines.end (); ++line) - if (status == 0) - context.footnote (*line); - else - context.error (*line); + if (line->length () && (*line)[0] == '{') + { + Task newTask (*line); + context.tdb2.add (newTask); + } + else + context.footnote (*line); } } + else + { + for (line = lines.begin (); line != lines.end (); ++line) + context.error (*line); + } } context.timer_hooks.stop (); From 3010ac667bdd87613a08e8f5eb08bf63cac2b85b Mon Sep 17 00:00:00 2001 From: Paul Beckingham Date: Wed, 14 May 2014 22:39:35 -0400 Subject: [PATCH 26/28] Hooks - ::onAdd now conforms to design. --- src/Hooks.cpp | 52 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 31 insertions(+), 21 deletions(-) diff --git a/src/Hooks.cpp b/src/Hooks.cpp index da14e0dfc..293bd0999 100644 --- a/src/Hooks.cpp +++ b/src/Hooks.cpp @@ -164,36 +164,46 @@ void Hooks::onAdd (Task& after) { context.timer_hooks.start (); + std::vector matchingScripts = scripts ("on-add"); std::vector ::iterator i; - for (i = _scripts.begin (); i != _scripts.end (); ++i) + for (i = matchingScripts.begin (); i != matchingScripts.end (); ++i) { - if (i->find ("/on-add") != std::string::npos) + std::string input = after.composeJSON () + "\n"; + std::string output; + int status = execute (*i, input, output); + + std::vector lines; + split (lines, output, '\n'); + std::vector ::iterator line; + + if (status == 0) { - File script (*i); - if (script.executable ()) + bool first = true; + for (line = lines.begin (); line != lines.end (); ++line) { - std::string input = after.composeJSON (); - std::string output; - int status = execute (*i, input, output); - - std::vector lines; - split (lines, output, '\n'); - std::vector ::iterator line; - - if (status == 0) + if (line->length () && (*line)[0] == '{') { - for (line = lines.begin (); line != lines.end (); ++line) - context.footnote (*line); + Task newTask (*line); + + if (first) + { + after = newTask; + first = false; + } + else + context.tdb2.add (newTask); } else - { - for (line = lines.begin (); line != lines.end (); ++line) - context.error (*line); - - throw 0; // This is how hooks silently terminate processing. - } + context.footnote (*line); } } + else + { + for (line = lines.begin (); line != lines.end (); ++line) + context.error (*line); + + throw 0; // This is how hooks silently terminate processing. + } } context.timer_hooks.stop (); From d70c8eef5c02306aeee3809e8c92a28422175376 Mon Sep 17 00:00:00 2001 From: Paul Beckingham Date: Wed, 14 May 2014 22:39:56 -0400 Subject: [PATCH 27/28] Hooks - ::onLaunch now conforms to design. --- src/Hooks.cpp | 60 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 35 insertions(+), 25 deletions(-) diff --git a/src/Hooks.cpp b/src/Hooks.cpp index 293bd0999..bd6d8641c 100644 --- a/src/Hooks.cpp +++ b/src/Hooks.cpp @@ -222,40 +222,50 @@ void Hooks::onModify (const Task& before, Task& after) { context.timer_hooks.start (); + std::vector matchingScripts = scripts ("on-modify"); std::vector ::iterator i; - for (i = _scripts.begin (); i != _scripts.end (); ++i) + for (i = matchingScripts.begin (); i != matchingScripts.end (); ++i) { - if (i->find ("/on-modify") != std::string::npos) + std::string afterJSON = after.composeJSON (); + std::string input = before.composeJSON () + + "\n" + + afterJSON + + "\n"; + std::string output; + int status = execute (*i, input, output); + + std::vector lines; + split (lines, output, '\n'); + std::vector ::iterator line; + + if (status == 0) { - File script (*i); - if (script.executable ()) + bool first = true; + for (line = lines.begin (); line != lines.end (); ++line) { - std::string afterJSON = after.composeJSON (); - std::string input = before.composeJSON () - + "\n" - + afterJSON; - std::string output; - int status = execute (*i, input, output); - - std::vector lines; - split (lines, output, '\n'); - std::vector ::iterator line; - - if (status == 0) + if (line->length () && (*line)[0] == '{') { - after = Task (afterJSON); - for (line = lines.begin (); line != lines.end (); ++line) - context.footnote (*line); + Task newTask (*line); + + if (first) + { + after = newTask; + first = false; + } + else + context.tdb2.add (newTask); } else - { - for (line = lines.begin (); line != lines.end (); ++line) - context.error (*line); - - throw 0; // This is how hooks silently terminate processing. - } + context.footnote (*line); } } + else + { + for (line = lines.begin (); line != lines.end (); ++line) + context.error (*line); + + throw 0; // This is how hooks silently terminate processing. + } } context.timer_hooks.stop (); From 9248f1569ff34018152e7b49e6ce61269b40be86 Mon Sep 17 00:00:00 2001 From: Paul Beckingham Date: Wed, 14 May 2014 22:47:12 -0400 Subject: [PATCH 28/28] Hooks - Corrected check for trivial input. --- src/Hooks.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Hooks.cpp b/src/Hooks.cpp index bd6d8641c..c99ab6425 100644 --- a/src/Hooks.cpp +++ b/src/Hooks.cpp @@ -300,7 +300,8 @@ int Hooks::execute ( if (fp) { // Write input to fp. - if (input != "") + if (input != "" && + input != "\n") { fputs (input.c_str (), fp); fflush (fp);