mirror of https://github.com/djcb/mu.git
mu: support json output directly
Allow for dumping json directly from the Sexp structures, so we don't need any external libs (i.e. json-glib) anymore.
This commit is contained in:
parent
f2e87ea2d4
commit
d2aa1f91b0
12
configure.ac
12
configure.ac
|
@ -146,14 +146,6 @@ glib_version="$($PKG_CONFIG --modversion glib-2.0)"
|
||||||
PKG_CHECK_MODULES(GMIME,gmime-3.0)
|
PKG_CHECK_MODULES(GMIME,gmime-3.0)
|
||||||
gmime_version="$($PKG_CONFIG --modversion gmime-3.0)"
|
gmime_version="$($PKG_CONFIG --modversion gmime-3.0)"
|
||||||
|
|
||||||
# gmime, version 3.0 or higher
|
|
||||||
PKG_CHECK_MODULES(JSON_GLIB,json-glib-1.0 >= 1.4,[have_json_glib=yes],[have_json_glib=no])
|
|
||||||
AS_IF([test "x$have_json_glib" = "xyes"],[
|
|
||||||
json_glib_version="$($PKG_CONFIG --modversion json-glib-1.0)"
|
|
||||||
AC_DEFINE(HAVE_JSON_GLIB,[1], [Do we support json-glib?])
|
|
||||||
])
|
|
||||||
AM_CONDITIONAL(HAVE_JSON_GLIB,[test "x$have_json_glib" = "xyes"])
|
|
||||||
|
|
||||||
# xapian checking - we need 1.4 at least
|
# xapian checking - we need 1.4 at least
|
||||||
PKG_CHECK_MODULES(XAPIAN,xapian-core >= 1.4,[
|
PKG_CHECK_MODULES(XAPIAN,xapian-core >= 1.4,[
|
||||||
have_xapian=yes
|
have_xapian=yes
|
||||||
|
@ -296,10 +288,6 @@ echo "Xapian version : $xapian_version"
|
||||||
echo "GLib version : $glib_version"
|
echo "GLib version : $glib_version"
|
||||||
echo "GMime version : $gmime_version"
|
echo "GMime version : $gmime_version"
|
||||||
|
|
||||||
AM_COND_IF([HAVE_JSON_GLIB],[
|
|
||||||
echo "Json-Glib version : $json_glib_version"
|
|
||||||
])
|
|
||||||
|
|
||||||
AM_COND_IF([BUILD_GUI],[
|
AM_COND_IF([BUILD_GUI],[
|
||||||
echo "GTK+ version : $gtk_version"
|
echo "GTK+ version : $gtk_version"
|
||||||
echo "Webkit2/GTK+ version : $webkit_version"
|
echo "Webkit2/GTK+ version : $webkit_version"
|
||||||
|
|
|
@ -20,13 +20,6 @@ include $(top_srcdir)/gtest.mk
|
||||||
|
|
||||||
SUBDIRS= utils query index
|
SUBDIRS= utils query index
|
||||||
|
|
||||||
if HAVE_JSON_GLIB
|
|
||||||
json_srcs= \
|
|
||||||
mu-msg-json.c \
|
|
||||||
mu-msg-json.h
|
|
||||||
json_flag="-DHAVE_JSON_GLIB"
|
|
||||||
endif
|
|
||||||
|
|
||||||
TESTDEFS= \
|
TESTDEFS= \
|
||||||
-DMU_TESTMAILDIR=\"${abs_srcdir}/testdir\" \
|
-DMU_TESTMAILDIR=\"${abs_srcdir}/testdir\" \
|
||||||
-DMU_TESTMAILDIR2=\"${abs_srcdir}/testdir2\" \
|
-DMU_TESTMAILDIR2=\"${abs_srcdir}/testdir2\" \
|
||||||
|
|
|
@ -478,5 +478,14 @@ mu_msg_to_sexp (MuMsg *msg, unsigned docid, const MuMsgIterThreadInfo *ti,
|
||||||
MuMsgOptions opts)
|
MuMsgOptions opts)
|
||||||
{
|
{
|
||||||
return g_strdup (Mu::msg_to_sexp (msg, docid, ti, opts)
|
return g_strdup (Mu::msg_to_sexp (msg, docid, ti, opts)
|
||||||
.to_string().c_str());
|
.to_sexp_string().c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
char*
|
||||||
|
mu_msg_to_json (MuMsg *msg, unsigned docid, const MuMsgIterThreadInfo *ti,
|
||||||
|
MuMsgOptions opts)
|
||||||
|
{
|
||||||
|
return g_strdup (Mu::msg_to_sexp (msg, docid, ti, opts)
|
||||||
|
.to_json_string().c_str());
|
||||||
}
|
}
|
||||||
|
|
10
lib/mu-msg.h
10
lib/mu-msg.h
|
@ -595,10 +595,6 @@ char* mu_str_flags (MuFlags flags)
|
||||||
|
|
||||||
struct _MuMsgIterThreadInfo;
|
struct _MuMsgIterThreadInfo;
|
||||||
|
|
||||||
#ifdef HAVE_JSON_GLIB
|
|
||||||
|
|
||||||
struct _JsonNode; /* forward declaration */
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* convert the msg to json
|
* convert the msg to json
|
||||||
*
|
*
|
||||||
|
@ -612,13 +608,11 @@ struct _JsonNode; /* forward declaration */
|
||||||
* - MU_MSG_OPTION_EXTRACT_IMAGES: extract image attachments as temporary
|
* - MU_MSG_OPTION_EXTRACT_IMAGES: extract image attachments as temporary
|
||||||
* files and include links to those in the sexp
|
* files and include links to those in the sexp
|
||||||
*
|
*
|
||||||
* @return a string with the sexp (free with g_free) or NULL in case of error
|
* @return a string with the json (free with g_free) or NULL in case of error
|
||||||
*/
|
*/
|
||||||
struct _JsonNode* mu_msg_to_json (MuMsg *msg, unsigned docid,
|
char* mu_msg_to_json (MuMsg *msg, unsigned docid,
|
||||||
const struct _MuMsgIterThreadInfo *ti,
|
const struct _MuMsgIterThreadInfo *ti,
|
||||||
MuMsgOptions ops) G_GNUC_WARN_UNUSED_RESULT;
|
MuMsgOptions ops) G_GNUC_WARN_UNUSED_RESULT;
|
||||||
#endif /*HAVE_JSON_GLIB*/
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* convert the msg to a Lisp symbolic expression (for further processing in
|
* convert the msg to a Lisp symbolic expression (for further processing in
|
||||||
|
|
|
@ -33,7 +33,7 @@ Command::invoke(const Command::CommandMap& cmap, const Sexp& call)
|
||||||
if (!call.is_call()) {
|
if (!call.is_call()) {
|
||||||
throw Mu::Error{Error::Code::Command,
|
throw Mu::Error{Error::Code::Command,
|
||||||
"expected call-sexpr but got %s",
|
"expected call-sexpr but got %s",
|
||||||
call.to_string().c_str()};
|
call.to_sexp_string().c_str()};
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto& params{call.list()};
|
const auto& params{call.list()};
|
||||||
|
@ -41,7 +41,7 @@ Command::invoke(const Command::CommandMap& cmap, const Sexp& call)
|
||||||
if (cmd_it == cmap.end())
|
if (cmd_it == cmap.end())
|
||||||
throw Mu::Error{Error::Code::Command,
|
throw Mu::Error{Error::Code::Command,
|
||||||
"unknown command in call %s",
|
"unknown command in call %s",
|
||||||
call.to_string().c_str()};
|
call.to_sexp_string().c_str()};
|
||||||
|
|
||||||
const auto& cinfo{cmd_it->second};
|
const auto& cinfo{cmd_it->second};
|
||||||
|
|
||||||
|
@ -67,7 +67,7 @@ Command::invoke(const Command::CommandMap& cmap, const Sexp& call)
|
||||||
if (arginfo.required)
|
if (arginfo.required)
|
||||||
throw Mu::Error{Error::Code::Command,
|
throw Mu::Error{Error::Code::Command,
|
||||||
"missing required parameter %s in call %s",
|
"missing required parameter %s in call %s",
|
||||||
argname.c_str(), call.to_string().c_str()};
|
argname.c_str(), call.to_sexp_string().c_str()};
|
||||||
continue; // not required
|
continue; // not required
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,7 +78,7 @@ Command::invoke(const Command::CommandMap& cmap, const Sexp& call)
|
||||||
"parameter %s expects type %s, but got %s in call %s",
|
"parameter %s expects type %s, but got %s in call %s",
|
||||||
argname.c_str(), to_string(arginfo.type).c_str(),
|
argname.c_str(), to_string(arginfo.type).c_str(),
|
||||||
to_string(param_it->type()).c_str(),
|
to_string(param_it->type()).c_str(),
|
||||||
call.to_string().c_str()};
|
call.to_sexp_string().c_str()};
|
||||||
}
|
}
|
||||||
|
|
||||||
// all passed parameters must be known
|
// all passed parameters must be known
|
||||||
|
@ -87,7 +87,7 @@ Command::invoke(const Command::CommandMap& cmap, const Sexp& call)
|
||||||
[&](auto&& arg) {return params.at(i).value() == arg.first;}))
|
[&](auto&& arg) {return params.at(i).value() == arg.first;}))
|
||||||
throw Mu::Error{Error::Code::Command,
|
throw Mu::Error{Error::Code::Command,
|
||||||
"unknown parameter %s in call %s",
|
"unknown parameter %s in call %s",
|
||||||
params.at(i).value().c_str(), call.to_string().c_str()};
|
params.at(i).value().c_str(), call.to_sexp_string().c_str()};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cinfo.handler)
|
if (cinfo.handler)
|
||||||
|
|
|
@ -179,7 +179,7 @@ Sexp::make_parse (const std::string& expr)
|
||||||
|
|
||||||
|
|
||||||
std::string
|
std::string
|
||||||
Sexp::to_string () const
|
Sexp::to_sexp_string () const
|
||||||
{
|
{
|
||||||
std::stringstream sstrm;
|
std::stringstream sstrm;
|
||||||
|
|
||||||
|
@ -188,7 +188,7 @@ Sexp::to_string () const
|
||||||
sstrm << '(';
|
sstrm << '(';
|
||||||
bool first{true};
|
bool first{true};
|
||||||
for (auto&& child : list()) {
|
for (auto&& child : list()) {
|
||||||
sstrm << (first ? "" : " ") << child.to_string();
|
sstrm << (first ? "" : " ") << child.to_sexp_string();
|
||||||
first = false;
|
first = false;
|
||||||
}
|
}
|
||||||
sstrm << ')';
|
sstrm << ')';
|
||||||
|
@ -206,3 +206,55 @@ Sexp::to_string () const
|
||||||
|
|
||||||
return sstrm.str();
|
return sstrm.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::string
|
||||||
|
Sexp::to_json_string () const
|
||||||
|
{
|
||||||
|
std::stringstream sstrm;
|
||||||
|
|
||||||
|
switch (type()) {
|
||||||
|
case Type::List: {
|
||||||
|
// property-lists become JSON objects
|
||||||
|
if (is_prop_list()) {
|
||||||
|
sstrm << "{";
|
||||||
|
auto it{list().begin()};
|
||||||
|
bool first{true};
|
||||||
|
while (it != list().end()) {
|
||||||
|
sstrm << (first?"":",") << quote(it->value()) << ":";
|
||||||
|
++it;
|
||||||
|
sstrm << it->to_json_string();
|
||||||
|
++it;
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
sstrm << "}";
|
||||||
|
} else { // other lists become arrays.
|
||||||
|
sstrm << '[';
|
||||||
|
bool first{true};
|
||||||
|
for (auto&& child : list()) {
|
||||||
|
sstrm << (first ? "" : ", ") << child.to_json_string();
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
sstrm << ']';
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Type::String:
|
||||||
|
sstrm << quote(value());
|
||||||
|
break;
|
||||||
|
case Type::Symbol:
|
||||||
|
if (is_nil())
|
||||||
|
sstrm << "false";
|
||||||
|
else if (is_t())
|
||||||
|
sstrm << "true";
|
||||||
|
else
|
||||||
|
sstrm << quote(value());
|
||||||
|
break;
|
||||||
|
case Type::Number:
|
||||||
|
case Type::Empty:
|
||||||
|
default:
|
||||||
|
sstrm << value();
|
||||||
|
}
|
||||||
|
|
||||||
|
return sstrm.str();
|
||||||
|
}
|
||||||
|
|
|
@ -104,11 +104,19 @@ struct Sexp {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert a Sexp::Node to its string representation
|
* Convert a Sexp::Node to its S-expression string representation
|
||||||
*
|
*
|
||||||
* @return the string representation
|
* @return the string representation
|
||||||
*/
|
*/
|
||||||
std::string to_string() const;
|
std::string to_sexp_string() const;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a Sexp::Node to its JSON string representation
|
||||||
|
*
|
||||||
|
* @return the string representation
|
||||||
|
*/
|
||||||
|
std::string to_json_string() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the type of this Node.
|
* Return the type of this Node.
|
||||||
|
@ -341,7 +349,7 @@ operator<<(std::ostream& os, Sexp::Type id)
|
||||||
static inline std::ostream&
|
static inline std::ostream&
|
||||||
operator<<(std::ostream& os, const Sexp& sexp)
|
operator<<(std::ostream& os, const Sexp& sexp)
|
||||||
{
|
{
|
||||||
os << sexp.to_string();
|
os << sexp.to_sexp_string();
|
||||||
return os;
|
return os;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -63,17 +63,17 @@ test_list()
|
||||||
const auto nstr{Sexp::make_string("foo")};
|
const auto nstr{Sexp::make_string("foo")};
|
||||||
g_assert_true(nstr.value() == "foo");
|
g_assert_true(nstr.value() == "foo");
|
||||||
g_assert_true(nstr.type() == Sexp::Type::String);
|
g_assert_true(nstr.type() == Sexp::Type::String);
|
||||||
assert_equal(nstr.to_string(), "\"foo\"");
|
assert_equal(nstr.to_sexp_string(), "\"foo\"");
|
||||||
|
|
||||||
const auto nnum{Sexp::make_number(123)};
|
const auto nnum{Sexp::make_number(123)};
|
||||||
g_assert_true(nnum.value() == "123");
|
g_assert_true(nnum.value() == "123");
|
||||||
g_assert_true(nnum.type() == Sexp::Type::Number);
|
g_assert_true(nnum.type() == Sexp::Type::Number);
|
||||||
assert_equal(nnum.to_string(), "123");
|
assert_equal(nnum.to_sexp_string(), "123");
|
||||||
|
|
||||||
const auto nsym{Sexp::make_symbol("blub")};
|
const auto nsym{Sexp::make_symbol("blub")};
|
||||||
g_assert_true(nsym.value() == "blub");
|
g_assert_true(nsym.value() == "blub");
|
||||||
g_assert_true(nsym.type() == Sexp::Type::Symbol);
|
g_assert_true(nsym.type() == Sexp::Type::Symbol);
|
||||||
assert_equal(nsym.to_string(), "blub");
|
assert_equal(nsym.to_sexp_string(), "blub");
|
||||||
|
|
||||||
Sexp::List list;
|
Sexp::List list;
|
||||||
list .add(Sexp::make_string("foo"))
|
list .add(Sexp::make_string("foo"))
|
||||||
|
@ -85,7 +85,7 @@ test_list()
|
||||||
g_assert_true(nlst.type() == Sexp::Type::List);
|
g_assert_true(nlst.type() == Sexp::Type::List);
|
||||||
g_assert_true(nlst.list().at(1).value() == "123");
|
g_assert_true(nlst.list().at(1).value() == "123");
|
||||||
|
|
||||||
assert_equal(nlst.to_string(),"(\"foo\" 123 blub)");
|
assert_equal(nlst.to_sexp_string(),"(\"foo\" 123 blub)");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -95,7 +95,7 @@ test_prop_list()
|
||||||
Sexp::List l1;
|
Sexp::List l1;
|
||||||
l1.add_prop(":foo", Sexp::make_string("bar"));
|
l1.add_prop(":foo", Sexp::make_string("bar"));
|
||||||
Sexp s2{Sexp::make_list(std::move(l1))};
|
Sexp s2{Sexp::make_list(std::move(l1))};
|
||||||
assert_equal(s2.to_string(), "(:foo \"bar\")");
|
assert_equal(s2.to_sexp_string(), "(:foo \"bar\")");
|
||||||
|
|
||||||
|
|
||||||
Sexp::List l2;
|
Sexp::List l2;
|
||||||
|
@ -105,7 +105,7 @@ test_prop_list()
|
||||||
Sexp::List l3;
|
Sexp::List l3;
|
||||||
l3.add_prop(":cuux", Sexp::make_list(std::move(l2)));
|
l3.add_prop(":cuux", Sexp::make_list(std::move(l2)));
|
||||||
Sexp s3{Sexp::make_list(std::move(l3))};
|
Sexp s3{Sexp::make_list(std::move(l3))};
|
||||||
assert_equal(s3.to_string(), "(:cuux (:foo \"bar\" :bar 77))");
|
assert_equal(s3.to_sexp_string(), "(:cuux (:foo \"bar\" :bar 77))");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -122,7 +122,7 @@ test_props()
|
||||||
":flub", Sexp::make_symbol("fnord"),
|
":flub", Sexp::make_symbol("fnord"),
|
||||||
":boo", std::move(sexp2));
|
":boo", std::move(sexp2));
|
||||||
|
|
||||||
assert_equal(sexp.to_string(),
|
assert_equal(sexp.to_sexp_string(),
|
||||||
"(:foo \"b\303\244r\" :cuux 123 :flub fnord :boo (\"foo\" 123 blub))");
|
"(:foo \"b\303\244r\" :cuux 123 :flub fnord :boo (\"foo\" 123 blub))");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -42,10 +42,6 @@
|
||||||
#include "mu-cmd.hh"
|
#include "mu-cmd.hh"
|
||||||
#include "mu-threader.h"
|
#include "mu-threader.h"
|
||||||
|
|
||||||
#ifdef HAVE_JSON_GLIB
|
|
||||||
#include <json-glib/json-glib.h>
|
|
||||||
#endif /*HAVE_JSON_GLIB*/
|
|
||||||
|
|
||||||
using namespace Mu;
|
using namespace Mu;
|
||||||
|
|
||||||
typedef gboolean (OutputFunc) (MuMsg *msg, MuMsgIter *iter,
|
typedef gboolean (OutputFunc) (MuMsg *msg, MuMsgIter *iter,
|
||||||
|
@ -539,7 +535,6 @@ to_string (const Mu::Sexp& sexp, bool color, size_t level = 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
output_sexp (MuMsg *msg, MuMsgIter *iter, const MuConfig *opts, GError **err)
|
output_sexp (MuMsg *msg, MuMsgIter *iter, const MuConfig *opts, GError **err)
|
||||||
{
|
{
|
||||||
|
@ -555,21 +550,15 @@ output_sexp (MuMsg *msg, MuMsgIter *iter, const MuConfig *opts, GError **err)
|
||||||
static gboolean
|
static gboolean
|
||||||
output_json (MuMsg *msg, MuMsgIter *iter, const MuConfig *opts, GError **err)
|
output_json (MuMsg *msg, MuMsgIter *iter, const MuConfig *opts, GError **err)
|
||||||
{
|
{
|
||||||
#ifdef HAVE_JSON_GLIB
|
|
||||||
JsonNode *node;
|
|
||||||
const MuMsgIterThreadInfo *ti;
|
const MuMsgIterThreadInfo *ti;
|
||||||
char *s;
|
char *s;
|
||||||
|
|
||||||
if (mu_msg_iter_is_first(iter))
|
if (mu_msg_iter_is_first(iter))
|
||||||
g_print ("[\n");
|
g_print ("[\n");
|
||||||
|
|
||||||
ti = opts->threads ? mu_msg_iter_get_thread_info (iter) : NULL;
|
ti = opts->threads ? mu_msg_iter_get_thread_info (iter) : NULL;
|
||||||
node = mu_msg_to_json (msg, mu_msg_iter_get_docid (iter),
|
s = mu_msg_to_json (msg, mu_msg_iter_get_docid (iter),
|
||||||
ti, MU_MSG_OPTION_HEADERS_ONLY);
|
ti, MU_MSG_OPTION_HEADERS_ONLY);
|
||||||
|
|
||||||
s = json_to_string (node, TRUE);
|
|
||||||
json_node_free (node);
|
|
||||||
|
|
||||||
fputs (s, stdout);
|
fputs (s, stdout);
|
||||||
g_free (s);
|
g_free (s);
|
||||||
|
|
||||||
|
@ -579,12 +568,6 @@ output_json (MuMsg *msg, MuMsgIter *iter, const MuConfig *opts, GError **err)
|
||||||
fputs (",\n", stdout);
|
fputs (",\n", stdout);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
#else
|
|
||||||
g_set_error (err, MU_ERROR_DOMAIN, MU_ERROR_IN_PARAMETERS,
|
|
||||||
"this mu was built without json support");
|
|
||||||
return FALSE;
|
|
||||||
#endif /*HAVE_JSON_GLIB*/
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
|
@ -147,7 +147,7 @@ print_expr (const char* frm, ...)
|
||||||
static void
|
static void
|
||||||
print_expr (const Sexp& sexp)
|
print_expr (const Sexp& sexp)
|
||||||
{
|
{
|
||||||
print_expr ("%s", sexp.to_string().c_str());
|
print_expr ("%s", sexp.to_sexp_string().c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
Loading…
Reference in New Issue