Enhancement - file import

- Added support for configuration variables that override field
  mapping.
- Updated documentation.
This commit is contained in:
Paul Beckingham 2009-04-12 20:29:37 -04:00
parent 120593887b
commit b8187e24ae
5 changed files with 107 additions and 22 deletions

View file

@ -337,6 +337,28 @@ ID Project Pri Description
</p>
</dd>
<dt>import.synonym.id</dt>
<dt>import.synonym.uuid</dt>
<dt>import.synonym.status</dt>
<dt>import.synonym.tags</dt>
<dt>import.synonym.entry</dt>
<dt>import.synonym.start</dt>
<dt>import.synonym.due</dt>
<dt>import.synonym.recur</dt>
<dt>import.synonym.end</dt>
<dt>import.synonym.project</dt>
<dt>import.synonym.priority</dt>
<dt>import.synonym.fg</dt>
<dt>import.synonym.bg</dt>
<dt>import.synonym.description</dt>
<dd>
If any of these configuration variables are found, they influence
data import by specifying a single additional field name synonym.
If a data import is failing because certain column names are not
being recognized, then this is how the field mapping can be
controlled.
</dd>
<p>
Note that the command:
</p>
@ -347,6 +369,8 @@ ID Project Pri Description
will display the configuration variables found in the .taskrc file,
and will warn you of any variables that are not recognized.
</p>
</div>
<br />

View file

@ -50,13 +50,56 @@
<li>Plain text files, with one task listed per line.
<li>Task command line format.
</ul>
Task makes a good effort to determine which of these formats a
file is, and then imports accordingly.
</p>
<p>
It would be wise to backup your task data files before an import.
Task makes a good effort to determine which of these formats a
file is. It does this by reading the file, and looking for
familiar patterns. For example, the easiest files to recognize
are those exported from task itself, because they all have a
header line that comes in only three variations. Other formats
are a little harder to identify, but they all have their own
identifying characteristics.
</p>
<p>
The most complex import is when a CSV file is recognized.
Task needs a field header line in order to map columns to task
data items. For example, the if the following file is
imported:
</p>
<pre><code>number,status,task
1,pending,task one
2,pending,task two</code></pre>
<p>
Task will map the "number" field to task's "id" field, etc,
based on name. Task has a list of synonyms that it uses to
map fields, but you can specify your own override with any of
the following configuration variables:
</p>
<ul>
<li>import.synonym.id
<li>import.synonym.uuid
<li>import.synonym.status
<li>import.synonym.tags
<li>import.synonym.entry
<li>import.synonym.start
<li>import.synonym.due
<li>import.synonym.recur
<li>import.synonym.end
<li>import.synonym.project
<li>import.synonym.priority
<li>import.synonym.fg
<li>import.synonym.bg
<li>import.synonym.description
</ul>
<p>
Please note that it is wise to backup your task data files
before an import.
</p>
</div>

View file

@ -372,7 +372,12 @@ std::string handleVersion (Config& conf)
"color.pri.L color.pri.M color.pri.none color.recurring color.tagged "
"confirmation curses data.location dateformat default.command "
"default.priority defaultwidth due echo.command locking monthsperline nag "
"next project shadow.command shadow.file shadow.notify";
"next project shadow.command shadow.file shadow.notify "
"import.synonym.id import.synonym.uuid import.synonym.status "
"import.synonym.tags import.synonym.entry import.synonym.start "
"import.synonym.due import.synonym.recur import.synonym.end "
"import.synonym.project import.synonym.priority import.synonym.fg "
"import.synonym.bg import.synonym.description";
// This configuration variable is supported, but not documented. It exists
// so that unit tests can force color to be on even when the output from task

View file

@ -917,7 +917,8 @@ static std::string importCSV (
std::string name = lowerCase (trim (unquoteText (trim (headings[h]))));
// If there is a mapping for the field, use the value.
if (name == "id" ||
if (name == conf.get ("import.synonym.id") ||
name == "id" ||
name == "#" ||
name == "sequence" ||
name.find ("num") != std::string::npos)
@ -925,28 +926,32 @@ static std::string importCSV (
mapping["id"] = (int)h;
}
else if (name == "uuid" ||
else if (name == conf.get ("import.synonym.uuid") ||
name == "uuid" ||
name == "guid" ||
name.find ("unique") != std::string::npos)
{
mapping["uuid"] = (int)h;
}
else if (name == "status" ||
else if (name == conf.get ("import.synonym.status") ||
name == "status" ||
name == "condition" ||
name == "state")
{
mapping["status"] = (int)h;
}
else if (name == "tags" ||
else if (name == conf.get ("import.synonym.tags") ||
name == "tags" ||
name.find ("categor") != std::string::npos ||
name.find ("tag") != std::string::npos)
{
mapping["tags"] = (int)h;
}
else if (name == "entry" ||
else if (name == conf.get ("import.synonym.entry") ||
name == "entry" ||
name.find ("added") != std::string::npos ||
name.find ("created") != std::string::npos ||
name.find ("entered") != std::string::npos)
@ -954,62 +959,71 @@ static std::string importCSV (
mapping["entry"] = (int)h;
}
else if (name == "start" ||
else if (name == conf.get ("import.synonym.start") ||
name == "start" ||
name.find ("began") != std::string::npos ||
name.find ("begun") != std::string::npos ||
name.find ("started") != std::string::npos ||
name == "")
name.find ("started") != std::string::npos)
{
mapping["start"] = (int)h;
}
else if (name == "due" ||
else if (name == conf.get ("import.synonym.due") ||
name == "due" ||
name.find ("expected") != std::string::npos)
{
mapping["due"] = (int)h;
}
else if (name == "recur" ||
else if (name == conf.get ("import.synonym.recur") ||
name == "recur" ||
name == "frequency")
{
mapping["recur"] = (int)h;
}
else if (name == "end" ||
else if (name == conf.get ("import.synonym.end") ||
name == "end" ||
name == "done" ||
name.find ("complete") != std::string::npos)
{
mapping["end"] = (int)h;
}
else if (name == "project" ||
else if (name == conf.get ("import.synonym.project") ||
name == "project" ||
name.find ("proj") != std::string::npos)
{
mapping["project"] = (int)h;
}
else if (name == "priority" ||
else if (name == conf.get ("import.synonym.priority") ||
name == "priority" ||
name == "pri" ||
name.find ("importan") != std::string::npos)
{
mapping["priority"] = (int)h;
}
else if (name.find ("fg") != std::string::npos ||
else if (name == conf.get ("import.synonym.fg") ||
name.find ("fg") != std::string::npos ||
name.find ("foreground") != std::string::npos ||
name.find ("color") != std::string::npos)
{
mapping["fg"] = (int)h;
}
else if (name == "bg" ||
else if (name == conf.get ("import.synonym.bg") ||
name == "bg" ||
name.find ("background") != std::string::npos)
{
mapping["bg"] = (int)h;
}
else if (name.find ("desc") != std::string::npos ||
else if (name == conf.get ("import.synonym.description") ||
name.find ("desc") != std::string::npos ||
name.find ("detail") != std::string::npos ||
name.find ("task") != std::string::npos ||
name.find ("what") != std::string::npos)
{
mapping["description"] = (int)h;

View file

@ -864,7 +864,6 @@ std::string runTaskCommand (
else if (command == "import") { cmdMod = true; out = handleImport (tdb, task, conf); }
// Command that display IDs and therefore need TDB::gc first.
else if (command == "completed") { if (gc) gcMod = tdb.gc (); out = handleCompleted (tdb, task, conf); }
else if (command == "next") { if (gc) gcMod = tdb.gc (); out = handleReportNext (tdb, task, conf); }
else if (command == "active") { if (gc) gcMod = tdb.gc (); out = handleReportActive (tdb, task, conf); }