mirror of
https://github.com/GothenburgBitFactory/taskwarrior.git
synced 2025-07-07 20:06:36 +02:00
Feature #282
- Applied large patch to make task return meaningful exit codes. - Added unit tests to prove this. - Thanks to Pietro Cerutti.
This commit is contained in:
parent
cc5c99c0a1
commit
62be3f8acb
11 changed files with 302 additions and 157 deletions
|
@ -2,7 +2,9 @@
|
|||
------ current release ---------------------------
|
||||
|
||||
1.8.2
|
||||
|
||||
+ Added feature #282 that returns useful exit codes to the shell. Now a
|
||||
script can detect whether no tasks were returned by a report (thanks to
|
||||
Pietro Cerutti).
|
||||
|
||||
------ old releases ------------------------------
|
||||
|
||||
|
|
1
NEWS
1
NEWS
|
@ -9,6 +9,7 @@ New Features in task 1.8
|
|||
- In addition to being a standard part of Fedora 10 and 11 (yum install task),
|
||||
task is now also a standard part of Cygwin 1.5
|
||||
- There are new demo movies on taskwarrior.org
|
||||
- Shell-friendly exit codes
|
||||
|
||||
Please refer to the ChangeLog file for full details. There are too many to
|
||||
list here.
|
||||
|
|
|
@ -126,23 +126,26 @@ void Context::initialize ()
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
int Context::run ()
|
||||
{
|
||||
int rc;
|
||||
Timer t ("Context::run");
|
||||
|
||||
std::string output;
|
||||
try
|
||||
{
|
||||
parse (); // Parse command line.
|
||||
output = dispatch (); // Dispatch to command handlers.
|
||||
parse (); // Parse command line.
|
||||
rc = dispatch (output); // Dispatch to command handlers.
|
||||
}
|
||||
|
||||
catch (const std::string& error)
|
||||
{
|
||||
footnote (error);
|
||||
rc = 2;
|
||||
}
|
||||
|
||||
catch (...)
|
||||
{
|
||||
footnote (stringtable.get (100, "Unknown error."));
|
||||
rc = 3;
|
||||
}
|
||||
|
||||
// Dump all debug messages.
|
||||
|
@ -170,63 +173,63 @@ int Context::run ()
|
|||
else
|
||||
std::cout << *f << std::endl;
|
||||
|
||||
return 0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string Context::dispatch ()
|
||||
int Context::dispatch (std::string &out)
|
||||
{
|
||||
int rc = 0;
|
||||
Timer t ("Context::dispatch");
|
||||
|
||||
// TODO Just look at this thing. It cries out for a dispatch table.
|
||||
std::string out;
|
||||
if (cmd.command == "projects") { out = handleProjects (); }
|
||||
else if (cmd.command == "tags") { out = handleTags (); }
|
||||
else if (cmd.command == "colors") { out = handleColor (); }
|
||||
else if (cmd.command == "version") { out = handleVersion (); }
|
||||
else if (cmd.command == "help") { out = longUsage (); }
|
||||
else if (cmd.command == "stats") { out = handleReportStats (); }
|
||||
else if (cmd.command == "info") { out = handleInfo (); }
|
||||
else if (cmd.command == "history") { out = handleReportHistory (); }
|
||||
else if (cmd.command == "ghistory") { out = handleReportGHistory (); }
|
||||
else if (cmd.command == "summary") { out = handleReportSummary (); }
|
||||
else if (cmd.command == "calendar") { out = handleReportCalendar (); }
|
||||
else if (cmd.command == "timesheet") { out = handleReportTimesheet (); }
|
||||
else if (cmd.command == "add") { out = handleAdd (); }
|
||||
else if (cmd.command == "append") { out = handleAppend (); }
|
||||
else if (cmd.command == "annotate") { out = handleAnnotate (); }
|
||||
else if (cmd.command == "done") { out = handleDone (); }
|
||||
else if (cmd.command == "delete") { out = handleDelete (); }
|
||||
else if (cmd.command == "start") { out = handleStart (); }
|
||||
else if (cmd.command == "stop") { out = handleStop (); }
|
||||
else if (cmd.command == "export") { out = handleExport (); }
|
||||
else if (cmd.command == "import") { out = handleImport (); }
|
||||
else if (cmd.command == "duplicate") { out = handleDuplicate (); }
|
||||
else if (cmd.command == "edit") { out = handleEdit (); }
|
||||
if (cmd.command == "projects") { rc = handleProjects (out); }
|
||||
else if (cmd.command == "tags") { rc = handleTags (out); }
|
||||
else if (cmd.command == "colors") { rc = handleColor (out); }
|
||||
else if (cmd.command == "version") { rc = handleVersion (out); }
|
||||
else if (cmd.command == "help") { rc = longUsage (out); }
|
||||
else if (cmd.command == "stats") { rc = handleReportStats (out); }
|
||||
else if (cmd.command == "info") { rc = handleInfo (out); }
|
||||
else if (cmd.command == "history") { rc = handleReportHistory (out); }
|
||||
else if (cmd.command == "ghistory") { rc = handleReportGHistory (out); }
|
||||
else if (cmd.command == "summary") { rc = handleReportSummary (out); }
|
||||
else if (cmd.command == "calendar") { rc = handleReportCalendar (out); }
|
||||
else if (cmd.command == "timesheet") { rc = handleReportTimesheet (out); }
|
||||
else if (cmd.command == "add") { rc = handleAdd (out); }
|
||||
else if (cmd.command == "append") { rc = handleAppend (out); }
|
||||
else if (cmd.command == "annotate") { rc = handleAnnotate (out); }
|
||||
else if (cmd.command == "done") { rc = handleDone (out); }
|
||||
else if (cmd.command == "delete") { rc = handleDelete (out); }
|
||||
else if (cmd.command == "start") { rc = handleStart (out); }
|
||||
else if (cmd.command == "stop") { rc = handleStop (out); }
|
||||
else if (cmd.command == "export") { rc = handleExport (out); }
|
||||
else if (cmd.command == "import") { rc = handleImport (out); }
|
||||
else if (cmd.command == "duplicate") { rc = handleDuplicate (out); }
|
||||
else if (cmd.command == "edit") { rc = handleEdit (out); }
|
||||
#ifdef FEATURE_SHELL
|
||||
else if (cmd.command == "shell") { handleShell (); }
|
||||
else if (cmd.command == "shell") { handleShell ( ); }
|
||||
#endif
|
||||
else if (cmd.command == "undo") { handleUndo (); }
|
||||
else if (cmd.command == "_projects") { out = handleCompletionProjects (); }
|
||||
else if (cmd.command == "_tags") { out = handleCompletionTags (); }
|
||||
else if (cmd.command == "_commands") { out = handleCompletionCommands (); }
|
||||
else if (cmd.command == "_ids") { out = handleCompletionIDs (); }
|
||||
else if (cmd.command == "_config") { out = handleCompletionConfig (); }
|
||||
else if (cmd.command == "undo") { handleUndo ( ); }
|
||||
else if (cmd.command == "_projects") { rc = handleCompletionProjects (out); }
|
||||
else if (cmd.command == "_tags") { rc = handleCompletionTags (out); }
|
||||
else if (cmd.command == "_commands") { rc = handleCompletionCommands (out); }
|
||||
else if (cmd.command == "_ids") { rc = handleCompletionIDs (out); }
|
||||
else if (cmd.command == "_config") { rc = handleCompletionConfig (out); }
|
||||
else if (cmd.command == "" &&
|
||||
sequence.size ()) { out = handleModify (); }
|
||||
sequence.size ()) { rc = handleModify (out); }
|
||||
|
||||
// Command that display IDs and therefore need TDB::gc first.
|
||||
else if (cmd.command == "next") { if (!inShadow) tdb.gc (); out = handleReportNext (); }
|
||||
else if (cmd.validCustom (cmd.command)) { if (!inShadow) tdb.gc (); out = handleCustomReport (cmd.command); }
|
||||
else if (cmd.command == "next") { if (!inShadow) tdb.gc (); rc = handleReportNext (out); }
|
||||
else if (cmd.validCustom (cmd.command)) { if (!inShadow) tdb.gc (); rc = handleCustomReport (cmd.command, out); }
|
||||
|
||||
// If the command is not recognized, display usage.
|
||||
else { out = shortUsage (); }
|
||||
else { rc = shortUsage (out); }
|
||||
|
||||
// Only update the shadow file if such an update was not suppressed (shadow),
|
||||
if (cmd.isWriteCommand () && !inShadow)
|
||||
shadow ();
|
||||
|
||||
return out;
|
||||
return rc;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -265,7 +268,8 @@ void Context::shadow ()
|
|||
|
||||
initialize ();
|
||||
parse ();
|
||||
std::string result = dispatch ();
|
||||
std::string result;
|
||||
(void)dispatch (result);
|
||||
std::ofstream out (shadowFile.c_str ());
|
||||
if (out.good ())
|
||||
{
|
||||
|
|
|
@ -50,7 +50,7 @@ public:
|
|||
void initialize (); // for reinitializing
|
||||
int run (); // task classic
|
||||
int interactive (); // task interactive (not implemented)
|
||||
std::string dispatch (); // command handler dispatch
|
||||
int dispatch (std::string&); // command handler dispatch
|
||||
void shadow (); // shadow file update
|
||||
|
||||
int getWidth (); // determine terminal width
|
||||
|
|
126
src/command.cpp
126
src/command.cpp
|
@ -49,7 +49,7 @@
|
|||
extern Context context;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string handleAdd ()
|
||||
int handleAdd (std::string &outs)
|
||||
{
|
||||
std::stringstream out;
|
||||
|
||||
|
@ -110,12 +110,14 @@ std::string handleAdd ()
|
|||
context.tdb.commit ();
|
||||
context.tdb.unlock ();
|
||||
|
||||
return out.str ();
|
||||
outs = out.str ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string handleProjects ()
|
||||
int handleProjects (std::string &outs)
|
||||
{
|
||||
int rc = 0;
|
||||
std::stringstream out;
|
||||
|
||||
context.filter.push_back (Att ("status", "pending"));
|
||||
|
@ -195,15 +197,18 @@ std::string handleProjects ()
|
|||
<< " (" << quantity << (quantity == 1 ? " task" : " tasks") << ")"
|
||||
<< std::endl;
|
||||
}
|
||||
else
|
||||
else {
|
||||
out << "No projects."
|
||||
<< std::endl;
|
||||
rc = 1;
|
||||
}
|
||||
|
||||
return out.str ();
|
||||
outs = out.str ();
|
||||
return rc;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string handleCompletionProjects ()
|
||||
int handleCompletionProjects (std::string &outs)
|
||||
{
|
||||
std::vector <Task> tasks;
|
||||
context.tdb.lock (context.config.get ("locking", true));
|
||||
|
@ -228,12 +233,14 @@ std::string handleCompletionProjects ()
|
|||
if (project->first.length ())
|
||||
out << project->first << std::endl;
|
||||
|
||||
return out.str ();
|
||||
outs = out.str ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string handleTags ()
|
||||
int handleTags (std::string &outs)
|
||||
{
|
||||
int rc = 0;
|
||||
std::stringstream out;
|
||||
|
||||
context.filter.push_back (Att ("status", "pending"));
|
||||
|
@ -290,15 +297,19 @@ std::string handleTags ()
|
|||
<< " (" << quantity << (quantity == 1 ? " task" : " tasks") << ")"
|
||||
<< std::endl;
|
||||
}
|
||||
else
|
||||
else {
|
||||
out << "No tags."
|
||||
<< std::endl;
|
||||
rc = 1;
|
||||
}
|
||||
|
||||
return out.str ();
|
||||
outs = out.str ();
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string handleCompletionTags ()
|
||||
int handleCompletionTags (std::string &outs)
|
||||
{
|
||||
std::vector <Task> tasks;
|
||||
context.tdb.lock (context.config.get ("locking", true));
|
||||
|
@ -328,11 +339,12 @@ std::string handleCompletionTags ()
|
|||
foreach (tag, unique)
|
||||
out << tag->first << std::endl;
|
||||
|
||||
return out.str ();
|
||||
outs = out.str ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string handleCompletionCommands ()
|
||||
int handleCompletionCommands (std::string &outs)
|
||||
{
|
||||
std::vector <std::string> commands;
|
||||
context.cmd.allCommands (commands);
|
||||
|
@ -342,11 +354,12 @@ std::string handleCompletionCommands ()
|
|||
foreach (command, commands)
|
||||
out << *command << std::endl;
|
||||
|
||||
return out.str ();
|
||||
outs = out.str ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string handleCompletionConfig ()
|
||||
int handleCompletionConfig (std::string &outs)
|
||||
{
|
||||
std::vector <std::string> configs;
|
||||
context.config.all (configs);
|
||||
|
@ -356,11 +369,12 @@ std::string handleCompletionConfig ()
|
|||
foreach (config, configs)
|
||||
out << *config << std::endl;
|
||||
|
||||
return out.str ();
|
||||
outs = out.str ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string handleCompletionIDs ()
|
||||
int handleCompletionIDs (std::string &outs)
|
||||
{
|
||||
std::vector <Task> tasks;
|
||||
context.tdb.lock (context.config.get ("locking", true));
|
||||
|
@ -381,7 +395,8 @@ std::string handleCompletionIDs ()
|
|||
foreach (id, ids)
|
||||
out << *id << std::endl;
|
||||
|
||||
return out.str ();
|
||||
outs = out.str ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -395,8 +410,9 @@ void handleUndo ()
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string handleVersion ()
|
||||
int handleVersion (std::string &outs)
|
||||
{
|
||||
int rc = 0;
|
||||
std::stringstream out;
|
||||
|
||||
// Create a table for the disclaimer.
|
||||
|
@ -524,7 +540,7 @@ std::string handleVersion ()
|
|||
if (unrecognized.size ())
|
||||
{
|
||||
out << "Your .taskrc file contains these unrecognized variables:"
|
||||
<< std::endl;
|
||||
<< std::endl;
|
||||
|
||||
foreach (i, unrecognized)
|
||||
out << " " << *i << std::endl;
|
||||
|
@ -535,9 +551,11 @@ std::string handleVersion ()
|
|||
// Verify installation. This is mentioned in the documentation as the way to
|
||||
// ensure everything is properly installed.
|
||||
|
||||
if (all.size () == 0)
|
||||
if (all.size () == 0) {
|
||||
out << "Configuration error: .taskrc contains no entries"
|
||||
<< std::endl;
|
||||
rc = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (context.config.get ("data.location") == "")
|
||||
|
@ -551,12 +569,14 @@ std::string handleVersion ()
|
|||
<< std::endl;
|
||||
}
|
||||
|
||||
return out.str ();
|
||||
outs = out.str ();
|
||||
return rc;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string handleDelete ()
|
||||
int handleDelete (std::string &outs)
|
||||
{
|
||||
int rc = 0;
|
||||
std::stringstream out;
|
||||
|
||||
context.disallowModification ();
|
||||
|
@ -645,19 +665,23 @@ std::string handleDelete ()
|
|||
<< std::endl;
|
||||
}
|
||||
}
|
||||
else
|
||||
else {
|
||||
out << "Task not deleted." << std::endl;
|
||||
rc = 1;
|
||||
}
|
||||
}
|
||||
|
||||
context.tdb.commit ();
|
||||
context.tdb.unlock ();
|
||||
|
||||
return out.str ();
|
||||
outs = out.str ();
|
||||
return rc;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string handleStart ()
|
||||
int handleStart (std::string &outs)
|
||||
{
|
||||
int rc = 0;
|
||||
std::stringstream out;
|
||||
|
||||
context.disallowModification ();
|
||||
|
@ -699,18 +723,21 @@ std::string handleStart ()
|
|||
<< task->get ("description")
|
||||
<< "' already started."
|
||||
<< std::endl;
|
||||
rc = 1;
|
||||
}
|
||||
}
|
||||
|
||||
context.tdb.commit ();
|
||||
context.tdb.unlock ();
|
||||
|
||||
return out.str ();
|
||||
outs = out.str ();
|
||||
return rc;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string handleStop ()
|
||||
int handleStop (std::string &outs)
|
||||
{
|
||||
int rc = 0;
|
||||
std::stringstream out;
|
||||
|
||||
context.disallowModification ();
|
||||
|
@ -746,18 +773,21 @@ std::string handleStop ()
|
|||
<< task->get ("description")
|
||||
<< "' not started."
|
||||
<< std::endl;
|
||||
rc = 1;
|
||||
}
|
||||
}
|
||||
|
||||
context.tdb.commit ();
|
||||
context.tdb.unlock ();
|
||||
|
||||
return out.str ();
|
||||
outs = out.str ();
|
||||
return rc;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string handleDone ()
|
||||
int handleDone (std::string &outs)
|
||||
{
|
||||
int rc = 0;
|
||||
int count = 0;
|
||||
std::stringstream out;
|
||||
|
||||
|
@ -826,6 +856,7 @@ std::string handleDone ()
|
|||
<< task->get ("description")
|
||||
<< "' is not pending"
|
||||
<< std::endl;
|
||||
rc = 1;
|
||||
}
|
||||
|
||||
context.tdb.commit ();
|
||||
|
@ -839,11 +870,12 @@ std::string handleDone ()
|
|||
<< " as done"
|
||||
<< std::endl;
|
||||
|
||||
return out.str ();
|
||||
outs = out.str ();
|
||||
return rc;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string handleExport ()
|
||||
int handleExport (std::string &outs)
|
||||
{
|
||||
std::stringstream out;
|
||||
|
||||
|
@ -882,11 +914,12 @@ std::string handleExport ()
|
|||
}
|
||||
}
|
||||
|
||||
return out.str ();
|
||||
outs = out.str ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string handleModify ()
|
||||
int handleModify (std::string &outs)
|
||||
{
|
||||
int count = 0;
|
||||
std::stringstream out;
|
||||
|
@ -959,11 +992,12 @@ std::string handleModify ()
|
|||
if (context.config.get ("echo.command", true))
|
||||
out << "Modified " << count << " task" << (count == 1 ? "" : "s") << std::endl;
|
||||
|
||||
return out.str ();
|
||||
outs = out.str ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string handleAppend ()
|
||||
int handleAppend (std::string &outs)
|
||||
{
|
||||
int count = 0;
|
||||
std::stringstream out;
|
||||
|
@ -1026,11 +1060,12 @@ std::string handleAppend ()
|
|||
if (context.config.get ("echo.command", true))
|
||||
out << "Appended " << count << " task" << (count == 1 ? "" : "s") << std::endl;
|
||||
|
||||
return out.str ();
|
||||
outs = out.str ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string handleDuplicate ()
|
||||
int handleDuplicate (std::string &outs)
|
||||
{
|
||||
std::stringstream out;
|
||||
int count = 0;
|
||||
|
@ -1095,7 +1130,8 @@ std::string handleDuplicate ()
|
|||
if (context.config.get ("echo.command", true))
|
||||
out << "Duplicated " << count << " task" << (count == 1 ? "" : "s") << std::endl;
|
||||
|
||||
return out.str ();
|
||||
outs = out.str ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -1174,8 +1210,9 @@ void handleShell ()
|
|||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string handleColor ()
|
||||
int handleColor (std::string &outs)
|
||||
{
|
||||
int rc = 0;
|
||||
std::stringstream out;
|
||||
if (context.config.get ("color", true) || context.config.get (std::string ("_forcecolor"), false))
|
||||
{
|
||||
|
@ -1257,13 +1294,15 @@ std::string handleColor ()
|
|||
out << "Color is currently turned off in your .taskrc file. "
|
||||
"To enable color, create the entry 'color=on'."
|
||||
<< std::endl;
|
||||
rc = 1;
|
||||
}
|
||||
|
||||
return out.str ();
|
||||
outs = out.str ();
|
||||
return rc;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string handleAnnotate ()
|
||||
int handleAnnotate (std::string &outs)
|
||||
{
|
||||
if (!context.task.has ("description"))
|
||||
throw std::string ("Cannot apply a blank annotation.");
|
||||
|
@ -1307,7 +1346,8 @@ std::string handleAnnotate ()
|
|||
context.tdb.commit ();
|
||||
context.tdb.unlock ();
|
||||
|
||||
return out.str ();
|
||||
outs = out.str ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -52,7 +52,7 @@ static std::vector <std::string> customReports;
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
// This report will eventually become the one report that many others morph into
|
||||
// via the .taskrc file.
|
||||
std::string handleCustomReport (const std::string& report)
|
||||
int handleCustomReport (const std::string& report, std::string &outs)
|
||||
{
|
||||
// Load report configuration.
|
||||
std::string columnList = context.config.get ("report." + report + ".columns");
|
||||
|
@ -94,21 +94,24 @@ std::string handleCustomReport (const std::string& report)
|
|||
labelList,
|
||||
sortList,
|
||||
filterList,
|
||||
tasks);
|
||||
tasks,
|
||||
outs);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// This report will eventually become the one report that many others morph into
|
||||
// via the .taskrc file.
|
||||
|
||||
std::string runCustomReport (
|
||||
int runCustomReport (
|
||||
const std::string& report,
|
||||
const std::string& columnList,
|
||||
const std::string& labelList,
|
||||
const std::string& sortList,
|
||||
const std::string& filterList,
|
||||
std::vector <Task>& tasks)
|
||||
std::vector <Task>& tasks,
|
||||
std::string &outs)
|
||||
{
|
||||
int rc = 0;
|
||||
// Load report configuration.
|
||||
std::vector <std::string> columns;
|
||||
split (columns, columnList, ',');
|
||||
|
@ -547,11 +550,14 @@ std::string runCustomReport (
|
|||
<< table.rowCount ()
|
||||
<< (table.rowCount () == 1 ? " task" : " tasks")
|
||||
<< std::endl;
|
||||
else
|
||||
else {
|
||||
out << "No matches."
|
||||
<< std::endl;
|
||||
rc = 1;
|
||||
}
|
||||
|
||||
return out.str ();
|
||||
outs = out.str ();
|
||||
return rc;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -599,7 +599,7 @@ ARE_THESE_REALLY_HARMFUL:
|
|||
// Introducing the Silver Bullet. This feature is the catch-all fixative for
|
||||
// various other ills. This is like opening up the hood and going in with a
|
||||
// wrench. To be used sparingly.
|
||||
std::string handleEdit ()
|
||||
int handleEdit (std::string &outs)
|
||||
{
|
||||
std::stringstream out;
|
||||
|
||||
|
@ -643,7 +643,8 @@ std::string handleEdit ()
|
|||
context.tdb.commit ();
|
||||
context.tdb.unlock ();
|
||||
|
||||
return out.str ();
|
||||
outs = out.str ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -666,6 +666,7 @@ static std::string importTask_1_6_0 (const std::vector <std::string>& lines)
|
|||
static std::string importTaskCmdLine (const std::vector <std::string>& lines)
|
||||
{
|
||||
std::vector <std::string> failed;
|
||||
std::string unused;
|
||||
|
||||
std::vector <std::string>::const_iterator it;
|
||||
for (it = lines.begin (); it != lines.end (); ++it)
|
||||
|
@ -680,7 +681,7 @@ static std::string importTaskCmdLine (const std::vector <std::string>& lines)
|
|||
context.task.clear ();
|
||||
context.cmd.command = "";
|
||||
context.parse ();
|
||||
handleAdd ();
|
||||
(void)handleAdd (unused);
|
||||
context.clearMessages ();
|
||||
}
|
||||
|
||||
|
@ -1144,7 +1145,7 @@ static std::string importCSV (const std::vector <std::string>& lines)
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string handleImport ()
|
||||
int handleImport (std::string &outs)
|
||||
{
|
||||
std::stringstream out;
|
||||
|
||||
|
@ -1212,7 +1213,8 @@ std::string handleImport ()
|
|||
else
|
||||
throw std::string ("You must specify a file to import.");
|
||||
|
||||
return out.str ();
|
||||
outs = out.str ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
71
src/main.h
71
src/main.h
|
@ -55,25 +55,25 @@ int getDueState (const std::string&);
|
|||
bool nag (Task&);
|
||||
|
||||
// command.cpp
|
||||
std::string handleAdd ();
|
||||
std::string handleAppend ();
|
||||
std::string handleExport ();
|
||||
std::string handleDone ();
|
||||
std::string handleModify ();
|
||||
std::string handleProjects ();
|
||||
std::string handleCompletionProjects ();
|
||||
std::string handleTags ();
|
||||
std::string handleCompletionTags ();
|
||||
std::string handleCompletionCommands ();
|
||||
std::string handleCompletionIDs ();
|
||||
std::string handleCompletionConfig ();
|
||||
std::string handleVersion ();
|
||||
std::string handleDelete ();
|
||||
std::string handleStart ();
|
||||
std::string handleStop ();
|
||||
std::string handleColor ();
|
||||
std::string handleAnnotate ();
|
||||
std::string handleDuplicate ();
|
||||
int handleAdd (std::string &);
|
||||
int handleAppend (std::string &);
|
||||
int handleExport (std::string &);
|
||||
int handleDone (std::string &);
|
||||
int handleModify (std::string &);
|
||||
int handleProjects (std::string &);
|
||||
int handleCompletionProjects (std::string &);
|
||||
int handleTags (std::string &);
|
||||
int handleCompletionTags (std::string &);
|
||||
int handleCompletionCommands (std::string &);
|
||||
int handleCompletionIDs (std::string &);
|
||||
int handleCompletionConfig (std::string &);
|
||||
int handleVersion (std::string &);
|
||||
int handleDelete (std::string &);
|
||||
int handleStart (std::string &);
|
||||
int handleStop (std::string &);
|
||||
int handleColor (std::string &);
|
||||
int handleAnnotate (std::string &);
|
||||
int handleDuplicate (std::string &);
|
||||
void handleUndo ();
|
||||
#ifdef FEATURE_SHELL
|
||||
void handleShell ();
|
||||
|
@ -85,27 +85,28 @@ int deltaAttributes (Task&);
|
|||
int deltaSubstitutions (Task&);
|
||||
|
||||
// edit.cpp
|
||||
std::string handleEdit ();
|
||||
int handleEdit (std::string &);
|
||||
|
||||
// report.cpp
|
||||
std::string shortUsage ();
|
||||
std::string longUsage ();
|
||||
std::string handleInfo ();
|
||||
std::string handleReportSummary ();
|
||||
std::string handleReportNext ();
|
||||
std::string handleReportHistory ();
|
||||
std::string handleReportGHistory ();
|
||||
std::string handleReportCalendar ();
|
||||
std::string handleReportStats ();
|
||||
std::string handleReportTimesheet ();
|
||||
int shortUsage (std::string &);
|
||||
int longUsage (std::string &);
|
||||
int handleInfo (std::string &);
|
||||
int handleReportSummary (std::string &);
|
||||
int handleReportNext (std::string &);
|
||||
int handleReportHistory (std::string &);
|
||||
int handleReportGHistory (std::string &);
|
||||
int handleReportCalendar (std::string &);
|
||||
int handleReportStats (std::string &);
|
||||
int handleReportTimesheet (std::string &);
|
||||
std::string getFullDescription (Task&);
|
||||
std::string getDueDate (Task&);
|
||||
|
||||
// custom.cpp
|
||||
std::string handleCustomReport (const std::string&);
|
||||
std::string runCustomReport (const std::string&, const std::string&,
|
||||
const std::string&, const std::string&,
|
||||
const std::string&, std::vector <Task>&);
|
||||
int handleCustomReport (const std::string&, std::string &);
|
||||
int runCustomReport (const std::string&, const std::string&,
|
||||
const std::string&, const std::string&,
|
||||
const std::string&, std::vector <Task>&,
|
||||
std::string&);
|
||||
void validReportColumns (const std::vector <std::string>&);
|
||||
void validSortColumns (const std::vector <std::string>&, const std::vector <std::string>&);
|
||||
|
||||
|
@ -118,7 +119,7 @@ std::string colorizeFootnote (const std::string&);
|
|||
std::string colorizeDebug (const std::string&);
|
||||
|
||||
// import.cpp
|
||||
std::string handleImport ();
|
||||
int handleImport (std::string&);
|
||||
|
||||
// list template
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -50,7 +50,7 @@
|
|||
extern Context context;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string shortUsage ()
|
||||
int shortUsage (std::string &outs)
|
||||
{
|
||||
Table table;
|
||||
|
||||
|
@ -209,14 +209,19 @@ std::string shortUsage ()
|
|||
<< std::endl
|
||||
<< std::endl;
|
||||
|
||||
return out.str ();
|
||||
outs = out.str ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string longUsage ()
|
||||
int longUsage (std::string &outs)
|
||||
{
|
||||
std::string shortUsageString;
|
||||
std::stringstream out;
|
||||
out << shortUsage ()
|
||||
|
||||
(void)shortUsage(shortUsageString);
|
||||
|
||||
out << shortUsageString
|
||||
<< "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 "
|
||||
|
@ -276,13 +281,15 @@ std::string longUsage ()
|
|||
<< " $ ! ' \" ( ) ; \\ ` * ? { } [ ] < > | & % # ~" << "\n"
|
||||
<< std::endl;
|
||||
|
||||
return out.str ();
|
||||
outs = out.str();
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Display all information for the given task.
|
||||
std::string handleInfo ()
|
||||
int handleInfo (std::string &outs)
|
||||
{
|
||||
int rc = 0;
|
||||
// Get all the tasks.
|
||||
std::vector <Task> tasks;
|
||||
context.tdb.lock (context.config.get ("locking", true));
|
||||
|
@ -497,18 +504,22 @@ std::string handleInfo ()
|
|||
<< std::endl;
|
||||
}
|
||||
|
||||
if (! tasks.size ())
|
||||
if (! tasks.size ()) {
|
||||
out << "No matches." << std::endl;
|
||||
rc = 1;
|
||||
}
|
||||
|
||||
return out.str ();
|
||||
outs = out.str ();
|
||||
return rc;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Project Remaining Avg Age Complete 0% 100%
|
||||
// A 12 13d 55% XXXXXXXXXXXXX-----------
|
||||
// B 109 3d 12h 10% XXX---------------------
|
||||
std::string handleReportSummary ()
|
||||
int handleReportSummary (std::string &outs)
|
||||
{
|
||||
int rc = 0;
|
||||
// Scan the pending tasks.
|
||||
std::vector <Task> tasks;
|
||||
context.tdb.lock (context.config.get ("locking", true));
|
||||
|
@ -648,10 +659,13 @@ std::string handleReportSummary ()
|
|||
<< table.rowCount ()
|
||||
<< (table.rowCount () == 1 ? " project" : " projects")
|
||||
<< std::endl;
|
||||
else
|
||||
else {
|
||||
out << "No projects." << std::endl;
|
||||
rc = 1;
|
||||
}
|
||||
|
||||
return out.str ();
|
||||
outs = out.str ();
|
||||
return rc;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -673,7 +687,7 @@ std::string handleReportSummary ()
|
|||
//
|
||||
// Make the "three" tasks a configurable number
|
||||
//
|
||||
std::string handleReportNext ()
|
||||
int handleReportNext (std::string &outs)
|
||||
{
|
||||
// Load report configuration.
|
||||
std::string columnList = context.config.get ("report.next.columns");
|
||||
|
@ -718,7 +732,8 @@ std::string handleReportNext ()
|
|||
labelList,
|
||||
sortList,
|
||||
filterList,
|
||||
tasks);
|
||||
tasks,
|
||||
outs);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -744,8 +759,9 @@ time_t monthlyEpoch (const std::string& date)
|
|||
return 0;
|
||||
}
|
||||
|
||||
std::string handleReportHistory ()
|
||||
int handleReportHistory (std::string &outs)
|
||||
{
|
||||
int rc = 0;
|
||||
std::map <time_t, int> groups; // Represents any month with data
|
||||
std::map <time_t, int> addedGroup; // Additions by month
|
||||
std::map <time_t, int> completedGroup; // Completions by month
|
||||
|
@ -891,15 +907,19 @@ std::string handleReportHistory ()
|
|||
out << optionalBlankLine ()
|
||||
<< table.render ()
|
||||
<< std::endl;
|
||||
else
|
||||
else {
|
||||
out << "No tasks." << std::endl;
|
||||
rc = 1;
|
||||
}
|
||||
|
||||
return out.str ();
|
||||
outs = out.str ();
|
||||
return rc;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string handleReportGHistory ()
|
||||
int handleReportGHistory (std::string &outs)
|
||||
{
|
||||
int rc = 0;
|
||||
std::map <time_t, int> groups; // Represents any month with data
|
||||
std::map <time_t, int> addedGroup; // Additions by month
|
||||
std::map <time_t, int> completedGroup; // Completions by month
|
||||
|
@ -1087,14 +1107,17 @@ std::string handleReportGHistory ()
|
|||
else
|
||||
out << "Legend: + added, X completed, - deleted" << std::endl;
|
||||
}
|
||||
else
|
||||
else {
|
||||
out << "No tasks." << std::endl;
|
||||
rc = 1;
|
||||
}
|
||||
|
||||
return out.str ();
|
||||
outs = out.str ();
|
||||
return rc;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string handleReportTimesheet ()
|
||||
int handleReportTimesheet (std::string &outs)
|
||||
{
|
||||
// Scan the pending tasks.
|
||||
std::vector <Task> tasks;
|
||||
|
@ -1264,7 +1287,8 @@ std::string handleReportTimesheet ()
|
|||
end -= 7 * 86400;
|
||||
}
|
||||
|
||||
return out.str ();
|
||||
outs = out.str ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -1432,7 +1456,7 @@ std::string renderMonths (
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string handleReportCalendar ()
|
||||
int handleReportCalendar (std::string &outs)
|
||||
{
|
||||
// Each month requires 28 text columns width. See how many will actually
|
||||
// fit. But if a preference is specified, and it fits, use it.
|
||||
|
@ -1604,11 +1628,12 @@ std::string handleReportCalendar ()
|
|||
<< optionalBlankLine ()
|
||||
<< std::endl;
|
||||
|
||||
return out.str ();
|
||||
outs = out.str ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string handleReportStats ()
|
||||
int handleReportStats (std::string &outs)
|
||||
{
|
||||
std::stringstream out;
|
||||
|
||||
|
@ -1836,7 +1861,8 @@ std::string handleReportStats ()
|
|||
<< table.render ()
|
||||
<< optionalBlankLine ();
|
||||
|
||||
return out.str ();
|
||||
outs = out.str ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
62
src/tests/feature.exit.t
Executable file
62
src/tests/feature.exit.t
Executable file
|
@ -0,0 +1,62 @@
|
|||
#! /usr/bin/perl
|
||||
################################################################################
|
||||
## task - a command line task list manager.
|
||||
##
|
||||
## Copyright 2006 - 2009, Paul Beckingham.
|
||||
## All rights reserved.
|
||||
##
|
||||
## This program is free software; you can redistribute it and/or modify it under
|
||||
## the terms of the GNU General Public License as published by the Free Software
|
||||
## Foundation; either version 2 of the License, or (at your option) any later
|
||||
## version.
|
||||
##
|
||||
## This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
## details.
|
||||
##
|
||||
## You should have received a copy of the GNU General Public License along with
|
||||
## this program; if not, write to the
|
||||
##
|
||||
## Free Software Foundation, Inc.,
|
||||
## 51 Franklin Street, Fifth Floor,
|
||||
## Boston, MA
|
||||
## 02110-1301
|
||||
## USA
|
||||
##
|
||||
################################################################################
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use Test::More tests => 7;
|
||||
|
||||
# Create the rc file.
|
||||
if (open my $fh, '>', 'exit.rc')
|
||||
{
|
||||
print $fh "data.location=.\n",
|
||||
"confirmation=no\n";
|
||||
close $fh;
|
||||
ok (-r 'exit.rc', 'Created exit.rc');
|
||||
}
|
||||
|
||||
qx{../task rc:exit.rc add foo};
|
||||
my $exit_good = system ('../task rc:exit.rc ls foo 2>&1 >>/dev/null');
|
||||
is ($exit_good, 0, 'task returns 0 on success');
|
||||
my $exit_bad = system ('../task rc:exit.rc ls bar 2>&1 >>/dev/null');
|
||||
isnt ($exit_bad, 0, 'task returns non-zero on failure');
|
||||
|
||||
# Cleanup.
|
||||
unlink 'pending.data';
|
||||
ok (!-r 'pending.data', 'Removed pending.data');
|
||||
|
||||
unlink 'completed.data';
|
||||
ok (!-r 'completed.data', 'Removed completed.data');
|
||||
|
||||
unlink 'undo.data';
|
||||
ok (!-r 'undo.data', 'Removed undo.data');
|
||||
|
||||
unlink 'exit.rc';
|
||||
ok (!-r 'exit.rc', 'Removed exit.rc');
|
||||
|
||||
exit 0;
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue