mu-init: guess maildir when --maildir is missing

Re-instate the guessing that's in the manpage. Add unit tests.
Update documentation.

Fixes #2616.
This commit is contained in:
Dirk-Jan C. Binnema 2024-01-01 10:02:56 +02:00
parent 8366e009cb
commit b4c768e6d0
6 changed files with 107 additions and 32 deletions

View File

@ -35,12 +35,12 @@ namespace Mu {
* Check if the directory has the given attributes * Check if the directory has the given attributes
* *
* @param path path to dir * @param path path to dir
* @param readable is it readable? * @param readable is it readable? false means "don't care"
* @param writeable is it writable? * @param writeable is it writable? false means "don't care"
* *
* @return true if is is a directory with given attributes; false otherwise. * @return true if is is a directory with given attributes; false otherwise.
*/ */
bool check_dir(const std::string& path, bool readable, bool writeable); bool check_dir(const std::string& path, bool readable=false, bool writeable=false);
/** /**
* See g_canonicalize_filename * See g_canonicalize_filename
@ -233,8 +233,9 @@ Result<void> remove_directory(const std::string& path);
* @param try_setsid whether to try setsid(2) (see its manpage for details) if this * @param try_setsid whether to try setsid(2) (see its manpage for details) if this
* system supports it. * system supports it.
* *
* @return Ok(exit code) or an error. Note that exit-code != 0 is _not_ considered an error from the * @return Ok(exit code) or an error. Note that exit-code != 0 is _not_
* perspective of run_command, but is for run_command0 * considered an error from the perspective of run_command, but is for
* run_command0
*/ */
struct CommandOutput { struct CommandOutput {
int exit_code; int exit_code;

View File

@ -18,9 +18,11 @@ has completed, you can run *mu index*
** -m, --maildir=<maildir> ** -m, --maildir=<maildir>
starts searching at =<maildir>=. By default, *mu* uses whatever the *MAILDIR* use =<maildir>= as the root-maildir.
environment variable is set to; if it is not set, it tries =~/Maildir= if it
already exists. By default, *mu* uses the *MAILDIR* environment; if it is not set, it uses =~/Maildir=
if it is an existing directory. If neither of those can be used, the ~--maildir~
option is required.
** --my-address=<email-address-or-regex> ** --my-address=<email-address-or-regex>
@ -37,8 +39,8 @@ argument may need to be quoted.
** --ignored-address=<email-address-or-regex> ** --ignored-address=<email-address-or-regex>
specifies that some e-mail address is to be ignored from the contacts-cache specifies that some e-mail address is to be ignored from the contacts-cache (the
(the option can be used multiple times). Such address then cannot be found with option can be used multiple times). Such addresses then cannot be found with
*mu-cfind(1)* or in the Mu4e contacts cache. *mu-cfind(1)* or in the Mu4e contacts cache.
=<my-email-address>= can be either a plain e-mail address or a regexp, just like =<my-email-address>= can be either a plain e-mail address or a regexp, just like
@ -51,9 +53,9 @@ specifies the maximum size for an e-mail message. Usually, the default of
** --batch-size=<size> ** --batch-size=<size>
number of changes after which they are committed to the database; decreasing the number of changes after which they are committed to the database; decreasing
this reduces the memory requirements, but make indexing substantially slows (and the value reduces the memory requirements, at the cost of make indexing
vice-versa for increasing). Usually, the default of 250000 should be fine. substantially slower. Usually, the default of 250000 should be fine.
Batch-size 0 is interpreted as 'use the default'. Batch-size 0 is interpreted as 'use the default'.
@ -61,7 +63,7 @@ Batch-size 0 is interpreted as 'use the default'.
whether to enable support for using ngrams in indexing and query parsing; this whether to enable support for using ngrams in indexing and query parsing; this
can be useful for languages without explicit word breaks, such as can be useful for languages without explicit word breaks, such as
Chinese/Japanese/Korean. See *NGRAM SUPPORT* below. Chinese/Japanese/Korean. See *NGRAM SUPPORT* below for details.
** --reinit ** --reinit
@ -75,9 +77,9 @@ options.
*mu*'s underlying Xapian database supports 'ngrams', which improve searching for *mu*'s underlying Xapian database supports 'ngrams', which improve searching for
languages/scripts that do not have explicit word breaks, such as Chinese, languages/scripts that do not have explicit word breaks, such as Chinese,
Japanese and Korean. It is fairly intrusive, and influence both indexing and Japanese and Korean. It is fairly intrusive, and influences both indexing and
query-parsing; it is not enabled by default, and is recommended only if you need query-parsing; it is not enabled by default, and is recommended only if you need
to search in such languages. to search for messages written in such languages.
When enabled, *mu* automatically uses ngrams automatically. Xapian environment When enabled, *mu* automatically uses ngrams automatically. Xapian environment
variables such as ~XAPIAN_CJK_NGRAM~ are ignored. variables such as ~XAPIAN_CJK_NGRAM~ are ignored.

View File

@ -77,6 +77,13 @@ test('test-cmd-index',
cpp_args: ['-DBUILD_TESTS'], cpp_args: ['-DBUILD_TESTS'],
dependencies: [glib_dep, lib_mu_dep])) dependencies: [glib_dep, lib_mu_dep]))
test('test-cmd-init',
executable('test-cmd-init',
'mu-cmd-init.cc',
install: false,
cpp_args: ['-DBUILD_TESTS'],
dependencies: [glib_dep, lib_mu_dep]))
test('test-cmd-mkdir', test('test-cmd-mkdir',
executable('test-cmd-mkdir', executable('test-cmd-mkdir',
'mu-cmd-mkdir.cc', 'mu-cmd-mkdir.cc',
@ -105,7 +112,6 @@ test('test-cmd-verify',
cpp_args: ['-DBUILD_TESTS'], cpp_args: ['-DBUILD_TESTS'],
dependencies: [glib_dep, lib_mu_dep])) dependencies: [glib_dep, lib_mu_dep]))
test('test-cmd-view', test('test-cmd-view',
executable('test-cmd-view', executable('test-cmd-view',
'mu-cmd-view.cc', 'mu-cmd-view.cc',

View File

@ -152,11 +152,11 @@ test_mu_index(size_t batch_size=0)
auto res1 = run_command({MU_PROGRAM, "--quiet", "init", "--batch-size", auto res1 = run_command({MU_PROGRAM, "--quiet", "init", "--batch-size",
mu_format("{}", batch_size == 0 ? 10000 : batch_size), mu_format("{}", batch_size == 0 ? 10000 : batch_size),
"--muhome", mu_home, "--maildir" , MU_TESTMAILDIR2}); "--muhome", mu_home, "--maildir" , MU_TESTMAILDIR2});
assert_valid_result(res1); assert_valid_command(res1);
auto res2 = run_command({MU_PROGRAM, "--quiet", "index", auto res2 = run_command({MU_PROGRAM, "--quiet", "index",
"--muhome", mu_home}); "--muhome", mu_home});
assert_valid_result(res2); assert_valid_command(res2);
auto&& store = unwrap(Store::make(join_paths(temp_dir.path(), "xapian"))); auto&& store = unwrap(Store::make(join_paths(temp_dir.path(), "xapian")));
g_assert_cmpuint(store.size(),==,14); g_assert_cmpuint(store.size(),==,14);

View File

@ -23,6 +23,8 @@
using namespace Mu; using namespace Mu;
#ifndef BUILD_TESTS
Result<void> Result<void>
Mu::mu_cmd_init(const Options& opts) Mu::mu_cmd_init(const Options& opts)
{ {
@ -79,3 +81,61 @@ Mu::mu_cmd_init(const Options& opts)
return Ok(); return Ok();
} }
#else /* BUILD_TESTS */
/*
* Tests.
*
*/
#include <config.h>
#include <mu-store.hh>
#include "utils/mu-test-utils.hh"
static void
test_mu_init_basic()
{
TempDir temp_dir{};
const auto mu_home{temp_dir.path()};
auto res1 = run_command({MU_PROGRAM, "--quiet", "init",
"--muhome", mu_home, "--maildir" , MU_TESTMAILDIR2});
assert_valid_command(res1);
auto&& store = unwrap(Store::make(join_paths(temp_dir.path(), "xapian")));
g_assert_true(store.empty());
}
static void
test_mu_init_maildir()
{
TempDir temp_dir{};
const auto mu_home{temp_dir.path()};
g_setenv("MAILDIR", MU_TESTMAILDIR2, 1);
auto res1 = run_command({MU_PROGRAM, "--quiet", "init",
"--muhome", mu_home});
assert_valid_command(res1);
auto&& store = unwrap(Store::make(join_paths(temp_dir.path(), "xapian")));
g_assert_true(store.empty());
assert_equal(store.root_maildir(), MU_TESTMAILDIR2);
}
int
main(int argc, char* argv[])
{
mu_test_init(&argc, &argv);
g_test_add_func("/cmd/init/basic", test_mu_init_basic);
g_test_add_func("/cmd/init/maildir", test_mu_init_maildir);
return g_test_run();
}
#endif /*BUILD_TESTS*/

View File

@ -184,20 +184,16 @@ options_map(const IE& ie)
return map; return map;
} }
// transformers // transformers
// Expand the path using wordexp // Expand the path using wordexp
static const std::function ExpandPath = [](std::string filepath)->std::string { static const std::function ExpandPath = [](std::string filepath)->std::string {
if (auto&& res{expand_path(filepath)}; !res) if (auto&& res{expand_path(filepath)}; !res)
throw CLI::ValidationError{res.error().what()}; throw CLI::ValidationError{res.error().what()};
else else
return filepath = std::move(res.value()); return res.value();
}; };
// Canonicalize path // Canonicalize path
static const std::function CanonicalizePath = [](std::string filepath)->std::string { static const std::function CanonicalizePath = [](std::string filepath)->std::string {
return filepath = canonicalize_filename(filepath); return filepath = canonicalize_filename(filepath);
@ -289,7 +285,7 @@ sub_extract(CLI::App& sub, Options& opts)
sub.add_option("--target-dir", opts.extract.targetdir, sub.add_option("--target-dir", opts.extract.targetdir,
"Target directory for saving") "Target directory for saving")
->type_name("<dir>") ->type_name("<dir>")
->transform(ExpandPath, "expand path") ->transform(ExpandPath, "expand target path")
->default_str("<current>") ->default_str("<current>")
->default_val("."); ->default_val(".");
sub.add_flag("--uncooked,-u", opts.extract.uncooked, sub.add_flag("--uncooked,-u", opts.extract.uncooked,
@ -403,7 +399,7 @@ sub_find(CLI::App& sub, Options& opts)
sub.add_option("--linksdir", opts.find.linksdir, sub.add_option("--linksdir", opts.find.linksdir,
"Use bookmarked query") "Use bookmarked query")
->type_name("<dir>") ->type_name("<dir>")
->transform(ExpandPath, "expand path"); ->transform(ExpandPath, "expand linksdir path");
sub.add_option("--summary-len", opts.find.summary_len, sub.add_option("--summary-len", opts.find.summary_len,
"Use up to so many lines for the summary") "Use up to so many lines for the summary")
@ -448,10 +444,20 @@ sub_info(CLI::App& sub, Options& opts)
static void static void
sub_init(CLI::App& sub, Options& opts) sub_init(CLI::App& sub, Options& opts)
{ {
sub.add_option("--maildir,-m", opts.init.maildir, const auto default_mdir = std::invoke([]()->std::string {
"Top of the maildir") if (const auto mdir_env{::getenv("MAILDIR")}; mdir_env)
return mdir_env;
else if (const auto mdir_home = ::join_paths(g_get_home_dir(), "Maildir");
check_dir(mdir_home))
return mdir_home;
else
return {};
});
sub.add_option("--maildir,-m", opts.init.maildir, "Top of the maildir")
->type_name("<maildir>") ->type_name("<maildir>")
->transform(ExpandPath, "expand path"); ->default_val(default_mdir)
->transform(ExpandPath, "expand maildir path");
sub.add_option("--my-address", opts.init.my_addresses, sub.add_option("--my-address", opts.init.my_addresses,
"Personal e-mail address or regexp") "Personal e-mail address or regexp")
->type_name("<address>"); ->type_name("<address>");
@ -503,8 +509,8 @@ sub_move(CLI::App& sub, Options& opts)
sub.add_option("source", opts.move.src, "Message file to move") sub.add_option("source", opts.move.src, "Message file to move")
->type_name("<message-path>") ->type_name("<message-path>")
->transform(ExpandPath, "expand path") ->transform(ExpandPath, "expand source path")
->transform(CanonicalizePath, "canonicalize path") ->transform(CanonicalizePath, "canonicalize source path")
->required(); ->required();
sub.add_option("destination", opts.move.dest, sub.add_option("destination", opts.move.dest,
"Destination maildir") "Destination maildir")
@ -813,7 +819,7 @@ There is NO WARRANTY, to the extent permitted by law.
opts.muhome, "Specify alternative mu directory") opts.muhome, "Specify alternative mu directory")
->envname("MUHOME") ->envname("MUHOME")
->type_name("<dir>") ->type_name("<dir>")
->transform(ExpandPath, "expand path"); ->transform(ExpandPath, "expand muhome path");
} }
/* add scripts (if supported) as semi-subcommands as well */ /* add scripts (if supported) as semi-subcommands as well */