[PATCH] test: test folder renames
On Sun, 23 Feb 2014, Mark Walters wrote: > I was experimenting with letting notmuch new take an argument to tell it > to scan only a particular directory (and sub-directories) for new > messages. I came across the following strange behaviour which is also > present in master (with a fresh database) > > I have a bunch of maildirs in /home/mail: so folders .mail.foo/ > .mail.bar/ each of which has cur/new/tmp and all the messages are in > cur. > > If I do mv .mail.foo .mail.bar/ and run notmuch new I get the expected > lots of renames (900 or so in the case I was trying). But if I then do > mv .mail.bar/.mail.foo . and run notmuch new almost all the messages get > removed (but 30 renames do get detected). If I then do touch .mail.foo/* > the messages get found again > > I am guessing the 30 renames might be because those 30 have duplicates > somewhere else. > > But the other behaviour has me puzzled. This test reproduces the problem for me, but it's not deterministic. With the loop, I get roughly one fail per test run: FAIL Rename folder back --- T051-new-renames.27.expected 2014-02-23 21:37:10.121774241 + +++ T051-new-renames.27.output 2014-02-23 21:37:10.121774241 + @@ -1 +1 @@ -No new mail. Detected 10 file renames. +No new mail. Removed 10 messages. FAIL Files remain the same --- T051-new-renames.28.expected 2014-02-23 21:37:10.133774652 + +++ T051-new-renames.28.output 2014-02-23 21:37:10.133774652 + @@ -1,13 +1,3 @@ -/path/to/test/tmp.T051-new-renames/mail/foo/msg-121 -/path/to/test/tmp.T051-new-renames/mail/foo/msg-122 -/path/to/test/tmp.T051-new-renames/mail/foo/msg-123 -/path/to/test/tmp.T051-new-renames/mail/foo/msg-124 -/path/to/test/tmp.T051-new-renames/mail/foo/msg-125 -/path/to/test/tmp.T051-new-renames/mail/foo/msg-126 -/path/to/test/tmp.T051-new-renames/mail/foo/msg-127 -/path/to/test/tmp.T051-new-renames/mail/foo/msg-128 -/path/to/test/tmp.T051-new-renames/mail/foo/msg-129 -/path/to/test/tmp.T051-new-renames/mail/foo/msg-130 /path/to/test/tmp.T051-new-renames/mail/bar/msg-131 /path/to/test/tmp.T051-new-renames/mail/bar/msg-132 /path/to/test/tmp.T051-new-renames/mail/bar/msg-133 I'm as puzzled as you are. BR, Jani. --- test/T051-new-renames.sh | 40 1 file changed, 40 insertions(+) create mode 100755 test/T051-new-renames.sh diff --git a/test/T051-new-renames.sh b/test/T051-new-renames.sh new file mode 100755 index ..febe006f5888 --- /dev/null +++ b/test/T051-new-renames.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env bash +test_description='"notmuch new" with directory renames' +. ./test-lib.sh + +for loop in `seq 10`; do + +rm -rf ${MAIL_DIR} + +for i in `seq 10`; do +generate_message '[dir]=foo' '[subject]="Message foo $i"' +done + +for i in `seq 10`; do +generate_message '[dir]=bar' '[subject]="Message bar $i"' +done + +test_begin_subtest "Index the messages, round $loop" +output=$(NOTMUCH_NEW) +test_expect_equal "$output" "Added 20 new messages to the database." + +all_files=$(notmuch search --output=files \*) +count_foo=$(notmuch count folder:foo) + +test_begin_subtest "Rename folder" +mv ${MAIL_DIR}/foo ${MAIL_DIR}/baz +output=$(NOTMUCH_NEW) +test_expect_equal "$output" "No new mail. Detected $count_foo file renames." + +test_begin_subtest "Rename folder back" +mv ${MAIL_DIR}/baz ${MAIL_DIR}/foo +output=$(NOTMUCH_NEW) +test_expect_equal "$output" "No new mail. Detected $count_foo file renames." + +test_begin_subtest "Files remain the same" +output=$(notmuch search --output=files \*) +test_expect_equal "$output" "$all_files" + +done + +test_done -- 1.8.5.3
[PATCH v3 3/3] emacs: defun notmuch-hello-versions and bind 'v' in hello mode to it
If notmuch cli & notmuch emacs MUA versions differ, print also the emacs MUA version string (along with the cli version) to the minibuffer. --- emacs/notmuch-hello.el | 15 +-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/emacs/notmuch-hello.el b/emacs/notmuch-hello.el index 7b3d76b..f5e7268 100644 --- a/emacs/notmuch-hello.el +++ b/emacs/notmuch-hello.el @@ -513,6 +513,18 @@ Such a list can be computed with `notmuch-hello-query-counts'." (remove-hook 'window-configuration-change-hook #'notmuch-hello-window-configuration-change +;; the following variable is defined as being defconst in notmuch.el +(defvar notmuch-emacs-version) + +(defun notmuch-hello-versions () + "Display the notmuch version(s)" + (interactive) + (let ((notmuch-cli-version (notmuch-version))) +(message "notmuch version %s" +(if (string= notmuch-emacs-version notmuch-cli-version) +notmuch-cli-version + (concat notmuch-cli-version + " (emacs mua version " notmuch-emacs-version ")") (defvar notmuch-hello-mode-map (let ((map (if (fboundp 'make-composed-keymap) @@ -523,8 +535,7 @@ Such a list can be computed with `notmuch-hello-query-counts'." ;; it's unlikely to change. (copy-keymap widget-keymap (set-keymap-parent map notmuch-common-keymap) -(define-key map "v" (lambda () "Display the notmuch version" (interactive) - (message "notmuch version %s" (notmuch-version +(define-key map "v" 'notmuch-hello-versions) (define-key map (kbd "") 'widget-backward) map) "Keymap for \"notmuch hello\" buffers.") -- 1.8.0
[PATCH v3 2/3] emacs: defconst notmuch-emacs-version to a value during byte compilation
The notmuch cli program and emacs lisp versions may differ. For now we can help users with their emacs client problems better if we can ask what version of emacs MUA they are running. In the future we can put the emacs MUA version to User-Agent: string in outgoing mail. --- emacs/Makefile.local | 6 +- emacs/notmuch.el | 7 +++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/emacs/Makefile.local b/emacs/Makefile.local index 6a39b32..9e3fb7a 100644 --- a/emacs/Makefile.local +++ b/emacs/Makefile.local @@ -24,6 +24,8 @@ emacs_images := \ emacs_bytecode = $(emacs_sources:.el=.elc) +$(dir)/notmuch.elc: version.stamp + # Because of defmacro's and defsubst's, we have to account for load # dependencies between Elisp files when byte compiling. Otherwise, # the byte compiler may load an old .elc file when processing a @@ -49,7 +51,9 @@ CLEAN+=$(dir)/.eldeps $(dir)/.eldeps.tmp $(dir)/.eldeps.x ifeq ($(HAVE_EMACS),1) %.elc: %.el $(global_deps) - $(call quiet,EMACS) --directory emacs -batch -f batch-byte-compile $< + $(call quiet,EMACS) --directory emacs \ + --eval "(setq notmuch--version \"$(VERSION)\")" \ + -batch -f batch-byte-compile $< endif ifeq ($(WITH_EMACS),1) diff --git a/emacs/notmuch.el b/emacs/notmuch.el index 0471750..1b15054 100644 --- a/emacs/notmuch.el +++ b/emacs/notmuch.el @@ -81,6 +81,13 @@ To enter a line break in customize, press \\[quoted-insert] C-j." :type '(alist :key-type (string) :value-type (string)) :group 'notmuch-search) +;; defconst notmuch-version to a value during build-time byte compilation... +(defconst notmuch-emacs-version + (eval-when-compile (if (boundp 'notmuch--version) +notmuch--version + "unknown")) + "Version string of this version of Notmuch Emacs MUA.") + (defvar notmuch-query-history nil "Variable to store minibuffer history for notmuch queries") -- 1.8.0
[PATCH v3 1/3] build: write version.stamp file containing $(VERSION) string
This version file will be as prerequisite to the target files that use the version info for some purpose, like printing it for the user to examine. The contents of the version.stamp file is seldom read by the build system itself as the $(VERSION) variable has the same information. Thanks to Trevor, David and Mark for their contributions. --- .gitignore | 1 + Makefile.local | 14 +- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index ef4f074..1fb3a71 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ .first-build-message Makefile.config +version.stamp TAGS tags *cscope* diff --git a/Makefile.local b/Makefile.local index 174506c..3a56c06 100644 --- a/Makefile.local +++ b/Makefile.local @@ -22,6 +22,11 @@ VERSION:=$(shell cat ${srcdir}/version) ifeq ($(filter release release-message pre-release update-versions,$(MAKECMDGOALS)),) ifeq ($(IS_GIT),yes) VERSION:=$(shell git describe --match '[0-9.]*'|sed -e s/_/~/ -e s/-/+/ -e s/-/~/) +# Write the file 'version.stamp' in case its contents differ from $(VERSION) +FILE_VERSION:=$(shell test -f version.stamp && read vs < version.stamp || vs=; echo $$vs) +ifneq ($(FILE_VERSION),$(VERSION)) + $(shell echo "$(VERSION)" > version.stamp) +endif endif endif @@ -69,6 +74,11 @@ ifeq ($(shell cat .first-build-message 2>/dev/null),) endif endif +# Depend (also) on the file 'version'. In case of ifeq ($(IS_GIT),yes) +# this file may already have been updated. +version.stamp: version + echo $(VERSION) > $@ + $(TAR_FILE): if git tag -v $(VERSION) >/dev/null 2>&1; then \ ref=$(VERSION); \ @@ -280,6 +290,8 @@ notmuch_client_srcs = \ notmuch_client_modules = $(notmuch_client_srcs:.c=.o) +notmuch.o: version.stamp + notmuch: $(notmuch_client_modules) lib/libnotmuch.a util/libutil.a parse-time-string/libparse-time-string.a $(call quiet,CXX $(CFLAGS)) $^ $(FINAL_LIBNOTMUCH_LDFLAGS) -o $@ @@ -318,7 +330,7 @@ install-desktop: desktop-file-install --mode 0644 --dir "$(DESTDIR)$(desktop_dir)" notmuch.desktop SRCS := $(SRCS) $(notmuch_client_srcs) -CLEAN := $(CLEAN) notmuch notmuch-shared $(notmuch_client_modules) notmuch.elc +CLEAN := $(CLEAN) notmuch notmuch-shared $(notmuch_client_modules) version.stamp DISTCLEAN := $(DISTCLEAN) .first-build-message Makefile.config -- 1.8.0
v3 of version change detection and notmuch emacs/hello version(s)
This is v3 of id:1393024837-30394-1-git-send-email-tomi.ollila at iki.fi The only change is that version.stamp was added to root .gitignore file.
[DRAFT PATCH] notmuch new: do not ignore '.notmuch' in non-toplevel directories
So that users may have email in subdir/.notmuch directories. --- Compiles, current tests pass. might ignore database_path/.notmuch and might descent into database_path/.../.notmuch :D Tomi notmuch-new.c | 18 ++ 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/notmuch-new.c b/notmuch-new.c index 8529fdd..b17bd75 100644 --- a/notmuch-new.c +++ b/notmuch-new.c @@ -344,7 +344,8 @@ add_file (notmuch_database_t *notmuch, const char *filename, static notmuch_status_t add_files (notmuch_database_t *notmuch, const char *path, - add_files_state_t *state) + add_files_state_t *state, + int dirlevel) { DIR *dir = NULL; struct dirent *entry = NULL; @@ -469,11 +470,11 @@ add_files (notmuch_database_t *notmuch, if (strcmp (entry->d_name, ".") == 0 || strcmp (entry->d_name, "..") == 0 || (is_maildir && strcmp (entry->d_name, "tmp") == 0) || - strcmp (entry->d_name, ".notmuch") == 0) + (dirlevel == 0 && strcmp (entry->d_name, ".notmuch") == 0)) continue; next = talloc_asprintf (notmuch, "%s/%s", path, entry->d_name); - status = add_files (notmuch, next, state); + status = add_files (notmuch, next, state, dirlevel + 1); if (status) { ret = status; goto DONE; @@ -702,7 +703,8 @@ stop_progress_printing_timer (void) * initialized to zero by the top-level caller before calling * count_files). */ static void -count_files (const char *path, int *count, add_files_state_t *state) +count_files (const char *path, int *count, add_files_state_t *state, +int dirlevel) { struct dirent *entry = NULL; char *next; @@ -725,7 +727,7 @@ count_files (const char *path, int *count, add_files_state_t *state) */ if (strcmp (entry->d_name, ".") == 0 || strcmp (entry->d_name, "..") == 0 || - strcmp (entry->d_name, ".notmuch") == 0 || + (dirlevel == 0 && strcmp (entry->d_name, ".notmuch") == 0) || _entry_in_ignore_list (entry->d_name, state)) { if (state->debug && _entry_in_ignore_list (entry->d_name, state)) @@ -750,7 +752,7 @@ count_files (const char *path, int *count, add_files_state_t *state) fflush (stdout); } } else if (entry_type == S_IFDIR) { - count_files (next, count, state); + count_files (next, count, state, dirlevel + 1); } free (next); @@ -962,7 +964,7 @@ notmuch_new_command (notmuch_config_t *config, int argc, char *argv[]) int count; count = 0; - count_files (db_path, &count, &add_files_state); + count_files (db_path, &count, &add_files_state, 0); if (interrupted) return EXIT_FAILURE; @@ -1021,7 +1023,7 @@ notmuch_new_command (notmuch_config_t *config, int argc, char *argv[]) timer_is_active = TRUE; } -ret = add_files (notmuch, db_path, &add_files_state); +ret = add_files (notmuch, db_path, &add_files_state, 0); if (ret) goto DONE; -- 1.8.4.2
[PATCH 0/3] check new.tags for invalid tags
On Sun, Feb 23 2014, Jani Nikula wrote: > On Sun, 23 Feb 2014, Rob Browning wrote: >> In the [new] section, "tags=;" will cause notmuch to create empty tags >> that are fairly hard to remove from the command line. > > Clearly broken. This series fixes the issue at the cli > level. (Forbidding empty tags at the lib level is slightly more > complicated, as we would still have to ensure old dump files can be > restored.) > >> After some help on #bup, here's what I came up with to remove them, >> though it assumes that the empty tag "+ " will always be first in dump's >> output: >> >> notmuch dump --format=batch-tag 'tag:""' | perl -pe 's/^\+ //' \ >> | notmuch restore --format=batch-tag >> >> And note that you have to use restore, "notmuch tag --batch" doesn't >> appear to accept "- " as a tag, even though dump will produce "+ ". > > I didn't check this further, but the regular, non-batch notmuch tag > should still work for removal of empty tags. LGTM. $ notmuch tag + -- id:edc2bc900f75bb2e72be2037e2df9105be7f0273.1393174108.git.jani at nikula.org Error: empty tag forbiddenzsh: exit 1 notmuch tag + -- $ notmuch restore --accumulate + id:edc2bc900f75bb2e72be2037e2df9105be7f0273.1393174108.git.jani at nikula.org -- notmuch search shows space after ( to inform there is empty tag. $ notmuch tag - -- id:edc2bc900f75bb2e72be2037e2df9105be7f0273.1393174108.git.jani at nikula.org notmuch search no longer shows space after ( Also, SomeBody(tm) should add '\n' to the fprintf() in tag-util.c:175 (line number after applying these patches). Tomi > > BR, > Jani. > > Jani Nikula (3): > cli: export function for illegal tag checking > cli: make sure notmuch new and insert don't add invalid tags > test: add tests for invalid new.tags > > notmuch-insert.c| 9 + > notmuch-new.c | 14 +- > tag-util.c | 9 + > tag-util.h | 12 > test/T050-new.sh| 17 + > test/T070-insert.sh | 19 +++ > 6 files changed, 71 insertions(+), 9 deletions(-) > > -- > 1.8.5.3 > > ___ > notmuch mailing list > notmuch at notmuchmail.org > http://notmuchmail.org/mailman/listinfo/notmuch
[RFC Patch v3 2/3] doc: add target rst2man to build man pages using rst2man
Tomi Ollila writes: > Anyway, I tried to build manual pages using 'make man' and got this: > > $ make man > sphinx-build -b man -d doc/_build/doctrees -q -c doc doc doc/_build/man > Sphinx error: > Builder name man not registered It seems you need sphinx version 1.0, from July 2010 for the man builder. > No fallback to use rst2man... I don't really plan on an automatic fallback. There is currently a separate target rst2man. I'm open to better names for the targets. > Comments regarding prerst2man.py inline below: Yeah, I'm sure there's lots that could be improved with that script. But I'll wait until I see if the general approach is acceptable. d
[RFC Patch v3 2/3] doc: add target rst2man to build man pages using rst2man
On Sun, Feb 23 2014, David Bremner wrote: > Many people have docutils installed, but not sphinx. Allow these > people to build the man pages. +1 from me to start having manuals in reStructuredText format and then converting these to the target formats. Some comments on the patch series below: Building any docs using this is not yet activated ? Anyway, I tried to build manual pages using 'make man' and got this: $ make man sphinx-build -b man -d doc/_build/doctrees -q -c doc doc doc/_build/man Making output directory... Sphinx error: Builder name man not registered No fallback to use rst2man... Comments regarding prerst2man.py inline below: Tomi > --- // stuff deleted // > diff --git a/doc/rst2man/prerst2man.py b/doc/rst2man/prerst2man.py > new file mode 100644 > index 000..797dd20 > --- /dev/null > +++ b/doc/rst2man/prerst2man.py > @@ -0,0 +1,53 @@ > +from sys import argv > +from datetime import date > +import re > + > +sourcedir=argv[1] > +outdir=argv[2] Style! run pep8 prerst2html.py and fix the issues it prints to the screen, like ' = ' above and remove trailing semicolon below... (and also pep8(1) doc/conf.py. > + > +execfile(sourcedir+"/conf.py"); > + > + > + > + > +def header(file,startdocname, command, description, authors, section): > +file.write(""" > +{:s} > +{:s} > +{:s} > + > +:Date: {:s} > +:Version: {:s} > +:Manual section: {:d} > +:Manual group: {:s} For python < 2.7 these needs to be {0:s}, {1:s}, {2:s}.. {5:d}... > + > +""".format( > +'-' * len(description), > +description, > +'-' * len(description), > +date.today().isoformat(),release,section,project)) Replace date.today.isoformat() with date determined from other sources (NEWS file?) > + > +blankre = re.compile("^\s*$") > +for page in man_pages: > +outfile = open(outdir+"/"+page[0]+'.rst','w') > +infile = open(sourcedir+"/"+page[0]+".rst",'r') In addition to formatting above, use either ".rst" or '.rst' (and perhaps other quotations in these 2 lines) for consistency. > + > + > +# this is a crude hack. We look for the first blank line, and > +# insert the rst2man header there. > +# > +# XXX consider really parsing input > + > +count=0 > +lines = infile.readlines() > +for line in lines: > +outfile.write(line); > +if (blankre.match(line)): > +break > +count = count + 1 > + > +del lines[0:count+1] pep8 will in the lime above (as it is not lines[0:count + 1]) I might not have complained but... :D > + > +header(outfile,*page) > + > +outfile.write("".join(lines)) > -- > 1.8.5.3
[PATCH 3/3] test: add tests for invalid new.tags
Similar tests for both notmuch new and insert. --- test/T050-new.sh| 17 + test/T070-insert.sh | 19 +++ 2 files changed, 36 insertions(+) diff --git a/test/T050-new.sh b/test/T050-new.sh index b7668ff0c4bc..ad46ee6d51b6 100755 --- a/test/T050-new.sh +++ b/test/T050-new.sh @@ -263,4 +263,21 @@ notmuch search --format=text0 --output=files --offset=1 --limit=1 '*' | xargs -0 output=$(NOTMUCH_NEW --quiet) test_expect_equal "$output" "" +OLDCONFIG=$(notmuch config get new.tags) + +test_begin_subtest "Empty tags in new.tags are forbidden" +notmuch config set new.tags "foo;;bar" +output=$(NOTMUCH_NEW 2>&1) +test_expect_equal "$output" "Error: tag '' in new.tags: empty tag forbidden" + +test_begin_subtest "Tags starting with '-' in new.tags are forbidden" +notmuch config set new.tags "-foo;bar" +output=$(NOTMUCH_NEW 2>&1) +test_expect_equal "$output" "Error: tag '-foo' in new.tags: tag starting with '-' forbidden" + +test_expect_code 1 "Invalid tags set exit code" \ +"NOTMUCH_NEW 2>&1" + +notmuch config set new.tags $OLDCONFIG + test_done diff --git a/test/T070-insert.sh b/test/T070-insert.sh index e8dc4c099ed1..b77c5e13c87f 100755 --- a/test/T070-insert.sh +++ b/test/T070-insert.sh @@ -164,4 +164,23 @@ gen_insert_msg test_expect_code 1 "Insert message, create invalid subfolder" \ "notmuch insert --folder=../G --create-folder $gen_msg_filename" +OLDCONFIG=$(notmuch config get new.tags) + +test_begin_subtest "Empty tags in new.tags are forbidden" +notmuch config set new.tags "foo;;bar" +gen_insert_msg +output=$(notmuch insert $gen_msg_filename 2>&1) +test_expect_equal "$output" "Error: tag '' in new.tags: empty tag forbidden" + +test_begin_subtest "Tags starting with '-' in new.tags are forbidden" +notmuch config set new.tags "-foo;bar" +gen_insert_msg +output=$(notmuch insert $gen_msg_filename 2>&1) +test_expect_equal "$output" "Error: tag '-foo' in new.tags: tag starting with '-' forbidden" + +test_expect_code 1 "Invalid tags set exit code" \ +"notmuch insert $gen_msg_filename 2>&1" + +notmuch config set new.tags $OLDCONFIG + test_done -- 1.8.5.3
[PATCH 2/3] cli: make sure notmuch new and insert don't add invalid tags
Check new.tags configuration values before doing anything, and bail out on invalid values. --- notmuch-insert.c | 9 + notmuch-new.c| 14 +- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/notmuch-insert.c b/notmuch-insert.c index cd6de88f6891..6752fc8de255 100644 --- a/notmuch-insert.c +++ b/notmuch-insert.c @@ -431,6 +431,15 @@ notmuch_insert_command (notmuch_config_t *config, int argc, char *argv[]) return EXIT_FAILURE; } for (i = 0; i < new_tags_length; i++) { + const char *error_msg; + + error_msg = illegal_tag (new_tags[i], FALSE); + if (error_msg) { + fprintf (stderr, "Error: tag '%s' in new.tags: %s\n", +new_tags[i], error_msg); + return EXIT_FAILURE; + } + if (tag_op_list_append (tag_ops, new_tags[i], FALSE)) return EXIT_FAILURE; } diff --git a/notmuch-new.c b/notmuch-new.c index 8529fdd3eac7..82acf695353e 100644 --- a/notmuch-new.c +++ b/notmuch-new.c @@ -19,6 +19,7 @@ */ #include "notmuch-client.h" +#include "tag-util.h" #include @@ -918,7 +919,7 @@ notmuch_new_command (notmuch_config_t *config, int argc, char *argv[]) struct sigaction action; _filename_node_t *f; int opt_index; -int i; +unsigned int i; notmuch_bool_t timer_is_active = FALSE; notmuch_bool_t no_hooks = FALSE; notmuch_bool_t quiet = FALSE, verbose = FALSE; @@ -950,6 +951,17 @@ notmuch_new_command (notmuch_config_t *config, int argc, char *argv[]) add_files_state.synchronize_flags = notmuch_config_get_maildir_synchronize_flags (config); db_path = notmuch_config_get_database_path (config); +for (i = 0; i < add_files_state.new_tags_length; i++) { + const char *error_msg; + + error_msg = illegal_tag (add_files_state.new_tags[i], FALSE); + if (error_msg) { + fprintf (stderr, "Error: tag '%s' in new.tags: %s\n", +add_files_state.new_tags[i], error_msg); + return EXIT_FAILURE; + } +} + if (!no_hooks) { ret = notmuch_run_hook (db_path, "pre-new"); if (ret) -- 1.8.5.3
[PATCH 1/3] cli: export function for illegal tag checking
This lets us check for forbidden tags consistently across the cli. No functional changes. --- tag-util.c | 9 + tag-util.h | 12 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/tag-util.c b/tag-util.c index 3bde4097372a..e2d5b795acc3 100644 --- a/tag-util.c +++ b/tag-util.c @@ -31,14 +31,7 @@ line_error (tag_parse_status_t status, return status; } -/* - * Test tags for some forbidden cases. - * - * return: NULL if OK, - *explanatory message otherwise. - */ - -static const char * +const char * illegal_tag (const char *tag, notmuch_bool_t remove) { diff --git a/tag-util.h b/tag-util.h index 4628f1630ad6..8a4074ce168f 100644 --- a/tag-util.h +++ b/tag-util.h @@ -90,6 +90,18 @@ parse_tag_command_line (void *ctx, int argc, char **argv, char **query_str, tag_op_list_t *ops); /* + * Test tags for some forbidden cases. + * + * Relax the checks if 'remove' is true to allow removal of previously + * added forbidden tags. + * + * return: NULL if OK, + *explanatory message otherwise. + */ +const char * +illegal_tag (const char *tag, notmuch_bool_t remove); + +/* * Create an empty list of tag operations * * ctx is passed to talloc -- 1.8.5.3
[PATCH 0/3] check new.tags for invalid tags
On Sun, 23 Feb 2014, Rob Browning wrote: > In the [new] section, "tags=;" will cause notmuch to create empty tags > that are fairly hard to remove from the command line. Clearly broken. This series fixes the issue at the cli level. (Forbidding empty tags at the lib level is slightly more complicated, as we would still have to ensure old dump files can be restored.) > After some help on #bup, here's what I came up with to remove them, > though it assumes that the empty tag "+ " will always be first in dump's > output: > > notmuch dump --format=batch-tag 'tag:""' | perl -pe 's/^\+ //' \ > | notmuch restore --format=batch-tag > > And note that you have to use restore, "notmuch tag --batch" doesn't > appear to accept "- " as a tag, even though dump will produce "+ ". I didn't check this further, but the regular, non-batch notmuch tag should still work for removal of empty tags. BR, Jani. Jani Nikula (3): cli: export function for illegal tag checking cli: make sure notmuch new and insert don't add invalid tags test: add tests for invalid new.tags notmuch-insert.c| 9 + notmuch-new.c | 14 +- tag-util.c | 9 + tag-util.h | 12 test/T050-new.sh| 17 + test/T070-insert.sh | 19 +++ 6 files changed, 71 insertions(+), 9 deletions(-) -- 1.8.5.3
Re: v3 of sphinx docs
This looks good to me. It will obviously need a little tweaking but I like it. There is some error in the conversion for SYNOPSIS for dump, restore and tag (which may also have caused the problem for compact?) Otherwise there were a small number of oddities in indentation, and a general reduction in boldness (using underlining instead). (This is on a standard xterm). One case we might care a little about is the SEE ALSO section at the end where the underlining rather than bold seems inconsistent with the rest of my debian manpages. Best wishes Mark On Sun, 23 Feb 2014, David Bremner wrote: > This version includes a complete conversion of the existing manpages. > The conversion uses doclifter + custom python code + pandoc. It is > pretty much fully automated, so I can rebase against changes to the > nroff source if needed. > > On the other hand, it is fully automated, so there are bound to be a > few rough spots. If there are systematic things, I can fix the > conversion scripts; one offs can just be added to the series. > > It does do a much better job of option indentation than the previous > version. > > I think this is reaching the point where if anybody has any strong > objections to sphinx (with a fallback to rst2man) for the docs, I'd > like to hear them. > > ___ > notmuch mailing list > notmuch@notmuchmail.org > http://notmuchmail.org/mailman/listinfo/notmuch ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
Re: [RFC Patch v3 2/3] doc: add target rst2man to build man pages using rst2man
Tomi Ollila writes: > Anyway, I tried to build manual pages using 'make man' and got this: > > $ make man > sphinx-build -b man -d doc/_build/doctrees -q -c doc doc doc/_build/man > Sphinx error: > Builder name man not registered It seems you need sphinx version 1.0, from July 2010 for the man builder. > No fallback to use rst2man... I don't really plan on an automatic fallback. There is currently a separate target rst2man. I'm open to better names for the targets. > Comments regarding prerst2man.py inline below: Yeah, I'm sure there's lots that could be improved with that script. But I'll wait until I see if the general approach is acceptable. d ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
Re: [PATCH] test: test folder renames
On Sun, Feb 23 2014, Jani Nikula wrote: > On Sun, 23 Feb 2014, Mark Walters wrote: >> I was experimenting with letting notmuch new take an argument to tell it >> to scan only a particular directory (and sub-directories) for new >> messages. I came across the following strange behaviour which is also >> present in master (with a fresh database) >> >> I have a bunch of maildirs in /home/mail: so folders .mail.foo/ >> .mail.bar/ each of which has cur/new/tmp and all the messages are in >> cur. >> >> If I do mv .mail.foo .mail.bar/ and run notmuch new I get the expected >> lots of renames (900 or so in the case I was trying). But if I then do >> mv .mail.bar/.mail.foo . and run notmuch new almost all the messages get >> removed (but 30 renames do get detected). If I then do touch .mail.foo/* >> the messages get found again >> >> I am guessing the 30 renames might be because those 30 have duplicates >> somewhere else. >> >> But the other behaviour has me puzzled. > > This test reproduces the problem for me, but it's not > deterministic. With the loop, I get roughly one fail per test run: > > FAIL Rename folder back > --- T051-new-renames.27.expected 2014-02-23 21:37:10.121774241 + > +++ T051-new-renames.27.output 2014-02-23 21:37:10.121774241 > + > @@ -1 +1 @@ > -No new mail. Detected 10 file renames. > +No new mail. Removed 10 messages. > FAIL Files remain the same > --- T051-new-renames.28.expected 2014-02-23 21:37:10.133774652 + > +++ T051-new-renames.28.output 2014-02-23 21:37:10.133774652 > + > @@ -1,13 +1,3 @@ > -/path/to/test/tmp.T051-new-renames/mail/foo/msg-121 > -/path/to/test/tmp.T051-new-renames/mail/foo/msg-122 > -/path/to/test/tmp.T051-new-renames/mail/foo/msg-123 > -/path/to/test/tmp.T051-new-renames/mail/foo/msg-124 > -/path/to/test/tmp.T051-new-renames/mail/foo/msg-125 > -/path/to/test/tmp.T051-new-renames/mail/foo/msg-126 > -/path/to/test/tmp.T051-new-renames/mail/foo/msg-127 > -/path/to/test/tmp.T051-new-renames/mail/foo/msg-128 > -/path/to/test/tmp.T051-new-renames/mail/foo/msg-129 > -/path/to/test/tmp.T051-new-renames/mail/foo/msg-130 > /path/to/test/tmp.T051-new-renames/mail/bar/msg-131 > /path/to/test/tmp.T051-new-renames/mail/bar/msg-132 > /path/to/test/tmp.T051-new-renames/mail/bar/msg-133 > > I'm as puzzled as you are. find /path/to/test/tmp.T051-new-renames/ might show what is the order or 'foo' and 'bar' directories there. the order might be arbitrary -- it surely is not alphabetical and it might not be the order created... The order should not matter -- and maybe it didn't and some change made that matter... I'd test now but I should be ZZZ :D > > BR, > Jani. Tomi > --- > test/T051-new-renames.sh | 40 > 1 file changed, 40 insertions(+) > create mode 100755 test/T051-new-renames.sh > > diff --git a/test/T051-new-renames.sh b/test/T051-new-renames.sh > new file mode 100755 > index ..febe006f5888 > --- /dev/null > +++ b/test/T051-new-renames.sh > @@ -0,0 +1,40 @@ > +#!/usr/bin/env bash > +test_description='"notmuch new" with directory renames' > +. ./test-lib.sh > + > +for loop in `seq 10`; do > + > +rm -rf ${MAIL_DIR} > + > +for i in `seq 10`; do > +generate_message '[dir]=foo' '[subject]="Message foo $i"' > +done > + > +for i in `seq 10`; do > +generate_message '[dir]=bar' '[subject]="Message bar $i"' > +done > + > +test_begin_subtest "Index the messages, round $loop" > +output=$(NOTMUCH_NEW) > +test_expect_equal "$output" "Added 20 new messages to the database." > + > +all_files=$(notmuch search --output=files \*) > +count_foo=$(notmuch count folder:foo) > + > +test_begin_subtest "Rename folder" > +mv ${MAIL_DIR}/foo ${MAIL_DIR}/baz > +output=$(NOTMUCH_NEW) > +test_expect_equal "$output" "No new mail. Detected $count_foo file renames." > + > +test_begin_subtest "Rename folder back" > +mv ${MAIL_DIR}/baz ${MAIL_DIR}/foo > +output=$(NOTMUCH_NEW) > +test_expect_equal "$output" "No new mail. Detected $count_foo file renames." > + > +test_begin_subtest "Files remain the same" > +output=$(notmuch search --output=files \*) > +test_expect_equal "$output" "$all_files" > + > +done > + > +test_done > -- > 1.8.5.3 > > ___ > notmuch mailing list > notmuch@notmuchmail.org > http://notmuchmail.org/mailman/listinfo/notmuch ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
Re: [DRAFT PATCH] notmuch new: do not ignore '.notmuch' in non-toplevel directories
On Sun, 23 Feb 2014, Tomi Ollila wrote: > So that users may have email in subdir/.notmuch directories. > --- > > Compiles, current tests pass. might ignore database_path/.notmuch and > might descent into database_path/.../.notmuch :D > > Tomi > > > notmuch-new.c | 18 ++ > 1 file changed, 10 insertions(+), 8 deletions(-) > > diff --git a/notmuch-new.c b/notmuch-new.c > index 8529fdd..b17bd75 100644 > --- a/notmuch-new.c > +++ b/notmuch-new.c > @@ -344,7 +344,8 @@ add_file (notmuch_database_t *notmuch, const char > *filename, > static notmuch_status_t > add_files (notmuch_database_t *notmuch, > const char *path, > -add_files_state_t *state) > +add_files_state_t *state, > +int dirlevel) I think this is ugly and makes the interface harder to use for indexing arbitrary paths. Instead, I suggest diff --git a/notmuch-new.c b/notmuch-new.c index 8529fdd3eac7..20bc33fca4bd 100644 --- a/notmuch-new.c +++ b/notmuch-new.c @@ -469,7 +469,8 @@ add_files (notmuch_database_t *notmuch, if (strcmp (entry->d_name, ".") == 0 || strcmp (entry->d_name, "..") == 0 || (is_maildir && strcmp (entry->d_name, "tmp") == 0) || - strcmp (entry->d_name, ".notmuch") == 0) + (strcmp (entry->d_name, ".notmuch") == 0 && +strcmp (path, notmuch_database_get_path (notmuch)) == 0)) continue; next = talloc_asprintf (notmuch, "%s/%s", path, entry->d_name); And similarly in count_files(), with the root db path passed as first argument (as the db is not open yet). BR, Jani. > { > DIR *dir = NULL; > struct dirent *entry = NULL; > @@ -469,11 +470,11 @@ add_files (notmuch_database_t *notmuch, > if (strcmp (entry->d_name, ".") == 0 || > strcmp (entry->d_name, "..") == 0 || > (is_maildir && strcmp (entry->d_name, "tmp") == 0) || > - strcmp (entry->d_name, ".notmuch") == 0) > + (dirlevel == 0 && strcmp (entry->d_name, ".notmuch") == 0)) > continue; > > next = talloc_asprintf (notmuch, "%s/%s", path, entry->d_name); > - status = add_files (notmuch, next, state); > + status = add_files (notmuch, next, state, dirlevel + 1); > if (status) { > ret = status; > goto DONE; > @@ -702,7 +703,8 @@ stop_progress_printing_timer (void) > * initialized to zero by the top-level caller before calling > * count_files). */ > static void > -count_files (const char *path, int *count, add_files_state_t *state) > +count_files (const char *path, int *count, add_files_state_t *state, > + int dirlevel) > { > struct dirent *entry = NULL; > char *next; > @@ -725,7 +727,7 @@ count_files (const char *path, int *count, > add_files_state_t *state) >*/ > if (strcmp (entry->d_name, ".") == 0 || > strcmp (entry->d_name, "..") == 0 || > - strcmp (entry->d_name, ".notmuch") == 0 || > + (dirlevel == 0 && strcmp (entry->d_name, ".notmuch") == 0) || > _entry_in_ignore_list (entry->d_name, state)) > { > if (state->debug && _entry_in_ignore_list (entry->d_name, state)) > @@ -750,7 +752,7 @@ count_files (const char *path, int *count, > add_files_state_t *state) > fflush (stdout); > } > } else if (entry_type == S_IFDIR) { > - count_files (next, count, state); > + count_files (next, count, state, dirlevel + 1); > } > > free (next); > @@ -962,7 +964,7 @@ notmuch_new_command (notmuch_config_t *config, int argc, > char *argv[]) > int count; > > count = 0; > - count_files (db_path, &count, &add_files_state); > + count_files (db_path, &count, &add_files_state, 0); > if (interrupted) > return EXIT_FAILURE; > > @@ -1021,7 +1023,7 @@ notmuch_new_command (notmuch_config_t *config, int > argc, char *argv[]) > timer_is_active = TRUE; > } > > -ret = add_files (notmuch, db_path, &add_files_state); > +ret = add_files (notmuch, db_path, &add_files_state, 0); > if (ret) > goto DONE; > > -- > 1.8.4.2 > > ___ > notmuch mailing list > notmuch@notmuchmail.org > http://notmuchmail.org/mailman/listinfo/notmuch ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
[PATCH] test: test folder renames
On Sun, 23 Feb 2014, Mark Walters wrote: > I was experimenting with letting notmuch new take an argument to tell it > to scan only a particular directory (and sub-directories) for new > messages. I came across the following strange behaviour which is also > present in master (with a fresh database) > > I have a bunch of maildirs in /home/mail: so folders .mail.foo/ > .mail.bar/ each of which has cur/new/tmp and all the messages are in > cur. > > If I do mv .mail.foo .mail.bar/ and run notmuch new I get the expected > lots of renames (900 or so in the case I was trying). But if I then do > mv .mail.bar/.mail.foo . and run notmuch new almost all the messages get > removed (but 30 renames do get detected). If I then do touch .mail.foo/* > the messages get found again > > I am guessing the 30 renames might be because those 30 have duplicates > somewhere else. > > But the other behaviour has me puzzled. This test reproduces the problem for me, but it's not deterministic. With the loop, I get roughly one fail per test run: FAIL Rename folder back --- T051-new-renames.27.expected 2014-02-23 21:37:10.121774241 + +++ T051-new-renames.27.output 2014-02-23 21:37:10.121774241 + @@ -1 +1 @@ -No new mail. Detected 10 file renames. +No new mail. Removed 10 messages. FAIL Files remain the same --- T051-new-renames.28.expected 2014-02-23 21:37:10.133774652 + +++ T051-new-renames.28.output 2014-02-23 21:37:10.133774652 + @@ -1,13 +1,3 @@ -/path/to/test/tmp.T051-new-renames/mail/foo/msg-121 -/path/to/test/tmp.T051-new-renames/mail/foo/msg-122 -/path/to/test/tmp.T051-new-renames/mail/foo/msg-123 -/path/to/test/tmp.T051-new-renames/mail/foo/msg-124 -/path/to/test/tmp.T051-new-renames/mail/foo/msg-125 -/path/to/test/tmp.T051-new-renames/mail/foo/msg-126 -/path/to/test/tmp.T051-new-renames/mail/foo/msg-127 -/path/to/test/tmp.T051-new-renames/mail/foo/msg-128 -/path/to/test/tmp.T051-new-renames/mail/foo/msg-129 -/path/to/test/tmp.T051-new-renames/mail/foo/msg-130 /path/to/test/tmp.T051-new-renames/mail/bar/msg-131 /path/to/test/tmp.T051-new-renames/mail/bar/msg-132 /path/to/test/tmp.T051-new-renames/mail/bar/msg-133 I'm as puzzled as you are. BR, Jani. --- test/T051-new-renames.sh | 40 1 file changed, 40 insertions(+) create mode 100755 test/T051-new-renames.sh diff --git a/test/T051-new-renames.sh b/test/T051-new-renames.sh new file mode 100755 index ..febe006f5888 --- /dev/null +++ b/test/T051-new-renames.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env bash +test_description='"notmuch new" with directory renames' +. ./test-lib.sh + +for loop in `seq 10`; do + +rm -rf ${MAIL_DIR} + +for i in `seq 10`; do +generate_message '[dir]=foo' '[subject]="Message foo $i"' +done + +for i in `seq 10`; do +generate_message '[dir]=bar' '[subject]="Message bar $i"' +done + +test_begin_subtest "Index the messages, round $loop" +output=$(NOTMUCH_NEW) +test_expect_equal "$output" "Added 20 new messages to the database." + +all_files=$(notmuch search --output=files \*) +count_foo=$(notmuch count folder:foo) + +test_begin_subtest "Rename folder" +mv ${MAIL_DIR}/foo ${MAIL_DIR}/baz +output=$(NOTMUCH_NEW) +test_expect_equal "$output" "No new mail. Detected $count_foo file renames." + +test_begin_subtest "Rename folder back" +mv ${MAIL_DIR}/baz ${MAIL_DIR}/foo +output=$(NOTMUCH_NEW) +test_expect_equal "$output" "No new mail. Detected $count_foo file renames." + +test_begin_subtest "Files remain the same" +output=$(notmuch search --output=files \*) +test_expect_equal "$output" "$all_files" + +done + +test_done -- 1.8.5.3 ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
[PATCH v2 00/13] literal folder: prefix, new path: prefix
On Sun, Feb 23 2014, Mark Walters wrote: > I have read most of this series, tested it and run the tests and LGTM +1. > > I read the C code fairly carefully, the tests rather less so but they > looked sane, and I didn't really look at patch 9 for building old > databases. Well, I can add (at this point) that patch 9 is tolerable... > > Best wishes > > Mark Tomi > > > > > On Sat, 22 Feb 2014, Jani Nikula wrote: >> Hi all, this is v2 of id:cover.1389304779.git.jani at nikula.org. >> >> The new path: prefix is a literal boolean prefix matching the paths, >> relative from the maildir root, of the message files. There's no >> interpretation of the maildir special cur/new folders, but a recursive >> match is provided with "/**" suffix. See the patch for details. >> >> The folder: prefix becomes a literal boolean prefix, similar to path:, >> except it matches the maildir cur/new folders in addition to the >> specified path. There's no recursive version. >> >> Patches 1-5 add the above. >> >> Patches 6-8 change the test infrastructure to make it easier to add >> multiple corpuses, and adds a new test for path: and folder:. >> >> Patches 9-11 add support for testing the database upgrade. >> >> Patches 12-13 update man pages. >> >> >> I've dropped most of the content in patches 7 and 10 due to their >> size. The patches (and the whole series) are available in the >> boolean-folder-and-path-v2 branch at >> git://gitorious.org/jani/notmuch.git. Web interface at >> https://gitorious.org/jani/notmuch/commits/0b3dd2d1cc6c413ea07ea326883ac448499c0e79. >> >> >> WARNING! The change requires a database format version bump, and a >> database upgrade, which is automatically done on 'notmuch new'. The >> upgrade is irreversible if you want to try this on your database! A >> complete database rebuild is required for reverting the database format >> version. Make sure your backups are in order! >> >> >> BR, >> Jani. >> >> >> Jani Nikula (13): >> lib: refactor folder term update after filename removal >> lib: add support for path: prefix searches >> test: make insert test use the path: prefix >> lib: make folder: prefix literal >> test: fix test for literal folder: search >> test: make it possible to have several corpora >> test: add new corpus with folders >> test: add tests for the new boolean folder: and path: prefixes >> devel: add script to generate test databases >> test: add test database in format version 1 >> test: add database upgrade test from format version 1 to 2 >> man: update man pages for folder: and path: search terms >> man: try to clarify the folder: and path: vs. --output=files confusion >> >> devel/gen-testdb.sh| 124 >> lib/database.cc| 45 - >> lib/message.cc | 249 --- >> lib/notmuch-private.h | 3 + >> man/man1/notmuch-search.1 | 10 +- >> man/man7/notmuch-search-terms.7| 28 ++- >> test/.gitignore| 2 +- >> test/Makefile.local| 2 +- >> test/T070-insert.sh| 10 +- >> test/T100-search-by-folder.sh | 24 ++- >> test/T101-search-by-folder-and-path.sh | 83 >> test/T480-hex-escaping.sh | 4 +- >> test/T530-upgrade.sh | 103 ++ >> test/corpus/{ => default}/cur/01:2,| 0 >> test/corpus/{ => default}/cur/02:2,| 0 >> test/corpus/{ => default}/cur/03:2,| 0 >> test/corpus/{ => default}/cur/04:2,| 0 >> test/corpus/{ => default}/cur/05:2,| 0 >> test/corpus/{ => default}/cur/06:2,| 0 >> test/corpus/{ => default}/cur/07:2,| 0 >> test/corpus/{ => default}/cur/08:2,| 0 >> test/corpus/{ => default}/cur/09:2,| 0 >> test/corpus/{ => default}/cur/10:2,| 0 >> test/corpus/{ => default}/cur/11:2,| 0 >> test/corpus/{ => default}/cur/12:2,| 0 >> test/corpus/{ => default}/cur/13:2,| 0 >> test/corpus/{ => default}/cur/14:2,| 0 >> test/corpus/{ => default}/cur/15:2,| 0 >> test/corpus/{ => default}/cur/16:2,| 0 >> test/corpus/{ => default}/cur/17:2,| 0 >> test/corpus/{ => default}/cur/18:2,| 0 >> test/corpus/{ => default}/cur/19:2,| 0 >> test/corpus/{ => default}/cur/20:2,| 0 >> test/corpus/{ => default}/cur/21:2,| 0 >> test/corpus/{ => default}/cur/22:2,| 0 >> test/corpus/{ => default}/cur/23:2,| 0 >> test/corpus/{ => default}/cur/24:2,| 0 >> test/corpus/{ => default}/cur/25:2,| 0 >> test/corpus/{ => default}/cur/26:2,| 0 >> test/corpus/{ => default}/cur/27:2,| 0 >> test/corpus/{ => default}/cur/28:2,| 0 >> test/corpus/{ => default}/cur/29:2,| 0 >> test/corpus/{ => default}/cur/30:2,| 0 >> test/corpus/{ => default}/cur/31:2,| 0 >> test/corpus/{ => default}/cur/32:2,| 0 >> test/corpus/{ => default}/cur/33:2,
[PATCH v3 1/3] build: write version.stamp file containing $(VERSION) string
This version file will be as prerequisite to the target files that use the version info for some purpose, like printing it for the user to examine. The contents of the version.stamp file is seldom read by the build system itself as the $(VERSION) variable has the same information. Thanks to Trevor, David and Mark for their contributions. --- .gitignore | 1 + Makefile.local | 14 +- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index ef4f074..1fb3a71 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ .first-build-message Makefile.config +version.stamp TAGS tags *cscope* diff --git a/Makefile.local b/Makefile.local index 174506c..3a56c06 100644 --- a/Makefile.local +++ b/Makefile.local @@ -22,6 +22,11 @@ VERSION:=$(shell cat ${srcdir}/version) ifeq ($(filter release release-message pre-release update-versions,$(MAKECMDGOALS)),) ifeq ($(IS_GIT),yes) VERSION:=$(shell git describe --match '[0-9.]*'|sed -e s/_/~/ -e s/-/+/ -e s/-/~/) +# Write the file 'version.stamp' in case its contents differ from $(VERSION) +FILE_VERSION:=$(shell test -f version.stamp && read vs < version.stamp || vs=; echo $$vs) +ifneq ($(FILE_VERSION),$(VERSION)) + $(shell echo "$(VERSION)" > version.stamp) +endif endif endif @@ -69,6 +74,11 @@ ifeq ($(shell cat .first-build-message 2>/dev/null),) endif endif +# Depend (also) on the file 'version'. In case of ifeq ($(IS_GIT),yes) +# this file may already have been updated. +version.stamp: version + echo $(VERSION) > $@ + $(TAR_FILE): if git tag -v $(VERSION) >/dev/null 2>&1; then \ ref=$(VERSION); \ @@ -280,6 +290,8 @@ notmuch_client_srcs = \ notmuch_client_modules = $(notmuch_client_srcs:.c=.o) +notmuch.o: version.stamp + notmuch: $(notmuch_client_modules) lib/libnotmuch.a util/libutil.a parse-time-string/libparse-time-string.a $(call quiet,CXX $(CFLAGS)) $^ $(FINAL_LIBNOTMUCH_LDFLAGS) -o $@ @@ -318,7 +330,7 @@ install-desktop: desktop-file-install --mode 0644 --dir "$(DESTDIR)$(desktop_dir)" notmuch.desktop SRCS := $(SRCS) $(notmuch_client_srcs) -CLEAN := $(CLEAN) notmuch notmuch-shared $(notmuch_client_modules) notmuch.elc +CLEAN := $(CLEAN) notmuch notmuch-shared $(notmuch_client_modules) version.stamp DISTCLEAN := $(DISTCLEAN) .first-build-message Makefile.config -- 1.8.0 ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
[PATCH v3 3/3] emacs: defun notmuch-hello-versions and bind 'v' in hello mode to it
If notmuch cli & notmuch emacs MUA versions differ, print also the emacs MUA version string (along with the cli version) to the minibuffer. --- emacs/notmuch-hello.el | 15 +-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/emacs/notmuch-hello.el b/emacs/notmuch-hello.el index 7b3d76b..f5e7268 100644 --- a/emacs/notmuch-hello.el +++ b/emacs/notmuch-hello.el @@ -513,6 +513,18 @@ Such a list can be computed with `notmuch-hello-query-counts'." (remove-hook 'window-configuration-change-hook #'notmuch-hello-window-configuration-change +;; the following variable is defined as being defconst in notmuch.el +(defvar notmuch-emacs-version) + +(defun notmuch-hello-versions () + "Display the notmuch version(s)" + (interactive) + (let ((notmuch-cli-version (notmuch-version))) +(message "notmuch version %s" +(if (string= notmuch-emacs-version notmuch-cli-version) +notmuch-cli-version + (concat notmuch-cli-version + " (emacs mua version " notmuch-emacs-version ")") (defvar notmuch-hello-mode-map (let ((map (if (fboundp 'make-composed-keymap) @@ -523,8 +535,7 @@ Such a list can be computed with `notmuch-hello-query-counts'." ;; it's unlikely to change. (copy-keymap widget-keymap (set-keymap-parent map notmuch-common-keymap) -(define-key map "v" (lambda () "Display the notmuch version" (interactive) - (message "notmuch version %s" (notmuch-version +(define-key map "v" 'notmuch-hello-versions) (define-key map (kbd "") 'widget-backward) map) "Keymap for \"notmuch hello\" buffers.") -- 1.8.0 ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
v3 of version change detection and notmuch emacs/hello version(s)
This is v3 of id:1393024837-30394-1-git-send-email-tomi.oll...@iki.fi The only change is that version.stamp was added to root .gitignore file. ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
[PATCH v3 2/3] emacs: defconst notmuch-emacs-version to a value during byte compilation
The notmuch cli program and emacs lisp versions may differ. For now we can help users with their emacs client problems better if we can ask what version of emacs MUA they are running. In the future we can put the emacs MUA version to User-Agent: string in outgoing mail. --- emacs/Makefile.local | 6 +- emacs/notmuch.el | 7 +++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/emacs/Makefile.local b/emacs/Makefile.local index 6a39b32..9e3fb7a 100644 --- a/emacs/Makefile.local +++ b/emacs/Makefile.local @@ -24,6 +24,8 @@ emacs_images := \ emacs_bytecode = $(emacs_sources:.el=.elc) +$(dir)/notmuch.elc: version.stamp + # Because of defmacro's and defsubst's, we have to account for load # dependencies between Elisp files when byte compiling. Otherwise, # the byte compiler may load an old .elc file when processing a @@ -49,7 +51,9 @@ CLEAN+=$(dir)/.eldeps $(dir)/.eldeps.tmp $(dir)/.eldeps.x ifeq ($(HAVE_EMACS),1) %.elc: %.el $(global_deps) - $(call quiet,EMACS) --directory emacs -batch -f batch-byte-compile $< + $(call quiet,EMACS) --directory emacs \ + --eval "(setq notmuch--version \"$(VERSION)\")" \ + -batch -f batch-byte-compile $< endif ifeq ($(WITH_EMACS),1) diff --git a/emacs/notmuch.el b/emacs/notmuch.el index 0471750..1b15054 100644 --- a/emacs/notmuch.el +++ b/emacs/notmuch.el @@ -81,6 +81,13 @@ To enter a line break in customize, press \\[quoted-insert] C-j." :type '(alist :key-type (string) :value-type (string)) :group 'notmuch-search) +;; defconst notmuch-version to a value during build-time byte compilation... +(defconst notmuch-emacs-version + (eval-when-compile (if (boundp 'notmuch--version) +notmuch--version + "unknown")) + "Version string of this version of Notmuch Emacs MUA.") + (defvar notmuch-query-history nil "Variable to store minibuffer history for notmuch queries") -- 1.8.0 ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
[DRAFT PATCH] notmuch new: do not ignore '.notmuch' in non-toplevel directories
So that users may have email in subdir/.notmuch directories. --- Compiles, current tests pass. might ignore database_path/.notmuch and might descent into database_path/.../.notmuch :D Tomi notmuch-new.c | 18 ++ 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/notmuch-new.c b/notmuch-new.c index 8529fdd..b17bd75 100644 --- a/notmuch-new.c +++ b/notmuch-new.c @@ -344,7 +344,8 @@ add_file (notmuch_database_t *notmuch, const char *filename, static notmuch_status_t add_files (notmuch_database_t *notmuch, const char *path, - add_files_state_t *state) + add_files_state_t *state, + int dirlevel) { DIR *dir = NULL; struct dirent *entry = NULL; @@ -469,11 +470,11 @@ add_files (notmuch_database_t *notmuch, if (strcmp (entry->d_name, ".") == 0 || strcmp (entry->d_name, "..") == 0 || (is_maildir && strcmp (entry->d_name, "tmp") == 0) || - strcmp (entry->d_name, ".notmuch") == 0) + (dirlevel == 0 && strcmp (entry->d_name, ".notmuch") == 0)) continue; next = talloc_asprintf (notmuch, "%s/%s", path, entry->d_name); - status = add_files (notmuch, next, state); + status = add_files (notmuch, next, state, dirlevel + 1); if (status) { ret = status; goto DONE; @@ -702,7 +703,8 @@ stop_progress_printing_timer (void) * initialized to zero by the top-level caller before calling * count_files). */ static void -count_files (const char *path, int *count, add_files_state_t *state) +count_files (const char *path, int *count, add_files_state_t *state, +int dirlevel) { struct dirent *entry = NULL; char *next; @@ -725,7 +727,7 @@ count_files (const char *path, int *count, add_files_state_t *state) */ if (strcmp (entry->d_name, ".") == 0 || strcmp (entry->d_name, "..") == 0 || - strcmp (entry->d_name, ".notmuch") == 0 || + (dirlevel == 0 && strcmp (entry->d_name, ".notmuch") == 0) || _entry_in_ignore_list (entry->d_name, state)) { if (state->debug && _entry_in_ignore_list (entry->d_name, state)) @@ -750,7 +752,7 @@ count_files (const char *path, int *count, add_files_state_t *state) fflush (stdout); } } else if (entry_type == S_IFDIR) { - count_files (next, count, state); + count_files (next, count, state, dirlevel + 1); } free (next); @@ -962,7 +964,7 @@ notmuch_new_command (notmuch_config_t *config, int argc, char *argv[]) int count; count = 0; - count_files (db_path, &count, &add_files_state); + count_files (db_path, &count, &add_files_state, 0); if (interrupted) return EXIT_FAILURE; @@ -1021,7 +1023,7 @@ notmuch_new_command (notmuch_config_t *config, int argc, char *argv[]) timer_is_active = TRUE; } -ret = add_files (notmuch, db_path, &add_files_state); +ret = add_files (notmuch, db_path, &add_files_state, 0); if (ret) goto DONE; -- 1.8.4.2 ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
Re: [PATCH 0/3] check new.tags for invalid tags
On Sun, Feb 23 2014, Jani Nikula wrote: > On Sun, 23 Feb 2014, Rob Browning wrote: >> In the [new] section, "tags=;" will cause notmuch to create empty tags >> that are fairly hard to remove from the command line. > > Clearly broken. This series fixes the issue at the cli > level. (Forbidding empty tags at the lib level is slightly more > complicated, as we would still have to ensure old dump files can be > restored.) > >> After some help on #bup, here's what I came up with to remove them, >> though it assumes that the empty tag "+ " will always be first in dump's >> output: >> >> notmuch dump --format=batch-tag 'tag:""' | perl -pe 's/^\+ //' \ >> | notmuch restore --format=batch-tag >> >> And note that you have to use restore, "notmuch tag --batch" doesn't >> appear to accept "- " as a tag, even though dump will produce "+ ". > > I didn't check this further, but the regular, non-batch notmuch tag > should still work for removal of empty tags. LGTM. $ notmuch tag + -- id:edc2bc900f75bb2e72be2037e2df9105be7f0273.1393174108.git.j...@nikula.org Error: empty tag forbiddenzsh: exit 1 notmuch tag + -- $ notmuch restore --accumulate + id:edc2bc900f75bb2e72be2037e2df9105be7f0273.1393174108.git.j...@nikula.org -- notmuch search shows space after ( to inform there is empty tag. $ notmuch tag - -- id:edc2bc900f75bb2e72be2037e2df9105be7f0273.1393174108.git.j...@nikula.org notmuch search no longer shows space after ( Also, SomeBody(tm) should add '\n' to the fprintf() in tag-util.c:175 (line number after applying these patches). Tomi > > BR, > Jani. > > Jani Nikula (3): > cli: export function for illegal tag checking > cli: make sure notmuch new and insert don't add invalid tags > test: add tests for invalid new.tags > > notmuch-insert.c| 9 + > notmuch-new.c | 14 +- > tag-util.c | 9 + > tag-util.h | 12 > test/T050-new.sh| 17 + > test/T070-insert.sh | 19 +++ > 6 files changed, 71 insertions(+), 9 deletions(-) > > -- > 1.8.5.3 > > ___ > notmuch mailing list > notmuch@notmuchmail.org > http://notmuchmail.org/mailman/listinfo/notmuch ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
[PATCH v2 05/13] test: fix test for literal folder: search
Jani Nikula writes: > Some of the folder: matching capabilities are lost in the > probabilistic to boolean prefix change. Fix them. the first 5 look copacetic. d
Re: [RFC Patch v3 2/3] doc: add target rst2man to build man pages using rst2man
On Sun, Feb 23 2014, David Bremner wrote: > Many people have docutils installed, but not sphinx. Allow these > people to build the man pages. +1 from me to start having manuals in reStructuredText format and then converting these to the target formats. Some comments on the patch series below: Building any docs using this is not yet activated ? Anyway, I tried to build manual pages using 'make man' and got this: $ make man sphinx-build -b man -d doc/_build/doctrees -q -c doc doc doc/_build/man Making output directory... Sphinx error: Builder name man not registered No fallback to use rst2man... Comments regarding prerst2man.py inline below: Tomi > --- // stuff deleted // > diff --git a/doc/rst2man/prerst2man.py b/doc/rst2man/prerst2man.py > new file mode 100644 > index 000..797dd20 > --- /dev/null > +++ b/doc/rst2man/prerst2man.py > @@ -0,0 +1,53 @@ > +from sys import argv > +from datetime import date > +import re > + > +sourcedir=argv[1] > +outdir=argv[2] Style! run pep8 prerst2html.py and fix the issues it prints to the screen, like ' = ' above and remove trailing semicolon below... (and also pep8(1) doc/conf.py. > + > +execfile(sourcedir+"/conf.py"); > + > + > + > + > +def header(file,startdocname, command, description, authors, section): > +file.write(""" > +{:s} > +{:s} > +{:s} > + > +:Date: {:s} > +:Version: {:s} > +:Manual section: {:d} > +:Manual group: {:s} For python < 2.7 these needs to be {0:s}, {1:s}, {2:s}.. {5:d}... > + > +""".format( > +'-' * len(description), > +description, > +'-' * len(description), > +date.today().isoformat(),release,section,project)) Replace date.today.isoformat() with date determined from other sources (NEWS file?) > + > +blankre = re.compile("^\s*$") > +for page in man_pages: > +outfile = open(outdir+"/"+page[0]+'.rst','w') > +infile = open(sourcedir+"/"+page[0]+".rst",'r') In addition to formatting above, use either ".rst" or '.rst' (and perhaps other quotations in these 2 lines) for consistency. > + > + > +# this is a crude hack. We look for the first blank line, and > +# insert the rst2man header there. > +# > +# XXX consider really parsing input > + > +count=0 > +lines = infile.readlines() > +for line in lines: > +outfile.write(line); > +if (blankre.match(line)): > +break > +count = count + 1 > + > +del lines[0:count+1] pep8 will in the lime above (as it is not lines[0:count + 1]) I might not have complained but... :D > + > +header(outfile,*page) > + > +outfile.write("".join(lines)) > -- > 1.8.5.3 ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
[PATCH] man: escape backslash in notmuch-tag example
The example was originally intended to have a literal backslash in it, but '\ ' is interpreted by nroff as a non-breaking space. It doesn't make much difference to the example, but the non-breaking space triggers a bug in doclifter. --- Tomi sortof convinced me on IRC that \e was a better choice that \\. I also looked at the groff manual, but that mostly encouraged me to work more on converting to something other than *roff. man/man1/notmuch-tag.1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/man/man1/notmuch-tag.1 b/man/man1/notmuch-tag.1 index 710fae6..f4fb1f3 100644 --- a/man/man1/notmuch-tag.1 +++ b/man/man1/notmuch-tag.1 @@ -126,7 +126,7 @@ of the tag +space%20in%20tags -- Two # add tag '(tags)', among other stunts. -+crazy{ +(tags) +&are +#possible\ -- tag:"space in tags" ++crazy{ +(tags) +&are +#possible\e -- tag:"space in tags" +match*crazy -- tag:crazy{ +some_tag -- id:"this is ""nauty)""" .fi -- 1.8.5.3
[PATCH 0/3] check new.tags for invalid tags
On Sun, 23 Feb 2014, Rob Browning wrote: > In the [new] section, "tags=;" will cause notmuch to create empty tags > that are fairly hard to remove from the command line. Clearly broken. This series fixes the issue at the cli level. (Forbidding empty tags at the lib level is slightly more complicated, as we would still have to ensure old dump files can be restored.) > After some help on #bup, here's what I came up with to remove them, > though it assumes that the empty tag "+ " will always be first in dump's > output: > > notmuch dump --format=batch-tag 'tag:""' | perl -pe 's/^\+ //' \ > | notmuch restore --format=batch-tag > > And note that you have to use restore, "notmuch tag --batch" doesn't > appear to accept "- " as a tag, even though dump will produce "+ ". I didn't check this further, but the regular, non-batch notmuch tag should still work for removal of empty tags. BR, Jani. Jani Nikula (3): cli: export function for illegal tag checking cli: make sure notmuch new and insert don't add invalid tags test: add tests for invalid new.tags notmuch-insert.c| 9 + notmuch-new.c | 14 +- tag-util.c | 9 + tag-util.h | 12 test/T050-new.sh| 17 + test/T070-insert.sh | 19 +++ 6 files changed, 71 insertions(+), 9 deletions(-) -- 1.8.5.3 ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
[PATCH 1/3] cli: export function for illegal tag checking
This lets us check for forbidden tags consistently across the cli. No functional changes. --- tag-util.c | 9 + tag-util.h | 12 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/tag-util.c b/tag-util.c index 3bde4097372a..e2d5b795acc3 100644 --- a/tag-util.c +++ b/tag-util.c @@ -31,14 +31,7 @@ line_error (tag_parse_status_t status, return status; } -/* - * Test tags for some forbidden cases. - * - * return: NULL if OK, - *explanatory message otherwise. - */ - -static const char * +const char * illegal_tag (const char *tag, notmuch_bool_t remove) { diff --git a/tag-util.h b/tag-util.h index 4628f1630ad6..8a4074ce168f 100644 --- a/tag-util.h +++ b/tag-util.h @@ -90,6 +90,18 @@ parse_tag_command_line (void *ctx, int argc, char **argv, char **query_str, tag_op_list_t *ops); /* + * Test tags for some forbidden cases. + * + * Relax the checks if 'remove' is true to allow removal of previously + * added forbidden tags. + * + * return: NULL if OK, + *explanatory message otherwise. + */ +const char * +illegal_tag (const char *tag, notmuch_bool_t remove); + +/* * Create an empty list of tag operations * * ctx is passed to talloc -- 1.8.5.3 ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
[PATCH 2/3] cli: make sure notmuch new and insert don't add invalid tags
Check new.tags configuration values before doing anything, and bail out on invalid values. --- notmuch-insert.c | 9 + notmuch-new.c| 14 +- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/notmuch-insert.c b/notmuch-insert.c index cd6de88f6891..6752fc8de255 100644 --- a/notmuch-insert.c +++ b/notmuch-insert.c @@ -431,6 +431,15 @@ notmuch_insert_command (notmuch_config_t *config, int argc, char *argv[]) return EXIT_FAILURE; } for (i = 0; i < new_tags_length; i++) { + const char *error_msg; + + error_msg = illegal_tag (new_tags[i], FALSE); + if (error_msg) { + fprintf (stderr, "Error: tag '%s' in new.tags: %s\n", +new_tags[i], error_msg); + return EXIT_FAILURE; + } + if (tag_op_list_append (tag_ops, new_tags[i], FALSE)) return EXIT_FAILURE; } diff --git a/notmuch-new.c b/notmuch-new.c index 8529fdd3eac7..82acf695353e 100644 --- a/notmuch-new.c +++ b/notmuch-new.c @@ -19,6 +19,7 @@ */ #include "notmuch-client.h" +#include "tag-util.h" #include @@ -918,7 +919,7 @@ notmuch_new_command (notmuch_config_t *config, int argc, char *argv[]) struct sigaction action; _filename_node_t *f; int opt_index; -int i; +unsigned int i; notmuch_bool_t timer_is_active = FALSE; notmuch_bool_t no_hooks = FALSE; notmuch_bool_t quiet = FALSE, verbose = FALSE; @@ -950,6 +951,17 @@ notmuch_new_command (notmuch_config_t *config, int argc, char *argv[]) add_files_state.synchronize_flags = notmuch_config_get_maildir_synchronize_flags (config); db_path = notmuch_config_get_database_path (config); +for (i = 0; i < add_files_state.new_tags_length; i++) { + const char *error_msg; + + error_msg = illegal_tag (add_files_state.new_tags[i], FALSE); + if (error_msg) { + fprintf (stderr, "Error: tag '%s' in new.tags: %s\n", +add_files_state.new_tags[i], error_msg); + return EXIT_FAILURE; + } +} + if (!no_hooks) { ret = notmuch_run_hook (db_path, "pre-new"); if (ret) -- 1.8.5.3 ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
[PATCH 3/3] test: add tests for invalid new.tags
Similar tests for both notmuch new and insert. --- test/T050-new.sh| 17 + test/T070-insert.sh | 19 +++ 2 files changed, 36 insertions(+) diff --git a/test/T050-new.sh b/test/T050-new.sh index b7668ff0c4bc..ad46ee6d51b6 100755 --- a/test/T050-new.sh +++ b/test/T050-new.sh @@ -263,4 +263,21 @@ notmuch search --format=text0 --output=files --offset=1 --limit=1 '*' | xargs -0 output=$(NOTMUCH_NEW --quiet) test_expect_equal "$output" "" +OLDCONFIG=$(notmuch config get new.tags) + +test_begin_subtest "Empty tags in new.tags are forbidden" +notmuch config set new.tags "foo;;bar" +output=$(NOTMUCH_NEW 2>&1) +test_expect_equal "$output" "Error: tag '' in new.tags: empty tag forbidden" + +test_begin_subtest "Tags starting with '-' in new.tags are forbidden" +notmuch config set new.tags "-foo;bar" +output=$(NOTMUCH_NEW 2>&1) +test_expect_equal "$output" "Error: tag '-foo' in new.tags: tag starting with '-' forbidden" + +test_expect_code 1 "Invalid tags set exit code" \ +"NOTMUCH_NEW 2>&1" + +notmuch config set new.tags $OLDCONFIG + test_done diff --git a/test/T070-insert.sh b/test/T070-insert.sh index e8dc4c099ed1..b77c5e13c87f 100755 --- a/test/T070-insert.sh +++ b/test/T070-insert.sh @@ -164,4 +164,23 @@ gen_insert_msg test_expect_code 1 "Insert message, create invalid subfolder" \ "notmuch insert --folder=../G --create-folder $gen_msg_filename" +OLDCONFIG=$(notmuch config get new.tags) + +test_begin_subtest "Empty tags in new.tags are forbidden" +notmuch config set new.tags "foo;;bar" +gen_insert_msg +output=$(notmuch insert $gen_msg_filename 2>&1) +test_expect_equal "$output" "Error: tag '' in new.tags: empty tag forbidden" + +test_begin_subtest "Tags starting with '-' in new.tags are forbidden" +notmuch config set new.tags "-foo;bar" +gen_insert_msg +output=$(notmuch insert $gen_msg_filename 2>&1) +test_expect_equal "$output" "Error: tag '-foo' in new.tags: tag starting with '-' forbidden" + +test_expect_code 1 "Invalid tags set exit code" \ +"notmuch insert $gen_msg_filename 2>&1" + +notmuch config set new.tags $OLDCONFIG + test_done -- 1.8.5.3 ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
Re: [PATCH v2 05/13] test: fix test for literal folder: search
Jani Nikula writes: > Some of the folder: matching capabilities are lost in the > probabilistic to boolean prefix change. Fix them. the first 5 look copacetic. d ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
[PATCH] man: escape backslash in notmuch-tag example
The example was originally intended to have a literal backslash in it, but '\ ' is interpreted by nroff as a non-breaking space. It doesn't make much difference to the example, but the non-breaking space triggers a bug in doclifter. --- Tomi sortof convinced me on IRC that \e was a better choice that \\. I also looked at the groff manual, but that mostly encouraged me to work more on converting to something other than *roff. man/man1/notmuch-tag.1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/man/man1/notmuch-tag.1 b/man/man1/notmuch-tag.1 index 710fae6..f4fb1f3 100644 --- a/man/man1/notmuch-tag.1 +++ b/man/man1/notmuch-tag.1 @@ -126,7 +126,7 @@ of the tag +space%20in%20tags -- Two # add tag '(tags)', among other stunts. -+crazy{ +(tags) +&are +#possible\ -- tag:"space in tags" ++crazy{ +(tags) +&are +#possible\e -- tag:"space in tags" +match*crazy -- tag:crazy{ +some_tag -- id:"this is ""nauty)""" .fi -- 1.8.5.3 ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
Re: [PATCH v2 00/13] literal folder: prefix, new path: prefix
On Sun, Feb 23 2014, Mark Walters wrote: > I have read most of this series, tested it and run the tests and LGTM +1. > > I read the C code fairly carefully, the tests rather less so but they > looked sane, and I didn't really look at patch 9 for building old > databases. Well, I can add (at this point) that patch 9 is tolerable... > > Best wishes > > Mark Tomi > > > > > On Sat, 22 Feb 2014, Jani Nikula wrote: >> Hi all, this is v2 of id:cover.1389304779.git.j...@nikula.org. >> >> The new path: prefix is a literal boolean prefix matching the paths, >> relative from the maildir root, of the message files. There's no >> interpretation of the maildir special cur/new folders, but a recursive >> match is provided with "/**" suffix. See the patch for details. >> >> The folder: prefix becomes a literal boolean prefix, similar to path:, >> except it matches the maildir cur/new folders in addition to the >> specified path. There's no recursive version. >> >> Patches 1-5 add the above. >> >> Patches 6-8 change the test infrastructure to make it easier to add >> multiple corpuses, and adds a new test for path: and folder:. >> >> Patches 9-11 add support for testing the database upgrade. >> >> Patches 12-13 update man pages. >> >> >> I've dropped most of the content in patches 7 and 10 due to their >> size. The patches (and the whole series) are available in the >> boolean-folder-and-path-v2 branch at >> git://gitorious.org/jani/notmuch.git. Web interface at >> https://gitorious.org/jani/notmuch/commits/0b3dd2d1cc6c413ea07ea326883ac448499c0e79. >> >> >> WARNING! The change requires a database format version bump, and a >> database upgrade, which is automatically done on 'notmuch new'. The >> upgrade is irreversible if you want to try this on your database! A >> complete database rebuild is required for reverting the database format >> version. Make sure your backups are in order! >> >> >> BR, >> Jani. >> >> >> Jani Nikula (13): >> lib: refactor folder term update after filename removal >> lib: add support for path: prefix searches >> test: make insert test use the path: prefix >> lib: make folder: prefix literal >> test: fix test for literal folder: search >> test: make it possible to have several corpora >> test: add new corpus with folders >> test: add tests for the new boolean folder: and path: prefixes >> devel: add script to generate test databases >> test: add test database in format version 1 >> test: add database upgrade test from format version 1 to 2 >> man: update man pages for folder: and path: search terms >> man: try to clarify the folder: and path: vs. --output=files confusion >> >> devel/gen-testdb.sh| 124 >> lib/database.cc| 45 - >> lib/message.cc | 249 --- >> lib/notmuch-private.h | 3 + >> man/man1/notmuch-search.1 | 10 +- >> man/man7/notmuch-search-terms.7| 28 ++- >> test/.gitignore| 2 +- >> test/Makefile.local| 2 +- >> test/T070-insert.sh| 10 +- >> test/T100-search-by-folder.sh | 24 ++- >> test/T101-search-by-folder-and-path.sh | 83 >> test/T480-hex-escaping.sh | 4 +- >> test/T530-upgrade.sh | 103 ++ >> test/corpus/{ => default}/cur/01:2,| 0 >> test/corpus/{ => default}/cur/02:2,| 0 >> test/corpus/{ => default}/cur/03:2,| 0 >> test/corpus/{ => default}/cur/04:2,| 0 >> test/corpus/{ => default}/cur/05:2,| 0 >> test/corpus/{ => default}/cur/06:2,| 0 >> test/corpus/{ => default}/cur/07:2,| 0 >> test/corpus/{ => default}/cur/08:2,| 0 >> test/corpus/{ => default}/cur/09:2,| 0 >> test/corpus/{ => default}/cur/10:2,| 0 >> test/corpus/{ => default}/cur/11:2,| 0 >> test/corpus/{ => default}/cur/12:2,| 0 >> test/corpus/{ => default}/cur/13:2,| 0 >> test/corpus/{ => default}/cur/14:2,| 0 >> test/corpus/{ => default}/cur/15:2,| 0 >> test/corpus/{ => default}/cur/16:2,| 0 >> test/corpus/{ => default}/cur/17:2,| 0 >> test/corpus/{ => default}/cur/18:2,| 0 >> test/corpus/{ => default}/cur/19:2,| 0 >> test/corpus/{ => default}/cur/20:2,| 0 >> test/corpus/{ => default}/cur/21:2,| 0 >> test/corpus/{ => default}/cur/22:2,| 0 >> test/corpus/{ => default}/cur/23:2,| 0 >> test/corpus/{ => default}/cur/24:2,| 0 >> test/corpus/{ => default}/cur/25:2,| 0 >> test/corpus/{ => default}/cur/26:2,| 0 >> test/corpus/{ => default}/cur/27:2,| 0 >> test/corpus/{ => default}/cur/28:2,| 0 >> test/corpus/{ => default}/cur/29:2,| 0 >> test/corpus/{ => default}/cur/30:2,| 0 >> test/corpus/{ => default}/cur/31:2,| 0 >> test/corpus/{ => default}/cur/32:2,| 0 >> test/corpus/{ => default}/cur/33:2,
Weird behaviour in notmuch new
Hi I was experimenting with letting notmuch new take an argument to tell it to scan only a particular directory (and sub-directories) for new messages. I came across the following strange behaviour which is also present in master (with a fresh database) I have a bunch of maildirs in /home/mail: so folders .mail.foo/ .mail.bar/ each of which has cur/new/tmp and all the messages are in cur. If I do mv .mail.foo .mail.bar/ and run notmuch new I get the expected lots of renames (900 or so in the case I was trying). But if I then do mv .mail.bar/.mail.foo . and run notmuch new almost all the messages get removed (but 30 renames do get detected). If I then do touch .mail.foo/* the messages get found again I am guessing the 30 renames might be because those 30 have duplicates somewhere else. But the other behaviour has me puzzled. Best wishes Mark
[PATCH v2 13/13] man: try to clarify the folder: and path: vs. --output=files confusion
--- man/man1/notmuch-search.1 | 10 -- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/man/man1/notmuch-search.1 b/man/man1/notmuch-search.1 index 55a81e79fce4..a2b1ae43f411 100644 --- a/man/man1/notmuch-search.1 +++ b/man/man1/notmuch-search.1 @@ -82,8 +82,14 @@ one per line (\-\-format=text), separated by null characters S-Expression list (\-\-format=sexp). Note that each message may have multiple filenames associated with it. -All of them are included in the output, unless limited with the -\-\-duplicate=N option. +All of them are included in the output (unless limited with the +\-\-duplicate=N option). This may be particularly confusing for +.B folder: +or +.B path: +searches in a specified directory, as the messages may have duplicates +in other directories that are included in the output, although these +files alone would not match the search. .RE .RS 4 .TP 4 -- 1.8.5.3
[PATCH v2 12/13] man: update man pages for folder: and path: search terms
--- man/man7/notmuch-search-terms.7 | 28 ++-- 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/man/man7/notmuch-search-terms.7 b/man/man7/notmuch-search-terms.7 index a768b630a4d1..907403dd6f2e 100644 --- a/man/man7/notmuch-search-terms.7 +++ b/man/man7/notmuch-search-terms.7 @@ -54,6 +54,8 @@ terms to match against specific portions of an email, (where folder: + path: or path:/** + date:.. The @@ -101,12 +103,26 @@ thread ID values can be seen in the first column of output from The .B folder: -prefix can be used to search for email message files that are -contained within particular directories within the mail store. If the -same email message has multiple message files associated with it, it's -sufficient for a match that at least one of the files is contained -within a matching directory. Only the directory components below the -top-level mail database path are available to be searched. +and +.B path: +prefixes can be used to search for email message files that are +contained within particular directories within the mail store. The +directories are specified relative from the top-level mail database +path, and thus only the directory components below that are available +to be searched. + +The +.B folder: +prefix matches messages in the specified maildir folder, i.e. in the +specified directory and its "new" and "cur" subdirectories. The +.B path: +prefix matches messages in the specified directory only, unless the +"/**" suffix is used to denote the specified directory and all its +subdirectories recursively. For both, the empty string "" matches the +top level maildir folder or directory. If the same email message has +multiple message files associated with it, it's sufficient for a match +that at least one of the files is contained within a matching +directory. The .B date: -- 1.8.5.3
[PATCH v2 11/13] test: add database upgrade test from format version 1 to 2
Test the upgrade from probabilistic to boolean folder: terms, and addition of path: terms. --- test/T530-upgrade.sh | 103 +++ 1 file changed, 103 insertions(+) create mode 100755 test/T530-upgrade.sh diff --git a/test/T530-upgrade.sh b/test/T530-upgrade.sh new file mode 100755 index ..cf9914e380be --- /dev/null +++ b/test/T530-upgrade.sh @@ -0,0 +1,103 @@ +#!/usr/bin/env bash +test_description="database upgrade" + +. ./test-lib.sh + +tar zxf $TEST_DIRECTORY/test-databases/database-v1.tar.gz -C ${MAIL_DIR} --strip-components=1 + +test_begin_subtest "folder: search does not work with old database version" +output=$(notmuch search folder:foo) +test_expect_equal "$output" "" + +test_begin_subtest "path: search does not work with old database version" +output=$(notmuch search path:foo) +test_expect_equal "$output" "" + +test_begin_subtest "database upgrade from format version 1" +output=$(notmuch new) +test_expect_equal "$output" "\ +Welcome to a new version of notmuch! Your database will now be upgraded. +Your notmuch database has now been upgraded to database format version 2. +No new mail." + +test_begin_subtest "folder: no longer matches in the middle of path" +output=$(notmuch search folder:baz) +test_expect_equal "$output" "" + +test_begin_subtest "folder: search" +output=$(notmuch search --output=files folder:foo | sed -e "s,$MAIL_DIR,MAIL_DIR," | sort) +# bar/baz/05:2, and new/03:2, are duplicates of foo/05:2, and +# foo/new/03:2, respectively +test_expect_equal "$output" "MAIL_DIR/bar/baz/05:2, +MAIL_DIR/foo/05:2, +MAIL_DIR/foo/06:2, +MAIL_DIR/foo/cur/07:2, +MAIL_DIR/foo/cur/08:2, +MAIL_DIR/foo/new/03:2, +MAIL_DIR/foo/new/09:2, +MAIL_DIR/foo/new/10:2, +MAIL_DIR/new/03:2," + +test_begin_subtest "top level folder: search" +output=$(notmuch search --output=files folder:'""' | sed -e "s,$MAIL_DIR,MAIL_DIR," | sort) +# foo/new/03:2, is a duplicate of new/03:2, +test_expect_equal "$output" "MAIL_DIR/01:2, +MAIL_DIR/02:2, +MAIL_DIR/cur/29:2, +MAIL_DIR/cur/30:2, +MAIL_DIR/cur/31:2, +MAIL_DIR/cur/32:2, +MAIL_DIR/cur/33:2, +MAIL_DIR/cur/34:2, +MAIL_DIR/cur/35:2, +MAIL_DIR/cur/36:2, +MAIL_DIR/cur/37:2, +MAIL_DIR/cur/38:2, +MAIL_DIR/cur/39:2, +MAIL_DIR/cur/40:2, +MAIL_DIR/cur/41:2, +MAIL_DIR/cur/42:2, +MAIL_DIR/cur/43:2, +MAIL_DIR/cur/44:2, +MAIL_DIR/cur/45:2, +MAIL_DIR/cur/46:2, +MAIL_DIR/cur/47:2, +MAIL_DIR/cur/48:2, +MAIL_DIR/cur/49:2, +MAIL_DIR/cur/50:2, +MAIL_DIR/cur/52:2, +MAIL_DIR/cur/53:2, +MAIL_DIR/foo/new/03:2, +MAIL_DIR/new/03:2, +MAIL_DIR/new/04:2," + +test_begin_subtest "path: search" +output=$(notmuch search --output=files path:"bar" | sed -e "s,$MAIL_DIR,MAIL_DIR," | sort) +# foo/05:2, is a duplicate of bar/baz/05:2, +test_expect_equal "$output" "MAIL_DIR/bar/17:2, +MAIL_DIR/bar/18:2," + +test_begin_subtest "top level path: search" +output=$(notmuch search --output=files path:'""' | sed -e "s,$MAIL_DIR,MAIL_DIR," | sort) +test_expect_equal "$output" "MAIL_DIR/01:2, +MAIL_DIR/02:2," + +test_begin_subtest "recursive path: search" +output=$(notmuch search --output=files path:"bar/**" | sed -e "s,$MAIL_DIR,MAIL_DIR," | sort) +# foo/05:2, is a duplicate of bar/baz/05:2, +test_expect_equal "$output" "MAIL_DIR/bar/17:2, +MAIL_DIR/bar/18:2, +MAIL_DIR/bar/baz/05:2, +MAIL_DIR/bar/baz/23:2, +MAIL_DIR/bar/baz/24:2, +MAIL_DIR/bar/baz/cur/25:2, +MAIL_DIR/bar/baz/cur/26:2, +MAIL_DIR/bar/baz/new/27:2, +MAIL_DIR/bar/baz/new/28:2, +MAIL_DIR/bar/cur/19:2, +MAIL_DIR/bar/cur/20:2, +MAIL_DIR/bar/new/21:2, +MAIL_DIR/bar/new/22:2, +MAIL_DIR/foo/05:2," + +test_done -- 1.8.5.3
[PATCH v2 10/13] test: add test database in format version 1
Generated using: $ cd test $ ../devel/gen-testdb.sh -v 0.17 -c $PWD/corpus/folders -s v1 This database contains old style probabilistic folder: terms and no path: terms. --- corpus/database content dropped to save bandwidth, see https://gitorious.org/jani/notmuch/commit/88bcffe31441e62d19769a2a941a2965f8c91486 test/test-databases/README | 5 + test/test-databases/database-v1.tar.gz | Bin 0 -> 262063 bytes 2 files changed, 5 insertions(+) create mode 100644 test/test-databases/README create mode 100644 test/test-databases/database-v1.tar.gz diff --git a/test/test-databases/README b/test/test-databases/README new file mode 100644 index ..af5defe80728 --- /dev/null +++ b/test/test-databases/README @@ -0,1 +1,5 @@ +Notmuch test databases +== + +This directory contains pre-generated databases with their source +corpus, chiefly for the purpose of testing database upgrade. -- 1.8.5.3
[PATCH v2 09/13] devel: add script to generate test databases
Add script to generate notmuch test databases using specified versions of notmuch. This is useful for generating material for database upgrade tests. This reuses the test infrastructure to have a sandbox environment for notmuch new etc. --- devel/gen-testdb.sh | 124 1 file changed, 124 insertions(+) create mode 100755 devel/gen-testdb.sh diff --git a/devel/gen-testdb.sh b/devel/gen-testdb.sh new file mode 100755 index ..c291dfff98c9 --- /dev/null +++ b/devel/gen-testdb.sh @@ -0,0 +1,124 @@ +#!/usr/bin/env bash +# +# NAME +# gen-testdb.sh - generate test databases +# +# SYNOPSIS +# gen-testdb.sh -v NOTMUCH-VERSION [-c CORPUS-PATH] [-s TAR-SUFFIX] +# +# DESCRIPTION +# Generate a tarball containing the specified test corpus and +# the corresponding notmuch database, indexed using a specific +# version of notmuch, resulting in a specific version of the +# database. +# +# The specific version of notmuch will be built on the fly. +# Therefore the script must be run within a git repository to be +# able to build the old versions of notmuch. +# +# This script reuses the test infrastructure, and the script +# must be run from within the test directory. +# +# The output tarballs, named database-.tar.gz, are +# placed in the test/test-databases directory. +# +# OPTIONS +# -v NOTMUCH-VERSION +# Notmuch version in terms of a git tag or commit to use +# for generating the database. Required. +# +# -c CORPUS-PATH +# Path to a corpus to use for generating the +# database. Due to CWD changes within the test +# infrastructure, use absolute paths. Defaults to the +# test corpus. +# +# -s TAR-SUFFIX +# Suffix for the tarball basename. Empty by default. +# +# EXAMPLE +# +# Generate a database indexed with notmuch 0.17. Use the default +# test corpus. Name the tarball database-v1.tar.gz to reflect +# the fact that notmuch 0.17 used database version 1. +# +# $ cd test +# $ ../devel/gen-testdb.sh -v 0.17 -s v1 +# +# CAVEATS +# Test infrastructure options won't work. +# +# Any existing databases with the same name will be overwritten. +# +# It may not be possible to build old versions of notmuch with +# the set of dependencies that satisfy building the current +# version of notmuch. +# +# AUTHOR +# Jani Nikula +# +# LICENSE +# Same as notmuch test infrastructure (GPLv2+). +# + +test_description="database generation abusing test infrastructure" + +# immediate exit on subtest failure; see test_failure_ in test-lib.sh +immediate=t + +VERSION= +CORPUS= +SUFFIX= + +while getopts v:c:s: opt; do +case "$opt" in + v) VERSION="$OPTARG";; + c) CORPUS="$OPTARG";; + s) SUFFIX="-$OPTARG";; +esac +done +shift `expr $OPTIND - 1` + +. ./test-lib.sh + +CORPUS=${CORPUS:-${TEST_DIRECTORY}/corpus} + +test_expect_code 0 "notmuch version specified on the command line" \ +"test -n ${VERSION}" + +test_expect_code 0 "the specified version ${VERSION} refers to a commit" \ +"git show ${VERSION} >/dev/null 2>&1" + +BUILD_DIR="notmuch-${VERSION}" +test_expect_code 0 "generate snapshot of notmuch version ${VERSION}" \ +"git -C $TEST_DIRECTORY/.. archive --prefix=${BUILD_DIR}/ --format=tar ${VERSION} | tar x" + +# force version string +git describe --match '[0-9.]*' ${VERSION} > ${BUILD_DIR}/version + +test_expect_code 0 "configure and build notmuch version ${VERSION}" \ +"make -C ${BUILD_DIR}" + +# use the newly built notmuch +export PATH=./${BUILD_DIR}:$PATH + +test_begin_subtest "verify the newly built notmuch version" +test_expect_equal "`notmuch --version`" "notmuch `cat ${BUILD_DIR}/version`" + +# replace the existing mails, if any, with the specified corpus +rm -rf ${MAIL_DIR} +cp -a ${CORPUS} ${MAIL_DIR} + +test_expect_code 0 "index the corpus" \ +"notmuch new" + +# finally, wrap the resulting mail store and database in a tarball +DBNAME=database${SUFFIX} +cp -a ${MAIL_DIR} ${TMP_DIRECTORY}/${DBNAME} +tar zcf ${TMP_DIRECTORY}/${DBNAME}.tar.gz -C ${TMP_DIRECTORY} ${DBNAME} +mkdir -p ${TEST_DIRECTORY}/test-databases +cp -a ${TMP_DIRECTORY}/${DBNAME}.tar.gz ${TEST_DIRECTORY}/test-databases +test_expect_code 0 "create the output tarball ${DBNAME}.tar.gz" \ +"test -f ${TEST_DIRECTORY}/test-databases/${DBNAME}.tar.gz" + +test_done -- 1.8.5.3
[PATCH v2 08/13] test: add tests for the new boolean folder: and path: prefixes
Additional tests for the boolean folder: and path: prefixes. --- test/T101-search-by-folder-and-path.sh | 83 ++ 1 file changed, 83 insertions(+) create mode 100755 test/T101-search-by-folder-and-path.sh diff --git a/test/T101-search-by-folder-and-path.sh b/test/T101-search-by-folder-and-path.sh new file mode 100755 index ..9f809e46e110 --- /dev/null +++ b/test/T101-search-by-folder-and-path.sh @@ -0,0 +1,83 @@ +#!/usr/bin/env bash +test_description='"notmuch search" by folder: and path:' +. ./test-lib.sh + +add_email_corpus folders + +test_begin_subtest "folder: search" +output=$(notmuch search --output=files folder:foo | sed -e "s,$MAIL_DIR,MAIL_DIR," | sort) +# bar/baz/05:2, and new/03:2, are duplicates of foo/05:2, and +# foo/new/03:2, respectively +test_expect_equal "$output" "MAIL_DIR/bar/baz/05:2, +MAIL_DIR/foo/05:2, +MAIL_DIR/foo/06:2, +MAIL_DIR/foo/cur/07:2, +MAIL_DIR/foo/cur/08:2, +MAIL_DIR/foo/new/03:2, +MAIL_DIR/foo/new/09:2, +MAIL_DIR/foo/new/10:2, +MAIL_DIR/new/03:2," + +test_begin_subtest "top level folder: search" +output=$(notmuch search --output=files folder:'""' | sed -e "s,$MAIL_DIR,MAIL_DIR," | sort) +# foo/new/03:2, is a duplicate of new/03:2, +test_expect_equal "$output" "MAIL_DIR/01:2, +MAIL_DIR/02:2, +MAIL_DIR/cur/29:2, +MAIL_DIR/cur/30:2, +MAIL_DIR/cur/31:2, +MAIL_DIR/cur/32:2, +MAIL_DIR/cur/33:2, +MAIL_DIR/cur/34:2, +MAIL_DIR/cur/35:2, +MAIL_DIR/cur/36:2, +MAIL_DIR/cur/37:2, +MAIL_DIR/cur/38:2, +MAIL_DIR/cur/39:2, +MAIL_DIR/cur/40:2, +MAIL_DIR/cur/41:2, +MAIL_DIR/cur/42:2, +MAIL_DIR/cur/43:2, +MAIL_DIR/cur/44:2, +MAIL_DIR/cur/45:2, +MAIL_DIR/cur/46:2, +MAIL_DIR/cur/47:2, +MAIL_DIR/cur/48:2, +MAIL_DIR/cur/49:2, +MAIL_DIR/cur/50:2, +MAIL_DIR/cur/52:2, +MAIL_DIR/cur/53:2, +MAIL_DIR/foo/new/03:2, +MAIL_DIR/new/03:2, +MAIL_DIR/new/04:2," + +test_begin_subtest "path: search" +output=$(notmuch search --output=files path:"bar" | sed -e "s,$MAIL_DIR,MAIL_DIR," | sort) +# foo/05:2, is a duplicate of bar/baz/05:2, +test_expect_equal "$output" "MAIL_DIR/bar/17:2, +MAIL_DIR/bar/18:2," + +test_begin_subtest "top level path: search" +output=$(notmuch search --output=files path:'""' | sed -e "s,$MAIL_DIR,MAIL_DIR," | sort) +test_expect_equal "$output" "MAIL_DIR/01:2, +MAIL_DIR/02:2," + +test_begin_subtest "recursive path: search" +output=$(notmuch search --output=files path:"bar/**" | sed -e "s,$MAIL_DIR,MAIL_DIR," | sort) +# foo/05:2, is a duplicate of bar/baz/05:2, +test_expect_equal "$output" "MAIL_DIR/bar/17:2, +MAIL_DIR/bar/18:2, +MAIL_DIR/bar/baz/05:2, +MAIL_DIR/bar/baz/23:2, +MAIL_DIR/bar/baz/24:2, +MAIL_DIR/bar/baz/cur/25:2, +MAIL_DIR/bar/baz/cur/26:2, +MAIL_DIR/bar/baz/new/27:2, +MAIL_DIR/bar/baz/new/28:2, +MAIL_DIR/bar/cur/19:2, +MAIL_DIR/bar/cur/20:2, +MAIL_DIR/bar/new/21:2, +MAIL_DIR/bar/new/22:2, +MAIL_DIR/foo/05:2," + +test_done -- 1.8.5.3
[PATCH v2 07/13] test: add new corpus with folders
--- corpus content dropped to save bandwidth, see https://gitorious.org/jani/notmuch/commit/3aff18b55de46e3b27748376a59cda41b6cd7f6d test/corpus/folders/01:2, | 34 test/corpus/folders/02:2, | 32 +++ test/corpus/folders/bar/17:2, | 23 +++ test/corpus/folders/bar/18:2, | 12 ++ test/corpus/folders/bar/baz/05:2, | 104 ++ test/corpus/folders/bar/baz/23:2, | 145 ++ test/corpus/folders/bar/baz/24:2, | 204 +++ test/corpus/folders/bar/baz/cur/25:2, | 32 +++ test/corpus/folders/bar/baz/cur/26:2, | 121 test/corpus/folders/bar/baz/new/27:2, | 21 ++ test/corpus/folders/bar/baz/new/28:2, | 38 test/corpus/folders/bar/cur/19:2, | 360 ++ test/corpus/folders/bar/cur/20:2, | 101 ++ test/corpus/folders/bar/new/21:2, | 102 ++ test/corpus/folders/bar/new/22:2, | 84 test/corpus/folders/cur/29:2, | 21 ++ test/corpus/folders/cur/30:2, | 75 +++ test/corpus/folders/cur/31:2, | 31 +++ test/corpus/folders/cur/32:2, | 165 test/corpus/folders/cur/33:2, | 13 ++ test/corpus/folders/cur/34:2, | 46 + test/corpus/folders/cur/35:2, | 24 +++ test/corpus/folders/cur/36:2, | 25 +++ test/corpus/folders/cur/37:2, | 22 +++ test/corpus/folders/cur/38:2, | 40 test/corpus/folders/cur/39:2, | 32 +++ test/corpus/folders/cur/40:2, | 31 +++ test/corpus/folders/cur/41:2, | 37 test/corpus/folders/cur/42:2, | 30 +++ test/corpus/folders/cur/43:2, | 26 +++ test/corpus/folders/cur/44:2, | 29 +++ test/corpus/folders/cur/45:2, | 41 test/corpus/folders/cur/46:2, | 57 ++ test/corpus/folders/cur/47:2, | 84 test/corpus/folders/cur/48:2, | 17 ++ test/corpus/folders/cur/49:2, | 33 test/corpus/folders/cur/50:2, | 39 test/corpus/folders/cur/52:2, | 39 test/corpus/folders/cur/53:2, | 20 ++ test/corpus/folders/foo/05:2, | 104 ++ test/corpus/folders/foo/06:2, | 36 test/corpus/folders/foo/baz/11:2, | 27 +++ test/corpus/folders/foo/baz/12:2, | 27 +++ test/corpus/folders/foo/baz/cur/13:2, | 178 + test/corpus/folders/foo/baz/cur/14:2, | 39 test/corpus/folders/foo/baz/new/15:2, | 22 +++ test/corpus/folders/foo/baz/new/16:2, | 27 +++ test/corpus/folders/foo/cur/07:2, | 57 ++ test/corpus/folders/foo/cur/08:2, | 87 test/corpus/folders/foo/new/03:2, | 93 + test/corpus/folders/foo/new/09:2, | 33 test/corpus/folders/foo/new/10:2, | 54 + test/corpus/folders/new/03:2, | 93 + test/corpus/folders/new/04:2, | 84 54 files changed, 3351 insertions(+) create mode 100644 test/corpus/folders/01:2, create mode 100644 test/corpus/folders/02:2, create mode 100644 test/corpus/folders/bar/17:2, create mode 100644 test/corpus/folders/bar/18:2, create mode 100644 test/corpus/folders/bar/baz/05:2, create mode 100644 test/corpus/folders/bar/baz/23:2, create mode 100644 test/corpus/folders/bar/baz/24:2, create mode 100644 test/corpus/folders/bar/baz/cur/25:2, create mode 100644 test/corpus/folders/bar/baz/cur/26:2, create mode 100644 test/corpus/folders/bar/baz/new/27:2, create mode 100644 test/corpus/folders/bar/baz/new/28:2, create mode 100644 test/corpus/folders/bar/cur/19:2, create mode 100644 test/corpus/folders/bar/cur/20:2, create mode 100644 test/corpus/folders/bar/new/21:2, create mode 100644 test/corpus/folders/bar/new/22:2, create mode 100644 test/corpus/folders/cur/29:2, create mode 100644 test/corpus/folders/cur/30:2, create mode 100644 test/corpus/folders/cur/31:2, create mode 100644 test/corpus/folders/cur/32:2, create mode 100644 test/corpus/folders/cur/33:2, create mode 100644 test/corpus/folders/cur/34:2, create mode 100644 test/corpus/folders/cur/35:2, create mode 100644 test/corpus/folders/cur/36:2, create mode 100644 test/corpus/folders/cur/37:2, create mode 100644 test/corpus/folders/cur/38:2, create mode 100644 test/corpus/folders/cur/39:2, create mode 100644 test/corpus/folders/cur/40:2, create mode 100644 test/corpus/folders/cur/41:2, create mode 100644 test/corpus/folders/cur/42:2, create mode 100644 test/corpus/folders/cur/43:2, create mode 100644 test/corpus/folders/cur/44:2, create mode 100644 test/corpus/folders/cur/45:2, create mode 100644 test/corpus/folders/cur/46:2, create mode 100644 test/corpus/folders/cur/47:2, create mode 100644 test/corpus/folders/cur/48:2, create mode 100644 test/corpus/folders/cur/49:2, create mode 100644 test/corpus/folders/cur/50:2, create mode 100644 test/corpus/folders/cur/52:2, create mode 100644 test/corpus/folders/cur/53:2, cre
[PATCH v2 06/13] test: make it possible to have several corpora
Move the existing corpus under corpus/default, and make it possible to have multiple corpora under the directory. --- test/.gitignore | 2 +- test/Makefile.local | 2 +- test/T480-hex-escaping.sh | 4 ++-- test/corpus/{ => default}/cur/01:2, | 0 test/corpus/{ => default}/cur/02:2, | 0 test/corpus/{ => default}/cur/03:2, | 0 test/corpus/{ => default}/cur/04:2, | 0 test/corpus/{ => default}/cur/05:2, | 0 test/corpus/{ => default}/cur/06:2, | 0 test/corpus/{ => default}/cur/07:2, | 0 test/corpus/{ => default}/cur/08:2, | 0 test/corpus/{ => default}/cur/09:2, | 0 test/corpus/{ => default}/cur/10:2, | 0 test/corpus/{ => default}/cur/11:2, | 0 test/corpus/{ => default}/cur/12:2, | 0 test/corpus/{ => default}/cur/13:2, | 0 test/corpus/{ => default}/cur/14:2, | 0 test/corpus/{ => default}/cur/15:2, | 0 test/corpus/{ => default}/cur/16:2, | 0 test/corpus/{ => default}/cur/17:2, | 0 test/corpus/{ => default}/cur/18:2, | 0 test/corpus/{ => default}/cur/19:2, | 0 test/corpus/{ => default}/cur/20:2, | 0 test/corpus/{ => default}/cur/21:2, | 0 test/corpus/{ => default}/cur/22:2, | 0 test/corpus/{ => default}/cur/23:2, | 0 test/corpus/{ => default}/cur/24:2, | 0 test/corpus/{ => default}/cur/25:2, | 0 test/corpus/{ => default}/cur/26:2, | 0 test/corpus/{ => default}/cur/27:2, | 0 test/corpus/{ => default}/cur/28:2, | 0 test/corpus/{ => default}/cur/29:2, | 0 test/corpus/{ => default}/cur/30:2, | 0 test/corpus/{ => default}/cur/31:2, | 0 test/corpus/{ => default}/cur/32:2, | 0 test/corpus/{ => default}/cur/33:2, | 0 test/corpus/{ => default}/cur/34:2, | 0 test/corpus/{ => default}/cur/35:2, | 0 test/corpus/{ => default}/cur/36:2, | 0 test/corpus/{ => default}/cur/37:2, | 0 test/corpus/{ => default}/cur/38:2, | 0 test/corpus/{ => default}/cur/39:2, | 0 test/corpus/{ => default}/cur/40:2, | 0 test/corpus/{ => default}/cur/41:2, | 0 test/corpus/{ => default}/cur/42:2, | 0 test/corpus/{ => default}/cur/43:2, | 0 test/corpus/{ => default}/cur/44:2, | 0 test/corpus/{ => default}/cur/45:2, | 0 test/corpus/{ => default}/cur/46:2, | 0 test/corpus/{ => default}/cur/47:2, | 0 test/corpus/{ => default}/cur/48:2, | 0 test/corpus/{ => default}/cur/49:2, | 0 test/corpus/{ => default}/cur/50:2, | 0 test/corpus/{ => default}/cur/51:2, | 0 test/corpus/{ => default}/cur/52:2, | 0 test/corpus/{ => default}/cur/53:2, | 0 test/notmuch-test | 2 +- test/test-lib.sh| 21 + 58 files changed, 18 insertions(+), 13 deletions(-) rename test/corpus/{ => default}/cur/01:2, (100%) rename test/corpus/{ => default}/cur/02:2, (100%) rename test/corpus/{ => default}/cur/03:2, (100%) rename test/corpus/{ => default}/cur/04:2, (100%) rename test/corpus/{ => default}/cur/05:2, (100%) rename test/corpus/{ => default}/cur/06:2, (100%) rename test/corpus/{ => default}/cur/07:2, (100%) rename test/corpus/{ => default}/cur/08:2, (100%) rename test/corpus/{ => default}/cur/09:2, (100%) rename test/corpus/{ => default}/cur/10:2, (100%) rename test/corpus/{ => default}/cur/11:2, (100%) rename test/corpus/{ => default}/cur/12:2, (100%) rename test/corpus/{ => default}/cur/13:2, (100%) rename test/corpus/{ => default}/cur/14:2, (100%) rename test/corpus/{ => default}/cur/15:2, (100%) rename test/corpus/{ => default}/cur/16:2, (100%) rename test/corpus/{ => default}/cur/17:2, (100%) rename test/corpus/{ => default}/cur/18:2, (100%) rename test/corpus/{ => default}/cur/19:2, (100%) rename test/corpus/{ => default}/cur/20:2, (100%) rename test/corpus/{ => default}/cur/21:2, (100%) rename test/corpus/{ => default}/cur/22:2, (100%) rename test/corpus/{ => default}/cur/23:2, (100%) rename test/corpus/{ => default}/cur/24:2, (100%) rename test/corpus/{ => default}/cur/25:2, (100%) rename test/corpus/{ => default}/cur/26:2, (100%) rename test/corpus/{ => default}/cur/27:2, (100%) rename test/corpus/{ => default}/cur/28:2, (100%) rename test/corpus/{ => default}/cur/29:2, (100%) rename test/corpus/{ => default}/cur/30:2, (100%) rename test/corpus/{ => default}/cur/31:2, (100%) rename test/corpus/{ => default}/cur/32:2, (100%) rename test/corpus/{ => default}/cur/33:2, (100%) rename test/corpus/{ => default}/cur/34:2, (100%) rename test/corpus/{ => default}/cur/35:2, (100%) rename test/corpus/{ => default}/cur/36:2, (100%) rename test/corpus/{ => default}/cur/37:2, (100%) rename test/corpus/{ => default}/cur/38:2, (100%) rename test/corpus/{ => default}/cur/39:2, (100%) rename test/corpus/{ => default}/cur/40:2, (100%) rename test/corpus/{ => default}/cur/41:2, (100%) rename test/corpus/{ => default}/cur/42:2, (100%) rename test/corpus/{ => default}/cur/43:2, (100%) rename test/corpus/{ => default}/cur/44:2, (100%) rename test/corpus/{ => default}/cur/45:2, (100%) rename test/corpus/{ => default}/cur/46:2, (100%) rename te
[PATCH v2 05/13] test: fix test for literal folder: search
Some of the folder: matching capabilities are lost in the probabilistic to boolean prefix change. Fix them. --- test/T100-search-by-folder.sh | 24 +--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/test/T100-search-by-folder.sh b/test/T100-search-by-folder.sh index 5cc2ca8d388a..84ca43820031 100755 --- a/test/T100-search-by-folder.sh +++ b/test/T100-search-by-folder.sh @@ -3,6 +3,7 @@ test_description='"notmuch search" by folder: (with variations)' . ./test-lib.sh add_message '[dir]=bad' '[subject]="To the bone"' +add_message '[dir]=.' '[subject]="Top level"' add_message '[dir]=bad/news' '[subject]="Bears"' mkdir -p "${MAIL_DIR}/duplicate/bad/news" cp "$gen_msg_filename" "${MAIL_DIR}/duplicate/bad/news" @@ -12,29 +13,46 @@ add_message '[dir]=things/favorite' '[subject]="Raindrops, whiskers, kettles"' add_message '[dir]=things/bad' '[subject]="Bites, stings, sad feelings"' test_begin_subtest "Single-world folder: specification (multiple results)" -output=$(notmuch search folder:bad | notmuch_search_sanitize) +output=$(notmuch search folder:bad folder:bad/news folder:things/bad | notmuch_search_sanitize) test_expect_equal "$output" "thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; To the bone (inbox unread) thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Bears (inbox unread) thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Bites, stings, sad feelings (inbox unread)" +test_begin_subtest "Top level folder" +output=$(notmuch search folder:'""' | notmuch_search_sanitize) +test_expect_equal "$output" "thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Top level (inbox unread)" + test_begin_subtest "Two-word path to narrow results to one" output=$(notmuch search folder:bad/news | notmuch_search_sanitize) test_expect_equal "$output" "thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Bears (inbox unread)" +test_begin_subtest "Folder search with --output=files" +output=$(notmuch search --output=files folder:bad/news | sed -e "s,$MAIL_DIR,MAIL_DIR,") +test_expect_equal "$output" "MAIL_DIR/bad/news/msg-003 +MAIL_DIR/duplicate/bad/news/msg-003" + test_begin_subtest "After removing duplicate instance of matching path" rm -r "${MAIL_DIR}/bad/news" notmuch new output=$(notmuch search folder:bad/news | notmuch_search_sanitize) +test_expect_equal "$output" "" + +test_begin_subtest "Folder search with --output=files part #2" +output=$(notmuch search --output=files folder:duplicate/bad/news | sed -e "s,$MAIL_DIR,MAIL_DIR,") +test_expect_equal "$output" "MAIL_DIR/duplicate/bad/news/msg-003" + +test_begin_subtest "After removing duplicate instance of matching path part #2" +output=$(notmuch search folder:duplicate/bad/news | notmuch_search_sanitize) test_expect_equal "$output" "thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Bears (inbox unread)" test_begin_subtest "After rename, old path returns nothing" mv "${MAIL_DIR}/duplicate/bad/news" "${MAIL_DIR}/duplicate/bad/olds" notmuch new -output=$(notmuch search folder:bad/news | notmuch_search_sanitize) +output=$(notmuch search folder:duplicate/bad/news | notmuch_search_sanitize) test_expect_equal "$output" "" test_begin_subtest "After rename, new path returns result" -output=$(notmuch search folder:bad/olds | notmuch_search_sanitize) +output=$(notmuch search folder:duplicate/bad/olds | notmuch_search_sanitize) test_expect_equal "$output" "thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Bears (inbox unread)" test_done -- 1.8.5.3
[PATCH v2 04/13] lib: make folder: prefix literal
In xapian terms, convert folder: prefix from probabilistic to boolean prefix, matching the paths, relative form the maildir root, of the message files, ignoring the maildir new and cur leaf directories. folder:foo matches all message files in foo, foo/new, and foo/cur. folder:foo/new does *not* match message files in foo/new. folder:"" matches all message files in the top level maildir and its new and cur subdirectories. This change constitutes a database change: bump the database version and add database upgrade support for folder: terms. The upgrade also adds path: terms. --- lib/database.cc | 38 ++-- lib/message.cc| 80 --- lib/notmuch-private.h | 3 ++ 3 files changed, 108 insertions(+), 13 deletions(-) diff --git a/lib/database.cc b/lib/database.cc index 93cc7f57e9db..186e3a7976fe 100644 --- a/lib/database.cc +++ b/lib/database.cc @@ -42,7 +42,7 @@ typedef struct { const char *prefix; } prefix_t; -#define NOTMUCH_DATABASE_VERSION 1 +#define NOTMUCH_DATABASE_VERSION 2 #define STRINGIFY(s) _SUB_STRINGIFY(s) #define _SUB_STRINGIFY(s) #s @@ -210,6 +210,7 @@ static prefix_t BOOLEAN_PREFIX_EXTERNAL[] = { { "is","K" }, { "id","Q" }, { "path", "P" }, +{ "folder","XFOLDER:" }, }; static prefix_t PROBABILISTIC_PREFIX[]= { @@ -217,7 +218,6 @@ static prefix_t PROBABILISTIC_PREFIX[]= { { "to","XTO" }, { "attachment","XATTACHMENT" }, { "subject", "XSUBJECT"}, -{ "folder","XFOLDER"} }; const char * @@ -1168,6 +1168,40 @@ notmuch_database_upgrade (notmuch_database_t *notmuch, } } +/* + * Prior to version 2, the "folder:" prefix was probabilistic and + * stemmed. Change it to the current boolean prefix. Add "path:" + * prefixes while at it. + */ +if (version < 2) { + notmuch_query_t *query = notmuch_query_create (notmuch, ""); + notmuch_messages_t *messages; + notmuch_message_t *message; + + count = 0; + total = notmuch_query_count_messages (query); + + for (messages = notmuch_query_search_messages (query); +notmuch_messages_valid (messages); +notmuch_messages_move_to_next (messages)) { + if (do_progress_notify) { + progress_notify (closure, (double) count / total); + do_progress_notify = 0; + } + + message = notmuch_messages_get (messages); + + _notmuch_message_upgrade_folder (message); + _notmuch_message_sync (message); + + notmuch_message_destroy (message); + + count++; + } + + notmuch_query_destroy (query); +} + db->set_metadata ("version", STRINGIFY (NOTMUCH_DATABASE_VERSION)); db->flush (); diff --git a/lib/message.cc b/lib/message.cc index 21abe8e12b9d..31cb9f107dd7 100644 --- a/lib/message.cc +++ b/lib/message.cc @@ -504,6 +504,56 @@ _notmuch_message_remove_terms (notmuch_message_t *message, const char *prefix) } } +/* Return true if p points at "new" or "cur". */ +static bool is_maildir (const char *p) +{ +return strcmp (p, "cur") == 0 || strcmp (p, "new") == 0; +} + +/* Add "folder:" term for directory. */ +static notmuch_status_t +_notmuch_message_add_folder_terms (notmuch_message_t *message, + const char *directory) +{ +char *folder, *last; + +folder = talloc_strdup (NULL, directory); +if (! folder) + return NOTMUCH_STATUS_OUT_OF_MEMORY; + +/* + * If the message file is in a leaf directory named "new" or + * "cur", presume maildir and index the parent directory. Thus a + * "folder:" prefix search matches messages in the specified + * maildir folder, i.e. in the specified directory and its "new" + * and "cur" subdirectories. + * + * Note that this means the "folder:" prefix can't be used for + * distinguishing between message files in "new" or "cur". The + * "path:" prefix needs to be used for that. + * + * Note the deliberate difference to _filename_is_in_maildir(). We + * don't want to index different things depending on the existence + * or non-existence of all maildir sibling directories "new", + * "cur", and "tmp". Doing so would be surprising, and difficult + * for the user to fix in case all subdirectories were not in + * place during indexing. + */ +last = strrchr (folder, '/'); +if (last) { + if (is_maildir (last + 1)) + *last = '\0'; +} else if (is_maildir (folder)) { + *folder = '\0'; +} + +_notmuch_message_add_term (message, "folder", folder); + +talloc_free (folder); + +return NOTMUCH_STATUS_SUCCESS; +} + #define RECURSIVE_SUFFIX "/**" /* Add "path:" terms for directory. */ @@ -570,9 +620,8 @@ _notmuch
[PATCH v2 03/13] test: make insert test use the path: prefix
This is a more strict test for the insert test. --- test/T070-insert.sh | 10 +- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/T070-insert.sh b/test/T070-insert.sh index e8dc4c099ed1..5de5da43cebb 100755 --- a/test/T070-insert.sh +++ b/test/T070-insert.sh @@ -126,14 +126,14 @@ test_expect_equal "$dirname" "$MAIL_DIR/new" test_begin_subtest "Insert message into folder" gen_insert_msg notmuch insert --folder=Drafts < "$gen_msg_filename" -output=$(notmuch search --output=files folder:Drafts) +output=$(notmuch search --output=files path:Drafts/new) dirname=$(dirname "$output") test_expect_equal "$dirname" "$MAIL_DIR/Drafts/new" test_begin_subtest "Insert message into folder, add/remove tags" gen_insert_msg notmuch insert --folder=Drafts +draft -unread < "$gen_msg_filename" -output=$(notmuch search --output=messages folder:Drafts tag:draft NOT tag:unread) +output=$(notmuch search --output=messages path:Drafts/cur tag:draft NOT tag:unread) test_expect_equal "$output" "id:$gen_msg_id" gen_insert_msg @@ -143,21 +143,21 @@ test_expect_code 1 "Insert message into non-existent folder" \ test_begin_subtest "Insert message, create folder" gen_insert_msg notmuch insert --folder=F --create-folder +folder < "$gen_msg_filename" -output=$(notmuch search --output=files folder:F tag:folder) +output=$(notmuch search --output=files path:F/new tag:folder) basename=$(basename "$output") test_expect_equal_file "$gen_msg_filename" "$MAIL_DIR/F/new/${basename}" test_begin_subtest "Insert message, create subfolder" gen_insert_msg notmuch insert --folder=F/G/H/I/J --create-folder +folder < "$gen_msg_filename" -output=$(notmuch search --output=files folder:F/G/H/I/J tag:folder) +output=$(notmuch search --output=files path:F/G/H/I/J/new tag:folder) basename=$(basename "$output") test_expect_equal_file "$gen_msg_filename" "${MAIL_DIR}/F/G/H/I/J/new/${basename}" test_begin_subtest "Insert message, create existing subfolder" gen_insert_msg notmuch insert --folder=F/G/H/I/J --create-folder +folder < "$gen_msg_filename" -output=$(notmuch count folder:F/G/H/I/J tag:folder) +output=$(notmuch count path:F/G/H/I/J/new tag:folder) test_expect_equal "$output" "2" gen_insert_msg -- 1.8.5.3
[PATCH v2 02/13] lib: add support for path: prefix searches
The path: prefix is a literal boolean prefix matching the paths, relative from the maildir root, of the message files. path:foo matches all message files in foo (but not in foo/new or foo/cur). path:foo/new matches all message files in foo/new. path:"" matches all message files in the top level maildir. path:foo/** matches all message files in foo and recursively in all subdirectories of foo. path:** matches all message files recursively, i.e. all messages. --- lib/database.cc | 7 --- lib/message.cc | 52 +--- 2 files changed, 49 insertions(+), 10 deletions(-) diff --git a/lib/database.cc b/lib/database.cc index f395061e3a73..93cc7f57e9db 100644 --- a/lib/database.cc +++ b/lib/database.cc @@ -100,8 +100,8 @@ typedef struct { * In addition, terms from the content of the message are added with * "from", "to", "attachment", and "subject" prefixes for use by the * user in searching. Similarly, terms from the path of the mail - * message are added with a "folder" prefix. But the database doesn't - * really care itself about any of these. + * message are added with "folder" and "path" prefixes. But the + * database doesn't really care itself about any of these. * * The data portion of a mail document is empty. * @@ -208,7 +208,8 @@ static prefix_t BOOLEAN_PREFIX_EXTERNAL[] = { { "thread","G" }, { "tag", "K" }, { "is","K" }, -{ "id","Q" } +{ "id","Q" }, +{ "path", "P" }, }; static prefix_t PROBABILISTIC_PREFIX[]= { diff --git a/lib/message.cc b/lib/message.cc index 7aff4ae5111a..21abe8e12b9d 100644 --- a/lib/message.cc +++ b/lib/message.cc @@ -504,6 +504,40 @@ _notmuch_message_remove_terms (notmuch_message_t *message, const char *prefix) } } +#define RECURSIVE_SUFFIX "/**" + +/* Add "path:" terms for directory. */ +static notmuch_status_t +_notmuch_message_add_path_terms (notmuch_message_t *message, +const char *directory) +{ +/* Add exact "path:" term. */ +_notmuch_message_add_term (message, "path", directory); + +if (strlen (directory)) { + char *path, *p; + + path = talloc_asprintf (NULL, "%s%s", directory, RECURSIVE_SUFFIX); + if (! path) + return NOTMUCH_STATUS_OUT_OF_MEMORY; + + /* Add recursive "path:" terms for directory and all parents. */ + for (p = path + strlen (path) - 1; p > path; p--) { + if (*p == '/') { + strcpy (p, RECURSIVE_SUFFIX); + _notmuch_message_add_term (message, "path", path); + } + } + + talloc_free (path); +} + +/* Recursive all-matching path:** for consistency. */ +_notmuch_message_add_term (message, "path", "**"); + +return NOTMUCH_STATUS_SUCCESS; +} + /* Add directory based terms for all filenames of the message. */ static notmuch_status_t _notmuch_message_add_directory_terms (void *ctx, notmuch_message_t *message) @@ -538,6 +572,8 @@ _notmuch_message_add_directory_terms (void *ctx, notmuch_message_t *message) directory_id); if (strlen (directory)) _notmuch_message_gen_terms (message, "folder", directory); + + _notmuch_message_add_path_terms (message, directory); } return status; @@ -577,6 +613,8 @@ _notmuch_message_add_filename (notmuch_message_t *message, /* New terms allow user to search with folder: specification. */ _notmuch_message_gen_terms (message, "folder", directory); +_notmuch_message_add_path_terms (message, directory); + talloc_free (local); return NOTMUCH_STATUS_SUCCESS; @@ -618,18 +656,18 @@ _notmuch_message_remove_filename (notmuch_message_t *message, if (status) return status; -/* Re-synchronize "folder:" terms for this message. This requires: - * 1. removing all "folder:" terms - * 2. removing all "folder:" stemmed terms - * 3. adding back terms for all remaining filenames of the message. */ +/* Re-synchronize "folder:" and "path:" terms for this message. */ -/* 1. removing all "folder:" terms */ +/* Remove all "folder:" terms. */ _notmuch_message_remove_terms (message, folder_prefix); -/* 2. removing all "folder:" stemmed terms */ +/* Remove all "folder:" stemmed terms. */ _notmuch_message_remove_terms (message, zfolder_prefix); -/* 3. adding back terms for all remaining filenames of the message. */ +/* Remove all "path:" terms. */ +_notmuch_message_remove_terms (message, _find_prefix ("path")); + +/* Add back terms for all remaining filenames of the message. */ status = _notmuch_message_add_directory_terms (local, message); talloc_free (local); -- 1.8.5.3
[PATCH v2 01/13] lib: refactor folder term update after filename removal
Abstract some blocks of code for reuse. No functional changes. --- lib/message.cc | 135 - 1 file changed, 66 insertions(+), 69 deletions(-) diff --git a/lib/message.cc b/lib/message.cc index c91f3a59836f..7aff4ae5111a 100644 --- a/lib/message.cc +++ b/lib/message.cc @@ -481,6 +481,68 @@ notmuch_message_get_replies (notmuch_message_t *message) return _notmuch_messages_create (message->replies); } +static void +_notmuch_message_remove_terms (notmuch_message_t *message, const char *prefix) +{ +Xapian::TermIterator i; +size_t prefix_len = strlen (prefix); + +while (1) { + i = message->doc.termlist_begin (); + i.skip_to (prefix); + + /* Terminate loop when no terms remain with desired prefix. */ + if (i == message->doc.termlist_end () || + strncmp ((*i).c_str (), prefix, prefix_len)) + break; + + try { + message->doc.remove_term ((*i)); + } catch (const Xapian::InvalidArgumentError) { + /* Ignore failure to remove non-existent term. */ + } +} +} + +/* Add directory based terms for all filenames of the message. */ +static notmuch_status_t +_notmuch_message_add_directory_terms (void *ctx, notmuch_message_t *message) +{ +const char *direntry_prefix = _find_prefix ("file-direntry"); +int direntry_prefix_len = strlen (direntry_prefix); +Xapian::TermIterator i = message->doc.termlist_begin (); +notmuch_status_t status = NOTMUCH_STATUS_SUCCESS; + +for (i.skip_to (direntry_prefix); i != message->doc.termlist_end (); i++) { + unsigned int directory_id; + const char *direntry, *directory; + char *colon; + + /* Terminate loop at first term without desired prefix. */ + if (strncmp ((*i).c_str (), direntry_prefix, direntry_prefix_len)) + break; + + /* Indicate that there are filenames remaining. */ + status = NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID; + + direntry = (*i).c_str (); + direntry += direntry_prefix_len; + + directory_id = strtol (direntry, &colon, 10); + + if (colon == NULL || *colon != ':') + INTERNAL_ERROR ("malformed direntry"); + + directory = _notmuch_database_get_directory_path (ctx, + message->notmuch, + directory_id); + if (strlen (directory)) + _notmuch_message_gen_terms (message, "folder", directory); +} + +return status; +} + /* Add an additional 'filename' for 'message'. * * This change will not be reflected in the database until the next @@ -536,17 +598,12 @@ notmuch_status_t _notmuch_message_remove_filename (notmuch_message_t *message, const char *filename) { -const char *direntry_prefix = _find_prefix ("file-direntry"); -int direntry_prefix_len = strlen (direntry_prefix); -const char *folder_prefix = _find_prefix ("folder"); -int folder_prefix_len = strlen (folder_prefix); void *local = talloc_new (message); +const char *folder_prefix = _find_prefix ("folder"); char *zfolder_prefix = talloc_asprintf(local, "Z%s", folder_prefix); -int zfolder_prefix_len = strlen (zfolder_prefix); char *direntry; notmuch_private_status_t private_status; notmuch_status_t status; -Xapian::TermIterator i, last; status = _notmuch_database_filename_to_direntry ( local, message->notmuch, filename, NOTMUCH_FIND_LOOKUP, &direntry); @@ -567,73 +624,13 @@ _notmuch_message_remove_filename (notmuch_message_t *message, * 3. adding back terms for all remaining filenames of the message. */ /* 1. removing all "folder:" terms */ -while (1) { - i = message->doc.termlist_begin (); - i.skip_to (folder_prefix); - - /* Terminate loop when no terms remain with desired prefix. */ - if (i == message->doc.termlist_end () || - strncmp ((*i).c_str (), folder_prefix, folder_prefix_len)) - { - break; - } - - try { - message->doc.remove_term ((*i)); - } catch (const Xapian::InvalidArgumentError) { - /* Ignore failure to remove non-existent term. */ - } -} +_notmuch_message_remove_terms (message, folder_prefix); /* 2. removing all "folder:" stemmed terms */ -while (1) { - i = message->doc.termlist_begin (); - i.skip_to (zfolder_prefix); - - /* Terminate loop when no terms remain with desired prefix. */ - if (i == message->doc.termlist_end () || - strncmp ((*i).c_str (), zfolder_prefix, zfolder_prefix_len)) - { - break; - } - - try { - message->doc.remove_term ((*i)); - } catch (const Xapian::InvalidArgumentError) { - /* Ignore failure to remove non-existent term. */ - } -} +_notmuch_message_remove_terms (message, zf
[PATCH v2 00/13] literal folder: prefix, new path: prefix
Hi all, this is v2 of id:cover.1389304779.git.jani at nikula.org. The new path: prefix is a literal boolean prefix matching the paths, relative from the maildir root, of the message files. There's no interpretation of the maildir special cur/new folders, but a recursive match is provided with "/**" suffix. See the patch for details. The folder: prefix becomes a literal boolean prefix, similar to path:, except it matches the maildir cur/new folders in addition to the specified path. There's no recursive version. Patches 1-5 add the above. Patches 6-8 change the test infrastructure to make it easier to add multiple corpuses, and adds a new test for path: and folder:. Patches 9-11 add support for testing the database upgrade. Patches 12-13 update man pages. I've dropped most of the content in patches 7 and 10 due to their size. The patches (and the whole series) are available in the boolean-folder-and-path-v2 branch at git://gitorious.org/jani/notmuch.git. Web interface at https://gitorious.org/jani/notmuch/commits/0b3dd2d1cc6c413ea07ea326883ac448499c0e79. WARNING! The change requires a database format version bump, and a database upgrade, which is automatically done on 'notmuch new'. The upgrade is irreversible if you want to try this on your database! A complete database rebuild is required for reverting the database format version. Make sure your backups are in order! BR, Jani. Jani Nikula (13): lib: refactor folder term update after filename removal lib: add support for path: prefix searches test: make insert test use the path: prefix lib: make folder: prefix literal test: fix test for literal folder: search test: make it possible to have several corpora test: add new corpus with folders test: add tests for the new boolean folder: and path: prefixes devel: add script to generate test databases test: add test database in format version 1 test: add database upgrade test from format version 1 to 2 man: update man pages for folder: and path: search terms man: try to clarify the folder: and path: vs. --output=files confusion devel/gen-testdb.sh| 124 lib/database.cc| 45 - lib/message.cc | 249 --- lib/notmuch-private.h | 3 + man/man1/notmuch-search.1 | 10 +- man/man7/notmuch-search-terms.7| 28 ++- test/.gitignore| 2 +- test/Makefile.local| 2 +- test/T070-insert.sh| 10 +- test/T100-search-by-folder.sh | 24 ++- test/T101-search-by-folder-and-path.sh | 83 test/T480-hex-escaping.sh | 4 +- test/T530-upgrade.sh | 103 ++ test/corpus/{ => default}/cur/01:2,| 0 test/corpus/{ => default}/cur/02:2,| 0 test/corpus/{ => default}/cur/03:2,| 0 test/corpus/{ => default}/cur/04:2,| 0 test/corpus/{ => default}/cur/05:2,| 0 test/corpus/{ => default}/cur/06:2,| 0 test/corpus/{ => default}/cur/07:2,| 0 test/corpus/{ => default}/cur/08:2,| 0 test/corpus/{ => default}/cur/09:2,| 0 test/corpus/{ => default}/cur/10:2,| 0 test/corpus/{ => default}/cur/11:2,| 0 test/corpus/{ => default}/cur/12:2,| 0 test/corpus/{ => default}/cur/13:2,| 0 test/corpus/{ => default}/cur/14:2,| 0 test/corpus/{ => default}/cur/15:2,| 0 test/corpus/{ => default}/cur/16:2,| 0 test/corpus/{ => default}/cur/17:2,| 0 test/corpus/{ => default}/cur/18:2,| 0 test/corpus/{ => default}/cur/19:2,| 0 test/corpus/{ => default}/cur/20:2,| 0 test/corpus/{ => default}/cur/21:2,| 0 test/corpus/{ => default}/cur/22:2,| 0 test/corpus/{ => default}/cur/23:2,| 0 test/corpus/{ => default}/cur/24:2,| 0 test/corpus/{ => default}/cur/25:2,| 0 test/corpus/{ => default}/cur/26:2,| 0 test/corpus/{ => default}/cur/27:2,| 0 test/corpus/{ => default}/cur/28:2,| 0 test/corpus/{ => default}/cur/29:2,| 0 test/corpus/{ => default}/cur/30:2,| 0 test/corpus/{ => default}/cur/31:2,| 0 test/corpus/{ => default}/cur/32:2,| 0 test/corpus/{ => default}/cur/33:2,| 0 test/corpus/{ => default}/cur/34:2,| 0 test/corpus/{ => default}/cur/35:2,| 0 test/corpus/{ => default}/cur/36:2,| 0 test/corpus/{ => default}/cur/37:2,| 0 test/corpus/{ => default}/cur/38:2,| 0 test/corpus/{ => default}/cur/39:2,| 0 test/corpus/{ => default}/cur/40:2,| 0 test/corpus/{ => default}/cur/41:2,| 0 test/corpus/{ => default}/cur/42:2,| 0 test/corpus/{ => default}/cur/43:2,| 0 test/corpus/{ => default}/cur/44:2,| 0 test/corpus/{ => default}/cur/45:2,| 0 test/corpus/{ => default}/cur/46:2,| 0 test/corpus/{ => default}/cur/47:2,| 0 test/corpus/{ => default}/cur/48:2,| 0 test/c