mirror of
https://github.com/GothenburgBitFactory/taskwarrior.git
synced 2025-07-07 20:06:36 +02:00
Command - import
- Implemented the import command, which only suports JSON. It is the basis for all other import formats, which will be implemented as external scripts.
This commit is contained in:
parent
e8a49b3e8e
commit
cdda791c84
5 changed files with 133 additions and 65 deletions
44
src/JSON.cpp
44
src/JSON.cpp
|
@ -36,11 +36,11 @@
|
|||
json::value* json::value::parse (Nibbler& nibbler)
|
||||
{
|
||||
json::value* v;
|
||||
if ((v = json::object::parse (nibbler)) ||
|
||||
(v = json::array::parse (nibbler)) ||
|
||||
(v = json::string::parse (nibbler)) ||
|
||||
(v = json::number::parse (nibbler)) ||
|
||||
(v = json::literal::parse (nibbler)))
|
||||
if ((v = json::object::parse (nibbler)) ||
|
||||
(v = json::array::parse (nibbler)) ||
|
||||
(v = json::string::parse (nibbler)) ||
|
||||
(v = json::number::parse (nibbler)) ||
|
||||
(v = json::literal::parse (nibbler)))
|
||||
return v;
|
||||
|
||||
return NULL;
|
||||
|
@ -61,7 +61,7 @@ std::string json::value::dump ()
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
json::string::string (const std::string& other)
|
||||
{
|
||||
*this = other;
|
||||
_data = other;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -71,7 +71,7 @@ json::string* json::string::parse (Nibbler& nibbler)
|
|||
if (nibbler.getQuoted ('"', value, false))
|
||||
{
|
||||
json::string* s = new json::string ();
|
||||
*(std::string*)s = value;
|
||||
s->_data = value;
|
||||
return s;
|
||||
}
|
||||
|
||||
|
@ -87,7 +87,7 @@ json::jtype json::string::type ()
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string json::string::dump ()
|
||||
{
|
||||
return std::string ("\"") + (std::string) *this + "\"";
|
||||
return std::string ("\"") + _data + "\"";
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -165,9 +165,7 @@ std::string json::literal::dump ()
|
|||
json::array::~array ()
|
||||
{
|
||||
std::vector <json::value*>::iterator i;
|
||||
for (i = ((std::vector <json::value*>*)this)->begin ();
|
||||
i != ((std::vector <json::value*>*)this)->end ();
|
||||
++i)
|
||||
for (i = _data.begin (); i != _data.end (); ++i)
|
||||
delete *i;
|
||||
}
|
||||
|
||||
|
@ -185,7 +183,7 @@ json::array* json::array::parse (Nibbler& nibbler)
|
|||
json::value* value;
|
||||
if ((value = json::value::parse (n)))
|
||||
{
|
||||
arr->push_back (value);
|
||||
arr->_data.push_back (value);
|
||||
value = NULL; // Not a leak. Looks like a leak.
|
||||
n.skipWS ();
|
||||
while (n.skip (','))
|
||||
|
@ -194,7 +192,7 @@ json::array* json::array::parse (Nibbler& nibbler)
|
|||
|
||||
if ((value = json::value::parse (n)))
|
||||
{
|
||||
arr->push_back (value);
|
||||
arr->_data.push_back (value);
|
||||
n.skipWS ();
|
||||
}
|
||||
else
|
||||
|
@ -232,11 +230,11 @@ std::string json::array::dump ()
|
|||
output += "[";
|
||||
|
||||
std::vector <json::value*>::iterator i;
|
||||
for (i = ((std::vector <json::value*>*)this)->begin ();
|
||||
i != ((std::vector <json::value*>*)this)->end ();
|
||||
for (i = _data.begin ();
|
||||
i != _data.end ();
|
||||
++i)
|
||||
{
|
||||
if (i != ((std::vector <json::value*>*)this)->begin ())
|
||||
if (i != _data.begin ())
|
||||
output += ",";
|
||||
|
||||
output += (*i)->dump ();
|
||||
|
@ -250,9 +248,7 @@ std::string json::array::dump ()
|
|||
json::object::~object ()
|
||||
{
|
||||
std::map <std::string, json::value*>::iterator i;
|
||||
for (i = ((std::map <std::string, json::value*>*)this)->begin ();
|
||||
i != ((std::map <std::string, json::value*>*)this)->end ();
|
||||
++i)
|
||||
for (i = _data.begin (); i != _data.end (); ++i)
|
||||
delete i->second;
|
||||
}
|
||||
|
||||
|
@ -271,7 +267,7 @@ json::object* json::object::parse (Nibbler& nibbler)
|
|||
json::value* value;
|
||||
if (json::object::parse_pair (n, name, value))
|
||||
{
|
||||
obj->insert (std::pair <std::string, json::value*> (name, value));
|
||||
obj->_data.insert (std::pair <std::string, json::value*> (name, value));
|
||||
value = NULL; // Not a leak. Looks like a leak.
|
||||
|
||||
n.skipWS ();
|
||||
|
@ -281,7 +277,7 @@ json::object* json::object::parse (Nibbler& nibbler)
|
|||
|
||||
if (json::object::parse_pair (n, name, value))
|
||||
{
|
||||
obj->insert (std::pair <std::string, json::value*> (name, value));
|
||||
obj->_data.insert (std::pair <std::string, json::value*> (name, value));
|
||||
n.skipWS ();
|
||||
}
|
||||
else
|
||||
|
@ -348,11 +344,9 @@ std::string json::object::dump ()
|
|||
output += "{";
|
||||
|
||||
std::map <std::string, json::value*>::iterator i;
|
||||
for (i = ((std::map <std::string, json::value*>*)this)->begin ();
|
||||
i != ((std::map <std::string, json::value*>*)this)->end ();
|
||||
++i)
|
||||
for (i = _data.begin (); i != _data.end (); ++i)
|
||||
{
|
||||
if (i != ((std::map <std::string, json::value*>*)this)->begin ())
|
||||
if (i != _data.begin ())
|
||||
output += ",";
|
||||
|
||||
output += "\"" + i->first + "\":";
|
||||
|
|
34
src/JSON.h
34
src/JSON.h
|
@ -38,12 +38,12 @@ namespace json
|
|||
{
|
||||
enum jtype
|
||||
{
|
||||
j_value,
|
||||
j_object,
|
||||
j_array,
|
||||
j_string,
|
||||
j_number,
|
||||
j_literal
|
||||
j_value, // 0
|
||||
j_object, // 1
|
||||
j_array, // 2
|
||||
j_string, // 3
|
||||
j_number, // 4
|
||||
j_literal // 5
|
||||
};
|
||||
|
||||
class value
|
||||
|
@ -56,7 +56,7 @@ namespace json
|
|||
virtual std::string dump ();
|
||||
};
|
||||
|
||||
class string : public value, public std::string
|
||||
class string : public value
|
||||
{
|
||||
public:
|
||||
string () {}
|
||||
|
@ -65,9 +65,12 @@ namespace json
|
|||
static string* parse (Nibbler&);
|
||||
jtype type ();
|
||||
std::string dump ();
|
||||
|
||||
public:
|
||||
std::string _data;
|
||||
};
|
||||
|
||||
class number : public value, public std::string
|
||||
class number : public value
|
||||
{
|
||||
public:
|
||||
number () : _dvalue (0.0) {}
|
||||
|
@ -77,6 +80,7 @@ namespace json
|
|||
std::string dump ();
|
||||
operator double () const;
|
||||
|
||||
public:
|
||||
double _dvalue;
|
||||
};
|
||||
|
||||
|
@ -89,11 +93,12 @@ namespace json
|
|||
jtype type ();
|
||||
std::string dump ();
|
||||
|
||||
public:
|
||||
enum literal_value {none, nullvalue, falsevalue, truevalue};
|
||||
literal_value _lvalue;
|
||||
};
|
||||
|
||||
class array : public value, public std::vector <value*>
|
||||
class array : public value
|
||||
{
|
||||
public:
|
||||
array () {}
|
||||
|
@ -101,9 +106,12 @@ namespace json
|
|||
static array* parse (Nibbler&);
|
||||
jtype type ();
|
||||
std::string dump ();
|
||||
|
||||
public:
|
||||
std::vector <value*> _data;
|
||||
};
|
||||
|
||||
class object : public value, public std::map <std::string, value*>
|
||||
class object : public value
|
||||
{
|
||||
public:
|
||||
object () {}
|
||||
|
@ -112,6 +120,9 @@ namespace json
|
|||
static bool parse_pair (Nibbler&, std::string&, value*&);
|
||||
jtype type ();
|
||||
std::string dump ();
|
||||
|
||||
public:
|
||||
std::map <std::string, value*> _data;
|
||||
};
|
||||
|
||||
// Parser entry point.
|
||||
|
@ -122,9 +133,6 @@ namespace json
|
|||
std::string decode (const std::string&);
|
||||
}
|
||||
|
||||
typedef std::vector<json::value*> json_array;
|
||||
typedef std::map<std::string, json::value*> json_object;
|
||||
|
||||
typedef std::vector <json::value*>::iterator json_array_iter;
|
||||
typedef std::map <std::string, json::value*>::iterator json_object_iter;
|
||||
|
||||
|
|
10
src/Task.cpp
10
src/Task.cpp
|
@ -121,11 +121,11 @@ Task::status Task::textToStatus (const std::string& input)
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string Task::statusToText (Task::status s)
|
||||
{
|
||||
if (s == Task::pending) return "pending"; // TODO i18n
|
||||
else if (s == Task::completed) return "completed"; // TODO i18n
|
||||
else if (s == Task::deleted) return "deleted"; // TODO i18n
|
||||
else if (s == Task::recurring) return "recurring"; // TODO i18n
|
||||
else if (s == Task::waiting) return "waiting"; // TODO i18n
|
||||
if (s == Task::pending) return "pending";
|
||||
else if (s == Task::completed) return "completed";
|
||||
else if (s == Task::deleted) return "deleted";
|
||||
else if (s == Task::recurring) return "recurring";
|
||||
else if (s == Task::waiting) return "waiting";
|
||||
|
||||
return "pending";
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include <JSON.h>
|
||||
#include <text.h>
|
||||
#include <util.h>
|
||||
#include <i18n.h>
|
||||
#include <main.h>
|
||||
#include <CmdImport.h>
|
||||
|
||||
|
@ -42,7 +43,7 @@ CmdImport::CmdImport ()
|
|||
{
|
||||
_keyword = "import";
|
||||
_usage = "task import <file> [<file> ...]";
|
||||
_description = "Imports JSON files.";
|
||||
_description = STRING_CMD_IMPORT_USAGE;
|
||||
_read_only = false;
|
||||
_displays_id = false;
|
||||
}
|
||||
|
@ -94,36 +95,100 @@ int CmdImport::execute (std::string& output)
|
|||
|
||||
// Parse the whole thing.
|
||||
json::value* root = json::parse (object);
|
||||
std::cout << root->dump ()
|
||||
<< "\n";
|
||||
|
||||
// For each object element...
|
||||
json_object_iter i;
|
||||
for (i = ((json_object*)root)->begin ();
|
||||
i != ((json_object*)root)->end ();
|
||||
++i)
|
||||
{
|
||||
std::cout << "!!!\n";
|
||||
}
|
||||
|
||||
/*
|
||||
std::map <std::string, json::value*>::iterator i;
|
||||
for (i = ((std::map <std::string, json::value*>*)root)->begin ();
|
||||
i != ((std::map <std::string, json::value*>*)root)->end ();
|
||||
++i)
|
||||
if (root->type () == json::j_object)
|
||||
{
|
||||
json::object* root_obj = (json::object*)root;
|
||||
Task task;
|
||||
std::cout << "!!!\n";
|
||||
task.set ("uuid", uuid ());
|
||||
|
||||
// TODO Navigate each object.
|
||||
// For each object element...
|
||||
json_object_iter i;
|
||||
for (i = root_obj->_data.begin ();
|
||||
i != root_obj->_data.end ();
|
||||
++i)
|
||||
{
|
||||
// If the attribute is a recognized column.
|
||||
Column* col = context.columns[i->first];
|
||||
if (col)
|
||||
{
|
||||
// Any specified id is ignored.
|
||||
if (i->first == "id")
|
||||
;
|
||||
|
||||
// Dates are converted from ISO to epoch.
|
||||
else if (col->type () == "date")
|
||||
{
|
||||
Date d (unquoteText (i->second->dump ()));
|
||||
task.set (i->first, d.toEpochString ());
|
||||
}
|
||||
|
||||
// Other types are simply added.
|
||||
else
|
||||
task.set (i->first, unquoteText (i->second->dump ()));
|
||||
}
|
||||
|
||||
// Several attributes do not have columns.
|
||||
// mask
|
||||
// imask
|
||||
// parent
|
||||
else
|
||||
{
|
||||
// Annotations are an array of JSON objects with 'entry' and
|
||||
// 'description' values and must be converted.
|
||||
if (i->first == "annotations")
|
||||
{
|
||||
std::vector <Att> annos;
|
||||
|
||||
json::array* atts = (json::array*)i->second;
|
||||
json_array_iter annotations;
|
||||
for (annotations = atts->_data.begin ();
|
||||
annotations != atts->_data.end ();
|
||||
++annotations)
|
||||
{
|
||||
json::object* annotation = (json::object*)*annotations;
|
||||
json::string* when = (json::string*)annotation->_data["entry"];
|
||||
json::string* what = (json::string*)annotation->_data["description"];
|
||||
|
||||
std::string name = "annotation_" + Date (when->_data).toEpochString ();
|
||||
|
||||
annos.push_back (Att (name, what->_data));
|
||||
}
|
||||
|
||||
task.setAnnotations (annos);
|
||||
}
|
||||
|
||||
// These must be imported, but are not represented by Column
|
||||
// objects.
|
||||
else if (i->first == "mask" ||
|
||||
i->first == "imask" ||
|
||||
i->first == "parent")
|
||||
{
|
||||
task.set (i->first, unquoteText (i->second->dump ()));
|
||||
}
|
||||
else
|
||||
throw std::string ("Unrecognized attribute '") + i->first + "'";
|
||||
}
|
||||
}
|
||||
|
||||
task.validate ();
|
||||
|
||||
// TODO Verify uuid is unique, to prevent double-import.
|
||||
|
||||
std::cout << " "
|
||||
<< task.get ("uuid")
|
||||
<< " "
|
||||
<< task.get ("description")
|
||||
<< "\n";
|
||||
context.tdb2.add (task);
|
||||
}
|
||||
*/
|
||||
else
|
||||
throw std::string ("Not a JSON object: ") + *line;
|
||||
|
||||
delete root;
|
||||
root = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
context.tdb2.commit ();
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
|
|
@ -308,6 +308,7 @@
|
|||
#define STRING_CMD_DENO_NONE "The specified task has no annotations that can be deleted."
|
||||
#define STRING_CMD_DENO_FOUND "Found annotation '{1}' and deleted it."
|
||||
#define STRING_CMD_DENO_NOMATCH "Did not find any matching annotation to be deleted for '{1}'."
|
||||
#define STRING_CMD_IMPORT_USAGE "Imports JSON files."
|
||||
|
||||
// Config
|
||||
#define STRING_CONFIG_OVERNEST "Configuration file nested to more than 10 levels deep - this has to be a mistake."
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue