Commands - stats

- Migrated handleReportStats to CmdStatistics.
This commit is contained in:
Paul Beckingham 2011-05-28 15:11:32 -04:00
parent 33d13ddb1d
commit 56e4c8172b
9 changed files with 323 additions and 236 deletions

View file

@ -156,13 +156,11 @@ void Cmd::load ()
commands.push_back ("delete"); commands.push_back ("delete");
commands.push_back ("done"); commands.push_back ("done");
commands.push_back ("duplicate"); commands.push_back ("duplicate");
commands.push_back ("help");
commands.push_back ("import"); commands.push_back ("import");
commands.push_back ("log"); commands.push_back ("log");
commands.push_back ("prepend"); commands.push_back ("prepend");
commands.push_back ("projects"); commands.push_back ("projects");
commands.push_back ("start"); commands.push_back ("start");
commands.push_back ("stats");
commands.push_back ("stop"); commands.push_back ("stop");
commands.push_back ("summary"); commands.push_back ("summary");
commands.push_back ("timesheet"); commands.push_back ("timesheet");
@ -246,10 +244,8 @@ bool Cmd::isReadOnlyCommand ()
command == "calendar" || command == "calendar" ||
command == "colors" || command == "colors" ||
command == "config" || command == "config" ||
command == "help" ||
command == "projects" || command == "projects" ||
command == "push" || command == "push" ||
command == "stats" ||
command == "summary" || command == "summary" ||
command == "timesheet" || command == "timesheet" ||
validCustom (command)) validCustom (command))

View file

@ -250,7 +250,6 @@ int Context::dispatch (std::string &out)
if (cmd.command == "projects") { rc = handleProjects (out); } if (cmd.command == "projects") { rc = handleProjects (out); }
else if (cmd.command == "colors") { rc = handleColor (out); } else if (cmd.command == "colors") { rc = handleColor (out); }
else if (cmd.command == "config") { rc = handleConfig (out); } else if (cmd.command == "config") { rc = handleConfig (out); }
else if (cmd.command == "stats") { rc = handleReportStats (out); }
else if (cmd.command == "history.monthly") { rc = handleReportHistoryMonthly (out); } else if (cmd.command == "history.monthly") { rc = handleReportHistoryMonthly (out); }
else if (cmd.command == "history.annual") { rc = handleReportHistoryAnnual (out); } else if (cmd.command == "history.annual") { rc = handleReportHistoryAnnual (out); }
else if (cmd.command == "ghistory.monthly") { rc = handleReportGHistoryMonthly (out); } else if (cmd.command == "ghistory.monthly") { rc = handleReportGHistoryMonthly (out); }

View file

@ -17,6 +17,7 @@ set (commands_SRCS Command.cpp Command.h
CmdLogo.cpp CmdLogo.h CmdLogo.cpp CmdLogo.h
CmdShell.cpp CmdShell.h CmdShell.cpp CmdShell.h
CmdShow.cpp CmdShow.h CmdShow.cpp CmdShow.h
CmdStatistics.cpp CmdStatistics.h
CmdTags.cpp CmdTags.h CmdTags.cpp CmdTags.h
CmdTip.cpp CmdTip.h CmdTip.cpp CmdTip.h
CmdUrgency.cpp CmdUrgency.h CmdUrgency.cpp CmdUrgency.h

View file

@ -195,10 +195,6 @@ int CmdHelp::execute (const std::string& command_line, std::string& output)
view.set (row, 1, "task calendar [due|month year|year]"); view.set (row, 1, "task calendar [due|month year|year]");
view.set (row, 2, "Shows a calendar, with due tasks marked."); view.set (row, 2, "Shows a calendar, with due tasks marked.");
row = view.addRow ();
view.set (row, 1, "task stats");
view.set (row, 2, "Shows task database statistics.");
row = view.addRow (); row = view.addRow ();
view.set (row, 1, "task import"); view.set (row, 1, "task import");
view.set (row, 2, "Imports tasks from a variety of formats."); view.set (row, 2, "Imports tasks from a variety of formats.");

View file

@ -0,0 +1,278 @@
////////////////////////////////////////////////////////////////////////////////
// taskwarrior - a command line task list manager.
//
// Copyright 2006 - 2011, Paul Beckingham, Federico Hernandez.
// 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
//
////////////////////////////////////////////////////////////////////////////////
#include <sstream>
#include <iomanip>
#include <ViewText.h>
#include <Duration.h>
#include <Context.h>
#include <main.h>
#include <text.h>
#include <util.h>
#include <CmdStatistics.h>
extern Context context;
////////////////////////////////////////////////////////////////////////////////
CmdStatistics::CmdStatistics ()
{
_keyword = "stats";
_usage = "task stats";
_description = "Shows task database statistics.";
_read_only = true;
_displays_id = false;
}
////////////////////////////////////////////////////////////////////////////////
int CmdStatistics::execute (const std::string& command_line, std::string& output)
{
int rc = 0;
std::stringstream out;
// Go get the file sizes.
size_t dataSize = 0;
Directory location (context.config.get ("data.location"));
File pending (location.data + "/pending.data");
dataSize += pending.size ();
File completed (location.data + "/completed.data");
dataSize += completed.size ();
File undo (location.data + "/undo.data");
dataSize += undo.size ();
std::vector <std::string> undoTxns;
File::read (undo, undoTxns);
int undoCount = 0;
std::vector <std::string>::iterator tx;
for (tx = undoTxns.begin (); tx != undoTxns.end (); ++tx)
if (tx->substr (0, 3) == "---")
++undoCount;
// Get all the tasks.
std::vector <Task> tasks;
context.tdb.lock (context.config.getBoolean ("locking"));
handleRecurrence ();
context.tdb.load (tasks, context.filter);
context.tdb.commit ();
context.tdb.unlock ();
Date now;
time_t earliest = time (NULL);
time_t latest = 1;
int totalT = 0;
int deletedT = 0;
int pendingT = 0;
int completedT = 0;
int waitingT = 0;
int taggedT = 0;
int annotationsT = 0;
int recurringT = 0;
float daysPending = 0.0;
int descLength = 0;
std::map <std::string, int> allTags;
std::map <std::string, int> allProjects;
std::vector <Task>::iterator it;
for (it = tasks.begin (); it != tasks.end (); ++it)
{
++totalT;
if (it->getStatus () == Task::deleted) ++deletedT;
if (it->getStatus () == Task::pending) ++pendingT;
if (it->getStatus () == Task::completed) ++completedT;
if (it->getStatus () == Task::recurring) ++recurringT;
if (it->getStatus () == Task::waiting) ++waitingT;
time_t entry = atoi (it->get ("entry").c_str ());
if (entry < earliest) earliest = entry;
if (entry > latest) latest = entry;
if (it->getStatus () == Task::completed)
{
time_t end = atoi (it->get ("end").c_str ());
daysPending += (end - entry) / 86400.0;
}
if (it->getStatus () == Task::pending)
daysPending += (now.toEpoch () - entry) / 86400.0;
descLength += it->get ("description").length ();
std::vector <Att> annotations;
it->getAnnotations (annotations);
annotationsT += annotations.size ();
std::vector <std::string> tags;
it->getTags (tags);
if (tags.size ()) ++taggedT;
std::vector <std::string>::iterator t;
for (t = tags.begin (); t != tags.end (); ++t)
allTags[*t] = 0;
std::string project = it->get ("project");
if (project != "")
allProjects[project] = 0;
}
// Create a table for output.
ViewText view;
view.width (context.getWidth ());
view.intraPadding (2);
view.add (Column::factory ("string", "Category"));
view.add (Column::factory ("string", "Data"));
int row = view.addRow ();
view.set (row, 0, "Pending");
view.set (row, 1, pendingT);
row = view.addRow ();
view.set (row, 0, "Waiting");
view.set (row, 1, waitingT);
row = view.addRow ();
view.set (row, 0, "Recurring");
view.set (row, 1, recurringT);
row = view.addRow ();
view.set (row, 0, "Completed");
view.set (row, 1, completedT);
row = view.addRow ();
view.set (row, 0, "Deleted");
view.set (row, 1, deletedT);
row = view.addRow ();
view.set (row, 0, "Total");
view.set (row, 1, totalT);
row = view.addRow ();
view.set (row, 0, "Annotations");
view.set (row, 1, annotationsT);
row = view.addRow ();
view.set (row, 0, "Unique tags");
view.set (row, 1, (int)allTags.size ());
row = view.addRow ();
view.set (row, 0, "Projects");
view.set (row, 1, (int)allProjects.size ());
row = view.addRow ();
view.set (row, 0, "Data size");
view.set (row, 1, formatBytes (dataSize));
row = view.addRow ();
view.set (row, 0, "Undo transactions");
view.set (row, 1, undoCount);
if (totalT)
{
row = view.addRow ();
view.set (row, 0, "Tasks tagged");
std::stringstream value;
value << std::setprecision (3) << (100.0 * taggedT / totalT) << "%";
view.set (row, 1, value.str ());
}
if (tasks.size ())
{
Date e (earliest);
row = view.addRow ();
view.set (row, 0, "Oldest task");
view.set (row, 1, e.toString (context.config.get ("dateformat")));
Date l (latest);
row = view.addRow ();
view.set (row, 0, "Newest task");
view.set (row, 1, l.toString (context.config.get ("dateformat")));
row = view.addRow ();
view.set (row, 0, "Task used for");
view.set (row, 1, Duration (latest - earliest).format ());
}
if (totalT)
{
row = view.addRow ();
view.set (row, 0, "Task added every");
view.set (row, 1, Duration (((latest - earliest) / totalT)).format ());
}
if (completedT)
{
row = view.addRow ();
view.set (row, 0, "Task completed every");
view.set (row, 1, Duration ((latest - earliest) / completedT).format ());
}
if (deletedT)
{
row = view.addRow ();
view.set (row, 0, "Task deleted every");
view.set (row, 1, Duration ((latest - earliest) / deletedT).format ());
}
if (pendingT || completedT)
{
row = view.addRow ();
view.set (row, 0, "Average time pending");
view.set (row, 1, Duration ((int) ((daysPending / (pendingT + completedT)) * 86400)).format ());
}
if (totalT)
{
row = view.addRow ();
view.set (row, 0, "Average desc length");
std::stringstream value;
value << (int) (descLength / totalT) << " characters";
view.set (row, 1, value.str ());
}
// If an alternating row color is specified, notify the table.
if (context.color ())
{
Color alternate (context.config.get ("color.alternate"));
if (alternate.nontrivial ())
{
view.colorOdd (alternate);
view.intraColorOdd (alternate);
view.extraColorOdd (alternate);
}
}
out << optionalBlankLine ()
<< view.render ()
<< optionalBlankLine ();
output = out.str ();
return rc;
}
////////////////////////////////////////////////////////////////////////////////

View file

@ -0,0 +1,42 @@
////////////////////////////////////////////////////////////////////////////////
// taskwarrior - a command line task list manager.
//
// Copyright 2006 - 2011, Paul Beckingham, Federico Hernandez.
// 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
//
////////////////////////////////////////////////////////////////////////////////
#ifndef INCLUDED_CMDSTATISTICS
#define INCLUDED_CMDSTATISTICS
#define L10N // Localization complete.
#include <string>
#include <Command.h>
class CmdStatistics : public Command
{
public:
CmdStatistics ();
int execute (const std::string&, std::string&);
};
#endif
////////////////////////////////////////////////////////////////////////////////

View file

@ -39,6 +39,7 @@
#include <CmdLogo.h> #include <CmdLogo.h>
#include <CmdShell.h> #include <CmdShell.h>
#include <CmdShow.h> #include <CmdShow.h>
#include <CmdStatistics.h>
#include <CmdTags.h> #include <CmdTags.h>
#include <CmdTip.h> #include <CmdTip.h>
#include <CmdUrgency.h> #include <CmdUrgency.h>
@ -64,6 +65,7 @@ void Command::factory (std::map <std::string, Command*>& all)
c = new CmdLogo (); all[c->keyword ()] = c; c = new CmdLogo (); all[c->keyword ()] = c;
c = new CmdShell (); all[c->keyword ()] = c; c = new CmdShell (); all[c->keyword ()] = c;
c = new CmdShow (); all[c->keyword ()] = c; c = new CmdShow (); all[c->keyword ()] = c;
c = new CmdStatistics (); all[c->keyword ()] = c;
c = new CmdTags (); all[c->keyword ()] = c; c = new CmdTags (); all[c->keyword ()] = c;
c = new CmdTip (); all[c->keyword ()] = c; c = new CmdTip (); all[c->keyword ()] = c;
c = new CmdUrgency (); all[c->keyword ()] = c; c = new CmdUrgency (); all[c->keyword ()] = c;

View file

@ -86,7 +86,6 @@ int deltaSubstitutions (Task&);
// report.cpp // report.cpp
int handleReportSummary (std::string&); int handleReportSummary (std::string&);
int handleReportCalendar (std::string&); int handleReportCalendar (std::string&);
int handleReportStats (std::string&);
int handleReportTimesheet (std::string&); int handleReportTimesheet (std::string&);
std::string getFullDescription (Task&, const std::string&); std::string getFullDescription (Task&, const std::string&);
std::string getDueDate (Task&, const std::string&); std::string getDueDate (Task&, const std::string&);

View file

@ -869,232 +869,6 @@ int handleReportCalendar (std::string& outs)
return rc; return rc;
} }
////////////////////////////////////////////////////////////////////////////////
int handleReportStats (std::string& outs)
{
int rc = 0;
std::stringstream out;
// Go get the file sizes.
size_t dataSize = 0;
Directory location (context.config.get ("data.location"));
File pending (location.data + "/pending.data");
dataSize += pending.size ();
File completed (location.data + "/completed.data");
dataSize += completed.size ();
File undo (location.data + "/undo.data");
dataSize += undo.size ();
std::vector <std::string> undoTxns;
File::read (undo, undoTxns);
int undoCount = 0;
foreach (tx, undoTxns)
if (tx->substr (0, 3) == "---")
++undoCount;
// Get all the tasks.
std::vector <Task> tasks;
context.tdb.lock (context.config.getBoolean ("locking"));
handleRecurrence ();
context.tdb.load (tasks, context.filter);
context.tdb.commit ();
context.tdb.unlock ();
Date now;
time_t earliest = time (NULL);
time_t latest = 1;
int totalT = 0;
int deletedT = 0;
int pendingT = 0;
int completedT = 0;
int waitingT = 0;
int taggedT = 0;
int annotationsT = 0;
int recurringT = 0;
float daysPending = 0.0;
int descLength = 0;
std::map <std::string, int> allTags;
std::map <std::string, int> allProjects;
std::vector <Task>::iterator it;
for (it = tasks.begin (); it != tasks.end (); ++it)
{
++totalT;
if (it->getStatus () == Task::deleted) ++deletedT;
if (it->getStatus () == Task::pending) ++pendingT;
if (it->getStatus () == Task::completed) ++completedT;
if (it->getStatus () == Task::recurring) ++recurringT;
if (it->getStatus () == Task::waiting) ++waitingT;
time_t entry = atoi (it->get ("entry").c_str ());
if (entry < earliest) earliest = entry;
if (entry > latest) latest = entry;
if (it->getStatus () == Task::completed)
{
time_t end = atoi (it->get ("end").c_str ());
daysPending += (end - entry) / 86400.0;
}
if (it->getStatus () == Task::pending)
daysPending += (now.toEpoch () - entry) / 86400.0;
descLength += it->get ("description").length ();
std::vector <Att> annotations;
it->getAnnotations (annotations);
annotationsT += annotations.size ();
std::vector <std::string> tags;
it->getTags (tags);
if (tags.size ()) ++taggedT;
foreach (t, tags)
allTags[*t] = 0;
std::string project = it->get ("project");
if (project != "")
allProjects[project] = 0;
}
// Create a table for output.
ViewText view;
view.width (context.getWidth ());
view.intraPadding (2);
view.add (Column::factory ("string", "Category"));
view.add (Column::factory ("string", "Data"));
int row = view.addRow ();
view.set (row, 0, "Pending");
view.set (row, 1, pendingT);
row = view.addRow ();
view.set (row, 0, "Waiting");
view.set (row, 1, waitingT);
row = view.addRow ();
view.set (row, 0, "Recurring");
view.set (row, 1, recurringT);
row = view.addRow ();
view.set (row, 0, "Completed");
view.set (row, 1, completedT);
row = view.addRow ();
view.set (row, 0, "Deleted");
view.set (row, 1, deletedT);
row = view.addRow ();
view.set (row, 0, "Total");
view.set (row, 1, totalT);
row = view.addRow ();
view.set (row, 0, "Annotations");
view.set (row, 1, annotationsT);
row = view.addRow ();
view.set (row, 0, "Unique tags");
view.set (row, 1, (int)allTags.size ());
row = view.addRow ();
view.set (row, 0, "Projects");
view.set (row, 1, (int)allProjects.size ());
row = view.addRow ();
view.set (row, 0, "Data size");
view.set (row, 1, formatBytes (dataSize));
row = view.addRow ();
view.set (row, 0, "Undo transactions");
view.set (row, 1, undoCount);
if (totalT)
{
row = view.addRow ();
view.set (row, 0, "Tasks tagged");
std::stringstream value;
value << std::setprecision (3) << (100.0 * taggedT / totalT) << "%";
view.set (row, 1, value.str ());
}
if (tasks.size ())
{
Date e (earliest);
row = view.addRow ();
view.set (row, 0, "Oldest task");
view.set (row, 1, e.toString (context.config.get ("dateformat")));
Date l (latest);
row = view.addRow ();
view.set (row, 0, "Newest task");
view.set (row, 1, l.toString (context.config.get ("dateformat")));
row = view.addRow ();
view.set (row, 0, "Task used for");
view.set (row, 1, Duration (latest - earliest).format ());
}
if (totalT)
{
row = view.addRow ();
view.set (row, 0, "Task added every");
view.set (row, 1, Duration (((latest - earliest) / totalT)).format ());
}
if (completedT)
{
row = view.addRow ();
view.set (row, 0, "Task completed every");
view.set (row, 1, Duration ((latest - earliest) / completedT).format ());
}
if (deletedT)
{
row = view.addRow ();
view.set (row, 0, "Task deleted every");
view.set (row, 1, Duration ((latest - earliest) / deletedT).format ());
}
if (pendingT || completedT)
{
row = view.addRow ();
view.set (row, 0, "Average time pending");
view.set (row, 1, Duration ((int) ((daysPending / (pendingT + completedT)) * 86400)).format ());
}
if (totalT)
{
row = view.addRow ();
view.set (row, 0, "Average desc length");
std::stringstream value;
value << (int) (descLength / totalT) << " characters";
view.set (row, 1, value.str ());
}
// If an alternating row color is specified, notify the table.
if (context.color ())
{
Color alternate (context.config.get ("color.alternate"));
if (alternate.nontrivial ())
{
view.colorOdd (alternate);
view.intraColorOdd (alternate);
view.extraColorOdd (alternate);
}
}
out << optionalBlankLine ()
<< view.render ()
<< optionalBlankLine ();
outs = out.str ();
return rc;
}
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
std::string getFullDescription (Task& task, const std::string& report) std::string getFullDescription (Task& task, const std::string& report)
{ {