[PATCH v2] NEWS: Document the recent 'nmbug clone' and @{upstream} changes

2014-04-16 Thread Tomi Ollila
On Wed, Apr 16 2014, "W. Trevor King"  wrote:

> The changes landed with c200167 (nmbug: Add 'clone' and replace
> FETCH_HEAD with @{upstream}, 2014-03-09).
>
> The preferred markup language for NEWS seems to be Markdown, which is
> parsed by devel/news2wiki.pl into Markdown chunks for rendering by
> ikiwiki [1].
>
> [1]: http://notmuchmail.org/news/
> ---

LGTM (source $ news2wiki.pl-generated mdwn).

> Changes since v1 [1]:
>
> * Use HTTP (instead of the Git protocol) for the remote URL [2].
> * Remove ?bare? from the text motivating a fresh clone.
>   Replace it with a reference to remote-tracking branches [2,3].
> * Elaborate on the local-commit-backup step (step 1) [4].
>
> [1]: id:151b4a1b9612daa53fb47b60f0aa65f7a8e5ef5e.1396972599.git.wking at 
> tremily.us
>  http://thread.gmane.org/gmane.mail.notmuch.general/17457/focus=17812
> [2]: id:20140409210108.GB21805 at odin.tremily.us
>  http://article.gmane.org/gmane.mail.notmuch.general/17817
> [3]: id:87bnw2wcwq.fsf at zancas.localnet
>  http://article.gmane.org/gmane.mail.notmuch.general/17885
> [4]: id:20140410020559.GC21805 at odin.tremily.us
>  http://article.gmane.org/gmane.mail.notmuch.general/17819
>
>  NEWS | 22 ++
>  1 file changed, 22 insertions(+)
>
> diff --git a/NEWS b/NEWS
> index d4f4ea4..630607f 100644
> --- a/NEWS
> +++ b/NEWS
> @@ -20,6 +20,28 @@ Bug fix for saved searches with newlines in them.
>Split lines confuse `notmuch count --batch`, so we remove embedded
>newlines before calling notmuch count.
>  
> +nmbug
> +-
> +
> +nmbug adds a `clone` command for setting up the initial repository and
> +uses `@{upstream}` instead of `FETCH_HEAD` to track upstream changes.
> +
> +  The `@{upstream}` change reduces ambiguity when fetching multiple
> +  branches, but requires existing users update their `NMBGIT`
> +  repository (usually `~/.nmbug`) to distinguish between local and
> +  remote-tracking branches.  The easiest way to do this is:
> +
> +  1. If you have any purely local commits (i.e. they aren't in the
> + nmbug repository on nmbug.tethera.net), push them to a remote
> + repository.  We'll restore them from the backup in step 4.
> +  2. Remove your `NMBGIT` repository (e.g. `mv .nmbug .nmbug.bak`).
> +  3. Use the new `clone` command to create a fresh clone:
> +
> +nmbug clone http://nmbug.tethera.net/git/nmbug-tags.git
> +
> +  4. If you had local commits in step 1, add a remote for that
> + repository and fetch them into the new repository.
> +
>  Notmuch 0.17 (2013-12-30)
>  =
>  
> -- 
> 1.9.1.353.gc66d89d
>
> ___
> notmuch mailing list
> notmuch at notmuchmail.org
> http://notmuchmail.org/mailman/listinfo/notmuch


[PATCH v2 10/10] man: update insert documentation

2014-04-16 Thread Peter Wang
Add documentation for the insert --must-index option
and failure exit codes.
---
 doc/man1/notmuch-insert.rst | 24 ++--
 1 file changed, 18 insertions(+), 6 deletions(-)

diff --git a/doc/man1/notmuch-insert.rst b/doc/man1/notmuch-insert.rst
index 2be1a7b..02c516b 100644
--- a/doc/man1/notmuch-insert.rst
+++ b/doc/man1/notmuch-insert.rst
@@ -38,16 +38,28 @@ Supported options for **insert** include
 does not exist. Otherwise the folder must already exist for mail
 delivery to succeed.

+``--must-index``
+Succeed only if the message is written to disk, added to the
+notmuch database, and tagged (unless a duplicate message).
+Failure to synchronize tags to maildir flags has no effect.
+Without this option, **insert** succeeds as long as the message
+is written to disk.
+
 EXIT STATUS
 ===

-This command returns exit status 0 if the message was successfully added
-to the mail directory, even if the message could not be indexed and
-added to the notmuch database. In the latter case, a warning will be
-printed to standard error but the message file will be left on disk.
+This command returns exit status 0 on success. On failure, it returns a
+non-zero exit status:
+
+1
+General failure code.
+
+2
+Failed to write the message to disk.

-If the message could not be written to disk then a non-zero exit status
-is returned.
+3
+Failed to index or tag the message (unless a duplicate message),
+and ``--must-index`` was specified.

 SEE ALSO
 
-- 
1.8.4



[PATCH v2 09/10] test: test insert --must-index

2014-04-16 Thread Peter Wang
Test the insert --must-index option.
---
 test/T070-insert.sh | 28 +---
 1 file changed, 25 insertions(+), 3 deletions(-)

diff --git a/test/T070-insert.sh b/test/T070-insert.sh
index c576efc..4e289c0 100755
--- a/test/T070-insert.sh
+++ b/test/T070-insert.sh
@@ -21,11 +21,20 @@ gen_insert_msg() {
 test_expect_code 2 "Insert zero-length file" \
 "notmuch insert < /dev/null"

-# This test is a proxy for other errors that may occur while trying to
-# add a message to the notmuch database, e.g. database locked.
-test_expect_code 0 "Insert non-message" \
+test_expect_code 3 "Insert non-message with --must-index on" \
+"echo bad_message | notmuch insert --must-index"
+
+test_begin_subtest "Non-message file should not exist"
+output=$(find "${MAIL_DIR}/cur" "${MAIL_DIR}/new" "${MAIL_DIR}/tmp" -type f 
-print | wc -l)
+test_expect_equal "$output" "0"
+
+test_expect_code 0 "Insert non-message with --must-index off" \
 "echo bad_message | notmuch insert"

+test_begin_subtest "Non-message file should exist"
+output=$(find "${MAIL_DIR}/cur" "${MAIL_DIR}/new" "${MAIL_DIR}/tmp" -type f 
-print | wc -l)
+test_expect_equal "$output" "1"
+
 test_begin_subtest "Database empty so far"
 test_expect_equal "0" "`notmuch count --output=messages '*'`"

@@ -77,6 +86,19 @@ notmuch insert +custom -unread < "$gen_msg_filename"
 output=$(notmuch search --output=messages tag:custom NOT tag:unread)
 test_expect_equal "$output" "id:$gen_msg_id"

+# overlongtag exceeds NOTMUCH_TAG_MAX
+ten=0123456789
+hundred=${ten}${ten}${ten}${ten}${ten}${ten}${ten}${ten}${ten}${ten}
+overlongtag=x${hundred}${hundred}
+gen_insert_msg
+test_expect_code 3 "Tagging fails with --must-index on" \
+"notmuch insert --must-index +$overlongtag < $gen_msg_filename"
+
+test_begin_subtest "Tagging fails with --must-index off"
+notmuch insert +$overlongtag < "$gen_msg_filename"
+output=$(notmuch search --output=messages id:$gen_msg_id)
+test_expect_equal "$output" "id:$gen_msg_id"
+
 test_begin_subtest "Insert message with default tags stays in new/"
 gen_insert_msg
 notmuch insert < "$gen_msg_filename"
-- 
1.8.4



[PATCH v2 08/10] cli: add insert --must-index option

2014-04-16 Thread Peter Wang
This option causes notmuch insert to fail (with exit code 3) on failure
to index the message, or failure to set the tags on the message, or if
closing (flushing) the database fails.  Failure to sync tags to flags
has no effect.
---
 notmuch-insert.c | 57 +++-
 1 file changed, 40 insertions(+), 17 deletions(-)

diff --git a/notmuch-insert.c b/notmuch-insert.c
index 29d82c9..83257f4 100644
--- a/notmuch-insert.c
+++ b/notmuch-insert.c
@@ -31,7 +31,8 @@
 enum {
 INSERT_EXIT_SUCCESS = 0,
 INSERT_EXIT_FAILURE = 1,
-INSERT_EXIT_FAILED_WRITE = 2
+INSERT_EXIT_FAILED_WRITE = 2,
+INSERT_EXIT_FAILED_INDEX = 3
 };

 static volatile sig_atomic_t interrupted;
@@ -298,13 +299,15 @@ copy_stdin (int fdin, int fdout)
 }

 /* Add the specified message file to the notmuch database, applying tags.
- * The file is renamed to encode notmuch tags as maildir flags. */
-static void
+ * If synchronize_flags is set then file is renamed to encode notmuch tags as
+ * maildir flags. */
+static notmuch_bool_t
 add_file_to_database (notmuch_database_t *notmuch, const char *path,
  tag_op_list_t *tag_ops, notmuch_bool_t synchronize_flags)
 {
 notmuch_message_t *message;
 notmuch_status_t status;
+notmuch_status_t sync;

 status = notmuch_database_add_message (notmuch, path, &message);
 switch (status) {
@@ -324,23 +327,28 @@ add_file_to_database (notmuch_database_t *notmuch, const 
char *path,
 case NOTMUCH_STATUS_LAST_STATUS:
fprintf (stderr, "Error: failed to add `%s' to notmuch database: %s\n",
 path, notmuch_status_to_string (status));
-   return;
+   return FALSE;
 }

 if (status == NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID) {
/* Don't change tags of an existing message. */
-   if (synchronize_flags) {
-   status = notmuch_message_tags_to_maildir_flags (message);
-   if (status != NOTMUCH_STATUS_SUCCESS)
-   fprintf (stderr, "Error: failed to sync tags to maildir 
flags\n");
-   }
+   status = NOTMUCH_STATUS_SUCCESS;
 } else {
-   tag_op_flag_t flags = synchronize_flags ? TAG_FLAG_MAILDIR_SYNC : 0;
+   status = tag_op_list_apply (message, tag_ops, 0);
+}

-   tag_op_list_apply (message, tag_ops, flags);
+/* Call notmuch_message_tags_to_maildir_flags directly instead of doing it
+ * as part of tag_op_list_apply. For --must-index we want to succeed if
+ * tagging succeeds, but disregard whether synchronizing flags fails. */
+if (status == NOTMUCH_STATUS_SUCCESS && synchronize_flags) {
+   sync = notmuch_message_tags_to_maildir_flags (message);
+   if (sync != NOTMUCH_STATUS_SUCCESS)
+   fprintf (stderr, "Error: failed to sync tags to maildir flags\n");
 }

 notmuch_message_destroy (message);
+
+return (status == NOTMUCH_STATUS_SUCCESS);
 }

 static notmuch_bool_t
@@ -400,15 +408,19 @@ notmuch_insert_command (notmuch_config_t *config, int 
argc, char *argv[])
 char *query_string = NULL;
 const char *folder = NULL;
 notmuch_bool_t create_folder = FALSE;
+notmuch_bool_t must_index = FALSE;
 notmuch_bool_t synchronize_flags;
 const char *maildir;
 char *newpath;
 int opt_index;
 unsigned int i;
+notmuch_bool_t indexed;
+notmuch_status_t status;

 notmuch_opt_desc_t options[] = {
{ NOTMUCH_OPT_STRING, &folder, "folder", 0, 0 },
{ NOTMUCH_OPT_BOOLEAN, &create_folder, "create-folder", 0, 0 },
+   { NOTMUCH_OPT_BOOLEAN, &must_index, "must-index", 0, 0 },
{ NOTMUCH_OPT_END, 0, 0, 0, 0 }
 };

@@ -485,12 +497,23 @@ notmuch_insert_command (notmuch_config_t *config, int 
argc, char *argv[])
return INSERT_EXIT_FAILED_WRITE;
 }

-/* Add the message to the index.
- * Even if adding the message to the notmuch database fails,
- * the message is on disk and we consider the delivery completed. */
-add_file_to_database (notmuch, newpath, tag_ops,
+/* Add the message to the index. */
+indexed = add_file_to_database (notmuch, newpath, tag_ops,
synchronize_flags);

-notmuch_database_destroy (notmuch);
-return INSERT_EXIT_SUCCESS;
+/* If must_index is FALSE then succeed as the message is on disk.
+ * Otherwise message indexing and tagging must succeed, and the database
+ * must be flushed. Don't flush the database if there was an earlier
+ * error, so as to abandon the transaction (is there a better way?) */
+if (! must_index) {
+   notmuch_database_destroy (notmuch);
+   return INSERT_EXIT_SUCCESS;
+}
+if (indexed) {
+   status = notmuch_database_destroy (notmuch);
+   if (status == NOTMUCH_STATUS_SUCCESS)
+   return INSERT_EXIT_SUCCESS;
+}
+unlink (newpath);
+return INSERT_EXIT_FAILED_INDEX;
 }
-- 
1.8.4



[PATCH v2 07/10] cli: indicate insert failure mode in exit status

2014-04-16 Thread Peter Wang
Make insert return a different exit code, 2, for failure to write the
message file to disk, and exit code 1 for other errors.
---
 notmuch-insert.c| 30 ++
 test/T070-insert.sh |  4 ++--
 2 files changed, 20 insertions(+), 14 deletions(-)

diff --git a/notmuch-insert.c b/notmuch-insert.c
index 7db4f73..29d82c9 100644
--- a/notmuch-insert.c
+++ b/notmuch-insert.c
@@ -28,6 +28,12 @@
 #include 
 #include 

+enum {
+INSERT_EXIT_SUCCESS = 0,
+INSERT_EXIT_FAILURE = 1,
+INSERT_EXIT_FAILED_WRITE = 2
+};
+
 static volatile sig_atomic_t interrupted;

 static void
@@ -408,7 +414,7 @@ notmuch_insert_command (notmuch_config_t *config, int argc, 
char *argv[])

 opt_index = parse_arguments (argc, argv, options, 1);
 if (opt_index < 0)
-   return EXIT_FAILURE;
+   return INSERT_EXIT_FAILURE;

 db_path = notmuch_config_get_database_path (config);
 new_tags = notmuch_config_get_new_tags (config, &new_tags_length);
@@ -417,7 +423,7 @@ notmuch_insert_command (notmuch_config_t *config, int argc, 
char *argv[])
 tag_ops = tag_op_list_create (config);
 if (tag_ops == NULL) {
fprintf (stderr, "Out of memory.\n");
-   return EXIT_FAILURE;
+   return INSERT_EXIT_FAILURE;
 }
 for (i = 0; i < new_tags_length; i++) {
const char *error_msg;
@@ -426,20 +432,20 @@ notmuch_insert_command (notmuch_config_t *config, int 
argc, char *argv[])
if (error_msg) {
fprintf (stderr, "Error: tag '%s' in new.tags: %s\n",
 new_tags[i],  error_msg);
-   return EXIT_FAILURE;
+   return INSERT_EXIT_FAILURE;
}

if (tag_op_list_append (tag_ops, new_tags[i], FALSE))
-   return EXIT_FAILURE;
+   return INSERT_EXIT_FAILURE;
 }

 if (parse_tag_command_line (config, argc - opt_index, argv + opt_index,
&query_string, tag_ops))
-   return EXIT_FAILURE;
+   return INSERT_EXIT_FAILURE;

 if (*query_string != '\0') {
fprintf (stderr, "Error: unexpected query string: %s\n", query_string);
-   return EXIT_FAILURE;
+   return INSERT_EXIT_FAILURE;
 }

 if (folder == NULL) {
@@ -447,17 +453,17 @@ notmuch_insert_command (notmuch_config_t *config, int 
argc, char *argv[])
 } else {
if (! check_folder_name (folder)) {
fprintf (stderr, "Error: bad folder name: %s\n", folder);
-   return EXIT_FAILURE;
+   return INSERT_EXIT_FAILURE;
}
maildir = talloc_asprintf (config, "%s/%s", db_path, folder);
if (! maildir) {
fprintf (stderr, "Out of memory\n");
-   return EXIT_FAILURE;
+   return INSERT_EXIT_FAILURE;
}
if (create_folder && ! maildir_create_folder (config, maildir)) {
fprintf (stderr, "Error: creating maildir %s: %s\n",
 maildir, strerror (errno));
-   return EXIT_FAILURE;
+   return INSERT_EXIT_FAILURE;
}
 }

@@ -471,12 +477,12 @@ notmuch_insert_command (notmuch_config_t *config, int 
argc, char *argv[])

 if (notmuch_database_open (notmuch_config_get_database_path (config),
   NOTMUCH_DATABASE_MODE_READ_WRITE, ¬much))
-   return EXIT_FAILURE;
+   return INSERT_EXIT_FAILURE;

 /* Write the message to the Maildir new directory. */
 if (! write_message (config, STDIN_FILENO, maildir, &newpath)) {
notmuch_database_destroy (notmuch);
-   return EXIT_FAILURE;
+   return INSERT_EXIT_FAILED_WRITE;
 }

 /* Add the message to the index.
@@ -486,5 +492,5 @@ notmuch_insert_command (notmuch_config_t *config, int argc, 
char *argv[])
synchronize_flags);

 notmuch_database_destroy (notmuch);
-return EXIT_SUCCESS;
+return INSERT_EXIT_SUCCESS;
 }
diff --git a/test/T070-insert.sh b/test/T070-insert.sh
index ea9db07..c576efc 100755
--- a/test/T070-insert.sh
+++ b/test/T070-insert.sh
@@ -18,7 +18,7 @@ gen_insert_msg() {
"[body]=\"insert-message\""
 }

-test_expect_code 1 "Insert zero-length file" \
+test_expect_code 2 "Insert zero-length file" \
 "notmuch insert < /dev/null"

 # This test is a proxy for other errors that may occur while trying to
@@ -137,7 +137,7 @@ output=$(notmuch search --output=messages path:Drafts/cur 
tag:draft NOT tag:unre
 test_expect_equal "$output" "id:$gen_msg_id"

 gen_insert_msg
-test_expect_code 1 "Insert message into non-existent folder" \
+test_expect_code 2 "Insert message into non-existent folder" \
 "notmuch insert --folder=nonesuch < $gen_msg_filename"

 test_begin_subtest "Insert message, create folder"
-- 
1.8.4



[PATCH v2 06/10] cli: refactor insert

2014-04-16 Thread Peter Wang
Change insert_message into write_message and move its responsibilities
for indexing the message into the main function, to simplify the control
flow.
---
 notmuch-insert.c | 63 +++-
 1 file changed, 30 insertions(+), 33 deletions(-)

diff --git a/notmuch-insert.c b/notmuch-insert.c
index 6752fc8..7db4f73 100644
--- a/notmuch-insert.c
+++ b/notmuch-insert.c
@@ -338,59 +338,48 @@ add_file_to_database (notmuch_database_t *notmuch, const 
char *path,
 }

 static notmuch_bool_t
-insert_message (void *ctx, notmuch_database_t *notmuch, int fdin,
-   const char *dir, tag_op_list_t *tag_ops,
-   notmuch_bool_t synchronize_flags)
+write_message (void *ctx, int fdin, const char *dir, char **newpath)
 {
 char *tmppath;
-char *newpath;
 char *newdir;
 int fdout;
-char *cleanup_path;

-fdout = maildir_open_tmp_file (ctx, dir, &tmppath, &newpath, &newdir);
+fdout = maildir_open_tmp_file (ctx, dir, &tmppath, newpath, &newdir);
 if (fdout < 0)
return FALSE;

-cleanup_path = tmppath;
-
-if (! copy_stdin (fdin, fdout))
-   goto FAIL;
+if (! copy_stdin (fdin, fdout)) {
+   close (fdout);
+   unlink (tmppath);
+   return FALSE;
+}

 if (fsync (fdout) != 0) {
fprintf (stderr, "Error: fsync failed: %s\n", strerror (errno));
-   goto FAIL;
+   close (fdout);
+   unlink (tmppath);
+   return FALSE;
 }

 close (fdout);
-fdout = -1;

 /* Atomically move the new message file from the Maildir 'tmp' directory
  * to the 'new' directory.  We follow the Dovecot recommendation to
  * simply use rename() instead of link() and unlink().
  * See also: http://wiki.dovecot.org/MailboxFormat/Maildir#Mail_delivery
  */
-if (rename (tmppath, newpath) != 0) {
+if (rename (tmppath, *newpath) != 0) {
fprintf (stderr, "Error: rename() failed: %s\n", strerror (errno));
-   goto FAIL;
+   unlink (tmppath);
+   return FALSE;
 }

-cleanup_path = newpath;
-
-if (! sync_dir (newdir))
-   goto FAIL;
-
-/* Even if adding the message to the notmuch database fails,
- * the message is on disk and we consider the delivery completed. */
-add_file_to_database (notmuch, newpath, tag_ops, synchronize_flags);
+if (! sync_dir (newdir)) {
+   unlink (*newpath);
+   return FALSE;
+}

 return TRUE;
-
-  FAIL:
-if (fdout >= 0)
-   close (fdout);
-unlink (cleanup_path);
-return FALSE;
 }

 int
@@ -407,9 +396,9 @@ notmuch_insert_command (notmuch_config_t *config, int argc, 
char *argv[])
 notmuch_bool_t create_folder = FALSE;
 notmuch_bool_t synchronize_flags;
 const char *maildir;
+char *newpath;
 int opt_index;
 unsigned int i;
-notmuch_bool_t ret;

 notmuch_opt_desc_t options[] = {
{ NOTMUCH_OPT_STRING, &folder, "folder", 0, 0 },
@@ -484,10 +473,18 @@ notmuch_insert_command (notmuch_config_t *config, int 
argc, char *argv[])
   NOTMUCH_DATABASE_MODE_READ_WRITE, ¬much))
return EXIT_FAILURE;

-ret = insert_message (config, notmuch, STDIN_FILENO, maildir, tag_ops,
- synchronize_flags);
+/* Write the message to the Maildir new directory. */
+if (! write_message (config, STDIN_FILENO, maildir, &newpath)) {
+   notmuch_database_destroy (notmuch);
+   return EXIT_FAILURE;
+}

-notmuch_database_destroy (notmuch);
+/* Add the message to the index.
+ * Even if adding the message to the notmuch database fails,
+ * the message is on disk and we consider the delivery completed. */
+add_file_to_database (notmuch, newpath, tag_ops,
+   synchronize_flags);

-return ret ? EXIT_SUCCESS : EXIT_FAILURE;
+notmuch_database_destroy (notmuch);
+return EXIT_SUCCESS;
 }
-- 
1.8.4



[PATCH v2 05/10] ruby: handle return status of database close

2014-04-16 Thread Peter Wang
Throw an exception if notmuch_database_destroy fails.
---
 bindings/ruby/database.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/bindings/ruby/database.c b/bindings/ruby/database.c
index e84f726..c03d701 100644
--- a/bindings/ruby/database.c
+++ b/bindings/ruby/database.c
@@ -113,11 +113,13 @@ notmuch_rb_database_open (int argc, VALUE *argv, VALUE 
klass)
 VALUE
 notmuch_rb_database_close (VALUE self)
 {
+notmuch_status_t ret;
 notmuch_database_t *db;

 Data_Get_Notmuch_Database (self, db);
-notmuch_database_destroy (db);
+ret = notmuch_database_destroy (db);
 DATA_PTR (self) = NULL;
+notmuch_rb_status_raise (ret);

 return Qnil;
 }
-- 
1.8.4



[PATCH v2 04/10] go: add return status to database close method

2014-04-16 Thread Peter Wang
Add return status to the Database.Close() method that calls
notmuch_database_destroy.
---
 bindings/go/src/notmuch/notmuch.go | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/bindings/go/src/notmuch/notmuch.go 
b/bindings/go/src/notmuch/notmuch.go
index 00bd53a..b9230ad 100644
--- a/bindings/go/src/notmuch/notmuch.go
+++ b/bindings/go/src/notmuch/notmuch.go
@@ -144,8 +144,8 @@ func OpenDatabase(path string, mode DatabaseMode) 
(*Database, Status) {

 /* Close the given notmuch database, freeing all associated
  * resources. See notmuch_database_open. */
-func (self *Database) Close() {
-   C.notmuch_database_destroy(self.db)
+func (self *Database) Close() Status {
+   return Status(C.notmuch_database_destroy(self.db))
 }

 /* Return the database path of the given database.
-- 
1.8.4



[PATCH v2 03/10] python: handle return status of database close and destroy

2014-04-16 Thread Peter Wang
Throw an exception if notmuch_database_close or notmuch_database_destroy
fail.
---
 bindings/python/notmuch/database.py | 12 
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/bindings/python/notmuch/database.py 
b/bindings/python/notmuch/database.py
index 7ddf5cf..5b58e09 100644
--- a/bindings/python/notmuch/database.py
+++ b/bindings/python/notmuch/database.py
@@ -157,11 +157,13 @@ class Database(object):

 _destroy = nmlib.notmuch_database_destroy
 _destroy.argtypes = [NotmuchDatabaseP]
-_destroy.restype = None
+_destroy.restype = c_uint

 def __del__(self):
 if self._db:
-self._destroy(self._db)
+status = self._destroy(self._db)
+if status != STATUS.SUCCESS:
+raise NotmuchError(status)

 def _assert_db_is_initialized(self):
 """Raises :exc:`NotInitializedError` if self._db is `None`"""
@@ -217,7 +219,7 @@ class Database(object):

 _close = nmlib.notmuch_database_close
 _close.argtypes = [NotmuchDatabaseP]
-_close.restype = None
+_close.restype = c_uint

 def close(self):
 '''
@@ -231,7 +233,9 @@ class Database(object):
 NotmuchError.
 '''
 if self._db:
-self._close(self._db)
+status = self._close(self._db)
+if status != STATUS.SUCCESS:
+raise NotmuchError(status)

 def __enter__(self):
 '''
-- 
1.8.4



[PATCH v2 02/10] lib: bump soname

2014-04-16 Thread Peter Wang
Adding return values to notmuch_database_close and
notmuch_database_destroy may require bumping the soname.
---
 lib/Makefile.local | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/Makefile.local b/lib/Makefile.local
index c56cba9..4120390 100644
--- a/lib/Makefile.local
+++ b/lib/Makefile.local
@@ -5,7 +5,7 @@
 # the library interface, (such as the deletion of an API or a major
 # semantic change that breaks formerly functioning code).
 #
-LIBNOTMUCH_VERSION_MAJOR = 3
+LIBNOTMUCH_VERSION_MAJOR = 4

 # The minor version of the library interface. This should be incremented at
 # the time of release for any additions to the library interface,
-- 
1.8.4



[PATCH v2 01/10] lib: add return status to database close and destroy

2014-04-16 Thread Peter Wang
From: Jani Nikula 

notmuch_database_close may fail in Xapian ->flush() or ->close(), so
report the status. Similarly for notmuch_database_destroy which calls
close.

This is required for notmuch insert to report error status if message
indexing failed.
---
 lib/database.cc | 30 --
 lib/notmuch.h   | 15 +--
 2 files changed, 37 insertions(+), 8 deletions(-)

diff --git a/lib/database.cc b/lib/database.cc
index 1efb14d..ef7005b 100644
--- a/lib/database.cc
+++ b/lib/database.cc
@@ -774,14 +774,17 @@ notmuch_database_open (const char *path,
 return status;
 }

-void
+notmuch_status_t
 notmuch_database_close (notmuch_database_t *notmuch)
 {
+notmuch_status_t status = NOTMUCH_STATUS_SUCCESS;
+
 try {
if (notmuch->xapian_db != NULL &&
notmuch->mode == NOTMUCH_DATABASE_MODE_READ_WRITE)
(static_cast  
(notmuch->xapian_db))->flush ();
 } catch (const Xapian::Error &error) {
+   status = NOTMUCH_STATUS_XAPIAN_EXCEPTION;
if (! notmuch->exception_reported) {
fprintf (stderr, "Error: A Xapian exception occurred flushing 
database: %s\n",
 error.get_msg().c_str());
@@ -795,7 +798,9 @@ notmuch_database_close (notmuch_database_t *notmuch)
try {
notmuch->xapian_db->close();
} catch (const Xapian::Error &error) {
-   /* do nothing */
+   /* don't clobber previous error status */
+   if (status == NOTMUCH_STATUS_SUCCESS)
+   status = NOTMUCH_STATUS_XAPIAN_EXCEPTION;
}
 }

@@ -809,6 +814,8 @@ notmuch_database_close (notmuch_database_t *notmuch)
 notmuch->value_range_processor = NULL;
 delete notmuch->date_range_processor;
 notmuch->date_range_processor = NULL;
+
+return status;
 }

 #if HAVE_XAPIAN_COMPACT
@@ -972,8 +979,15 @@ notmuch_database_compact (const char *path,
 }

   DONE:
-if (notmuch)
-   notmuch_database_destroy (notmuch);
+if (notmuch) {
+   notmuch_status_t ret2;
+
+   ret2 = notmuch_database_destroy (notmuch);
+
+   /* don't clobber previous error status */
+   if (ret == NOTMUCH_STATUS_SUCCESS && ret2 != NOTMUCH_STATUS_SUCCESS)
+   ret = ret2;
+}

 talloc_free (local);

@@ -991,11 +1005,15 @@ notmuch_database_compact (unused (const char *path),
 }
 #endif

-void
+notmuch_status_t
 notmuch_database_destroy (notmuch_database_t *notmuch)
 {
-notmuch_database_close (notmuch);
+notmuch_status_t status;
+
+status = notmuch_database_close (notmuch);
 talloc_free (notmuch);
+
+return status;
 }

 const char *
diff --git a/lib/notmuch.h b/lib/notmuch.h
index 350bed8..3c5ec98 100644
--- a/lib/notmuch.h
+++ b/lib/notmuch.h
@@ -287,8 +287,16 @@ notmuch_database_open (const char *path,
  *
  * notmuch_database_close can be called multiple times.  Later calls
  * have no effect.
+ *
+ * Return value:
+ *
+ * NOTMUCH_STATUS_SUCCESS: Successfully closed the database.
+ *
+ * NOTMUCH_STATUS_XAPIAN_EXCEPTION: A Xapian exception occurred; the
+ * database has been closed but there are no guarantees the
+ * changes to the database, if any, have been flushed to disk.
  */
-void
+notmuch_status_t
 notmuch_database_close (notmuch_database_t *database);

 /**
@@ -317,8 +325,11 @@ notmuch_database_compact (const char* path,
 /**
  * Destroy the notmuch database, closing it if necessary and freeing
  * all associated resources.
+ *
+ * Return value as in notmuch_database_close if the database was open;
+ * notmuch_database_destroy itself has no failure modes.
  */
-void
+notmuch_status_t
 notmuch_database_destroy (notmuch_database_t *database);

 /**
-- 
1.8.4



[PATCH v2 00/10] add insert --must-index option

2014-04-16 Thread Peter Wang
Follow up to id:1374365254-13227-1-git-send-email-novalazy at gmail.com
The main changes are to take into account failures during
tagging and flushing of the database.

I took Jani's patch id:1390152046-6509-1-git-send-email-jani at nikula.org
without modification.

The soname bump is included in case it is required.

The python/go/ruby changes are untested.


Jani Nikula (1):
  lib: add return status to database close and destroy

Peter Wang (9):
  lib: bump soname
  python: handle return status of database close and destroy
  go: add return status to database close method
  ruby: handle return status of database close
  cli: refactor insert
  cli: indicate insert failure mode in exit status
  cli: add insert --must-index option
  test: test insert --must-index
  man: update insert documentation

 bindings/go/src/notmuch/notmuch.go  |   4 +-
 bindings/python/notmuch/database.py |  12 ++--
 bindings/ruby/database.c|   4 +-
 doc/man1/notmuch-insert.rst |  24 +--
 lib/Makefile.local  |   2 +-
 lib/database.cc |  30 ++--
 lib/notmuch.h   |  15 +++-
 notmuch-insert.c| 134 +---
 test/T070-insert.sh |  32 +++--
 9 files changed, 176 insertions(+), 81 deletions(-)

-- 
1.8.4



[PATCH] emacs: search: edit current query

2014-04-16 Thread Mark Walters
This adds an option to edit the current query. It is bound to
prefix-key f as it is a sort of inverse operation to filtering.
---
rlb asked for the option to modify the existing search query on
irc. This implements that for the search view.

Best wishes

Mark 





 emacs/notmuch.el |   37 ++---
 1 file changed, 26 insertions(+), 11 deletions(-)

diff --git a/emacs/notmuch.el b/emacs/notmuch.el
index 6c0bc1b..b4408f1 100644
--- a/emacs/notmuch.el
+++ b/emacs/notmuch.el
@@ -848,7 +848,7 @@ See `notmuch-tag' for information on the format of 
TAG-CHANGES."
   (concat "*notmuch-search-" query "*"))
  )))
 
-(defun notmuch-read-query (prompt)
+(defun notmuch-read-query (prompt &optional initial-contents)
   "Read a notmuch-query from the minibuffer with completion.
 
 PROMPT is the string to prompt with."
@@ -876,7 +876,7 @@ PROMPT is the string to prompt with."
   ;; this was simpler than convincing completing-read to accept spaces:
   (define-key keymap (kbd "TAB") 'minibuffer-complete)
   (let ((history-delete-duplicates t))
-   (read-from-minibuffer prompt nil keymap nil
+   (read-from-minibuffer prompt initial-contents keymap nil
  'notmuch-search-history nil nil)
 
 ;;;###autoload
@@ -963,18 +963,33 @@ default sort order is defined by 
`notmuch-search-oldest-first'."
   (set 'notmuch-search-oldest-first (not notmuch-search-oldest-first))
   (notmuch-search-refresh-view))
 
-(defun notmuch-search-filter (query)
+(put 'notmuch-search-filter 'notmuch-doc
+ "Filter the current search results based on an additional query string.")
+(put 'notmuch-search-filter 'notmuch-prefix-doc
+ "Edit the current search query.")
+(defun notmuch-search-filter (modify query)
   "Filter the current search results based on an additional query string.
 
 Runs a new search matching only messages that match both the
-current search results AND the additional query string provided."
-  (interactive (list (notmuch-read-query "Filter search: ")))
-  (let ((grouped-query (if (string-match-p notmuch-search-disjunctive-regexp 
query)
-  (concat "( " query " )")
-query)))
-(notmuch-search (if (string= notmuch-search-query-string "*")
-   grouped-query
- (concat notmuch-search-query-string " and " 
grouped-query)) notmuch-search-oldest-first)))
+current search results AND the additional query string provided.
+
+If called with a prefix-arg then present the user with the
+existing query string to allow the user to edit it."
+  (interactive (let ((query-string (if current-prefix-arg
+  "Modify Search: "
+"Filter Search: "))
+(initial-contents (if current-prefix-arg
+notmuch-search-query-string
+nil)))
+(list current-prefix-arg (notmuch-read-query query-string 
initial-contents
+  (if modify
+  (notmuch-search query notmuch-search-oldest-first)
+(let ((grouped-query (if (string-match-p notmuch-search-disjunctive-regexp 
query)
+(concat "( " query " )")
+  query)))
+  (notmuch-search (if (string= notmuch-search-query-string "*")
+ grouped-query
+   (concat notmuch-search-query-string " and " 
grouped-query)) notmuch-search-oldest-first
 
 (defun notmuch-search-filter-by-tag (tag)
   "Filter the current search results based on a single tag.
-- 
1.7.10.4

___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


[PATCH 1/1] emacs: hello: bugfix for saved searches defcustom

2014-04-16 Thread Mark Walters
The recent changes for saved searches introduced a bug when notmuch
was loaded after the saved search was defined. This was caused by a
utility function not being defined when the defcustom was loaded.

Fix this by moving some code around: the defcustom is moved into
notmuch-hello (which is a more natural place anyway), and the utility
functions are moved before the defcustom in notmuch-hello. We are
rather constrained as the defcustom for saved searches is the first
variable in the notmuch-hello customize window; to avoid moving this
customize the defcustom needs to be the first defcustom in
notmuch-hello, and the utility functions come before that.

This patch also renames one of the utility functions from
notmuch--saved-searches-to-plist to
notmuch-hello--saved-searches-to-plist (as it is purely local to
notmuch-hello) and corrects a couple of typo/spelling mistakes pointed
out by Tomi.
---
 emacs/notmuch-hello.el |  128 ++--
 emacs/notmuch-lib.el   |   52 
 2 files changed, 90 insertions(+), 90 deletions(-)

diff --git a/emacs/notmuch-hello.el b/emacs/notmuch-hello.el
index 4900a24..a7a8e20 100644
--- a/emacs/notmuch-hello.el
+++ b/emacs/notmuch-hello.el
@@ -29,6 +29,96 @@
 (declare-function notmuch-search "notmuch" (&optional query oldest-first 
target-thread target-line continuation))
 (declare-function notmuch-poll "notmuch" ())

+(defun notmuch-saved-search-get (saved-search field)
+  "Get FIELD from SAVED-SEARCH.
+
+If SAVED-SEARCH is a plist, this is just `plist-get', but for
+backwards compatibility, this also deals with the two other
+possible formats for SAVED-SEARCH: cons cells (NAME . QUERY) and
+lists (NAME QUERY COUNT-QUERY)."
+  (cond
+   ((keywordp (car saved-search))
+(plist-get saved-search field))
+   ;; It is not a plist so it is an old-style entry.
+   ((consp (cdr saved-search)) ;; It is a list (NAME QUERY COUNT-QUERY)
+(case field
+  (:name (first saved-search))
+  (:query (second saved-search))
+  (:count-query (third saved-search))
+  (t nil)))
+   (t  ;; It is a cons-cell (NAME . QUERY)
+(case field
+  (:name (car saved-search))
+  (:query (cdr saved-search))
+  (t nil)
+
+(defun notmuch-hello-saved-search-to-plist (saved-search)
+  "Return a copy of SAVED-SEARCH in plist form.
+
+If saved search is a plist then just return a copy. In other
+cases, for backwards compatibility, convert to plist form and
+return that."
+  (if (keywordp (car saved-search))
+  (copy-seq saved-search)
+(let ((fields (list :name :query :count-query))
+ plist-search)
+  (dolist (field fields plist-search)
+   (let ((string (notmuch-saved-search-get saved-search field)))
+ (when string
+   (setq plist-search (append plist-search (list field string)
+
+(defun notmuch-hello--saved-searches-to-plist (symbol)
+  "Extract a saved-search variable into plist form.
+
+The new style saved search is just a plist, but for backwards
+compatibility we use this function to extract old style saved
+searches so they still work in customize."
+  (let ((saved-searches (default-value symbol)))
+(mapcar #'notmuch-hello-saved-search-to-plist saved-searches)))
+
+(define-widget 'notmuch-saved-search-plist 'list
+  "A single saved search property list."
+  :tag "Saved Search"
+  :args '((list :inline t
+   :format "%v"
+   (group :format "%v" :inline t (const :format "   Name: " :name) 
(string :format "%v"))
+   (group :format "%v" :inline t (const :format "  Query: " 
:query) (string :format "%v")))
+ (checklist :inline t
+:format "%v"
+(group :format "%v" :inline t (const :format "Count-Query: 
" :count-query) (string :format "%v"))
+(group :format "%v" :inline t (const :format "" 
:sort-order)
+   (choice :tag " Sort Order"
+   (const :tag "Default" nil)
+   (const :tag "Oldest-first" oldest-first)
+   (const :tag "Newest-first" 
newest-first))
+
+(defcustom notmuch-saved-searches '((:name "inbox" :query "tag:inbox")
+   (:name "unread" :query "tag:unread"))
+  "A list of saved searches to display.
+
+The saved search can be given in 3 forms. The preferred way is as
+a plist. Supported properties are
+
+  :nameName of the search (required).
+  :query   Search to run (required).
+  :count-query Optional extra query to generate the count
+   shown. If not present then the :query property
+   is used.
+  :sort-order  Specify the sort order to be used for the search.
+   Possible values are 'oldest-first 'newest-first or
+   nil. Nil means use the default sort order.
+
+Other accepted forms are a cons cell of the form (NAM

[PATCH 0/1] emacs: hello: bugfix for saved searches defcustom

2014-04-16 Thread Mark Walters
This is almost the same as  
  id:1397627927-9692-1-git-send-email-markwalters1009 at 
gmail.com but witha commit message a couple of 
function renames and a couple of 
spelling/typo mistakes fixed (pointed out by Tomi)  
  

The diff from the WIP version is:

diff --git a/emacs/notmuch-hello.el b/emacs/notmuch-hello.el
index 27eac72..a7a8e20 100644
--- a/emacs/notmuch-hello.el
+++ b/emacs/notmuch-hello.el
@@ -56,7 +56,7 @@ lists (NAME QUERY COUNT-QUERY)."
   "Return a copy of SAVED-SEARCH in plist form.

 If saved search is a plist then just return a copy. In other
-cases, for backwards compatability, convert to plist form and
+cases, for backwards compatibility, convert to plist form and
 return that."
   (if (keywordp (car saved-search))
   (copy-seq saved-search)
@@ -67,11 +67,11 @@ return that."
  (when string
(setq plist-search (append plist-search (list field string)

-(defun notmuch--saved-searches-to-plist (symbol)
+(defun notmuch-hello--saved-searches-to-plist (symbol)
   "Extract a saved-search variable into plist form.

 The new style saved search is just a plist, but for backwards
-compatatibility we use this function to extract old style saved
+compatibility we use this function to extract old style saved
 searches so they still work in customize."
   (let ((saved-searches (default-value symbol)))
 (mapcar #'notmuch-hello-saved-search-to-plist saved-searches)))
@@ -114,7 +114,7 @@ or a list of the form (NAME QUERY COUNT-QUERY)."
 ;; section. This section generates its own saved-search list in one of
 ;; the latter two forms.

-  :get 'notmuch--saved-searches-to-plist
+  :get 'notmuch-hello--saved-searches-to-plist
   :type '(repeat notmuch-saved-search-plist)
   :tag "List of Saved Searches"
   :group 'notmuch-hello)


Mark Walters (1):
  emacs: hello: bugfix for saved searches defcustom

 emacs/notmuch-hello.el |  128 ++--
 emacs/notmuch-lib.el   |   52 
 2 files changed, 90 insertions(+), 90 deletions(-)

-- 
1.7.10.4



[PATCH 1/1] emacs: hello: bugfix for saved searches defcustom

2014-04-16 Thread Mark Walters
The recent changes for saved searches introduced a bug when notmuch
was loaded after the saved search was defined. This was caused by a
utility function not being defined when the defcustom was loaded.

Fix this by moving some code around: the defcustom is moved into
notmuch-hello (which is a more natural place anyway), and the utility
functions are moved before the defcustom in notmuch-hello. We are
rather constrained as the defcustom for saved searches is the first
variable in the notmuch-hello customize window; to avoid moving this
customize the defcustom needs to be the first defcustom in
notmuch-hello, and the utility functions come before that.

This patch also renames one of the utility functions from
notmuch--saved-searches-to-plist to
notmuch-hello--saved-searches-to-plist (as it is purely local to
notmuch-hello) and corrects a couple of typo/spelling mistakes pointed
out by Tomi.
---
 emacs/notmuch-hello.el |  128 ++--
 emacs/notmuch-lib.el   |   52 
 2 files changed, 90 insertions(+), 90 deletions(-)

diff --git a/emacs/notmuch-hello.el b/emacs/notmuch-hello.el
index 4900a24..a7a8e20 100644
--- a/emacs/notmuch-hello.el
+++ b/emacs/notmuch-hello.el
@@ -29,6 +29,96 @@
 (declare-function notmuch-search "notmuch" (&optional query oldest-first 
target-thread target-line continuation))
 (declare-function notmuch-poll "notmuch" ())
 
+(defun notmuch-saved-search-get (saved-search field)
+  "Get FIELD from SAVED-SEARCH.
+
+If SAVED-SEARCH is a plist, this is just `plist-get', but for
+backwards compatibility, this also deals with the two other
+possible formats for SAVED-SEARCH: cons cells (NAME . QUERY) and
+lists (NAME QUERY COUNT-QUERY)."
+  (cond
+   ((keywordp (car saved-search))
+(plist-get saved-search field))
+   ;; It is not a plist so it is an old-style entry.
+   ((consp (cdr saved-search)) ;; It is a list (NAME QUERY COUNT-QUERY)
+(case field
+  (:name (first saved-search))
+  (:query (second saved-search))
+  (:count-query (third saved-search))
+  (t nil)))
+   (t  ;; It is a cons-cell (NAME . QUERY)
+(case field
+  (:name (car saved-search))
+  (:query (cdr saved-search))
+  (t nil)
+
+(defun notmuch-hello-saved-search-to-plist (saved-search)
+  "Return a copy of SAVED-SEARCH in plist form.
+
+If saved search is a plist then just return a copy. In other
+cases, for backwards compatibility, convert to plist form and
+return that."
+  (if (keywordp (car saved-search))
+  (copy-seq saved-search)
+(let ((fields (list :name :query :count-query))
+ plist-search)
+  (dolist (field fields plist-search)
+   (let ((string (notmuch-saved-search-get saved-search field)))
+ (when string
+   (setq plist-search (append plist-search (list field string)
+
+(defun notmuch-hello--saved-searches-to-plist (symbol)
+  "Extract a saved-search variable into plist form.
+
+The new style saved search is just a plist, but for backwards
+compatibility we use this function to extract old style saved
+searches so they still work in customize."
+  (let ((saved-searches (default-value symbol)))
+(mapcar #'notmuch-hello-saved-search-to-plist saved-searches)))
+
+(define-widget 'notmuch-saved-search-plist 'list
+  "A single saved search property list."
+  :tag "Saved Search"
+  :args '((list :inline t
+   :format "%v"
+   (group :format "%v" :inline t (const :format "   Name: " :name) 
(string :format "%v"))
+   (group :format "%v" :inline t (const :format "  Query: " 
:query) (string :format "%v")))
+ (checklist :inline t
+:format "%v"
+(group :format "%v" :inline t (const :format "Count-Query: 
" :count-query) (string :format "%v"))
+(group :format "%v" :inline t (const :format "" 
:sort-order)
+   (choice :tag " Sort Order"
+   (const :tag "Default" nil)
+   (const :tag "Oldest-first" oldest-first)
+   (const :tag "Newest-first" 
newest-first))
+
+(defcustom notmuch-saved-searches '((:name "inbox" :query "tag:inbox")
+   (:name "unread" :query "tag:unread"))
+  "A list of saved searches to display.
+
+The saved search can be given in 3 forms. The preferred way is as
+a plist. Supported properties are
+
+  :nameName of the search (required).
+  :query   Search to run (required).
+  :count-query Optional extra query to generate the count
+   shown. If not present then the :query property
+   is used.
+  :sort-order  Specify the sort order to be used for the search.
+   Possible values are 'oldest-first 'newest-first or
+   nil. Nil means use the default sort order.
+
+Other accepted forms are a cons cell of the form (NA

[PATCH 0/1] emacs: hello: bugfix for saved searches defcustom

2014-04-16 Thread Mark Walters
This is almost the same as  
  
id:1397627927-9692-1-git-send-email-markwalters1...@gmail.com but with  
  a commit message a couple of function renames and a 
couple of spelling/typo mistakes fixed 
(pointed out by Tomi)

The diff from the WIP version is:

diff --git a/emacs/notmuch-hello.el b/emacs/notmuch-hello.el
index 27eac72..a7a8e20 100644
--- a/emacs/notmuch-hello.el
+++ b/emacs/notmuch-hello.el
@@ -56,7 +56,7 @@ lists (NAME QUERY COUNT-QUERY)."
   "Return a copy of SAVED-SEARCH in plist form.
 
 If saved search is a plist then just return a copy. In other
-cases, for backwards compatability, convert to plist form and
+cases, for backwards compatibility, convert to plist form and
 return that."
   (if (keywordp (car saved-search))
   (copy-seq saved-search)
@@ -67,11 +67,11 @@ return that."
  (when string
(setq plist-search (append plist-search (list field string)
 
-(defun notmuch--saved-searches-to-plist (symbol)
+(defun notmuch-hello--saved-searches-to-plist (symbol)
   "Extract a saved-search variable into plist form.
 
 The new style saved search is just a plist, but for backwards
-compatatibility we use this function to extract old style saved
+compatibility we use this function to extract old style saved
 searches so they still work in customize."
   (let ((saved-searches (default-value symbol)))
 (mapcar #'notmuch-hello-saved-search-to-plist saved-searches)))
@@ -114,7 +114,7 @@ or a list of the form (NAME QUERY COUNT-QUERY)."
 ;; section. This section generates its own saved-search list in one of
 ;; the latter two forms.
 
-  :get 'notmuch--saved-searches-to-plist
+  :get 'notmuch-hello--saved-searches-to-plist
   :type '(repeat notmuch-saved-search-plist)
   :tag "List of Saved Searches"
   :group 'notmuch-hello)


Mark Walters (1):
  emacs: hello: bugfix for saved searches defcustom

 emacs/notmuch-hello.el |  128 ++--
 emacs/notmuch-lib.el   |   52 
 2 files changed, 90 insertions(+), 90 deletions(-)

-- 
1.7.10.4

___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


Re: [PATCH v2] NEWS: Document the recent 'nmbug clone' and @{upstream} changes

2014-04-16 Thread Tomi Ollila
On Wed, Apr 16 2014, "W. Trevor King"  wrote:

> The changes landed with c200167 (nmbug: Add 'clone' and replace
> FETCH_HEAD with @{upstream}, 2014-03-09).
>
> The preferred markup language for NEWS seems to be Markdown, which is
> parsed by devel/news2wiki.pl into Markdown chunks for rendering by
> ikiwiki [1].
>
> [1]: http://notmuchmail.org/news/
> ---

LGTM (source $ news2wiki.pl-generated mdwn).

> Changes since v1 [1]:
>
> * Use HTTP (instead of the Git protocol) for the remote URL [2].
> * Remove “bare” from the text motivating a fresh clone.
>   Replace it with a reference to remote-tracking branches [2,3].
> * Elaborate on the local-commit-backup step (step 1) [4].
>
> [1]: 
> id:151b4a1b9612daa53fb47b60f0aa65f7a8e5ef5e.1396972599.git.wk...@tremily.us
>  http://thread.gmane.org/gmane.mail.notmuch.general/17457/focus=17812
> [2]: id:20140409210108.gb21...@odin.tremily.us
>  http://article.gmane.org/gmane.mail.notmuch.general/17817
> [3]: id:87bnw2wcwq.fsf@zancas.localnet
>  http://article.gmane.org/gmane.mail.notmuch.general/17885
> [4]: id:20140410020559.gc21...@odin.tremily.us
>  http://article.gmane.org/gmane.mail.notmuch.general/17819
>
>  NEWS | 22 ++
>  1 file changed, 22 insertions(+)
>
> diff --git a/NEWS b/NEWS
> index d4f4ea4..630607f 100644
> --- a/NEWS
> +++ b/NEWS
> @@ -20,6 +20,28 @@ Bug fix for saved searches with newlines in them.
>Split lines confuse `notmuch count --batch`, so we remove embedded
>newlines before calling notmuch count.
>  
> +nmbug
> +-
> +
> +nmbug adds a `clone` command for setting up the initial repository and
> +uses `@{upstream}` instead of `FETCH_HEAD` to track upstream changes.
> +
> +  The `@{upstream}` change reduces ambiguity when fetching multiple
> +  branches, but requires existing users update their `NMBGIT`
> +  repository (usually `~/.nmbug`) to distinguish between local and
> +  remote-tracking branches.  The easiest way to do this is:
> +
> +  1. If you have any purely local commits (i.e. they aren't in the
> + nmbug repository on nmbug.tethera.net), push them to a remote
> + repository.  We'll restore them from the backup in step 4.
> +  2. Remove your `NMBGIT` repository (e.g. `mv .nmbug .nmbug.bak`).
> +  3. Use the new `clone` command to create a fresh clone:
> +
> +nmbug clone http://nmbug.tethera.net/git/nmbug-tags.git
> +
> +  4. If you had local commits in step 1, add a remote for that
> + repository and fetch them into the new repository.
> +
>  Notmuch 0.17 (2013-12-30)
>  =
>  
> -- 
> 1.9.1.353.gc66d89d
>
> ___
> notmuch mailing list
> notmuch@notmuchmail.org
> http://notmuchmail.org/mailman/listinfo/notmuch
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


Emacs Keybindings no longer work after upgrading to 0.17

2014-04-16 Thread Tomi Ollila
On Wed, Apr 16 2014, Neeum Zawaz  wrote:

> Hi,
>
> I have this function:
>
>
> (define-key notmuch-search-mode-map "a"
>   (lambda ()
> "Archive message."
> (interactive)
> (notmuch-search-tag "-inbox")
> (notmuch-search-tag "-lowpriority")
> (notmuch-search-tag "- at review")
> (notmuch-search-tag "- at respond")
>   ))
>
> With the upgrade, if I try pressing "a" in search view, I get:
>
> Wrong type argument: stringp, 43

Short answer:

(notmuch-search-tag '("-inbox" "-lowpriority" "- at review" "- at respond"))

i.e. notmuch-search-tag takes list argument in these days... :D

yes, it is inconvenient that formats change, but...

Tomi


>
> Yet if I run the commands manually, it works fine.
>
> The full error, BTW, is:
>
> Debugger entered--Lisp error: (wrong-type-argument stringp 45)
>   string-match("^[-+]\\S-+$" 45 nil)
>   #[(tag-change) "\305\306\307\310\n  #,?\205\311\312!\207" [tag-change start 
> string regexp inhibit-changing-match-data "^[-+]\\S-+$" nil t string-match 
> error "Tag must be of the form `+this_tag' or `-that_tag'"] 4](45)
>   mapc(#[(tag-change) "\305\306\307\310\n #,?\205\311\312!\207" 
> [tag-change start string regexp inhibit-changing-match-data "^[-+]\\S-+$" nil 
> t string-match error "Tag must be of the form `+this_tag' or `-that_tag'"] 4] 
> "-inbox")
>   notmuch-tag("(id:20140414235421.43aad8ffb333 at www.pentaxforums.com)" 
> "-inbox")
>   notmuch-search-tag("-inbox")
>   (lambda nil "Archive message." (interactive) (notmuch-search-tag "-inbox") 
> (notmuch-search-tag "-lowpriority") (notmuch-search-tag "- at review") 
> (notmuch-search-tag "- at respond"))()
>   call-interactively((lambda nil "Delete message." (interactive) 
> (notmuch-search-tag "-inbox") (notmuch-search-tag "-lowpriority") 
> (notmuch-search-tag "- at review") (notmuch-search-tag "- at respond")) nil 
> nil)
>
> Strangely enough, the following works in show view.
>
> (define-key notmuch-show-mode-map "a"
>   (lambda ()
> "Archive message."
> (interactive)
> (notmuch-show-tag-message "-inbox")
> (notmuch-show-tag-message "-lowpriority")
> (notmuch-show-tag-message "- at review")
> (notmuch-show-tag-message "- at respond")
>   ))
>
> -- 
> Dictionaries are for loosers.
>
>
> /\  /\   /\  /
>/  \/  \ u e e n /  \/  a w a z
>>>mueen at nawaz.org<<
>anl
>
>  
> ___
> notmuch mailing list
> notmuch at notmuchmail.org
> http://notmuchmail.org/mailman/listinfo/notmuch


[WIP PATCH] emacs: hello: bugfix for saved searches defcustom

2014-04-16 Thread David Bremner
Mark Walters  writes:

> ---
> Hi
>
> David found a bug in the recent notmuch hello saved searches and
> reduced to a small test case. The problem occurs if the user sets
> notmuch-saved-searches and then loads notmuch. The reason is that the
> defcustom calls some utility functions and these need to be defined
> (not just declared) when the defcustom is encountered.
>
> This patch moves the code around so that they are defined first. I
> have marked the patch WIP as I am not sure what the best reordering
> is, and we may want to rename some functions which have changed file
> for namespace reasons.
>
> Anyway this fixes the test case. If it fixes the original bug too then
> I will provide a better version.

Hi Mark;

This fixes the problem for me.

Thanks for your efforts,

d


[WIP PATCH] emacs: hello: bugfix for saved searches defcustom

2014-04-16 Thread Mark Walters
---
Hi

David found a bug in the recent notmuch hello saved searches and
reduced to a small test case. The problem occurs if the user sets
notmuch-saved-searches and then loads notmuch. The reason is that the
defcustom calls some utility functions and these need to be defined
(not just declared) when the defcustom is encountered.

This patch moves the code around so that they are defined first. I
have marked the patch WIP as I am not sure what the best reordering
is, and we may want to rename some functions which have changed file
for namespace reasons.

Anyway this fixes the test case. If it fixes the original bug too then
I will provide a better version.

Best wishes 

Mark



 emacs/notmuch-hello.el |  128 ++--
 emacs/notmuch-lib.el   |   52 
 2 files changed, 90 insertions(+), 90 deletions(-)

diff --git a/emacs/notmuch-hello.el b/emacs/notmuch-hello.el
index 4900a24..27eac72 100644
--- a/emacs/notmuch-hello.el
+++ b/emacs/notmuch-hello.el
@@ -29,6 +29,96 @@
 (declare-function notmuch-search "notmuch" (&optional query oldest-first 
target-thread target-line continuation))
 (declare-function notmuch-poll "notmuch" ())

+(defun notmuch-saved-search-get (saved-search field)
+  "Get FIELD from SAVED-SEARCH.
+
+If SAVED-SEARCH is a plist, this is just `plist-get', but for
+backwards compatibility, this also deals with the two other
+possible formats for SAVED-SEARCH: cons cells (NAME . QUERY) and
+lists (NAME QUERY COUNT-QUERY)."
+  (cond
+   ((keywordp (car saved-search))
+(plist-get saved-search field))
+   ;; It is not a plist so it is an old-style entry.
+   ((consp (cdr saved-search)) ;; It is a list (NAME QUERY COUNT-QUERY)
+(case field
+  (:name (first saved-search))
+  (:query (second saved-search))
+  (:count-query (third saved-search))
+  (t nil)))
+   (t  ;; It is a cons-cell (NAME . QUERY)
+(case field
+  (:name (car saved-search))
+  (:query (cdr saved-search))
+  (t nil)
+
+(defun notmuch-hello-saved-search-to-plist (saved-search)
+  "Return a copy of SAVED-SEARCH in plist form.
+
+If saved search is a plist then just return a copy. In other
+cases, for backwards compatability, convert to plist form and
+return that."
+  (if (keywordp (car saved-search))
+  (copy-seq saved-search)
+(let ((fields (list :name :query :count-query))
+ plist-search)
+  (dolist (field fields plist-search)
+   (let ((string (notmuch-saved-search-get saved-search field)))
+ (when string
+   (setq plist-search (append plist-search (list field string)
+
+(defun notmuch--saved-searches-to-plist (symbol)
+  "Extract a saved-search variable into plist form.
+
+The new style saved search is just a plist, but for backwards
+compatatibility we use this function to extract old style saved
+searches so they still work in customize."
+  (let ((saved-searches (default-value symbol)))
+(mapcar #'notmuch-hello-saved-search-to-plist saved-searches)))
+
+(define-widget 'notmuch-saved-search-plist 'list
+  "A single saved search property list."
+  :tag "Saved Search"
+  :args '((list :inline t
+   :format "%v"
+   (group :format "%v" :inline t (const :format "   Name: " :name) 
(string :format "%v"))
+   (group :format "%v" :inline t (const :format "  Query: " 
:query) (string :format "%v")))
+ (checklist :inline t
+:format "%v"
+(group :format "%v" :inline t (const :format "Count-Query: 
" :count-query) (string :format "%v"))
+(group :format "%v" :inline t (const :format "" 
:sort-order)
+   (choice :tag " Sort Order"
+   (const :tag "Default" nil)
+   (const :tag "Oldest-first" oldest-first)
+   (const :tag "Newest-first" 
newest-first))
+
+(defcustom notmuch-saved-searches '((:name "inbox" :query "tag:inbox")
+   (:name "unread" :query "tag:unread"))
+  "A list of saved searches to display.
+
+The saved search can be given in 3 forms. The preferred way is as
+a plist. Supported properties are
+
+  :nameName of the search (required).
+  :query   Search to run (required).
+  :count-query Optional extra query to generate the count
+   shown. If not present then the :query property
+   is used.
+  :sort-order  Specify the sort order to be used for the search.
+   Possible values are 'oldest-first 'newest-first or
+   nil. Nil means use the default sort order.
+
+Other accepted forms are a cons cell of the form (NAME . QUERY)
+or a list of the form (NAME QUERY COUNT-QUERY)."
+;; The saved-search format is also used by the all-tags notmuch-hello
+;; section. This section generates its own saved-search list in one of
+;; the latter two 

[PATCH v2 09/10] test: test insert --must-index

2014-04-16 Thread Peter Wang
Test the insert --must-index option.
---
 test/T070-insert.sh | 28 +---
 1 file changed, 25 insertions(+), 3 deletions(-)

diff --git a/test/T070-insert.sh b/test/T070-insert.sh
index c576efc..4e289c0 100755
--- a/test/T070-insert.sh
+++ b/test/T070-insert.sh
@@ -21,11 +21,20 @@ gen_insert_msg() {
 test_expect_code 2 "Insert zero-length file" \
 "notmuch insert < /dev/null"
 
-# This test is a proxy for other errors that may occur while trying to
-# add a message to the notmuch database, e.g. database locked.
-test_expect_code 0 "Insert non-message" \
+test_expect_code 3 "Insert non-message with --must-index on" \
+"echo bad_message | notmuch insert --must-index"
+
+test_begin_subtest "Non-message file should not exist"
+output=$(find "${MAIL_DIR}/cur" "${MAIL_DIR}/new" "${MAIL_DIR}/tmp" -type f 
-print | wc -l)
+test_expect_equal "$output" "0"
+
+test_expect_code 0 "Insert non-message with --must-index off" \
 "echo bad_message | notmuch insert"
 
+test_begin_subtest "Non-message file should exist"
+output=$(find "${MAIL_DIR}/cur" "${MAIL_DIR}/new" "${MAIL_DIR}/tmp" -type f 
-print | wc -l)
+test_expect_equal "$output" "1"
+
 test_begin_subtest "Database empty so far"
 test_expect_equal "0" "`notmuch count --output=messages '*'`"
 
@@ -77,6 +86,19 @@ notmuch insert +custom -unread < "$gen_msg_filename"
 output=$(notmuch search --output=messages tag:custom NOT tag:unread)
 test_expect_equal "$output" "id:$gen_msg_id"
 
+# overlongtag exceeds NOTMUCH_TAG_MAX
+ten=0123456789
+hundred=${ten}${ten}${ten}${ten}${ten}${ten}${ten}${ten}${ten}${ten}
+overlongtag=x${hundred}${hundred}
+gen_insert_msg
+test_expect_code 3 "Tagging fails with --must-index on" \
+"notmuch insert --must-index +$overlongtag < $gen_msg_filename"
+
+test_begin_subtest "Tagging fails with --must-index off"
+notmuch insert +$overlongtag < "$gen_msg_filename"
+output=$(notmuch search --output=messages id:$gen_msg_id)
+test_expect_equal "$output" "id:$gen_msg_id"
+
 test_begin_subtest "Insert message with default tags stays in new/"
 gen_insert_msg
 notmuch insert < "$gen_msg_filename"
-- 
1.8.4

___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


[PATCH v2 10/10] man: update insert documentation

2014-04-16 Thread Peter Wang
Add documentation for the insert --must-index option
and failure exit codes.
---
 doc/man1/notmuch-insert.rst | 24 ++--
 1 file changed, 18 insertions(+), 6 deletions(-)

diff --git a/doc/man1/notmuch-insert.rst b/doc/man1/notmuch-insert.rst
index 2be1a7b..02c516b 100644
--- a/doc/man1/notmuch-insert.rst
+++ b/doc/man1/notmuch-insert.rst
@@ -38,16 +38,28 @@ Supported options for **insert** include
 does not exist. Otherwise the folder must already exist for mail
 delivery to succeed.
 
+``--must-index``
+Succeed only if the message is written to disk, added to the
+notmuch database, and tagged (unless a duplicate message).
+Failure to synchronize tags to maildir flags has no effect.
+Without this option, **insert** succeeds as long as the message
+is written to disk.
+
 EXIT STATUS
 ===
 
-This command returns exit status 0 if the message was successfully added
-to the mail directory, even if the message could not be indexed and
-added to the notmuch database. In the latter case, a warning will be
-printed to standard error but the message file will be left on disk.
+This command returns exit status 0 on success. On failure, it returns a
+non-zero exit status:
+
+1
+General failure code.
+
+2
+Failed to write the message to disk.
 
-If the message could not be written to disk then a non-zero exit status
-is returned.
+3
+Failed to index or tag the message (unless a duplicate message),
+and ``--must-index`` was specified.
 
 SEE ALSO
 
-- 
1.8.4

___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


[PATCH v2 08/10] cli: add insert --must-index option

2014-04-16 Thread Peter Wang
This option causes notmuch insert to fail (with exit code 3) on failure
to index the message, or failure to set the tags on the message, or if
closing (flushing) the database fails.  Failure to sync tags to flags
has no effect.
---
 notmuch-insert.c | 57 +++-
 1 file changed, 40 insertions(+), 17 deletions(-)

diff --git a/notmuch-insert.c b/notmuch-insert.c
index 29d82c9..83257f4 100644
--- a/notmuch-insert.c
+++ b/notmuch-insert.c
@@ -31,7 +31,8 @@
 enum {
 INSERT_EXIT_SUCCESS = 0,
 INSERT_EXIT_FAILURE = 1,
-INSERT_EXIT_FAILED_WRITE = 2
+INSERT_EXIT_FAILED_WRITE = 2,
+INSERT_EXIT_FAILED_INDEX = 3
 };
 
 static volatile sig_atomic_t interrupted;
@@ -298,13 +299,15 @@ copy_stdin (int fdin, int fdout)
 }
 
 /* Add the specified message file to the notmuch database, applying tags.
- * The file is renamed to encode notmuch tags as maildir flags. */
-static void
+ * If synchronize_flags is set then file is renamed to encode notmuch tags as
+ * maildir flags. */
+static notmuch_bool_t
 add_file_to_database (notmuch_database_t *notmuch, const char *path,
  tag_op_list_t *tag_ops, notmuch_bool_t synchronize_flags)
 {
 notmuch_message_t *message;
 notmuch_status_t status;
+notmuch_status_t sync;
 
 status = notmuch_database_add_message (notmuch, path, &message);
 switch (status) {
@@ -324,23 +327,28 @@ add_file_to_database (notmuch_database_t *notmuch, const 
char *path,
 case NOTMUCH_STATUS_LAST_STATUS:
fprintf (stderr, "Error: failed to add `%s' to notmuch database: %s\n",
 path, notmuch_status_to_string (status));
-   return;
+   return FALSE;
 }
 
 if (status == NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID) {
/* Don't change tags of an existing message. */
-   if (synchronize_flags) {
-   status = notmuch_message_tags_to_maildir_flags (message);
-   if (status != NOTMUCH_STATUS_SUCCESS)
-   fprintf (stderr, "Error: failed to sync tags to maildir 
flags\n");
-   }
+   status = NOTMUCH_STATUS_SUCCESS;
 } else {
-   tag_op_flag_t flags = synchronize_flags ? TAG_FLAG_MAILDIR_SYNC : 0;
+   status = tag_op_list_apply (message, tag_ops, 0);
+}
 
-   tag_op_list_apply (message, tag_ops, flags);
+/* Call notmuch_message_tags_to_maildir_flags directly instead of doing it
+ * as part of tag_op_list_apply. For --must-index we want to succeed if
+ * tagging succeeds, but disregard whether synchronizing flags fails. */
+if (status == NOTMUCH_STATUS_SUCCESS && synchronize_flags) {
+   sync = notmuch_message_tags_to_maildir_flags (message);
+   if (sync != NOTMUCH_STATUS_SUCCESS)
+   fprintf (stderr, "Error: failed to sync tags to maildir flags\n");
 }
 
 notmuch_message_destroy (message);
+
+return (status == NOTMUCH_STATUS_SUCCESS);
 }
 
 static notmuch_bool_t
@@ -400,15 +408,19 @@ notmuch_insert_command (notmuch_config_t *config, int 
argc, char *argv[])
 char *query_string = NULL;
 const char *folder = NULL;
 notmuch_bool_t create_folder = FALSE;
+notmuch_bool_t must_index = FALSE;
 notmuch_bool_t synchronize_flags;
 const char *maildir;
 char *newpath;
 int opt_index;
 unsigned int i;
+notmuch_bool_t indexed;
+notmuch_status_t status;
 
 notmuch_opt_desc_t options[] = {
{ NOTMUCH_OPT_STRING, &folder, "folder", 0, 0 },
{ NOTMUCH_OPT_BOOLEAN, &create_folder, "create-folder", 0, 0 },
+   { NOTMUCH_OPT_BOOLEAN, &must_index, "must-index", 0, 0 },
{ NOTMUCH_OPT_END, 0, 0, 0, 0 }
 };
 
@@ -485,12 +497,23 @@ notmuch_insert_command (notmuch_config_t *config, int 
argc, char *argv[])
return INSERT_EXIT_FAILED_WRITE;
 }
 
-/* Add the message to the index.
- * Even if adding the message to the notmuch database fails,
- * the message is on disk and we consider the delivery completed. */
-add_file_to_database (notmuch, newpath, tag_ops,
+/* Add the message to the index. */
+indexed = add_file_to_database (notmuch, newpath, tag_ops,
synchronize_flags);
 
-notmuch_database_destroy (notmuch);
-return INSERT_EXIT_SUCCESS;
+/* If must_index is FALSE then succeed as the message is on disk.
+ * Otherwise message indexing and tagging must succeed, and the database
+ * must be flushed. Don't flush the database if there was an earlier
+ * error, so as to abandon the transaction (is there a better way?) */
+if (! must_index) {
+   notmuch_database_destroy (notmuch);
+   return INSERT_EXIT_SUCCESS;
+}
+if (indexed) {
+   status = notmuch_database_destroy (notmuch);
+   if (status == NOTMUCH_STATUS_SUCCESS)
+   return INSERT_EXIT_SUCCESS;
+}
+unlink (newpath);
+return INSERT_EXIT_FAILED_INDEX;
 }
-- 
1.8.4

___
notmuch mailing lis

[PATCH v2 06/10] cli: refactor insert

2014-04-16 Thread Peter Wang
Change insert_message into write_message and move its responsibilities
for indexing the message into the main function, to simplify the control
flow.
---
 notmuch-insert.c | 63 +++-
 1 file changed, 30 insertions(+), 33 deletions(-)

diff --git a/notmuch-insert.c b/notmuch-insert.c
index 6752fc8..7db4f73 100644
--- a/notmuch-insert.c
+++ b/notmuch-insert.c
@@ -338,59 +338,48 @@ add_file_to_database (notmuch_database_t *notmuch, const 
char *path,
 }
 
 static notmuch_bool_t
-insert_message (void *ctx, notmuch_database_t *notmuch, int fdin,
-   const char *dir, tag_op_list_t *tag_ops,
-   notmuch_bool_t synchronize_flags)
+write_message (void *ctx, int fdin, const char *dir, char **newpath)
 {
 char *tmppath;
-char *newpath;
 char *newdir;
 int fdout;
-char *cleanup_path;
 
-fdout = maildir_open_tmp_file (ctx, dir, &tmppath, &newpath, &newdir);
+fdout = maildir_open_tmp_file (ctx, dir, &tmppath, newpath, &newdir);
 if (fdout < 0)
return FALSE;
 
-cleanup_path = tmppath;
-
-if (! copy_stdin (fdin, fdout))
-   goto FAIL;
+if (! copy_stdin (fdin, fdout)) {
+   close (fdout);
+   unlink (tmppath);
+   return FALSE;
+}
 
 if (fsync (fdout) != 0) {
fprintf (stderr, "Error: fsync failed: %s\n", strerror (errno));
-   goto FAIL;
+   close (fdout);
+   unlink (tmppath);
+   return FALSE;
 }
 
 close (fdout);
-fdout = -1;
 
 /* Atomically move the new message file from the Maildir 'tmp' directory
  * to the 'new' directory.  We follow the Dovecot recommendation to
  * simply use rename() instead of link() and unlink().
  * See also: http://wiki.dovecot.org/MailboxFormat/Maildir#Mail_delivery
  */
-if (rename (tmppath, newpath) != 0) {
+if (rename (tmppath, *newpath) != 0) {
fprintf (stderr, "Error: rename() failed: %s\n", strerror (errno));
-   goto FAIL;
+   unlink (tmppath);
+   return FALSE;
 }
 
-cleanup_path = newpath;
-
-if (! sync_dir (newdir))
-   goto FAIL;
-
-/* Even if adding the message to the notmuch database fails,
- * the message is on disk and we consider the delivery completed. */
-add_file_to_database (notmuch, newpath, tag_ops, synchronize_flags);
+if (! sync_dir (newdir)) {
+   unlink (*newpath);
+   return FALSE;
+}
 
 return TRUE;
-
-  FAIL:
-if (fdout >= 0)
-   close (fdout);
-unlink (cleanup_path);
-return FALSE;
 }
 
 int
@@ -407,9 +396,9 @@ notmuch_insert_command (notmuch_config_t *config, int argc, 
char *argv[])
 notmuch_bool_t create_folder = FALSE;
 notmuch_bool_t synchronize_flags;
 const char *maildir;
+char *newpath;
 int opt_index;
 unsigned int i;
-notmuch_bool_t ret;
 
 notmuch_opt_desc_t options[] = {
{ NOTMUCH_OPT_STRING, &folder, "folder", 0, 0 },
@@ -484,10 +473,18 @@ notmuch_insert_command (notmuch_config_t *config, int 
argc, char *argv[])
   NOTMUCH_DATABASE_MODE_READ_WRITE, ¬much))
return EXIT_FAILURE;
 
-ret = insert_message (config, notmuch, STDIN_FILENO, maildir, tag_ops,
- synchronize_flags);
+/* Write the message to the Maildir new directory. */
+if (! write_message (config, STDIN_FILENO, maildir, &newpath)) {
+   notmuch_database_destroy (notmuch);
+   return EXIT_FAILURE;
+}
 
-notmuch_database_destroy (notmuch);
+/* Add the message to the index.
+ * Even if adding the message to the notmuch database fails,
+ * the message is on disk and we consider the delivery completed. */
+add_file_to_database (notmuch, newpath, tag_ops,
+   synchronize_flags);
 
-return ret ? EXIT_SUCCESS : EXIT_FAILURE;
+notmuch_database_destroy (notmuch);
+return EXIT_SUCCESS;
 }
-- 
1.8.4

___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


[PATCH v2 04/10] go: add return status to database close method

2014-04-16 Thread Peter Wang
Add return status to the Database.Close() method that calls
notmuch_database_destroy.
---
 bindings/go/src/notmuch/notmuch.go | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/bindings/go/src/notmuch/notmuch.go 
b/bindings/go/src/notmuch/notmuch.go
index 00bd53a..b9230ad 100644
--- a/bindings/go/src/notmuch/notmuch.go
+++ b/bindings/go/src/notmuch/notmuch.go
@@ -144,8 +144,8 @@ func OpenDatabase(path string, mode DatabaseMode) 
(*Database, Status) {
 
 /* Close the given notmuch database, freeing all associated
  * resources. See notmuch_database_open. */
-func (self *Database) Close() {
-   C.notmuch_database_destroy(self.db)
+func (self *Database) Close() Status {
+   return Status(C.notmuch_database_destroy(self.db))
 }
 
 /* Return the database path of the given database.
-- 
1.8.4

___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


[PATCH v2 05/10] ruby: handle return status of database close

2014-04-16 Thread Peter Wang
Throw an exception if notmuch_database_destroy fails.
---
 bindings/ruby/database.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/bindings/ruby/database.c b/bindings/ruby/database.c
index e84f726..c03d701 100644
--- a/bindings/ruby/database.c
+++ b/bindings/ruby/database.c
@@ -113,11 +113,13 @@ notmuch_rb_database_open (int argc, VALUE *argv, VALUE 
klass)
 VALUE
 notmuch_rb_database_close (VALUE self)
 {
+notmuch_status_t ret;
 notmuch_database_t *db;
 
 Data_Get_Notmuch_Database (self, db);
-notmuch_database_destroy (db);
+ret = notmuch_database_destroy (db);
 DATA_PTR (self) = NULL;
+notmuch_rb_status_raise (ret);
 
 return Qnil;
 }
-- 
1.8.4

___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


[PATCH v2 07/10] cli: indicate insert failure mode in exit status

2014-04-16 Thread Peter Wang
Make insert return a different exit code, 2, for failure to write the
message file to disk, and exit code 1 for other errors.
---
 notmuch-insert.c| 30 ++
 test/T070-insert.sh |  4 ++--
 2 files changed, 20 insertions(+), 14 deletions(-)

diff --git a/notmuch-insert.c b/notmuch-insert.c
index 7db4f73..29d82c9 100644
--- a/notmuch-insert.c
+++ b/notmuch-insert.c
@@ -28,6 +28,12 @@
 #include 
 #include 
 
+enum {
+INSERT_EXIT_SUCCESS = 0,
+INSERT_EXIT_FAILURE = 1,
+INSERT_EXIT_FAILED_WRITE = 2
+};
+
 static volatile sig_atomic_t interrupted;
 
 static void
@@ -408,7 +414,7 @@ notmuch_insert_command (notmuch_config_t *config, int argc, 
char *argv[])
 
 opt_index = parse_arguments (argc, argv, options, 1);
 if (opt_index < 0)
-   return EXIT_FAILURE;
+   return INSERT_EXIT_FAILURE;
 
 db_path = notmuch_config_get_database_path (config);
 new_tags = notmuch_config_get_new_tags (config, &new_tags_length);
@@ -417,7 +423,7 @@ notmuch_insert_command (notmuch_config_t *config, int argc, 
char *argv[])
 tag_ops = tag_op_list_create (config);
 if (tag_ops == NULL) {
fprintf (stderr, "Out of memory.\n");
-   return EXIT_FAILURE;
+   return INSERT_EXIT_FAILURE;
 }
 for (i = 0; i < new_tags_length; i++) {
const char *error_msg;
@@ -426,20 +432,20 @@ notmuch_insert_command (notmuch_config_t *config, int 
argc, char *argv[])
if (error_msg) {
fprintf (stderr, "Error: tag '%s' in new.tags: %s\n",
 new_tags[i],  error_msg);
-   return EXIT_FAILURE;
+   return INSERT_EXIT_FAILURE;
}
 
if (tag_op_list_append (tag_ops, new_tags[i], FALSE))
-   return EXIT_FAILURE;
+   return INSERT_EXIT_FAILURE;
 }
 
 if (parse_tag_command_line (config, argc - opt_index, argv + opt_index,
&query_string, tag_ops))
-   return EXIT_FAILURE;
+   return INSERT_EXIT_FAILURE;
 
 if (*query_string != '\0') {
fprintf (stderr, "Error: unexpected query string: %s\n", query_string);
-   return EXIT_FAILURE;
+   return INSERT_EXIT_FAILURE;
 }
 
 if (folder == NULL) {
@@ -447,17 +453,17 @@ notmuch_insert_command (notmuch_config_t *config, int 
argc, char *argv[])
 } else {
if (! check_folder_name (folder)) {
fprintf (stderr, "Error: bad folder name: %s\n", folder);
-   return EXIT_FAILURE;
+   return INSERT_EXIT_FAILURE;
}
maildir = talloc_asprintf (config, "%s/%s", db_path, folder);
if (! maildir) {
fprintf (stderr, "Out of memory\n");
-   return EXIT_FAILURE;
+   return INSERT_EXIT_FAILURE;
}
if (create_folder && ! maildir_create_folder (config, maildir)) {
fprintf (stderr, "Error: creating maildir %s: %s\n",
 maildir, strerror (errno));
-   return EXIT_FAILURE;
+   return INSERT_EXIT_FAILURE;
}
 }
 
@@ -471,12 +477,12 @@ notmuch_insert_command (notmuch_config_t *config, int 
argc, char *argv[])
 
 if (notmuch_database_open (notmuch_config_get_database_path (config),
   NOTMUCH_DATABASE_MODE_READ_WRITE, ¬much))
-   return EXIT_FAILURE;
+   return INSERT_EXIT_FAILURE;
 
 /* Write the message to the Maildir new directory. */
 if (! write_message (config, STDIN_FILENO, maildir, &newpath)) {
notmuch_database_destroy (notmuch);
-   return EXIT_FAILURE;
+   return INSERT_EXIT_FAILED_WRITE;
 }
 
 /* Add the message to the index.
@@ -486,5 +492,5 @@ notmuch_insert_command (notmuch_config_t *config, int argc, 
char *argv[])
synchronize_flags);
 
 notmuch_database_destroy (notmuch);
-return EXIT_SUCCESS;
+return INSERT_EXIT_SUCCESS;
 }
diff --git a/test/T070-insert.sh b/test/T070-insert.sh
index ea9db07..c576efc 100755
--- a/test/T070-insert.sh
+++ b/test/T070-insert.sh
@@ -18,7 +18,7 @@ gen_insert_msg() {
"[body]=\"insert-message\""
 }
 
-test_expect_code 1 "Insert zero-length file" \
+test_expect_code 2 "Insert zero-length file" \
 "notmuch insert < /dev/null"
 
 # This test is a proxy for other errors that may occur while trying to
@@ -137,7 +137,7 @@ output=$(notmuch search --output=messages path:Drafts/cur 
tag:draft NOT tag:unre
 test_expect_equal "$output" "id:$gen_msg_id"
 
 gen_insert_msg
-test_expect_code 1 "Insert message into non-existent folder" \
+test_expect_code 2 "Insert message into non-existent folder" \
 "notmuch insert --folder=nonesuch < $gen_msg_filename"
 
 test_begin_subtest "Insert message, create folder"
-- 
1.8.4

___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


[PATCH v2 03/10] python: handle return status of database close and destroy

2014-04-16 Thread Peter Wang
Throw an exception if notmuch_database_close or notmuch_database_destroy
fail.
---
 bindings/python/notmuch/database.py | 12 
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/bindings/python/notmuch/database.py 
b/bindings/python/notmuch/database.py
index 7ddf5cf..5b58e09 100644
--- a/bindings/python/notmuch/database.py
+++ b/bindings/python/notmuch/database.py
@@ -157,11 +157,13 @@ class Database(object):
 
 _destroy = nmlib.notmuch_database_destroy
 _destroy.argtypes = [NotmuchDatabaseP]
-_destroy.restype = None
+_destroy.restype = c_uint
 
 def __del__(self):
 if self._db:
-self._destroy(self._db)
+status = self._destroy(self._db)
+if status != STATUS.SUCCESS:
+raise NotmuchError(status)
 
 def _assert_db_is_initialized(self):
 """Raises :exc:`NotInitializedError` if self._db is `None`"""
@@ -217,7 +219,7 @@ class Database(object):
 
 _close = nmlib.notmuch_database_close
 _close.argtypes = [NotmuchDatabaseP]
-_close.restype = None
+_close.restype = c_uint
 
 def close(self):
 '''
@@ -231,7 +233,9 @@ class Database(object):
 NotmuchError.
 '''
 if self._db:
-self._close(self._db)
+status = self._close(self._db)
+if status != STATUS.SUCCESS:
+raise NotmuchError(status)
 
 def __enter__(self):
 '''
-- 
1.8.4

___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


[PATCH v2 01/10] lib: add return status to database close and destroy

2014-04-16 Thread Peter Wang
From: Jani Nikula 

notmuch_database_close may fail in Xapian ->flush() or ->close(), so
report the status. Similarly for notmuch_database_destroy which calls
close.

This is required for notmuch insert to report error status if message
indexing failed.
---
 lib/database.cc | 30 --
 lib/notmuch.h   | 15 +--
 2 files changed, 37 insertions(+), 8 deletions(-)

diff --git a/lib/database.cc b/lib/database.cc
index 1efb14d..ef7005b 100644
--- a/lib/database.cc
+++ b/lib/database.cc
@@ -774,14 +774,17 @@ notmuch_database_open (const char *path,
 return status;
 }
 
-void
+notmuch_status_t
 notmuch_database_close (notmuch_database_t *notmuch)
 {
+notmuch_status_t status = NOTMUCH_STATUS_SUCCESS;
+
 try {
if (notmuch->xapian_db != NULL &&
notmuch->mode == NOTMUCH_DATABASE_MODE_READ_WRITE)
(static_cast  
(notmuch->xapian_db))->flush ();
 } catch (const Xapian::Error &error) {
+   status = NOTMUCH_STATUS_XAPIAN_EXCEPTION;
if (! notmuch->exception_reported) {
fprintf (stderr, "Error: A Xapian exception occurred flushing 
database: %s\n",
 error.get_msg().c_str());
@@ -795,7 +798,9 @@ notmuch_database_close (notmuch_database_t *notmuch)
try {
notmuch->xapian_db->close();
} catch (const Xapian::Error &error) {
-   /* do nothing */
+   /* don't clobber previous error status */
+   if (status == NOTMUCH_STATUS_SUCCESS)
+   status = NOTMUCH_STATUS_XAPIAN_EXCEPTION;
}
 }
 
@@ -809,6 +814,8 @@ notmuch_database_close (notmuch_database_t *notmuch)
 notmuch->value_range_processor = NULL;
 delete notmuch->date_range_processor;
 notmuch->date_range_processor = NULL;
+
+return status;
 }
 
 #if HAVE_XAPIAN_COMPACT
@@ -972,8 +979,15 @@ notmuch_database_compact (const char *path,
 }
 
   DONE:
-if (notmuch)
-   notmuch_database_destroy (notmuch);
+if (notmuch) {
+   notmuch_status_t ret2;
+
+   ret2 = notmuch_database_destroy (notmuch);
+
+   /* don't clobber previous error status */
+   if (ret == NOTMUCH_STATUS_SUCCESS && ret2 != NOTMUCH_STATUS_SUCCESS)
+   ret = ret2;
+}
 
 talloc_free (local);
 
@@ -991,11 +1005,15 @@ notmuch_database_compact (unused (const char *path),
 }
 #endif
 
-void
+notmuch_status_t
 notmuch_database_destroy (notmuch_database_t *notmuch)
 {
-notmuch_database_close (notmuch);
+notmuch_status_t status;
+
+status = notmuch_database_close (notmuch);
 talloc_free (notmuch);
+
+return status;
 }
 
 const char *
diff --git a/lib/notmuch.h b/lib/notmuch.h
index 350bed8..3c5ec98 100644
--- a/lib/notmuch.h
+++ b/lib/notmuch.h
@@ -287,8 +287,16 @@ notmuch_database_open (const char *path,
  *
  * notmuch_database_close can be called multiple times.  Later calls
  * have no effect.
+ *
+ * Return value:
+ *
+ * NOTMUCH_STATUS_SUCCESS: Successfully closed the database.
+ *
+ * NOTMUCH_STATUS_XAPIAN_EXCEPTION: A Xapian exception occurred; the
+ * database has been closed but there are no guarantees the
+ * changes to the database, if any, have been flushed to disk.
  */
-void
+notmuch_status_t
 notmuch_database_close (notmuch_database_t *database);
 
 /**
@@ -317,8 +325,11 @@ notmuch_database_compact (const char* path,
 /**
  * Destroy the notmuch database, closing it if necessary and freeing
  * all associated resources.
+ *
+ * Return value as in notmuch_database_close if the database was open;
+ * notmuch_database_destroy itself has no failure modes.
  */
-void
+notmuch_status_t
 notmuch_database_destroy (notmuch_database_t *database);
 
 /**
-- 
1.8.4

___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


[PATCH v2 02/10] lib: bump soname

2014-04-16 Thread Peter Wang
Adding return values to notmuch_database_close and
notmuch_database_destroy may require bumping the soname.
---
 lib/Makefile.local | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/Makefile.local b/lib/Makefile.local
index c56cba9..4120390 100644
--- a/lib/Makefile.local
+++ b/lib/Makefile.local
@@ -5,7 +5,7 @@
 # the library interface, (such as the deletion of an API or a major
 # semantic change that breaks formerly functioning code).
 #
-LIBNOTMUCH_VERSION_MAJOR = 3
+LIBNOTMUCH_VERSION_MAJOR = 4
 
 # The minor version of the library interface. This should be incremented at
 # the time of release for any additions to the library interface,
-- 
1.8.4

___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


[PATCH v2 00/10] add insert --must-index option

2014-04-16 Thread Peter Wang
Follow up to id:1374365254-13227-1-git-send-email-noval...@gmail.com
The main changes are to take into account failures during
tagging and flushing of the database.

I took Jani's patch id:1390152046-6509-1-git-send-email-j...@nikula.org
without modification.

The soname bump is included in case it is required.

The python/go/ruby changes are untested.


Jani Nikula (1):
  lib: add return status to database close and destroy

Peter Wang (9):
  lib: bump soname
  python: handle return status of database close and destroy
  go: add return status to database close method
  ruby: handle return status of database close
  cli: refactor insert
  cli: indicate insert failure mode in exit status
  cli: add insert --must-index option
  test: test insert --must-index
  man: update insert documentation

 bindings/go/src/notmuch/notmuch.go  |   4 +-
 bindings/python/notmuch/database.py |  12 ++--
 bindings/ruby/database.c|   4 +-
 doc/man1/notmuch-insert.rst |  24 +--
 lib/Makefile.local  |   2 +-
 lib/database.cc |  30 ++--
 lib/notmuch.h   |  15 +++-
 notmuch-insert.c| 134 +---
 test/T070-insert.sh |  32 +++--
 9 files changed, 176 insertions(+), 81 deletions(-)

-- 
1.8.4

___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


Re: [WIP PATCH] emacs: hello: bugfix for saved searches defcustom

2014-04-16 Thread David Bremner
Mark Walters  writes:

> ---
> Hi
>
> David found a bug in the recent notmuch hello saved searches and
> reduced to a small test case. The problem occurs if the user sets
> notmuch-saved-searches and then loads notmuch. The reason is that the
> defcustom calls some utility functions and these need to be defined
> (not just declared) when the defcustom is encountered.
>
> This patch moves the code around so that they are defined first. I
> have marked the patch WIP as I am not sure what the best reordering
> is, and we may want to rename some functions which have changed file
> for namespace reasons.
>
> Anyway this fixes the test case. If it fixes the original bug too then
> I will provide a better version.

Hi Mark;

This fixes the problem for me.

Thanks for your efforts,

d
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


Synchronization success stories?

2014-04-16 Thread Tilmann Singer
David Bremner  writes:
>> With a reused ssh connection this is sufficiently fast for me (<2s).  If
>> there is interest I can clean up the script of hardcoded paths etc. and
>> put it on github.
>
> Sure, sounds at least as good as what I am using. Also, syncmaildir
> recently did something pretty annoying for upward compatibility, so in
> the long term I'm interested in alternatives.

I've put the ruby script with a README on github:
https://github.com/til/notmuch-rsync


Til
-- next part --
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 489 bytes
Desc: not available
URL: 
<http://notmuchmail.org/pipermail/notmuch/attachments/20140416/0249247e/attachment.pgp>