mirror of
https://github.com/GothenburgBitFactory/taskwarrior.git
synced 2025-06-26 10:54:26 +02:00
File Import
- Implemented import from task 1.4.3, 1.5.0, 1.6.0, plain text, todo.sh and task command line files. - Implemented unit tests to cover the above.
This commit is contained in:
parent
c1291dc587
commit
5f4563af2f
16 changed files with 1180 additions and 54 deletions
|
@ -24,6 +24,8 @@
|
||||||
export files from versions 1.4.3 and earlier, versions 1.5.0 and later,
|
export files from versions 1.4.3 and earlier, versions 1.5.0 and later,
|
||||||
todo.sh 2.x, CSV, plain text and task command line. See online docs for
|
todo.sh 2.x, CSV, plain text and task command line. See online docs for
|
||||||
full details.
|
full details.
|
||||||
|
+ Export was including 'id' in the column header even though it was not
|
||||||
|
included in the data.
|
||||||
|
|
||||||
------ old releases ------------------------------
|
------ old releases ------------------------------
|
||||||
|
|
||||||
|
|
|
@ -121,6 +121,8 @@
|
||||||
export files from versions 1.4.3 and earlier, versions 1.5.0 and later,
|
export files from versions 1.4.3 and earlier, versions 1.5.0 and later,
|
||||||
todo.sh 2.x, CSV, plain text and task command line. See online docs for
|
todo.sh 2.x, CSV, plain text and task command line. See online docs for
|
||||||
full details.
|
full details.
|
||||||
|
<li>Export was including 'id' in the column header even though it was not
|
||||||
|
included in the data.
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
|
787
src/import.cpp
787
src/import.cpp
|
@ -26,6 +26,7 @@
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include "Date.h"
|
||||||
#include "task.h"
|
#include "task.h"
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -34,6 +35,7 @@ enum fileType
|
||||||
not_a_clue,
|
not_a_clue,
|
||||||
task_1_4_3,
|
task_1_4_3,
|
||||||
task_1_5_0,
|
task_1_5_0,
|
||||||
|
task_1_6_0,
|
||||||
task_cmd_line,
|
task_cmd_line,
|
||||||
todo_sh_2_0,
|
todo_sh_2_0,
|
||||||
csv,
|
csv,
|
||||||
|
@ -55,6 +57,10 @@ static fileType determineFileType (const std::vector <std::string>& lines)
|
||||||
lines[1][38] == ',' &&
|
lines[1][38] == ',' &&
|
||||||
lines[1][39] == '\'')
|
lines[1][39] == '\'')
|
||||||
{
|
{
|
||||||
|
if (lines[0] == "'uuid','status','tags','entry','start','due','recur',"
|
||||||
|
"'end','project','priority','fg','bg','description'")
|
||||||
|
return task_1_6_0;
|
||||||
|
|
||||||
if (lines[0] == "'id','uuid','status','tags','entry','start','due','recur',"
|
if (lines[0] == "'id','uuid','status','tags','entry','start','due','recur',"
|
||||||
"'end','project','priority','fg','bg','description'")
|
"'end','project','priority','fg','bg','description'")
|
||||||
return task_1_5_0;
|
return task_1_5_0;
|
||||||
|
@ -64,7 +70,26 @@ static fileType determineFileType (const std::vector <std::string>& lines)
|
||||||
return task_1_4_3;
|
return task_1_4_3;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO task_cmd_line
|
// A task command line might include a priority or project.
|
||||||
|
for (unsigned int i = 0; i < lines.size (); ++i)
|
||||||
|
{
|
||||||
|
std::vector <std::string> words;
|
||||||
|
split (words, lines[i], ' ');
|
||||||
|
|
||||||
|
for (unsigned int w = 0; w < words.size (); ++w)
|
||||||
|
if (words[w].substr (0, 9) == "priority:" ||
|
||||||
|
words[w].substr (0, 8) == "priorit:" ||
|
||||||
|
words[w].substr (0, 7) == "priori:" ||
|
||||||
|
words[w].substr (0, 6) == "prior:" ||
|
||||||
|
words[w].substr (0, 5) == "prio:" ||
|
||||||
|
words[w].substr (0, 4) == "pri:" ||
|
||||||
|
words[w].substr (0, 8) == "project:" ||
|
||||||
|
words[w].substr (0, 7) == "projec:" ||
|
||||||
|
words[w].substr (0, 6) == "proje:" ||
|
||||||
|
words[w].substr (0, 5) == "proj:" ||
|
||||||
|
words[w].substr (0, 4) == "pro:")
|
||||||
|
return task_cmd_line;
|
||||||
|
}
|
||||||
|
|
||||||
// x 2009-03-25 Walk the dog +project @context
|
// x 2009-03-25 Walk the dog +project @context
|
||||||
// This is a test +project @context
|
// This is a test +project @context
|
||||||
|
@ -111,7 +136,6 @@ static fileType determineFileType (const std::vector <std::string>& lines)
|
||||||
for (unsigned int i = 0; i < lines.size (); ++i)
|
for (unsigned int i = 0; i < lines.size (); ++i)
|
||||||
{
|
{
|
||||||
if (lines[i].length () > 10 &&
|
if (lines[i].length () > 10 &&
|
||||||
lines[i][0] != '#' &&
|
|
||||||
lines[i].find (",") == std::string::npos)
|
lines[i].find (",") == std::string::npos)
|
||||||
{
|
{
|
||||||
commas_on_every_line = false;
|
commas_on_every_line = false;
|
||||||
|
@ -121,32 +145,187 @@ static fileType determineFileType (const std::vector <std::string>& lines)
|
||||||
if (commas_on_every_line)
|
if (commas_on_every_line)
|
||||||
return csv;
|
return csv;
|
||||||
|
|
||||||
// TODO text, possibly with commas.
|
// Looks like 'text' is the default case, if there is any data at all.
|
||||||
for (unsigned int i = 0; i < lines.size (); ++i)
|
if (lines.size () > 1)
|
||||||
{
|
return text;
|
||||||
// TODO priority:{H,M,L}
|
|
||||||
// TODO priorit:{H,M,L}
|
|
||||||
// TODO priori:{H,M,L}
|
|
||||||
// TODO prior:{H,M,L}
|
|
||||||
// TODO prio:{H,M,L}
|
|
||||||
// TODO pri:{H,M,L}
|
|
||||||
// TODO project:.+
|
|
||||||
// TODO projec:.+
|
|
||||||
// TODO proje:.+
|
|
||||||
// TODO proj:.+
|
|
||||||
// TODO pro:.+
|
|
||||||
}
|
|
||||||
|
|
||||||
return not_a_clue;
|
return not_a_clue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
static void decorateTask (T& task, Config& conf)
|
||||||
|
{
|
||||||
|
char entryTime[16];
|
||||||
|
sprintf (entryTime, "%u", (unsigned int) time (NULL));
|
||||||
|
task.setAttribute ("entry", entryTime);
|
||||||
|
|
||||||
|
// Override with default.project, if not specified.
|
||||||
|
std::string defaultProject = conf.get ("default.project", "");
|
||||||
|
if (task.getAttribute ("project") == "" && defaultProject != "")
|
||||||
|
task.setAttribute ("project", defaultProject);
|
||||||
|
|
||||||
|
// Override with default.priority, if not specified.
|
||||||
|
std::string defaultPriority = conf.get ("default.priority", "");
|
||||||
|
if (task.getAttribute ("priority") == "" &&
|
||||||
|
defaultPriority != "" &&
|
||||||
|
validPriority (defaultPriority))
|
||||||
|
task.setAttribute ("priority", defaultPriority);
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
static std::string importTask_1_4_3 (
|
static std::string importTask_1_4_3 (
|
||||||
TDB& tdb,
|
TDB& tdb,
|
||||||
Config& conf,
|
Config& conf,
|
||||||
const std::vector <std::string>& lines)
|
const std::vector <std::string>& lines)
|
||||||
{
|
{
|
||||||
return "task 1.4.3\n";
|
std::vector <std::string> failed;
|
||||||
|
|
||||||
|
std::vector <std::string>::const_iterator it;
|
||||||
|
for (it = lines.begin (); it != lines.end (); ++it)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Skip the first line, if it is a columns header line.
|
||||||
|
if (it->substr (0, 5) == "'id',")
|
||||||
|
continue;
|
||||||
|
|
||||||
|
std::vector <std::string> fields;
|
||||||
|
split (fields, *it, ',');
|
||||||
|
|
||||||
|
// If there is an unexpected number of fields, something is wrong. Perhaps
|
||||||
|
// an embedded comma, in which case there are (at least) two fields that
|
||||||
|
// need to be concatenated.
|
||||||
|
if (fields.size () > 12)
|
||||||
|
{
|
||||||
|
int safety = 10; // Shouldn't be more than 10 commas in a description/project.
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
std::vector <std::string> modified;
|
||||||
|
for (unsigned int f = 0; f < fields.size (); ++f)
|
||||||
|
{
|
||||||
|
if (fields[f][0] != '\'' &&
|
||||||
|
fields[f][fields[f].length () - 1] == '\'')
|
||||||
|
{
|
||||||
|
modified[modified.size () - 1] += "," + fields[f];
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
modified.push_back (fields[f]);
|
||||||
|
}
|
||||||
|
fields = modified;
|
||||||
|
|
||||||
|
if (safety-- <= 0)
|
||||||
|
throw "unrecoverable";
|
||||||
|
}
|
||||||
|
while (fields.size () > 12);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fields.size () < 12)
|
||||||
|
throw "unrecoverable";
|
||||||
|
|
||||||
|
// Build up this task ready for insertion.
|
||||||
|
T task;
|
||||||
|
|
||||||
|
// Handle the 12 fields.
|
||||||
|
for (unsigned int f = 0; f < fields.size (); ++f)
|
||||||
|
{
|
||||||
|
switch (f)
|
||||||
|
{
|
||||||
|
case 0: // 'uuid'
|
||||||
|
task.setUUID (fields[f].substr (1, 36));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1: // 'status'
|
||||||
|
if (fields[f] == "'pending'") task.setStatus (T::pending);
|
||||||
|
else if (fields[f] == "'recurring'") task.setStatus (T::recurring);
|
||||||
|
else if (fields[f] == "'deleted'") task.setStatus (T::deleted);
|
||||||
|
else if (fields[f] == "'completed'") task.setStatus (T::completed);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2: // 'tags'
|
||||||
|
if (fields[f].length () > 2)
|
||||||
|
{
|
||||||
|
std::string tokens = fields[f].substr (1, fields[f].length () - 2);
|
||||||
|
std::vector <std::string> tags;
|
||||||
|
split (tags, tokens, ' ');
|
||||||
|
for (unsigned int i = 0; i > tags.size (); ++i)
|
||||||
|
task.addTag (tags[i]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3: // entry
|
||||||
|
task.setAttribute ("entry", fields[f]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 4: // start
|
||||||
|
if (fields[f].length ())
|
||||||
|
task.setAttribute ("start", fields[f]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 5: // due
|
||||||
|
if (fields[f].length ())
|
||||||
|
task.setAttribute ("due", fields[f]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 6: // end
|
||||||
|
if (fields[f].length ())
|
||||||
|
task.setAttribute ("end", fields[f]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 7: // 'project'
|
||||||
|
if (fields[f].length () > 2)
|
||||||
|
task.setAttribute ("project", fields[f].substr (1, fields[f].length () - 2));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 8: // 'priority'
|
||||||
|
if (fields[f].length () > 2)
|
||||||
|
task.setAttribute ("priority", fields[f].substr (1, fields[f].length () - 2));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 9: // 'fg'
|
||||||
|
if (fields[f].length () > 2)
|
||||||
|
task.setAttribute ("fg", fields[f].substr (1, fields[f].length () - 2));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 10: // 'bg'
|
||||||
|
if (fields[f].length () > 2)
|
||||||
|
task.setAttribute ("bg", fields[f].substr (1, fields[f].length () - 2));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 11: // 'description'
|
||||||
|
if (fields[f].length () > 2)
|
||||||
|
task.setDescription (fields[f].substr (1, fields[f].length () - 2));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! tdb.addT (task))
|
||||||
|
failed.push_back (*it);
|
||||||
|
}
|
||||||
|
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
failed.push_back (*it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::stringstream out;
|
||||||
|
out << "Imported "
|
||||||
|
<< (lines.size () - failed.size () - 1)
|
||||||
|
<< " tasks successfully, with "
|
||||||
|
<< failed.size ()
|
||||||
|
<< " errors."
|
||||||
|
<< std::endl;
|
||||||
|
|
||||||
|
if (failed.size ())
|
||||||
|
{
|
||||||
|
std::string bad;
|
||||||
|
join (bad, "\n", failed);
|
||||||
|
return out.str () + "\nCould not import:\n\n" + bad;
|
||||||
|
}
|
||||||
|
|
||||||
|
return out.str ();
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -155,7 +334,320 @@ static std::string importTask_1_5_0 (
|
||||||
Config& conf,
|
Config& conf,
|
||||||
const std::vector <std::string>& lines)
|
const std::vector <std::string>& lines)
|
||||||
{
|
{
|
||||||
return "task 1.5.0\n";
|
std::vector <std::string> failed;
|
||||||
|
|
||||||
|
std::vector <std::string>::const_iterator it;
|
||||||
|
for (it = lines.begin (); it != lines.end (); ++it)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Skip the first line, if it is a columns header line.
|
||||||
|
if (it->substr (0, 5) == "'id',")
|
||||||
|
continue;
|
||||||
|
|
||||||
|
std::vector <std::string> fields;
|
||||||
|
split (fields, *it, ',');
|
||||||
|
|
||||||
|
// If there is an unexpected number of fields, something is wrong. Perhaps
|
||||||
|
// an embedded comma, in which case there are (at least) two fields that
|
||||||
|
// need to be concatenated.
|
||||||
|
if (fields.size () > 13)
|
||||||
|
{
|
||||||
|
int safety = 10; // Shouldn't be more than 10 commas in a description/project.
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
std::vector <std::string> modified;
|
||||||
|
for (unsigned int f = 0; f < fields.size (); ++f)
|
||||||
|
{
|
||||||
|
if (fields[f][0] != '\'' &&
|
||||||
|
fields[f][fields[f].length () - 1] == '\'')
|
||||||
|
{
|
||||||
|
modified[modified.size () - 1] += "," + fields[f];
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
modified.push_back (fields[f]);
|
||||||
|
}
|
||||||
|
fields = modified;
|
||||||
|
|
||||||
|
if (safety-- <= 0)
|
||||||
|
throw "unrecoverable";
|
||||||
|
}
|
||||||
|
while (fields.size () > 13);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fields.size () < 13)
|
||||||
|
throw "unrecoverable";
|
||||||
|
|
||||||
|
// Build up this task ready for insertion.
|
||||||
|
T task;
|
||||||
|
|
||||||
|
// Handle the 13 fields.
|
||||||
|
for (unsigned int f = 0; f < fields.size (); ++f)
|
||||||
|
{
|
||||||
|
switch (f)
|
||||||
|
{
|
||||||
|
case 0: // 'uuid'
|
||||||
|
task.setUUID (fields[f].substr (1, 36));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1: // 'status'
|
||||||
|
if (fields[f] == "'pending'") task.setStatus (T::pending);
|
||||||
|
else if (fields[f] == "'recurring'") task.setStatus (T::recurring);
|
||||||
|
else if (fields[f] == "'deleted'") task.setStatus (T::deleted);
|
||||||
|
else if (fields[f] == "'completed'") task.setStatus (T::completed);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2: // 'tags'
|
||||||
|
if (fields[f].length () > 2)
|
||||||
|
{
|
||||||
|
std::string tokens = fields[f].substr (1, fields[f].length () - 2);
|
||||||
|
std::vector <std::string> tags;
|
||||||
|
split (tags, tokens, ' ');
|
||||||
|
for (unsigned int i = 0; i > tags.size (); ++i)
|
||||||
|
task.addTag (tags[i]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3: // entry
|
||||||
|
task.setAttribute ("entry", fields[f]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 4: // start
|
||||||
|
if (fields[f].length ())
|
||||||
|
task.setAttribute ("start", fields[f]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 5: // due
|
||||||
|
if (fields[f].length ())
|
||||||
|
task.setAttribute ("due", fields[f]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 6: // recur
|
||||||
|
if (fields[f].length ())
|
||||||
|
task.setAttribute ("recur", fields[f]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 7: // end
|
||||||
|
if (fields[f].length ())
|
||||||
|
task.setAttribute ("end", fields[f]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 8: // 'project'
|
||||||
|
if (fields[f].length () > 2)
|
||||||
|
task.setAttribute ("project", fields[f].substr (1, fields[f].length () - 2));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 9: // 'priority'
|
||||||
|
if (fields[f].length () > 2)
|
||||||
|
task.setAttribute ("priority", fields[f].substr (1, fields[f].length () - 2));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 10: // 'fg'
|
||||||
|
if (fields[f].length () > 2)
|
||||||
|
task.setAttribute ("fg", fields[f].substr (1, fields[f].length () - 2));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 11: // 'bg'
|
||||||
|
if (fields[f].length () > 2)
|
||||||
|
task.setAttribute ("bg", fields[f].substr (1, fields[f].length () - 2));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 12: // 'description'
|
||||||
|
if (fields[f].length () > 2)
|
||||||
|
task.setDescription (fields[f].substr (1, fields[f].length () - 2));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! tdb.addT (task))
|
||||||
|
failed.push_back (*it);
|
||||||
|
}
|
||||||
|
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
failed.push_back (*it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::stringstream out;
|
||||||
|
out << "Imported "
|
||||||
|
<< (lines.size () - failed.size () - 1)
|
||||||
|
<< " tasks successfully, with "
|
||||||
|
<< failed.size ()
|
||||||
|
<< " errors."
|
||||||
|
<< std::endl;
|
||||||
|
|
||||||
|
if (failed.size ())
|
||||||
|
{
|
||||||
|
std::string bad;
|
||||||
|
join (bad, "\n", failed);
|
||||||
|
return out.str () + "\nCould not import:\n\n" + bad;
|
||||||
|
}
|
||||||
|
|
||||||
|
return out.str ();
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
static std::string importTask_1_6_0 (
|
||||||
|
TDB& tdb,
|
||||||
|
Config& conf,
|
||||||
|
const std::vector <std::string>& lines)
|
||||||
|
{
|
||||||
|
std::vector <std::string> failed;
|
||||||
|
|
||||||
|
std::vector <std::string>::const_iterator it;
|
||||||
|
for (it = lines.begin (); it != lines.end (); ++it)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Skip the first line, if it is a columns header line.
|
||||||
|
if (it->substr (0, 7) == "'uuid',")
|
||||||
|
continue;
|
||||||
|
|
||||||
|
std::vector <std::string> fields;
|
||||||
|
split (fields, *it, ',');
|
||||||
|
|
||||||
|
// If there is an unexpected number of fields, something is wrong. Perhaps
|
||||||
|
// an embedded comma, in which case there are (at least) two fields that
|
||||||
|
// need to be concatenated.
|
||||||
|
if (fields.size () > 13)
|
||||||
|
{
|
||||||
|
int safety = 10; // Shouldn't be more than 10 commas in a description/project.
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
std::vector <std::string> modified;
|
||||||
|
for (unsigned int f = 0; f < fields.size (); ++f)
|
||||||
|
{
|
||||||
|
if (fields[f][0] != '\'' &&
|
||||||
|
fields[f][fields[f].length () - 1] == '\'')
|
||||||
|
{
|
||||||
|
modified[modified.size () - 1] += "," + fields[f];
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
modified.push_back (fields[f]);
|
||||||
|
}
|
||||||
|
fields = modified;
|
||||||
|
|
||||||
|
if (safety-- <= 0)
|
||||||
|
throw "unrecoverable";
|
||||||
|
}
|
||||||
|
while (fields.size () > 13);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fields.size () < 13)
|
||||||
|
throw "unrecoverable";
|
||||||
|
|
||||||
|
// Build up this task ready for insertion.
|
||||||
|
T task;
|
||||||
|
|
||||||
|
// Handle the 13 fields.
|
||||||
|
for (unsigned int f = 0; f < fields.size (); ++f)
|
||||||
|
{
|
||||||
|
switch (f)
|
||||||
|
{
|
||||||
|
case 0: // 'uuid'
|
||||||
|
task.setUUID (fields[f].substr (1, 36));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1: // 'status'
|
||||||
|
if (fields[f] == "'pending'") task.setStatus (T::pending);
|
||||||
|
else if (fields[f] == "'recurring'") task.setStatus (T::recurring);
|
||||||
|
else if (fields[f] == "'deleted'") task.setStatus (T::deleted);
|
||||||
|
else if (fields[f] == "'completed'") task.setStatus (T::completed);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2: // 'tags'
|
||||||
|
if (fields[f].length () > 2)
|
||||||
|
{
|
||||||
|
std::string tokens = fields[f].substr (1, fields[f].length () - 2);
|
||||||
|
std::vector <std::string> tags;
|
||||||
|
split (tags, tokens, ' ');
|
||||||
|
for (unsigned int i = 0; i > tags.size (); ++i)
|
||||||
|
task.addTag (tags[i]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3: // entry
|
||||||
|
task.setAttribute ("entry", fields[f]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 4: // start
|
||||||
|
if (fields[f].length ())
|
||||||
|
task.setAttribute ("start", fields[f]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 5: // due
|
||||||
|
if (fields[f].length ())
|
||||||
|
task.setAttribute ("due", fields[f]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 6: // recur
|
||||||
|
if (fields[f].length ())
|
||||||
|
task.setAttribute ("recur", fields[f]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 7: // end
|
||||||
|
if (fields[f].length ())
|
||||||
|
task.setAttribute ("end", fields[f]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 8: // 'project'
|
||||||
|
if (fields[f].length () > 2)
|
||||||
|
task.setAttribute ("project", fields[f].substr (1, fields[f].length () - 2));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 9: // 'priority'
|
||||||
|
if (fields[f].length () > 2)
|
||||||
|
task.setAttribute ("priority", fields[f].substr (1, fields[f].length () - 2));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 10: // 'fg'
|
||||||
|
if (fields[f].length () > 2)
|
||||||
|
task.setAttribute ("fg", fields[f].substr (1, fields[f].length () - 2));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 11: // 'bg'
|
||||||
|
if (fields[f].length () > 2)
|
||||||
|
task.setAttribute ("bg", fields[f].substr (1, fields[f].length () - 2));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 12: // 'description'
|
||||||
|
if (fields[f].length () > 2)
|
||||||
|
task.setDescription (fields[f].substr (1, fields[f].length () - 2));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! tdb.addT (task))
|
||||||
|
failed.push_back (*it);
|
||||||
|
}
|
||||||
|
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
failed.push_back (*it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::stringstream out;
|
||||||
|
out << "Imported "
|
||||||
|
<< (lines.size () - failed.size () - 1)
|
||||||
|
<< " tasks successfully, with "
|
||||||
|
<< failed.size ()
|
||||||
|
<< " errors."
|
||||||
|
<< std::endl;
|
||||||
|
|
||||||
|
if (failed.size ())
|
||||||
|
{
|
||||||
|
std::string bad;
|
||||||
|
join (bad, "\n", failed);
|
||||||
|
return out.str () + "\nCould not import:\n\n" + bad;
|
||||||
|
}
|
||||||
|
|
||||||
|
return out.str ();
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -163,43 +655,28 @@ static std::string importTaskCmdLine (
|
||||||
TDB& tdb,
|
TDB& tdb,
|
||||||
Config& conf,
|
Config& conf,
|
||||||
const std::vector <std::string>& lines)
|
const std::vector <std::string>& lines)
|
||||||
{
|
|
||||||
return "task command line\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
static std::string importTodoSh_2_0 (
|
|
||||||
TDB& tdb,
|
|
||||||
Config& conf,
|
|
||||||
const std::vector <std::string>& lines)
|
|
||||||
{
|
|
||||||
return "todo.sh 2.0\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
static std::string importText (
|
|
||||||
TDB& tdb,
|
|
||||||
Config& conf,
|
|
||||||
const std::vector <std::string>& lines)
|
|
||||||
{
|
{
|
||||||
std::vector <std::string> failed;
|
std::vector <std::string> failed;
|
||||||
|
|
||||||
for (unsigned int i = 0; i < lines.size (); ++i)
|
std::vector <std::string>::const_iterator it;
|
||||||
|
for (it = lines.begin (); it != lines.end (); ++it)
|
||||||
{
|
{
|
||||||
std::string line = lines[i];
|
std::string line = *it;
|
||||||
|
|
||||||
// Strip comments
|
try
|
||||||
std::string::size_type pound = line.find ("#");
|
|
||||||
if (pound != std::string::npos)
|
|
||||||
line = line.substr (0, pound);
|
|
||||||
|
|
||||||
// Skip blank lines
|
|
||||||
if (line.length () > 0)
|
|
||||||
{
|
{
|
||||||
|
std::vector <std::string> args;
|
||||||
|
split (args, std::string ("add ") + line, ' ');
|
||||||
|
|
||||||
T task;
|
T task;
|
||||||
task.parse (std::string ("\"") + lines[i] + "\"");
|
std::string command;
|
||||||
if (! tdb.addT (task))
|
parse (args, command, task, conf);
|
||||||
failed.push_back (lines[i]);
|
handleAdd (tdb, task, conf);
|
||||||
|
}
|
||||||
|
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
failed.push_back (line);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -211,9 +688,198 @@ static std::string importText (
|
||||||
<< " errors."
|
<< " errors."
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
|
|
||||||
|
if (failed.size ())
|
||||||
|
{
|
||||||
std::string bad;
|
std::string bad;
|
||||||
join (bad, "\n", failed);
|
join (bad, "\n", failed);
|
||||||
return out.str () + "\n" + bad;
|
return out.str () + "\nCould not import:\n\n" + bad;
|
||||||
|
}
|
||||||
|
|
||||||
|
return out.str ();
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
static std::string importTodoSh_2_0 (
|
||||||
|
TDB& tdb,
|
||||||
|
Config& conf,
|
||||||
|
const std::vector <std::string>& lines)
|
||||||
|
{
|
||||||
|
std::vector <std::string> failed;
|
||||||
|
|
||||||
|
std::vector <std::string>::const_iterator it;
|
||||||
|
for (it = lines.begin (); it != lines.end (); ++it)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
std::vector <std::string> args;
|
||||||
|
args.push_back ("add");
|
||||||
|
|
||||||
|
bool isPending = true;
|
||||||
|
Date endDate;
|
||||||
|
|
||||||
|
std::vector <std::string> words;
|
||||||
|
split (words, *it, ' ');
|
||||||
|
|
||||||
|
for (unsigned int w = 0; w < words.size (); ++w)
|
||||||
|
{
|
||||||
|
if (words[w].length () > 1 &&
|
||||||
|
words[w][0] == '+')
|
||||||
|
{
|
||||||
|
args.push_back (std::string ("project:") +
|
||||||
|
words[w].substr (1, std::string::npos));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert "+aaa" to "project:aaa".
|
||||||
|
// Convert "@aaa" to "+aaa".
|
||||||
|
else if (words[w].length () > 1 &&
|
||||||
|
words[w][0] == '@')
|
||||||
|
{
|
||||||
|
args.push_back (std::string ("+") +
|
||||||
|
words[w].substr (1, std::string::npos));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert "(A)" to "priority:H".
|
||||||
|
// Convert "(B)" to "priority:M".
|
||||||
|
// Convert "(?)" to "priority:L".
|
||||||
|
else if (words[w].length () == 3 &&
|
||||||
|
words[w][0] == '(' &&
|
||||||
|
words[w][2] == ')')
|
||||||
|
{
|
||||||
|
if (words[w][1] == 'A') args.push_back ("priority:H");
|
||||||
|
else if (words[w][1] == 'B') args.push_back ("priority:M");
|
||||||
|
else args.push_back ("priority:L");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set status, if completed.
|
||||||
|
else if (w == 0 &&
|
||||||
|
words[w] == "x")
|
||||||
|
{
|
||||||
|
isPending = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set status, and add an end date, if completed.
|
||||||
|
else if (! isPending &&
|
||||||
|
w == 1 &&
|
||||||
|
words[w].length () == 10 &&
|
||||||
|
words[w][4] == '-' &&
|
||||||
|
words[w][7] == '-')
|
||||||
|
{
|
||||||
|
endDate = Date (words[w], "Y-M-D");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Just an ordinary word.
|
||||||
|
else
|
||||||
|
{
|
||||||
|
args.push_back (words[w]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
T task;
|
||||||
|
std::string command;
|
||||||
|
parse (args, command, task, conf);
|
||||||
|
decorateTask (task, conf);
|
||||||
|
|
||||||
|
if (isPending)
|
||||||
|
{
|
||||||
|
task.setStatus (T::pending);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
task.setStatus (T::completed);
|
||||||
|
|
||||||
|
char end[16];
|
||||||
|
sprintf (end, "%u", (unsigned int) endDate.toEpoch ());
|
||||||
|
task.setAttribute ("end", end);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! tdb.addT (task))
|
||||||
|
failed.push_back (*it);
|
||||||
|
}
|
||||||
|
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
failed.push_back (*it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::stringstream out;
|
||||||
|
out << "Imported "
|
||||||
|
<< (lines.size () - failed.size ())
|
||||||
|
<< " tasks successfully, with "
|
||||||
|
<< failed.size ()
|
||||||
|
<< " errors."
|
||||||
|
<< std::endl;
|
||||||
|
|
||||||
|
if (failed.size ())
|
||||||
|
{
|
||||||
|
std::string bad;
|
||||||
|
join (bad, "\n", failed);
|
||||||
|
return out.str () + "\nCould not import:\n\n" + bad;
|
||||||
|
}
|
||||||
|
|
||||||
|
return out.str ();
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
static std::string importText (
|
||||||
|
TDB& tdb,
|
||||||
|
Config& conf,
|
||||||
|
const std::vector <std::string>& lines)
|
||||||
|
{
|
||||||
|
std::vector <std::string> failed;
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
std::vector <std::string>::const_iterator it;
|
||||||
|
for (it = lines.begin (); it != lines.end (); ++it)
|
||||||
|
{
|
||||||
|
std::string line = *it;
|
||||||
|
|
||||||
|
// Strip comments
|
||||||
|
std::string::size_type pound = line.find ("#");
|
||||||
|
if (pound != std::string::npos)
|
||||||
|
line = line.substr (0, pound);
|
||||||
|
|
||||||
|
// Skip blank lines
|
||||||
|
if (line.length () > 0)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
++count;
|
||||||
|
std::vector <std::string> args;
|
||||||
|
split (args, std::string ("add ") + line, ' ');
|
||||||
|
|
||||||
|
T task;
|
||||||
|
std::string command;
|
||||||
|
parse (args, command, task, conf);
|
||||||
|
decorateTask (task, conf);
|
||||||
|
|
||||||
|
if (! tdb.addT (task))
|
||||||
|
failed.push_back (*it);
|
||||||
|
}
|
||||||
|
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
failed.push_back (line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::stringstream out;
|
||||||
|
out << "Imported "
|
||||||
|
<< count
|
||||||
|
<< " tasks successfully, with "
|
||||||
|
<< failed.size ()
|
||||||
|
<< " errors."
|
||||||
|
<< std::endl;
|
||||||
|
|
||||||
|
if (failed.size ())
|
||||||
|
{
|
||||||
|
std::string bad;
|
||||||
|
join (bad, "\n", failed);
|
||||||
|
return out.str () + "\nCould not import:\n\n" + bad;
|
||||||
|
}
|
||||||
|
|
||||||
|
return out.str ();
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -237,8 +903,26 @@ std::string handleImport (TDB& tdb, T& task, Config& conf)
|
||||||
if (file.length () > 0)
|
if (file.length () > 0)
|
||||||
{
|
{
|
||||||
// Load the file.
|
// Load the file.
|
||||||
|
std::vector <std::string> all;
|
||||||
|
slurp (file, all, true);
|
||||||
|
|
||||||
std::vector <std::string> lines;
|
std::vector <std::string> lines;
|
||||||
slurp (file, lines, true);
|
std::vector <std::string>::iterator it;
|
||||||
|
for (it = all.begin (); it != all.end (); ++it)
|
||||||
|
{
|
||||||
|
std::string line = *it;
|
||||||
|
|
||||||
|
// Strip comments
|
||||||
|
std::string::size_type pound = line.find ("#");
|
||||||
|
if (pound != std::string::npos)
|
||||||
|
line = line.substr (0, pound);
|
||||||
|
|
||||||
|
trim (line);
|
||||||
|
|
||||||
|
// Skip blank lines
|
||||||
|
if (line.length () > 0)
|
||||||
|
lines.push_back (line);
|
||||||
|
}
|
||||||
|
|
||||||
// Take a guess at the file type.
|
// Take a guess at the file type.
|
||||||
fileType type = determineFileType (lines);
|
fileType type = determineFileType (lines);
|
||||||
|
@ -250,6 +934,7 @@ std::string handleImport (TDB& tdb, T& task, Config& conf)
|
||||||
{
|
{
|
||||||
case task_1_4_3: out << importTask_1_4_3 (tdb, conf, lines); break;
|
case task_1_4_3: out << importTask_1_4_3 (tdb, conf, lines); break;
|
||||||
case task_1_5_0: out << importTask_1_5_0 (tdb, conf, lines); break;
|
case task_1_5_0: out << importTask_1_5_0 (tdb, conf, lines); break;
|
||||||
|
case task_1_6_0: out << importTask_1_6_0 (tdb, conf, lines); break;
|
||||||
case task_cmd_line: out << importTaskCmdLine (tdb, conf, lines); break;
|
case task_cmd_line: out << importTaskCmdLine (tdb, conf, lines); break;
|
||||||
case todo_sh_2_0: out << importTodoSh_2_0 (tdb, conf, lines); break;
|
case todo_sh_2_0: out << importTodoSh_2_0 (tdb, conf, lines); break;
|
||||||
case csv: out << importCSV (tdb, conf, lines); break;
|
case csv: out << importCSV (tdb, conf, lines); break;
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
'id','status','tags','entry','start','due','end','project','priority','fg','bg','description'
|
'id','status','tags','entry','start','due','end','project','priority','fg','bg','description'
|
||||||
'545629d2-24a3-4a32-8894-57e708b98354','pending','',1238037900,,,,'A','M',,,'foo bar '
|
'545629d2-24a3-4a32-8894-57e708b98354','pending','',1238037900,,,,'A','M',,,'foo bar '
|
||||||
|
'545629d2-24a3-4a32-8894-57e708b98354','pending','',1238037900,,,,'A','M',,,'foo, bar '
|
||||||
|
|
|
|
@ -1,2 +1,3 @@
|
||||||
'id','uuid','status','tags','entry','start','due','recur','end','project','priority','fg','bg','description'
|
'id','uuid','status','tags','entry','start','due','recur','end','project','priority','fg','bg','description'
|
||||||
'7f7a4191-c2f2-487f-8855-7a1eb378c267','pending','',1238037947,,,,,'A','M',,,'foo bar'
|
'7f7a4191-c2f2-487f-8855-7a1eb378c267','pending','',1238037947,,,,,'A','M',,,'foo bar'
|
||||||
|
'7f7a4191-c2f2-487f-8855-7a1eb378c267','pending','',1238037947,,,,,'A','M',,,'foo, bar'
|
||||||
|
|
|
3
src/import/task-1.6.0.csv
Normal file
3
src/import/task-1.6.0.csv
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
'uuid','status','tags','entry','start','due','recur','end','project','priority','fg','bg','description'
|
||||||
|
'7f7a4191-c2f2-487f-8855-7a1eb378c267','pending','',1238037947,,,,,'A','M',,,'foo bar'
|
||||||
|
'7f7a4191-c2f2-487f-8855-7a1eb378c267','pending','',1238037947,,,,,'A','M',,,'foo, bar'
|
|
4
src/import/text.txt
Normal file
4
src/import/text.txt
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
Get milk, bread
|
||||||
|
Order cake
|
||||||
|
Clean house
|
||||||
|
|
|
@ -1,2 +1,4 @@
|
||||||
x 2009-03-25 Walk the dog +project @context
|
x 2009-03-25 Walk the dog +project @context
|
||||||
This is a test +project @context
|
This is a test +project @context
|
||||||
|
(A) A prioritized task
|
||||||
|
|
||||||
|
|
|
@ -235,7 +235,7 @@ bool validDate (std::string& date, Config& conf)
|
||||||
{
|
{
|
||||||
Date test (date, conf.get ("dateformat", "m/d/Y"));
|
Date test (date, conf.get ("dateformat", "m/d/Y"));
|
||||||
|
|
||||||
char epoch[12];
|
char epoch[16];
|
||||||
sprintf (epoch, "%d", (int) test.toEpoch ());
|
sprintf (epoch, "%d", (int) test.toEpoch ());
|
||||||
date = epoch;
|
date = epoch;
|
||||||
|
|
||||||
|
|
70
src/tests/import.143.t
Executable file
70
src/tests/import.143.t
Executable file
|
@ -0,0 +1,70 @@
|
||||||
|
#! /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 => 8;
|
||||||
|
|
||||||
|
# Create the rc file.
|
||||||
|
if (open my $fh, '>', 'import.rc')
|
||||||
|
{
|
||||||
|
print $fh "data.location=.\n";
|
||||||
|
close $fh;
|
||||||
|
ok (-r 'import.rc', 'Created import.rc');
|
||||||
|
}
|
||||||
|
|
||||||
|
# Create import file.
|
||||||
|
if (open my $fh, '>', 'import.txt')
|
||||||
|
{
|
||||||
|
print $fh "'id','status','tags','entry','start','due','end','project','priority','fg','bg','description'\n",
|
||||||
|
"'7f7a4191-c2f2-487f-8855-7a1eb378c267','pending','',1238037947,,,,'A','M',,,'foo bar'\n",
|
||||||
|
"'7f7a4191-c2f2-487f-8855-7a1eb378c267','pending','',1238037947,,,,'A','M',,,'foo, bar'\n",
|
||||||
|
"\n";
|
||||||
|
close $fh;
|
||||||
|
ok (-r 'import.txt', 'Created sample import data');
|
||||||
|
}
|
||||||
|
|
||||||
|
my $output = qx{../task rc:import.rc import import.txt};
|
||||||
|
is ($output, "Imported 2 tasks successfully, with 0 errors.\n", 'no errors');
|
||||||
|
|
||||||
|
$output = qx{../task rc:import.rc list};
|
||||||
|
like ($output, qr/1.+A.+M.+foo bar/, 't1');
|
||||||
|
like ($output, qr/2.+A.+M.+foo, bar/, 't2');
|
||||||
|
|
||||||
|
# Cleanup.
|
||||||
|
unlink 'import.txt';
|
||||||
|
ok (!-r 'import.txt', 'Removed import.txt');
|
||||||
|
|
||||||
|
unlink 'pending.data';
|
||||||
|
ok (!-r 'pending.data', 'Removed pending.data');
|
||||||
|
|
||||||
|
unlink 'import.rc';
|
||||||
|
ok (!-r 'import.rc', 'Removed import.rc');
|
||||||
|
|
||||||
|
exit 0;
|
||||||
|
|
70
src/tests/import.150.t
Executable file
70
src/tests/import.150.t
Executable file
|
@ -0,0 +1,70 @@
|
||||||
|
#! /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 => 8;
|
||||||
|
|
||||||
|
# Create the rc file.
|
||||||
|
if (open my $fh, '>', 'import.rc')
|
||||||
|
{
|
||||||
|
print $fh "data.location=.\n";
|
||||||
|
close $fh;
|
||||||
|
ok (-r 'import.rc', 'Created import.rc');
|
||||||
|
}
|
||||||
|
|
||||||
|
# Create import file.
|
||||||
|
if (open my $fh, '>', 'import.txt')
|
||||||
|
{
|
||||||
|
print $fh "'id','uuid','status','tags','entry','start','due','recur','end','project','priority','fg','bg','description'\n",
|
||||||
|
"'7f7a4191-c2f2-487f-8855-7a1eb378c267','pending','',1238037947,,,,,'A','M',,,'foo bar'\n",
|
||||||
|
"'7f7a4191-c2f2-487f-8855-7a1eb378c267','pending','',1238037947,,,,,'A','M',,,'foo, bar'\n",
|
||||||
|
"\n";
|
||||||
|
close $fh;
|
||||||
|
ok (-r 'import.txt', 'Created sample import data');
|
||||||
|
}
|
||||||
|
|
||||||
|
my $output = qx{../task rc:import.rc import import.txt};
|
||||||
|
is ($output, "Imported 2 tasks successfully, with 0 errors.\n", 'no errors');
|
||||||
|
|
||||||
|
$output = qx{../task rc:import.rc list};
|
||||||
|
like ($output, qr/1.+A.+M.+foo bar/, 't1');
|
||||||
|
like ($output, qr/2.+A.+M.+foo, bar/, 't2');
|
||||||
|
|
||||||
|
# Cleanup.
|
||||||
|
unlink 'import.txt';
|
||||||
|
ok (!-r 'import.txt', 'Removed import.txt');
|
||||||
|
|
||||||
|
unlink 'pending.data';
|
||||||
|
ok (!-r 'pending.data', 'Removed pending.data');
|
||||||
|
|
||||||
|
unlink 'import.rc';
|
||||||
|
ok (!-r 'import.rc', 'Removed import.rc');
|
||||||
|
|
||||||
|
exit 0;
|
||||||
|
|
70
src/tests/import.160.t
Executable file
70
src/tests/import.160.t
Executable file
|
@ -0,0 +1,70 @@
|
||||||
|
#! /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 => 8;
|
||||||
|
|
||||||
|
# Create the rc file.
|
||||||
|
if (open my $fh, '>', 'import.rc')
|
||||||
|
{
|
||||||
|
print $fh "data.location=.\n";
|
||||||
|
close $fh;
|
||||||
|
ok (-r 'import.rc', 'Created import.rc');
|
||||||
|
}
|
||||||
|
|
||||||
|
# Create import file.
|
||||||
|
if (open my $fh, '>', 'import.txt')
|
||||||
|
{
|
||||||
|
print $fh "'uuid','status','tags','entry','start','due','recur','end','project','priority','fg','bg','description'\n",
|
||||||
|
"'7f7a4191-c2f2-487f-8855-7a1eb378c267','pending','',1238037947,,,,,'A','M',,,'foo bar'\n",
|
||||||
|
"'7f7a4191-c2f2-487f-8855-7a1eb378c267','pending','',1238037947,,,,,'A','M',,,'foo, bar'\n",
|
||||||
|
"\n";
|
||||||
|
close $fh;
|
||||||
|
ok (-r 'import.txt', 'Created sample import data');
|
||||||
|
}
|
||||||
|
|
||||||
|
my $output = qx{../task rc:import.rc import import.txt};
|
||||||
|
is ($output, "Imported 2 tasks successfully, with 0 errors.\n", 'no errors');
|
||||||
|
|
||||||
|
$output = qx{../task rc:import.rc list};
|
||||||
|
like ($output, qr/1.+A.+M.+foo bar/, 't1');
|
||||||
|
like ($output, qr/2.+A.+M.+foo, bar/, 't2');
|
||||||
|
|
||||||
|
# Cleanup.
|
||||||
|
unlink 'import.txt';
|
||||||
|
ok (!-r 'import.txt', 'Removed import.txt');
|
||||||
|
|
||||||
|
unlink 'pending.data';
|
||||||
|
ok (!-r 'pending.data', 'Removed pending.data');
|
||||||
|
|
||||||
|
unlink 'import.rc';
|
||||||
|
ok (!-r 'import.rc', 'Removed import.rc');
|
||||||
|
|
||||||
|
exit 0;
|
||||||
|
|
69
src/tests/import.cmd.t
Executable file
69
src/tests/import.cmd.t
Executable file
|
@ -0,0 +1,69 @@
|
||||||
|
#! /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 => 8;
|
||||||
|
|
||||||
|
# Create the rc file.
|
||||||
|
if (open my $fh, '>', 'import.rc')
|
||||||
|
{
|
||||||
|
print $fh "data.location=.\n";
|
||||||
|
close $fh;
|
||||||
|
ok (-r 'import.rc', 'Created import.rc');
|
||||||
|
}
|
||||||
|
|
||||||
|
# Create import file.
|
||||||
|
if (open my $fh, '>', 'import.txt')
|
||||||
|
{
|
||||||
|
print $fh "This is a test priority:H project:A\n",
|
||||||
|
"Another task\n",
|
||||||
|
"\n";
|
||||||
|
close $fh;
|
||||||
|
ok (-r 'import.txt', 'Created sample import data');
|
||||||
|
}
|
||||||
|
|
||||||
|
my $output = qx{../task rc:import.rc import import.txt};
|
||||||
|
is ($output, "Imported 2 tasks successfully, with 0 errors.\n", 'no errors');
|
||||||
|
|
||||||
|
$output = qx{../task rc:import.rc list};
|
||||||
|
like ($output, qr/1.+A.+H.+This is a test/, 't1');
|
||||||
|
like ($output, qr/2.+Another task/, 't2');
|
||||||
|
|
||||||
|
# Cleanup.
|
||||||
|
unlink 'import.txt';
|
||||||
|
ok (!-r 'import.txt', 'Removed import.txt');
|
||||||
|
|
||||||
|
unlink 'pending.data';
|
||||||
|
ok (!-r 'pending.data', 'Removed pending.data');
|
||||||
|
|
||||||
|
unlink 'import.rc';
|
||||||
|
ok (!-r 'import.rc', 'Removed import.rc');
|
||||||
|
|
||||||
|
exit 0;
|
||||||
|
|
76
src/tests/import.todo.t
Executable file
76
src/tests/import.todo.t
Executable file
|
@ -0,0 +1,76 @@
|
||||||
|
#! /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 => 10;
|
||||||
|
|
||||||
|
# Create the rc file.
|
||||||
|
if (open my $fh, '>', 'import.rc')
|
||||||
|
{
|
||||||
|
print $fh "data.location=.\n";
|
||||||
|
close $fh;
|
||||||
|
ok (-r 'import.rc', 'Created import.rc');
|
||||||
|
}
|
||||||
|
|
||||||
|
# Create import file.
|
||||||
|
if (open my $fh, '>', 'import.txt')
|
||||||
|
{
|
||||||
|
print $fh "x 2010-03-25 Walk the dog +project \@context\n",
|
||||||
|
"This is a test +project \@context\n",
|
||||||
|
"(A) A prioritized task\n",
|
||||||
|
"\n";
|
||||||
|
close $fh;
|
||||||
|
ok (-r 'import.txt', 'Created sample import data');
|
||||||
|
}
|
||||||
|
|
||||||
|
my $output = qx{../task rc:import.rc import import.txt};
|
||||||
|
is ($output, "Imported 3 tasks successfully, with 0 errors.\n", 'no errors');
|
||||||
|
|
||||||
|
$output = qx{../task rc:import.rc list};
|
||||||
|
like ($output, qr/1.+project.+This is a test/, 't1');
|
||||||
|
like ($output, qr/2.+H.+A prioritized task/, 't2');
|
||||||
|
|
||||||
|
$output = qx{../task rc:import.rc completed};
|
||||||
|
like ($output, qr/3\/25\/2009.+Walk the dog/, 't3');
|
||||||
|
|
||||||
|
# Cleanup.
|
||||||
|
unlink 'import.txt';
|
||||||
|
ok (!-r 'import.txt', 'Removed import.txt');
|
||||||
|
|
||||||
|
unlink 'pending.data';
|
||||||
|
ok (!-r 'pending.data', 'Removed pending.data');
|
||||||
|
|
||||||
|
unlink 'completed.data';
|
||||||
|
ok (!-r 'completed.data', 'Removed completed.data');
|
||||||
|
|
||||||
|
unlink 'import.rc';
|
||||||
|
ok (!-r 'import.rc', 'Removed import.rc');
|
||||||
|
|
||||||
|
exit 0;
|
||||||
|
|
71
src/tests/import.txt.t
Executable file
71
src/tests/import.txt.t
Executable file
|
@ -0,0 +1,71 @@
|
||||||
|
#! /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 => 9;
|
||||||
|
|
||||||
|
# Create the rc file.
|
||||||
|
if (open my $fh, '>', 'import.rc')
|
||||||
|
{
|
||||||
|
print $fh "data.location=.\n";
|
||||||
|
close $fh;
|
||||||
|
ok (-r 'import.rc', 'Created import.rc');
|
||||||
|
}
|
||||||
|
|
||||||
|
# Create import file.
|
||||||
|
if (open my $fh, '>', 'import.txt')
|
||||||
|
{
|
||||||
|
print $fh "Get milk, bread\n",
|
||||||
|
"Order cake\n",
|
||||||
|
"Clean house\n",
|
||||||
|
"\n";
|
||||||
|
close $fh;
|
||||||
|
ok (-r 'import.txt', 'Created sample import data');
|
||||||
|
}
|
||||||
|
|
||||||
|
my $output = qx{../task rc:import.rc import import.txt};
|
||||||
|
is ($output, "Imported 3 tasks successfully, with 0 errors.\n", 'no errors');
|
||||||
|
|
||||||
|
$output = qx{../task rc:import.rc list};
|
||||||
|
like ($output, qr/1.+Get milk, bread/, 't1');
|
||||||
|
like ($output, qr/2.+Order cake/, 't2');
|
||||||
|
like ($output, qr/3.+Clean house/, 't3');
|
||||||
|
|
||||||
|
# Cleanup.
|
||||||
|
unlink 'import.txt';
|
||||||
|
ok (!-r 'import.txt', 'Removed import.txt');
|
||||||
|
|
||||||
|
unlink 'pending.data';
|
||||||
|
ok (!-r 'pending.data', 'Removed pending.data');
|
||||||
|
|
||||||
|
unlink 'import.rc';
|
||||||
|
ok (!-r 'import.rc', 'Removed import.rc');
|
||||||
|
|
||||||
|
exit 0;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue