diff options
| author | Dirk-Jan C. Binnema <djcb@djcbsoftware.nl> | 2025-08-16 15:48:08 +0300 |
|---|---|---|
| committer | Dirk-Jan C. Binnema <djcb@djcbsoftware.nl> | 2025-08-16 16:20:33 +0300 |
| commit | 8c706a77db5a2aee6bcc6af53788e35e9805f945 (patch) | |
| tree | 1470215e0f915b122d5a0760d03e8091c1020dc0 /lib | |
| parent | a6b1f47a30c7aea84697553da4848b626c9faaca (diff) | |
mu-init: automatic export labels with --reinit
When re-initializing the store, automatically write the labels to a file in mu's
cache, so user can later import them.
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/mu-store-labels.cc | 24 | ||||
| -rw-r--r-- | lib/mu-store-labels.hh | 16 | ||||
| -rw-r--r-- | lib/mu-store.cc | 40 | ||||
| -rw-r--r-- | lib/utils/mu-utils-file.cc | 3 |
4 files changed, 62 insertions, 21 deletions
diff --git a/lib/mu-store-labels.cc b/lib/mu-store-labels.cc index 5aa6c94..61666aa 100644 --- a/lib/mu-store-labels.cc +++ b/lib/mu-store-labels.cc @@ -24,9 +24,9 @@ using namespace Mu; namespace { -constexpr std::string_view path_key = "path:"; -constexpr std::string_view message_id_key = "message-id:"; -constexpr std::string_view labels_key = "labels:"; +constexpr std::string_view path_key = "path:"; +constexpr std::string_view message_id_key = "message-id:"; +constexpr std::string_view labels_key = "labels:"; } using OutputPair = std::pair<std::ofstream, std::string>; @@ -36,14 +36,26 @@ export_output(Option<std::string> path) { const auto now_t{::time({})}; const auto now_tm{::localtime(&now_t)}; - const auto now{mu_format("{:%F-%T}", *now_tm)}; - auto fname = path.value_or(mu_format("mu-export-{}.txt", now)); + + // if path is not specified, use a generated file name (in pwd) + // if path is specified but ends in '/', use the generated file in that + // directory (must exist) + // otherwise, use the path. + auto fname = [&]() { + const auto default_fname{mu_format("mu-export-{}.txt", now)}; + if (!path || path->empty()) + return default_fname; + else if (path->at(path->length() - 1) == '/') + return *path + default_fname; + else + return *path; + }(); auto output{std::ofstream{fname, std::ios::out}}; if (!output.good()) return Err(Error{Error::Code::File, - "failed pen '{}' for writing", fname}); + "failed to open '{}' for writing", fname}); mu_println(output, ";; version:0 @ {}\n", now); diff --git a/lib/mu-store-labels.hh b/lib/mu-store-labels.hh index 55b33f4..f9daae3 100644 --- a/lib/mu-store-labels.hh +++ b/lib/mu-store-labels.hh @@ -129,11 +129,13 @@ public: std::string line; while (std::getline(ss, line)) { - if (const auto parts = Mu::split(line, SepaChar2); parts.size() != 2) + if (const auto parts = + Mu::split(line, SepaChar2); parts.size() != 2) mu_warning("error: '{}'", line); else map.emplace(std::move(parts[0]), - static_cast<std::size_t>(g_ascii_strtoll(parts[1].c_str(),{}, 10))); + static_cast<std::size_t>( + g_ascii_strtoll(parts[1].c_str(),{}, 10))); } return map; } @@ -148,14 +150,17 @@ class Store; * Export labels to a file * * If path is not specified, use a file in the current directory + * If path ends in '/', write file in the path-directory * * @param store a store object - * @param query for the message whose labels to export + * @param query for the message whose labels to export (empty for "all") * @param path the path or nothing * * @return either the output filename or some error */ -Result<std::string> export_labels(const Store& store, const std::string& query="", Option<std::string> path); +Result<std::string> export_labels(const Store& store, + const std::string& query="", + Option<std::string> path={}); /** * Import labels from a file @@ -170,7 +175,8 @@ Result<std::string> export_labels(const Store& store, const std::string& query=" * * @return Ok or some error */ -Result<void> import_labels(Store&, const std::string& path, bool dry_run, bool quiet, bool verbose); +Result<void> import_labels(Store&, const std::string& path, bool dry_run, + bool quiet, bool verbose); } // namespace Mux #endif /*MU_LABELS_CACHE_HH*/ diff --git a/lib/mu-store.cc b/lib/mu-store.cc index f0a36ed..b8526e9 100644 --- a/lib/mu-store.cc +++ b/lib/mu-store.cc @@ -127,7 +127,6 @@ struct Store::Private { Result<Store::Id> update_message_unlocked(Message& msg, Store::Id docid); Result<Store::Id> update_message_unlocked(Message& msg, const std::string& old_path); - using PathMessage = std::pair<std::string, Message>; Result<PathMessage> move_message_unlocked(Message&& msg, Option<const std::string&> target_mdir, @@ -211,9 +210,29 @@ Store::Private::find_duplicates_unlocked(const Store& store, } } +static void +reinit_export_labels(const Store& store) +{ + // slightly hacky way to get the cache-path... + const auto cache_path{canonicalize_filename( + join_paths(store.path(), "..")) + "/"}; + + if (const auto res = + Mu::export_labels(store, "", cache_path); !res) + throw Mu::Error(Error::Code::CannotReinit, + "cannot re-init; " + "failed to export labels: {}", + res.error().what()) + .add_hint("see mu-init(1) for details"); + else { + mu_info("exported labels to: {}", *res); + mu_println("exported labels to: {}", *res); + } +} Store::Store(const std::string& path, Store::Options opts) - : priv_{std::make_unique<Private>(path, none_of(opts & Store::Options::Writable))} + : priv_{std::make_unique<Private>( + path, none_of(opts & Store::Options::Writable))} { if (none_of(opts & Store::Options::Writable) && any_of(opts & Store::Options::ReInit)) @@ -222,12 +241,19 @@ Store::Store(const std::string& path, Store::Options opts) const auto s_version{config().get<Config::Id::SchemaVersion>()}; if (any_of(opts & Store::Options::ReInit)) { - /* don't try to recover from version with an incompatible scheme */ + + /* export labels, if necessary (throws if there's an error) */ + if (!label_map().empty()) + reinit_export_labels(*this); + + /* don't try to recover from version with an incompatible + * scheme */ if (s_version < 500) - throw Mu::Error(Error::Code::CannotReinit, - "old schema ({}) is too old to re-initialize from", - s_version).add_hint("Invoke 'mu init' without '--reinit'; " - "see mu-init(1) for details"); + throw Mu::Error( + Error::Code::CannotReinit, + "old schema ({}) is too old to re-initialize from", + s_version).add_hint("Invoke 'mu init' without '--reinit'; " + "see mu-init(1) for details"); const auto old_root_maildir{root_maildir()}; MemDb mem_db; diff --git a/lib/utils/mu-utils-file.cc b/lib/utils/mu-utils-file.cc index bd58102..e9bccb0 100644 --- a/lib/utils/mu-utils-file.cc +++ b/lib/utils/mu-utils-file.cc @@ -131,9 +131,6 @@ Mu::remove_directory(const std::string& path) return Ok(); } - - - std::string Mu::runtime_path(Mu::RuntimePath path, const std::string& muhome) { |
