Commands - modify

- Migrated handleModify to CmdModify.
This commit is contained in:
Paul Beckingham 2011-05-30 15:48:20 -04:00
parent 510ce650a6
commit a2da93b681
8 changed files with 240 additions and 168 deletions

View file

@ -249,13 +249,12 @@ int Context::dispatch (std::string &out)
Timer t ("Context::dispatch"); Timer t ("Context::dispatch");
// TODO Chain-of-command pattern dispatch. // TODO Chain-of-command pattern dispatch.
if (cmd.command == "" && sequence.size ()) { rc = handleModify (out); } // ...
// Commands that display IDs and therefore need TDB::gc first. // Commands that display IDs and therefore need TDB::gc first.
// ... // ...
// If the command is not recognized, display usage. rc = commands["help"]->execute (commandLine, out);
else { rc = commands["help"]->execute (commandLine, out); }
// Only update the shadow file if such an update was not suppressed (shadow), // Only update the shadow file if such an update was not suppressed (shadow),
if ((cmd.isWriteCommand () || if ((cmd.isWriteCommand () ||

View file

@ -25,167 +25,11 @@
// //
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
#include <iostream>
#include <iomanip>
#include <sstream>
#include <fstream>
#include <algorithm>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pwd.h>
#include <time.h>
#include <Permission.h>
#include <Directory.h>
#include <Nibbler.h>
#include <text.h> #include <text.h>
#include <util.h> #include <Context.h>
#include <main.h>
#include <Transport.h>
#include <ViewText.h>
#include <cmake.h>
#ifdef HAVE_COMMIT
#include <commit.h>
#endif
extern Context context; extern Context context;
////////////////////////////////////////////////////////////////////////////////
int handleModify (std::string& outs)
{
int count = 0;
std::stringstream out;
std::vector <Task> tasks;
context.tdb.lock (context.config.getBoolean ("locking"));
Filter filter;
context.tdb.loadPending (tasks, filter);
// Filter sequence.
std::vector <Task> all = tasks;
context.filter.applySequence (tasks, context.sequence);
if (tasks.size () == 0)
{
std::cout << "No tasks specified.\n";
return 1;
}
Permission permission;
if (context.sequence.size () > (size_t) context.config.getInteger ("bulk"))
permission.bigSequence ();
foreach (task, tasks)
{
// Perform some logical consistency checks.
if (context.task.has ("recur") &&
!context.task.has ("due") &&
!task->has ("due"))
throw std::string ("You cannot specify a recurring task without a due date.");
if (context.task.has ("until") &&
!context.task.has ("recur") &&
!task->has ("recur"))
throw std::string ("You cannot specify an until date for a non-recurring task.");
if (task->has ("recur") &&
task->has ("due") &&
context.task.has ("due") &&
context.task.get ("due") == "")
throw std::string ("You cannot remove the due date from a recurring task.");
if (task->has ("recur") &&
context.task.has ("recur") &&
context.task.get ("recur") == "")
throw std::string ("You cannot remove the recurrence from a recurring task.");
// Make all changes.
bool warned = false;
foreach (other, all)
{
// Skip wait: modification to a parent task, and other child tasks. Too
// difficult to achieve properly without losing 'waiting' as a status.
// Soon...
if (other->id == task->id || // Self
(! context.task.has ("wait") && // skip waits
task->has ("parent") && // is recurring
task->get ("parent") == other->get ("parent")) || // Sibling
other->get ("uuid") == task->get ("parent")) // Parent
{
if (task->has ("parent") && !warned)
{
warned = true;
std::cout << "Task "
<< task->id
<< " is a recurring task, and all other instances of this"
<< " task will be modified.\n";
}
Task before (*other);
// A non-zero value forces a file write.
int changes = 0;
// If a task is being made recurring, there are other cascading
// changes.
if (!task->has ("recur") &&
context.task.has ("recur"))
{
other->setStatus (Task::recurring);
other->set ("mask", "");
++changes;
std::cout << "Task "
<< other->id
<< " is now a recurring task.\n";
}
// Apply other deltas.
if (deltaDescription (*other))
{
permission.bigChange ();
++changes;
}
changes += deltaTags (*other);
changes += deltaAttributes (*other);
changes += deltaSubstitutions (*other);
if (taskDiff (before, *other))
{
// Only allow valid tasks.
other->validate ();
if (changes && permission.confirmed (before, taskDifferences (before, *other) + "Proceed with change?"))
{
// TODO Are dependencies being explicitly removed?
// Either we scan context.task for negative IDs "depends:-n"
// or we ask deltaAttributes (above) to record dependency
// removal.
dependencyChainOnModify (before, *other);
context.tdb.update (*other);
if (before.get ("project") != other->get ("project"))
context.footnote (onProjectChange (before, *other));
++count;
}
}
}
}
}
context.tdb.commit ();
context.tdb.unlock ();
if (context.config.getBoolean ("echo.command"))
out << "Modified " << count << " task" << (count == 1 ? ".\n" : "s.\n");
outs = out.str ();
return 0;
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
int deltaAppend (Task& task) int deltaAppend (Task& task)
{ {
@ -232,13 +76,14 @@ int deltaTags (Task& task)
// Apply or remove tags, if any. // Apply or remove tags, if any.
std::vector <std::string> tags; std::vector <std::string> tags;
context.task.getTags (tags); context.task.getTags (tags);
foreach (tag, tags) std::vector <std::string>::iterator tag;
for (tag = tags.begin (); tag != tags.end (); ++tag)
{ {
task.addTag (*tag); task.addTag (*tag);
++changes; ++changes;
} }
foreach (tag, context.tagRemovals) for (tag = context.tagRemovals.begin (); tag != context.tagRemovals.end (); ++tag)
{ {
task.removeTag (*tag); task.removeTag (*tag);
++changes; ++changes;
@ -252,7 +97,8 @@ int deltaAttributes (Task& task)
{ {
int changes = 0; int changes = 0;
foreach (att, context.task) std::map <std::string, Att>::iterator att;
for (att = context.task.begin (); att != context.task.end (); ++att)
{ {
if (att->second.name () != "uuid" && if (att->second.name () != "uuid" &&
att->second.name () != "description" && att->second.name () != "description" &&

View file

@ -32,6 +32,7 @@ set (commands_SRCS Command.cpp Command.h
CmdLog.cpp CmdLog.h CmdLog.cpp CmdLog.h
CmdLogo.cpp CmdLogo.h CmdLogo.cpp CmdLogo.h
CmdMerge.cpp CmdMerge.h CmdMerge.cpp CmdMerge.h
CmdModify.cpp CmdModify.h
CmdPrepend.cpp CmdPrepend.h CmdPrepend.cpp CmdPrepend.h
CmdProjects.cpp CmdProjects.h CmdProjects.cpp CmdProjects.h
CmdPull.cpp CmdPull.h CmdPull.cpp CmdPull.h

View file

@ -88,10 +88,6 @@ int CmdHelp::execute (const std::string&, std::string& output)
} }
/* /*
row = view.addRow ();
view.set (row, 1, "task ID [tags] [attrs] [desc...]");
view.set (row, 2, "Modifies the existing task with provided arguments.");
row = view.addRow (); row = view.addRow ();
view.set (row, 1, "task ID /from/to/g"); view.set (row, 1, "task ID /from/to/g");
view.set (row, 2, "Performs substitution on the task description and " view.set (row, 2, "Performs substitution on the task description and "

187
src/commands/CmdModify.cpp Normal file
View file

@ -0,0 +1,187 @@
////////////////////////////////////////////////////////////////////////////////
// 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 <iostream>
#include <sstream>
#include <Context.h>
#include <Permission.h>
#include <main.h>
#include <CmdModify.h>
extern Context context;
////////////////////////////////////////////////////////////////////////////////
CmdModify::CmdModify ()
{
// TODO Mention substitutions.
_keyword = "modify";
_usage = "task modify ID [tags] [attrs] [desc...]\n"
"task ID [tags] [attrs] [desc...]";
_description = "Modifies the existing task with provided arguments.\n"
"The 'modify' keyword is optional.";
_read_only = false;
_displays_id = false;
}
////////////////////////////////////////////////////////////////////////////////
int CmdModify::execute (const std::string&, std::string& output)
{
int count = 0;
std::stringstream out;
std::vector <Task> tasks;
context.tdb.lock (context.config.getBoolean ("locking"));
Filter filter;
context.tdb.loadPending (tasks, filter);
// Filter sequence.
std::vector <Task> all = tasks;
context.filter.applySequence (tasks, context.sequence);
if (tasks.size () == 0)
{
context.footnote ("No tasks specified.");
return 1;
}
Permission permission;
if (context.sequence.size () > (size_t) context.config.getInteger ("bulk"))
permission.bigSequence ();
std::vector <Task>::iterator task;
for (task = tasks.begin (); task != tasks.end (); ++task)
{
// Perform some logical consistency checks.
if (context.task.has ("recur") &&
!context.task.has ("due") &&
!task->has ("due"))
throw std::string ("You cannot specify a recurring task without a due date.");
if (context.task.has ("until") &&
!context.task.has ("recur") &&
!task->has ("recur"))
throw std::string ("You cannot specify an until date for a non-recurring task.");
if (task->has ("recur") &&
task->has ("due") &&
context.task.has ("due") &&
context.task.get ("due") == "")
throw std::string ("You cannot remove the due date from a recurring task.");
if (task->has ("recur") &&
context.task.has ("recur") &&
context.task.get ("recur") == "")
throw std::string ("You cannot remove the recurrence from a recurring task.");
// Make all changes.
bool warned = false;
std::vector <Task>::iterator other;
for (other = all.begin (); other != all.end (); ++other)
{
// Skip wait: modification to a parent task, and other child tasks. Too
// difficult to achieve properly without losing 'waiting' as a status.
// Soon...
if (other->id == task->id || // Self
(! context.task.has ("wait") && // skip waits
task->has ("parent") && // is recurring
task->get ("parent") == other->get ("parent")) || // Sibling
other->get ("uuid") == task->get ("parent")) // Parent
{
if (task->has ("parent") && !warned)
{
warned = true;
std::cout << "Task "
<< task->id
<< " is a recurring task, and all other instances of this"
<< " task will be modified.\n";
}
Task before (*other);
// A non-zero value forces a file write.
int changes = 0;
// If a task is being made recurring, there are other cascading
// changes.
if (!task->has ("recur") &&
context.task.has ("recur"))
{
other->setStatus (Task::recurring);
other->set ("mask", "");
++changes;
std::cout << "Task "
<< other->id
<< " is now a recurring task.\n";
}
// Apply other deltas.
if (deltaDescription (*other))
{
permission.bigChange ();
++changes;
}
changes += deltaTags (*other);
changes += deltaAttributes (*other);
changes += deltaSubstitutions (*other);
if (taskDiff (before, *other))
{
// Only allow valid tasks.
other->validate ();
if (changes && permission.confirmed (before, taskDifferences (before, *other) + "Proceed with change?"))
{
// TODO Are dependencies being explicitly removed?
// Either we scan context.task for negative IDs "depends:-n"
// or we ask deltaAttributes (above) to record dependency
// removal.
dependencyChainOnModify (before, *other);
context.tdb.update (*other);
if (before.get ("project") != other->get ("project"))
context.footnote (onProjectChange (before, *other));
++count;
}
}
}
}
}
context.tdb.commit ();
context.tdb.unlock ();
if (context.config.getBoolean ("echo.command"))
out << "Modified " << count << " task" << (count == 1 ? ".\n" : "s.\n");
output = out.str ();
return 0;
}
////////////////////////////////////////////////////////////////////////////////

42
src/commands/CmdModify.h Normal file
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_CMDMODIFY
#define INCLUDED_CMDMODIFY
#define L10N // Localization complete.
#include <string>
#include <Command.h>
class CmdModify : public Command
{
public:
CmdModify ();
int execute (const std::string&, std::string&);
};
#endif
////////////////////////////////////////////////////////////////////////////////

View file

@ -54,6 +54,7 @@
#include <CmdLog.h> #include <CmdLog.h>
#include <CmdLogo.h> #include <CmdLogo.h>
#include <CmdMerge.h> #include <CmdMerge.h>
#include <CmdModify.h>
#include <CmdPrepend.h> #include <CmdPrepend.h>
#include <CmdProjects.h> #include <CmdProjects.h>
#include <CmdPull.h> #include <CmdPull.h>
@ -116,6 +117,7 @@ void Command::factory (std::map <std::string, Command*>& all)
c = new CmdLog (); all[c->keyword ()] = c; c = new CmdLog (); all[c->keyword ()] = c;
c = new CmdLogo (); all[c->keyword ()] = c; c = new CmdLogo (); all[c->keyword ()] = c;
c = new CmdMerge (); all[c->keyword ()] = c; c = new CmdMerge (); all[c->keyword ()] = c;
c = new CmdModify (); all[c->keyword ()] = c;
c = new CmdPrepend (); all[c->keyword ()] = c; c = new CmdPrepend (); all[c->keyword ()] = c;
c = new CmdProjects (); all[c->keyword ()] = c; c = new CmdProjects (); all[c->keyword ()] = c;
c = new CmdPull (); all[c->keyword ()] = c; c = new CmdPull (); all[c->keyword ()] = c;

View file

@ -50,7 +50,6 @@ int getDueState (const std::string&);
bool nag (Task&); bool nag (Task&);
// command.cpp // command.cpp
int handleModify (std::string&);
int deltaAppend (Task&); int deltaAppend (Task&);
int deltaPrepend (Task&); int deltaPrepend (Task&);
int deltaDescription (Task&); int deltaDescription (Task&);