This is an early version of a series to convert the remaining CLI (config, setup, and notmuch_command) to the new configuration framework. There are a few design decisions / compromomises that people might have opinions about. - The merged config API uses a notmuch_data_t as the primary "object". This mostly makes sense (since you nead a database anyway), but here I needed to add a function "notmuch_database_load_config", which does not really open the database. - There is a bit of growth in the public API here, including notmuch_database_get_config_values, and the config_pairs iterators. - The notmuch_config_set_{field} API is kept around soley for use in notmuch-setup - The location of the backups when upgrading is now configurable, with the default changing to a subdirectory. The latter change is arguably gratitous. - The behaviour of "notmuch config set" is changed with respect to storing in the database. Rather than silently doing so for a selected set of keys, it now does so optionally for any set of keys. I think this is positive for users, but requires e.g. a few tweaks to our test suite. It is conceivable that it may require some updates to advanced users scripts as well.
--- lib/database.cc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/database.cc b/lib/database.cc index ffd42ac4..87ad1385 100644 --- a/lib/database.cc +++ b/lib/database.cc @@ -292,12 +292,20 @@ notmuch_status_to_string (notmuch_status_t status) return "Operation requires a database upgrade"; case NOTMUCH_STATUS_PATH_ERROR: return "Path supplied is illegal for this function"; + case NOTMUCH_STATUS_IGNORED: + return "Argument was ignored"; + case NOTMUCH_STATUS_ILLEGAL_ARGUMENT: + return "Illegal argument for function"; case NOTMUCH_STATUS_MALFORMED_CRYPTO_PROTOCOL: return "Crypto protocol missing, malformed, or unintelligible"; case NOTMUCH_STATUS_FAILED_CRYPTO_CONTEXT_CREATION: return "Crypto engine initialization failure"; case NOTMUCH_STATUS_UNKNOWN_CRYPTO_PROTOCOL: return "Unknown crypto protocol"; + case NOTMUCH_STATUS_NO_CONFIG: + return "No configuration file found"; + case NOTMUCH_STATUS_DATABASE_EXISTS: + return "Database exists, not recreated"; default: case NOTMUCH_STATUS_LAST_STATUS: return "Unknown error status value"; -- 2.30.0
Remove one more usage of notmuch_config_get_database_path --- test/random-corpus.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/test/random-corpus.c b/test/random-corpus.c index ff413252..67e106e0 100644 --- a/test/random-corpus.c +++ b/test/random-corpus.c @@ -141,7 +141,6 @@ main (int argc, char **argv) void *ctx = talloc_new (NULL); const char *config_path = NULL; - notmuch_config_t *config; notmuch_database_t *notmuch; int num_messages = 500; @@ -179,12 +178,12 @@ main (int argc, char **argv) exit (1); } - config = notmuch_config_open (ctx, config_path, false); - if (config == NULL) - return 1; - - if (notmuch_database_open (notmuch_config_get_database_path (config), - NOTMUCH_DATABASE_MODE_READ_WRITE, ¬much)) + if (notmuch_database_open_with_config (NULL, + NOTMUCH_DATABASE_MODE_READ_WRITE, + config_path, + NULL, + ¬much, + NULL)) return 1; srandom (seed); -- 2.30.0
Although this increases code duplication, it also increases flexibility in handling various combinations of missing config file and missing database. --- lib/open.cc | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/lib/open.cc b/lib/open.cc index e5ef351e..e1ad957f 100644 --- a/lib/open.cc +++ b/lib/open.cc @@ -183,27 +183,18 @@ _db_dir_exists (const char *database_path, char **message) static notmuch_status_t _choose_database_path (void * ctx, - const char *config_path, const char *profile, - GKeyFile **key_file, + GKeyFile *key_file, const char **database_path, bool *split, char **message) { - notmuch_status_t status; - - status =_load_key_file (config_path, profile, key_file); - if (status) { - *message = strdup ("Error: cannot load config file.\n"); - return status; - } - if (! *database_path) { *database_path = getenv ("NOTMUCH_DATABASE"); } - if (! *database_path && *key_file) - *database_path = g_key_file_get_value (*key_file, "database", "path", NULL); + if (! *database_path && key_file) + *database_path = g_key_file_get_value (key_file, "database", "path", NULL); if (! *database_path) { *database_path = _xdg_dir (ctx, "XDG_DATA_HOME", ".local/share", profile); @@ -482,8 +473,14 @@ notmuch_database_open_with_config (const char *database_path, goto DONE; } - if ((status = _choose_database_path (local, config_path, profile, - &key_file, &database_path, &split, + status =_load_key_file (config_path, profile, &key_file); + if (status) { + message = strdup ("Error: cannot load config file.\n"); + goto DONE; + } + + if ((status = _choose_database_path (local, profile, key_file, + &database_path, &split, &message))) goto DONE; @@ -569,9 +566,14 @@ notmuch_database_create_with_config (const char *database_path, goto DONE; } - if ((status = _choose_database_path (local, config_path, profile, - &key_file, &database_path, &split, - &message))) + status =_load_key_file (config_path, profile, &key_file); + if (status) { + message = strdup ("Error: cannot load config file.\n"); + goto DONE; + } + + if ((status = _choose_database_path (local, profile, key_file, + &database_path, &split, &message))) goto DONE; status = _db_dir_exists (database_path, &message); -- 2.30.0
This needs at least documentation and probably more tests. --- lib/notmuch.h | 9 ++ lib/open.cc | 96 ++++++++++++++++++++++ test/T590-libconfig.sh | 182 ++++++++++++++++++++++++++++++++++++++++- 3 files changed, 284 insertions(+), 3 deletions(-) diff --git a/lib/notmuch.h b/lib/notmuch.h index 5e4f1dac..60c79696 100644 --- a/lib/notmuch.h +++ b/lib/notmuch.h @@ -442,6 +442,15 @@ notmuch_database_open_with_config (const char *database_path, const char *profile, notmuch_database_t **database, char **error_message); + + +notmuch_status_t +notmuch_database_load_config (const char *database_path, + const char *config_path, + const char *profile, + notmuch_database_t **database, + char **error_message); + /** * Create a new notmuch database located at 'database_path', using * configuration in 'config_path'. diff --git a/lib/open.cc b/lib/open.cc index e1ad957f..be9151b0 100644 --- a/lib/open.cc +++ b/lib/open.cc @@ -709,3 +709,99 @@ notmuch_database_reopen (notmuch_database_t *notmuch, notmuch->open = true; return NOTMUCH_STATUS_SUCCESS; } + +notmuch_status_t +_maybe_load_config_from_database (notmuch_database_t *notmuch, + GKeyFile *key_file, + const char *database_path, + const char *profile) +{ + char *message; /* ignored */ + + if (_db_dir_exists (database_path, &message)) + return NOTMUCH_STATUS_SUCCESS; + + _set_database_path (notmuch, database_path); + + if (_notmuch_choose_xapian_path (notmuch, database_path, ¬much->xapian_path, &message)) + return NOTMUCH_STATUS_SUCCESS; + + (void) _finish_open (notmuch, profile, NOTMUCH_DATABASE_MODE_READ_ONLY, key_file, &message); + + return NOTMUCH_STATUS_SUCCESS; +} + +notmuch_status_t +notmuch_database_load_config (const char *database_path, + const char *config_path, + const char *profile, + notmuch_database_t **database, + char **status_string) +{ + notmuch_status_t status = NOTMUCH_STATUS_SUCCESS, status2 = NOTMUCH_STATUS_SUCCESS; + void *local = talloc_new (NULL); + notmuch_database_t *notmuch = NULL; + char *message = NULL; + GKeyFile *key_file = NULL; + bool split = false; + + _init_libs (); + + notmuch = _alloc_notmuch (); + if (!notmuch) { + status = NOTMUCH_STATUS_OUT_OF_MEMORY; + goto DONE; + } + + status =_load_key_file (config_path, profile, &key_file); + switch (status) { + case NOTMUCH_STATUS_SUCCESS: + case NOTMUCH_STATUS_NO_CONFIG: + status2 = status; + break; + default: + message = strdup ("Error: cannot load config file.\n"); + goto DONE; + } + + status = _choose_database_path (local, profile, key_file, + &database_path, &split, &message); + switch (status) { + /* weirdly NULL_POINTER is what is returned if we fail to find + * a database */ + case NOTMUCH_STATUS_NULL_POINTER: + case NOTMUCH_STATUS_SUCCESS: + break; + default: + goto DONE; + } + + if (database_path) { + status = _maybe_load_config_from_database (notmuch, key_file, database_path, profile); + if (status) + goto DONE; + } + + if (key_file) { + status = _notmuch_config_load_from_file (notmuch, key_file); + if (status) + goto DONE; + } + status = _notmuch_config_load_defaults (notmuch); + if (status) + goto DONE; + + DONE: + talloc_free (local); + + if (status_string) + *status_string = message; + + if (database) + *database = notmuch; + + if (status) + return status; + else + return status2; +} diff --git a/test/T590-libconfig.sh b/test/T590-libconfig.sh index 310668a9..dc9964cf 100755 --- a/test/T590-libconfig.sh +++ b/test/T590-libconfig.sh @@ -538,7 +538,7 @@ cat c_head - c_tail <<'EOF' | test_C %NULL% '' %NULL% printf("test.key2 = %s\n", val); } EOF -NOTMUCH_CONFIG=${old_NOTMUCH_CONFIG} +export NOTMUCH_CONFIG=${old_NOTMUCH_CONFIG} unset NOTMUCH_DATABASE cat <<'EOF' >EXPECTED == stdout == @@ -549,7 +549,7 @@ EOF test_expect_equal_file EXPECTED OUTPUT test_begin_subtest "NOTMUCH_DATABASE overrides config" -old_path=$(notmuch config get database.path) +cp notmuch-config notmuch-config.bak notmuch config set database.path /nonexistent export NOTMUCH_DATABASE=${MAIL_DIR} cat c_head - c_tail <<'EOF' | test_C %NULL% '' %NULL% @@ -568,8 +568,184 @@ test.key1 = testvalue1 test.key2 = testvalue2 == stderr == EOF -notmuch config set database.path "${old_path}" +cp notmuch-config.bak notmuch-config +test_expect_equal_file EXPECTED OUTPUT + +cat <<EOF > c_head2 +#include <string.h> +#include <stdlib.h> +#include <notmuch-test.h> + +int main (int argc, char** argv) +{ + notmuch_database_t *db; + char *val; + notmuch_status_t stat; + char *msg = NULL; + + for (int i = 1; i < argc; i++) + if (strcmp (argv[i], "%NULL%") == 0) argv[i] = NULL; + + stat = notmuch_database_load_config (argv[1], + argv[2], + argv[3], + &db, + &msg); + if (stat != NOTMUCH_STATUS_SUCCESS && stat != NOTMUCH_STATUS_NO_CONFIG) { + fprintf (stderr, "error opening database\n%d: %s\n%s\n", stat, + notmuch_status_to_string (stat), msg ? msg : ""); + exit (1); + } +EOF + + +test_begin_subtest "notmuch_database_get_config (ndlc)" +echo NOTMUCH_CONFIG=$NOTMUCH_CONFIG +echo NOTMUCH_PROFILE=$NOTMUCH_PROFILE +echo HOME=$HOME +cat c_head2 - c_tail <<'EOF' | test_C ${MAIL_DIR} %NULL% %NULL% +{ + EXPECT0(notmuch_database_get_config (db, "test.key1", &val)); + printf("test.key1 = %s\n", val); + EXPECT0(notmuch_database_get_config (db, "test.key2", &val)); + printf("test.key2 = %s\n", val); +} +EOF +cat <<'EOF' >EXPECTED +== stdout == +test.key1 = testvalue1 +test.key2 = testvalue2 +== stderr == +EOF +test_expect_equal_file EXPECTED OUTPUT + + +test_begin_subtest "notmuch_database_get_config_list: all pairs (ndlc)" +cat c_head2 - c_tail <<'EOF' | test_C ${MAIL_DIR} ${NOTMUCH_CONFIG} %NULL% +{ + notmuch_config_list_t *list; + EXPECT0(notmuch_database_get_config_list (db, "", &list)); + for (; notmuch_config_list_valid (list); notmuch_config_list_move_to_next (list)) { + printf("%s %s\n", notmuch_config_list_key (list), notmuch_config_list_value(list)); + } + notmuch_config_list_destroy (list); +} +EOF +cat <<'EOF' >EXPECTED +== stdout == +aaabefore beforeval +key with spaces value, with, spaces! +test.key1 testvalue1 +test.key2 testvalue2 +zzzafter afterval +== stderr == +EOF +test_expect_equal_file EXPECTED OUTPUT + +test_begin_subtest "notmuch_database_get_config_list: one prefix (ndlc)" +cat c_head2 - c_tail <<'EOF' | test_C ${MAIL_DIR} ${NOTMUCH_CONFIG} %NULL% +{ + notmuch_config_list_t *list; + EXPECT0(notmuch_database_get_config_list (db, "test.key", &list)); + for (; notmuch_config_list_valid (list); notmuch_config_list_move_to_next (list)) { + printf("%s %s\n", notmuch_config_list_key (list), notmuch_config_list_value(list)); + } + notmuch_config_list_destroy (list); +} +EOF +cat <<'EOF' >EXPECTED +== stdout == +test.key1 testvalue1 +test.key2 testvalue2 +== stderr == +EOF test_expect_equal_file EXPECTED OUTPUT +test_begin_subtest "list by keys (ndlc)" +notmuch config set search.exclude_tags "foo;bar;fub" +notmuch config set new.ignore "sekrit_junk" +cat c_head2 - c_tail <<'EOF' | test_C ${MAIL_DIR} %NULL% %NULL% +{ + notmuch_config_key_t key; + for (key = NOTMUCH_CONFIG_FIRST; + key < NOTMUCH_CONFIG_LAST; + key = (notmuch_config_key_t)(key + 1)) { + const char *val = notmuch_config_get (db, key); + printf("%s\n", val ? val : "NULL" ); + } +} +EOF +cat <<'EOF' >EXPECTED +== stdout == +MAIL_DIR +MAIL_DIR +MAIL_DIR/.notmuch/hooks +MAIL_DIR/.notmuch/backups +foo;bar;fub +unread;inbox; +sekrit_junk +true +test_suite@notmuchmail.org +test_suite_other@notmuchmail.org;test_suite@otherdomain.org +Notmuch Test Suite +== stderr == +EOF +test_expect_equal_file EXPECTED OUTPUT + +test_begin_subtest "load default values (ndlc, nonexistent config)" +cat c_head2 - c_tail <<'EOF' | test_C ${MAIL_DIR} /nonexistent %NULL% +{ + notmuch_config_key_t key; + for (key = NOTMUCH_CONFIG_FIRST; + key < NOTMUCH_CONFIG_LAST; + key = (notmuch_config_key_t)(key + 1)) { + const char *val = notmuch_config_get (db, key); + printf("%s\n", val ? val : "NULL" ); + } +} +EOF +cat <<'EOF' >EXPECTED +== stdout == +MAIL_DIR +MAIL_DIR +MAIL_DIR/.notmuch/hooks +MAIL_DIR/.notmuch/backups + +inbox;unread +NULL +true +NULL +NULL +NULL +== stderr == +EOF +test_expect_equal_file EXPECTED OUTPUT + +backup_database +test_begin_subtest "override config from \${HOME}/.notmuch-config (ndlc)" +ovconfig=${HOME}/.notmuch-config +cp ${NOTMUCH_CONFIG} ${ovconfig} +old_NOTMUCH_CONFIG=${NOTMUCH_CONFIG} +unset NOTMUCH_CONFIG +notmuch --config=${ovconfig} config set test.key1 overridden-home +cat c_head2 - c_tail <<'EOF' | test_C ${MAIL_DIR} %NULL% %NULL% +{ + EXPECT0(notmuch_database_get_config (db, "test.key1", &val)); + printf("test.key1 = %s\n", val); + EXPECT0(notmuch_database_get_config (db, "test.key2", &val)); + printf("test.key2 = %s\n", val); +} +EOF +rm -f ${ovconfig} +NOTMUCH_CONFIG=${old_NOTMUCH_CONFIG} +cat <<'EOF' >EXPECTED +== stdout == +test.key1 = overridden-home +test.key2 = testvalue2 +== stderr == +EOF +test_expect_equal_file EXPECTED OUTPUT +restore_database + test_done -- 2.30.0
--- lib/config.cc | 14 ++++++++++---- lib/notmuch.h | 2 ++ test/T590-libconfig.sh | 23 +++++++++++++++++++++++ 3 files changed, 35 insertions(+), 4 deletions(-) diff --git a/lib/config.cc b/lib/config.cc index 32ed6f8f..47e8bf82 100644 --- a/lib/config.cc +++ b/lib/config.cc @@ -258,13 +258,19 @@ _notmuch_config_load_from_database (notmuch_database_t *notmuch) notmuch_config_values_t * notmuch_config_get_values (notmuch_database_t *notmuch, notmuch_config_key_t key) { - notmuch_config_values_t *values = NULL; - bool ok = false; - const char *key_str = _notmuch_config_key_to_string (key); if (! key_str) - goto DONE; + return NULL; + + return notmuch_database_get_config_values (notmuch, key_str); +} + +notmuch_config_values_t * +notmuch_database_get_config_values (notmuch_database_t *notmuch, const char *key_str) +{ + notmuch_config_values_t *values = NULL; + bool ok = false; values = talloc (notmuch, notmuch_config_values_t); if (unlikely(! values)) diff --git a/lib/notmuch.h b/lib/notmuch.h index 60c79696..45616a22 100644 --- a/lib/notmuch.h +++ b/lib/notmuch.h @@ -2475,6 +2475,8 @@ notmuch_config_list_move_to_next (notmuch_config_list_t *config_list); void notmuch_config_list_destroy (notmuch_config_list_t *config_list); +notmuch_config_values_t * +notmuch_database_get_config_values (notmuch_database_t *notmuch, const char *key_string); /** * Configuration keys known to libnotmuch diff --git a/test/T590-libconfig.sh b/test/T590-libconfig.sh index dc9964cf..ad044275 100755 --- a/test/T590-libconfig.sh +++ b/test/T590-libconfig.sh @@ -255,6 +255,29 @@ EOF test_expect_equal_file EXPECTED OUTPUT restore_database +test_begin_subtest "notmuch_database_get_config_values" +cat c_head - c_tail <<'EOF' | test_C ${MAIL_DIR} ${NOTMUCH_CONFIG} %NULL% +{ + notmuch_config_values_t *values; + EXPECT0(notmuch_database_set_config (db, "test.list", "x;y;z")); + for (values = notmuch_database_get_config_values (db, "test.list"); + notmuch_config_values_valid (values); + notmuch_config_values_move_to_next (values)) + { + puts (notmuch_config_values_get (values)); + } +} +EOF +cat <<'EOF' >EXPECTED +== stdout == +x +y +z +== stderr == +EOF +test_expect_equal_file EXPECTED OUTPUT +restore_database + test_begin_subtest "notmuch_config_get_values (restart)" cat c_head - c_tail <<'EOF' | test_C ${MAIL_DIR} ${NOTMUCH_CONFIG} %NULL% { -- 2.30.0
The layer of shims here seems a bit wasteful compared to just calling the corresponding string map functions directly, but it allows control over the API (calling with notmuch_database_t *) and flexibility for future changes. --- lib/config.cc | 39 ++++++++++++++++++++++++++++++ lib/notmuch.h | 21 ++++++++++++++++ test/T590-libconfig.sh | 54 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 114 insertions(+) diff --git a/lib/config.cc b/lib/config.cc index 47e8bf82..490cb1c3 100644 --- a/lib/config.cc +++ b/lib/config.cc @@ -38,6 +38,10 @@ struct _notmuch_config_values { void *children; /* talloc_context */ }; +struct _notmuch_config_pairs { + notmuch_string_map_iterator_t *iter; +}; + static const char * _notmuch_config_key_to_string (notmuch_config_key_t key); static int @@ -331,6 +335,41 @@ notmuch_config_values_destroy (notmuch_config_values_t *values) { talloc_free (values); } +notmuch_config_pairs_t * +notmuch_config_get_pairs (notmuch_database_t *notmuch, + const char *prefix) +{ + notmuch_config_pairs_t *pairs = talloc(notmuch,notmuch_config_pairs_t); + pairs->iter = _notmuch_string_map_iterator_create (notmuch->config, prefix, false); + return pairs; +} + +notmuch_bool_t +notmuch_config_pairs_valid (notmuch_config_pairs_t *pairs) { + return _notmuch_string_map_iterator_valid (pairs->iter); +} + +void +notmuch_config_pairs_move_to_next (notmuch_config_pairs_t *pairs) { + _notmuch_string_map_iterator_move_to_next (pairs->iter); +} + +const char * +notmuch_config_pairs_key (notmuch_config_pairs_t *pairs) { + return _notmuch_string_map_iterator_key (pairs->iter); +} + +const char * +notmuch_config_pairs_value (notmuch_config_pairs_t *pairs) { + return _notmuch_string_map_iterator_value (pairs->iter); +} + +void +notmuch_config_pairs_destroy (notmuch_config_pairs_t *pairs) { + _notmuch_string_map_iterator_destroy (pairs->iter); + talloc_free (pairs); +} + notmuch_status_t _notmuch_config_load_from_file (notmuch_database_t *notmuch, GKeyFile *file) diff --git a/lib/notmuch.h b/lib/notmuch.h index 45616a22..e6e26fe5 100644 --- a/lib/notmuch.h +++ b/lib/notmuch.h @@ -245,6 +245,7 @@ typedef struct _notmuch_directory notmuch_directory_t; typedef struct _notmuch_filenames notmuch_filenames_t; typedef struct _notmuch_config_list notmuch_config_list_t; typedef struct _notmuch_config_values notmuch_config_values_t; +typedef struct _notmuch_config_pairs notmuch_config_pairs_t; typedef struct _notmuch_indexopts notmuch_indexopts_t; #endif /* __DOXYGEN__ */ @@ -2607,6 +2608,26 @@ notmuch_config_values_start (notmuch_config_values_t *values); void notmuch_config_values_destroy (notmuch_config_values_t *values); + +notmuch_config_pairs_t * +notmuch_config_get_pairs (notmuch_database_t *notmuch, + const char *prefix); + +notmuch_bool_t +notmuch_config_pairs_valid (notmuch_config_pairs_t *pairs); + +void +notmuch_config_pairs_move_to_next (notmuch_config_pairs_t *pairs); + +const char * +notmuch_config_pairs_key (notmuch_config_pairs_t *pairs); + +const char * +notmuch_config_pairs_value (notmuch_config_pairs_t *pairs); + +void +notmuch_config_pairs_destroy (notmuch_config_pairs_t *pairs); + /** * get a configuration value from an open database as Boolean * diff --git a/test/T590-libconfig.sh b/test/T590-libconfig.sh index ad044275..c93c2859 100755 --- a/test/T590-libconfig.sh +++ b/test/T590-libconfig.sh @@ -770,5 +770,59 @@ EOF test_expect_equal_file EXPECTED OUTPUT restore_database +test_begin_subtest "notmuch_config_get_pairs: prefix (ndlc)" +cat c_head2 - c_tail <<'EOF' | test_C ${MAIL_DIR} ${NOTMUCH_CONFIG} %NULL% +{ + notmuch_config_pairs_t *list; + for (list = notmuch_config_get_pairs (db, "user."); + notmuch_config_pairs_valid (list); + notmuch_config_pairs_move_to_next (list)) { + printf("%s %s\n", notmuch_config_pairs_key (list), notmuch_config_pairs_value(list)); + } + notmuch_config_pairs_destroy (list); +} +EOF +cat <<'EOF' >EXPECTED +== stdout == +user.name Notmuch Test Suite +user.other_email test_suite_other@notmuchmail.org;test_suite@otherdomain.org +user.primary_email test_suite@notmuchmail.org +== stderr == +EOF +test_expect_equal_file EXPECTED OUTPUT + +test_begin_subtest "notmuch_config_get_pairs: all pairs (ndlc)" +cat c_head2 - c_tail <<'EOF' | test_C ${MAIL_DIR} ${NOTMUCH_CONFIG} %NULL% +{ + notmuch_config_pairs_t *list; + for (list = notmuch_config_get_pairs (db, ""); + notmuch_config_pairs_valid (list); + notmuch_config_pairs_move_to_next (list)) { + printf("%s %s\n", notmuch_config_pairs_key (list), notmuch_config_pairs_value(list)); + } + notmuch_config_pairs_destroy (list); +} +EOF +cat <<'EOF' >EXPECTED +== stdout == +aaabefore beforeval +database.backup_dir MAIL_DIR/.notmuch/backups +database.hook_dir MAIL_DIR/.notmuch/hooks +database.mail_root MAIL_DIR +database.path MAIL_DIR +key with spaces value, with, spaces! +maildir.synchronize_flags true +new.ignore sekrit_junk +new.tags unread;inbox; +search.exclude_tags foo;bar;fub +test.key1 testvalue1 +test.key2 testvalue2 +user.name Notmuch Test Suite +user.other_email test_suite_other@notmuchmail.org;test_suite@otherdomain.org +user.primary_email test_suite@notmuchmail.org +zzzafter afterval +== stderr == +EOF +test_expect_equal_file EXPECTED OUTPUT test_done -- 2.30.0
This just copies code from from the CLI into the library. New test infrastructure is needed because apparently we have never tested this code path. --- lib/config.cc | 48 +++++++++++++++++++++++++++++++++++++++++- test/T590-libconfig.sh | 13 ++++++++---- test/test-lib.sh | 7 ++++++ 3 files changed, 63 insertions(+), 5 deletions(-) diff --git a/lib/config.cc b/lib/config.cc index 490cb1c3..d07aac5e 100644 --- a/lib/config.cc +++ b/lib/config.cc @@ -22,6 +22,8 @@ #include "notmuch-private.h" #include "database-private.h" +#include <pwd.h> + static const std::string CONFIG_PREFIX = "C"; struct _notmuch_config_list { @@ -430,6 +432,41 @@ notmuch_config_get_bool (notmuch_database_t *notmuch, notmuch_config_key_t key, return NOTMUCH_STATUS_SUCCESS; } +static const char * +_get_name_from_passwd_file (void *ctx) +{ + long pw_buf_size; + char *pw_buf; + struct passwd passwd, *ignored; + const char *name; + int e; + + pw_buf_size = sysconf (_SC_GETPW_R_SIZE_MAX); + if (pw_buf_size == -1) pw_buf_size = 64; + pw_buf = (char *) talloc_size (ctx, pw_buf_size); + + while ((e = getpwuid_r (getuid (), &passwd, pw_buf, + pw_buf_size, &ignored)) == ERANGE) { + pw_buf_size = pw_buf_size * 2; + pw_buf = (char *) talloc_zero_size (ctx, pw_buf_size); + } + + if (e == 0) { + char *comma = strchr (passwd.pw_gecos, ','); + if (comma) + name = talloc_strndup (ctx, passwd.pw_gecos, + comma - passwd.pw_gecos); + else + name = talloc_strdup (ctx, passwd.pw_gecos); + } else { + name = talloc_strdup (ctx, ""); + } + + talloc_free (pw_buf); + + return name; +} + static const char * _notmuch_config_key_to_string (notmuch_config_key_t key) { switch (key) { @@ -463,6 +500,7 @@ _notmuch_config_key_to_string (notmuch_config_key_t key) { static const char * _notmuch_config_default (notmuch_database_t *notmuch, notmuch_config_key_t key) { char *path; + const char* name; switch (key) { case NOTMUCH_CONFIG_DATABASE_PATH: @@ -482,10 +520,18 @@ _notmuch_config_default (notmuch_database_t *notmuch, notmuch_config_key_t key) return "inbox;unread"; case NOTMUCH_CONFIG_SYNC_MAILDIR_FLAGS: return "true"; + case NOTMUCH_CONFIG_USER_NAME: + name = getenv ("NAME"); + if (name) + name = talloc_strdup (notmuch, name); + else + name = _get_name_from_passwd_file (notmuch); + + return name; + break; case NOTMUCH_CONFIG_HOOK_DIR: case NOTMUCH_CONFIG_BACKUP_DIR: case NOTMUCH_CONFIG_NEW_IGNORE: - case NOTMUCH_CONFIG_USER_NAME: case NOTMUCH_CONFIG_PRIMARY_EMAIL: case NOTMUCH_CONFIG_OTHER_EMAIL: return NULL; diff --git a/test/T590-libconfig.sh b/test/T590-libconfig.sh index c93c2859..95538bba 100755 --- a/test/T590-libconfig.sh +++ b/test/T590-libconfig.sh @@ -384,6 +384,9 @@ cat c_head - c_tail <<'EOF' | test_C ${MAIL_DIR} '' %NULL% } } EOF + +notmuch_passwd_sanitize < OUTPUT > OUTPUT.clean + cat <<'EOF' >EXPECTED == stdout == MAIL_DIR @@ -396,11 +399,11 @@ NULL true NULL NULL -NULL +USER_FULL_NAME == stderr == EOF unset MAILDIR -test_expect_equal_file EXPECTED OUTPUT +test_expect_equal_file EXPECTED OUTPUT.clean backup_database test_begin_subtest "override config from \${NOTMUCH_CONFIG}" @@ -727,6 +730,8 @@ cat c_head2 - c_tail <<'EOF' | test_C ${MAIL_DIR} /nonexistent %NULL% } } EOF + +notmuch_passwd_sanitize < OUTPUT > OUTPUT.clean cat <<'EOF' >EXPECTED == stdout == MAIL_DIR @@ -739,10 +744,10 @@ NULL true NULL NULL -NULL +USER_FULL_NAME == stderr == EOF -test_expect_equal_file EXPECTED OUTPUT +test_expect_equal_file EXPECTED OUTPUT.clean backup_database test_begin_subtest "override config from \${HOME}/.notmuch-config (ndlc)" diff --git a/test/test-lib.sh b/test/test-lib.sh index 29baa0c1..e881dc40 100644 --- a/test/test-lib.sh +++ b/test/test-lib.sh @@ -694,6 +694,13 @@ notmuch_built_with_sanitize () sed 's/^built_with[.]\(.*\)=.*$/built_with.\1=something/' } +notmuch_passwd_sanitize () +{ + local user=$(id -un) + local full_name=$(getent passwd $user | cut -d: -f 5 | cut -d, -f1) + sed "s/$full_name/USER_FULL_NAME/" +} + notmuch_config_sanitize () { notmuch_dir_sanitize | notmuch_built_with_sanitize -- 2.30.0
This is mainly copying code from the CLI into the lib. The CLI copy will be deleted in a later commit. --- lib/config.cc | 70 +++++++++++++++++++++++++++++++++++++++--- test/T590-libconfig.sh | 4 +-- test/test-lib.sh | 6 +++- 3 files changed, 73 insertions(+), 7 deletions(-) diff --git a/lib/config.cc b/lib/config.cc index d07aac5e..03ba2731 100644 --- a/lib/config.cc +++ b/lib/config.cc @@ -23,6 +23,7 @@ #include "database-private.h" #include <pwd.h> +#include <netdb.h> static const std::string CONFIG_PREFIX = "C"; @@ -467,6 +468,63 @@ _get_name_from_passwd_file (void *ctx) return name; } +static char * +_get_username_from_passwd_file (void *ctx) +{ + long pw_buf_size; + char *pw_buf; + struct passwd passwd, *ignored; + char *name; + int e; + + pw_buf_size = sysconf (_SC_GETPW_R_SIZE_MAX); + if (pw_buf_size == -1) pw_buf_size = 64; + pw_buf = (char *)talloc_zero_size (ctx, pw_buf_size); + + while ((e = getpwuid_r (getuid (), &passwd, pw_buf, + pw_buf_size, &ignored)) == ERANGE) { + pw_buf_size = pw_buf_size * 2; + pw_buf = (char *)talloc_zero_size (ctx, pw_buf_size); + } + + if (e == 0) + name = talloc_strdup (ctx, passwd.pw_name); + else + name = talloc_strdup (ctx, ""); + + talloc_free (pw_buf); + + return name; +} + +static const char * +_get_email_from_passwd_file (void *ctx) +{ + + char hostname[256]; + struct hostent *hostent; + const char *domainname; + char *email; + + char *username = _get_username_from_passwd_file (ctx); + + gethostname (hostname, 256); + hostname[255] = '\0'; + + hostent = gethostbyname (hostname); + if (hostent && (domainname = strchr (hostent->h_name, '.'))) + domainname += 1; + else + domainname = "(none)"; + + email = talloc_asprintf (ctx, "%s@%s.%s", + username, hostname, domainname); + + talloc_free (username); + talloc_free (email); + return email; +} + static const char * _notmuch_config_key_to_string (notmuch_config_key_t key) { switch (key) { @@ -500,7 +558,7 @@ _notmuch_config_key_to_string (notmuch_config_key_t key) { static const char * _notmuch_config_default (notmuch_database_t *notmuch, notmuch_config_key_t key) { char *path; - const char* name; + const char *name, *email; switch (key) { case NOTMUCH_CONFIG_DATABASE_PATH: @@ -526,13 +584,17 @@ _notmuch_config_default (notmuch_database_t *notmuch, notmuch_config_key_t key) name = talloc_strdup (notmuch, name); else name = _get_name_from_passwd_file (notmuch); - return name; - break; + case NOTMUCH_CONFIG_PRIMARY_EMAIL: + email = getenv ("EMAIL"); + if (email) + email = talloc_strdup (notmuch, email); + else + email = _get_email_from_passwd_file (notmuch); + return email; case NOTMUCH_CONFIG_HOOK_DIR: case NOTMUCH_CONFIG_BACKUP_DIR: case NOTMUCH_CONFIG_NEW_IGNORE: - case NOTMUCH_CONFIG_PRIMARY_EMAIL: case NOTMUCH_CONFIG_OTHER_EMAIL: return NULL; default: diff --git a/test/T590-libconfig.sh b/test/T590-libconfig.sh index 95538bba..01a9ac06 100755 --- a/test/T590-libconfig.sh +++ b/test/T590-libconfig.sh @@ -397,7 +397,7 @@ MAIL_DIR/.notmuch/backups inbox;unread NULL true -NULL +USERNAME@FQDN NULL USER_FULL_NAME == stderr == @@ -742,7 +742,7 @@ MAIL_DIR/.notmuch/backups inbox;unread NULL true -NULL +USERNAME@FQDN NULL USER_FULL_NAME == stderr == diff --git a/test/test-lib.sh b/test/test-lib.sh index e881dc40..cb27cb78 100644 --- a/test/test-lib.sh +++ b/test/test-lib.sh @@ -107,6 +107,9 @@ unset GREP_OPTIONS # For emacsclient unset ALTERNATE_EDITOR +# for reproducibility +unset EMAIL + add_gnupg_home () { [ -e "${GNUPGHOME}/gpg.conf" ] && return @@ -697,8 +700,9 @@ notmuch_built_with_sanitize () notmuch_passwd_sanitize () { local user=$(id -un) + local fqdn=$(hostname -f) local full_name=$(getent passwd $user | cut -d: -f 5 | cut -d, -f1) - sed "s/$full_name/USER_FULL_NAME/" + sed -e "s/$user/USERNAME/" -e "s/$fqdn/FQDN/" -e "s/$full_name/USER_FULL_NAME/" } notmuch_config_sanitize () -- 2.30.0
The notmuch_config_get_{field_name} internal API will be removed in a subsequent commit. --- notmuch.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/notmuch.c b/notmuch.c index 71482e43..a161f127 100644 --- a/notmuch.c +++ b/notmuch.c @@ -364,7 +364,7 @@ notmuch_help_command (unused (notmuch_config_t *config), unused(notmuch_database */ static int notmuch_command (notmuch_config_t *config, - unused(notmuch_database_t *notmuch), + notmuch_database_t *notmuch, unused(int argc), unused(char **argv)) { char *db_path; @@ -378,7 +378,7 @@ notmuch_command (notmuch_config_t *config, /* Notmuch is already configured, but is there a database? */ db_path = talloc_asprintf (config, "%s/%s", - notmuch_config_get_database_path (config), + notmuch_config_get (notmuch, NOTMUCH_CONFIG_DATABASE_PATH), ".notmuch"); if (stat (db_path, &st)) { if (errno != ENOENT) { @@ -409,8 +409,8 @@ notmuch_command (notmuch_config_t *config, "or any other interface described at https://notmuchmail.org\n\n" "And don't forget to run \"notmuch new\" whenever new mail arrives.\n\n" "Have fun, and may your inbox never have much mail.\n\n", - notmuch_config_get_user_name (config), - notmuch_config_get_user_primary_email (config)); + notmuch_config_get (notmuch, NOTMUCH_CONFIG_USER_NAME), + notmuch_config_get (notmuch, NOTMUCH_CONFIG_PRIMARY_EMAIL)); return EXIT_SUCCESS; } -- 2.30.0
--- notmuch-client.h | 1 + notmuch.c | 29 ++++++++++++++++++++++++++--- test/T030-config.sh | 11 +++++++---- test/T590-libconfig.sh | 3 --- 4 files changed, 34 insertions(+), 10 deletions(-) diff --git a/notmuch-client.h b/notmuch-client.h index f60f5406..db88daf8 100644 --- a/notmuch-client.h +++ b/notmuch-client.h @@ -258,6 +258,7 @@ typedef enum { NOTMUCH_COMMAND_DATABASE_EARLY = 1 << 2, NOTMUCH_COMMAND_DATABASE_WRITE = 1 << 3, NOTMUCH_COMMAND_DATABASE_CREATE = 1 << 4, + NOTMUCH_COMMAND_CONFIG_LOAD = 1 << 5, } notmuch_command_mode_t; notmuch_config_t * diff --git a/notmuch.c b/notmuch.c index a161f127..90504d37 100644 --- a/notmuch.c +++ b/notmuch.c @@ -168,7 +168,7 @@ static command_t commands[] = { "Compact the notmuch database." }, { "reindex", notmuch_reindex_command, NOTMUCH_COMMAND_DATABASE_EARLY | NOTMUCH_COMMAND_DATABASE_WRITE, "Re-index all messages matching the search terms." }, - { "config", notmuch_config_command, NOTMUCH_COMMAND_CONFIG_OPEN, + { "config", notmuch_config_command, NOTMUCH_COMMAND_CONFIG_OPEN | NOTMUCH_COMMAND_CONFIG_LOAD, "Get or set settings in the notmuch configuration file." }, #if WITH_EMACS { "emacs-mua", NULL, 0, @@ -460,7 +460,7 @@ main (int argc, char *argv[]) notmuch_config_t *config = NULL; notmuch_database_t *notmuch = NULL; int opt_index; - int ret; + int ret = EXIT_SUCCESS; notmuch_opt_desc_t options[] = { { .opt_string = &config_file_name, .name = "config" }, @@ -548,7 +548,30 @@ main (int argc, char *argv[]) return EXIT_FAILURE; } } - } else { + } + + if (command->mode & NOTMUCH_COMMAND_CONFIG_LOAD) { + char *status_string = NULL; + notmuch_status_t status; + status = notmuch_database_load_config (NULL, + config_file_name, + NULL, + ¬much, + &status_string); + if (status) { + if (status_string) { + fputs (status_string, stderr); + free (status_string); + } + + if (status == NOTMUCH_STATUS_NO_CONFIG) + fputs ("Try running 'notmuch setup' to create a configuration.", stderr); + goto DONE; + } + + } + + if (command->mode & NOTMUCH_COMMAND_CONFIG_OPEN) { config = notmuch_config_open (local, config_file_name, command->mode); if (! config) { ret = EXIT_FAILURE; diff --git a/test/T030-config.sh b/test/T030-config.sh index 67c9545c..14d1f4f2 100755 --- a/test/T030-config.sh +++ b/test/T030-config.sh @@ -96,14 +96,17 @@ test_expect_equal "$(notmuch --config=alt-config-link config get user.name)" \ test_begin_subtest "Writing config file through symlink follows symlink" test_expect_equal "$(readlink alt-config-link)" "alt-config" +db_path=${HOME}/database-path + test_begin_subtest "Absolute database path returned" -notmuch config set database.path ${HOME}/Maildir +mkdir -p ${db_path} +notmuch config set database.path ${db_path} test_expect_equal "$(notmuch config get database.path)" \ - "${HOME}/Maildir" + "${db_path}" test_begin_subtest "Relative database path properly expanded" -notmuch config set database.path Maildir +notmuch config set database.path ${db_path} test_expect_equal "$(notmuch config get database.path)" \ - "${HOME}/Maildir" + "${db_path}" test_done diff --git a/test/T590-libconfig.sh b/test/T590-libconfig.sh index 01a9ac06..cf294d04 100755 --- a/test/T590-libconfig.sh +++ b/test/T590-libconfig.sh @@ -626,9 +626,6 @@ EOF test_begin_subtest "notmuch_database_get_config (ndlc)" -echo NOTMUCH_CONFIG=$NOTMUCH_CONFIG -echo NOTMUCH_PROFILE=$NOTMUCH_PROFILE -echo HOME=$HOME cat c_head2 - c_tail <<'EOF' | test_C ${MAIL_DIR} %NULL% %NULL% { EXPECT0(notmuch_database_get_config (db, "test.key1", &val)); -- 2.30.0
--- notmuch-config.c | 92 +++++---------------------------------------- test/T030-config.sh | 20 +++++++++- 2 files changed, 28 insertions(+), 84 deletions(-) diff --git a/notmuch-config.c b/notmuch-config.c index 0193401f..a4613227 100644 --- a/notmuch-config.c +++ b/notmuch-config.c @@ -862,89 +862,17 @@ _config_key_info (const char *item) return NULL; } -static bool -_stored_in_db (const char *item) -{ - config_key_info_t *info; - - info = _config_key_info (item); - - return (info && info->in_db); -} - -static int -_print_db_config (notmuch_config_t *config, const char *name) -{ - notmuch_database_t *notmuch; - char *val; - - if (notmuch_database_open (notmuch_config_get_database_path (config), - NOTMUCH_DATABASE_MODE_READ_ONLY, ¬much)) - return EXIT_FAILURE; - - /* XXX Handle UUID mismatch? */ - - if (print_status_database ("notmuch config", notmuch, - notmuch_database_get_config (notmuch, name, &val))) - return EXIT_FAILURE; - - puts (val); - - return EXIT_SUCCESS; -} - static int -notmuch_config_command_get (notmuch_config_t *config, char *item) +notmuch_config_command_get (notmuch_database_t *notmuch, char *item) { - if (strcmp (item, "database.path") == 0) { - printf ("%s\n", notmuch_config_get_database_path (config)); - } else if (strcmp (item, "user.name") == 0) { - printf ("%s\n", notmuch_config_get_user_name (config)); - } else if (strcmp (item, "user.primary_email") == 0) { - printf ("%s\n", notmuch_config_get_user_primary_email (config)); - } else if (strcmp (item, "user.other_email") == 0) { - const char **other_email; - size_t i, length; - - other_email = notmuch_config_get_user_other_email (config, &length); - for (i = 0; i < length; i++) - printf ("%s\n", other_email[i]); - } else if (strcmp (item, "new.tags") == 0) { - const char **tags; - size_t i, length; - - tags = notmuch_config_get_new_tags (config, &length); - for (i = 0; i < length; i++) - printf ("%s\n", tags[i]); - } else if (STRNCMP_LITERAL (item, BUILT_WITH_PREFIX) == 0) { - printf ("%s\n", - notmuch_built_with (item + strlen (BUILT_WITH_PREFIX)) ? "true" : "false"); - } else if (_stored_in_db (item)) { - return _print_db_config (config, item); - } else { - char **value; - size_t i, length; - char *group, *key; - - if (_item_split (item, &group, &key)) - return 1; - - value = g_key_file_get_string_list (config->key_file, - group, key, - &length, NULL); - if (value == NULL) { - fprintf (stderr, "Unknown configuration item: %s.%s\n", - group, key); - return 1; - } - - for (i = 0; i < length; i++) - printf ("%s\n", value[i]); - - g_strfreev (value); + notmuch_config_values_t *list; + for (list = notmuch_database_get_config_values (notmuch, item); + notmuch_config_values_valid (list); + notmuch_config_values_move_to_next (list)) { + const char *val = notmuch_config_values_get (list); + puts(val); } - - return 0; + return EXIT_SUCCESS; } static int @@ -1105,7 +1033,7 @@ notmuch_config_command_list (notmuch_config_t *config) } int -notmuch_config_command (notmuch_config_t *config, unused(notmuch_database_t *notmuch), int argc, char *argv[]) +notmuch_config_command (notmuch_config_t *config, notmuch_database_t *notmuch, int argc, char *argv[]) { int ret; int opt_index; @@ -1133,7 +1061,7 @@ notmuch_config_command (notmuch_config_t *config, unused(notmuch_database_t *not "one argument.\n"); return EXIT_FAILURE; } - ret = notmuch_config_command_get (config, argv[1]); + ret = notmuch_config_command_get (notmuch, argv[1]); } else if (strcmp (argv[0], "set") == 0) { if (argc < 2) { fprintf (stderr, "Error: notmuch config set requires at least " diff --git a/test/T030-config.sh b/test/T030-config.sh index 14d1f4f2..023e97b3 100755 --- a/test/T030-config.sh +++ b/test/T030-config.sh @@ -7,9 +7,12 @@ test_begin_subtest "Get string value" test_expect_equal "$(notmuch config get user.name)" "Notmuch Test Suite" test_begin_subtest "Get list value" -test_expect_equal "$(notmuch config get new.tags)" "\ +cat <<EOF > EXPECTED +inbox unread -inbox" +EOF +notmuch config get new.tags | sort > OUTPUT +test_expect_equal_file EXPECTED OUTPUT test_begin_subtest "Set string value" notmuch config set foo.string "this is a string value" @@ -96,6 +99,18 @@ test_expect_equal "$(notmuch --config=alt-config-link config get user.name)" \ test_begin_subtest "Writing config file through symlink follows symlink" test_expect_equal "$(readlink alt-config-link)" "alt-config" +test_begin_subtest "Round trip arbitrary key" +key=g${RANDOM}.m${RANDOM} +value=${RANDOM} +notmuch config set ${key} ${value} +output=$(notmuch config get ${key}) +test_expect_equal "${output}" "${value}" + +test_begin_subtest "Clear arbitrary key" +notmuch config set ${key} +output=$(notmuch config get ${key}) +test_expect_equal "${output}" "" + db_path=${HOME}/database-path test_begin_subtest "Absolute database path returned" @@ -109,4 +124,5 @@ notmuch config set database.path ${db_path} test_expect_equal "$(notmuch config get database.path)" \ "${db_path}" + test_done -- 2.30.0
--- notmuch-setup.c | 55 +++++++++++++++++++++++-------------------------- notmuch.c | 19 ++++++++++------- 2 files changed, 38 insertions(+), 36 deletions(-) diff --git a/notmuch-setup.c b/notmuch-setup.c index 67214470..1e22412b 100644 --- a/notmuch-setup.c +++ b/notmuch-setup.c @@ -88,14 +88,17 @@ welcome_message_post_setup (void) } static void -print_tag_list (const char **tags, size_t tags_len) +print_tag_list (notmuch_config_values_t *tags) { - unsigned int i; - - for (i = 0; i < tags_len; i++) { - if (i != 0) - printf (" "); - printf ("%s", tags[i]); + bool first = false; + + for (; + notmuch_config_values_valid(tags); + notmuch_config_values_move_to_next (tags)) { + if (!first) + printf(" "); + first = false; + printf("%s", notmuch_config_values_get (tags)); } } @@ -122,19 +125,13 @@ parse_tag_list (void *ctx, char *response) int notmuch_setup_command (notmuch_config_t *config, - unused(notmuch_database_t *notmuch), + notmuch_database_t *notmuch, int argc, char *argv[]) { char *response = NULL; size_t response_size = 0; - const char **old_other_emails; - size_t old_other_emails_len; GPtrArray *other_emails; - unsigned int i; - const char **new_tags; - size_t new_tags_len; - const char **search_exclude_tags; - size_t search_exclude_tags_len; + notmuch_config_values_t *new_tags, *search_exclude_tags, *emails; #define prompt(format, ...) \ do { \ @@ -157,26 +154,27 @@ notmuch_setup_command (notmuch_config_t *config, if (notmuch_config_is_new (config)) welcome_message_pre_setup (); - prompt ("Your full name [%s]: ", notmuch_config_get_user_name (config)); + prompt ("Your full name [%s]: ", notmuch_config_get (notmuch, NOTMUCH_CONFIG_USER_NAME)); if (strlen (response)) notmuch_config_set_user_name (config, response); prompt ("Your primary email address [%s]: ", - notmuch_config_get_user_primary_email (config)); + notmuch_config_get (notmuch, NOTMUCH_CONFIG_PRIMARY_EMAIL)); if (strlen (response)) notmuch_config_set_user_primary_email (config, response); other_emails = g_ptr_array_new (); - old_other_emails = notmuch_config_get_user_other_email (config, - &old_other_emails_len); - for (i = 0; i < old_other_emails_len; i++) { - prompt ("Additional email address [%s]: ", old_other_emails[i]); + for (emails = notmuch_config_get_values (notmuch, NOTMUCH_CONFIG_OTHER_EMAIL); + notmuch_config_values_valid (emails); + notmuch_config_values_move_to_next (emails)) { + const char *email = notmuch_config_values_get (emails); + + prompt ("Additional email address [%s]: ", email); if (strlen (response)) g_ptr_array_add (other_emails, talloc_strdup (config, response)); else - g_ptr_array_add (other_emails, talloc_strdup (config, - old_other_emails[i])); + g_ptr_array_add (other_emails, talloc_strdup (config, email)); } do { @@ -192,7 +190,7 @@ notmuch_setup_command (notmuch_config_t *config, g_ptr_array_free (other_emails, true); prompt ("Top-level directory of your email archive [%s]: ", - notmuch_config_get_database_path (config)); + notmuch_config_get (notmuch, NOTMUCH_CONFIG_DATABASE_PATH)); if (strlen (response)) { const char *absolute_path; @@ -200,10 +198,10 @@ notmuch_setup_command (notmuch_config_t *config, notmuch_config_set_database_path (config, absolute_path); } - new_tags = notmuch_config_get_new_tags (config, &new_tags_len); + new_tags = notmuch_config_get_values (notmuch, NOTMUCH_CONFIG_NEW_TAGS); printf ("Tags to apply to all new messages (separated by spaces) ["); - print_tag_list (new_tags, new_tags_len); + print_tag_list (new_tags); prompt ("]: "); if (strlen (response)) { @@ -215,11 +213,10 @@ notmuch_setup_command (notmuch_config_t *config, g_ptr_array_free (tags, true); } - - search_exclude_tags = notmuch_config_get_search_exclude_tags (config, &search_exclude_tags_len); + search_exclude_tags = notmuch_config_get_values (notmuch, NOTMUCH_CONFIG_EXCLUDE_TAGS); printf ("Tags to exclude when searching messages (separated by spaces) ["); - print_tag_list (search_exclude_tags, search_exclude_tags_len); + print_tag_list (search_exclude_tags); prompt ("]: "); if (strlen (response)) { diff --git a/notmuch.c b/notmuch.c index 90504d37..7beeb177 100644 --- a/notmuch.c +++ b/notmuch.c @@ -139,9 +139,11 @@ notmuch_process_shared_indexing_options (notmuch_database_t *notmuch) static command_t commands[] = { - { NULL, notmuch_command, NOTMUCH_COMMAND_CONFIG_OPEN | NOTMUCH_COMMAND_CONFIG_CREATE, + { NULL, notmuch_command, NOTMUCH_COMMAND_CONFIG_OPEN | NOTMUCH_COMMAND_CONFIG_CREATE + | NOTMUCH_COMMAND_CONFIG_LOAD, "Notmuch main command." }, - { "setup", notmuch_setup_command, NOTMUCH_COMMAND_CONFIG_OPEN | NOTMUCH_COMMAND_CONFIG_CREATE, + { "setup", notmuch_setup_command, NOTMUCH_COMMAND_CONFIG_OPEN | NOTMUCH_COMMAND_CONFIG_CREATE + | NOTMUCH_COMMAND_CONFIG_LOAD, "Interactively set up notmuch for first use." }, { "new", notmuch_new_command, NOTMUCH_COMMAND_DATABASE_EARLY | NOTMUCH_COMMAND_DATABASE_WRITE | NOTMUCH_COMMAND_DATABASE_CREATE, @@ -374,7 +376,7 @@ notmuch_command (notmuch_config_t *config, * notmuch_setup_command which will give a nice welcome message, * and interactively guide the user through the configuration. */ if (notmuch_config_is_new (config)) - return notmuch_setup_command (config, NULL, 0, NULL); + return notmuch_setup_command (config, notmuch, 0, NULL); /* Notmuch is already configured, but is there a database? */ db_path = talloc_asprintf (config, "%s/%s", @@ -558,14 +560,17 @@ main (int argc, char *argv[]) NULL, ¬much, &status_string); - if (status) { + + if (status == NOTMUCH_STATUS_NO_CONFIG && !(command->mode & NOTMUCH_COMMAND_CONFIG_CREATE)) { + fputs ("Try running 'notmuch setup' to create a configuration.", stderr); + goto DONE; + } + + if (status && (status != NOTMUCH_STATUS_NO_CONFIG)) { if (status_string) { fputs (status_string, stderr); free (status_string); } - - if (status == NOTMUCH_STATUS_NO_CONFIG) - fputs ("Try running 'notmuch setup' to create a configuration.", stderr); goto DONE; } -- 2.30.0
Test output changes because keys are now listed in alphabetical order, and because a missing database is no longer an error. --- notmuch-config.c | 69 ++++++++------------------------------------- test/T030-config.sh | 27 ++++++++---------- test/T040-setup.sh | 27 +++++++++++------- 3 files changed, 40 insertions(+), 83 deletions(-) diff --git a/notmuch-config.c b/notmuch-config.c index a4613227..f46e5c27 100644 --- a/notmuch-config.c +++ b/notmuch-config.c @@ -969,69 +969,22 @@ _notmuch_config_list_built_with () } static int -_list_db_config (notmuch_config_t *config) +notmuch_config_command_list (notmuch_database_t *notmuch) { - notmuch_database_t *notmuch; - notmuch_config_list_t *list; - - if (notmuch_database_open (notmuch_config_get_database_path (config), - NOTMUCH_DATABASE_MODE_READ_ONLY, ¬much)) - return EXIT_FAILURE; + notmuch_config_pairs_t *list; - /* XXX Handle UUID mismatch? */ - - - if (print_status_database ("notmuch config", notmuch, - notmuch_database_get_config_list (notmuch, "", &list))) - return EXIT_FAILURE; - - for (; notmuch_config_list_valid (list); notmuch_config_list_move_to_next (list)) { - printf ("%s=%s\n", notmuch_config_list_key (list), notmuch_config_list_value (list)); + _notmuch_config_list_built_with (); + for (list = notmuch_config_get_pairs (notmuch, ""); + notmuch_config_pairs_valid (list); + notmuch_config_pairs_move_to_next (list)) { + const char *value = notmuch_config_pairs_value (list); + if (value) + printf ("%s=%s\n", notmuch_config_pairs_key (list), value); } - notmuch_config_list_destroy (list); - + notmuch_config_pairs_destroy (list); return EXIT_SUCCESS; } -static int -notmuch_config_command_list (notmuch_config_t *config) -{ - char **groups; - size_t g, groups_length; - - groups = g_key_file_get_groups (config->key_file, &groups_length); - if (groups == NULL) - return 1; - - for (g = 0; g < groups_length; g++) { - char **keys; - size_t k, keys_length; - - keys = g_key_file_get_keys (config->key_file, - groups[g], &keys_length, NULL); - if (keys == NULL) - continue; - - for (k = 0; k < keys_length; k++) { - char *value; - - value = g_key_file_get_string (config->key_file, - groups[g], keys[k], NULL); - if (value != NULL) { - printf ("%s.%s=%s\n", groups[g], keys[k], value); - free (value); - } - } - - g_strfreev (keys); - } - - g_strfreev (groups); - - _notmuch_config_list_built_with (); - return _list_db_config (config); -} - int notmuch_config_command (notmuch_config_t *config, notmuch_database_t *notmuch, int argc, char *argv[]) { @@ -1070,7 +1023,7 @@ notmuch_config_command (notmuch_config_t *config, notmuch_database_t *notmuch, i } ret = notmuch_config_command_set (config, argv[1], argc - 2, argv + 2); } else if (strcmp (argv[0], "list") == 0) { - ret = notmuch_config_command_list (config); + ret = notmuch_config_command_list (notmuch); } else { fprintf (stderr, "Unrecognized argument for notmuch config: %s\n", argv[0]); diff --git a/test/T030-config.sh b/test/T030-config.sh index 023e97b3..d974850f 100755 --- a/test/T030-config.sh +++ b/test/T030-config.sh @@ -46,25 +46,22 @@ notmuch config set foo.nonexistent test_expect_equal "$(notmuch config get foo.nonexistent)" "" test_begin_subtest "List all items" -notmuch config list > STDOUT 2> STDERR -printf "%s\n====\n%s\n" "$(< STDOUT)" "$(< STDERR)" | notmuch_config_sanitize > OUTPUT - +notmuch config list 2>&1 | notmuch_config_sanitize > OUTPUT cat <<EOF > EXPECTED -database.path=MAIL_DIR -user.name=Notmuch Test Suite -user.primary_email=test_suite@notmuchmail.org -user.other_email=test_suite_other@notmuchmail.org;test_suite@otherdomain.org -new.tags=unread;inbox; -new.ignore= -search.exclude_tags= -maildir.synchronize_flags=true -foo.string=this is another string value -foo.list=this;is another;list value; built_with.compact=something built_with.field_processor=something built_with.retry_lock=something -==== -Error: Cannot open database at MAIL_DIR/.notmuch: No such file or directory. +database.mail_root=MAIL_DIR +database.path=MAIL_DIR +foo.list=this;is another;list value; +foo.string=this is another string value +maildir.synchronize_flags=true +new.ignore= +new.tags=unread;inbox; +search.exclude_tags= +user.name=Notmuch Test Suite +user.other_email=test_suite_other@notmuchmail.org;test_suite@otherdomain.org +user.primary_email=test_suite@notmuchmail.org EOF test_expect_equal_file EXPECTED OUTPUT diff --git a/test/T040-setup.sh b/test/T040-setup.sh index 1223ebf7..87d386fd 100755 --- a/test/T040-setup.sh +++ b/test/T040-setup.sh @@ -20,18 +20,25 @@ foo bar baz EOF -output=$(notmuch --config=new-notmuch-config config list | notmuch_built_with_sanitize) -test_expect_equal "$output" "\ +cat <<EOF > EXPECTED +built_with.compact=something +built_with.field_processor=something +built_with.retry_lock=something +database.mail_root=/path/to/maildir database.path=/path/to/maildir -user.name=Test Suite -user.primary_email=test.suite@example.com -user.other_email=another.suite@example.com; -new.tags=foo;bar; +maildir.synchronize_flags=true new.ignore= +new.tags=foo;bar; search.exclude_tags=baz; -maildir.synchronize_flags=true -built_with.compact=something -built_with.field_processor=something -built_with.retry_lock=something" +user.name=Test Suite +user.other_email=another.suite@example.com; +user.primary_email=test.suite@example.com +EOF + +notmuch --config=new-notmuch-config config list | notmuch_built_with_sanitize > OUTPUT + +test_expect_equal_file EXPECTED OUTPUT + + test_done -- 2.30.0
notmuch_config_open will be preserved in the medium term for use by the commands that are manipulating the config file directly (config and setup) --- lib/config.cc | 5 +- notmuch-client.h | 2 +- notmuch-config.c | 157 +---------------------------------------- notmuch.c | 2 +- test/T030-config.sh | 2 +- test/T590-libconfig.sh | 12 ++-- 6 files changed, 15 insertions(+), 165 deletions(-) diff --git a/lib/config.cc b/lib/config.cc index 03ba2731..44cbe711 100644 --- a/lib/config.cc +++ b/lib/config.cc @@ -575,7 +575,7 @@ _notmuch_config_default (notmuch_database_t *notmuch, notmuch_config_key_t key) case NOTMUCH_CONFIG_EXCLUDE_TAGS: return ""; case NOTMUCH_CONFIG_NEW_TAGS: - return "inbox;unread"; + return "unread;inbox"; case NOTMUCH_CONFIG_SYNC_MAILDIR_FLAGS: return "true"; case NOTMUCH_CONFIG_USER_NAME: @@ -592,9 +592,10 @@ _notmuch_config_default (notmuch_database_t *notmuch, notmuch_config_key_t key) else email = _get_email_from_passwd_file (notmuch); return email; + case NOTMUCH_CONFIG_NEW_IGNORE: + return ""; case NOTMUCH_CONFIG_HOOK_DIR: case NOTMUCH_CONFIG_BACKUP_DIR: - case NOTMUCH_CONFIG_NEW_IGNORE: case NOTMUCH_CONFIG_OTHER_EMAIL: return NULL; default: diff --git a/notmuch-client.h b/notmuch-client.h index db88daf8..dfdfc876 100644 --- a/notmuch-client.h +++ b/notmuch-client.h @@ -262,7 +262,7 @@ typedef enum { } notmuch_command_mode_t; notmuch_config_t * -notmuch_config_open (void *ctx, +notmuch_config_open (notmuch_database_t *notmuch, const char *filename, notmuch_command_mode_t config_mode); diff --git a/notmuch-config.c b/notmuch-config.c index f46e5c27..3d0959fb 100644 --- a/notmuch-config.c +++ b/notmuch-config.c @@ -141,69 +141,6 @@ notmuch_config_destructor (notmuch_config_t *config) return 0; } -static char * -get_name_from_passwd_file (void *ctx) -{ - long pw_buf_size; - char *pw_buf; - struct passwd passwd, *ignored; - char *name; - int e; - - pw_buf_size = sysconf (_SC_GETPW_R_SIZE_MAX); - if (pw_buf_size == -1) pw_buf_size = 64; - pw_buf = talloc_size (ctx, pw_buf_size); - - while ((e = getpwuid_r (getuid (), &passwd, pw_buf, - pw_buf_size, &ignored)) == ERANGE) { - pw_buf_size = pw_buf_size * 2; - pw_buf = talloc_zero_size (ctx, pw_buf_size); - } - - if (e == 0) { - char *comma = strchr (passwd.pw_gecos, ','); - if (comma) - name = talloc_strndup (ctx, passwd.pw_gecos, - comma - passwd.pw_gecos); - else - name = talloc_strdup (ctx, passwd.pw_gecos); - } else { - name = talloc_strdup (ctx, ""); - } - - talloc_free (pw_buf); - - return name; -} - -static char * -get_username_from_passwd_file (void *ctx) -{ - long pw_buf_size; - char *pw_buf; - struct passwd passwd, *ignored; - char *name; - int e; - - pw_buf_size = sysconf (_SC_GETPW_R_SIZE_MAX); - if (pw_buf_size == -1) pw_buf_size = 64; - pw_buf = talloc_zero_size (ctx, pw_buf_size); - - while ((e = getpwuid_r (getuid (), &passwd, pw_buf, - pw_buf_size, &ignored)) == ERANGE) { - pw_buf_size = pw_buf_size * 2; - pw_buf = talloc_zero_size (ctx, pw_buf_size); - } - - if (e == 0) - name = talloc_strdup (ctx, passwd.pw_name); - else - name = talloc_strdup (ctx, ""); - - talloc_free (pw_buf); - - return name; -} static bool get_config_from_file (notmuch_config_t *config, bool create_new) @@ -322,12 +259,10 @@ get_config_from_file (notmuch_config_t *config, bool create_new) * user in editing the file directly. */ notmuch_config_t * -notmuch_config_open (void *ctx, +notmuch_config_open (notmuch_database_t *notmuch, const char *filename, notmuch_command_mode_t config_mode) { - GError *error = NULL; - size_t tmp; char *notmuch_config_env = NULL; int file_had_database_group; int file_had_new_group; @@ -336,7 +271,7 @@ notmuch_config_open (void *ctx, int file_had_search_group; int file_had_crypto_group; - notmuch_config_t *config = talloc_zero (ctx, notmuch_config_t); + notmuch_config_t *config = talloc_zero (notmuch, notmuch_config_t); if (config == NULL) { fprintf (stderr, "Out of memory.\n"); @@ -368,15 +303,10 @@ notmuch_config_open (void *ctx, } } + /* Whenever we know of configuration sections that don't appear in * the configuration file, we add some comments to help the user * understand what can be done. - * - * It would be convenient to just add those comments now, but - * apparently g_key_file will clear any comments when keys are - * added later that create the groups. So we have to check for the - * groups now, but add the comments only after setting all of our - * values. */ file_had_database_group = g_key_file_has_group (config->key_file, "database"); @@ -386,87 +316,6 @@ notmuch_config_open (void *ctx, file_had_search_group = g_key_file_has_group (config->key_file, "search"); file_had_crypto_group = g_key_file_has_group (config->key_file, "crypto"); - if (notmuch_config_get_database_path (config) == NULL) { - char *path = getenv ("MAILDIR"); - if (path) - path = talloc_strdup (config, path); - else - path = talloc_asprintf (config, "%s/mail", - getenv ("HOME")); - notmuch_config_set_database_path (config, path); - talloc_free (path); - } - - if (notmuch_config_get_user_name (config) == NULL) { - char *name = getenv ("NAME"); - if (name) - name = talloc_strdup (config, name); - else - name = get_name_from_passwd_file (config); - notmuch_config_set_user_name (config, name); - talloc_free (name); - } - - if (notmuch_config_get_user_primary_email (config) == NULL) { - char *email = getenv ("EMAIL"); - if (email) { - notmuch_config_set_user_primary_email (config, email); - } else { - char hostname[256]; - struct hostent *hostent; - const char *domainname; - - char *username = get_username_from_passwd_file (config); - - gethostname (hostname, 256); - hostname[255] = '\0'; - - hostent = gethostbyname (hostname); - if (hostent && (domainname = strchr (hostent->h_name, '.'))) - domainname += 1; - else - domainname = "(none)"; - - email = talloc_asprintf (config, "%s@%s.%s", - username, hostname, domainname); - - notmuch_config_set_user_primary_email (config, email); - - talloc_free (username); - talloc_free (email); - } - } - - if (notmuch_config_get_new_tags (config, &tmp) == NULL) { - const char *tags[] = { "unread", "inbox" }; - notmuch_config_set_new_tags (config, tags, 2); - } - - if (notmuch_config_get_new_ignore (config, &tmp) == NULL) { - notmuch_config_set_new_ignore (config, NULL, 0); - } - - if (notmuch_config_get_search_exclude_tags (config, &tmp) == NULL) { - if (config->is_new) { - const char *tags[] = { "deleted", "spam" }; - notmuch_config_set_search_exclude_tags (config, tags, 2); - } else { - notmuch_config_set_search_exclude_tags (config, NULL, 0); - } - } - - error = NULL; - config->maildir_synchronize_flags = - g_key_file_get_boolean (config->key_file, - "maildir", "synchronize_flags", &error); - if (error) { - notmuch_config_set_maildir_synchronize_flags (config, true); - g_error_free (error); - } - - /* Whenever we know of configuration sections that don't appear in - * the configuration file, we add some comments to help the user - * understand what can be done. */ if (config->is_new) g_key_file_set_comment (config->key_file, NULL, NULL, toplevel_config_comment, NULL); diff --git a/notmuch.c b/notmuch.c index 7beeb177..093af0a5 100644 --- a/notmuch.c +++ b/notmuch.c @@ -577,7 +577,7 @@ main (int argc, char *argv[]) } if (command->mode & NOTMUCH_COMMAND_CONFIG_OPEN) { - config = notmuch_config_open (local, config_file_name, command->mode); + config = notmuch_config_open (notmuch, config_file_name, command->mode); if (! config) { ret = EXIT_FAILURE; goto DONE; diff --git a/test/T030-config.sh b/test/T030-config.sh index d974850f..9a43c1e4 100755 --- a/test/T030-config.sh +++ b/test/T030-config.sh @@ -57,7 +57,7 @@ foo.list=this;is another;list value; foo.string=this is another string value maildir.synchronize_flags=true new.ignore= -new.tags=unread;inbox; +new.tags=unread;inbox search.exclude_tags= user.name=Notmuch Test Suite user.other_email=test_suite_other@notmuchmail.org;test_suite@otherdomain.org diff --git a/test/T590-libconfig.sh b/test/T590-libconfig.sh index cf294d04..75b47073 100755 --- a/test/T590-libconfig.sh +++ b/test/T590-libconfig.sh @@ -394,8 +394,8 @@ MAIL_DIR MAIL_DIR/.notmuch/hooks MAIL_DIR/.notmuch/backups -inbox;unread -NULL +unread;inbox + true USERNAME@FQDN NULL @@ -705,7 +705,7 @@ MAIL_DIR MAIL_DIR/.notmuch/hooks MAIL_DIR/.notmuch/backups foo;bar;fub -unread;inbox; +unread;inbox sekrit_junk true test_suite@notmuchmail.org @@ -736,8 +736,8 @@ MAIL_DIR MAIL_DIR/.notmuch/hooks MAIL_DIR/.notmuch/backups -inbox;unread -NULL +unread;inbox + true USERNAME@FQDN NULL @@ -815,7 +815,7 @@ database.path MAIL_DIR key with spaces value, with, spaces! maildir.synchronize_flags true new.ignore sekrit_junk -new.tags unread;inbox; +new.tags unread;inbox search.exclude_tags foo;bar;fub test.key1 testvalue1 test.key2 testvalue2 -- 2.30.0
--- notmuch-config.c | 16 +++++++--------- test/T750-user-header.sh | 3 ++- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/notmuch-config.c b/notmuch-config.c index 3d0959fb..390998b1 100644 --- a/notmuch-config.c +++ b/notmuch-config.c @@ -725,9 +725,8 @@ notmuch_config_command_get (notmuch_database_t *notmuch, char *item) } static int -_set_db_config (notmuch_config_t *config, const char *key, int argc, char **argv) +_set_db_config (notmuch_database_t *notmuch, const char *key, int argc, char **argv) { - notmuch_database_t *notmuch; const char *val = ""; if (argc > 1) { @@ -740,12 +739,11 @@ _set_db_config (notmuch_config_t *config, const char *key, int argc, char **argv val = argv[0]; } - if (notmuch_database_open (notmuch_config_get_database_path (config), - NOTMUCH_DATABASE_MODE_READ_WRITE, ¬much)) + if (print_status_database ("notmuch config", notmuch, + notmuch_database_reopen (notmuch, + NOTMUCH_DATABASE_MODE_READ_WRITE))) return EXIT_FAILURE; - /* XXX Handle UUID mismatch? */ - if (print_status_database ("notmuch config", notmuch, notmuch_database_set_config (notmuch, key, val))) return EXIT_FAILURE; @@ -758,7 +756,7 @@ _set_db_config (notmuch_config_t *config, const char *key, int argc, char **argv } static int -notmuch_config_command_set (notmuch_config_t *config, char *item, int argc, char *argv[]) +notmuch_config_command_set (notmuch_config_t *config, notmuch_database_t *notmuch, char *item, int argc, char *argv[]) { char *group, *key; config_key_info_t *key_info; @@ -773,7 +771,7 @@ notmuch_config_command_set (notmuch_config_t *config, char *item, int argc, char return 1; if (key_info && key_info->in_db) { - return _set_db_config (config, item, argc, argv); + return _set_db_config (notmuch, item, argc, argv); } if (_item_split (item, &group, &key)) @@ -870,7 +868,7 @@ notmuch_config_command (notmuch_config_t *config, notmuch_database_t *notmuch, i "one argument.\n"); return EXIT_FAILURE; } - ret = notmuch_config_command_set (config, argv[1], argc - 2, argv + 2); + ret = notmuch_config_command_set (config, notmuch, argv[1], argc - 2, argv + 2); } else if (strcmp (argv[0], "list") == 0) { ret = notmuch_config_command_list (notmuch); } else { diff --git a/test/T750-user-header.sh b/test/T750-user-header.sh index b19db571..586788b3 100755 --- a/test/T750-user-header.sh +++ b/test/T750-user-header.sh @@ -5,7 +5,8 @@ test_description='indexing user specified headers' test_begin_subtest "error adding user header before initializing DB" notmuch config set index.header.List List-Id 2>&1 | notmuch_dir_sanitize > OUTPUT cat <<EOF > EXPECTED -Error: Cannot open database at MAIL_DIR/.notmuch: No such file or directory. +notmuch config: Illegal argument for function +Cannot reopen closed or nonexistent database EOF test_expect_equal_file EXPECTED OUTPUT -- 2.30.0
These are no longer used, replaced by notmuch_config_get. --- notmuch-client.h | 29 ------------ notmuch-config.c | 119 ----------------------------------------------- 2 files changed, 148 deletions(-) diff --git a/notmuch-client.h b/notmuch-client.h index dfdfc876..677f2f39 100644 --- a/notmuch-client.h +++ b/notmuch-client.h @@ -275,70 +275,41 @@ notmuch_config_save (notmuch_config_t *config); bool notmuch_config_is_new (notmuch_config_t *config); -const char * -notmuch_config_get_database_path (notmuch_config_t *config); - void notmuch_config_set_database_path (notmuch_config_t *config, const char *database_path); -const char * -notmuch_config_get_user_name (notmuch_config_t *config); - void notmuch_config_set_user_name (notmuch_config_t *config, const char *user_name); -const char * -notmuch_config_get_user_primary_email (notmuch_config_t *config); - void notmuch_config_set_user_primary_email (notmuch_config_t *config, const char *primary_email); -const char ** -notmuch_config_get_user_other_email (notmuch_config_t *config, - size_t *length); - void notmuch_config_set_user_other_email (notmuch_config_t *config, const char *other_email[], size_t length); -const char ** -notmuch_config_get_new_tags (notmuch_config_t *config, - size_t *length); void notmuch_config_set_new_tags (notmuch_config_t *config, const char *new_tags[], size_t length); -const char ** -notmuch_config_get_new_ignore (notmuch_config_t *config, - size_t *length); - void notmuch_config_set_new_ignore (notmuch_config_t *config, const char *new_ignore[], size_t length); -bool -notmuch_config_get_maildir_synchronize_flags (notmuch_config_t *config); - void notmuch_config_set_maildir_synchronize_flags (notmuch_config_t *config, bool synchronize_flags); -const char ** -notmuch_config_get_search_exclude_tags (notmuch_config_t *config, size_t *length); - void notmuch_config_set_search_exclude_tags (notmuch_config_t *config, const char *list[], size_t length); -const char * -_notmuch_config_get_path (notmuch_config_t *config); - int notmuch_run_hook (notmuch_database_t *notmuch, const char *hook); diff --git a/notmuch-config.c b/notmuch-config.c index 390998b1..1382b0a3 100644 --- a/notmuch-config.c +++ b/notmuch-config.c @@ -359,9 +359,6 @@ notmuch_config_close (notmuch_config_t *config) talloc_free (config); } -const char *_notmuch_config_get_path (notmuch_config_t *config) { - return config->filename; -} /* Save any changes made to the notmuch configuration. * * Any comments originally in the file will be preserved. @@ -425,22 +422,6 @@ notmuch_config_is_new (notmuch_config_t *config) return config->is_new; } -static const char * -_config_get (notmuch_config_t *config, char **field, - const char *group, const char *key) -{ - /* read from config file and cache value, if not cached already */ - if (*field == NULL) { - char *value; - value = g_key_file_get_string (config->key_file, group, key, NULL); - if (value) { - *field = talloc_strdup (config, value); - free (value); - } - } - return *field; -} - static void _config_set (notmuch_config_t *config, char **field, const char *group, const char *key, const char *value) @@ -452,38 +433,6 @@ _config_set (notmuch_config_t *config, char **field, *field = NULL; } -static const char ** -_config_get_list (notmuch_config_t *config, - const char *section, const char *key, - const char ***outlist, size_t *list_length, size_t *ret_length) -{ - assert (outlist); - - /* read from config file and cache value, if not cached already */ - if (*outlist == NULL) { - - char **inlist = g_key_file_get_string_list (config->key_file, - section, key, list_length, NULL); - if (inlist) { - unsigned int i; - - *outlist = talloc_size (config, sizeof (char *) * (*list_length + 1)); - - for (i = 0; i < *list_length; i++) - (*outlist)[i] = talloc_strdup (*outlist, inlist[i]); - - (*outlist)[i] = NULL; - - g_strfreev (inlist); - } - } - - if (ret_length) - *ret_length = *list_length; - - return *outlist; -} - static void _config_set_list (notmuch_config_t *config, const char *group, const char *key, @@ -497,24 +446,6 @@ _config_set_list (notmuch_config_t *config, *config_var = NULL; } -const char * -notmuch_config_get_database_path (notmuch_config_t *config) -{ - char *db_path = (char *) _config_get (config, &config->database_path, "database", "path"); - - if (db_path && *db_path != '/') { - /* If the path in the configuration file begins with any - * character other than /, presume that it is relative to - * $HOME and update as appropriate. - */ - char *abs_path = talloc_asprintf (config, "%s/%s", getenv ("HOME"), db_path); - talloc_free (db_path); - db_path = config->database_path = abs_path; - } - - return db_path; -} - void notmuch_config_set_database_path (notmuch_config_t *config, const char *database_path) @@ -522,12 +453,6 @@ notmuch_config_set_database_path (notmuch_config_t *config, _config_set (config, &config->database_path, "database", "path", database_path); } -const char * -notmuch_config_get_user_name (notmuch_config_t *config) -{ - return _config_get (config, &config->user_name, "user", "name"); -} - void notmuch_config_set_user_name (notmuch_config_t *config, const char *user_name) @@ -535,12 +460,6 @@ notmuch_config_set_user_name (notmuch_config_t *config, _config_set (config, &config->user_name, "user", "name", user_name); } -const char * -notmuch_config_get_user_primary_email (notmuch_config_t *config) -{ - return _config_get (config, &config->user_primary_email, "user", "primary_email"); -} - void notmuch_config_set_user_primary_email (notmuch_config_t *config, const char *primary_email) @@ -548,30 +467,6 @@ notmuch_config_set_user_primary_email (notmuch_config_t *config, _config_set (config, &config->user_primary_email, "user", "primary_email", primary_email); } -const char ** -notmuch_config_get_user_other_email (notmuch_config_t *config, size_t *length) -{ - return _config_get_list (config, "user", "other_email", - &(config->user_other_email), - &(config->user_other_email_length), length); -} - -const char ** -notmuch_config_get_new_tags (notmuch_config_t *config, size_t *length) -{ - return _config_get_list (config, "new", "tags", - &(config->new_tags), - &(config->new_tags_length), length); -} - -const char ** -notmuch_config_get_new_ignore (notmuch_config_t *config, size_t *length) -{ - return _config_get_list (config, "new", "ignore", - &(config->new_ignore), - &(config->new_ignore_length), length); -} - void notmuch_config_set_user_other_email (notmuch_config_t *config, const char *list[], @@ -599,14 +494,6 @@ notmuch_config_set_new_ignore (notmuch_config_t *config, &(config->new_ignore)); } -const char ** -notmuch_config_get_search_exclude_tags (notmuch_config_t *config, size_t *length) -{ - return _config_get_list (config, "search", "exclude_tags", - &(config->search_exclude_tags), - &(config->search_exclude_tags_length), length); -} - void notmuch_config_set_search_exclude_tags (notmuch_config_t *config, const char *list[], @@ -881,12 +768,6 @@ notmuch_config_command (notmuch_config_t *config, notmuch_database_t *notmuch, i } -bool -notmuch_config_get_maildir_synchronize_flags (notmuch_config_t *config) -{ - return config->maildir_synchronize_flags; -} - void notmuch_config_set_maildir_synchronize_flags (notmuch_config_t *config, bool synchronize_flags) -- 2.30.0
The idea is to preserve notmuch_config_t as a thin wrapper for GKeyFile. --- notmuch-config.c | 48 +++++++++--------------------------------------- 1 file changed, 9 insertions(+), 39 deletions(-) diff --git a/notmuch-config.c b/notmuch-config.c index 1382b0a3..0b2976f4 100644 --- a/notmuch-config.c +++ b/notmuch-config.c @@ -117,19 +117,6 @@ struct _notmuch_config { char *filename; GKeyFile *key_file; bool is_new; - - char *database_path; - char *user_name; - char *user_primary_email; - const char **user_other_email; - size_t user_other_email_length; - const char **new_tags; - size_t new_tags_length; - const char **new_ignore; - size_t new_ignore_length; - bool maildir_synchronize_flags; - const char **search_exclude_tags; - size_t search_exclude_tags_length; }; static int @@ -141,7 +128,6 @@ notmuch_config_destructor (notmuch_config_t *config) return 0; } - static bool get_config_from_file (notmuch_config_t *config, bool create_new) { @@ -280,9 +266,6 @@ notmuch_config_open (notmuch_database_t *notmuch, talloc_set_destructor (config, notmuch_config_destructor); - /* non-zero defaults */ - config->maildir_synchronize_flags = true; - if (filename) { config->filename = talloc_strdup (config, filename); } else if ((notmuch_config_env = getenv ("NOTMUCH_CONFIG"))) { @@ -423,48 +406,40 @@ notmuch_config_is_new (notmuch_config_t *config) } static void -_config_set (notmuch_config_t *config, char **field, +_config_set (notmuch_config_t *config, const char *group, const char *key, const char *value) { g_key_file_set_string (config->key_file, group, key, value); - - /* drop the cached value */ - talloc_free (*field); - *field = NULL; } static void _config_set_list (notmuch_config_t *config, const char *group, const char *key, const char *list[], - size_t length, const char ***config_var ) + size_t length) { g_key_file_set_string_list (config->key_file, group, key, list, length); - - /* drop the cached value */ - talloc_free (*config_var); - *config_var = NULL; } void notmuch_config_set_database_path (notmuch_config_t *config, const char *database_path) { - _config_set (config, &config->database_path, "database", "path", database_path); + _config_set (config, "database", "path", database_path); } void notmuch_config_set_user_name (notmuch_config_t *config, const char *user_name) { - _config_set (config, &config->user_name, "user", "name", user_name); + _config_set (config, "user", "name", user_name); } void notmuch_config_set_user_primary_email (notmuch_config_t *config, const char *primary_email) { - _config_set (config, &config->user_primary_email, "user", "primary_email", primary_email); + _config_set (config, "user", "primary_email", primary_email); } void @@ -472,8 +447,7 @@ notmuch_config_set_user_other_email (notmuch_config_t *config, const char *list[], size_t length) { - _config_set_list (config, "user", "other_email", list, length, - &(config->user_other_email)); + _config_set_list (config, "user", "other_email", list, length); } void @@ -481,8 +455,7 @@ notmuch_config_set_new_tags (notmuch_config_t *config, const char *list[], size_t length) { - _config_set_list (config, "new", "tags", list, length, - &(config->new_tags)); + _config_set_list (config, "new", "tags", list, length); } void @@ -490,8 +463,7 @@ notmuch_config_set_new_ignore (notmuch_config_t *config, const char *list[], size_t length) { - _config_set_list (config, "new", "ignore", list, length, - &(config->new_ignore)); + _config_set_list (config, "new", "ignore", list, length); } void @@ -499,8 +471,7 @@ notmuch_config_set_search_exclude_tags (notmuch_config_t *config, const char *list[], size_t length) { - _config_set_list (config, "search", "exclude_tags", list, length, - &(config->search_exclude_tags)); + _config_set_list (config, "search", "exclude_tags", list, length); } @@ -774,5 +745,4 @@ notmuch_config_set_maildir_synchronize_flags (notmuch_config_t *config, { g_key_file_set_boolean (config->key_file, "maildir", "synchronize_flags", synchronize_flags); - config->maildir_synchronize_flags = synchronize_flags; } -- 2.30.0
Originally I planned to drop this functionality, but it is useful e.g. for our test suite to be able to set config keys in the database without using notmuch-restore. New option needs documentation --- notmuch-config.c | 26 ++++++++++++++++++-------- test/T030-config.sh | 19 +++++++++++++++++++ test/T600-named-queries.sh | 17 +++++++---------- test/T750-user-header.sh | 8 -------- 4 files changed, 44 insertions(+), 26 deletions(-) diff --git a/notmuch-config.c b/notmuch-config.c index 0b2976f4..f786e462 100644 --- a/notmuch-config.c +++ b/notmuch-config.c @@ -543,16 +543,15 @@ validate_field_name (const char *str) typedef struct config_key { const char *name; - bool in_db; bool prefix; bool (*validate)(const char *); } config_key_info_t; static struct config_key config_key_table[] = { - { "index.decrypt", true, false, NULL }, - { "index.header.", true, true, validate_field_name }, - { "query.", true, true, NULL }, + { "index.decrypt", false, NULL }, + { "index.header.", true, validate_field_name }, + { "query.", true, NULL }, }; static config_key_info_t * @@ -614,7 +613,9 @@ _set_db_config (notmuch_database_t *notmuch, const char *key, int argc, char **a } static int -notmuch_config_command_set (notmuch_config_t *config, notmuch_database_t *notmuch, char *item, int argc, char *argv[]) +notmuch_config_command_set (notmuch_config_t *config, notmuch_database_t *notmuch, + char *item, bool update_db, + int argc, char *argv[]) { char *group, *key; config_key_info_t *key_info; @@ -628,7 +629,7 @@ notmuch_config_command_set (notmuch_config_t *config, notmuch_database_t *notmuc if (key_info && key_info->validate && (! key_info->validate (item))) return 1; - if (key_info && key_info->in_db) { + if (update_db) { return _set_db_config (notmuch, item, argc, argv); } @@ -695,11 +696,20 @@ notmuch_config_command (notmuch_config_t *config, notmuch_database_t *notmuch, i { int ret; int opt_index; + bool update_database; - opt_index = notmuch_minimal_options ("config", argc, argv); + notmuch_opt_desc_t options[] = { + { .opt_bool = &update_database, .name = "database" }, + { .opt_inherit = notmuch_shared_options }, + { } + }; + + opt_index = parse_arguments (argc, argv, options, 1); if (opt_index < 0) return EXIT_FAILURE; + notmuch_process_shared_options (argv[0]); + if (notmuch_requested_db_uuid) fprintf (stderr, "Warning: ignoring --uuid=%s\n", notmuch_requested_db_uuid); @@ -726,7 +736,7 @@ notmuch_config_command (notmuch_config_t *config, notmuch_database_t *notmuch, i "one argument.\n"); return EXIT_FAILURE; } - ret = notmuch_config_command_set (config, notmuch, argv[1], argc - 2, argv + 2); + ret = notmuch_config_command_set (config, notmuch, argv[1], update_database, argc - 2, argv + 2); } else if (strcmp (argv[0], "list") == 0) { ret = notmuch_config_command_list (notmuch); } else { diff --git a/test/T030-config.sh b/test/T030-config.sh index 9a43c1e4..31aa550c 100755 --- a/test/T030-config.sh +++ b/test/T030-config.sh @@ -121,5 +121,24 @@ notmuch config set database.path ${db_path} test_expect_equal "$(notmuch config get database.path)" \ "${db_path}" +test_begin_subtest "Add config to database" +notmuch new +key=g${RANDOM}.m${RANDOM} +value=${RANDOM} +notmuch config --database set ${key} ${value} +notmuch dump --include=config > OUTPUT +cat <<EOF > EXPECTED +#notmuch-dump batch-tag:3 config +#@ ${key} ${value} +EOF +test_expect_equal_file EXPECTED OUTPUT + +test_begin_subtest "Roundtrip config to/from database" +notmuch new +key=g${RANDOM}.m${RANDOM} +value=${RANDOM} +notmuch config --database set ${key} ${value} +output=$(notmuch config get ${key}) +test_expect_equal "${output}" "${value}" test_done diff --git a/test/T600-named-queries.sh b/test/T600-named-queries.sh index 0ae8b83d..d70156eb 100755 --- a/test/T600-named-queries.sh +++ b/test/T600-named-queries.sh @@ -4,13 +4,13 @@ test_description='named queries' QUERYSTR="date:2009-11-18..2009-11-18 and tag:unread" -test_begin_subtest "error adding named query before initializing DB" -test_expect_code 1 "notmuch config set query.test \"$QUERYSTR\"" +test_begin_subtest "error adding named query to DB before initialization" +test_expect_code 1 "notmuch config --database set query.test \"$QUERYSTR\"" add_email_corpus -test_begin_subtest "adding named query" -test_expect_success "notmuch config set query.test \"$QUERYSTR\"" +test_begin_subtest "adding named query (database)" +test_expect_success "notmuch config --database set query.test \"$QUERYSTR\"" test_begin_subtest "adding nested named query" QUERYSTR2="query:test and subject:Maildir" @@ -32,7 +32,6 @@ test_begin_subtest "dump named queries" notmuch dump | grep '^#@' > OUTPUT cat<<EOF > QUERIES.BEFORE #@ query.test date%3a2009-11-18..2009-11-18%20and%20tag%3aunread -#@ query.test2 query%3atest%20and%20subject%3aMaildir EOF test_expect_equal_file QUERIES.BEFORE OUTPUT @@ -40,23 +39,21 @@ test_begin_subtest 'dumping large queries' # This value is just large enough to trigger a limitation of gzprintf # to 8191 bytes in total (by default). repeat=1329 -notmuch config set query.big "$(seq -s' ' $repeat)" +notmuch config --database set query.big "$(seq -s' ' $repeat)" notmuch dump --include=config > OUTPUT -notmuch config set query.big '' +notmuch config --database set query.big printf "#notmuch-dump batch-tag:3 config\n#@ query.big " > EXPECTED seq -s'%20' $repeat >> EXPECTED cat <<EOF >> EXPECTED #@ query.test date%3a2009-11-18..2009-11-18%20and%20tag%3aunread -#@ query.test2 query%3atest%20and%20subject%3aMaildir EOF test_expect_equal_file EXPECTED OUTPUT test_begin_subtest "delete named queries" notmuch dump > BEFORE -notmuch config set query.test +notmuch config --database set query.test notmuch dump | grep '^#@' > OUTPUT cat<<EOF > EXPECTED -#@ query.test2 query%3atest%20and%20subject%3aMaildir EOF test_expect_equal_file EXPECTED OUTPUT diff --git a/test/T750-user-header.sh b/test/T750-user-header.sh index 586788b3..05f80885 100755 --- a/test/T750-user-header.sh +++ b/test/T750-user-header.sh @@ -2,14 +2,6 @@ test_description='indexing user specified headers' . $(dirname "$0")/test-lib.sh || exit 1 -test_begin_subtest "error adding user header before initializing DB" -notmuch config set index.header.List List-Id 2>&1 | notmuch_dir_sanitize > OUTPUT -cat <<EOF > EXPECTED -notmuch config: Illegal argument for function -Cannot reopen closed or nonexistent database -EOF -test_expect_equal_file EXPECTED OUTPUT - add_email_corpus notmuch search '*' | notmuch_search_sanitize > initial-threads -- 2.30.0