1
0
mirror of https://github.com/djcb/mu.git synced 2024-06-28 07:41:04 +02:00

mu-find: internal cleanups / modernization

use fmt and Result-based APIs.
This commit is contained in:
Dirk-Jan C. Binnema 2023-07-25 21:23:30 +03:00
parent 11c807f955
commit 23ba61a650

View File

@ -1,5 +1,5 @@
/* /*
** Copyright (C) 2008-2022 Dirk-Jan C. Binnema <djcb@djcbsoftware.nl> ** Copyright (C) 2008-2023 Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
** **
** This program is free software; you can redistribute it and/or modify it ** This program is free software; you can redistribute it and/or modify it
** under the terms of the GNU General Public License as published by the ** under the terms of the GNU General Public License as published by the
@ -55,8 +55,8 @@ struct OutputInfo {
constexpr auto FirstOutput{OutputInfo{0, true, false, {}, {}}}; constexpr auto FirstOutput{OutputInfo{0, true, false, {}, {}}};
constexpr auto LastOutput{OutputInfo{0, false, true, {}, {}}}; constexpr auto LastOutput{OutputInfo{0, false, true, {}, {}}};
using OutputFunc = std::function<bool(const Option<Message>& msg, const OutputInfo&, using OutputFunc = std::function<Result<void>(const Option<Message>& msg, const OutputInfo&,
const Options&, GError**)>; const Options&)>;
using Format = Options::Find::Format; using Format = Options::Find::Format;
@ -66,7 +66,7 @@ print_internal(const Store& store,
bool xapian, bool xapian,
bool warn) bool warn)
{ {
std::cout << store.parse_query(expr, xapian) << "\n"; mu_println("{}", store.parse_query(expr, xapian));
return Ok(); return Ok();
} }
@ -88,25 +88,25 @@ run_query(const Store& store, const std::string& expr, const Options& opts)
qflags, opts.find.maxnum.value_or(0)); qflags, opts.find.maxnum.value_or(0));
} }
static bool static Result<void>
exec_cmd(const Option<Message>& msg, const OutputInfo& info, const Options& opts, GError** err) exec_cmd(const Option<Message>& msg, const OutputInfo& info, const Options& opts)
{ {
if (!msg) if (!msg)
return true; return Ok();
gint status; int wait_status{};
char * cmdline, *escpath; GError *err{};
bool rv; auto cmdline{mu_format("{} {}", opts.find.exec,
to_string_gchar(g_shell_quote(msg->path().c_str())))};
escpath = g_shell_quote(msg->path().c_str()); if (!g_spawn_command_line_sync(cmdline.c_str(), {}, {}, &wait_status, &err))
cmdline = g_strdup_printf("%s %s", opts.find.exec.c_str(), escpath); return Err(Error::Code::File, &err/*consumed*/,
"failed to execute shell command");
rv = g_spawn_command_line_sync(cmdline, NULL, NULL, &status, err); else if (WEXITSTATUS(wait_status) != 0)
return Err(Error::Code::File,
g_free(cmdline); "shell command exited with exit-code {}",
g_free(escpath); WEXITSTATUS(wait_status));
return Ok();
return rv;
} }
static Result<std::string> static Result<std::string>
@ -149,45 +149,39 @@ get_query(const Options& opts)
return Ok(bookmark + query); return Ok(bookmark + query);
} }
static bool static Result<void>
prepare_links(const Options& opts, GError** err) prepare_links(const Options& opts)
{ {
/* note, mu_maildir_mkdir simply ignores whatever part of the /* note, mu_maildir_mkdir simply ignores whatever part of the
* mail dir already exists */ * mail dir already exists */
if (auto&& res = maildir_mkdir(opts.find.linksdir, 0700, true); !res) { if (auto&& res = maildir_mkdir(opts.find.linksdir, 0700, true); !res)
res.error().fill_g_error(err); return Err(std::move(res.error()));
return false;
}
if (!opts.find.clearlinks) if (!opts.find.clearlinks)
return false; return Ok();
if (auto&& res = maildir_clear_links(opts.find.linksdir); !res) { if (auto&& res = maildir_clear_links(opts.find.linksdir); !res)
res.error().fill_g_error(err); return Err(std::move(res.error()));
return false;
}
return true; return Ok();
} }
static bool static Result<void>
output_link(const Option<Message>& msg, const OutputInfo& info, const Options& opts, GError** err) output_link(const Option<Message>& msg, const OutputInfo& info, const Options& opts)
{ {
if (info.header) if (info.header)
return prepare_links(opts, err); return prepare_links(opts);
else if (info.footer) else if (info.footer)
return true; return Ok();
/* during test, do not create "unique names" (i.e., names with path /* during test, do not create "unique names" (i.e., names with path
* hashes), so we get a predictable result */ * hashes), so we get a predictable result */
const auto unique_names{!g_getenv("MU_TEST")&&!g_test_initialized()}; const auto unique_names{!g_getenv("MU_TEST")&&!g_test_initialized()};
if (auto&& res = maildir_link(msg->path(), opts.find.linksdir, unique_names); !res) { if (auto&& res = maildir_link(msg->path(), opts.find.linksdir, unique_names); !res)
res.error().fill_g_error(err); return Err(std::move(res.error()));
return false;
}
return true; return Ok();
} }
static void static void
@ -322,12 +316,12 @@ output_plain_fields(const Message& msg, const std::string& fields,
fputs("\n", stdout); fputs("\n", stdout);
} }
static bool static Result<void>
output_plain(const Option<Message>& msg, const OutputInfo& info, output_plain(const Option<Message>& msg, const OutputInfo& info,
const Options& opts, GError** err) const Options& opts)
{ {
if (!msg) if (!msg)
return true; return Ok();
/* we reuse the color (whatever that may be) /* we reuse the color (whatever that may be)
* for message-priority for threads, too */ * for message-priority for threads, too */
@ -340,11 +334,11 @@ output_plain(const Option<Message>& msg, const OutputInfo& info,
if (opts.view.summary_len) if (opts.view.summary_len)
print_summary(*msg, opts); print_summary(*msg, opts);
return true; return Ok();
} }
static bool static Result<void>
output_sexp(const Option<Message>& msg, const OutputInfo& info, const Options& opts, GError** err) output_sexp(const Option<Message>& msg, const OutputInfo& info, const Options& opts)
{ {
if (msg) { if (msg) {
if (const auto sexp{msg->sexp()}; !sexp.empty()) if (const auto sexp{msg->sexp()}; !sexp.empty())
@ -354,28 +348,28 @@ output_sexp(const Option<Message>& msg, const OutputInfo& info, const Options& o
fputs("\n", stdout); fputs("\n", stdout);
} }
return true; return Ok();
} }
static bool static Result<void>
output_json(const Option<Message>& msg, const OutputInfo& info, const Options& opts, GError** err) output_json(const Option<Message>& msg, const OutputInfo& info, const Options& opts)
{ {
if (info.header) { if (info.header) {
mu_println("["); mu_println("[");
return true; return Ok();
} }
if (info.footer) { if (info.footer) {
mu_println("]"); mu_println("]");
return true; return Ok();
} }
if (!msg) if (!msg)
return true; return Ok();
mu_println("{}{}", msg->sexp().to_json_string(), info.last ? "" : ","); mu_println("{}{}", msg->sexp().to_json_string(), info.last ? "" : ",");
return true; return Ok();
} }
static void static void
@ -388,18 +382,18 @@ print_attr_xml(const std::string& elm, const std::string& str)
mu_println("\t\t<{}>{}</{}>", elm, esc.value_or(""), elm); mu_println("\t\t<{}>{}</{}>", elm, esc.value_or(""), elm);
} }
static bool static Result<void>
output_xml(const Option<Message>& msg, const OutputInfo& info, const Options& opts, GError** err) output_xml(const Option<Message>& msg, const OutputInfo& info, const Options& opts)
{ {
if (info.header) { if (info.header) {
mu_println("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>"); mu_println("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>");
mu_println("<messages>"); mu_println("<messages>");
return true; return Ok();
} }
if (info.footer) { if (info.footer) {
mu_println("</messages>"); mu_println("</messages>");
return true; return Ok();
} }
mu_println("\t<message>"); mu_println("\t<message>");
@ -414,37 +408,43 @@ output_xml(const Option<Message>& msg, const OutputInfo& info, const Options& op
print_attr_xml("maildir", msg->maildir()); print_attr_xml("maildir", msg->maildir());
mu_println("\t</message>"); mu_println("\t</message>");
return true; return Ok();
} }
static OutputFunc static OutputFunc
get_output_func(const Options& opts, GError** err) get_output_func(const Options& opts)
{ {
if (!opts.find.exec.empty()) if (!opts.find.exec.empty())
return exec_cmd; return exec_cmd;
switch (opts.find.format) { switch (opts.find.format) {
case Format::Links: return output_link; case Format::Links:
case Format::Plain: return output_plain; return output_link;
case Format::Xml: return output_xml; case Format::Plain:
case Format::Sexp: return output_sexp; return output_plain;
case Format::Json: return output_json; case Format::Xml:
default: g_return_val_if_reached(NULL); return NULL; return output_xml;
case Format::Sexp:
return output_sexp;
case Format::Json:
return output_json;
default:
throw Error(Error::Code::Internal,
"invalid format {}",
static_cast<size_t>(opts.find.format));
} }
} }
static Result<void> static Result<void>
output_query_results(const QueryResults& qres, const Options& opts) output_query_results(const QueryResults& qres, const Options& opts)
{ {
GError* err{}; GError* err{};
const auto output_func{get_output_func(opts, &err)}; const auto output_func{get_output_func(opts)};
if (!output_func) if (!output_func)
return Err(Error::Code::Query, &err, "failed to find output function"); return Err(Error::Code::Query, &err, "failed to find output function");
bool rv{true}; if (auto&& res = output_func(Nothing, FirstOutput, opts); !res)
output_func(Nothing, FirstOutput, opts, {}); return Err(std::move(res.error()));
size_t n{0}; size_t n{0};
for (auto&& item : qres) { for (auto&& item : qres) {
@ -456,24 +456,20 @@ output_query_results(const QueryResults& qres, const Options& opts)
if (msg->changed() < opts.find.after.value_or(0)) if (msg->changed() < opts.find.after.value_or(0))
continue; continue;
rv = output_func(msg, if (auto&& res = output_func(msg,
{item.doc_id(), {item.doc_id(),
false, false,
false, false,
n == qres.size(), /* last? */ n == qres.size(), /* last? */
item.query_match()}, item.query_match()},
opts, opts); !res)
&err); return Err(std::move(res.error()));
if (!rv)
break;
} }
output_func(Nothing, LastOutput, opts, {});
if (auto&& res{output_func(Nothing, LastOutput, opts)}; !res)
if (rv) return Err(std::move(res.error()));
return Ok();
else else
return Err(Error::Code::Query, &err, "error in query results output"); return Ok();
} }
static Result<void> static Result<void>