From 9a4ba3826a91d81cc61e3e39c6687e73ee1e07c5 Mon Sep 17 00:00:00 2001 From: Dominik Peteler Date: Wed, 18 Jul 2012 20:09:30 +0200 Subject: [PATCH] [PATCHv2] cli: Hooks for tag-command --- 25/3e05db5ba6493f5211171b696f95609518ab03 | 337 ++++++++++++++++++++++ 1 file changed, 337 insertions(+) create mode 100644 25/3e05db5ba6493f5211171b696f95609518ab03 diff --git a/25/3e05db5ba6493f5211171b696f95609518ab03 b/25/3e05db5ba6493f5211171b696f95609518ab03 new file mode 100644 index 000000000..f9c488f9d --- /dev/null +++ b/25/3e05db5ba6493f5211171b696f95609518ab03 @@ -0,0 +1,337 @@ +Return-Path: +X-Original-To: notmuch@notmuchmail.org +Delivered-To: notmuch@notmuchmail.org +Received: from localhost (localhost [127.0.0.1]) + by olra.theworths.org (Postfix) with ESMTP id D222F431FAF + for ; Wed, 18 Jul 2012 11:11:14 -0700 (PDT) +X-Virus-Scanned: Debian amavisd-new at olra.theworths.org +X-Spam-Flag: NO +X-Spam-Score: 0 +X-Spam-Level: +X-Spam-Status: No, score=0 tagged_above=-999 required=5 tests=[none] + autolearn=disabled +Received: from olra.theworths.org ([127.0.0.1]) + by localhost (olra.theworths.org [127.0.0.1]) (amavisd-new, port 10024) + with ESMTP id MF9c3hsdbnQO for ; + Wed, 18 Jul 2012 11:11:10 -0700 (PDT) +Received: from www73.your-server.de (www73.your-server.de [213.133.104.73]) + (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) + (No client certificate requested) + by olra.theworths.org (Postfix) with ESMTPS id 6E715431FAE + for ; Wed, 18 Jul 2012 11:11:10 -0700 (PDT) +Received: from [78.46.5.203] (helo=sslproxy01.your-server.de) + by www73.your-server.de with esmtpsa (TLSv1:AES256-SHA:256) + (Exim 4.74) (envelope-from ) + id 1SrYiF-0003Pp-V6; Wed, 18 Jul 2012 20:11:03 +0200 +Received: from [132.187.246.85] (helo=fuckup.wlan1.rzuw) + by sslproxy01.your-server.de with esmtpsa + (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.72) + (envelope-from ) + id 1SrYi8-0006ph-86; Wed, 18 Jul 2012 20:10:56 +0200 +From: Dominik Peteler +To: notmuch@notmuchmail.org +Subject: [PATCHv2] cli: Hooks for tag-command +Date: Wed, 18 Jul 2012 20:09:30 +0200 +Message-Id: <1342634970-12991-1-git-send-email-dominik@with-h.at> +X-Mailer: git-send-email 1.7.11.2 +In-Reply-To: + +X-Authenticated-Sender: dude@with-h.at +X-Virus-Scanned: Clear (ClamAV 0.97.3/15151/Wed Jul 18 17:49:52 2012) +X-Mailman-Approved-At: Wed, 18 Jul 2012 13:16:17 -0700 +Cc: Dominik Peteler +X-BeenThere: notmuch@notmuchmail.org +X-Mailman-Version: 2.1.13 +Precedence: list +List-Id: "Use and development of the notmuch mail system." + +List-Unsubscribe: , + +List-Archive: +List-Post: +List-Help: +List-Subscribe: , + +X-List-Received-Date: Wed, 18 Jul 2012 18:11:15 -0000 + +hello, + +I improved my patch according to Janis mail: + * new cli syntax: notmuch tag [ --no-hooks ] -- [ -- ] + * adjusted man pages and wrote tests + +I had the idea to improve this feature by passing the message-ids or the filename to the hooks. +What's your opinion about that ? Any suggestions ? + +regards + +dominik + + + +There are two hooks: + * pre-tag: Run before tagging + * post-tag: Run after + +This allows users to react on changes of tags. For example, +you might want to move a message to a special Maildir +depending on its notmuch tags. +--- + man/man1/notmuch-tag.1 | 22 +++++++++++++++++++- + man/man5/notmuch-hooks.5 | 19 ++++++++++++++++++ + notmuch-tag.c | 52 +++++++++++++++++++++++++++++++++++++++++++++--- + test/hooks | 36 +++++++++++++++++++++++++++++++++ + test/tagging | 28 ++++++++++++++++++++++++++ + 5 files changed, 153 insertions(+), 4 deletions(-) + +diff --git a/man/man1/notmuch-tag.1 b/man/man1/notmuch-tag.1 +index d810e1b..e00e189 100644 +--- a/man/man1/notmuch-tag.1 ++++ b/man/man1/notmuch-tag.1 +@@ -4,7 +4,11 @@ notmuch-tag \- add/remove tags for all messages matching the search terms + + .SH SYNOPSIS + .B notmuch tag +-.RI "+<" tag> "|\-<" tag "> [...] [\-\-] <" search-term ">..." ++.RI "+<" tag "> |\-<" tag "> [...] [\-\-] <" search-term ">..." ++ ++.B notmuch tag ++.RB "[" --no-hooks "]" ++.RI "\-\- +<" tag "> |\-<" tag "> [...] \-\- <" search-term ">..." + + .SH DESCRIPTION + +@@ -29,6 +33,22 @@ updates the maildir flags according to tag changes if the + configuration option is enabled. See \fBnotmuch-config\fR(1) for + details. + ++The ++.B tag ++command supports hooks. See \fBnotmuch-hooks(5)\fR ++for more details on hooks. ++ ++Supported options for ++.B tag ++include ++.RS 4 ++.TP 4 ++.BR \-\-no\-hooks ++ ++Prevents hooks from being run. ++.RE ++.RE ++ + .SH SEE ALSO + + \fBnotmuch\fR(1), \fBnotmuch-config\fR(1), \fBnotmuch-count\fR(1), +diff --git a/man/man5/notmuch-hooks.5 b/man/man5/notmuch-hooks.5 +index b914a29..e193ef5 100644 +--- a/man/man5/notmuch-hooks.5 ++++ b/man/man5/notmuch-hooks.5 +@@ -38,6 +38,25 @@ the scan or import. + Typically this hook is used to perform additional query\-based tagging on the + imported messages. + .RE ++.RS 4 ++.TP 4 ++.B pre\-tag ++This hook is invoked by the ++.B tag ++command before tagging messages. If this ++hook exits with a non-zero status, notmuch will abort further processing of the ++.B tag ++command. ++.RE ++.RS 4 ++.TP 4 ++.B post\-tag ++This hook is invoked by the ++.B tag ++command after messages have been tagged. The hook will not be run if there have been any errors during ++the tagging. ++.RE ++ + + .SH SEE ALSO + +diff --git a/notmuch-tag.c b/notmuch-tag.c +index 7d18639..7572059 100644 +--- a/notmuch-tag.c ++++ b/notmuch-tag.c +@@ -174,9 +174,17 @@ notmuch_tag_command (void *ctx, int argc, char *argv[]) + int tag_ops_count = 0; + char *query_string; + notmuch_config_t *config; ++ const char *db_path; + notmuch_database_t *notmuch; + struct sigaction action; + notmuch_bool_t synchronize_flags; ++ /* Points to the position of the "--" delimiters, e. g. ++ * arg_delimiters[0] arg_delimiters[1] ++ * ++ * arg_delimiters[0] may remain -1 if there are no arguments given ++ * arg_delimiters[0] may remain -1 if there is no delimiter between tag ops and search terms */ ++ int arg_delimiters[2] = {-1, -1}; ++ notmuch_bool_t run_hooks = TRUE; + int i; + int ret; + +@@ -197,11 +205,37 @@ notmuch_tag_command (void *ctx, int argc, char *argv[]) + return 1; + } + ++ /* Determine position of delimiters */ + for (i = 0; i < argc; i++) { + if (strcmp (argv[i], "--") == 0) { +- i++; +- break; ++ if (arg_delimiters[1] == -1) { ++ arg_delimiters[1] = i; ++ } else if (arg_delimiters[0] == -1) { ++ arg_delimiters[0] = arg_delimiters[1]; ++ arg_delimiters[1] = i; ++ } else { ++ fprintf (stderr, "Error: 'notmuch tag' requires delimiter \"--\" at most two times.\n"); ++ return 1; ++ } + } ++ } ++ ++ /* Process arguments if present */ ++ for (i = 0; i < arg_delimiters[0]; i++) { ++ if (strcmp (argv[i], "--no-hooks") == 0) { ++ run_hooks = FALSE; ++ } else { ++ fprintf (stderr, "Error: 'notmuch tag' doesn't recognize argument '%s'.\n", argv[i]); ++ return 1; ++ } ++ } ++ ++ /* Set arg_delimiters[1] to argc if no delimiters at all are present */ ++ if (arg_delimiters[1] == -1) ++ arg_delimiters[1] = argc; ++ ++ /* Read tag ops */ ++ for (i = arg_delimiters[0]+1; i < arg_delimiters[1]; i++) { + if (argv[i][0] == '+' || argv[i][0] == '-') { + tag_ops[tag_ops_count].tag = argv[i] + 1; + tag_ops[tag_ops_count].remove = (argv[i][0] == '-'); +@@ -229,7 +263,15 @@ notmuch_tag_command (void *ctx, int argc, char *argv[]) + if (config == NULL) + return 1; + +- if (notmuch_database_open (notmuch_config_get_database_path (config), ++ db_path = notmuch_config_get_database_path (config); ++ ++ if (run_hooks) { ++ ret = notmuch_run_hook (db_path, "pre-tag"); ++ if (ret) ++ return ret; ++ } ++ ++ if (notmuch_database_open (db_path, + NOTMUCH_DATABASE_MODE_READ_WRITE, ¬much)) + return 1; + +@@ -239,5 +281,9 @@ notmuch_tag_command (void *ctx, int argc, char *argv[]) + + notmuch_database_destroy (notmuch); + ++ if (!ret && run_hooks) { ++ ret = notmuch_run_hook (db_path, "post-tag"); ++ } ++ + return ret; + } +diff --git a/test/hooks b/test/hooks +index 77e8569..ae857cc 100755 +--- a/test/hooks ++++ b/test/hooks +@@ -31,6 +31,7 @@ rm_hooks () { + # add a message to generate mail dir and database + add_message + ++# {pre,post}-new hooks + test_begin_subtest "pre-new is run" + rm_hooks + generate_message +@@ -101,4 +102,39 @@ EOF + chmod +x "${HOOK_DIR}/pre-new" + test_expect_code 1 "hook execution failure" "notmuch new" + ++ ++ ++# {pre,post}-tag hooks ++test_begin_subtest "pre-tag is run" ++rm_hooks ++generate_message ++create_echo_hook "pre-tag" expected output ++notmuch tag +foo -- '*' > /dev/null ++test_expect_equal_file expected output ++ ++test_begin_subtest "post-tag is run" ++rm_hooks ++generate_message ++create_echo_hook "post-tag" expected output ++notmuch tag +foo -- '*' > /dev/null ++test_expect_equal_file expected output ++ ++test_begin_subtest "pre-tag is run before post-new" ++rm_hooks ++generate_message ++create_echo_hook "pre-tag" pre-tag.expected pre-tag.output ++create_echo_hook "post-tag" post-tag.expected post-tag.output ++notmuch tag +foo -- '*' > /dev/null ++test_expect_equal_file post-tag.expected post-tag.output ++ ++test_begin_subtest "pre-tag non-zero exit status (hook status)" ++rm_hooks ++generate_message ++create_failing_hook "pre-tag" ++output=`notmuch tag +foo -- '*' 2>&1` ++test_expect_equal "$output" "Error: pre-tag hook failed with status 13" ++ ++# depends on the previous subtest leaving broken hook behind ++test_expect_code 1 "pre-tag non-zero exit status (notmuch status)" "notmuch tag +foo -- '*'" ++ + test_done +diff --git a/test/tagging b/test/tagging +index e4782ed..5167f4f 100755 +--- a/test/tagging ++++ b/test/tagging +@@ -46,4 +46,32 @@ test_expect_equal "$output" "\ + thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; One (:\" inbox tag1 unread) + thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Two (inbox tag1 tag4 unread)" + ++test_begin_subtest "Arguments mixed with tag ops" ++notmuch tag +-no-hooks --no-hooks -- One ++notmuch tag --no-hooks +-no-hooks -tag4 -- Two ++output=$(notmuch search \* | notmuch_search_sanitize) ++test_expect_equal "$output" "\ ++thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; One (:\" inbox tag1 unread) ++thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Two (-no-hooks inbox tag1 unread)" ++notmuch tag --no-hooks -- Two ++ ++test_begin_subtest "Arguments with correct position" ++notmuch tag --no-hooks -- +tag4 -tag4 -- One ++output=$(notmuch search \* | notmuch_search_sanitize) ++test_expect_equal "$output" "\ ++thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; One (:\" inbox tag1 unread) ++thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Two (inbox tag1 unread)" ++ ++test_begin_subtest "Missing arguments" ++notmuch tag -- +tag4 -tag4 -- One ++output=$(notmuch search \* | notmuch_search_sanitize) ++test_expect_equal "$output" "\ ++thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; One (:\" inbox tag1 unread) ++thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Two (inbox tag1 unread)" ++ ++test_begin_subtest "Unknown argument" ++output=$(notmuch tag --no-blubb -- +tag4 -tag4 -- One 2>&1) ++test_expect_equal "$output" "\ ++Error: 'notmuch tag' doesn't recognize argument '--no-blubb'." ++ + test_done +-- +1.7.11.2 + -- 2.26.2