rename 'mu label' -> 'mu labels'

Update names, docs etc.
This commit is contained in:
Dirk-Jan C. Binnema
2025-09-08 21:45:39 +03:00
committed by Seth Ladygo
parent 755c453b9f
commit 656aa41ada
13 changed files with 155 additions and 149 deletions

View File

@ -25,7 +25,7 @@ mu = executable(
'mu-cmd-info.cc',
'mu-cmd-init.cc',
'mu-cmd-index.cc',
'mu-cmd-label.cc',
'mu-cmd-labels.cc',
'mu-cmd-mkdir.cc',
'mu-cmd-move.cc',
'mu-cmd-remove.cc',

View File

@ -37,7 +37,7 @@ label_update(Mu::Store& store, const Options& opts)
// First get our list of parsed delta-label, and ensure they
// are valid.
DeltaLabelVec deltas{};
for (auto&& delta_label : opts.label.delta_labels) {
for (auto&& delta_label : opts.labels.delta_labels) {
if (const auto res = parse_delta_label(delta_label); !res)
return Err(Error{Error::Code::InvalidArgument,
"invalid delta-label '{}': {}", delta_label,
@ -46,12 +46,12 @@ label_update(Mu::Store& store, const Options& opts)
deltas.emplace_back(std::move(*res));
}
if (!opts.label.query)
if (!opts.labels.query)
return Err(Error{Error::Code::Query,
"missing query"});
// now run the query and apply the deltas to each.
const auto query{*opts.label.query};
const auto query{*opts.labels.query};
auto results{store.run_query(query)};
if (!results)
return Err(Error{Error::Code::Query,
@ -59,23 +59,23 @@ label_update(Mu::Store& store, const Options& opts)
// seems we got some results... let's apply to each
size_t n{};
const auto labelstr{join(opts.label.delta_labels, " ")};
const auto labelstr{join(opts.labels.delta_labels, " ")};
for (auto&& result : *results) {
if (auto &&msg{result.message()}; msg) {
if (opts.label.dry_run || opts.verbose)
if (opts.labels.dry_run || opts.verbose)
mu_println("labels: apply {} to {}", labelstr, msg->path());
if (!opts.label.dry_run) {
if (!opts.labels.dry_run) {
store.update_labels(*msg, deltas);
}
++n;
}
}
if (opts.verbose || opts.label.dry_run)
if (opts.verbose || opts.labels.dry_run)
mu_println("labels: {}updated {} message(s)",
opts.label.dry_run ? "would have " : "", n);
opts.labels.dry_run ? "would have " : "", n);
return Ok();
}
@ -83,11 +83,11 @@ label_update(Mu::Store& store, const Options& opts)
static Result<void>
label_clear(Mu::Store& store, const Options& opts)
{
if (!opts.label.query)
if (!opts.labels.query)
return Err(Error{Error::Code::Query,
"missing query"});
const auto query{*opts.label.query};
const auto query{*opts.labels.query};
auto results{store.run_query(query)};
if (!results)
return Err(Error{Error::Code::Query,
@ -97,19 +97,19 @@ label_clear(Mu::Store& store, const Options& opts)
for (auto&& result : *results) {
if (auto &&msg{result.message()}; msg) {
if (opts.label.dry_run || opts.verbose)
if (opts.labels.dry_run || opts.verbose)
mu_println("labels: clear all from {}", msg->path());
if (!opts.label.dry_run) {
if (!opts.labels.dry_run) {
store.clear_labels(*msg);
}
++n;
}
}
if (opts.verbose || opts.label.dry_run)
if (opts.verbose || opts.labels.dry_run)
mu_println("labels: {}cleared {} message(s)",
opts.label.dry_run ? "would have " : "", n);
opts.labels.dry_run ? "would have " : "", n);
return Ok();
}
@ -117,14 +117,6 @@ label_clear(Mu::Store& store, const Options& opts)
static Result<void>
label_list(Mu::Store& store, const Options& opts)
{
if (opts.label.restore) {
if (!opts.quiet)
mu_println("labels: restoring list from store...");
if (const auto res = store.restore_label_map(); !res) {
return res;
}
}
for (const auto& [label, n]: store.label_map())
if (opts.verbose)
mu_println("{}: {}", label, n);
@ -134,10 +126,24 @@ label_list(Mu::Store& store, const Options& opts)
return Ok();
}
static Result<void>
label_restore_list(Mu::Store& store, const Options& opts)
{
if (!opts.quiet)
mu_println("labels: restoring list from store...");
if (const auto res = store.restore_label_map(); !res || opts.quiet)
return res;
return label_list(store, opts);
}
static Result<void>
label_export(const Mu::Store& store, const Options& opts)
{
const auto res = export_labels(store, "", opts.label.file);
const auto res = export_labels(store, "", opts.labels.file);
if (!res)
return Err(res.error());
@ -151,27 +157,29 @@ static Result<void>
label_import(Mu::Store& store, const Options& opts)
{
// sanity check, should be caught during arg parsing
if (!opts.label.file)
if (!opts.labels.file)
return Err(Error{Error::Code::InvalidArgument,
"missing input file"});
return Mu::import_labels(store, *opts.label.file,
opts.label.dry_run, opts.quiet, opts.verbose);
return Mu::import_labels(store, *opts.labels.file,
opts.labels.dry_run, opts.quiet, opts.verbose);
}
Result<void>
Mu::mu_cmd_label(Mu::Store &store, const Options &opts)
Mu::mu_cmd_labels(Mu::Store &store, const Options &opts)
{
switch (opts.label.sub) {
case Options::Label::Sub::List:
switch (opts.labels.sub) {
case Options::Labels::Sub::List:
return label_list(store, opts);
case Options::Label::Sub::Update:
case Options::Labels::Sub::RestoreList:
return label_restore_list(store, opts);
case Options::Labels::Sub::Update:
return label_update(store, opts);
case Options::Label::Sub::Clear:
case Options::Labels::Sub::Clear:
return label_clear(store, opts);
case Options::Label::Sub::Export:
case Options::Labels::Sub::Export:
return label_export(store, opts);
case Options::Label::Sub::Import:
case Options::Labels::Sub::Import:
return label_import(store, opts);
default:
@ -193,11 +201,11 @@ Mu::mu_cmd_label(Mu::Store &store, const Options &opts)
static std::string test_mu_home;
static void
test_mu_label_update()
test_mu_labels_update()
{
{
const auto res = run_command({MU_PROGRAM,
"label", "update", "subject:abc",
"labels", "update", "subject:abc",
"--labels", "+foo,-bar",
"--muhome", test_mu_home});
assert_valid_result(res);
@ -223,7 +231,7 @@ test_mu_label_update()
{
const auto res = run_command({MU_PROGRAM,
"label", "update",
"labels", "update",
"subject:abc",
"--labels", "-foo,+bar",
"--muhome", test_mu_home});
@ -250,11 +258,11 @@ test_mu_label_update()
}
static void
test_mu_label_clear()
test_mu_labels_clear()
{
{
const auto res = run_command({MU_PROGRAM,
"label", "update", "subject:abc",
"labels", "update", "subject:abc",
"--labels", "+foo",
"--muhome", test_mu_home});
assert_valid_result(res);
@ -271,7 +279,7 @@ test_mu_label_clear()
}
{
const auto res = run_command({MU_PROGRAM,
"label", "clear", "subject:abc",
"labels", "clear", "subject:abc",
"--muhome", test_mu_home});
assert_valid_result(res);
g_assert_cmpuint(res->exit_code,==,0);
@ -289,11 +297,11 @@ test_mu_label_clear()
static void
test_mu_label_list()
test_mu_labels_list()
{
{
const auto res = run_command({MU_PROGRAM,
"label", "update", "subject:abc",
"labels", "update", "subject:abc",
"--labels", "+foo,-bar,+cuux,+fnorb",
"--muhome", test_mu_home});
assert_valid_result(res);
@ -302,7 +310,7 @@ test_mu_label_list()
{
const auto res = run_command({MU_PROGRAM,
"label", "update", "subject:abc",
"labels", "update", "subject:abc",
"--labels", "-cuux",
"--muhome", test_mu_home});
assert_valid_result(res);
@ -312,7 +320,7 @@ test_mu_label_list()
{
const auto res = run_command({MU_PROGRAM,
"label", "list",
"labels", "list",
"--muhome", test_mu_home});
assert_valid_result(res);
g_assert_cmpuint(res->exit_code,==,0);
@ -322,7 +330,7 @@ test_mu_label_list()
}
static void
test_mu_label_export_import()
test_mu_labels_export_import()
{
TempDir temp_dir{};
const auto exportfile{join_paths(temp_dir.path(), "export.txt")};
@ -330,7 +338,7 @@ test_mu_label_export_import()
// ensure there are some labels (from previous test)
{
const auto res = run_command({MU_PROGRAM,
"label", "list",
"labels", "list",
"--muhome", test_mu_home});
assert_valid_result(res);
g_assert_cmpuint(res->exit_code,==,0);
@ -342,7 +350,7 @@ test_mu_label_export_import()
// fnorb,foo
{
const auto res = run_command({MU_PROGRAM,
"label", "export", exportfile,
"labels", "export", exportfile,
"--muhome", test_mu_home});
assert_valid_result(res);
g_assert_cmpuint(res->exit_code,==,0);
@ -362,7 +370,7 @@ test_mu_label_export_import()
// ensure the labels are gone.
{
const auto res = run_command({MU_PROGRAM,
"label", "list",
"labels", "list",
"--muhome", test_mu_home});
assert_valid_result(res);
g_assert_cmpuint(res->exit_code,==,0);
@ -372,7 +380,7 @@ test_mu_label_export_import()
// import the labels
{
const auto res = run_command({MU_PROGRAM,
"label", "import", exportfile,
"labels", "import", exportfile,
"--muhome", test_mu_home});
assert_valid_result(res);
g_assert_cmpuint(res->exit_code,==,0);
@ -381,7 +389,7 @@ test_mu_label_export_import()
// ensure the label are back
{
const auto res = run_command({MU_PROGRAM,
"label", "list",
"labels", "list",
"--muhome", test_mu_home});
assert_valid_result(res);
g_assert_cmpuint(res->exit_code,==,0);
@ -410,10 +418,10 @@ main(int argc, char* argv[])
assert_valid_result(res2);
}
g_test_add_func("/cmd/label/update", test_mu_label_update);
g_test_add_func("/cmd/label/clear", test_mu_label_clear);
g_test_add_func("/cmd/label/list", test_mu_label_list);
g_test_add_func("/cmd/label/export-import", test_mu_label_export_import);
g_test_add_func("/cmd/labels/update", test_mu_labels_update);
g_test_add_func("/cmd/labels/clear", test_mu_labels_clear);
g_test_add_func("/cmd/labels/list", test_mu_labels_list);
g_test_add_func("/cmd/labels/export-import", test_mu_labels_export_import);
return g_test_run();

View File

@ -177,11 +177,11 @@ Mu::mu_cmd_execute(const Options& opts) try {
/*
* read-only _or_ writable store
*/
case Options::SubCommand::Label:
if (opts.label.read_only)
return with_readonly_store2(mu_cmd_label, opts);
case Options::SubCommand::Labels:
if (opts.labels.read_only)
return with_readonly_store2(mu_cmd_labels, opts);
else
return with_writable_store(mu_cmd_label, opts);
return with_writable_store(mu_cmd_labels, opts);
/*
* commands instantiate store themselves
*/

View File

@ -117,14 +117,14 @@ Result<void> mu_cmd_info(const Mu::Store& store, const Options& opts);
Result<void> mu_cmd_init(const Options& opts);
/**
* execute the 'label' command
* execute the 'labels' sub-command
*
* @param store message store object.
* @param opts configuration options
*
* @return Ok() or some error
*/
Result<void> mu_cmd_label(Store& store, const Options& opts);
Result<void> mu_cmd_labels(Store& store, const Options& opts);
/**
* execute the 'mkdir' command

View File

@ -33,7 +33,6 @@
*
*/
#include <config.h>
#include <stdexcept>
#include <array>
@ -68,7 +67,6 @@ using namespace Mu;
template<typename T1, typename T2, std::size_t N>
using AssocPairs = std::array<std::pair<T1, T2>, N>;
/**
* Get the first value of the pair where the second element is @param s.
*
@ -105,7 +103,6 @@ to_second(const P& p, typename P::value_type::first_type f)
return Nothing;
}
/**
* Options-specific array-bases type that maps some enum to a <name, description> pair
*/
@ -170,7 +167,6 @@ options_help(const IE& ie, typename IE::value_type::first_type default_opt)
return s;
}
/**
* Get map from string->type
*/
@ -275,7 +271,6 @@ sub_cfind(CLI::App& sub, Options& opts)
}
static void
sub_extract(CLI::App& sub, Options& opts)
{
@ -328,7 +323,6 @@ sub_fields(CLI::App& sub, Options& opts)
// nothing to do.
}
static void
sub_find(CLI::App& sub, Options& opts)
{
@ -447,7 +441,6 @@ sub_index(CLI::App& sub, Options& opts)
"Perform a complete reindexing");
}
static void
sub_info(CLI::App& sub, Options& opts)
{
@ -501,48 +494,51 @@ sub_init(CLI::App& sub, Options& opts)
}
static void
sub_label(CLI::App& sub, Options& opts)
sub_labels(CLI::App& sub, Options& opts)
{
sub.require_subcommand(1);
sub.require_subcommand(0);
// update
auto update{sub.add_subcommand("update", "update labels")};
update->add_option("--labels", opts.label.delta_labels,
update->add_option("--labels", opts.labels.delta_labels,
"One or more comma-separated +label,-label")
->delimiter(',')
->type_name("<delta-label>")
->required();
update->add_flag("-n,--dry-run", opts.label.dry_run,
update->add_flag("-n,--dry-run", opts.labels.dry_run,
"Output what would change without changing anything");
update->add_option("query", opts.label.query, "Query for messages to update")
update->add_option("query", opts.labels.query, "Query for messages to update")
->required();
add_muhome_option(*update, opts);
// clear
auto clear = sub.add_subcommand("clear", "clear all labels from matched messages");
clear ->add_option("query", opts.label.query, "Query for messages to clear of labels")
clear ->add_option("query", opts.labels.query, "Query for messages to clear of labels")
->required();
clear->add_flag("-n,--dry-run", opts.label.dry_run,
clear->add_flag("-n,--dry-run", opts.labels.dry_run,
"Output what would change without changing anything");
add_muhome_option(*clear, opts);
// list
[[maybe_unused]] auto list = sub.add_subcommand("list", "list labels in the store");
list->add_flag("--restore", opts.label.restore,
"Restore the label-list from the labels in store");
add_muhome_option(*list, opts);
// restore-list
[[maybe_unused]] auto restore_list = sub.add_subcommand(
"restore-list", "restore the labels cache");
add_muhome_option(*restore_list, opts);
// export
[[maybe_unused]] auto exportsub = sub.add_subcommand("export", "export labels to a file");
add_muhome_option(*exportsub, opts);
exportsub->add_option("output", opts.label.file, "File to export labels to")
exportsub->add_option("output", opts.labels.file, "File to export labels to")
->type_name("<file>");
// import
auto importsub = sub.add_subcommand("import", "import labels from a file");
importsub->add_flag("-n,--dry-run", opts.label.dry_run,
importsub->add_flag("-n,--dry-run", opts.labels.dry_run,
"Output what would change without changing anything");
importsub->add_option("input", opts.label.file, "File with labels to import")
importsub->add_option("input", opts.labels.file, "File with labels to import")
->required()
->type_name("<file>");
add_muhome_option(*importsub, opts);
@ -555,25 +551,27 @@ sub_label(CLI::App& sub, Options& opts)
sub.final_callback([&](){
if (sub.got_subcommand("list")) {
opts.label.sub = Options::Label::Sub::List;
opts.label.read_only = opts.label.restore ? false : true;
opts.labels.sub = Options::Labels::Sub::List;
opts.labels.read_only = true;
} else if (sub.got_subcommand("restore-list")) {
opts.labels.sub = Options::Labels::Sub::RestoreList;
opts.labels.read_only = false;/*opts.labels.dry_run*/
} else if (sub.got_subcommand("clear")) {
opts.label.sub = Options::Label::Sub::Clear;
opts.label.read_only = opts.label.dry_run;
opts.labels.sub = Options::Labels::Sub::Clear;
opts.labels.read_only = opts.labels.dry_run;
} else if (sub.got_subcommand("update")){
opts.label.sub = Options::Label::Sub::Update;
opts.label.read_only = opts.label.dry_run;
opts.labels.sub = Options::Labels::Sub::Update;
opts.labels.read_only = opts.labels.dry_run;
} else if (sub.got_subcommand("export")){
opts.label.sub = Options::Label::Sub::Export;
opts.label.read_only = true;
opts.labels.sub = Options::Labels::Sub::Export;
opts.labels.read_only = true;
} else if (sub.got_subcommand("import")){
opts.label.sub = Options::Label::Sub::Import;
opts.label.read_only = opts.label.dry_run;
opts.labels.sub = Options::Labels::Sub::Import;
opts.labels.read_only = opts.labels.dry_run;
}
});
}
static void
sub_mkdir(CLI::App& sub, Options& opts)
{
@ -586,7 +584,6 @@ sub_mkdir(CLI::App& sub, Options& opts)
->required();
}
static void
sub_move(CLI::App& sub, Options& opts)
{
@ -609,7 +606,6 @@ sub_move(CLI::App& sub, Options& opts)
->type_name("<maildir>");
}
static void
sub_remove(CLI::App& sub, Options& opts)
{
@ -719,7 +715,6 @@ sub_view(CLI::App& sub, Options& opts)
->type_name("<message-path>");
}
using SubCommand = Options::SubCommand;
using Category = Options::Category;
@ -771,9 +766,9 @@ AssocPairs<SubCommand, CommandInfo, Options::SubCommandNum> SubCommandInfos= {{
{Category::NeedsWritableStore,
"init", "Initialize the mu database", sub_init }
},
{ SubCommand::Label,
{ SubCommand::Labels,
{Category::None, // note Store handled on sub-subcommmands
"label", "Add/remove labels form messages", sub_label }
"labels", "Manage message labels", sub_labels }
},
{ SubCommand::Mkdir,
{Category::None,
@ -811,7 +806,6 @@ AssocPairs<SubCommand, CommandInfo, Options::SubCommandNum> SubCommandInfos= {{
},
}};
static ScriptInfos
add_scripts(CLI::App& app, Options& opts)
{
@ -832,7 +826,6 @@ add_scripts(CLI::App& app, Options& opts)
#endif /*BUILD_GUILE*/
}
static Result<Options>
show_manpage(Options& opts, const std::string& name)
{
@ -851,7 +844,6 @@ show_manpage(Options& opts, const std::string& name)
return Ok(std::move(opts));
}
static Result<Options>
cmd_help(const CLI::App& app, Options& opts)
{
@ -905,7 +897,7 @@ Result<Options>
Options::make(int argc, char *argv[])
{
Options opts{};
CLI::App app{"mu mail indexer/searcher", "mu"};
CLI::App app{"mu mail indexer/searcher " PACKAGE_VERSION, "mu"};
app.description(R"(mu mail indexer/searcher
Copyright (C) 2008-2025 Dirk-Jan C. Binnema
@ -915,7 +907,7 @@ This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
)");
app.set_version_flag("-V,--version", PACKAGE_VERSION);
app.set_help_flag("-h,--help", "Show help informmation");
app.set_help_flag("-h,--help", "Show help information");
app.set_help_all_flag("--help-all");
app.require_subcommand(0, 1);
@ -1031,7 +1023,6 @@ validate_subcommand_ids()
#define static_assert g_assert_true
#endif /*BUILD_TESTS*/
[[maybe_unused]]
static void
test_ids()

View File

@ -62,7 +62,7 @@ struct Options {
static bool default_no_color();
enum struct SubCommand {
Add, Cfind, Extract, Fields, Find, Help, Index,Info, Init, Label, Mkdir,
Add, Cfind, Extract, Fields, Find, Help, Index,Info, Init, Labels, Mkdir,
Move, Remove, Scm, Script, Server, Verify, View,
// <private>
__count__
@ -78,7 +78,7 @@ struct Options {
SubCommand::Index,
SubCommand::Info,
SubCommand::Init,
SubCommand::Label,
SubCommand::Labels,
SubCommand::Mkdir,
SubCommand::Move,
SubCommand::Remove,
@ -202,29 +202,26 @@ struct Options {
} init;
/*
* Label
* Labels
*/
struct Label {
struct Labels {
OptString query; /**< Query for the messages to label */
bool dry_run{}; /**< Merely print the messages that would be
* labeled without doing so */
StringVec delta_labels; /**< labels to add (+) or remove (-) */
bool read_only{}; /**< do not require writable store */
bool restore{}; /**< restore the labels list */
OptString file; /** file for import/export */
enum struct Sub { // sub-subcommands
Update, // add/remove labels
Clear, // clear all labels
List, // list all labels in the store
List, // list all labels in the store (from cache)
RestoreList, // restore the labels cache
Export, // export labels
Import, // import labels
};
Sub sub;
} label;
} labels;
/*
* Mkdir

View File

@ -66,9 +66,9 @@ test('test-cmd-init',
build_by_default: false,
cpp_args: ['-DBUILD_TESTS'],
dependencies: [glib_dep, lib_mu_dep]))
test('test-cmd-label',
executable('test-cmd-label',
'../mu-cmd-label.cc',
test('test-cmd-labels',
executable('test-cmd-labels',
'../mu-cmd-labels.cc',
install: false,
build_by_default: false,
cpp_args: ['-DBUILD_TESTS'],