]> git.notmuchmail.org Git - notmuch/commitdiff
Merge branch 'release'
authorDavid Bremner <david@tethera.net>
Sat, 22 May 2021 12:34:55 +0000 (09:34 -0300)
committerDavid Bremner <david@tethera.net>
Sat, 22 May 2021 12:34:55 +0000 (09:34 -0300)
66 files changed:
Makefile.local
NEWS
bindings/Makefile.local
bindings/ruby/database.c
bindings/ruby/defs.h
bindings/ruby/directory.c
bindings/ruby/filenames.c
bindings/ruby/init.c
bindings/ruby/message.c
bindings/ruby/messages.c
bindings/ruby/query.c
bindings/ruby/tags.c
bindings/ruby/thread.c
bindings/ruby/threads.c
gmime-filter-reply.c
gmime-filter-reply.h
lib/Makefile.local
lib/add-message.cc
lib/database-private.h
lib/index.cc
lib/init.cc [new file with mode: 0644]
lib/message-file.c
lib/message.cc
lib/notmuch-private.h
lib/open.cc
notmuch-client-init.c [new file with mode: 0644]
notmuch-client.h
notmuch-config.c
notmuch-insert.c
notmuch-new.c
notmuch-reindex.c
notmuch-tag.c
notmuch.c
performance-test/README
performance-test/perf-test-lib.sh
test/T000-basic.sh
test/T070-insert.sh
test/T140-excludes.sh
test/T160-json.sh
test/T170-sexp.sh
test/T190-multipart.sh
test/T310-emacs.sh
test/T320-emacs-large-search-buffer.sh
test/T330-emacs-subject-to-filename.sh
test/T350-crypto.sh
test/T355-smime.sh
test/T357-index-decryption.sh
test/T358-emacs-protected-headers.sh
test/T395-ruby.sh
test/T420-emacs-test-functions.sh
test/T430-emacs-address-cleaning.sh
test/T440-emacs-hello.sh
test/T450-emacs-show.sh
test/T455-emacs-charsets.sh
test/T460-emacs-tree.sh
test/T490-parse-time-string.sh
test/T510-thread-replies.sh
test/T590-thread-breakage.sh
test/T630-emacs-draft.sh
test/T720-emacs-attachment-warnings.sh
test/T730-emacs-forwarding.sh
test/export-dirs.sh
test/test-lib-common.sh
test/test-lib-emacs.sh [new file with mode: 0644]
test/test-lib.sh
vim/notmuch.vim

index bbb8f0b61a3fab43819e906ad3a2a9b3195b65f2..e12b94cd6f668bfc830070ec24d924ff8941bebf 100644 (file)
@@ -231,6 +231,7 @@ notmuch_client_srcs =               \
        gmime-filter-reply.c    \
        hooks.c                 \
        notmuch.c               \
+       notmuch-client-init.c   \
        notmuch-compact.c       \
        notmuch-config.c        \
        notmuch-count.c         \
diff --git a/NEWS b/NEWS
index e1fa2d73ae027c8e2dfa666b3dcbde5be789ca5a..c0ae6afe9c7b4307a15350673c0714db0f53879c 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,11 @@
+Notmuch 0.33 (UNRELEASED)
+=========================
+
+Vim
+---
+
+Respect excluded tags when showing a thread.
+
 Notmuch 0.32.1 (2021-05-15)
 ===========================
 
index bc960bbceabe592bb75522c25c20bbc2c9c70e10..3672e69ff76af07da05afc0a527355d2c0271941 100644 (file)
@@ -10,7 +10,7 @@ ifeq ($(HAVE_RUBY_DEV),1)
                LIBNOTMUCH="../../lib/$(LINKER_NAME)" \
                NOTMUCH_SRCDIR='$(NOTMUCH_SRCDIR)' \
                $(RUBY) extconf.rb --vendor
-       $(MAKE) -C $(dir)/ruby
+       $(MAKE) -C $(dir)/ruby CFLAGS="$(CFLAGS) -pipe -fno-plt -fPIC"
 endif
 
 python-cffi-bindings: lib/$(LINKER_NAME)
index 416eb709f19d231bfdf6460c37a8e2262fad24af..bb993d8688848df012f26d4f9a545f31b78c195d 100644 (file)
@@ -23,7 +23,7 @@
 VALUE
 notmuch_rb_database_alloc (VALUE klass)
 {
-    return Data_Wrap_Struct (klass, NULL, NULL, NULL);
+    return Data_Wrap_Notmuch_Object (klass, &notmuch_rb_database_type, NULL);
 }
 
 /*
@@ -74,7 +74,7 @@ notmuch_rb_database_initialize (int argc, VALUE *argv, VALUE self)
        mode = NOTMUCH_DATABASE_MODE_READ_ONLY;
     }
 
-    Check_Type (self, T_DATA);
+    rb_check_typeddata (self, &notmuch_rb_database_type);
     if (create)
        ret = notmuch_database_create (path, &database);
     else
@@ -114,11 +114,7 @@ VALUE
 notmuch_rb_database_close (VALUE self)
 {
     notmuch_status_t ret;
-    notmuch_database_t *db;
-
-    Data_Get_Notmuch_Database (self, db);
-    ret = notmuch_database_destroy (db);
-    DATA_PTR (self) = NULL;
+    ret = notmuch_rb_object_destroy (self, &notmuch_rb_database_type);
     notmuch_rb_status_raise (ret);
 
     return Qnil;
@@ -266,7 +262,7 @@ notmuch_rb_database_get_directory (VALUE self, VALUE pathv)
     ret = notmuch_database_get_directory (db, path, &dir);
     notmuch_rb_status_raise (ret);
     if (dir)
-       return Data_Wrap_Struct (notmuch_rb_cDirectory, NULL, NULL, dir);
+       return Data_Wrap_Notmuch_Object (notmuch_rb_cDirectory, &notmuch_rb_directory_type, dir);
     return Qnil;
 }
 
@@ -293,7 +289,7 @@ notmuch_rb_database_add_message (VALUE self, VALUE pathv)
 
     ret = notmuch_database_index_file (db, path, NULL, &message);
     notmuch_rb_status_raise (ret);
-    return rb_assoc_new (Data_Wrap_Struct (notmuch_rb_cMessage, NULL, NULL, message),
+    return rb_assoc_new (Data_Wrap_Notmuch_Object (notmuch_rb_cMessage, &notmuch_rb_message_type, message),
         (ret == NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID) ? Qtrue : Qfalse);
 }
 
@@ -344,7 +340,7 @@ notmuch_rb_database_find_message (VALUE self, VALUE idv)
     notmuch_rb_status_raise (ret);
 
     if (message)
-        return Data_Wrap_Struct (notmuch_rb_cMessage, NULL, NULL, message);
+       return Data_Wrap_Notmuch_Object (notmuch_rb_cMessage, &notmuch_rb_message_type, message);
     return Qnil;
 }
 
@@ -370,7 +366,7 @@ notmuch_rb_database_find_message_by_filename (VALUE self, VALUE pathv)
     notmuch_rb_status_raise (ret);
 
     if (message)
-        return Data_Wrap_Struct (notmuch_rb_cMessage, NULL, NULL, message);
+       return Data_Wrap_Notmuch_Object (notmuch_rb_cMessage, &notmuch_rb_message_type, message);
     return Qnil;
 }
 
@@ -395,7 +391,7 @@ notmuch_rb_database_get_all_tags (VALUE self)
 
        rb_raise (notmuch_rb_eBaseError, "%s", msg);
     }
-    return Data_Wrap_Struct (notmuch_rb_cTags, NULL, NULL, tags);
+    return Data_Wrap_Notmuch_Object (notmuch_rb_cTags, &notmuch_rb_tags_type, tags);
 }
 
 /*
@@ -419,5 +415,5 @@ notmuch_rb_database_query_create (VALUE self, VALUE qstrv)
     if (!query)
         rb_raise (notmuch_rb_eMemoryError, "Out of memory");
 
-    return Data_Wrap_Struct (notmuch_rb_cQuery, NULL, NULL, query);
+    return Data_Wrap_Notmuch_Object (notmuch_rb_cQuery, &notmuch_rb_query_type, query);
 }
index 48544ca2a4acbe57a48630957e9dd059de504f69..9860ee17d9479e1bc1101978585ed986e0e704c1 100644 (file)
@@ -55,77 +55,70 @@ extern ID ID_db_mode;
 # define RSTRING_PTR(v) (RSTRING((v))->ptr)
 #endif /* !defined (RSTRING_PTR) */
 
-#define Data_Get_Notmuch_Database(obj, ptr)                    \
-    do {                                                       \
-       Check_Type ((obj), T_DATA);                             \
-       if (DATA_PTR ((obj)) == NULL)                           \
-       rb_raise (rb_eRuntimeError, "database closed");         \
-       Data_Get_Struct ((obj), notmuch_database_t, (ptr));     \
+extern const rb_data_type_t notmuch_rb_object_type;
+extern const rb_data_type_t notmuch_rb_database_type;
+extern const rb_data_type_t notmuch_rb_directory_type;
+extern const rb_data_type_t notmuch_rb_filenames_type;
+extern const rb_data_type_t notmuch_rb_query_type;
+extern const rb_data_type_t notmuch_rb_threads_type;
+extern const rb_data_type_t notmuch_rb_thread_type;
+extern const rb_data_type_t notmuch_rb_messages_type;
+extern const rb_data_type_t notmuch_rb_message_type;
+extern const rb_data_type_t notmuch_rb_tags_type;
+
+#define Data_Get_Notmuch_Object(obj, type, ptr)                                            \
+    do {                                                                           \
+       (ptr) = rb_check_typeddata ((obj), (type));                                 \
+       if (RB_UNLIKELY (!(ptr))) {                                                 \
+           VALUE cname = rb_class_name (CLASS_OF ((obj)));                         \
+           rb_raise (rb_eRuntimeError, "%"PRIsVALUE" object destroyed", cname);    \
+       }                                                                           \
     } while (0)
 
-#define Data_Get_Notmuch_Directory(obj, ptr)                   \
-    do {                                                       \
-       Check_Type ((obj), T_DATA);                             \
-       if (DATA_PTR ((obj)) == NULL)                           \
-       rb_raise (rb_eRuntimeError, "directory destroyed");     \
-       Data_Get_Struct ((obj), notmuch_directory_t, (ptr));    \
-    } while (0)
+#define Data_Wrap_Notmuch_Object(klass, type, ptr) \
+    TypedData_Wrap_Struct ((klass), (type), (ptr))
 
-#define Data_Get_Notmuch_FileNames(obj, ptr)                   \
-    do {                                                       \
-       Check_Type ((obj), T_DATA);                             \
-       if (DATA_PTR ((obj)) == NULL)                           \
-       rb_raise (rb_eRuntimeError, "filenames destroyed");     \
-       Data_Get_Struct ((obj), notmuch_filenames_t, (ptr));    \
-    } while (0)
+#define Data_Get_Notmuch_Database(obj, ptr) \
+    Data_Get_Notmuch_Object ((obj), &notmuch_rb_database_type, (ptr))
 
-#define Data_Get_Notmuch_Query(obj, ptr)                       \
-    do {                                                       \
-       Check_Type ((obj), T_DATA);                             \
-       if (DATA_PTR ((obj)) == NULL)                           \
-       rb_raise (rb_eRuntimeError, "query destroyed");         \
-       Data_Get_Struct ((obj), notmuch_query_t, (ptr));        \
-    } while (0)
+#define Data_Get_Notmuch_Directory(obj, ptr) \
+    Data_Get_Notmuch_Object ((obj), &notmuch_rb_directory_type, (ptr))
 
-#define Data_Get_Notmuch_Threads(obj, ptr)                     \
-    do {                                                       \
-       Check_Type ((obj), T_DATA);                             \
-       if (DATA_PTR ((obj)) == NULL)                           \
-       rb_raise (rb_eRuntimeError, "threads destroyed");       \
-       Data_Get_Struct ((obj), notmuch_threads_t, (ptr));      \
-    } while (0)
+#define Data_Get_Notmuch_FileNames(obj, ptr) \
+    Data_Get_Notmuch_Object ((obj), &notmuch_rb_filenames_type, (ptr))
 
-#define Data_Get_Notmuch_Messages(obj, ptr)                    \
-    do {                                                       \
-       Check_Type ((obj), T_DATA);                             \
-       if (DATA_PTR ((obj)) == NULL)                           \
-       rb_raise (rb_eRuntimeError, "messages destroyed");      \
-       Data_Get_Struct ((obj), notmuch_messages_t, (ptr));     \
-    } while (0)
+#define Data_Get_Notmuch_Query(obj, ptr) \
+    Data_Get_Notmuch_Object ((obj), &notmuch_rb_query_type, (ptr))
 
-#define Data_Get_Notmuch_Thread(obj, ptr)                      \
-    do {                                                       \
-       Check_Type ((obj), T_DATA);                             \
-       if (DATA_PTR ((obj)) == NULL)                           \
-       rb_raise (rb_eRuntimeError, "thread destroyed");        \
-       Data_Get_Struct ((obj), notmuch_thread_t, (ptr));       \
-    } while (0)
+#define Data_Get_Notmuch_Threads(obj, ptr) \
+    Data_Get_Notmuch_Object ((obj), &notmuch_rb_threads_type, (ptr))
 
-#define Data_Get_Notmuch_Message(obj, ptr)                     \
-    do {                                                       \
-       Check_Type ((obj), T_DATA);                             \
-       if (DATA_PTR ((obj)) == NULL)                           \
-       rb_raise (rb_eRuntimeError, "message destroyed");       \
-       Data_Get_Struct ((obj), notmuch_message_t, (ptr));      \
-    } while (0)
+#define Data_Get_Notmuch_Messages(obj, ptr) \
+    Data_Get_Notmuch_Object ((obj), &notmuch_rb_messages_type, (ptr))
 
-#define Data_Get_Notmuch_Tags(obj, ptr)                        \
-    do {                                               \
-       Check_Type ((obj), T_DATA);                     \
-       if (DATA_PTR ((obj)) == NULL)                   \
-       rb_raise (rb_eRuntimeError, "tags destroyed");  \
-       Data_Get_Struct ((obj), notmuch_tags_t, (ptr)); \
-    } while (0)
+#define Data_Get_Notmuch_Thread(obj, ptr) \
+    Data_Get_Notmuch_Object ((obj), &notmuch_rb_thread_type, (ptr))
+
+#define Data_Get_Notmuch_Message(obj, ptr) \
+    Data_Get_Notmuch_Object ((obj), &notmuch_rb_message_type, (ptr))
+
+#define Data_Get_Notmuch_Tags(obj, ptr) \
+    Data_Get_Notmuch_Object ((obj), &notmuch_rb_tags_type, (ptr))
+
+static inline notmuch_status_t
+notmuch_rb_object_destroy (VALUE rb_object, const rb_data_type_t *type)
+{
+    void *nm_object;
+    notmuch_status_t ret;
+
+    Data_Get_Notmuch_Object (rb_object, type, nm_object);
+
+    /* Call the corresponding notmuch_*_destroy function */
+    ret = ((notmuch_status_t (*)(void *)) type->data) (nm_object);
+    DATA_PTR (rb_object) = NULL;
+
+    return ret;
+}
 
 /* status.c */
 void
index 0f37b3910042426219ae7cdf7137ec1b017cfb11..910f0a99f238239f2c5717b2a85b2cbca190bcf5 100644 (file)
 VALUE
 notmuch_rb_directory_destroy (VALUE self)
 {
-    notmuch_directory_t *dir;
-
-    Data_Get_Struct (self, notmuch_directory_t, dir);
-
-    notmuch_directory_destroy (dir);
-    DATA_PTR (self) = NULL;
+    notmuch_rb_object_destroy (self, &notmuch_rb_directory_type);
 
     return Qnil;
 }
@@ -92,7 +87,7 @@ notmuch_rb_directory_get_child_files (VALUE self)
 
     fnames = notmuch_directory_get_child_files (dir);
 
-    return Data_Wrap_Struct (notmuch_rb_cFileNames, NULL, NULL, fnames);
+    return Data_Wrap_Notmuch_Object (notmuch_rb_cFileNames, &notmuch_rb_filenames_type, fnames);
 }
 
 /*
@@ -111,5 +106,5 @@ notmuch_rb_directory_get_child_directories (VALUE self)
 
     fnames = notmuch_directory_get_child_directories (dir);
 
-    return Data_Wrap_Struct (notmuch_rb_cFileNames, NULL, NULL, fnames);
+    return Data_Wrap_Notmuch_Object (notmuch_rb_cFileNames, &notmuch_rb_filenames_type, fnames);
 }
index 656c58e6f40dfdc87bcbc86b6dd7b2eb2680ecab..0dec19520b59b0b421df5c7a4cb03826e69d235d 100644 (file)
 VALUE
 notmuch_rb_filenames_destroy (VALUE self)
 {
-    notmuch_filenames_t *fnames;
-
-    Data_Get_Notmuch_FileNames (self, fnames);
-
-    notmuch_filenames_destroy (fnames);
-    DATA_PTR (self) = NULL;
+    notmuch_rb_object_destroy (self, &notmuch_rb_filenames_type);
 
     return Qnil;
 }
index 819fd1e35dc87a85945b57791149748910134ce3..62515ecad54b11120b29e95f816476c9727587cb 100644 (file)
@@ -46,6 +46,27 @@ ID ID_call;
 ID ID_db_create;
 ID ID_db_mode;
 
+const rb_data_type_t notmuch_rb_object_type = {
+    .wrap_struct_name = "notmuch_object",
+};
+
+#define define_type(id) \
+    const rb_data_type_t notmuch_rb_ ## id ## _type = { \
+       .wrap_struct_name = "notmuch_" #id, \
+       .parent = &notmuch_rb_object_type, \
+       .data = &notmuch_ ## id ## _destroy, \
+    }
+
+define_type (database);
+define_type (directory);
+define_type (filenames);
+define_type (query);
+define_type (threads);
+define_type (thread);
+define_type (messages);
+define_type (message);
+define_type (tags);
+
 /*
  * Document-module: Notmuch
  *
index 6ea82afa20c5071086883b437054d80613e7a45d..f45c95cc5051d8475920c5a59bf07706e829e0be 100644 (file)
 VALUE
 notmuch_rb_message_destroy (VALUE self)
 {
-    notmuch_message_t *message;
-
-    Data_Get_Notmuch_Message (self, message);
-
-    notmuch_message_destroy (message);
-    DATA_PTR (self) = NULL;
+    notmuch_rb_object_destroy (self, &notmuch_rb_message_type);
 
     return Qnil;
 }
@@ -89,7 +84,7 @@ notmuch_rb_message_get_replies (VALUE self)
 
     messages = notmuch_message_get_replies (message);
 
-    return Data_Wrap_Struct (notmuch_rb_cMessages, NULL, NULL, messages);
+    return Data_Wrap_Notmuch_Object (notmuch_rb_cMessages, &notmuch_rb_messages_type, messages);
 }
 
 /*
@@ -125,7 +120,7 @@ notmuch_rb_message_get_filenames (VALUE self)
 
     fnames = notmuch_message_get_filenames (message);
 
-    return Data_Wrap_Struct (notmuch_rb_cFileNames, NULL, NULL, fnames);
+    return Data_Wrap_Notmuch_Object (notmuch_rb_cFileNames, &notmuch_rb_filenames_type, fnames);
 }
 
 /*
@@ -226,7 +221,7 @@ notmuch_rb_message_get_tags (VALUE self)
     if (!tags)
        rb_raise (notmuch_rb_eMemoryError, "Out of memory");
 
-    return Data_Wrap_Struct (notmuch_rb_cTags, NULL, NULL, tags);
+    return Data_Wrap_Notmuch_Object (notmuch_rb_cTags, &notmuch_rb_tags_type, tags);
 }
 
 /*
index a337feeb499fff177e7f3c6659373eaf0c004a00..ca5b10d04b09702629eddbeb1eb217bef84a4274 100644 (file)
 VALUE
 notmuch_rb_messages_destroy (VALUE self)
 {
-    notmuch_messages_t *messages;
-
-    Data_Get_Notmuch_Messages (self, messages);
-
-    notmuch_messages_destroy (messages);
-    DATA_PTR (self) = NULL;
+    notmuch_rb_object_destroy (self, &notmuch_rb_messages_type);
 
     return Qnil;
 }
@@ -53,7 +48,7 @@ notmuch_rb_messages_each (VALUE self)
 
     for (; notmuch_messages_valid (messages); notmuch_messages_move_to_next (messages)) {
        message = notmuch_messages_get (messages);
-       rb_yield (Data_Wrap_Struct (notmuch_rb_cMessage, NULL, NULL, message));
+       rb_yield (Data_Wrap_Notmuch_Object (notmuch_rb_cMessage, &notmuch_rb_message_type, message));
     }
 
     return self;
@@ -76,5 +71,5 @@ notmuch_rb_messages_collect_tags (VALUE self)
     if (!tags)
        rb_raise (notmuch_rb_eMemoryError, "Out of memory");
 
-    return Data_Wrap_Struct (notmuch_rb_cTags, NULL, NULL, tags);
+    return Data_Wrap_Notmuch_Object (notmuch_rb_cTags, &notmuch_rb_tags_type, tags);
 }
index 8b46d700bdab01554c8944ec7903ea9ce8a3707e..3ec98c6c1d80db12feb7dd66c8b5e2fa3201a56e 100644 (file)
 VALUE
 notmuch_rb_query_destroy (VALUE self)
 {
-    notmuch_query_t *query;
-
-    Data_Get_Notmuch_Query (self, query);
-
-    notmuch_query_destroy (query);
-    DATA_PTR (self) = NULL;
+    notmuch_rb_object_destroy (self, &notmuch_rb_query_type);
 
     return Qnil;
 }
@@ -142,7 +137,7 @@ notmuch_rb_query_search_threads (VALUE self)
     if (status)
        notmuch_rb_status_raise (status);
 
-    return Data_Wrap_Struct (notmuch_rb_cThreads, NULL, NULL, threads);
+    return Data_Wrap_Notmuch_Object (notmuch_rb_cThreads, &notmuch_rb_threads_type, threads);
 }
 
 /*
@@ -163,7 +158,7 @@ notmuch_rb_query_search_messages (VALUE self)
     if (status)
        notmuch_rb_status_raise (status);
 
-    return Data_Wrap_Struct (notmuch_rb_cMessages, NULL, NULL, messages);
+    return Data_Wrap_Notmuch_Object (notmuch_rb_cMessages, &notmuch_rb_messages_type, messages);
 }
 
 /*
index db8b4cfc86f0b3eaa818ce0d7876862158826862..2af85e36598220f1cb93e806a8080ed2c3a3b862 100644 (file)
 VALUE
 notmuch_rb_tags_destroy (VALUE self)
 {
-    notmuch_tags_t *tags;
-
-    Data_Get_Notmuch_Tags (self, tags);
-
-    notmuch_tags_destroy (tags);
-    DATA_PTR (self) = NULL;
+    notmuch_rb_object_destroy (self, &notmuch_rb_tags_type);
 
     return Qnil;
 }
index 9b295981801779e1d970972d595b60eec1c4d5c6..7cb2a3dcc6ebeacdd5c4c37b726a53056c436a5c 100644 (file)
 VALUE
 notmuch_rb_thread_destroy (VALUE self)
 {
-    notmuch_thread_t *thread;
-
-    Data_Get_Notmuch_Thread (self, thread);
-
-    notmuch_thread_destroy (thread);
-    DATA_PTR (self) = NULL;
+    notmuch_rb_object_destroy (self, &notmuch_rb_thread_type);
 
     return Qnil;
 }
@@ -88,7 +83,7 @@ notmuch_rb_thread_get_toplevel_messages (VALUE self)
     if (!messages)
        rb_raise (notmuch_rb_eMemoryError, "Out of memory");
 
-    return Data_Wrap_Struct (notmuch_rb_cMessages, NULL, NULL, messages);
+    return Data_Wrap_Notmuch_Object (notmuch_rb_cMessages, &notmuch_rb_messages_type, messages);
 }
 
 /*
@@ -108,7 +103,7 @@ notmuch_rb_thread_get_messages (VALUE self)
     if (!messages)
        rb_raise (notmuch_rb_eMemoryError, "Out of memory");
 
-    return Data_Wrap_Struct (notmuch_rb_cMessages, NULL, NULL, messages);
+    return Data_Wrap_Notmuch_Object (notmuch_rb_cMessages, &notmuch_rb_messages_type, messages);
 }
 
 /*
@@ -209,5 +204,5 @@ notmuch_rb_thread_get_tags (VALUE self)
     if (!tags)
        rb_raise (notmuch_rb_eMemoryError, "Out of memory");
 
-    return Data_Wrap_Struct (notmuch_rb_cTags, NULL, NULL, tags);
+    return Data_Wrap_Notmuch_Object (notmuch_rb_cTags, &notmuch_rb_tags_type, tags);
 }
index ed403a8f1f3db30e88d8fd030991ae1b62b1c9e6..50280260a4d3aa9576f4d09c7d9528ed6be6539c 100644 (file)
 VALUE
 notmuch_rb_threads_destroy (VALUE self)
 {
-    notmuch_threads_t *threads;
-
-    Data_Get_Struct (self, notmuch_threads_t, threads);
-
-    notmuch_threads_destroy (threads);
-    DATA_PTR (self) = NULL;
+    notmuch_rb_object_destroy (self, &notmuch_rb_threads_type);
 
     return Qnil;
 }
@@ -53,7 +48,7 @@ notmuch_rb_threads_each (VALUE self)
 
     for (; notmuch_threads_valid (threads); notmuch_threads_move_to_next (threads)) {
        thread = notmuch_threads_get (threads);
-       rb_yield (Data_Wrap_Struct (notmuch_rb_cThread, NULL, NULL, thread));
+       rb_yield (Data_Wrap_Notmuch_Object (notmuch_rb_cThread, &notmuch_rb_thread_type, thread));
     }
 
     return self;
index 2b0676698b8ff7225b164c9db52ab5ad5b5ea314..35349cc8170fdd7abcaa08684e83320eb9f1df08 100644 (file)
@@ -43,29 +43,31 @@ static void filter_reset (GMimeFilter *filter);
 
 
 static GMimeFilterClass *parent_class = NULL;
+static GType type = 0;
+static const GTypeInfo info = {
+    .class_size = sizeof (GMimeFilterReplyClass),
+    .base_init = NULL,
+    .base_finalize = NULL,
+    .class_init = (GClassInitFunc) g_mime_filter_reply_class_init,
+    .class_finalize = NULL,
+    .class_data = NULL,
+    .instance_size = sizeof (GMimeFilterReply),
+    .n_preallocs = 0,
+    .instance_init = (GInstanceInitFunc) g_mime_filter_reply_init,
+    .value_table = NULL,
+};
+
+
+void
+g_mime_filter_reply_module_init (void)
+{
+    type = g_type_register_static (GMIME_TYPE_FILTER, "GMimeFilterReply", &info, (GTypeFlags) 0);
+    parent_class = (GMimeFilterClass *) g_type_class_ref (GMIME_TYPE_FILTER);
+}
 
 GType
 g_mime_filter_reply_get_type (void)
 {
-    static GType type = 0;
-
-    if (! type) {
-       static const GTypeInfo info = {
-           .class_size = sizeof (GMimeFilterReplyClass),
-           .base_init = NULL,
-           .base_finalize = NULL,
-           .class_init = (GClassInitFunc) g_mime_filter_reply_class_init,
-           .class_finalize = NULL,
-           .class_data = NULL,
-           .instance_size = sizeof (GMimeFilterReply),
-           .n_preallocs = 0,
-           .instance_init = (GInstanceInitFunc) g_mime_filter_reply_init,
-           .value_table = NULL,
-       };
-
-       type = g_type_register_static (GMIME_TYPE_FILTER, "GMimeFilterReply", &info, (GTypeFlags) 0);
-    }
-
     return type;
 }
 
@@ -76,8 +78,6 @@ g_mime_filter_reply_class_init (GMimeFilterReplyClass *klass, unused (void *clas
     GObjectClass *object_class = G_OBJECT_CLASS (klass);
     GMimeFilterClass *filter_class = GMIME_FILTER_CLASS (klass);
 
-    parent_class = (GMimeFilterClass *) g_type_class_ref (GMIME_TYPE_FILTER);
-
     object_class->finalize = g_mime_filter_reply_finalize;
 
     filter_class->copy = filter_copy;
index 7cdefcd1f127ff45e5ca9cbd63bf0f541816e1c9..988fe2d6e8c5122fcbc523e8ceefdab4e38bd38e 100644 (file)
@@ -21,6 +21,8 @@
 
 #include <gmime/gmime-filter.h>
 
+void g_mime_filter_reply_module_init (void);
+
 G_BEGIN_DECLS
 
 #define GMIME_TYPE_FILTER_REPLY            (g_mime_filter_reply_get_type ())
index 01cbb3f2821c8e0a1e0145192e2e3368b625d6c7..e2d4b91dcaf2add44978fa28ed49dbadcbf8eaa3 100644 (file)
@@ -62,7 +62,8 @@ libnotmuch_cxx_srcs =         \
        $(dir)/thread-fp.cc     \
        $(dir)/features.cc      \
        $(dir)/prefix.cc        \
-       $(dir)/open.cc
+       $(dir)/open.cc          \
+       $(dir)/init.cc
 
 libnotmuch_modules := $(libnotmuch_c_srcs:.c=.o) $(libnotmuch_cxx_srcs:.cc=.o)
 
index d6e5e73d35f4b4c3183df5642ac251c95ad48641..b16748fda20ebf4128f4e8fd78f4a66f9c9a83c2 100644 (file)
@@ -40,17 +40,14 @@ parse_references (void *ctx,
 static const char *
 _notmuch_database_generate_thread_id (notmuch_database_t *notmuch)
 {
-    /* 16 bytes (+ terminator) for hexadecimal representation of
-     * a 64-bit integer. */
-    static char thread_id[17];
 
     notmuch->last_thread_id++;
 
-    sprintf (thread_id, "%016" PRIx64, notmuch->last_thread_id);
+    sprintf (notmuch->thread_id_str, "%016" PRIx64, notmuch->last_thread_id);
 
-    notmuch->writable_xapian_db->set_metadata ("last_thread_id", thread_id);
+    notmuch->writable_xapian_db->set_metadata ("last_thread_id", notmuch->thread_id_str);
 
-    return thread_id;
+    return notmuch->thread_id_str;
 }
 
 static char *
index 0d12ec1efde57b4862f1001facdbfafe3dec54cd..1a73dacc365f563134d123fe09d91668b45a6d1f 100644 (file)
@@ -206,6 +206,10 @@ struct _notmuch_database {
     enum _notmuch_features features;
 
     unsigned int last_doc_id;
+
+    /* 16 bytes (+ terminator) for hexadecimal representation of
+     * a 64-bit integer. */
+    char thread_id_str[17];
     uint64_t last_thread_id;
 
     /* error reporting; this value persists only until the
index 55c8372e3aa1c146913222369f7185cb6805531a..728bfb22ab69c4eef52795cf86d7971c7d42e2fe 100644 (file)
@@ -148,8 +148,6 @@ notmuch_filter_discard_non_term_class_init (NotmuchFilterDiscardNonTermClass *kl
     GObjectClass *object_class = G_OBJECT_CLASS (klass);
     GMimeFilterClass *filter_class = GMIME_FILTER_CLASS (klass);
 
-    parent_class = (GMimeFilterClass *) g_type_class_ref (GMIME_TYPE_FILTER);
-
     object_class->finalize = notmuch_filter_discard_non_term_finalize;
 
     filter_class->copy = filter_copy;
@@ -240,30 +238,33 @@ filter_reset (GMimeFilter *gmime_filter)
  *
  * Returns: a new #NotmuchFilterDiscardNonTerm filter.
  **/
+static GType type = 0;
+
+static const GTypeInfo info = {
+    .class_size = sizeof (NotmuchFilterDiscardNonTermClass),
+    .base_init = NULL,
+    .base_finalize = NULL,
+    .class_init = (GClassInitFunc) notmuch_filter_discard_non_term_class_init,
+    .class_finalize = NULL,
+    .class_data = NULL,
+    .instance_size = sizeof (NotmuchFilterDiscardNonTerm),
+    .n_preallocs = 0,
+    .instance_init = NULL,
+    .value_table = NULL,
+};
+
+void
+_notmuch_filter_init () {
+    type = g_type_register_static (GMIME_TYPE_FILTER, "NotmuchFilterDiscardNonTerm", &info,
+                                  (GTypeFlags) 0);
+    parent_class = (GMimeFilterClass *) g_type_class_ref (GMIME_TYPE_FILTER);
+}
+
 static GMimeFilter *
 notmuch_filter_discard_non_term_new (GMimeContentType *content_type)
 {
-    static GType type = 0;
     NotmuchFilterDiscardNonTerm *filter;
 
-    if (! type) {
-       static const GTypeInfo info = {
-           .class_size = sizeof (NotmuchFilterDiscardNonTermClass),
-           .base_init = NULL,
-           .base_finalize = NULL,
-           .class_init = (GClassInitFunc) notmuch_filter_discard_non_term_class_init,
-           .class_finalize = NULL,
-           .class_data = NULL,
-           .instance_size = sizeof (NotmuchFilterDiscardNonTerm),
-           .n_preallocs = 0,
-           .instance_init = NULL,
-           .value_table = NULL,
-       };
-
-       type = g_type_register_static (GMIME_TYPE_FILTER, "NotmuchFilterDiscardNonTerm", &info,
-                                      (GTypeFlags) 0);
-    }
-
     filter = (NotmuchFilterDiscardNonTerm *) g_object_new (type, NULL);
     filter->content_type = content_type;
     filter->state = 0;
diff --git a/lib/init.cc b/lib/init.cc
new file mode 100644 (file)
index 0000000..cf29200
--- /dev/null
@@ -0,0 +1,21 @@
+#include "notmuch-private.h"
+
+#include <mutex>
+
+static void do_init ()
+{
+    /* Initialize the GLib type system and threads */
+#if ! GLIB_CHECK_VERSION (2, 35, 1)
+    g_type_init ();
+#endif
+
+    g_mime_init ();
+    _notmuch_filter_init ();
+}
+
+void
+_notmuch_init ()
+{
+    static std::once_flag initialized;
+    std::call_once (initialized, do_init);
+}
index 9e9b387fcc697a8e8b3d13a8bbbd03147714ef58..647ccf3abedaaf52f95bcc44e9a3199de8d4b42d 100644 (file)
@@ -141,7 +141,6 @@ _notmuch_message_file_parse (notmuch_message_file_t *message)
 {
     GMimeParser *parser;
     notmuch_status_t status = NOTMUCH_STATUS_SUCCESS;
-    static int initialized = 0;
     bool is_mbox;
 
     if (message->message)
@@ -149,10 +148,7 @@ _notmuch_message_file_parse (notmuch_message_file_t *message)
 
     is_mbox = _is_mbox (message->stream);
 
-    if (! initialized) {
-       g_mime_init ();
-       initialized = 1;
-    }
+    _notmuch_init ();
 
     message->headers = g_hash_table_new_full (strcase_hash, strcase_equal,
                                              free, g_free);
index 42d56acb10e4ae80a3f36e92c2f6c644b03afd43..7af6ab82a721699ac7f09153724b9e8038484b2a 100644 (file)
@@ -68,7 +68,7 @@ struct maildir_flag_tag {
 };
 
 /* ASCII ordered table of Maildir flags and associated tags */
-static struct maildir_flag_tag flag2tag[] = {
+static const struct maildir_flag_tag flag2tag[] = {
     { 'D', "draft",   false },
     { 'F', "flagged", false },
     { 'P', "passed",  false },
index 10b1b0245b16d12b8caca6f0bb109a6cde3ba89a..093c29b1bbc5384198b90c351046a6a3b19200e1 100644 (file)
@@ -469,11 +469,18 @@ _notmuch_database_link_message_to_parents (notmuch_database_t *notmuch,
                                           const char **thread_id);
 /* index.cc */
 
+void
+_notmuch_filter_init ();
+
 notmuch_status_t
 _notmuch_message_index_file (notmuch_message_t *message,
                             notmuch_indexopts_t *indexopts,
                             notmuch_message_file_t *message_file);
 
+/* init.cc */
+void
+_notmuch_init ();
+
 /* messages.c */
 
 typedef struct _notmuch_message_node {
index 3325e72506cb3023911c870056265ef63b305fd5..1ca69665c4e446ce4023b90713a86376c91310ee 100644 (file)
@@ -324,24 +324,6 @@ _set_database_path (notmuch_database_t *notmuch,
     _notmuch_config_cache (notmuch, NOTMUCH_CONFIG_DATABASE_PATH, path);
 }
 
-static void
-_init_libs ()
-{
-
-    static int initialized = 0;
-
-    /* Initialize the GLib type system and threads */
-#if ! GLIB_CHECK_VERSION (2, 35, 1)
-    g_type_init ();
-#endif
-
-    /* Initialize gmime */
-    if (! initialized) {
-       g_mime_init ();
-       initialized = 1;
-    }
-}
-
 static void
 _load_database_state (notmuch_database_t *notmuch)
 {
@@ -515,7 +497,7 @@ notmuch_database_open_with_config (const char *database_path,
     GKeyFile *key_file = NULL;
     bool split = false;
 
-    _init_libs ();
+    _notmuch_init ();
 
     notmuch = _alloc_notmuch ();
     if (! notmuch) {
@@ -612,7 +594,7 @@ notmuch_database_create_with_config (const char *database_path,
     int err;
     bool split = false;
 
-    _init_libs ();
+    _notmuch_init ();
 
     notmuch = _alloc_notmuch ();
     if (! notmuch) {
@@ -808,7 +790,7 @@ notmuch_database_load_config (const char *database_path,
     GKeyFile *key_file = NULL;
     bool split = false;
 
-    _init_libs ();
+    _notmuch_init ();
 
     notmuch = _alloc_notmuch ();
     if (! notmuch) {
diff --git a/notmuch-client-init.c b/notmuch-client-init.c
new file mode 100644 (file)
index 0000000..60db6ba
--- /dev/null
@@ -0,0 +1,18 @@
+#include "notmuch-client.h"
+#include "gmime-filter-reply.h"
+
+/* Caller is responsible for only calling this once */
+
+void
+notmuch_client_init (void)
+{
+#if ! GLIB_CHECK_VERSION (2, 35, 1)
+    g_type_init ();
+#endif
+
+    g_mime_init ();
+
+    g_mime_filter_reply_module_init ();
+
+    talloc_enable_null_tracking ();
+}
index 270553ad7f1cc9d5f79c4a20226301fdb2f49871..8227fea479d4e234da32c4e2f9d26dfd4f60cf41 100644 (file)
@@ -250,6 +250,10 @@ json_quote_chararray (const void *ctx, const char *str, const size_t len);
 char *
 json_quote_str (const void *ctx, const char *str);
 
+/* notmuch-client-init.c */
+
+void notmuch_client_init (void);
+
 /* notmuch-config.c */
 
 typedef enum {
index d9390c4d81ea10ff7e82196a5d034025b4915250..3430a3d35e7fe06052065575f21220457547d070 100644 (file)
@@ -32,7 +32,7 @@ static const char toplevel_config_comment[] =
     "\n"
     " For more information about notmuch, see https://notmuchmail.org";
 
-struct config_group {
+static const struct config_group {
     const char *group_name;
     const char *comment;
 } group_comment_table [] = {
@@ -512,14 +512,14 @@ typedef struct config_key {
     bool (*validate)(const char *);
 } config_key_info_t;
 
-static struct config_key
+static const struct config_key
     config_key_table[] = {
     { "index.decrypt",   false,  NULL },
     { "index.header.",   true,   validate_field_name },
     { "query.",          true,   NULL },
 };
 
-static config_key_info_t *
+static const config_key_info_t *
 _config_key_info (const char *item)
 {
     for (size_t i = 0; i < ARRAY_SIZE (config_key_table); i++) {
@@ -583,7 +583,7 @@ notmuch_config_command_set (notmuch_database_t *notmuch,
                            int argc, char *argv[])
 {
     char *group, *key;
-    config_key_info_t *key_info;
+    const config_key_info_t *key_info;
     notmuch_conffile_t *config;
     bool update_database = false;
     int opt_index, ret;
index 00c0046873f50cc788717ebb86ef6a10314bf70a..e3d87e4aed184af827b35e0e5276ff9b6cdc3f4d 100644 (file)
@@ -34,7 +34,7 @@ static volatile sig_atomic_t interrupted;
 static void
 handle_sigint (unused (int sig))
 {
-    static char msg[] = "Stopping...         \n";
+    static const char msg[] = "Stopping...         \n";
 
     /* This write is "opportunistic", so it's okay to ignore the
      * result.  It is not required for correctness, and if it does
index 993359d603a9bf75d9e606014741ee9cc6f0d83f..1ee498faaf7c4f79a174adab84c033cb3a8b2fd9 100644 (file)
@@ -81,7 +81,7 @@ static volatile sig_atomic_t interrupted;
 static void
 handle_sigint (unused (int sig))
 {
-    static char msg[] = "Stopping...         \n";
+    static const char msg[] = "Stopping...         \n";
 
     /* This write is "opportunistic", so it's okay to ignore the
      * result.  It is not required for correctness, and if it does
@@ -403,8 +403,11 @@ add_file (notmuch_database_t *notmuch, const char *filename,
        break;
     /* Non-fatal issues (go on to next file). */
     case NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID:
-       if (state->synchronize_flags)
-           notmuch_message_maildir_flags_to_tags (message);
+       if (state->synchronize_flags) {
+           status = notmuch_message_maildir_flags_to_tags (message);
+           if (print_status_message ("add_file", message, status))
+               goto DONE;
+       }
        break;
     case NOTMUCH_STATUS_FILE_NOT_EMAIL:
        fprintf (stderr, "Note: Ignoring non-mail file: %s\n", filename);
index 8904c1f41dca4d880a23708616705b76ede399eb..a7380a4bc197beb60f8140b9c37c5cc06ed8cf3e 100644 (file)
@@ -26,7 +26,7 @@ static volatile sig_atomic_t interrupted;
 static void
 handle_sigint (unused (int sig))
 {
-    static char msg[] = "Stopping...         \n";
+    static const char msg[] = "Stopping...         \n";
 
     /* This write is "opportunistic", so it's okay to ignore the
      * result.  It is not required for correctness, and if it does
index 667a75d6b960c3b2cc27b75d08753a813badc037..de428c8e9d99b902701a296a577cba87cb00c99c 100644 (file)
@@ -27,7 +27,7 @@ static volatile sig_atomic_t interrupted;
 static void
 handle_sigint (unused (int sig))
 {
-    static char msg[] = "Stopping...         \n";
+    static const char msg[] = "Stopping...         \n";
 
     /* This write is "opportunistic", so it's okay to ignore the
      * result.  It is not required for correctness, and if it does
index 2429999c2694345dd71b556e282b6dbb5a943dbe..d0a94fc2650993ae18bbd1ae6eae0109c3ca249b 100644 (file)
--- a/notmuch.c
+++ b/notmuch.c
@@ -139,7 +139,7 @@ notmuch_process_shared_indexing_options (notmuch_database_t *notmuch)
 }
 
 
-static command_t commands[] = {
+static const command_t commands[] = {
     { NULL, notmuch_command, NOTMUCH_COMMAND_CONFIG_CREATE | NOTMUCH_COMMAND_CONFIG_LOAD,
       "Notmuch main command." },
     { "setup", notmuch_setup_command, NOTMUCH_COMMAND_CONFIG_CREATE | NOTMUCH_COMMAND_CONFIG_LOAD,
@@ -189,7 +189,7 @@ typedef struct help_topic {
     const char *summary;
 } help_topic_t;
 
-static help_topic_t help_topics[] = {
+static const help_topic_t help_topics[] = {
     { "search-terms",
       "Common search term syntax." },
     { "hooks",
@@ -198,7 +198,7 @@ static help_topic_t help_topics[] = {
       "Message property conventions and documentation." },
 };
 
-static command_t *
+static const command_t *
 find_command (const char *name)
 {
     size_t i;
@@ -216,8 +216,8 @@ int notmuch_format_version;
 static void
 usage (FILE *out)
 {
-    command_t *command;
-    help_topic_t *topic;
+    const command_t *command;
+    const help_topic_t *topic;
     unsigned int i;
 
     fprintf (out,
@@ -308,8 +308,8 @@ exec_man (const char *page)
 static int
 _help_for (const char *topic_name)
 {
-    command_t *command;
-    help_topic_t *topic;
+    const command_t *command;
+    const help_topic_t *topic;
     unsigned int i;
 
     if (! topic_name) {
@@ -452,7 +452,7 @@ main (int argc, char *argv[])
     void *local;
     char *talloc_report;
     const char *command_name = NULL;
-    command_t *command;
+    const command_t *command;
     const char *config_file_name = NULL;
     notmuch_database_t *notmuch = NULL;
     int opt_index;
@@ -464,15 +464,10 @@ main (int argc, char *argv[])
        { }
     };
 
-    talloc_enable_null_tracking ();
+    notmuch_client_init ();
 
     local = talloc_new (NULL);
 
-    g_mime_init ();
-#if ! GLIB_CHECK_VERSION (2, 35, 1)
-    g_type_init ();
-#endif
-
     /* Globally default to the current output format version. */
     notmuch_format_version = NOTMUCH_FORMAT_CUR;
 
index fbc61028d2db4dfdc204cd4a78e2613cadd78c3c..59b37b1b8ff033092591ede74f9b1f7eb551ec62 100644 (file)
@@ -16,6 +16,7 @@ In addition to having notmuch, you need:
 - xz. Some speedup can be gotten by installing "pixz", but this is
   probably only worthwhile if you are debugging the tests.
 - valgrind (for the memory tests)
+- perf (optional, for more fine-grained timing)
 
 Getting set up to run tests:
 ----------------------------
@@ -56,11 +57,24 @@ supports the following arguments
 
 --small / --medium / --large   Choose corpus size.
 --debug                                Enable debugging. In particular don't delete
-                               temporary directories.
+                                temporary directories.
+--perf                          Run perf record in place of /usr/bin/time. Perf output can be
+                                found in a log directory.
+--call-graph {fp,lbr,dwarf}     Call graph option for perf record. Default is 'lbr'.
 
 When using the make targets, you can pass arguments to all test
 scripts by defining the make variable OPTIONS.
 
+Log Directory
+-------------
+
+The memory tests, and the time tests when option '--perf' is given
+save their output in a directory named as follows
+
+     log.$test_name-$corpus_size-$timestamp
+
+These directories are removed by "make clean".
+
 Writing tests
 -------------
 
index b70288ccaf316158b5c6ab16a46bff799c1b46a0..e7c502b6ca3d024aab87ab4d60d808fa8cf199df 100644 (file)
@@ -1,6 +1,9 @@
 . $(dirname "$0")/version.sh || exit 1
 
+debug=""
 corpus_size=large
+perf_callgraph=lbr
+use_perf=0
 
 while test "$#" -ne 0
 do
@@ -9,6 +12,15 @@ do
                debug=t;
                shift
                ;;
+       -p|--perf)
+               use_perf=1;
+               shift
+               ;;
+       -c|--call-graph)
+               shift
+               perf_callgraph=$1
+               shift
+               ;;
        -s|--small)
                corpus_size=small;
                shift
@@ -127,10 +139,20 @@ notmuch_new_with_cache ()
     fi
 }
 
+make_log_dir () {
+    local timestamp=$(date +%Y%m%dT%H%M%S)
+    log_dir=${TEST_DIRECTORY}/log.$(basename $0)-$corpus_size-${timestamp}
+    mkdir -p "${log_dir}"
+}
+
 time_start ()
 {
     add_email_corpus
 
+    if [[ "$use_perf" = 1 ]]; then
+       make_log_dir
+    fi
+
     print_header
 
     notmuch_new_with_cache time_run
@@ -140,9 +162,7 @@ memory_start ()
 {
     add_email_corpus
 
-    local timestamp=$(date +%Y%m%dT%H%M%S)
-    log_dir="${TEST_DIRECTORY}/log.$(basename $0)-$corpus_size-${timestamp}"
-    mkdir -p ${log_dir}
+    make_log_dir
 
     notmuch_new_with_cache memory_run
 }
@@ -193,7 +213,13 @@ time_run ()
     printf "  %-22s" "$1"
     test_count=$(($test_count+1))
     if test "$verbose" != "t"; then exec 4>test.output 3>&4; fi
-    if ! eval >&3 "/usr/bin/time -f '%e\t%U\t%S\t%M\t%I/%O' $2" ; then
+    if [[ "$use_perf" = 1 ]]; then
+       command_str="perf record --call-graph=${perf_callgraph} -o ${log_dir}/${test_count}.perf $2"
+    else
+       command_str="/usr/bin/time -f '%e\t%U\t%S\t%M\t%I/%O' $2"
+    fi
+
+    if ! eval >&3 "$command_str" ; then
        test_failure=$(($test_failure + 1))
        return 1
     fi
index 7fbdcfa3036cd860b13647a1678efde2063ce621..a2f4d93fd2652a832aad55466c602a51963dfc2f 100755 (executable)
@@ -33,7 +33,7 @@ test_begin_subtest 'failure to clean up causes the test to fail'
 test_expect_code 2 'test_when_finished "(exit 2)"'
 
 EXPECTED=$NOTMUCH_SRCDIR/test/test.expected-output
-suppress_diff_date() {
+suppress_diff_date () {
     sed -e 's/\(.*\-\-\- test-verbose\.4\.\expected\).*/\1/' \
        -e 's/\(.*\+\+\+ test-verbose\.4\.\output\).*/\1/'
 }
index b37a9b672bbad63bc34751f14c7363a6e3f5650d..208deb1c210c68b4cbfaa0586c6320da94c7c20f 100755 (executable)
@@ -15,7 +15,7 @@ notmuch new > /dev/null
 # They happen to be in the mail directory already but that is okay
 # since we do not call notmuch new hereafter.
 
-gen_insert_msg() {
+gen_insert_msg () {
     generate_message \
        "[subject]=\"insert-subject\"" \
        "[date]=\"Sat, 01 Jan 2000 12:00:00 -0000\"" \
index acab5381b94334bed54f1453eaf61a1e54807eba..352b3eb8c14314cbbd17391c9c795f8b66b2cf02 100755 (executable)
@@ -5,8 +5,7 @@ test_description='"notmuch search, count and show" with excludes in several vari
 # Generates a thread consisting of a top level message and 'length'
 # replies. The subject of the top message 'subject: top message"
 # and the subject of the nth reply in the thread is "subject: reply n"
-generate_thread ()
-{
+generate_thread () {
     local subject="$1"
     local length="$2"
     generate_message '[subject]="'"${subject}: top message"'"' '[body]="'"body of top message"'"'
index e8b75605fd2a391eaa0c51351d8f8bd6e0d80499..638afb4d5ef80ce50e2a9dc30c18fcf82444f353 100755 (executable)
@@ -1,6 +1,7 @@
 #!/usr/bin/env bash
 test_description="--format=json output"
 . $(dirname "$0")/test-lib.sh || exit 1
+. $(dirname "$0")/test-lib-emacs.sh || exit 1
 
 test_begin_subtest "Show message: json"
 add_message "[subject]=\"json-show-subject\"" "[date]=\"Sat, 01 Jan 2000 12:00:00 -0000\"" "[bcc]=\"test_suite+bcc@notmuchmail.org\"" "[reply-to]=\"test_suite+replyto@notmuchmail.org\"" "[body]=\"json-show-message\""
index 24be8351006e3d5bc64e9c4589f238104a9af14f..af8c4b44800decc4392e2fa8d17a9479b900fbc7 100755 (executable)
@@ -1,6 +1,7 @@
 #!/usr/bin/env bash
 test_description="--format=sexp output"
 . $(dirname "$0")/test-lib.sh || exit 1
+. $(dirname "$0")/test-lib-emacs.sh || exit 1
 
 test_begin_subtest "Show message: sexp"
 add_message "[subject]=\"sexp-show-subject\"" "[date]=\"Sat, 01 Jan 2000 12:00:00 -0000\"" "[bcc]=\"test_suite+bcc@notmuchmail.org\"" "[reply-to]=\"test_suite+replyto@notmuchmail.org\"" "[body]=\"sexp-show-message\""
index 6f715ff9b42e834b03ef67e1ebc8f25b89756a59..3545a59998e91ef5537ef0473eb876d860260072 100755 (executable)
@@ -725,8 +725,7 @@ EOF
 
 notmuch new > /dev/null
 
-cat_expected_head ()
-{
+cat_expected_head () {
         cat <<EOF
 [[[{"id": "htmlmessage", "match":true, "excluded": false, "date_relative":"2000-01-01",
    "crypto": {},
index e648924675f6551a33414d8d70b04e30b4ea1257..1ece6e0026933f44fffce57829ba9b08e7763042 100755 (executable)
@@ -2,9 +2,11 @@
 
 test_description="emacs interface"
 . $(dirname "$0")/test-lib.sh || exit 1
+. $(dirname "$0")/test-lib-emacs.sh || exit 1
 
 EXPECTED=$NOTMUCH_SRCDIR/test/emacs.expected-output
 
+test_require_emacs
 add_email_corpus
 
 # syntax errors in test-lib.el cause mysterious failures
index f61e8a973fc58b1cd8a74a623aaa48dc786be06a..d2638c8bf034d7e84b2c15346e5507be39f727f9 100755 (executable)
@@ -1,11 +1,14 @@
 #!/usr/bin/env bash
 test_description="Emacs with large search results buffer"
 . $(dirname "$0")/test-lib.sh || exit 1
+. $(dirname "$0")/test-lib-emacs.sh || exit 1
 
 x=xxxxxxxxxx # 10
 x=$x$x$x$x$x$x$x$x$x$x # 100
 x=$x$x$x$x$x$x$x$x$x # 900
 
+test_require_emacs
+
 # We generate a long subject here (over 900 bytes) so that the emacs
 # search results get large quickly. With 30 such messages we should
 # cross several 4kB page boundaries and see the bug.
index eaf7c980903bed112fc2df81f7af8c7307f1eda1..6e09a0486e802da77189bfaf9b5b5e1ca3e3aee8 100755 (executable)
@@ -2,6 +2,9 @@
 
 test_description="emacs: mail subject to filename"
 . $(dirname "$0")/test-lib.sh || exit 1
+. $(dirname "$0")/test-lib-emacs.sh || exit 1
+
+test_require_emacs
 
 # emacs server can't be started in a child process with $(test_emacs ...)
 test_emacs '(ignore)' > /dev/null
index 0aada4dfe7023a15384f121fb794f97126d9a30a..4508c984b94c7fcd77d3c88cd71bd69277cba87a 100755 (executable)
@@ -6,9 +6,11 @@
 
 test_description='PGP/MIME signature verification and decryption'
 . $(dirname "$0")/test-lib.sh || exit 1
+. $(dirname "$0")/test-lib-emacs.sh || exit 1
 
 ##################################################
 
+test_require_emacs
 add_gnupg_home
 
 test_begin_subtest "emacs delivery of signed message"
index 8b2b52be032a34ec539ee673ffa8fee23dc8dc3d..69bdcfac13b11fc9cad87c69a23abb549efd0ff8 100755 (executable)
@@ -2,7 +2,9 @@
 
 test_description='S/MIME signature verification and decryption'
 . $(dirname "$0")/test-lib.sh || exit 1
+. $(dirname "$0")/test-lib-emacs.sh || exit 1
 
+test_require_emacs
 test_require_external_prereq openssl
 test_require_external_prereq gpgsm
 
index 1951ef783a36bf0d3d17cfd4d82420d207574b48..0d30e566ec97fa55b9a60c418c76b70fab3bcef2 100755 (executable)
@@ -4,9 +4,11 @@
 
 test_description='indexing decrypted mail'
 . $(dirname "$0")/test-lib.sh || exit 1
+. $(dirname "$0")/test-lib-emacs.sh || exit 1
 
 ##################################################
 
+test_require_emacs
 add_gnupg_home
 
 # create a test encrypted message
index bca78531af616f9258fef8efc964264def92d71a..b25d7ea79e4626950b89fcb2893da195d9f3da92 100755 (executable)
@@ -2,8 +2,10 @@
 
 test_description="protected headers in emacs interface"
 . $(dirname "$0")/test-lib.sh || exit 1
+. $(dirname "$0")/test-lib-emacs.sh || exit 1
 
 # testing protected headers with emacs
+test_require_emacs
 add_gnupg_home
 add_email_corpus protected-headers
 
index a0b76eb89ca1ba1da02c861a39f1e280105dbaf6..597330d3a1c2fbd92468afb3c98fae800ad814d1 100755 (executable)
@@ -8,95 +8,61 @@ fi
 
 add_email_corpus
 
+test_ruby() {
+    (
+       cat <<-EOF
+       require 'notmuch'
+       db = Notmuch::Database.new('$MAIL_DIR')
+       EOF
+       cat
+    ) | $NOTMUCH_RUBY -I "$NOTMUCH_BUILDDIR/bindings/ruby"> OUTPUT
+    test_expect_equal_file EXPECTED OUTPUT
+}
+
 test_begin_subtest "compare thread ids"
+notmuch search --sort=oldest-first --output=threads tag:inbox > EXPECTED
 test_ruby <<"EOF"
-require 'notmuch'
-$maildir = ENV['MAIL_DIR']
-if not $maildir then
-  abort('environment variable MAIL_DIR must be set')
-end
-@db = Notmuch::Database.new($maildir)
-@q = @db.query('tag:inbox')
-@q.sort = Notmuch::SORT_OLDEST_FIRST
-for t in @q.search_threads do
-  print t.thread_id, "\n"
+q = db.query('tag:inbox')
+q.sort = Notmuch::SORT_OLDEST_FIRST
+q.search_threads.each do |t|
+  puts 'thread:%s' % t.thread_id
 end
 EOF
-notmuch search --sort=oldest-first --output=threads tag:inbox | sed s/^thread:// > EXPECTED
-test_expect_equal_file EXPECTED OUTPUT
 
 test_begin_subtest "compare message ids"
+notmuch search --sort=oldest-first --output=messages tag:inbox > EXPECTED
 test_ruby <<"EOF"
-require 'notmuch'
-$maildir = ENV['MAIL_DIR']
-if not $maildir then
-  abort('environment variable MAIL_DIR must be set')
-end
-@db = Notmuch::Database.new($maildir)
-@q = @db.query('tag:inbox')
-@q.sort = Notmuch::SORT_OLDEST_FIRST
-for m in @q.search_messages do
-  print m.message_id, "\n"
+q = db.query('tag:inbox')
+q.sort = Notmuch::SORT_OLDEST_FIRST
+q.search_messages.each do |m|
+  puts 'id:%s' % m.message_id
 end
 EOF
-notmuch search --sort=oldest-first --output=messages tag:inbox | sed s/^id:// > EXPECTED
-test_expect_equal_file EXPECTED OUTPUT
 
 test_begin_subtest "get non-existent file"
+echo nil > EXPECTED
 test_ruby <<"EOF"
-require 'notmuch'
-$maildir = ENV['MAIL_DIR']
-if not $maildir then
-  abort('environment variable MAIL_DIR must be set')
-end
-@db = Notmuch::Database.new($maildir)
-result = @db.find_message_by_filename('i-dont-exist')
-print (result == nil)
+p db.find_message_by_filename('i-dont-exist')
 EOF
-test_expect_equal "$(cat OUTPUT)" "true"
 
 test_begin_subtest "count messages"
+notmuch count --output=messages tag:inbox > EXPECTED
 test_ruby <<"EOF"
-require 'notmuch'
-$maildir = ENV['MAIL_DIR']
-if not $maildir then
-  abort('environment variable MAIL_DIR must be set')
-end
-@db = Notmuch::Database.new($maildir)
-@q = @db.query('tag:inbox')
-print @q.count_messages(),"\n"
+puts db.query('tag:inbox').count_messages()
 EOF
-notmuch count --output=messages tag:inbox > EXPECTED
-test_expect_equal_file EXPECTED OUTPUT
 
 test_begin_subtest "count threads"
+notmuch count --output=threads tag:inbox > EXPECTED
 test_ruby <<"EOF"
-require 'notmuch'
-$maildir = ENV['MAIL_DIR']
-if not $maildir then
-  abort('environment variable MAIL_DIR must be set')
-end
-@db = Notmuch::Database.new($maildir)
-@q = @db.query('tag:inbox')
-print @q.count_threads(),"\n"
+puts db.query('tag:inbox').count_threads()
 EOF
-notmuch count --output=threads tag:inbox > EXPECTED
-test_expect_equal_file EXPECTED OUTPUT
 
 test_begin_subtest "get all tags"
+notmuch search --output=tags '*' > EXPECTED
 test_ruby <<"EOF"
-require 'notmuch'
-$maildir = ENV['MAIL_DIR']
-if not $maildir then
-  abort('environment variable MAIL_DIR must be set')
-end
-@db = Notmuch::Database.new($maildir)
-@t = @db.all_tags()
-for tag in @t do
-   print tag,"\n"
+db.all_tags.each do |tag|
+  puts tag
 end
 EOF
-notmuch search --output=tags '*' > EXPECTED
-test_expect_equal_file EXPECTED OUTPUT
 
 test_done
index bfc10be3b7b5101ee213a620a0628962336f9e09..22e4f01effb52f98a0f93ceb2e27cc9279f7e802 100755 (executable)
@@ -2,6 +2,7 @@
 
 test_description="emacs test function sanity"
 . $(dirname "$0")/test-lib.sh || exit 1
+. $(dirname "$0")/test-lib-emacs.sh || exit 1
 
 test_begin_subtest "emacs test function sanity"
 test_emacs_expect_t 't'
index 02d3b4117b9407f8fed83330681e45ddfa6d9e13..640bff3fe0f1dadb6e975178db7abee2bdf84c20 100755 (executable)
@@ -2,6 +2,9 @@
 
 test_description="emacs address cleaning"
 . $(dirname "$0")/test-lib.sh || exit 1
+. $(dirname "$0")/test-lib-emacs.sh || exit 1
+
+test_require_emacs
 
 test_begin_subtest "notmuch-test-address-clean part 1"
 test_emacs_expect_t '(notmuch-test-address-cleaning-1)'
index d23c1fca9876bb656065fb7cd9ac77221ee071ca..642aa3cc3b677609c63d056afaec31dc391bfe86 100755 (executable)
@@ -2,9 +2,11 @@
 
 test_description="emacs notmuch-hello view"
 . $(dirname "$0")/test-lib.sh || exit 1
+. $(dirname "$0")/test-lib-emacs.sh || exit 1
 
 EXPECTED=$NOTMUCH_SRCDIR/test/emacs.expected-output
 
+test_require_emacs
 add_email_corpus
 
 test_begin_subtest "User-defined section with inbox tag"
index cca56ca32cd6875e6da4dbcd7b3b90932b3e3bef..e58124d45bcec99373d880b236e1a3f3c3b14349 100755 (executable)
@@ -2,9 +2,11 @@
 
 test_description="emacs notmuch-show view"
 . $(dirname "$0")/test-lib.sh || exit 1
+. $(dirname "$0")/test-lib-emacs.sh || exit 1
 
 EXPECTED=$NOTMUCH_SRCDIR/test/emacs-show.expected-output
 
+test_require_emacs
 add_email_corpus
 
 test_begin_subtest "Hiding Original Message region at beginning of a message"
index cb1297caa5dc3f1421c57de1bbeddea41dd3e194..a0f4dc24e3aa607abfe1f749e0c1f881f0e238d4 100755 (executable)
@@ -2,11 +2,14 @@
 
 test_description="emacs notmuch-show charset handling"
 . $(dirname "$0")/test-lib.sh || exit 1
+. $(dirname "$0")/test-lib-emacs.sh || exit 1
 
 
 UTF8_YEN=$'\xef\xbf\xa5'
 BIG5_YEN=$'\xa2\x44'
 
+test_require_emacs
+
 # Add four messages with unusual encoding requirements:
 #
 # 1) text/plain in quoted-printable big5
index cb2c90b80991ec4a1bf31529bc1f6e74493eefdd..dfc69049a0ac8414eefb58186761327d92891fad 100755 (executable)
@@ -2,9 +2,11 @@
 
 test_description="emacs tree view interface"
 . $(dirname "$0")/test-lib.sh || exit 1
+. $(dirname "$0")/test-lib-emacs.sh || exit 1
 
 EXPECTED=$NOTMUCH_SRCDIR/test/emacs-tree.expected-output
 
+test_require_emacs
 add_email_corpus
 
 test_begin_subtest "Basic notmuch-tree view in emacs"
index d1c70cfaf5d5fca98e66b9e1c6a2709f55fb7731..f89755ed0e42cfe7d87040f85410e77b8002adfd 100755 (executable)
@@ -4,13 +4,11 @@ test_description="date/time parser module"
 
 # Sanity/smoke tests for the date/time parser independent of notmuch
 
-_date ()
-{
+_date () {
     date -d "$*" +%s
 }
 
-_parse_time ()
-{
+_parse_time () {
     ${TEST_DIRECTORY}/parse-time --format=%s "$*"
 }
 
index 2859d29f37f7548c789e10c12311f406528b4bef..cdb4be444ab2dad529dab8e3a8947ce3f916eff6 100755 (executable)
@@ -10,6 +10,7 @@ test_description='test of proper handling of in-reply-to and references headers'
 # non-RFC-compliant headers'
 
 . $(dirname "$0")/test-lib.sh || exit 1
+. $(dirname "$0")/test-lib-emacs.sh || exit 1
 
 test_begin_subtest "Use References when In-Reply-To is broken"
 add_message '[id]="foo@one.com"' \
index aeb82cf4e3f300b10dfc80b9333fc18f433ce6ac..92a70e3eb12123d4ba5a947f794727cbb7d66899 100755 (executable)
@@ -21,7 +21,7 @@ test_description='thread breakage during reindexing'
 
 . $(dirname "$0")/test-lib.sh || exit 1
 
-message_a() {
+message_a () {
     mkdir -p ${MAIL_DIR}/cur
     cat > ${MAIL_DIR}/cur/a <<EOF
 Subject: First message
@@ -35,7 +35,7 @@ Apple
 EOF
 }
 
-message_b() {
+message_b () {
     mkdir -p ${MAIL_DIR}/cur
     cat > ${MAIL_DIR}/cur/b <<EOF
 Subject: Second message
@@ -52,19 +52,19 @@ EOF
 }
 
 
-test_content_count() {
+test_content_count () {
     test_begin_subtest "${3:-looking for $2 instance of '$1'}"
     count=$(notmuch count --output=threads "$1")
     test_expect_equal "$count" "$2"
 }
 
-test_thread_count() {
+test_thread_count () {
     test_begin_subtest "${2:-Expecting $1 thread(s)}"
     count=$(notmuch count --output=threads)
     test_expect_equal "$count" "$1"
 }
 
-test_ghost_count() {
+test_ghost_count () {
     test_begin_subtest "${2:-Expecting $1 ghosts(s)}"
     ghosts=$($NOTMUCH_BUILDDIR/test/ghost-report ${MAIL_DIR}/.notmuch/xapian)
     test_expect_equal "$ghosts" "$1"
index d7903ce799da7ac846fce8c50f0c521f70650adc..8553f022e4ade0bfa1999e01a759fc91624465e0 100755 (executable)
@@ -1,7 +1,9 @@
 #!/usr/bin/env bash
 test_description="Emacs Draft Handling"
 . $(dirname "$0")/test-lib.sh || exit 1
+. $(dirname "$0")/test-lib-emacs.sh || exit 1
 
+test_require_emacs
 add_email_corpus
 
 notmuch config set search.exclude_tags deleted
index c8d2bcc241a6b4f2141bb0001cf36bed80b12c70..4e8c5d260dcdf6be259475b81b1058192a27d572 100755 (executable)
@@ -2,6 +2,9 @@
 
 test_description="emacs attachment warnings"
 . $(dirname "$0")/test-lib.sh || exit 1
+. $(dirname "$0")/test-lib-emacs.sh || exit 1
+
+test_require_emacs
 
 test_begin_subtest "notmuch-test-attachment-warning part 1"
 test_emacs_expect_t '(notmuch-test-attachment-warning-1)'
index 45e61568ec62540b03094562dfb3aa1c0def08f8..378067edd5d6321148f17298dabe9b1c362c48f3 100755 (executable)
@@ -2,6 +2,9 @@
 
 test_description="emacs forwarding"
 . $(dirname "$0")/test-lib.sh || exit 1
+. $(dirname "$0")/test-lib-emacs.sh || exit 1
+
+test_require_emacs
 
 test_begin_subtest "Forward setting the correct references header"
 # Check that, when forwarding a message, the new message has
index 0578b1e50194d308d42f782556c951630a702bf1..0a048e1fe66940b914182c78400ad4dea8a8a94c 100644 (file)
@@ -9,8 +9,7 @@ if [[ -z "${NOTMUCH_SRCDIR}" ]]; then
        export NOTMUCH_SRCDIR="$(cd "$(dirname "$0")"/.. && pwd)"
 fi
 
-find_builddir()
-{
+find_builddir () {
        local dir="$1"
 
        while [[ -n "$dir" ]] && [[ "$dir" != "/" ]]; do
index 2f7950ac75b7b6c61777560bb933d847b9a7e3f7..ebbf4cdfa6fd2e727f78d651fdf31dcb8c3ead7d 100644 (file)
@@ -105,8 +105,7 @@ fi
 gen_msg_cnt=0
 gen_msg_filename=""
 gen_msg_id=""
-generate_message ()
-{
+generate_message () {
     # This is our (bash-specific) magic for doing named parameters
     local -A template="($@)"
     local additional_headers
@@ -225,8 +224,7 @@ EOF
 #
 # All of the arguments and return values supported by generate_message
 # are also supported here, so see that function for details.
-add_message ()
-{
+add_message () {
     generate_message "$@" &&
     notmuch new > /dev/null
 }
diff --git a/test/test-lib-emacs.sh b/test/test-lib-emacs.sh
new file mode 100644 (file)
index 0000000..dde3217
--- /dev/null
@@ -0,0 +1,209 @@
+#
+# Copyright (c) 2010-2020 Notmuch Developers
+#
+# 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 2 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 https://www.gnu.org/licenses/ .
+
+test_require_emacs () {
+    local ret=0
+    test_require_external_prereq "$TEST_EMACS" || ret=1
+    test_require_external_prereq "$TEST_EMACSCLIENT" || ret=1
+    test_require_external_prereq dtach || ret=1
+    return $ret
+}
+
+# Deliver a message with emacs and add it to the database
+#
+# Uses emacs to generate and deliver a message to the mail store.
+# Accepts arbitrary extra emacs/elisp functions to modify the message
+# before sending, which is useful to doing things like attaching files
+# to the message and encrypting/signing.
+emacs_deliver_message () {
+    local subject body smtp_dummy_pid smtp_dummy_port
+    subject="$1"
+    body="$2"
+    shift 2
+    # before we can send a message, we have to prepare the FCC maildir
+    mkdir -p "$MAIL_DIR"/sent/{cur,new,tmp}
+    # eval'ing smtp-dummy --background will set smtp_dummy_pid and -_port
+    smtp_dummy_pid= smtp_dummy_port=
+    eval `$TEST_DIRECTORY/smtp-dummy --background sent_message`
+    test -n "$smtp_dummy_pid" || return 1
+    test -n "$smtp_dummy_port" || return 1
+
+    test_emacs \
+       "(let ((message-send-mail-function 'message-smtpmail-send-it)
+              (mail-host-address \"example.com\")
+              (smtpmail-smtp-server \"localhost\")
+              (smtpmail-smtp-service \"${smtp_dummy_port}\"))
+          (notmuch-mua-mail)
+          (message-goto-to)
+          (insert \"test_suite@notmuchmail.org\nDate: 01 Jan 2000 12:00:00 -0000\")
+          (message-goto-subject)
+          (insert \"${subject}\")
+          (message-goto-body)
+          (insert \"${body}\")
+          $*
+          (notmuch-mua-send-and-exit))"
+
+    # In case message was sent properly, client waits for confirmation
+    # before exiting and resuming control here; therefore making sure
+    # that server exits by sending (KILL) signal to it is safe.
+    kill -9 $smtp_dummy_pid
+    notmuch new >/dev/null
+}
+
+# Pretend to deliver a message with emacs. Really save it to a file
+# and add it to the database
+#
+# Uses emacs to generate and deliver a message to the mail store.
+# Accepts arbitrary extra emacs/elisp functions to modify the message
+# before sending, which is useful to doing things like attaching files
+# to the message and encrypting/signing.
+#
+# If any GNU-style long-arguments (like --quiet or --decrypt=true) are
+# at the head of the argument list, they are sent directly to "notmuch
+# new" after message delivery
+emacs_fcc_message () {
+    local nmn_args subject body
+    nmn_args=''
+    while [[ "$1" =~ ^-- ]]; do
+       nmn_args="$nmn_args $1"
+       shift
+    done
+    subject="$1"
+    body="$2"
+    shift 2
+    # before we can send a message, we have to prepare the FCC maildir
+    mkdir -p "$MAIL_DIR"/sent/{cur,new,tmp}
+
+    test_emacs \
+       "(let ((message-send-mail-function (lambda () t))
+              (mail-host-address \"example.com\"))
+          (notmuch-mua-mail)
+          (message-goto-to)
+          (insert \"test_suite@notmuchmail.org\nDate: 01 Jan 2000 12:00:00 -0000\")
+          (message-goto-subject)
+          (insert \"${subject}\")
+          (message-goto-body)
+          (insert \"${body}\")
+          $*
+          (let ((mml-secure-smime-sign-with-sender t)
+                (mml-secure-openpgp-sign-with-sender t))
+            (notmuch-mua-send-and-exit)))" || return 1
+    notmuch new $nmn_args >/dev/null
+}
+
+test_emacs_expect_t () {
+       local result
+       test "$#" = 1 ||
+       error "bug in the test script: not 1 parameter to test_emacs_expect_t"
+       if [ -z "$inside_subtest" ]; then
+               error "bug in the test script: test_emacs_expect_t without test_begin_subtest"
+       fi
+
+       # Run the test.
+       if ! test_skip "$test_subtest_name"
+       then
+               test_emacs "(notmuch-test-run $1)" >/dev/null
+
+               # Restore state after the test.
+               exec 1>&6 2>&7          # Restore stdout and stderr
+               inside_subtest=
+
+               # test_emacs may update missing external prerequisites
+               test_check_missing_external_prereqs_ "$test_subtest_name" && return
+
+               # Report success/failure.
+               result=$(cat OUTPUT)
+               if [ "$result" = t ]
+               then
+                       test_ok_
+               else
+                       test_failure_ "${result}"
+               fi
+       else
+               # Restore state after the (non) test.
+               exec 1>&6 2>&7          # Restore stdout and stderr
+               inside_subtest=
+       fi
+}
+
+emacs_generate_script () {
+       # Construct a little test script here for the benefit of the user,
+       # (who can easily run "run_emacs" to get the same emacs environment
+       # for investigating any failures).
+       cat <<EOF >"$TMP_DIRECTORY/run_emacs"
+#!/bin/sh
+export PATH=$PATH
+export NOTMUCH_CONFIG=$NOTMUCH_CONFIG
+
+# Here's what we are using here:
+#
+# --quick              Use minimal customization. This implies --no-init-file,
+#                      --no-site-file and (emacs 24) --no-site-lisp
+#
+# --directory          Ensure that the local elisp sources are found
+#
+# --load               Force loading of notmuch.el and test-lib.el
+
+exec ${TEST_EMACS} --quick \
+       --directory "$NOTMUCH_BUILDDIR/emacs" --load notmuch.el \
+       --directory "$NOTMUCH_SRCDIR/test" --load test-lib.el \
+       "\$@"
+EOF
+       chmod a+x "$TMP_DIRECTORY/run_emacs"
+}
+
+test_emacs () {
+       # test dependencies beforehand to avoid the waiting loop below
+       test_require_emacs || return
+
+       if [ -z "$EMACS_SERVER" ]; then
+               emacs_tests="$NOTMUCH_SRCDIR/test/${this_test_bare}.el"
+               if [ -f "$emacs_tests" ]; then
+                       load_emacs_tests="--eval '(load \"$emacs_tests\")'"
+               else
+                       load_emacs_tests=
+               fi
+               server_name="notmuch-test-suite-$$"
+               # start a detached session with an emacs server
+               # user's TERM (or 'vt100' in case user's TERM is known dumb
+               # or unknown) is given to dtach which assumes a minimally
+               # VT100-compatible terminal -- and emacs inherits that
+               TERM=$SMART_TERM dtach -n "$TEST_TMPDIR/emacs-dtach-socket.$$" \
+                       sh -c "stty rows 24 cols 80; exec '$TMP_DIRECTORY/run_emacs' \
+                               --no-window-system \
+                               $load_emacs_tests \
+                               --eval '(setq server-name \"$server_name\")' \
+                               --eval '(server-start)' \
+                               --eval '(orphan-watchdog $$)'" || return
+               EMACS_SERVER="$server_name"
+               # wait until the emacs server is up
+               until test_emacs '()' >/dev/null 2>/dev/null; do
+                       sleep 1
+               done
+       fi
+
+       # Clear test-output output file.  Most Emacs tests end with a
+       # call to (test-output).  If the test code fails with an
+       # exception before this call, the output file won't get
+       # updated.  Since we don't want to compare against an output
+       # file from another test, so start out with an empty file.
+       rm -f OUTPUT
+       touch OUTPUT
+
+       ${TEST_EMACSCLIENT} --socket-name="$EMACS_SERVER" --eval "(notmuch-test-progn $*)"
+}
+
+emacs_generate_script
index 4c9f2a2103e32a18c2c14dc257669300ecbe4d6f..89eb744da6f253457d52ac6194b488fe27dc4b90 100644 (file)
@@ -112,9 +112,9 @@ unset ALTERNATE_EDITOR
 
 # for reproducibility
 unset EMAIL
+unset NAME
 
-add_gnupg_home ()
-{
+add_gnupg_home () {
     [ -e "${GNUPGHOME}/gpg.conf" ] && return
     _gnupg_exit () { gpgconf --kill all 2>/dev/null || true; }
     at_exit_function _gnupg_exit
@@ -134,8 +134,7 @@ add_gnupg_home ()
     printf '%s:6:\n' "$FINGERPRINT" | gpg --quiet --batch --no-tty --import-ownertrust
 }
 
-add_gpgsm_home ()
-{
+add_gpgsm_home () {
     local fpr
     [ -e "$GNUPGHOME/gpgsm.conf" ] && return
     _gnupg_exit () { gpgconf --kill all 2>/dev/null || true; }
@@ -267,8 +266,7 @@ then
 fi
 
 test_description_printed=
-print_test_description ()
-{
+print_test_description () {
        test -z "$test_description_printed" || return 0
        echo
        echo $this_test: "Testing ${test_description}"
@@ -342,90 +340,6 @@ export GNUPGHOME="${TEST_TMPDIR}/gnupg"
 trap 'trap_exit' EXIT
 trap 'trap_signal' HUP INT TERM
 
-# Deliver a message with emacs and add it to the database
-#
-# Uses emacs to generate and deliver a message to the mail store.
-# Accepts arbitrary extra emacs/elisp functions to modify the message
-# before sending, which is useful to doing things like attaching files
-# to the message and encrypting/signing.
-emacs_deliver_message ()
-{
-    local subject body smtp_dummy_pid smtp_dummy_port
-    subject="$1"
-    body="$2"
-    shift 2
-    # before we can send a message, we have to prepare the FCC maildir
-    mkdir -p "$MAIL_DIR"/sent/{cur,new,tmp}
-    # eval'ing smtp-dummy --background will set smtp_dummy_pid and -_port
-    smtp_dummy_pid= smtp_dummy_port=
-    eval `$TEST_DIRECTORY/smtp-dummy --background sent_message`
-    test -n "$smtp_dummy_pid" || return 1
-    test -n "$smtp_dummy_port" || return 1
-
-    test_emacs \
-       "(let ((message-send-mail-function 'message-smtpmail-send-it)
-              (mail-host-address \"example.com\")
-              (smtpmail-smtp-server \"localhost\")
-              (smtpmail-smtp-service \"${smtp_dummy_port}\"))
-          (notmuch-mua-mail)
-          (message-goto-to)
-          (insert \"test_suite@notmuchmail.org\nDate: 01 Jan 2000 12:00:00 -0000\")
-          (message-goto-subject)
-          (insert \"${subject}\")
-          (message-goto-body)
-          (insert \"${body}\")
-          $*
-          (notmuch-mua-send-and-exit))"
-
-    # In case message was sent properly, client waits for confirmation
-    # before exiting and resuming control here; therefore making sure
-    # that server exits by sending (KILL) signal to it is safe.
-    kill -9 $smtp_dummy_pid
-    notmuch new >/dev/null
-}
-
-# Pretend to deliver a message with emacs. Really save it to a file
-# and add it to the database
-#
-# Uses emacs to generate and deliver a message to the mail store.
-# Accepts arbitrary extra emacs/elisp functions to modify the message
-# before sending, which is useful to doing things like attaching files
-# to the message and encrypting/signing.
-#
-# If any GNU-style long-arguments (like --quiet or --decrypt=true) are
-# at the head of the argument list, they are sent directly to "notmuch
-# new" after message delivery
-emacs_fcc_message ()
-{
-    local nmn_args subject body
-    nmn_args=''
-    while [[ "$1" =~ ^-- ]]; do
-       nmn_args="$nmn_args $1"
-       shift
-    done
-    subject="$1"
-    body="$2"
-    shift 2
-    # before we can send a message, we have to prepare the FCC maildir
-    mkdir -p "$MAIL_DIR"/sent/{cur,new,tmp}
-
-    test_emacs \
-       "(let ((message-send-mail-function (lambda () t))
-              (mail-host-address \"example.com\"))
-          (notmuch-mua-mail)
-          (message-goto-to)
-          (insert \"test_suite@notmuchmail.org\nDate: 01 Jan 2000 12:00:00 -0000\")
-          (message-goto-subject)
-          (insert \"${subject}\")
-          (message-goto-body)
-          (insert \"${body}\")
-          $*
-          (let ((mml-secure-smime-sign-with-sender t)
-                (mml-secure-openpgp-sign-with-sender t))
-            (notmuch-mua-send-and-exit)))" || return 1
-    notmuch new $nmn_args >/dev/null
-}
-
 # Add an existing, fixed corpus of email to the database.
 #
 # $1 is the corpus dir under corpora to add, using "default" if unset.
@@ -434,8 +348,7 @@ emacs_fcc_message ()
 # history of the notmuch mailing list, which allows for reliably
 # testing commands that need to operate on a not-totally-trivial
 # number of messages.
-add_email_corpus ()
-{
+add_email_corpus () {
     local corpus
     corpus=${1:-default}
 
@@ -444,8 +357,7 @@ add_email_corpus ()
     notmuch new >/dev/null || die "'notmuch new' failed while adding email corpus"
 }
 
-test_begin_subtest ()
-{
+test_begin_subtest () {
     if [ -n "$inside_subtest" ]; then
        exec 1>&6 2>&7          # Restore stdout and stderr
        error "bug in test script: Missing test_expect_equal in ${BASH_SOURCE[1]}:${BASH_LINENO[0]}"
@@ -465,8 +377,7 @@ test_begin_subtest ()
 # not accept a test name. Instead, the caller should call
 # test_begin_subtest before calling this function in order to set the
 # name.
-test_expect_equal ()
-{
+test_expect_equal () {
        local output expected testname
        exec 1>&6 2>&7          # Restore stdout and stderr
        if [ -z "$inside_subtest" ]; then
@@ -492,8 +403,7 @@ test_expect_equal ()
 }
 
 # Like test_expect_equal, but takes two filenames.
-test_expect_equal_file ()
-{
+test_expect_equal_file () {
        local file1 file2 testname basename1 basename2
        exec 1>&6 2>&7          # Restore stdout and stderr
        if [ -z "$inside_subtest" ]; then
@@ -574,51 +484,16 @@ test_json_nodes () {
        fi
 }
 
-test_emacs_expect_t () {
-       local result
-       test "$#" = 1 ||
-       error "bug in the test script: not 1 parameter to test_emacs_expect_t"
-       if [ -z "$inside_subtest" ]; then
-               error "bug in the test script: test_emacs_expect_t without test_begin_subtest"
-       fi
-
-       # Run the test.
-       if ! test_skip "$test_subtest_name"
-       then
-               test_emacs "(notmuch-test-run $1)" >/dev/null
-
-               # Restore state after the test.
-               exec 1>&6 2>&7          # Restore stdout and stderr
-               inside_subtest=
-
-               # Report success/failure.
-               result=$(cat OUTPUT)
-               if [ "$result" = t ]
-               then
-                       test_ok_
-               else
-                       test_failure_ "${result}"
-               fi
-       else
-               # Restore state after the (non) test.
-               exec 1>&6 2>&7          # Restore stdout and stderr
-               inside_subtest=
-       fi
-}
-
-NOTMUCH_NEW ()
-{
+NOTMUCH_NEW () {
     notmuch new "${@}" | grep -v -E -e '^Processed [0-9]*( total)? file|Found [0-9]* total file'
 }
 
-NOTMUCH_DUMP_TAGS ()
-{
+NOTMUCH_DUMP_TAGS () {
     # this relies on the default format being batch-tag, otherwise some tests will break
     notmuch dump --include=tags "${@}" | sed '/^#/d' | sort
 }
 
-notmuch_drop_mail_headers ()
-{
+notmuch_drop_mail_headers () {
     $NOTMUCH_PYTHON -c '
 import email, sys
 msg = email.message_from_file(sys.stdin)
@@ -627,41 +502,34 @@ print(msg.as_string(False))
 ' "$@"
 }
 
-notmuch_exception_sanitize ()
-{
+notmuch_exception_sanitize () {
     perl -pe 's/(A Xapian exception occurred at .*[.]cc?):([0-9]*)/\1:XXX/'
 }
 
-notmuch_search_sanitize ()
-{
+notmuch_search_sanitize () {
     perl -pe 's/("?thread"?: ?)("?)................("?)/\1\2XXX\3/'
 }
 
-notmuch_search_files_sanitize ()
-{
+notmuch_search_files_sanitize () {
     notmuch_dir_sanitize
 }
 
-notmuch_dir_sanitize ()
-{
+notmuch_dir_sanitize () {
     sed -e "s,$MAIL_DIR,MAIL_DIR," -e "s,${PWD},CWD,g" "$@"
 }
 
 NOTMUCH_SHOW_FILENAME_SQUELCH='s,filename:.*/mail,filename:/XXX/mail,'
-notmuch_show_sanitize ()
-{
+notmuch_show_sanitize () {
     sed -e "$NOTMUCH_SHOW_FILENAME_SQUELCH"
 }
-notmuch_show_sanitize_all ()
-{
+notmuch_show_sanitize_all () {
     sed \
        -e 's| filename:.*| filename:XXXXX|' \
        -e 's| id:[^ ]* | id:XXXXX |' | \
        notmuch_date_sanitize
 }
 
-notmuch_json_show_sanitize ()
-{
+notmuch_json_show_sanitize () {
     sed \
        -e 's|"id": "[^"]*",|"id": "XXXXX",|g' \
        -e 's|"Date": "Fri, 05 Jan 2001 [^"]*0000"|"Date": "GENERATED_DATE"|g' \
@@ -671,8 +539,7 @@ notmuch_json_show_sanitize ()
        -e 's|"content-length": [1-9][0-9]*|"content-length": "NONZERO"|g'
 }
 
-notmuch_emacs_error_sanitize ()
-{
+notmuch_emacs_error_sanitize () {
     local command
     command=$1
     shift
@@ -684,45 +551,44 @@ notmuch_emacs_error_sanitize ()
        -e "s|^\(command: \)\{0,1\}/.*/$command|\1YYY/$command|"
 }
 
-notmuch_date_sanitize ()
-{
+notmuch_date_sanitize () {
     sed \
        -e 's/^Date: Fri, 05 Jan 2001 .*0000/Date: GENERATED_DATE/'
 }
 
-notmuch_uuid_sanitize ()
-{
+notmuch_uuid_sanitize () {
     sed 's/[0-9a-f]\{8\}-[0-9a-f]\{4\}-[0-9a-f]\{4\}-[0-9a-f]\{4\}-[0-9a-f]\{12\}/UUID/g'
 }
 
-notmuch_built_with_sanitize ()
-{
+notmuch_built_with_sanitize () {
     sed 's/^built_with[.]\(.*\)=.*$/built_with.\1=something/'
 }
 
-notmuch_passwd_sanitize()
-{
+notmuch_passwd_sanitize () {
     ${NOTMUCH_PYTHON} -c'
 import os, sys, pwd, socket
 
 pw = pwd.getpwuid(os.getuid())
 user = pw.pw_name
 name = pw.pw_gecos.partition(",")[0]
-fqdn = socket.getfqdn()
+fqdn = socket.getaddrinfo(socket.gethostname(), 0, 0, socket.SOCK_STREAM, 0, socket.AI_CANONNAME)[0][3]
 
 for l in sys.stdin:
-    l = l.replace(user, "USERNAME").replace(fqdn, "FQDN").replace(".(none)","").replace(name, "USER_FULL_NAME")
+    if user:
+        l = l.replace(user, "USERNAME")
+    if fqdn:
+        l = l.replace(fqdn, "FQDN").replace(".(none)","")
+    if name:
+        l = l.replace(name, "USER_FULL_NAME")
     sys.stdout.write(l)
 '
 }
 
-notmuch_config_sanitize ()
-{
+notmuch_config_sanitize () {
     notmuch_dir_sanitize | notmuch_built_with_sanitize
 }
 
-notmuch_show_part ()
-{
+notmuch_show_part () {
     awk '/^\014part}/{ f=0 }; { if (f) { print $0 } } /^\014part{ ID: '"$1"'/{ f=1 }'
 }
 
@@ -913,7 +779,7 @@ test_expect_success () {
                test_run_ "$1"
                run_ret="$?"
                # test_run_ may update missing external prerequisites
-               test_check_missing_external_prereqs_ "$@" ||
+               test_check_missing_external_prereqs_ "$test_subtest_name" ||
                if [ "$run_ret" = 0 -a "$eval_ret" = 0 ]
                then
                        test_ok_
@@ -937,7 +803,7 @@ test_expect_code () {
                test_run_ "$2"
                run_ret="$?"
                # test_run_ may update missing external prerequisites,
-               test_check_missing_external_prereqs_ "$@" ||
+               test_check_missing_external_prereqs_ "$test_subtest_name" ||
                if [ "$run_ret" = 0 -a "$eval_ret" = "$1" ]
                then
                        test_ok_
@@ -977,7 +843,7 @@ test_must_fail () {
 # - cmp's output is not nearly as easy to read as diff -u
 # - not all diff versions understand "-u"
 
-test_cmp() {
+test_cmp () {
        $GIT_TEST_CMP "$@"
 }
 
@@ -1031,88 +897,13 @@ test_done () {
        fi
 }
 
-emacs_generate_script () {
-       # Construct a little test script here for the benefit of the user,
-       # (who can easily run "run_emacs" to get the same emacs environment
-       # for investigating any failures).
-       cat <<EOF >"$TMP_DIRECTORY/run_emacs"
-#!/bin/sh
-export PATH=$PATH
-export NOTMUCH_CONFIG=$NOTMUCH_CONFIG
-
-# Here's what we are using here:
-#
-# --quick              Use minimal customization. This implies --no-init-file,
-#                      --no-site-file and (emacs 24) --no-site-lisp
-#
-# --directory          Ensure that the local elisp sources are found
-#
-# --load               Force loading of notmuch.el and test-lib.el
-
-exec ${TEST_EMACS} --quick \
-       --directory "$NOTMUCH_BUILDDIR/emacs" --load notmuch.el \
-       --directory "$NOTMUCH_SRCDIR/test" --load test-lib.el \
-       "\$@"
-EOF
-       chmod a+x "$TMP_DIRECTORY/run_emacs"
-}
-
-test_emacs () {
-       # test dependencies beforehand to avoid the waiting loop below
-       missing_dependencies=
-       test_require_external_prereq dtach || missing_dependencies=1
-       test_require_external_prereq emacs || missing_dependencies=1
-       test_require_external_prereq ${TEST_EMACSCLIENT} || missing_dependencies=1
-       test -z "$missing_dependencies" || return
-
-       if [ -z "$EMACS_SERVER" ]; then
-               emacs_tests="$NOTMUCH_SRCDIR/test/${this_test_bare}.el"
-               if [ -f "$emacs_tests" ]; then
-                       load_emacs_tests="--eval '(load \"$emacs_tests\")'"
-               else
-                       load_emacs_tests=
-               fi
-               server_name="notmuch-test-suite-$$"
-               # start a detached session with an emacs server
-               # user's TERM (or 'vt100' in case user's TERM is known dumb
-               # or unknown) is given to dtach which assumes a minimally
-               # VT100-compatible terminal -- and emacs inherits that
-               TERM=$SMART_TERM dtach -n "$TEST_TMPDIR/emacs-dtach-socket.$$" \
-                       sh -c "stty rows 24 cols 80; exec '$TMP_DIRECTORY/run_emacs' \
-                               --no-window-system \
-                               $load_emacs_tests \
-                               --eval '(setq server-name \"$server_name\")' \
-                               --eval '(server-start)' \
-                               --eval '(orphan-watchdog $$)'" || return
-               EMACS_SERVER="$server_name"
-               # wait until the emacs server is up
-               until test_emacs '()' >/dev/null 2>/dev/null; do
-                       sleep 1
-               done
-       fi
-
-       # Clear test-output output file.  Most Emacs tests end with a
-       # call to (test-output).  If the test code fails with an
-       # exception before this call, the output file won't get
-       # updated.  Since we don't want to compare against an output
-       # file from another test, so start out with an empty file.
-       rm -f OUTPUT
-       touch OUTPUT
-
-       ${TEST_EMACSCLIENT} --socket-name="$EMACS_SERVER" --eval "(notmuch-test-progn $*)"
-}
-
-test_python() {
+test_python () {
     # Note: if there is need to print debug information from python program,
     # use stdout = os.fdopen(6, 'w') or stderr = os.fdopen(7, 'w')
     PYTHONPATH="$NOTMUCH_SRCDIR/bindings/python${PYTHONPATH:+:$PYTHONPATH}" \
        $NOTMUCH_PYTHON -B - > OUTPUT
 }
 
-test_ruby() {
-    MAIL_DIR=$MAIL_DIR $NOTMUCH_RUBY -I "$NOTMUCH_BUILDDIR/bindings/ruby"> OUTPUT
-}
-
 test_C () {
     local exec_file test_file
     exec_file="test${test_count}"
@@ -1195,9 +986,6 @@ TEST_DIRECTORY=$NOTMUCH_BUILDDIR/test
 
 . "$NOTMUCH_SRCDIR/test/test-lib-common.sh" || exit 1
 
-emacs_generate_script
-
-
 # Use -P to resolve symlinks in our working directory so that the cwd
 # in subprocesses like git equals our $PWD (for pathname comparisons).
 cd -P "$TMP_DIRECTORY" || error "Cannot set up test environment"
index 541698cdfee7939e05aa3554ff39c91295920940..c1c2f63d20178dab69f92c9ff9aab4631dda6ee5 100644 (file)
@@ -317,6 +317,9 @@ ruby << EOF
        $curbuf.render do |b|
                q = $curbuf.query(get_cur_view)
                q.sort = Notmuch::SORT_OLDEST_FIRST
+               $exclude_tags.each { |t|
+                       q.add_tag_exclude(t)
+               }
                msgs = q.search_messages
                msgs.each do |msg|
                        m = Mail.read(msg.filename)