Merge branch 'release'

merge 0.13.1 bugfix patches back to master, fixes for emacs reply and
spurious directory document creation.
This commit is contained in:
David Bremner 2012-05-23 22:48:16 -03:00
commit 6d44c5af65
10 changed files with 120 additions and 103 deletions

41
NEWS
View file

@ -1,24 +1,17 @@
Notmuch 0.13 (2012-xx-xx) Notmuch 0.13 (2012-05-15)
========================= =========================
Command-Line Interface 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 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 for a reply message and full information about the original message
begin replied to. This allows MUAs to create replies intelligently. begin replied to. This allows MUAs to create replies intelligently.
For example, an MUA that can parse HTML might quote HTML parts. 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 only a single message is returned by the search, as replying to
multiple messages does not have a well-defined behavior. The default multiple messages does not have a well-defined behavior. The default
retains its current behavior for multiple message replies. retains its current behavior for multiple message replies.
@ -26,14 +19,14 @@ JSON reply format
Tag exclusion Tag exclusion
Tags can be automatically excluded from search results by adding them 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 This behaviour can be overridden by explicitly including an excluded
tag in your query, for example: 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. the new well-commented [search] section to the configuration file.
For new configurations, accepting the default setting will cause the For new configurations, accepting the default setting will cause the
@ -43,7 +36,7 @@ Tag exclusion
Raw show format changes 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 message parts. Previously, the output was a mash of somewhat-parsed
headers and transfer-decoded bodies. Now, such parts are reproduced headers and transfer-decoded bodies. Now, such parts are reproduced
faithfully from the original source. Message parts (which includes faithfully from the original source. Message parts (which includes
@ -54,7 +47,7 @@ Raw show format changes
Listing configuration items 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. their values.
Emacs Interface Emacs Interface
@ -64,7 +57,7 @@ Changes to tagging interface
The user-facing tagging functions in the Emacs interface have been The user-facing tagging functions in the Emacs interface have been
normalized across all notmuch modes. The tagging functions are now 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, show-mode. They accept a string representing a single tag change,
or a list of tag changes. See 'M-x describe-function notmuch-tag' or a list of tag changes. See 'M-x describe-function notmuch-tag'
for more information. for more information.
@ -83,11 +76,11 @@ Reply improvement using the JSON format
New add-on tool: notmuch-mutt 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 the Mutt mail user agent. Using it, Mutt users can perform mail
search, thread reconstruction, and mail tagging/untagging without search, thread reconstruction, and mail tagging/untagging without
leaving Mutt. notmuch-mutt, formerly distributed under the name 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. contrib/ from now on.
Library changes Library changes
@ -96,26 +89,26 @@ Library changes
The API changes detailed below break binary and source compatibility, The API changes detailed below break binary and source compatibility,
so libnotmuch has been bumped to version 3.0.0. so libnotmuch has been bumped to version 3.0.0.
The function notmuch_database_close has been split into The function `notmuch_database_close` has been split into
notmuch_database_close and notmuch_database_destroy `notmuch_database_close` and `notmuch_database_destroy`
This makes it possible for long running programs to close the xapian This makes it possible for long running programs to close the xapian
database and thus release the lock associated with it without database and thus release the lock associated with it without
destroying the data structures obtained from it. destroying the data structures obtained from it.
notmuch_database_open, notmuch_database_create, and `notmuch_database_open`, `notmuch_database_create`, and
notmuch_database_get_directory now return errors `notmuch_database_get_directory` now return errors
The type signatures of these functions have changed so that the 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. returning the new database object or directory object.
go bindings changes Go bindings changes
------------------- -------------------
Go 1 compatibility 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. compatible with go 1.
Notmuch 0.12 (2012-03-20) Notmuch 0.12 (2012-03-20)

View file

@ -347,7 +347,6 @@ class Database(object):
def get_directory(self, path): def get_directory(self, path):
"""Returns a :class:`Directory` of 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 :param path: An unicode string containing the path relative to the path
of database (see :meth:`get_path`), or else should be an absolute of database (see :meth:`get_path`), or else should be an absolute
@ -355,8 +354,6 @@ class Database(object):
:returns: :class:`Directory` or raises an exception. :returns: :class:`Directory` or raises an exception.
:raises: :exc:`FileError` if path is not relative database or absolute :raises: :exc:`FileError` if path is not relative database or absolute
with initial components same as database. 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() self._assert_db_is_initialized()
@ -530,19 +527,10 @@ class Database(object):
retry. retry.
:raises: :exc:`NotInitializedError` if the database was not :raises: :exc:`NotInitializedError` if the database was not
intitialized. intitialized.
:raises: :exc:`ReadOnlyDatabaseError` if the database has not been
opened in read-write mode
*Added in notmuch 0.9*""" *Added in notmuch 0.9*"""
self._assert_db_is_initialized() 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() msg_p = NotmuchMessageP()
status = Database._find_message_by_filename(self._db, _str(filename), status = Database._find_message_by_filename(self._db, _str(filename),
byref(msg_p)) byref(msg_p))

View file

@ -244,7 +244,12 @@ the given type."
current buffer, if possible." current buffer, if possible."
(let ((display-buffer (current-buffer))) (let ((display-buffer (current-buffer)))
(with-temp-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))))) (handle (mm-make-handle (current-buffer) `(,content-type (charset . ,charset)))))
;; If the user wants the part inlined, insert the content and ;; If the user wants the part inlined, insert the content and
;; test whether we are able to inline it (which includes both ;; test whether we are able to inline it (which includes both

View file

@ -956,7 +956,7 @@ notmuch_database_upgrade (notmuch_database_t *notmuch,
document.get_value (NOTMUCH_VALUE_TIMESTAMP)); document.get_value (NOTMUCH_VALUE_TIMESTAMP));
directory = _notmuch_directory_create (notmuch, term.c_str() + 10, directory = _notmuch_directory_create (notmuch, term.c_str() + 10,
&status); NOTMUCH_FIND_CREATE, &status);
notmuch_directory_set_mtime (directory, mtime); notmuch_directory_set_mtime (directory, mtime);
notmuch_directory_destroy (directory); notmuch_directory_destroy (directory);
} }
@ -1197,9 +1197,17 @@ _notmuch_database_split_path (void *ctx,
return NOTMUCH_STATUS_SUCCESS; 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_status_t
_notmuch_database_find_directory_id (notmuch_database_t *notmuch, _notmuch_database_find_directory_id (notmuch_database_t *notmuch,
const char *path, const char *path,
notmuch_find_flags_t flags,
unsigned int *directory_id) unsigned int *directory_id)
{ {
notmuch_directory_t *directory; notmuch_directory_t *directory;
@ -1210,8 +1218,8 @@ _notmuch_database_find_directory_id (notmuch_database_t *notmuch,
return NOTMUCH_STATUS_SUCCESS; return NOTMUCH_STATUS_SUCCESS;
} }
directory = _notmuch_directory_create (notmuch, path, &status); directory = _notmuch_directory_create (notmuch, path, flags, &status);
if (status) { if (status || !directory) {
*directory_id = -1; *directory_id = -1;
return status; return status;
} }
@ -1240,13 +1248,16 @@ _notmuch_database_get_directory_path (void *ctx,
* database path), return a new string (with 'ctx' as the talloc * database path), return a new string (with 'ctx' as the talloc
* owner) suitable for use as a direntry term value. * owner) suitable for use as a direntry term value.
* *
* The necessary directory documents will be created in the database * If (flags & NOTMUCH_FIND_CREATE), the necessary directory documents
* as needed. * 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_status_t
_notmuch_database_filename_to_direntry (void *ctx, _notmuch_database_filename_to_direntry (void *ctx,
notmuch_database_t *notmuch, notmuch_database_t *notmuch,
const char *filename, const char *filename,
notmuch_find_flags_t flags,
char **direntry) char **direntry)
{ {
const char *relative, *directory, *basename; const char *relative, *directory, *basename;
@ -1260,10 +1271,12 @@ _notmuch_database_filename_to_direntry (void *ctx,
if (status) if (status)
return status; return status;
status = _notmuch_database_find_directory_id (notmuch, directory, status = _notmuch_database_find_directory_id (notmuch, directory, flags,
&directory_id); &directory_id);
if (status) if (status || directory_id == (unsigned int)-1) {
*direntry = NULL;
return status; return status;
}
*direntry = talloc_asprintf (ctx, "%u:%s", directory_id, basename); *direntry = talloc_asprintf (ctx, "%u:%s", directory_id, basename);
@ -1315,12 +1328,9 @@ notmuch_database_get_directory (notmuch_database_t *notmuch,
return NOTMUCH_STATUS_NULL_POINTER; return NOTMUCH_STATUS_NULL_POINTER;
*directory = NULL; *directory = NULL;
/* XXX Handle read-only databases properly */
if (notmuch->mode == NOTMUCH_DATABASE_MODE_READ_ONLY)
return NOTMUCH_STATUS_READ_ONLY_DATABASE;
try { try {
*directory = _notmuch_directory_create (notmuch, path, &status); *directory = _notmuch_directory_create (notmuch, path,
NOTMUCH_FIND_LOOKUP, &status);
} catch (const Xapian::Error &error) { } catch (const Xapian::Error &error) {
fprintf (stderr, "A Xapian exception occurred getting directory: %s.\n", fprintf (stderr, "A Xapian exception occurred getting directory: %s.\n",
error.get_msg().c_str()); error.get_msg().c_str());
@ -1884,9 +1894,9 @@ notmuch_database_find_message_by_filename (notmuch_database_t *notmuch,
local = talloc_new (notmuch); local = talloc_new (notmuch);
try { try {
status = _notmuch_database_filename_to_direntry (local, notmuch, status = _notmuch_database_filename_to_direntry (
filename, &direntry); local, notmuch, filename, NOTMUCH_FIND_LOOKUP, &direntry);
if (status) if (status || !direntry)
goto DONE; goto DONE;
term = talloc_asprintf (local, "%s%s", prefix, direntry); term = talloc_asprintf (local, "%s%s", prefix, direntry);

View file

@ -82,28 +82,41 @@ find_directory_document (notmuch_database_t *notmuch,
return NOTMUCH_PRIVATE_STATUS_SUCCESS; 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_t *
_notmuch_directory_create (notmuch_database_t *notmuch, _notmuch_directory_create (notmuch_database_t *notmuch,
const char *path, const char *path,
notmuch_find_flags_t flags,
notmuch_status_t *status_ret) notmuch_status_t *status_ret)
{ {
Xapian::WritableDatabase *db; Xapian::WritableDatabase *db;
notmuch_directory_t *directory; notmuch_directory_t *directory;
notmuch_private_status_t private_status; notmuch_private_status_t private_status;
const char *db_path; const char *db_path;
notmuch_bool_t create = (flags & NOTMUCH_FIND_CREATE);
*status_ret = NOTMUCH_STATUS_SUCCESS; *status_ret = NOTMUCH_STATUS_SUCCESS;
path = _notmuch_database_relative_path (notmuch, path); 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"); INTERNAL_ERROR ("Failure to ensure database is writable");
db = static_cast <Xapian::WritableDatabase *> (notmuch->xapian_db);
directory = talloc (notmuch, notmuch_directory_t); directory = talloc (notmuch, notmuch_directory_t);
if (unlikely (directory == NULL)) if (unlikely (directory == NULL)) {
*status_ret = NOTMUCH_STATUS_OUT_OF_MEMORY;
return NULL; return NULL;
}
directory->notmuch = notmuch; directory->notmuch = notmuch;
@ -122,6 +135,13 @@ _notmuch_directory_create (notmuch_database_t *notmuch,
directory->document_id = directory->doc.get_docid (); directory->document_id = directory->doc.get_docid ();
if (private_status == NOTMUCH_PRIVATE_STATUS_NO_DOCUMENT_FOUND) { 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); void *local = talloc_new (directory);
const char *parent, *basename; const char *parent, *basename;
Xapian::docid parent_id; Xapian::docid parent_id;
@ -133,7 +153,13 @@ _notmuch_directory_create (notmuch_database_t *notmuch,
_notmuch_database_split_path (local, path, &parent, &basename); _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) { if (basename) {
term = talloc_asprintf (local, "%s%u:%s", term = talloc_asprintf (local, "%s%u:%s",
@ -145,6 +171,8 @@ _notmuch_directory_create (notmuch_database_t *notmuch,
directory->doc.add_value (NOTMUCH_VALUE_TIMESTAMP, directory->doc.add_value (NOTMUCH_VALUE_TIMESTAMP,
Xapian::sortable_serialise (0)); Xapian::sortable_serialise (0));
db = static_cast <Xapian::WritableDatabase *> (notmuch->xapian_db);
directory->document_id = _notmuch_database_generate_doc_id (notmuch); directory->document_id = _notmuch_database_generate_doc_id (notmuch);
db->replace_document (directory->document_id, directory->doc); db->replace_document (directory->document_id, directory->doc);
talloc_free (local); talloc_free (local);
@ -158,10 +186,11 @@ _notmuch_directory_create (notmuch_database_t *notmuch,
error.get_msg().c_str()); error.get_msg().c_str());
notmuch->exception_reported = TRUE; notmuch->exception_reported = TRUE;
notmuch_directory_destroy (directory); notmuch_directory_destroy (directory);
directory = NULL;
*status_ret = NOTMUCH_STATUS_XAPIAN_EXCEPTION; *status_ret = NOTMUCH_STATUS_XAPIAN_EXCEPTION;
return NULL;
} }
DONE:
if (db_path != path) if (db_path != path)
free ((char *) db_path); free ((char *) db_path);

View file

@ -495,9 +495,8 @@ _notmuch_message_add_filename (notmuch_message_t *message,
if (status) if (status)
return status; return status;
status = _notmuch_database_filename_to_direntry (local, status = _notmuch_database_filename_to_direntry (
message->notmuch, local, message->notmuch, filename, NOTMUCH_FIND_CREATE, &direntry);
filename, &direntry);
if (status) if (status)
return status; return status;
@ -541,9 +540,9 @@ _notmuch_message_remove_filename (notmuch_message_t *message,
notmuch_status_t status; notmuch_status_t status;
Xapian::TermIterator i, last; Xapian::TermIterator i, last;
status = _notmuch_database_filename_to_direntry (local, message->notmuch, status = _notmuch_database_filename_to_direntry (
filename, &direntry); local, message->notmuch, filename, NOTMUCH_FIND_LOOKUP, &direntry);
if (status) if (status || !direntry)
return status; return status;
/* Unlink this file from its parent directory. */ /* Unlink this file from its parent directory. */

View file

@ -146,6 +146,16 @@ typedef enum _notmuch_private_status {
: \ : \
(notmuch_status_t) private_status) (notmuch_status_t) 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,
} notmuch_find_flags_t;
typedef struct _notmuch_doc_id_set notmuch_doc_id_set_t; typedef struct _notmuch_doc_id_set notmuch_doc_id_set_t;
typedef struct _notmuch_string_list notmuch_string_list_t; typedef struct _notmuch_string_list notmuch_string_list_t;
@ -188,6 +198,7 @@ _notmuch_database_find_unique_doc_id (notmuch_database_t *notmuch,
notmuch_status_t notmuch_status_t
_notmuch_database_find_directory_id (notmuch_database_t *database, _notmuch_database_find_directory_id (notmuch_database_t *database,
const char *path, const char *path,
notmuch_find_flags_t flags,
unsigned int *directory_id); unsigned int *directory_id);
const char * const char *
@ -199,6 +210,7 @@ notmuch_status_t
_notmuch_database_filename_to_direntry (void *ctx, _notmuch_database_filename_to_direntry (void *ctx,
notmuch_database_t *notmuch, notmuch_database_t *notmuch,
const char *filename, const char *filename,
notmuch_find_flags_t flags,
char **direntry); char **direntry);
/* directory.cc */ /* directory.cc */
@ -206,6 +218,7 @@ _notmuch_database_filename_to_direntry (void *ctx,
notmuch_directory_t * notmuch_directory_t *
_notmuch_directory_create (notmuch_database_t *notmuch, _notmuch_directory_create (notmuch_database_t *notmuch,
const char *path, const char *path,
notmuch_find_flags_t flags,
notmuch_status_t *status_ret); notmuch_status_t *status_ret);
unsigned int unsigned int

View file

@ -300,10 +300,8 @@ notmuch_database_end_atomic (notmuch_database_t *notmuch);
* (see notmuch_database_get_path), or else should be an absolute path * (see notmuch_database_get_path), or else should be an absolute path
* with initial components that match the path of 'database'. * with initial components that match the path of 'database'.
* *
* Note: Currently this will create the directory object if it doesn't * If this directory object does not exist in the database, this
* exist. In the future, when a directory object does not exist this * returns NOTMUCH_STATUS_SUCCESS and sets *directory to NULL.
* will return NOTMUCH_STATUS_SUCCESS and set *directory to NULL.
* Callers should be prepared for this.
* *
* Return value: * Return value:
* *
@ -313,10 +311,6 @@ notmuch_database_end_atomic (notmuch_database_t *notmuch);
* *
* NOTMUCH_STATUS_XAPIAN_EXCEPTION: A Xapian exception occurred; * NOTMUCH_STATUS_XAPIAN_EXCEPTION: A Xapian exception occurred;
* directory not retrieved. * 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_status_t
notmuch_database_get_directory (notmuch_database_t *database, notmuch_database_get_directory (notmuch_database_t *database,

View file

@ -256,7 +256,7 @@ add_files_recursive (notmuch_database_t *notmuch,
notmuch_filenames_t *db_subdirs = NULL; notmuch_filenames_t *db_subdirs = NULL;
time_t stat_time; time_t stat_time;
struct stat st; struct stat st;
notmuch_bool_t is_maildir, new_directory; notmuch_bool_t is_maildir;
const char **tag; const char **tag;
if (stat (path, &st)) { if (stat (path, &st)) {
@ -281,33 +281,12 @@ add_files_recursive (notmuch_database_t *notmuch,
} }
db_mtime = directory ? notmuch_directory_get_mtime (directory) : 0; 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 /* If the database knows about this directory, then we sort based
* on strcmp to match the database sorting. Otherwise, we can do * on strcmp to match the database sorting. Otherwise, we can do
* inode-based sorting for faster filesystem operation. */ * inode-based sorting for faster filesystem operation. */
num_fs_entries = scandir (path, &fs_entries, 0, num_fs_entries = scandir (path, &fs_entries, 0,
new_directory ? directory ?
dirent_sort_inode : dirent_sort_strcmp_name); dirent_sort_strcmp_name : dirent_sort_inode);
if (num_fs_entries == -1) { if (num_fs_entries == -1) {
fprintf (stderr, "Error opening directory %s: %s\n", 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 * being discovered until the clock catches up and the directory
* is modified again). * is modified again).
*/ */
if (fs_mtime == db_mtime) if (directory && fs_mtime == db_mtime)
goto DONE; goto DONE;
/* new_directory means a directory that the database has never /* If the database has never seen this directory before, we can
* seen before. In that case, we can simply leave db_files and * simply leave db_files and db_subdirs NULL. */
* db_subdirs NULL. */ if (directory) {
if (!new_directory) {
db_files = notmuch_directory_get_child_files (directory); db_files = notmuch_directory_get_child_files (directory);
db_subdirs = notmuch_directory_get_child_directories (directory); db_subdirs = notmuch_directory_get_child_directories (directory);
} }

View file

@ -28,4 +28,12 @@ EOF
notmuch search --sort=oldest-first --output=messages tag:inbox | sed s/^id:// > EXPECTED notmuch search --sort=oldest-first --output=messages tag:inbox | sed s/^id:// > EXPECTED
test_expect_equal_file OUTPUT EXPECTED test_expect_equal_file OUTPUT EXPECTED
test_begin_subtest "get non-existent file"
test_python <<EOF
import notmuch
db = notmuch.Database(mode=notmuch.Database.MODE.READ_ONLY)
print db.find_message_by_filename("i-dont-exist")
EOF
test_expect_equal "$(cat OUTPUT)" "None"
test_done test_done