diff --git a/src/Cmd.cpp b/src/Cmd.cpp index b257f3fb7..aa257927d 100644 --- a/src/Cmd.cpp +++ b/src/Cmd.cpp @@ -173,6 +173,7 @@ void Cmd::load () commands.push_back (context.stringtable.get (CMD_UNDO, "undo")); commands.push_back (context.stringtable.get (CMD_VERSION, "version")); commands.push_back (context.stringtable.get (CMD_MERGE, "merge")); + commands.push_back (context.stringtable.get (CMD_PUSH, "push")); // Now load the custom reports. std::vector all; @@ -247,12 +248,13 @@ bool Cmd::isReadOnlyCommand () command == context.stringtable.get (CMD_HELP, "help") || command == context.stringtable.get (CMD_INFO, "info") || command == context.stringtable.get (CMD_PROJECTS, "projects") || + command == context.stringtable.get (CMD_PUSH, "push") || command == context.stringtable.get (CMD_SHELL, "shell") || command == context.stringtable.get (CMD_STATS, "stats") || command == context.stringtable.get (CMD_SUMMARY, "summary") || command == context.stringtable.get (CMD_TAGS, "tags") || command == context.stringtable.get (CMD_TIMESHEET, "timesheet") || - command == context.stringtable.get (CMD_VERSION, "version") || + command == context.stringtable.get (CMD_VERSION, "version") || validCustom (command)) return true; @@ -276,7 +278,7 @@ bool Cmd::isWriteCommand () command == context.stringtable.get (CMD_LOG, "log") || command == context.stringtable.get (CMD_PREPEND, "prepend") || command == context.stringtable.get (CMD_START, "start") || - command == context.stringtable.get (CMD_STOP, "stop") || + command == context.stringtable.get (CMD_STOP, "stop") || command == context.stringtable.get (CMD_UNDO, "undo")) return true; diff --git a/src/Config.cpp b/src/Config.cpp index 6b1568df8..a779edf26 100644 --- a/src/Config.cpp +++ b/src/Config.cpp @@ -80,6 +80,7 @@ std::string Config::defaults = "recurrence.indicator=R # What to show as a task recurrence indicator\n" "recurrence.limit=1 # Number of future recurring pending tasks\n" "undo.style=side # Undo style - can be 'side', or 'diff'\n" + "merge.autopush=ask # Push database to remote origin after merge: yes, no, ask\n" "\n" "# Dates\n" "dateformat=m/d/Y # Preferred input and display date format\n" diff --git a/src/Context.cpp b/src/Context.cpp index 8aeb1073f..76d27a32b 100644 --- a/src/Context.cpp +++ b/src/Context.cpp @@ -245,6 +245,7 @@ int Context::dispatch (std::string &out) else if (cmd.command == "undo") { handleUndo ( ); } else if (cmd.command == "merge") { tdb.gc (); handleMerge (out); } + else if (cmd.command == "push") { handlePush (out); } else if (cmd.command == "_projects") { rc = handleCompletionProjects (out); } else if (cmd.command == "_tags") { rc = handleCompletionTags (out); } else if (cmd.command == "_commands") { rc = handleCompletionCommands (out); } diff --git a/src/Hooks.cpp b/src/Hooks.cpp index e2c1aa2de..95dff2e24 100644 --- a/src/Hooks.cpp +++ b/src/Hooks.cpp @@ -159,12 +159,16 @@ Hooks::Hooks () validProgramEvents.push_back ("post-import-command"); validProgramEvents.push_back ("pre-info-command"); validProgramEvents.push_back ("post-info-command"); + validProgramEvents.push_back ("pre-merge-command"); + validProgramEvents.push_back ("post-merge-command"); validProgramEvents.push_back ("pre-modify-command"); validProgramEvents.push_back ("post-modify-command"); validProgramEvents.push_back ("pre-prepend-command"); validProgramEvents.push_back ("post-prepend-command"); validProgramEvents.push_back ("pre-projects-command"); validProgramEvents.push_back ("post-projects-command"); + validProgramEvents.push_back ("pre-push-command"); + validProgramEvents.push_back ("post-push-command"); validProgramEvents.push_back ("pre-shell-command"); validProgramEvents.push_back ("post-shell-command"); validProgramEvents.push_back ("pre-start-command"); diff --git a/src/command.cpp b/src/command.cpp index 39d0ac559..98b4e3a76 100644 --- a/src/command.cpp +++ b/src/command.cpp @@ -43,6 +43,7 @@ #include "util.h" #include "main.h" #include "../auto.h" +#include "TransportSSH.h" #ifdef HAVE_LIBNCURSES #include @@ -596,19 +597,86 @@ void handleMerge (std::string& outs) if (context.hooks.trigger ("pre-merge-command")) { std::string file = trim (context.task.get ("description")); + std::string tmpfile = ""; + if (file.length () > 0) { - context.tdb.lock (context.config.getBoolean ("locking")); + Directory location (context.config.get ("data.location")); + + // add undo.data to path if necessary + if (file.find ("undo.data") == std::string::npos) + { + if (file[file.length()-1] != '/') + file += "/"; + + file += "undo.data"; + } + + Transport* transport; + if ((transport = Transport::getTransport (file)) != NULL ) + { + tmpfile = location.data + "/undo_remote.data"; + transport->recv (tmpfile); + delete transport; + + file = tmpfile; + } + + context.tdb.lock (context.config.getBoolean ("locking")); context.tdb.merge (file); context.tdb.unlock (); + + context.hooks.trigger ("post-merge-command"); - context.hooks.trigger ("post-merge-command"); + if (tmpfile != "") + { + remove (tmpfile.c_str()); + + std::string autopush = context.config.get ("merge.autopush"); + + if ( ((autopush == "ask") && (confirm ("Do you want to push the changes to the database you merged from?")) ) + || (autopush == "yes") ) + { + std::string out; + handlePush(out); + } + + } } - else + else // TODO : get default source from config file throw std::string ("You must specify a file to merge."); } } +//////////////////////////////////////////////////////////////////////////////// +void handlePush (std::string& outs) +{ + if (context.hooks.trigger ("pre-push-command")) + { + std::string file = trim (context.task.get ("description")); + + if (file.length () > 0) + { + Directory location (context.config.get ("data.location")); + + Transport* transport; + if ((transport = Transport::getTransport (file)) != NULL ) + { + transport->send (location.data + "/*.data"); + delete transport; + } + else + { + throw std::string ("Push failed"); + } + + context.hooks.trigger ("post-push-command"); + } + else // TODO : get default target from config file + throw std::string ("You must specify a target."); + } +} + //////////////////////////////////////////////////////////////////////////////// int handleVersion (std::string &outs) { diff --git a/src/i18n.h b/src/i18n.h index 259eb005f..cfad6777f 100644 --- a/src/i18n.h +++ b/src/i18n.h @@ -99,6 +99,7 @@ #define CMD_CONFIG 230 #define CMD_SHOW 231 #define CMD_MERGE 232 +#define CMD_PUSH 233 // 3xx Attributes #define ATT_PROJECT 300 diff --git a/src/main.h b/src/main.h index 4f4f184ff..2b238eccb 100644 --- a/src/main.h +++ b/src/main.h @@ -78,6 +78,7 @@ int handleDenotate (std::string &); int handleDuplicate (std::string &); void handleUndo (); void handleMerge (std::string&); +void handlePush (std::string&); #ifdef FEATURE_SHELL void handleShell (); #endif diff --git a/src/tests/merge.t b/src/tests/merge.t index beb97e566..de7de36d9 100755 --- a/src/tests/merge.t +++ b/src/tests/merge.t @@ -45,6 +45,7 @@ if (open my $fh, '>', 'local.rc') { print $fh "data.location=./local\n", "confirmation=no\n", + "merge.autopush=no\n", "report.list.description=DESC\n", "report.list.columns=id,project,active,priority,description,tags\n", "report.list.labels=id,pro,a,pri,d,t\n", @@ -58,6 +59,7 @@ if (open my $fh, '>', 'remote.rc') { print $fh "data.location=./remote\n", "confirmation=no\n", + "merge.autopush=no\n", "report.list.description=DESC\n", "report.list.columns=id,project,active,priority,description,tags\n", "report.list.labels=id,pro,a,pri,d,t\n",