From b400d57ce6f4f02896aff3ff419a6d7e88039d97 Mon Sep 17 00:00:00 2001 From: Tomi Ollila Date: Wed, 16 May 2012 10:21:47 +0300 Subject: [PATCH 01/15] NEWS: Dropped old 'Reply to sender' section 'Reply to sender' section was 0.12 news which was accidentally duplicated in 0.13 news --- NEWS | 7 ------- 1 file changed, 7 deletions(-) diff --git a/NEWS b/NEWS index 69a72030..9a690cb7 100644 --- a/NEWS +++ b/NEWS @@ -4,13 +4,6 @@ Notmuch 0.13 (2012-xx-xx) Command-Line Interface ---------------------- -Reply to sender - - "notmuch reply" has gained the ability to create a reply template - for replying just to the sender of the message, in addition to reply - to all. The feature is available through the new command line option - --reply-to=(all|sender). - JSON reply format "notmuch reply" can now produce JSON output that contains the headers From be63e154232a349c2c82c48c300cb5b99c76c491 Mon Sep 17 00:00:00 2001 From: Tomi Ollila Date: Wed, 16 May 2012 10:21:48 +0300 Subject: [PATCH 02/15] NEWS: Changed 0.13 release date in NEWS file to 2012-05-15 --- NEWS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NEWS b/NEWS index 9a690cb7..970aa40f 100644 --- a/NEWS +++ b/NEWS @@ -1,4 +1,4 @@ -Notmuch 0.13 (2012-xx-xx) +Notmuch 0.13 (2012-05-15) ========================= Command-Line Interface From b9faffac126d57d9fc6a3493583b49c67efa8621 Mon Sep 17 00:00:00 2001 From: Tomi Ollila Date: Wed, 16 May 2012 10:21:49 +0300 Subject: [PATCH 03/15] NEWS: Insert markdown formatting commands in 0.13 section text NEWS entries in section 0.13 is brought consistent with rest of the NEWS file. --- NEWS | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/NEWS b/NEWS index 970aa40f..ad4859df 100644 --- a/NEWS +++ b/NEWS @@ -6,12 +6,12 @@ Command-Line Interface JSON reply format - "notmuch reply" can now produce JSON output that contains the headers + `notmuch reply` can now produce JSON output that contains the headers for a reply message and full information about the original message begin replied to. This allows MUAs to create replies intelligently. For example, an MUA that can parse HTML might quote HTML parts. - Calling notmuch reply with --format=json imposes the restriction that + Calling notmuch reply with `--format=json` imposes the restriction that only a single message is returned by the search, as replying to multiple messages does not have a well-defined behavior. The default retains its current behavior for multiple message replies. @@ -19,24 +19,24 @@ JSON reply format Tag exclusion Tags can be automatically excluded from search results by adding them - to the new 'search.exclude_tags' option in the Notmuch config file. + to the new `search.exclude_tags` option in the Notmuch config file. This behaviour can be overridden by explicitly including an excluded tag in your query, for example: - notmuch search $your_query and tag:$excluded_tag + notmuch search $your_query and tag:$excluded_tag - Existing users will probably want to run "notmuch setup" again to add + Existing users will probably want to run `notmuch setup` again to add the new well-commented [search] section to the configuration file. For new configurations, accepting the default setting will cause the tags "deleted" and "spam" to be excluded, equivalent to running: - notmuch config set search.exclude_tags deleted spam + notmuch config set search.exclude_tags deleted spam Raw show format changes - The output of show --format=raw has changed for multipart and + The output of show `--format=raw` has changed for multipart and message parts. Previously, the output was a mash of somewhat-parsed headers and transfer-decoded bodies. Now, such parts are reproduced faithfully from the original source. Message parts (which includes @@ -47,7 +47,7 @@ Raw show format changes Listing configuration items - The new "config list" command prints out all configuration items and + The new `config list` command prints out all configuration items and their values. Emacs Interface @@ -57,7 +57,7 @@ Changes to tagging interface The user-facing tagging functions in the Emacs interface have been normalized across all notmuch modes. The tagging functions are now - 'notmuch-search-tag' in search-mode, and 'notmuch-show-tag' in + notmuch-search-tag in search-mode, and notmuch-show-tag in show-mode. They accept a string representing a single tag change, or a list of tag changes. See 'M-x describe-function notmuch-tag' for more information. @@ -76,11 +76,11 @@ Reply improvement using the JSON format New add-on tool: notmuch-mutt ----------------------------- -The new contrib/ tool "notmuch-mutt" provides Notmuch integration for +The new contrib/ tool `notmuch-mutt` provides Notmuch integration for the Mutt mail user agent. Using it, Mutt users can perform mail search, thread reconstruction, and mail tagging/untagging without leaving Mutt. notmuch-mutt, formerly distributed under the name -"mutt-notmuch" by Stefano Zacchiroli, will be maintained as a notmuch +`mutt-notmuch` by Stefano Zacchiroli, will be maintained as a notmuch contrib/ from now on. Library changes @@ -89,18 +89,18 @@ Library changes The API changes detailed below break binary and source compatibility, so libnotmuch has been bumped to version 3.0.0. -The function notmuch_database_close has been split into -notmuch_database_close and notmuch_database_destroy +The function `notmuch_database_close` has been split into +`notmuch_database_close` and `notmuch_database_destroy` This makes it possible for long running programs to close the xapian database and thus release the lock associated with it without destroying the data structures obtained from it. -notmuch_database_open, notmuch_database_create, and -notmuch_database_get_directory now return errors +`notmuch_database_open`, `notmuch_database_create`, and +`notmuch_database_get_directory` now return errors The type signatures of these functions have changed so that the - functions now return a notmuch_status_t and take an out-argument for + functions now return a `notmuch_status_t` and take an out-argument for returning the new database object or directory object. go bindings changes @@ -108,7 +108,7 @@ go bindings changes Go 1 compatibility - The go bindings and the notmuch-addrlookup utility are now + The go bindings and the `notmuch-addrlookup` utility are now compatible with go 1. Notmuch 0.12 (2012-03-20) From d2d476b014076eec69018b5f584c27fc20508313 Mon Sep 17 00:00:00 2001 From: Tomi Ollila Date: Wed, 16 May 2012 10:21:50 +0300 Subject: [PATCH 04/15] NEWS: Capitalized go bindings changes title Align 'Go bindings changes' title capitalization to rest of the file --- NEWS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NEWS b/NEWS index ad4859df..668281c5 100644 --- a/NEWS +++ b/NEWS @@ -103,7 +103,7 @@ The function `notmuch_database_close` has been split into functions now return a `notmuch_status_t` and take an out-argument for returning the new database object or directory object. -go bindings changes +Go bindings changes ------------------- Go 1 compatibility From d15a5e38a90dbf78619cb11bbbb61f0cda38f475 Mon Sep 17 00:00:00 2001 From: David Bremner Date: Wed, 16 May 2012 13:49:23 -0300 Subject: [PATCH 05/15] debian: fix typo in changelog. the path for NEWS was wrong (cherry picked from commit b9520ef033ea9ae54507f94f7258641a6a1ad2e6) --- debian/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index 2f2357ca..720573d4 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,6 +1,6 @@ notmuch (0.13-1) unstable; urgency=low - * New upstream release. See /usr/share/doc/NEWS.gz for changes. + * New upstream release. See /usr/share/doc/notmuch/NEWS.gz for changes. [ Stefano Zacchiroli ] * Recommend all notmuch UI (including notmuch-mutt) as alternatives, From 70ca3444c75beaa693fcac411dd6a2819bd4341e Mon Sep 17 00:00:00 2001 From: Tomi Ollila Date: Sun, 20 May 2012 19:58:14 +0300 Subject: [PATCH 06/15] emacs: use 'gnus-decoded in notmuch-mm-display-part-inline () When mail message is read from emacs, the message structure obtained may contain parts which have content included (`text/plain` for example) and other parts where content is not included (`text/html` for example). In case content is included, the string is already available in emacs' internal format and therefore mm-... functions should not attempt to do further decoding for the data in temp buffer provided for it. Currently when reply buffer is created, notmuch-mm-display-part-inline () is used to provided quoted reply content. This change makes the mm-... functions called by it use 'gnus-decoded as charset whenever the content is already available. File .../emacs-23.3/lisp/gnus/mm-uu.el mentions: "`gnus-decoded' is a fake charset, which means no further decoding." --- emacs/notmuch-lib.el | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/emacs/notmuch-lib.el b/emacs/notmuch-lib.el index 7fa441af..e99b48d1 100644 --- a/emacs/notmuch-lib.el +++ b/emacs/notmuch-lib.el @@ -244,7 +244,12 @@ the given type." current buffer, if possible." (let ((display-buffer (current-buffer))) (with-temp-buffer - (let* ((charset (plist-get part :content-charset)) + ;; In case there is :content, the content string is already converted + ;; into emacs internal format. `gnus-decoded' is a fake charset, + ;; which means no further decoding (to be done by mm- functions). + (let* ((charset (if (plist-member part :content) + 'gnus-decoded + (plist-get part :content-charset))) (handle (mm-make-handle (current-buffer) `(,content-type (charset . ,charset))))) ;; If the user wants the part inlined, insert the content and ;; test whether we are able to inline it (which includes both From f69314fbd37f403a395b7c1c44595c8f696b05b7 Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Fri, 18 May 2012 00:13:34 -0400 Subject: [PATCH 07/15] lib: Make directory document creation optional for _notmuch_directory_create Previously this function would create directory documents if they didn't exist. As a result, it could only be used on writable databases. This adds an argument to make creation optional and to make this function work on read-only databases. We use a flag argument to avoid a bare boolean and to permit future expansion. Both callers have been updated, but currently retain the old behavior. We'll take advantage of the new argument in the following patches. --- lib/database.cc | 6 +++--- lib/directory.cc | 33 ++++++++++++++++++++++++++++----- lib/notmuch-private.h | 8 ++++++++ 3 files changed, 39 insertions(+), 8 deletions(-) diff --git a/lib/database.cc b/lib/database.cc index f8c4a7d1..df996a9a 100644 --- a/lib/database.cc +++ b/lib/database.cc @@ -956,7 +956,7 @@ notmuch_database_upgrade (notmuch_database_t *notmuch, document.get_value (NOTMUCH_VALUE_TIMESTAMP)); directory = _notmuch_directory_create (notmuch, term.c_str() + 10, - &status); + NOTMUCH_FIND_CREATE, &status); notmuch_directory_set_mtime (directory, mtime); notmuch_directory_destroy (directory); } @@ -1210,7 +1210,7 @@ _notmuch_database_find_directory_id (notmuch_database_t *notmuch, return NOTMUCH_STATUS_SUCCESS; } - directory = _notmuch_directory_create (notmuch, path, &status); + directory = _notmuch_directory_create (notmuch, path, NOTMUCH_FIND_CREATE, &status); if (status) { *directory_id = -1; return status; @@ -1320,7 +1320,7 @@ notmuch_database_get_directory (notmuch_database_t *notmuch, return NOTMUCH_STATUS_READ_ONLY_DATABASE; try { - *directory = _notmuch_directory_create (notmuch, path, &status); + *directory = _notmuch_directory_create (notmuch, path, NOTMUCH_FIND_CREATE, &status); } catch (const Xapian::Error &error) { fprintf (stderr, "A Xapian exception occurred getting directory: %s.\n", error.get_msg().c_str()); diff --git a/lib/directory.cc b/lib/directory.cc index 70e1693e..83bb19bc 100644 --- a/lib/directory.cc +++ b/lib/directory.cc @@ -82,28 +82,41 @@ find_directory_document (notmuch_database_t *notmuch, return NOTMUCH_PRIVATE_STATUS_SUCCESS; } +/* Find or create a directory document. + * + * 'path' should be a path relative to the path of 'database', or else + * should be an absolute path with initial components that match the + * path of 'database'. + * + * If (flags & NOTMUCH_FIND_CREATE), then the directory document will + * be created if it does not exist. Otherwise, if the directory + * document does not exist, *status_ret is set to + * NOTMUCH_STATUS_SUCCESS and this returns NULL. + */ notmuch_directory_t * _notmuch_directory_create (notmuch_database_t *notmuch, const char *path, + notmuch_find_flags_t flags, notmuch_status_t *status_ret) { Xapian::WritableDatabase *db; notmuch_directory_t *directory; notmuch_private_status_t private_status; const char *db_path; + notmuch_bool_t create = (flags & NOTMUCH_FIND_CREATE); *status_ret = NOTMUCH_STATUS_SUCCESS; path = _notmuch_database_relative_path (notmuch, path); - if (notmuch->mode == NOTMUCH_DATABASE_MODE_READ_ONLY) + if (create && notmuch->mode == NOTMUCH_DATABASE_MODE_READ_ONLY) INTERNAL_ERROR ("Failure to ensure database is writable"); - db = static_cast (notmuch->xapian_db); - directory = talloc (notmuch, notmuch_directory_t); - if (unlikely (directory == NULL)) + if (unlikely (directory == NULL)) { + *status_ret = NOTMUCH_STATUS_OUT_OF_MEMORY; return NULL; + } directory->notmuch = notmuch; @@ -122,6 +135,13 @@ _notmuch_directory_create (notmuch_database_t *notmuch, directory->document_id = directory->doc.get_docid (); if (private_status == NOTMUCH_PRIVATE_STATUS_NO_DOCUMENT_FOUND) { + if (!create) { + notmuch_directory_destroy (directory); + directory = NULL; + *status_ret = NOTMUCH_STATUS_SUCCESS; + goto DONE; + } + void *local = talloc_new (directory); const char *parent, *basename; Xapian::docid parent_id; @@ -145,6 +165,8 @@ _notmuch_directory_create (notmuch_database_t *notmuch, directory->doc.add_value (NOTMUCH_VALUE_TIMESTAMP, Xapian::sortable_serialise (0)); + db = static_cast (notmuch->xapian_db); + directory->document_id = _notmuch_database_generate_doc_id (notmuch); db->replace_document (directory->document_id, directory->doc); talloc_free (local); @@ -158,10 +180,11 @@ _notmuch_directory_create (notmuch_database_t *notmuch, error.get_msg().c_str()); notmuch->exception_reported = TRUE; notmuch_directory_destroy (directory); + directory = NULL; *status_ret = NOTMUCH_STATUS_XAPIAN_EXCEPTION; - return NULL; } + DONE: if (db_path != path) free ((char *) db_path); diff --git a/lib/notmuch-private.h b/lib/notmuch-private.h index 3886e0ca..538274f4 100644 --- a/lib/notmuch-private.h +++ b/lib/notmuch-private.h @@ -146,6 +146,13 @@ typedef enum _notmuch_private_status { : \ (notmuch_status_t) private_status) +/* Flags shared by various lookup functions. */ +typedef enum _notmuch_find_flags { + /* If set, create the necessary document (or documents) if they + * are missing. Requires a read/write database. */ + NOTMUCH_FIND_CREATE = 1<<0, +} notmuch_find_flags_t; + typedef struct _notmuch_doc_id_set notmuch_doc_id_set_t; typedef struct _notmuch_string_list notmuch_string_list_t; @@ -206,6 +213,7 @@ _notmuch_database_filename_to_direntry (void *ctx, notmuch_directory_t * _notmuch_directory_create (notmuch_database_t *notmuch, const char *path, + notmuch_find_flags_t flags, notmuch_status_t *status_ret); unsigned int From 0c950146a14fa2bb0a0bf542073b2cdca141afd1 Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Fri, 18 May 2012 00:13:35 -0400 Subject: [PATCH 08/15] lib: Perform the same transformation to _notmuch_database_find_directory_id Now _notmuch_database_find_directory_id takes a flags argument, which it passes through to _notmuch_directory_create and can indicate if the directory does not exist. Again, callers have been updated, but retain their original behavior. --- lib/database.cc | 14 +++++++++++--- lib/directory.cc | 8 +++++++- lib/notmuch-private.h | 1 + 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/lib/database.cc b/lib/database.cc index df996a9a..716982d0 100644 --- a/lib/database.cc +++ b/lib/database.cc @@ -1197,9 +1197,17 @@ _notmuch_database_split_path (void *ctx, return NOTMUCH_STATUS_SUCCESS; } +/* Find the document ID of the specified directory. + * + * If (flags & NOTMUCH_FIND_CREATE), a new directory document will be + * created if one does not exist for 'path'. Otherwise, if the + * directory document does not exist, this sets *directory_id to + * ((unsigned int)-1) and returns NOTMUCH_STATUS_SUCCESS. + */ notmuch_status_t _notmuch_database_find_directory_id (notmuch_database_t *notmuch, const char *path, + notmuch_find_flags_t flags, unsigned int *directory_id) { notmuch_directory_t *directory; @@ -1210,8 +1218,8 @@ _notmuch_database_find_directory_id (notmuch_database_t *notmuch, return NOTMUCH_STATUS_SUCCESS; } - directory = _notmuch_directory_create (notmuch, path, NOTMUCH_FIND_CREATE, &status); - if (status) { + directory = _notmuch_directory_create (notmuch, path, flags, &status); + if (status || !directory) { *directory_id = -1; return status; } @@ -1260,7 +1268,7 @@ _notmuch_database_filename_to_direntry (void *ctx, if (status) return status; - status = _notmuch_database_find_directory_id (notmuch, directory, + status = _notmuch_database_find_directory_id (notmuch, directory, NOTMUCH_FIND_CREATE, &directory_id); if (status) return status; diff --git a/lib/directory.cc b/lib/directory.cc index 83bb19bc..6a3ffed7 100644 --- a/lib/directory.cc +++ b/lib/directory.cc @@ -153,7 +153,13 @@ _notmuch_directory_create (notmuch_database_t *notmuch, _notmuch_database_split_path (local, path, &parent, &basename); - _notmuch_database_find_directory_id (notmuch, parent, &parent_id); + *status_ret = _notmuch_database_find_directory_id ( + notmuch, parent, NOTMUCH_FIND_CREATE, &parent_id); + if (*status_ret) { + notmuch_directory_destroy (directory); + directory = NULL; + goto DONE; + } if (basename) { term = talloc_asprintf (local, "%s%u:%s", diff --git a/lib/notmuch-private.h b/lib/notmuch-private.h index 538274f4..a36549d2 100644 --- a/lib/notmuch-private.h +++ b/lib/notmuch-private.h @@ -195,6 +195,7 @@ _notmuch_database_find_unique_doc_id (notmuch_database_t *notmuch, notmuch_status_t _notmuch_database_find_directory_id (notmuch_database_t *database, const char *path, + notmuch_find_flags_t flags, unsigned int *directory_id); const char * From 67ae2377a9ec2da296a2e012352f962664a4d1a8 Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Fri, 18 May 2012 00:13:36 -0400 Subject: [PATCH 09/15] lib: Perform the same transformation to _notmuch_database_filename_to_direntry Now _notmuch_database_filename_to_direntry takes a flags argument and can indicate if the necessary directory documents do not exist. Again, callers have been updated, but retain their original behavior. --- lib/database.cc | 17 +++++++++++------ lib/message.cc | 9 ++++----- lib/notmuch-private.h | 1 + 3 files changed, 16 insertions(+), 11 deletions(-) diff --git a/lib/database.cc b/lib/database.cc index 716982d0..b4c76b4e 100644 --- a/lib/database.cc +++ b/lib/database.cc @@ -1248,13 +1248,16 @@ _notmuch_database_get_directory_path (void *ctx, * database path), return a new string (with 'ctx' as the talloc * owner) suitable for use as a direntry term value. * - * The necessary directory documents will be created in the database - * as needed. + * If (flags & NOTMUCH_FIND_CREATE), the necessary directory documents + * will be created in the database as needed. Otherwise, if the + * necessary directory documents do not exist, this sets + * *direntry to NULL and returns NOTMUCH_STATUS_SUCCESS. */ notmuch_status_t _notmuch_database_filename_to_direntry (void *ctx, notmuch_database_t *notmuch, const char *filename, + notmuch_find_flags_t flags, char **direntry) { const char *relative, *directory, *basename; @@ -1268,10 +1271,12 @@ _notmuch_database_filename_to_direntry (void *ctx, if (status) return status; - status = _notmuch_database_find_directory_id (notmuch, directory, NOTMUCH_FIND_CREATE, + status = _notmuch_database_find_directory_id (notmuch, directory, flags, &directory_id); - if (status) + if (status || directory_id == (unsigned int)-1) { + *direntry = NULL; return status; + } *direntry = talloc_asprintf (ctx, "%u:%s", directory_id, basename); @@ -1892,8 +1897,8 @@ notmuch_database_find_message_by_filename (notmuch_database_t *notmuch, local = talloc_new (notmuch); try { - status = _notmuch_database_filename_to_direntry (local, notmuch, - filename, &direntry); + status = _notmuch_database_filename_to_direntry ( + local, notmuch, filename, NOTMUCH_FIND_CREATE, &direntry); if (status) goto DONE; diff --git a/lib/message.cc b/lib/message.cc index 00754254..8d552f1f 100644 --- a/lib/message.cc +++ b/lib/message.cc @@ -495,9 +495,8 @@ _notmuch_message_add_filename (notmuch_message_t *message, if (status) return status; - status = _notmuch_database_filename_to_direntry (local, - message->notmuch, - filename, &direntry); + status = _notmuch_database_filename_to_direntry ( + local, message->notmuch, filename, NOTMUCH_FIND_CREATE, &direntry); if (status) return status; @@ -541,8 +540,8 @@ _notmuch_message_remove_filename (notmuch_message_t *message, notmuch_status_t status; Xapian::TermIterator i, last; - status = _notmuch_database_filename_to_direntry (local, message->notmuch, - filename, &direntry); + status = _notmuch_database_filename_to_direntry ( + local, message->notmuch, filename, NOTMUCH_FIND_CREATE, &direntry); if (status) return status; diff --git a/lib/notmuch-private.h b/lib/notmuch-private.h index a36549d2..34f7ac7c 100644 --- a/lib/notmuch-private.h +++ b/lib/notmuch-private.h @@ -207,6 +207,7 @@ notmuch_status_t _notmuch_database_filename_to_direntry (void *ctx, notmuch_database_t *notmuch, const char *filename, + notmuch_find_flags_t flags, char **direntry); /* directory.cc */ From fe1ca1410423d99db09543f4a97bc2ba0c6ade81 Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Fri, 18 May 2012 00:13:37 -0400 Subject: [PATCH 10/15] lib: Make notmuch_database_get_directory return NULL if the directory is not found Using the new support from _notmuch_directory_create, this makes notmuch_database_get_directory a read-only operation that simply returns the directory object if it exists or NULL otherwise. This also means that notmuch_database_get_directory can work on read-only databases. This change breaks the directory mtime workaround in notmuch-new.c by fixing the exact issue it was working around. This permits mtime update races to prevent scans of changed directories, which non-deterministically breaks a few tests. The next patch fixes this. --- lib/database.cc | 7 ++----- lib/notmuch-private.h | 3 +++ lib/notmuch.h | 10 ++-------- 3 files changed, 7 insertions(+), 13 deletions(-) diff --git a/lib/database.cc b/lib/database.cc index b4c76b4e..e27a0e16 100644 --- a/lib/database.cc +++ b/lib/database.cc @@ -1328,12 +1328,9 @@ notmuch_database_get_directory (notmuch_database_t *notmuch, return NOTMUCH_STATUS_NULL_POINTER; *directory = NULL; - /* XXX Handle read-only databases properly */ - if (notmuch->mode == NOTMUCH_DATABASE_MODE_READ_ONLY) - return NOTMUCH_STATUS_READ_ONLY_DATABASE; - try { - *directory = _notmuch_directory_create (notmuch, path, NOTMUCH_FIND_CREATE, &status); + *directory = _notmuch_directory_create (notmuch, path, + NOTMUCH_FIND_LOOKUP, &status); } catch (const Xapian::Error &error) { fprintf (stderr, "A Xapian exception occurred getting directory: %s.\n", error.get_msg().c_str()); diff --git a/lib/notmuch-private.h b/lib/notmuch-private.h index 34f7ac7c..bfb41116 100644 --- a/lib/notmuch-private.h +++ b/lib/notmuch-private.h @@ -148,6 +148,9 @@ typedef enum _notmuch_private_status { /* Flags shared by various lookup functions. */ typedef enum _notmuch_find_flags { + /* Lookup without creating any documents. This is the default + * behavior. */ + NOTMUCH_FIND_LOOKUP = 0, /* If set, create the necessary document (or documents) if they * are missing. Requires a read/write database. */ NOTMUCH_FIND_CREATE = 1<<0, diff --git a/lib/notmuch.h b/lib/notmuch.h index bbb17e4a..3633bedd 100644 --- a/lib/notmuch.h +++ b/lib/notmuch.h @@ -300,10 +300,8 @@ notmuch_database_end_atomic (notmuch_database_t *notmuch); * (see notmuch_database_get_path), or else should be an absolute path * with initial components that match the path of 'database'. * - * Note: Currently this will create the directory object if it doesn't - * exist. In the future, when a directory object does not exist this - * will return NOTMUCH_STATUS_SUCCESS and set *directory to NULL. - * Callers should be prepared for this. + * If this directory object does not exist in the database, this + * returns NOTMUCH_STATUS_SUCCESS and sets *directory to NULL. * * Return value: * @@ -313,10 +311,6 @@ notmuch_database_end_atomic (notmuch_database_t *notmuch); * * NOTMUCH_STATUS_XAPIAN_EXCEPTION: A Xapian exception occurred; * directory not retrieved. - * - * NOTMUCH_STATUS_READ_ONLY_DATABASE: Database was opened in read-only - * mode so the directory cannot be created (this case will be - * removed in the future). */ notmuch_status_t notmuch_database_get_directory (notmuch_database_t *database, From 3f3c446c40e6e7661620645f1c152968b5590f10 Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Fri, 18 May 2012 00:13:38 -0400 Subject: [PATCH 11/15] new: Remove workaround for detecting newly created directory objects Previously, notmuch_database_get_directory did not indicate whether or not the returned directory object was newly created, which required a workaround to distinguish newly created directory objects with no child messages from directory objects that had no mtime set but did have child messages. Now that notmuch_database_get_directory distinguishes whether or not the directory object exists in the database, this workaround is no longer necessary. --- notmuch-new.c | 36 +++++++----------------------------- 1 file changed, 7 insertions(+), 29 deletions(-) diff --git a/notmuch-new.c b/notmuch-new.c index a3a8bece..72dd558d 100644 --- a/notmuch-new.c +++ b/notmuch-new.c @@ -256,7 +256,7 @@ add_files_recursive (notmuch_database_t *notmuch, notmuch_filenames_t *db_subdirs = NULL; time_t stat_time; struct stat st; - notmuch_bool_t is_maildir, new_directory; + notmuch_bool_t is_maildir; const char **tag; if (stat (path, &st)) { @@ -281,33 +281,12 @@ add_files_recursive (notmuch_database_t *notmuch, } db_mtime = directory ? notmuch_directory_get_mtime (directory) : 0; - new_directory = db_mtime ? FALSE : TRUE; - - /* XXX This is a temporary workaround. If we don't update the - * database mtime until after processing messages in this - * directory, then a 0 mtime is *not* sufficient to indicate that - * this directory has no messages or subdirs in the database (for - * example, if an earlier run skipped the mtime update because - * fs_mtime == stat_time, or was interrupted before updating the - * mtime at the end). To address this, we record a (bogus) - * non-zero value before processing any child messages so that a - * later run won't mistake this for a new directory (and, for - * example, fail to detect removed files and subdirs). - * - * A better solution would be for notmuch_database_get_directory - * to indicate if it really created a new directory or not, either - * by a new out-argument, or by recording this information and - * providing an accessor. - */ - if (new_directory && directory) - notmuch_directory_set_mtime (directory, -1); - /* If the database knows about this directory, then we sort based * on strcmp to match the database sorting. Otherwise, we can do * inode-based sorting for faster filesystem operation. */ num_fs_entries = scandir (path, &fs_entries, 0, - new_directory ? - dirent_sort_inode : dirent_sort_strcmp_name); + directory ? + dirent_sort_strcmp_name : dirent_sort_inode); if (num_fs_entries == -1) { fprintf (stderr, "Error opening directory %s: %s\n", @@ -376,13 +355,12 @@ add_files_recursive (notmuch_database_t *notmuch, * being discovered until the clock catches up and the directory * is modified again). */ - if (fs_mtime == db_mtime) + if (directory && fs_mtime == db_mtime) goto DONE; - /* new_directory means a directory that the database has never - * seen before. In that case, we can simply leave db_files and - * db_subdirs NULL. */ - if (!new_directory) { + /* If the database has never seen this directory before, we can + * simply leave db_files and db_subdirs NULL. */ + if (directory) { db_files = notmuch_directory_get_child_files (directory); db_subdirs = notmuch_directory_get_child_directories (directory); } From f1f1e3963910a845e2bc0ebe6b9b5c852b4564eb Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Fri, 18 May 2012 00:13:39 -0400 Subject: [PATCH 12/15] python: Update Database.get_directory documentation notmuch_database_get_directory no longer returns an error for read-only databases, so remove ReadOnlyDatabaseError from the list of get_directory exceptions. --- bindings/python/notmuch/database.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/bindings/python/notmuch/database.py b/bindings/python/notmuch/database.py index 797554d3..ff89818b 100644 --- a/bindings/python/notmuch/database.py +++ b/bindings/python/notmuch/database.py @@ -346,7 +346,6 @@ class Database(object): def get_directory(self, path): """Returns a :class:`Directory` of path, - (creating it if it does not exist(?)) :param path: An unicode string containing the path relative to the path of database (see :meth:`get_path`), or else should be an absolute @@ -354,8 +353,6 @@ class Database(object): :returns: :class:`Directory` or raises an exception. :raises: :exc:`FileError` if path is not relative database or absolute with initial components same as database. - :raises: :exc:`ReadOnlyDatabaseError` if the database has not been - opened in read-write mode """ self._assert_db_is_initialized() From cdd698f96976dc8fc43efd19c452d0fca48e2618 Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Fri, 18 May 2012 00:13:40 -0400 Subject: [PATCH 13/15] lib: Make notmuch_database_find_message_by_filename not crash on read-only databases Previously, _notmuch_database_filename_to_direntry would abort with an internal error when called on a read-only database. Now that creating the directory document is optional, notmuch_database_find_message_by_filename can disable directory document creation (as it should) and, as a result, not abort on read-only databases. --- lib/database.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/database.cc b/lib/database.cc index e27a0e16..761dc1a2 100644 --- a/lib/database.cc +++ b/lib/database.cc @@ -1895,8 +1895,8 @@ notmuch_database_find_message_by_filename (notmuch_database_t *notmuch, try { status = _notmuch_database_filename_to_direntry ( - local, notmuch, filename, NOTMUCH_FIND_CREATE, &direntry); - if (status) + local, notmuch, filename, NOTMUCH_FIND_LOOKUP, &direntry); + if (status || !direntry) goto DONE; term = talloc_asprintf (local, "%s%s", prefix, direntry); From 54508eb78d1c5c1c67c8b220cf2bd826af1203a9 Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Fri, 18 May 2012 00:13:41 -0400 Subject: [PATCH 14/15] python: Remove find_message_by_filename workaround Now that notmuch_database_find_message_by_filename works on read-only databases, remove the workaround that disabled it on read-write databases. This also adds a regression test for find_message_by_filename. --- bindings/python/notmuch/database.py | 9 --------- test/python | 8 ++++++++ 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/bindings/python/notmuch/database.py b/bindings/python/notmuch/database.py index ff89818b..e5c74cfb 100644 --- a/bindings/python/notmuch/database.py +++ b/bindings/python/notmuch/database.py @@ -526,19 +526,10 @@ class Database(object): retry. :raises: :exc:`NotInitializedError` if the database was not intitialized. - :raises: :exc:`ReadOnlyDatabaseError` if the database has not been - opened in read-write mode *Added in notmuch 0.9*""" self._assert_db_is_initialized() - # work around libnotmuch calling exit(3), see - # id:20120221002921.8534.57091@thinkbox.jade-hamburg.de - # TODO: remove once this issue is resolved - if self.mode != Database.MODE.READ_WRITE: - raise ReadOnlyDatabaseError('The database has to be opened in ' - 'read-write mode for get_directory') - msg_p = NotmuchMessageP() status = Database._find_message_by_filename(self._db, _str(filename), byref(msg_p)) diff --git a/test/python b/test/python index 6018c2d0..3f03a2e3 100755 --- a/test/python +++ b/test/python @@ -28,4 +28,12 @@ EOF notmuch search --sort=oldest-first --output=messages tag:inbox | sed s/^id:// > EXPECTED test_expect_equal_file OUTPUT EXPECTED +test_begin_subtest "get non-existent file" +test_python < Date: Fri, 18 May 2012 00:13:42 -0400 Subject: [PATCH 15/15] lib: Don't needlessly create directory docs in _notmuch_message_remove_filename Previously, if passed a filename with a directory that did not exist in the database, _notmuch_message_remove_filename would needlessly create that directory document. Fix it so that doesn't happen. --- lib/message.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/message.cc b/lib/message.cc index 8d552f1f..67875065 100644 --- a/lib/message.cc +++ b/lib/message.cc @@ -541,8 +541,8 @@ _notmuch_message_remove_filename (notmuch_message_t *message, Xapian::TermIterator i, last; status = _notmuch_database_filename_to_direntry ( - local, message->notmuch, filename, NOTMUCH_FIND_CREATE, &direntry); - if (status) + local, message->notmuch, filename, NOTMUCH_FIND_LOOKUP, &direntry); + if (status || !direntry) return status; /* Unlink this file from its parent directory. */