- 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:
Paul Beckingham 2009-08-29 09:14:26 -04:00
parent cc5c99c0a1
commit 62be3f8acb
11 changed files with 302 additions and 157 deletions

View file

@ -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
View file

@ -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.

View file

@ -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 ())
{

View file

@ -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

View file

@ -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;
}
////////////////////////////////////////////////////////////////////////////////

View file

@ -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;
}
////////////////////////////////////////////////////////////////////////////////

View file

@ -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;
}
////////////////////////////////////////////////////////////////////////////////

View file

@ -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;
}
////////////////////////////////////////////////////////////////////////////////

View file

@ -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
///////////////////////////////////////////////////////////////////////////////

View file

@ -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
View 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;