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* json::value::parse (Nibbler& nibbler)
|
||||||
{
|
{
|
||||||
json::value* v;
|
json::value* v;
|
||||||
if ((v = json::object::parse (nibbler)) ||
|
if ((v = json::object::parse (nibbler)) ||
|
||||||
(v = json::array::parse (nibbler)) ||
|
(v = json::array::parse (nibbler)) ||
|
||||||
(v = json::string::parse (nibbler)) ||
|
(v = json::string::parse (nibbler)) ||
|
||||||
(v = json::number::parse (nibbler)) ||
|
(v = json::number::parse (nibbler)) ||
|
||||||
(v = json::literal::parse (nibbler)))
|
(v = json::literal::parse (nibbler)))
|
||||||
return v;
|
return v;
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -61,7 +61,7 @@ std::string json::value::dump ()
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
json::string::string (const std::string& other)
|
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))
|
if (nibbler.getQuoted ('"', value, false))
|
||||||
{
|
{
|
||||||
json::string* s = new json::string ();
|
json::string* s = new json::string ();
|
||||||
*(std::string*)s = value;
|
s->_data = value;
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,7 +87,7 @@ json::jtype json::string::type ()
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
std::string json::string::dump ()
|
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 ()
|
json::array::~array ()
|
||||||
{
|
{
|
||||||
std::vector <json::value*>::iterator i;
|
std::vector <json::value*>::iterator i;
|
||||||
for (i = ((std::vector <json::value*>*)this)->begin ();
|
for (i = _data.begin (); i != _data.end (); ++i)
|
||||||
i != ((std::vector <json::value*>*)this)->end ();
|
|
||||||
++i)
|
|
||||||
delete *i;
|
delete *i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -185,7 +183,7 @@ json::array* json::array::parse (Nibbler& nibbler)
|
||||||
json::value* value;
|
json::value* value;
|
||||||
if ((value = json::value::parse (n)))
|
if ((value = json::value::parse (n)))
|
||||||
{
|
{
|
||||||
arr->push_back (value);
|
arr->_data.push_back (value);
|
||||||
value = NULL; // Not a leak. Looks like a leak.
|
value = NULL; // Not a leak. Looks like a leak.
|
||||||
n.skipWS ();
|
n.skipWS ();
|
||||||
while (n.skip (','))
|
while (n.skip (','))
|
||||||
|
@ -194,7 +192,7 @@ json::array* json::array::parse (Nibbler& nibbler)
|
||||||
|
|
||||||
if ((value = json::value::parse (n)))
|
if ((value = json::value::parse (n)))
|
||||||
{
|
{
|
||||||
arr->push_back (value);
|
arr->_data.push_back (value);
|
||||||
n.skipWS ();
|
n.skipWS ();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -232,11 +230,11 @@ std::string json::array::dump ()
|
||||||
output += "[";
|
output += "[";
|
||||||
|
|
||||||
std::vector <json::value*>::iterator i;
|
std::vector <json::value*>::iterator i;
|
||||||
for (i = ((std::vector <json::value*>*)this)->begin ();
|
for (i = _data.begin ();
|
||||||
i != ((std::vector <json::value*>*)this)->end ();
|
i != _data.end ();
|
||||||
++i)
|
++i)
|
||||||
{
|
{
|
||||||
if (i != ((std::vector <json::value*>*)this)->begin ())
|
if (i != _data.begin ())
|
||||||
output += ",";
|
output += ",";
|
||||||
|
|
||||||
output += (*i)->dump ();
|
output += (*i)->dump ();
|
||||||
|
@ -250,9 +248,7 @@ std::string json::array::dump ()
|
||||||
json::object::~object ()
|
json::object::~object ()
|
||||||
{
|
{
|
||||||
std::map <std::string, json::value*>::iterator i;
|
std::map <std::string, json::value*>::iterator i;
|
||||||
for (i = ((std::map <std::string, json::value*>*)this)->begin ();
|
for (i = _data.begin (); i != _data.end (); ++i)
|
||||||
i != ((std::map <std::string, json::value*>*)this)->end ();
|
|
||||||
++i)
|
|
||||||
delete i->second;
|
delete i->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -271,7 +267,7 @@ json::object* json::object::parse (Nibbler& nibbler)
|
||||||
json::value* value;
|
json::value* value;
|
||||||
if (json::object::parse_pair (n, name, 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.
|
value = NULL; // Not a leak. Looks like a leak.
|
||||||
|
|
||||||
n.skipWS ();
|
n.skipWS ();
|
||||||
|
@ -281,7 +277,7 @@ json::object* json::object::parse (Nibbler& nibbler)
|
||||||
|
|
||||||
if (json::object::parse_pair (n, name, 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));
|
||||||
n.skipWS ();
|
n.skipWS ();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -348,11 +344,9 @@ std::string json::object::dump ()
|
||||||
output += "{";
|
output += "{";
|
||||||
|
|
||||||
std::map <std::string, json::value*>::iterator i;
|
std::map <std::string, json::value*>::iterator i;
|
||||||
for (i = ((std::map <std::string, json::value*>*)this)->begin ();
|
for (i = _data.begin (); i != _data.end (); ++i)
|
||||||
i != ((std::map <std::string, json::value*>*)this)->end ();
|
|
||||||
++i)
|
|
||||||
{
|
{
|
||||||
if (i != ((std::map <std::string, json::value*>*)this)->begin ())
|
if (i != _data.begin ())
|
||||||
output += ",";
|
output += ",";
|
||||||
|
|
||||||
output += "\"" + i->first + "\":";
|
output += "\"" + i->first + "\":";
|
||||||
|
|
34
src/JSON.h
34
src/JSON.h
|
@ -38,12 +38,12 @@ namespace json
|
||||||
{
|
{
|
||||||
enum jtype
|
enum jtype
|
||||||
{
|
{
|
||||||
j_value,
|
j_value, // 0
|
||||||
j_object,
|
j_object, // 1
|
||||||
j_array,
|
j_array, // 2
|
||||||
j_string,
|
j_string, // 3
|
||||||
j_number,
|
j_number, // 4
|
||||||
j_literal
|
j_literal // 5
|
||||||
};
|
};
|
||||||
|
|
||||||
class value
|
class value
|
||||||
|
@ -56,7 +56,7 @@ namespace json
|
||||||
virtual std::string dump ();
|
virtual std::string dump ();
|
||||||
};
|
};
|
||||||
|
|
||||||
class string : public value, public std::string
|
class string : public value
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
string () {}
|
string () {}
|
||||||
|
@ -65,9 +65,12 @@ namespace json
|
||||||
static string* parse (Nibbler&);
|
static string* parse (Nibbler&);
|
||||||
jtype type ();
|
jtype type ();
|
||||||
std::string dump ();
|
std::string dump ();
|
||||||
|
|
||||||
|
public:
|
||||||
|
std::string _data;
|
||||||
};
|
};
|
||||||
|
|
||||||
class number : public value, public std::string
|
class number : public value
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
number () : _dvalue (0.0) {}
|
number () : _dvalue (0.0) {}
|
||||||
|
@ -77,6 +80,7 @@ namespace json
|
||||||
std::string dump ();
|
std::string dump ();
|
||||||
operator double () const;
|
operator double () const;
|
||||||
|
|
||||||
|
public:
|
||||||
double _dvalue;
|
double _dvalue;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -89,11 +93,12 @@ namespace json
|
||||||
jtype type ();
|
jtype type ();
|
||||||
std::string dump ();
|
std::string dump ();
|
||||||
|
|
||||||
|
public:
|
||||||
enum literal_value {none, nullvalue, falsevalue, truevalue};
|
enum literal_value {none, nullvalue, falsevalue, truevalue};
|
||||||
literal_value _lvalue;
|
literal_value _lvalue;
|
||||||
};
|
};
|
||||||
|
|
||||||
class array : public value, public std::vector <value*>
|
class array : public value
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
array () {}
|
array () {}
|
||||||
|
@ -101,9 +106,12 @@ namespace json
|
||||||
static array* parse (Nibbler&);
|
static array* parse (Nibbler&);
|
||||||
jtype type ();
|
jtype type ();
|
||||||
std::string dump ();
|
std::string dump ();
|
||||||
|
|
||||||
|
public:
|
||||||
|
std::vector <value*> _data;
|
||||||
};
|
};
|
||||||
|
|
||||||
class object : public value, public std::map <std::string, value*>
|
class object : public value
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
object () {}
|
object () {}
|
||||||
|
@ -112,6 +120,9 @@ namespace json
|
||||||
static bool parse_pair (Nibbler&, std::string&, value*&);
|
static bool parse_pair (Nibbler&, std::string&, value*&);
|
||||||
jtype type ();
|
jtype type ();
|
||||||
std::string dump ();
|
std::string dump ();
|
||||||
|
|
||||||
|
public:
|
||||||
|
std::map <std::string, value*> _data;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Parser entry point.
|
// Parser entry point.
|
||||||
|
@ -122,9 +133,6 @@ namespace json
|
||||||
std::string decode (const std::string&);
|
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::vector <json::value*>::iterator json_array_iter;
|
||||||
typedef std::map <std::string, json::value*>::iterator json_object_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)
|
std::string Task::statusToText (Task::status s)
|
||||||
{
|
{
|
||||||
if (s == Task::pending) return "pending"; // TODO i18n
|
if (s == Task::pending) return "pending";
|
||||||
else if (s == Task::completed) return "completed"; // TODO i18n
|
else if (s == Task::completed) return "completed";
|
||||||
else if (s == Task::deleted) return "deleted"; // TODO i18n
|
else if (s == Task::deleted) return "deleted";
|
||||||
else if (s == Task::recurring) return "recurring"; // TODO i18n
|
else if (s == Task::recurring) return "recurring";
|
||||||
else if (s == Task::waiting) return "waiting"; // TODO i18n
|
else if (s == Task::waiting) return "waiting";
|
||||||
|
|
||||||
return "pending";
|
return "pending";
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
#include <JSON.h>
|
#include <JSON.h>
|
||||||
#include <text.h>
|
#include <text.h>
|
||||||
#include <util.h>
|
#include <util.h>
|
||||||
|
#include <i18n.h>
|
||||||
#include <main.h>
|
#include <main.h>
|
||||||
#include <CmdImport.h>
|
#include <CmdImport.h>
|
||||||
|
|
||||||
|
@ -42,7 +43,7 @@ CmdImport::CmdImport ()
|
||||||
{
|
{
|
||||||
_keyword = "import";
|
_keyword = "import";
|
||||||
_usage = "task import <file> [<file> ...]";
|
_usage = "task import <file> [<file> ...]";
|
||||||
_description = "Imports JSON files.";
|
_description = STRING_CMD_IMPORT_USAGE;
|
||||||
_read_only = false;
|
_read_only = false;
|
||||||
_displays_id = false;
|
_displays_id = false;
|
||||||
}
|
}
|
||||||
|
@ -94,36 +95,100 @@ int CmdImport::execute (std::string& output)
|
||||||
|
|
||||||
// Parse the whole thing.
|
// Parse the whole thing.
|
||||||
json::value* root = json::parse (object);
|
json::value* root = json::parse (object);
|
||||||
std::cout << root->dump ()
|
if (root->type () == json::j_object)
|
||||||
<< "\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)
|
|
||||||
{
|
{
|
||||||
|
json::object* root_obj = (json::object*)root;
|
||||||
Task task;
|
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;
|
delete root;
|
||||||
root = NULL;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
context.tdb2.commit ();
|
||||||
return rc;
|
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_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_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_DENO_NOMATCH "Did not find any matching annotation to be deleted for '{1}'."
|
||||||
|
#define STRING_CMD_IMPORT_USAGE "Imports JSON files."
|
||||||
|
|
||||||
// Config
|
// Config
|
||||||
#define STRING_CONFIG_OVERNEST "Configuration file nested to more than 10 levels deep - this has to be a mistake."
|
#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