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:
parent
11c807f955
commit
23ba61a650
|
@ -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>
|
||||||
|
|
Loading…
Reference in New Issue
Block a user