From b8187e24ae844f75eb42204f8420252e411aafc7 Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Note that the command:
@@ -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. + +- 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. +
+ ++ 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: +
+ +number,status,task
+1,pending,task one
+2,pending,task two
+
+ + 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: +
+ ++ Please note that it is wise to backup your task data files + before an import.
diff --git a/src/command.cpp b/src/command.cpp index 16282bdc9..968763656 100644 --- a/src/command.cpp +++ b/src/command.cpp @@ -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 diff --git a/src/import.cpp b/src/import.cpp index ce36f8480..163dca30d 100644 --- a/src/import.cpp +++ b/src/import.cpp @@ -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; diff --git a/src/task.cpp b/src/task.cpp index b08a2f139..40904aae1 100644 --- a/src/task.cpp +++ b/src/task.cpp @@ -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); }