unofficial mirror of notmuch@notmuchmail.org
 help / color / mirror / code / Atom feed
* second round of library config API and dump
@ 2016-01-13  3:10 David Bremner
  2016-01-13  3:10 ` [WIP2 1/4] lib: provide config API David Bremner
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: David Bremner @ 2016-01-13  3:10 UTC (permalink / raw)
  To: notmuch

Based on feedback on IRC from Austin and Tomi, I've simplified the API
and no longer expose the database level prefix to the caller.

This series does fix at least one memory ownership bug. Not a
particularly subtle one, I apparently only got half way through making
the current 'value' owned by the iterator.

There's also a few more tests, as the API starts to settle down.

Because some global renaming, the interdiff is somewhat noisy, but
hopefully mostly straightforward.

diff --git a/lib/Makefile.local b/lib/Makefile.local
index ccc1e49..eb442d1 100644
--- a/lib/Makefile.local
+++ b/lib/Makefile.local
@@ -48,7 +48,7 @@ libnotmuch_cxx_srcs =		\
 	$(dir)/index.cc		\
 	$(dir)/message.cc	\
 	$(dir)/query.cc		\
-	$(dir)/metadata.cc	\
+	$(dir)/config.cc	\
 	$(dir)/thread.cc
 
 libnotmuch_modules := $(libnotmuch_c_srcs:.c=.o) $(libnotmuch_cxx_srcs:.cc=.o)
diff --git a/lib/metadata.cc b/lib/config.cc
similarity index 47%
rename from lib/metadata.cc
rename to lib/config.cc
index 34b46e0..4cd9314 100644
--- a/lib/metadata.cc
+++ b/lib/config.cc
@@ -22,88 +22,36 @@
 #include "notmuch-private.h"
 #include "database-private.h"
 
-struct _notmuch_metadata {
+static const std::string CONFIG_PREFIX="C";
+
+struct _notmuch_config_list {
     notmuch_database_t *notmuch;
     Xapian::TermIterator *iterator;
-    notmuch_metadata_class_t mclass;
     char *current_key;
+    char *current_val;
 };
 
 static int
-_notmuch_metadata_destroy (notmuch_metadata_t *list) {
+_notmuch_config_list_destroy (notmuch_config_list_t *list) {
     delete list->iterator;
     return 0;
 }
 
-typedef struct prefix {
-    notmuch_metadata_class_t mclass;
-    const char *prefix;
-} prefix_t;
-
-static prefix_t METADATA_PREFIX[] = {
-    {NOTMUCH_METADATA_CONFIG, "C"},
-};
-
-#define ARRAY_SIZE(arr) (sizeof (arr) / sizeof (arr[0]))
-
-const char *
-notmuch_metadata_prefix_string (notmuch_metadata_class_t mclass)
-{
-    unsigned int i;
-
-    for (i=0; i < ARRAY_SIZE(METADATA_PREFIX); i++) {
-	if (METADATA_PREFIX[0].mclass == mclass)
-	    return METADATA_PREFIX[i].prefix;
-    }
-    return NULL;
-}
-
-notmuch_status_t _make_key(void *ctx, notmuch_metadata_class_t mclass,
-			    const char *in, const char **out)
-{
-    const char *term;
-    const char *prefix = NULL;
-
-    if (!out)
-	return NOTMUCH_STATUS_NULL_POINTER;
-
-    prefix = notmuch_metadata_prefix_string(mclass);
-    if (!prefix)
-	return NOTMUCH_STATUS_UNSUPPORTED_OPERATION;
-
-    term = talloc_asprintf (ctx, "%s%s",
-			    prefix, in);
-    if (!term)
-	return NOTMUCH_STATUS_OUT_OF_MEMORY;
-
-    *out = term;
-    return NOTMUCH_STATUS_SUCCESS;
-}
-
 notmuch_status_t
-notmuch_database_set_metadata (notmuch_database_t *notmuch,
-			       notmuch_metadata_class_t mclass,
-			       const char *key,
-			       const char *value)
+notmuch_database_set_config (notmuch_database_t *notmuch,
+			     const char *key,
+			     const char *value)
 {
     notmuch_status_t status;
     Xapian::WritableDatabase *db;
-    const char *key_term = NULL;
-    void *local;
-
-    local = talloc_new (NULL);
 
     status = _notmuch_database_ensure_writable (notmuch);
     if (status)
-	goto DONE;
-
-    status = _make_key (local, mclass, key, &key_term);
-    if (status)
-	goto DONE;
+	return status;
 
     try {
 	db = static_cast <Xapian::WritableDatabase *> (notmuch->xapian_db);
-	db->set_metadata (key_term, value);
+	db->set_metadata (CONFIG_PREFIX+key, value);
     } catch (const Xapian::Error &error) {
 	status = NOTMUCH_STATUS_XAPIAN_EXCEPTION;
 	notmuch->exception_reported = TRUE;
@@ -112,33 +60,18 @@ notmuch_database_set_metadata (notmuch_database_t *notmuch,
 				   error.get_msg().c_str());
 	}
     }
- DONE:
-    talloc_free (local);
-
-    return status;
+    return NOTMUCH_STATUS_SUCCESS;
 }
 
 static notmuch_status_t
 _metadata_value (notmuch_database_t *notmuch,
-		 notmuch_metadata_class_t mclass,
 		 const char *key,
 		 std::string &value)
 {
-    notmuch_status_t status;
-
-    const char *key_term = NULL;
-    void *local;
-
-    local = talloc_new (NULL);
-
-    status = _make_key (local, mclass, key, &key_term);
-    if (status)
-	goto DONE;
+    notmuch_status_t status = NOTMUCH_STATUS_SUCCESS;
 
     try {
-
-	value = notmuch->xapian_db->get_metadata (key_term);
-
+	value = notmuch->xapian_db->get_metadata (CONFIG_PREFIX+key);
     } catch (const Xapian::Error &error) {
 	status = NOTMUCH_STATUS_XAPIAN_EXCEPTION;
 	notmuch->exception_reported = TRUE;
@@ -147,24 +80,20 @@ _metadata_value (notmuch_database_t *notmuch,
 				   error.get_msg().c_str());
 	}
     }
-
- DONE:
-    talloc_free (local);
     return status;
 }
 
 notmuch_status_t
-notmuch_database_get_metadata (notmuch_database_t *notmuch,
-			       notmuch_metadata_class_t mclass,
-			       const char *key,
-			       char **value) {
+notmuch_database_get_config (notmuch_database_t *notmuch,
+			     const char *key,
+			     char **value) {
     std::string strval;
     notmuch_status_t status;
 
     if (!value)
 	return NOTMUCH_STATUS_NULL_POINTER;
 
-    status = _metadata_value (notmuch, mclass, key, strval);
+    status = _metadata_value (notmuch, key, strval);
     if (status)
 	return status;
 
@@ -174,31 +103,28 @@ notmuch_database_get_metadata (notmuch_database_t *notmuch,
 }
 
 notmuch_status_t
-notmuch_database_get_all_metadata (notmuch_database_t *notmuch,
-				   notmuch_metadata_class_t mclass,
-				   notmuch_metadata_t **out)
+notmuch_database_get_config_list (notmuch_database_t *notmuch,
+				 const char *prefix,
+				 notmuch_config_list_t **out)
 {
-    notmuch_metadata_t *list = NULL;
+    notmuch_config_list_t *list = NULL;
     notmuch_status_t status = NOTMUCH_STATUS_SUCCESS;
 
-    const char *prefix = notmuch_metadata_prefix_string (mclass);
-
-    list = talloc (notmuch, notmuch_metadata_t);
+    list = talloc (notmuch, notmuch_config_list_t);
     if (!list) {
 	status = NOTMUCH_STATUS_OUT_OF_MEMORY;
 	goto DONE;
     }
 
-    talloc_set_destructor(list, _notmuch_metadata_destroy);
+    talloc_set_destructor(list, _notmuch_config_list_destroy);
     list->iterator = new Xapian::TermIterator;
     list->notmuch = notmuch;
-    list->mclass = mclass;
     list->current_key = NULL;
+    list->current_val = NULL;
 
     try {
 
-	*list->iterator = notmuch->xapian_db->metadata_keys_begin();
-	list->iterator->skip_to (prefix);
+	*list->iterator = notmuch->xapian_db->metadata_keys_begin(CONFIG_PREFIX + (prefix ? prefix : NULL));
 
     } catch (const Xapian::Error &error) {
 	_notmuch_database_log (notmuch, "A Xapian exception occurred getting metadata iterator: %s.\n",
@@ -217,49 +143,52 @@ notmuch_database_get_all_metadata (notmuch_database_t *notmuch,
 }
 
 notmuch_bool_t
-notmuch_metadata_valid (notmuch_metadata_t *metadata)
+notmuch_config_list_valid (notmuch_config_list_t *metadata)
 {
-    const char *prefix = notmuch_metadata_prefix_string (metadata->mclass);
     if (*(metadata->iterator) == metadata->notmuch->xapian_db->metadata_keys_end())
 	return FALSE;
 
-    return (strncmp((**(metadata->iterator)).c_str (), prefix, strlen (prefix)) == 0);
+    return TRUE;
 }
 
 const char *
-notmuch_metadata_key (notmuch_metadata_t *metadata)
+notmuch_config_list_key (notmuch_config_list_t *list)
 {
-    const char *prefix = notmuch_metadata_prefix_string (metadata->mclass);
+    if (list->current_key)
+	talloc_free (list->current_key);
 
-    if (metadata->current_key)
-	talloc_free (metadata->current_key);
-    metadata->current_key = talloc_strdup (metadata, (**(metadata->iterator)).c_str () + strlen (prefix));
+    list->current_key = talloc_strdup (list, (**(list->iterator)).c_str () + CONFIG_PREFIX.length ());
 
-    return  metadata->current_key;
+    return  list->current_key;
 }
 
 const char *
-notmuch_metadata_value (notmuch_metadata_t *metadata)
+notmuch_config_list_value (notmuch_config_list_t *list)
 {
-    const char *key = notmuch_metadata_key (metadata);
-    char *val;
+    std::string strval;
     notmuch_status_t status;
+    const char *key = notmuch_config_list_key (list);
 
-    status=notmuch_database_get_metadata (metadata->notmuch, metadata->mclass, key, &val);
+    /* TODO: better error reporting?? */
+    status = _metadata_value (list->notmuch, key, strval);
     if (status)
 	return NULL;
 
-    return val;
+    if (list->current_val)
+	talloc_free(list->current_val);
+
+    list->current_val = talloc_strdup(list, strval.c_str ());
+    return list->current_val;
 }
 
 void
-notmuch_metadata_move_to_next (notmuch_metadata_t *metadata)
+notmuch_config_list_move_to_next (notmuch_config_list_t *list)
 {
-    (*(metadata->iterator))++;
+    (*(list->iterator))++;
 }
 
 void
-notmuch_metadata_destroy (notmuch_metadata_t *metadata)
+notmuch_config_list_destroy (notmuch_config_list_t *list)
 {
-    talloc_free (metadata);
+    talloc_free (list);
 }
diff --git a/lib/notmuch.h b/lib/notmuch.h
index 657a7d6..b439c88 100644
--- a/lib/notmuch.h
+++ b/lib/notmuch.h
@@ -197,7 +197,7 @@ typedef struct _notmuch_message notmuch_message_t;
 typedef struct _notmuch_tags notmuch_tags_t;
 typedef struct _notmuch_directory notmuch_directory_t;
 typedef struct _notmuch_filenames notmuch_filenames_t;
-typedef struct _notmuch_metadata notmuch_metadata_t;
+typedef struct _notmuch_config_list notmuch_config_list_t;
 #endif /* __DOXYGEN__ */
 
 /**
@@ -1830,78 +1830,69 @@ notmuch_filenames_move_to_next (notmuch_filenames_t *filenames);
 void
 notmuch_filenames_destroy (notmuch_filenames_t *filenames);
 
-/**
- * metadata class
- */
-
-typedef enum _notmuch_metadata_class {
-    NOTMUCH_METADATA_FIRST_CLASS = 1,
-    NOTMUCH_METADATA_CONFIG = 1,
-    NOTMUCH_METADATA_LAST_CLASS
-} notmuch_metadata_class_t;
 
 /**
- * set metadata
+ * set config 'key' to 'value'
  *
  */
 notmuch_status_t
-notmuch_database_set_metadata (notmuch_database_t *db, notmuch_metadata_class_t mclass, const char *key, const char *value);
+notmuch_database_set_config (notmuch_database_t *db, const char *key, const char *value);
 
 /**
- * retrieve one metadata value
+ * retrieve config item 'key', assign to  'value'
+ *
+ * keys which have not been previously set with n_d_set_config will
+ * return an empty string.
  *
- * return value is allocated by malloc and should be freed by the caller.
+ * return value is allocated by malloc and should be freed by the
+ * caller.
  */
 notmuch_status_t
-notmuch_database_get_metadata (notmuch_database_t *db, notmuch_metadata_class_t mclass, const char *key, char **value);
+notmuch_database_get_config (notmuch_database_t *db, const char *key, char **value);
 
 /**
- * get all metadata of a given class
+ * Create an iterator for all config items with keys matching a given prefix
  */
 notmuch_status_t
-notmuch_database_get_all_metadata (notmuch_database_t *db, notmuch_metadata_class_t mclass, notmuch_metadata_t **out);
+notmuch_database_get_config_list (notmuch_database_t *db, const char *prefix, notmuch_config_list_t **out);
 
 /**
- * Is 'metadata' iterator valid (i.e. _key, _value, _move_to_next can be called).
+ * Is 'config_list' iterator valid (i.e. _key, _value, _move_to_next can be called).
  */
 notmuch_bool_t
-notmuch_metadata_valid (notmuch_metadata_t *metadata);
+notmuch_config_list_valid (notmuch_config_list_t *config_list);
 
 /**
- * return key for current metadata pair
+ * return key for current config pair
  *
  * return value is owned by the iterator, and will be destroyed by the
- * next call to notmuch_metadata_key or notmuch_metadata_destroy.
+ * next call to notmuch_config_list_key or notmuch_config_list_destroy.
  */
 const char *
-notmuch_metadata_key (notmuch_metadata_t *metadata);
+notmuch_config_list_key (notmuch_config_list_t *config_list);
 
 /**
- * return 'value' for current metadata pair
+ * return 'value' for current config pair
  *
  * return value is owned by the iterator, and will be destroyed by the
- * next call to notmuch_metadata_value
+ * next call to notmuch_config_list_value or notmuch config_list_destroy
  */
 const char *
-notmuch_metadata_value (notmuch_metadata_t *metadata);
+notmuch_config_list_value (notmuch_config_list_t *config_list);
+
 
 /**
- * move 'metadata' iterator to the next pair
+ * move 'config_list' iterator to the next pair
  */
 void
-notmuch_metadata_move_to_next (notmuch_metadata_t *metadata);
+notmuch_config_list_move_to_next (notmuch_config_list_t *config_list);
 
 /**
- * free any resources held by 'metadata'
+ * free any resources held by 'config_list'
  */
 void
-notmuch_metadata_destroy (notmuch_metadata_t * metadata);
+notmuch_config_list_destroy (notmuch_config_list_t *config_list);
 
-/**
- * convert enum to string
- */
-const char *
-notmuch_metadata_prefix_string (notmuch_metadata_class_t mclass);
 /* @} */
 
 NOTMUCH_END_DECLS
diff --git a/notmuch-client.h b/notmuch-client.h
index 8ee6e0e..2dca83c 100644
--- a/notmuch-client.h
+++ b/notmuch-client.h
@@ -445,7 +445,7 @@ typedef enum dump_formats {
 
 typedef enum dump_includes {
     DUMP_INCLUDE_TAGS=1,
-    DUMP_INCLUDE_METADATA=2,
+    DUMP_INCLUDE_CONFIG=2,
 } dump_include_t;
 
 int
diff --git a/notmuch-dump.c b/notmuch-dump.c
index a88b5d5..4909493 100644
--- a/notmuch-dump.c
+++ b/notmuch-dump.c
@@ -24,25 +24,21 @@
 #include <zlib.h>
 
 static notmuch_status_t
-database_dump_metadata(notmuch_database_t *notmuch, gzFile output)
+database_dump_config(notmuch_database_t *notmuch, gzFile output)
 {
-    notmuch_metadata_class_t mclass;
-    notmuch_metadata_t *meta;
+    notmuch_config_list_t *list;
     notmuch_status_t status;
-
-    for (mclass = NOTMUCH_METADATA_FIRST_CLASS; mclass < NOTMUCH_METADATA_LAST_CLASS; mclass++) {
-	status = notmuch_database_get_all_metadata (notmuch, NOTMUCH_METADATA_CONFIG, &meta);
-	if (status)
-	    return status;
-
-	for (; notmuch_metadata_valid (meta); notmuch_metadata_move_to_next (meta)) {
-	    /* FIXME hexencode key and values */
-	    gzprintf(output, "#@ %s %s %s\n",
-		     notmuch_metadata_prefix_string(mclass),
-		     notmuch_metadata_key (meta), notmuch_metadata_value (meta));
-	}
-	notmuch_metadata_destroy (meta);
+    status = notmuch_database_get_config_list (notmuch, NULL, &list);
+    if (status)
+	return status;
+
+    for (; notmuch_config_list_valid (list); notmuch_config_list_move_to_next (list)) {
+	/* FIXME hexencode key and values */
+	gzprintf(output, "#@ %s %s\n",
+		 notmuch_config_list_key (list), notmuch_config_list_value (list));
     }
+    notmuch_config_list_destroy (list);
+
     return NOTMUCH_STATUS_SUCCESS;
 }
 
@@ -55,9 +51,9 @@ database_dump_file (notmuch_database_t *notmuch, gzFile output,
     notmuch_message_t *message;
     notmuch_tags_t *tags;
 
-    if (include | DUMP_INCLUDE_METADATA) {
+    if (include | DUMP_INCLUDE_CONFIG) {
 	if (print_status_database ("notmuch dump", notmuch,
-				   database_dump_metadata(notmuch,output)))
+				   database_dump_config(notmuch,output)))
 	    return EXIT_FAILURE;
     }
 
@@ -267,7 +263,7 @@ notmuch_dump_command (notmuch_config_t *config, int argc, char *argv[])
 				  { "batch-tag", DUMP_FORMAT_BATCH_TAG },
 				  { 0, 0 } } },
 	{ NOTMUCH_OPT_KEYWORD_FLAGS, &include, "include", 'i',
-	  (notmuch_keyword_t []){ { "metadata", DUMP_INCLUDE_METADATA },
+	  (notmuch_keyword_t []){ { "metadata", DUMP_INCLUDE_CONFIG },
 				  { "tags", DUMP_INCLUDE_TAGS} } },
 	{ NOTMUCH_OPT_STRING, &output_file_name, "output", 'o', 0  },
 	{ NOTMUCH_OPT_BOOLEAN, &gzip_output, "gzip", 'z', 0 },
@@ -282,7 +278,7 @@ notmuch_dump_command (notmuch_config_t *config, int argc, char *argv[])
     notmuch_process_shared_options (argv[0]);
 
     if (include == 0)
-	include = DUMP_INCLUDE_METADATA | DUMP_INCLUDE_TAGS;
+	include = DUMP_INCLUDE_CONFIG | DUMP_INCLUDE_TAGS;
 
     if (opt_index < argc) {
 	query_str = query_string_from_args (notmuch, argc - opt_index, argv + opt_index);
diff --git a/notmuch-new.c b/notmuch-new.c
index 1f8050d..fd2ff82 100644
--- a/notmuch-new.c
+++ b/notmuch-new.c
@@ -1041,7 +1041,7 @@ notmuch_new_command (notmuch_config_t *config, int argc, char *argv[])
 	    }
 
 	    if (notmuch_database_dump (notmuch, backup_name, "",
-				       DUMP_FORMAT_BATCH_TAG, DUMP_INCLUDE_METADATA | DUMP_INCLUDE_TAGS, TRUE)) {
+				       DUMP_FORMAT_BATCH_TAG, DUMP_INCLUDE_CONFIG | DUMP_INCLUDE_TAGS, TRUE)) {
 		fprintf (stderr, "Backup failed. Aborting upgrade.");
 		return EXIT_FAILURE;
 	    }
diff --git a/test/T590-metadata.sh b/test/T590-libconfig.sh
similarity index 35%
rename from test/T590-metadata.sh
rename to test/T590-libconfig.sh
index 45a49be..4fe6bd1 100755
--- a/test/T590-metadata.sh
+++ b/test/T590-libconfig.sh
@@ -1,5 +1,5 @@
 #!/usr/bin/env bash
-test_description="metadata API"
+test_description="library config API"
 
 . ./test-lib.sh || exit 1
 
@@ -36,14 +36,14 @@ cat <<EOF > c_tail
 }
 EOF
 
-test_begin_subtest "notmuch_database_{set,get}_metadata"
+test_begin_subtest "notmuch_database_{set,get}_config"
 cat c_head - c_tail <<'EOF' | test_C ${MAIL_DIR}
 {
-   RUN(notmuch_database_set_metadata (db, NOTMUCH_METADATA_CONFIG, "testkey1", "testvalue1"));
-   RUN(notmuch_database_set_metadata (db, NOTMUCH_METADATA_CONFIG, "testkey2", "testvalue2"));
-   RUN(notmuch_database_get_metadata (db, NOTMUCH_METADATA_CONFIG, "testkey1", &val));
+   RUN(notmuch_database_set_config (db, "testkey1", "testvalue1"));
+   RUN(notmuch_database_set_config (db, "testkey2", "testvalue2"));
+   RUN(notmuch_database_get_config (db, "testkey1", &val));
    printf("testkey1 = %s\n", val);
-   RUN(notmuch_database_get_metadata (db, NOTMUCH_METADATA_CONFIG, "testkey2", &val));
+   RUN(notmuch_database_get_config (db, "testkey2", &val));
    printf("testkey2 = %s\n", val);
 }
 EOF
@@ -55,33 +55,73 @@ testkey2 = testvalue2
 EOF
 test_expect_equal_file EXPECTED OUTPUT
 
-test_begin_subtest "get all metadata in one class"
+
+test_begin_subtest "notmuch_database_get_config_list: empty list"
+cat c_head - c_tail <<'EOF' | test_C ${MAIL_DIR}
+{
+   notmuch_config_list_t *list;
+   RUN(notmuch_database_get_config_list (db, "nonexistent", &list));
+   printf("valid = %d\n", notmuch_config_list_valid (list));
+   notmuch_config_list_destroy (list);
+}
+EOF
+cat <<'EOF' >EXPECTED
+== stdout ==
+valid = 0
+== stderr ==
+EOF
+test_expect_equal_file EXPECTED OUTPUT
+
+
+test_begin_subtest "notmuch_database_get_config_list: all pairs"
+cat c_head - c_tail <<'EOF' | test_C ${MAIL_DIR}
+{
+   notmuch_config_list_t *list;
+   RUN(notmuch_database_set_config (db, "zzzafter", "afterval"));
+   RUN(notmuch_database_set_config (db, "aaabefore", "beforeval"));
+   RUN(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
+testkey1 testvalue1
+testkey2 testvalue2
+zzzafter afterval
+== stderr ==
+EOF
+test_expect_equal_file EXPECTED OUTPUT
+
+test_begin_subtest "notmuch_database_get_config_list: one prefix"
 cat c_head - c_tail <<'EOF' | test_C ${MAIL_DIR}
 {
-   notmuch_metadata_t *meta;
-   RUN(notmuch_database_get_all_metadata (db, NOTMUCH_METADATA_CONFIG, &meta));
-   for (; notmuch_metadata_valid (meta); notmuch_metadata_move_to_next (meta)) {
-      printf("key = %s\n", notmuch_metadata_key (meta));
-      printf("val = %s\n", notmuch_metadata_value (meta));
+   notmuch_config_list_t *list;
+   RUN(notmuch_database_get_config_list (db, "testkey", &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_metadata_destroy (meta);
+   notmuch_config_list_destroy (list);
 }
 EOF
 cat <<'EOF' >EXPECTED
 == stdout ==
-key = testkey1
-val = testvalue1
-key = testkey2
-val = testvalue2
+testkey1 testvalue1
+testkey2 testvalue2
 == stderr ==
 EOF
 test_expect_equal_file EXPECTED OUTPUT
 
-test_begin_subtest "dump metadata"
+test_begin_subtest "dump config"
 notmuch dump --include=metadata >OUTPUT
 cat <<'EOF' >EXPECTED
-#@ C testkey1 testvalue1
-#@ C testkey2 testvalue2
+#@ aaabefore beforeval
+#@ testkey1 testvalue1
+#@ testkey2 testvalue2
+#@ zzzafter afterval
 EOF
 test_expect_equal_file EXPECTED OUTPUT
 

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [WIP2 1/4] lib: provide config API
  2016-01-13  3:10 second round of library config API and dump David Bremner
@ 2016-01-13  3:10 ` David Bremner
  2016-01-13  3:10 ` [WIP2 2/4] lib: config list iterators David Bremner
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 5+ messages in thread
From: David Bremner @ 2016-01-13  3:10 UTC (permalink / raw)
  To: notmuch

This is a thin wrapper around the Xapian metadata API. The job of this
layer is to keep the config key value pairs from colliding with other
metadata by transparently prefixing the keys, along with the usual glue
to provide a C interface.

The split of _get_config into two functions is to allow returning of the
return value with different memory ownership semantics.
---
 lib/Makefile.local     |  1 +
 lib/config.cc          | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/notmuch.h          | 20 +++++++++++
 test/T590-libconfig.sh | 58 ++++++++++++++++++++++++++++++++
 4 files changed, 169 insertions(+)
 create mode 100644 lib/config.cc
 create mode 100755 test/T590-libconfig.sh

diff --git a/lib/Makefile.local b/lib/Makefile.local
index 3a07090..eb442d1 100644
--- a/lib/Makefile.local
+++ b/lib/Makefile.local
@@ -48,6 +48,7 @@ libnotmuch_cxx_srcs =		\
 	$(dir)/index.cc		\
 	$(dir)/message.cc	\
 	$(dir)/query.cc		\
+	$(dir)/config.cc	\
 	$(dir)/thread.cc
 
 libnotmuch_modules := $(libnotmuch_c_srcs:.c=.o) $(libnotmuch_cxx_srcs:.cc=.o)
diff --git a/lib/config.cc b/lib/config.cc
new file mode 100644
index 0000000..af00d6f
--- /dev/null
+++ b/lib/config.cc
@@ -0,0 +1,90 @@
+/* metadata.cc - API for database metadata
+ *
+ * Copyright © 2015 David Bremner
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see http://www.gnu.org/licenses/ .
+ *
+ * Author: David Bremner <david@tethera.net>
+ */
+
+#include "notmuch.h"
+#include "notmuch-private.h"
+#include "database-private.h"
+
+static const std::string CONFIG_PREFIX="C";
+
+notmuch_status_t
+notmuch_database_set_config (notmuch_database_t *notmuch,
+			     const char *key,
+			     const char *value)
+{
+    notmuch_status_t status;
+    Xapian::WritableDatabase *db;
+
+    status = _notmuch_database_ensure_writable (notmuch);
+    if (status)
+	return status;
+
+    try {
+	db = static_cast <Xapian::WritableDatabase *> (notmuch->xapian_db);
+	db->set_metadata (CONFIG_PREFIX+key, value);
+    } catch (const Xapian::Error &error) {
+	status = NOTMUCH_STATUS_XAPIAN_EXCEPTION;
+	notmuch->exception_reported = TRUE;
+	if (! notmuch->exception_reported) {
+	    _notmuch_database_log (notmuch, "Error: A Xapian exception occurred setting metadata: %s\n",
+				   error.get_msg().c_str());
+	}
+    }
+    return NOTMUCH_STATUS_SUCCESS;
+}
+
+static notmuch_status_t
+_metadata_value (notmuch_database_t *notmuch,
+		 const char *key,
+		 std::string &value)
+{
+    notmuch_status_t status = NOTMUCH_STATUS_SUCCESS;
+
+    try {
+	value = notmuch->xapian_db->get_metadata (CONFIG_PREFIX+key);
+    } catch (const Xapian::Error &error) {
+	status = NOTMUCH_STATUS_XAPIAN_EXCEPTION;
+	notmuch->exception_reported = TRUE;
+	if (! notmuch->exception_reported) {
+	    _notmuch_database_log (notmuch, "Error: A Xapian exception occurred getting metadata: %s\n",
+				   error.get_msg().c_str());
+	}
+    }
+    return status;
+}
+
+notmuch_status_t
+notmuch_database_get_config (notmuch_database_t *notmuch,
+			     const char *key,
+			     char **value) {
+    std::string strval;
+    notmuch_status_t status;
+
+    if (!value)
+	return NOTMUCH_STATUS_NULL_POINTER;
+
+    status = _metadata_value (notmuch, key, strval);
+    if (status)
+	return status;
+
+    *value = strdup (strval.c_str ());
+
+    return NOTMUCH_STATUS_SUCCESS;
+}
diff --git a/lib/notmuch.h b/lib/notmuch.h
index 310a8b8..c62223b 100644
--- a/lib/notmuch.h
+++ b/lib/notmuch.h
@@ -1829,6 +1829,26 @@ notmuch_filenames_move_to_next (notmuch_filenames_t *filenames);
 void
 notmuch_filenames_destroy (notmuch_filenames_t *filenames);
 
+
+/**
+ * set config 'key' to 'value'
+ *
+ */
+notmuch_status_t
+notmuch_database_set_config (notmuch_database_t *db, const char *key, const char *value);
+
+/**
+ * retrieve config item 'key', assign to  'value'
+ *
+ * keys which have not been previously set with n_d_set_config will
+ * return an empty string.
+ *
+ * return value is allocated by malloc and should be freed by the
+ * caller.
+ */
+notmuch_status_t
+notmuch_database_get_config (notmuch_database_t *db, const char *key, char **value);
+
 /* @} */
 
 NOTMUCH_END_DECLS
diff --git a/test/T590-libconfig.sh b/test/T590-libconfig.sh
new file mode 100755
index 0000000..85e4497
--- /dev/null
+++ b/test/T590-libconfig.sh
@@ -0,0 +1,58 @@
+#!/usr/bin/env bash
+test_description="library config API"
+
+. ./test-lib.sh || exit 1
+
+add_email_corpus
+
+cat <<EOF > c_head
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <notmuch.h>
+
+void run(int line, notmuch_status_t ret)
+{
+   if (ret) {
+	fprintf (stderr, "line %d: %s\n", line, ret);
+	exit (1);
+   }
+}
+
+#define RUN(v)  run(__LINE__, v);
+
+int main (int argc, char** argv)
+{
+   notmuch_database_t *db;
+   char *val;
+   notmuch_status_t stat;
+
+   RUN(notmuch_database_open (argv[1], NOTMUCH_DATABASE_MODE_READ_WRITE, &db));
+
+EOF
+
+cat <<EOF > c_tail
+   RUN(notmuch_database_destroy(db));
+}
+EOF
+
+test_begin_subtest "notmuch_database_{set,get}_config"
+cat c_head - c_tail <<'EOF' | test_C ${MAIL_DIR}
+{
+   RUN(notmuch_database_set_config (db, "testkey1", "testvalue1"));
+   RUN(notmuch_database_set_config (db, "testkey2", "testvalue2"));
+   RUN(notmuch_database_get_config (db, "testkey1", &val));
+   printf("testkey1 = %s\n", val);
+   RUN(notmuch_database_get_config (db, "testkey2", &val));
+   printf("testkey2 = %s\n", val);
+}
+EOF
+cat <<'EOF' >EXPECTED
+== stdout ==
+testkey1 = testvalue1
+testkey2 = testvalue2
+== stderr ==
+EOF
+test_expect_equal_file EXPECTED OUTPUT
+
+test_done
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [WIP2 2/4] lib: config list iterators
  2016-01-13  3:10 second round of library config API and dump David Bremner
  2016-01-13  3:10 ` [WIP2 1/4] lib: provide config API David Bremner
@ 2016-01-13  3:10 ` David Bremner
  2016-01-13  3:10 ` [WIP2 3/4] CLI: add print_status_database David Bremner
  2016-01-13  3:10 ` [WIP2 4/4] CLI: add optional metadata to dump output David Bremner
  3 siblings, 0 replies; 5+ messages in thread
From: David Bremner @ 2016-01-13  3:10 UTC (permalink / raw)
  To: notmuch

Since xapian provides the ability to restrict the iterator to a given
prefix, we expose this ability to the user. Otherwise we mimic the other
iterator interfances in notmuch (e.g. tags.c).
---
 lib/config.cc          | 104 +++++++++++++++++++++++++++++++++++++++++++++++++
 lib/notmuch.h          |  44 +++++++++++++++++++++
 test/T590-libconfig.sh |  60 ++++++++++++++++++++++++++++
 3 files changed, 208 insertions(+)

diff --git a/lib/config.cc b/lib/config.cc
index af00d6f..4cd9314 100644
--- a/lib/config.cc
+++ b/lib/config.cc
@@ -24,6 +24,19 @@
 
 static const std::string CONFIG_PREFIX="C";
 
+struct _notmuch_config_list {
+    notmuch_database_t *notmuch;
+    Xapian::TermIterator *iterator;
+    char *current_key;
+    char *current_val;
+};
+
+static int
+_notmuch_config_list_destroy (notmuch_config_list_t *list) {
+    delete list->iterator;
+    return 0;
+}
+
 notmuch_status_t
 notmuch_database_set_config (notmuch_database_t *notmuch,
 			     const char *key,
@@ -88,3 +101,94 @@ notmuch_database_get_config (notmuch_database_t *notmuch,
 
     return NOTMUCH_STATUS_SUCCESS;
 }
+
+notmuch_status_t
+notmuch_database_get_config_list (notmuch_database_t *notmuch,
+				 const char *prefix,
+				 notmuch_config_list_t **out)
+{
+    notmuch_config_list_t *list = NULL;
+    notmuch_status_t status = NOTMUCH_STATUS_SUCCESS;
+
+    list = talloc (notmuch, notmuch_config_list_t);
+    if (!list) {
+	status = NOTMUCH_STATUS_OUT_OF_MEMORY;
+	goto DONE;
+    }
+
+    talloc_set_destructor(list, _notmuch_config_list_destroy);
+    list->iterator = new Xapian::TermIterator;
+    list->notmuch = notmuch;
+    list->current_key = NULL;
+    list->current_val = NULL;
+
+    try {
+
+	*list->iterator = notmuch->xapian_db->metadata_keys_begin(CONFIG_PREFIX + (prefix ? prefix : NULL));
+
+    } catch (const Xapian::Error &error) {
+	_notmuch_database_log (notmuch, "A Xapian exception occurred getting metadata iterator: %s.\n",
+			       error.get_msg().c_str());
+	notmuch->exception_reported = TRUE;
+	status = NOTMUCH_STATUS_XAPIAN_EXCEPTION;
+    }
+
+    *out = list;
+
+ DONE:
+    if (status && list)
+	talloc_free (list);
+
+    return status;
+}
+
+notmuch_bool_t
+notmuch_config_list_valid (notmuch_config_list_t *metadata)
+{
+    if (*(metadata->iterator) == metadata->notmuch->xapian_db->metadata_keys_end())
+	return FALSE;
+
+    return TRUE;
+}
+
+const char *
+notmuch_config_list_key (notmuch_config_list_t *list)
+{
+    if (list->current_key)
+	talloc_free (list->current_key);
+
+    list->current_key = talloc_strdup (list, (**(list->iterator)).c_str () + CONFIG_PREFIX.length ());
+
+    return  list->current_key;
+}
+
+const char *
+notmuch_config_list_value (notmuch_config_list_t *list)
+{
+    std::string strval;
+    notmuch_status_t status;
+    const char *key = notmuch_config_list_key (list);
+
+    /* TODO: better error reporting?? */
+    status = _metadata_value (list->notmuch, key, strval);
+    if (status)
+	return NULL;
+
+    if (list->current_val)
+	talloc_free(list->current_val);
+
+    list->current_val = talloc_strdup(list, strval.c_str ());
+    return list->current_val;
+}
+
+void
+notmuch_config_list_move_to_next (notmuch_config_list_t *list)
+{
+    (*(list->iterator))++;
+}
+
+void
+notmuch_config_list_destroy (notmuch_config_list_t *list)
+{
+    talloc_free (list);
+}
diff --git a/lib/notmuch.h b/lib/notmuch.h
index c62223b..b439c88 100644
--- a/lib/notmuch.h
+++ b/lib/notmuch.h
@@ -197,6 +197,7 @@ typedef struct _notmuch_message notmuch_message_t;
 typedef struct _notmuch_tags notmuch_tags_t;
 typedef struct _notmuch_directory notmuch_directory_t;
 typedef struct _notmuch_filenames notmuch_filenames_t;
+typedef struct _notmuch_config_list notmuch_config_list_t;
 #endif /* __DOXYGEN__ */
 
 /**
@@ -1849,6 +1850,49 @@ notmuch_database_set_config (notmuch_database_t *db, const char *key, const char
 notmuch_status_t
 notmuch_database_get_config (notmuch_database_t *db, const char *key, char **value);
 
+/**
+ * Create an iterator for all config items with keys matching a given prefix
+ */
+notmuch_status_t
+notmuch_database_get_config_list (notmuch_database_t *db, const char *prefix, notmuch_config_list_t **out);
+
+/**
+ * Is 'config_list' iterator valid (i.e. _key, _value, _move_to_next can be called).
+ */
+notmuch_bool_t
+notmuch_config_list_valid (notmuch_config_list_t *config_list);
+
+/**
+ * return key for current config pair
+ *
+ * return value is owned by the iterator, and will be destroyed by the
+ * next call to notmuch_config_list_key or notmuch_config_list_destroy.
+ */
+const char *
+notmuch_config_list_key (notmuch_config_list_t *config_list);
+
+/**
+ * return 'value' for current config pair
+ *
+ * return value is owned by the iterator, and will be destroyed by the
+ * next call to notmuch_config_list_value or notmuch config_list_destroy
+ */
+const char *
+notmuch_config_list_value (notmuch_config_list_t *config_list);
+
+
+/**
+ * move 'config_list' iterator to the next pair
+ */
+void
+notmuch_config_list_move_to_next (notmuch_config_list_t *config_list);
+
+/**
+ * free any resources held by 'config_list'
+ */
+void
+notmuch_config_list_destroy (notmuch_config_list_t *config_list);
+
 /* @} */
 
 NOTMUCH_END_DECLS
diff --git a/test/T590-libconfig.sh b/test/T590-libconfig.sh
index 85e4497..8ca6883 100755
--- a/test/T590-libconfig.sh
+++ b/test/T590-libconfig.sh
@@ -55,4 +55,64 @@ testkey2 = testvalue2
 EOF
 test_expect_equal_file EXPECTED OUTPUT
 
+
+test_begin_subtest "notmuch_database_get_config_list: empty list"
+cat c_head - c_tail <<'EOF' | test_C ${MAIL_DIR}
+{
+   notmuch_config_list_t *list;
+   RUN(notmuch_database_get_config_list (db, "nonexistent", &list));
+   printf("valid = %d\n", notmuch_config_list_valid (list));
+   notmuch_config_list_destroy (list);
+}
+EOF
+cat <<'EOF' >EXPECTED
+== stdout ==
+valid = 0
+== stderr ==
+EOF
+test_expect_equal_file EXPECTED OUTPUT
+
+
+test_begin_subtest "notmuch_database_get_config_list: all pairs"
+cat c_head - c_tail <<'EOF' | test_C ${MAIL_DIR}
+{
+   notmuch_config_list_t *list;
+   RUN(notmuch_database_set_config (db, "zzzafter", "afterval"));
+   RUN(notmuch_database_set_config (db, "aaabefore", "beforeval"));
+   RUN(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
+testkey1 testvalue1
+testkey2 testvalue2
+zzzafter afterval
+== stderr ==
+EOF
+test_expect_equal_file EXPECTED OUTPUT
+
+test_begin_subtest "notmuch_database_get_config_list: one prefix"
+cat c_head - c_tail <<'EOF' | test_C ${MAIL_DIR}
+{
+   notmuch_config_list_t *list;
+   RUN(notmuch_database_get_config_list (db, "testkey", &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 ==
+testkey1 testvalue1
+testkey2 testvalue2
+== stderr ==
+EOF
+test_expect_equal_file EXPECTED OUTPUT
+
 test_done
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [WIP2 3/4] CLI: add print_status_database
  2016-01-13  3:10 second round of library config API and dump David Bremner
  2016-01-13  3:10 ` [WIP2 1/4] lib: provide config API David Bremner
  2016-01-13  3:10 ` [WIP2 2/4] lib: config list iterators David Bremner
@ 2016-01-13  3:10 ` David Bremner
  2016-01-13  3:10 ` [WIP2 4/4] CLI: add optional metadata to dump output David Bremner
  3 siblings, 0 replies; 5+ messages in thread
From: David Bremner @ 2016-01-13  3:10 UTC (permalink / raw)
  To: notmuch

This could probably be used at quite a few places in the existing code,
but in the immediate future I plan to use in some new code in
notmuch-dump
---
 notmuch-client.h |  5 +++++
 status.c         | 17 +++++++++++++++++
 2 files changed, 22 insertions(+)

diff --git a/notmuch-client.h b/notmuch-client.h
index 3bd2903..7c9a1ea 100644
--- a/notmuch-client.h
+++ b/notmuch-client.h
@@ -459,6 +459,11 @@ print_status_query (const char *loc,
 		    const notmuch_query_t *query,
 		    notmuch_status_t status);
 
+notmuch_status_t
+print_status_database (const char *loc,
+		       const notmuch_database_t *database,
+		       notmuch_status_t status);
+
 #include "command-line-arguments.h"
 
 extern char *notmuch_requested_db_uuid;
diff --git a/status.c b/status.c
index 8fa81cb..45d3fb4 100644
--- a/status.c
+++ b/status.c
@@ -19,3 +19,20 @@ print_status_query (const char *loc,
     }
     return status;
 }
+
+notmuch_status_t
+print_status_database (const char *loc,
+		    const notmuch_database_t *notmuch,
+		    notmuch_status_t status)
+{
+    if (status) {
+	const char *msg;
+
+	fprintf (stderr, "%s: %s\n", loc,
+		 notmuch_status_to_string (status));
+	msg = notmuch_database_status_string (notmuch);
+	if (msg)
+	    fputs (msg, stderr);
+    }
+    return status;
+}
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [WIP2 4/4] CLI: add optional metadata to dump output.
  2016-01-13  3:10 second round of library config API and dump David Bremner
                   ` (2 preceding siblings ...)
  2016-01-13  3:10 ` [WIP2 3/4] CLI: add print_status_database David Bremner
@ 2016-01-13  3:10 ` David Bremner
  3 siblings, 0 replies; 5+ messages in thread
From: David Bremner @ 2016-01-13  3:10 UTC (permalink / raw)
  To: notmuch

This lacks at least documentation. Note that it changes the default dump
output format, but doesn't break existing notmuch-restore. It might
break user scripts though.
---
 notmuch-client.h       |  6 ++++++
 notmuch-dump.c         | 41 ++++++++++++++++++++++++++++++++++++++---
 notmuch-new.c          |  2 +-
 test/T590-libconfig.sh | 10 ++++++++++
 4 files changed, 55 insertions(+), 4 deletions(-)

diff --git a/notmuch-client.h b/notmuch-client.h
index 7c9a1ea..2dca83c 100644
--- a/notmuch-client.h
+++ b/notmuch-client.h
@@ -443,11 +443,17 @@ typedef enum dump_formats {
     DUMP_FORMAT_SUP
 } dump_format_t;
 
+typedef enum dump_includes {
+    DUMP_INCLUDE_TAGS=1,
+    DUMP_INCLUDE_CONFIG=2,
+} dump_include_t;
+
 int
 notmuch_database_dump (notmuch_database_t *notmuch,
 		       const char *output_file_name,
 		       const char *query_str,
 		       dump_format_t output_format,
+		       dump_include_t include,
 		       notmuch_bool_t gzip_output);
 
 /* If status is non-zero (i.e. error) print appropriate
diff --git a/notmuch-dump.c b/notmuch-dump.c
index 829781f..4909493 100644
--- a/notmuch-dump.c
+++ b/notmuch-dump.c
@@ -23,16 +23,43 @@
 #include "string-util.h"
 #include <zlib.h>
 
+static notmuch_status_t
+database_dump_config(notmuch_database_t *notmuch, gzFile output)
+{
+    notmuch_config_list_t *list;
+    notmuch_status_t status;
+    status = notmuch_database_get_config_list (notmuch, NULL, &list);
+    if (status)
+	return status;
+
+    for (; notmuch_config_list_valid (list); notmuch_config_list_move_to_next (list)) {
+	/* FIXME hexencode key and values */
+	gzprintf(output, "#@ %s %s\n",
+		 notmuch_config_list_key (list), notmuch_config_list_value (list));
+    }
+    notmuch_config_list_destroy (list);
+
+    return NOTMUCH_STATUS_SUCCESS;
+}
 
 static int
 database_dump_file (notmuch_database_t *notmuch, gzFile output,
-		    const char *query_str, int output_format)
+		    const char *query_str, int output_format, int include)
 {
     notmuch_query_t *query;
     notmuch_messages_t *messages;
     notmuch_message_t *message;
     notmuch_tags_t *tags;
 
+    if (include | DUMP_INCLUDE_CONFIG) {
+	if (print_status_database ("notmuch dump", notmuch,
+				   database_dump_config(notmuch,output)))
+	    return EXIT_FAILURE;
+    }
+
+    if (! (include & DUMP_INCLUDE_TAGS))
+	return EXIT_SUCCESS;
+
     if (! query_str)
 	query_str = "";
 
@@ -130,6 +157,7 @@ notmuch_database_dump (notmuch_database_t *notmuch,
 		       const char *output_file_name,
 		       const char *query_str,
 		       dump_format_t output_format,
+		       dump_include_t include,
 		       notmuch_bool_t gzip_output)
 {
     gzFile output = NULL;
@@ -164,7 +192,7 @@ notmuch_database_dump (notmuch_database_t *notmuch,
 	goto DONE;
     }
 
-    ret = database_dump_file (notmuch, output, query_str, output_format);
+    ret = database_dump_file (notmuch, output, query_str, output_format, include);
     if (ret) goto DONE;
 
     ret = gzflush (output, Z_FINISH);
@@ -226,6 +254,7 @@ notmuch_dump_command (notmuch_config_t *config, int argc, char *argv[])
     int opt_index;
 
     int output_format = DUMP_FORMAT_BATCH_TAG;
+    int include = 0;
     notmuch_bool_t gzip_output = 0;
 
     notmuch_opt_desc_t options[] = {
@@ -233,6 +262,9 @@ notmuch_dump_command (notmuch_config_t *config, int argc, char *argv[])
 	  (notmuch_keyword_t []){ { "sup", DUMP_FORMAT_SUP },
 				  { "batch-tag", DUMP_FORMAT_BATCH_TAG },
 				  { 0, 0 } } },
+	{ NOTMUCH_OPT_KEYWORD_FLAGS, &include, "include", 'i',
+	  (notmuch_keyword_t []){ { "metadata", DUMP_INCLUDE_CONFIG },
+				  { "tags", DUMP_INCLUDE_TAGS} } },
 	{ NOTMUCH_OPT_STRING, &output_file_name, "output", 'o', 0  },
 	{ NOTMUCH_OPT_BOOLEAN, &gzip_output, "gzip", 'z', 0 },
 	{ NOTMUCH_OPT_INHERIT, (void *) &notmuch_shared_options, NULL, 0, 0 },
@@ -245,6 +277,9 @@ notmuch_dump_command (notmuch_config_t *config, int argc, char *argv[])
 
     notmuch_process_shared_options (argv[0]);
 
+    if (include == 0)
+	include = DUMP_INCLUDE_CONFIG | DUMP_INCLUDE_TAGS;
+
     if (opt_index < argc) {
 	query_str = query_string_from_args (notmuch, argc - opt_index, argv + opt_index);
 	if (query_str == NULL) {
@@ -254,7 +289,7 @@ notmuch_dump_command (notmuch_config_t *config, int argc, char *argv[])
     }
 
     ret = notmuch_database_dump (notmuch, output_file_name, query_str,
-				 output_format, gzip_output);
+				 output_format, include, gzip_output);
 
     notmuch_database_destroy (notmuch);
 
diff --git a/notmuch-new.c b/notmuch-new.c
index e503776..fd2ff82 100644
--- a/notmuch-new.c
+++ b/notmuch-new.c
@@ -1041,7 +1041,7 @@ notmuch_new_command (notmuch_config_t *config, int argc, char *argv[])
 	    }
 
 	    if (notmuch_database_dump (notmuch, backup_name, "",
-				       DUMP_FORMAT_BATCH_TAG, TRUE)) {
+				       DUMP_FORMAT_BATCH_TAG, DUMP_INCLUDE_CONFIG | DUMP_INCLUDE_TAGS, TRUE)) {
 		fprintf (stderr, "Backup failed. Aborting upgrade.");
 		return EXIT_FAILURE;
 	    }
diff --git a/test/T590-libconfig.sh b/test/T590-libconfig.sh
index 8ca6883..4fe6bd1 100755
--- a/test/T590-libconfig.sh
+++ b/test/T590-libconfig.sh
@@ -115,4 +115,14 @@ testkey2 testvalue2
 EOF
 test_expect_equal_file EXPECTED OUTPUT
 
+test_begin_subtest "dump config"
+notmuch dump --include=metadata >OUTPUT
+cat <<'EOF' >EXPECTED
+#@ aaabefore beforeval
+#@ testkey1 testvalue1
+#@ testkey2 testvalue2
+#@ zzzafter afterval
+EOF
+test_expect_equal_file EXPECTED OUTPUT
+
 test_done
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2016-01-13  3:10 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-01-13  3:10 second round of library config API and dump David Bremner
2016-01-13  3:10 ` [WIP2 1/4] lib: provide config API David Bremner
2016-01-13  3:10 ` [WIP2 2/4] lib: config list iterators David Bremner
2016-01-13  3:10 ` [WIP2 3/4] CLI: add print_status_database David Bremner
2016-01-13  3:10 ` [WIP2 4/4] CLI: add optional metadata to dump output David Bremner

Code repositories for project(s) associated with this public inbox

	https://yhetil.org/notmuch.git/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).