From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mp1 ([2001:41d0:2:4a6f::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by ms11 with LMTPS id sHVjDVlIHWAIRwAA0tVLHw (envelope-from ) for ; Fri, 05 Feb 2021 13:30:01 +0000 Received: from aspmx1.migadu.com ([2001:41d0:2:4a6f::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by mp1 with LMTPS id EOroCFlIHWC4cQAAbx9fmQ (envelope-from ) for ; Fri, 05 Feb 2021 13:30:01 +0000 Received: from mail.notmuchmail.org (nmbug.tethera.net [IPv6:2607:5300:201:3100::1657]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) server-signature RSA-PSS (2048 bits)) (No client certificate requested) by aspmx1.migadu.com (Postfix) with ESMTPS id 9BE389402BD for ; Fri, 5 Feb 2021 13:30:00 +0000 (UTC) Received: from nmbug.tethera.net (localhost [127.0.0.1]) by mail.notmuchmail.org (Postfix) with ESMTP id AF55920664; Fri, 5 Feb 2021 08:28:11 -0500 (EST) Received: from fethera.tethera.net (fethera.tethera.net [198.245.60.197]) by mail.notmuchmail.org (Postfix) with ESMTP id 816DC1FBF9 for ; Fri, 5 Feb 2021 08:27:29 -0500 (EST) Received: by fethera.tethera.net (Postfix, from userid 1001) id 6346F6067F; Fri, 5 Feb 2021 08:27:29 -0500 (EST) Received: (nullmailer pid 3258454 invoked by uid 1000); Fri, 05 Feb 2021 13:27:02 -0000 From: David Bremner To: notmuch@notmuchmail.org Cc: David Bremner Subject: [PATCH 37/39] CLI: use configured hook directory Date: Fri, 5 Feb 2021 09:26:52 -0400 Message-Id: <20210205132654.3258292-38-david@tethera.net> X-Mailer: git-send-email 2.30.0 In-Reply-To: <20210205132654.3258292-1-david@tethera.net> References: <20210205132654.3258292-1-david@tethera.net> MIME-Version: 1.0 Message-ID-Hash: 7JFGBKTXGBYZK7ROI3RWQQ376VMYCO4L X-Message-ID-Hash: 7JFGBKTXGBYZK7ROI3RWQQ376VMYCO4L X-MailFrom: bremner@tethera.net X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; header-match-notmuch.notmuchmail.org-0; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; suspicious-header X-Mailman-Version: 3.2.1 Precedence: list List-Id: "Use and development of the notmuch mail system." List-Help: List-Post: List-Subscribe: List-Unsubscribe: Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit X-Migadu-Flow: FLOW_IN X-Migadu-Spam-Score: -0.93 Authentication-Results: aspmx1.migadu.com; dkim=none; dmarc=none; spf=pass (aspmx1.migadu.com: domain of notmuch-bounces@notmuchmail.org designates 2607:5300:201:3100::1657 as permitted sender) smtp.mailfrom=notmuch-bounces@notmuchmail.org X-Migadu-Queue-Id: 9BE389402BD X-Spam-Score: -0.93 X-Migadu-Scanner: scn1.migadu.com X-TUID: Omf0Wwk0AuLl This enables support for hooks outside the database directory. It relies strongly on configuration information being usable between closing the database and destroying it. --- hooks.c | 7 +- notmuch-client.h | 2 +- notmuch-insert.c | 7 +- notmuch-new.c | 10 +-- test/T400-hooks.sh | 197 +++++++++++++++++++++++++-------------------- 5 files changed, 120 insertions(+), 103 deletions(-) diff --git a/hooks.c b/hooks.c index 59c58070..ec89b22e 100644 --- a/hooks.c +++ b/hooks.c @@ -24,14 +24,15 @@ #include int -notmuch_run_hook (const char *db_path, const char *hook) +notmuch_run_hook (notmuch_database_t *notmuch, const char *hook) { char *hook_path; int status = 0; pid_t pid; - hook_path = talloc_asprintf (NULL, "%s/%s/%s/%s", db_path, ".notmuch", - "hooks", hook); + hook_path = talloc_asprintf (notmuch, "%s/%s", + notmuch_config_get (notmuch, NOTMUCH_CONFIG_HOOK_DIR), + hook); if (hook_path == NULL) { fprintf (stderr, "Out of memory\n"); return 1; diff --git a/notmuch-client.h b/notmuch-client.h index 9e09c36a..f60f5406 100644 --- a/notmuch-client.h +++ b/notmuch-client.h @@ -339,7 +339,7 @@ const char * _notmuch_config_get_path (notmuch_config_t *config); int -notmuch_run_hook (const char *db_path, const char *hook); +notmuch_run_hook (notmuch_database_t *notmuch, const char *hook); bool debugger_is_active (void); diff --git a/notmuch-insert.c b/notmuch-insert.c index e483b949..0f272e2e 100644 --- a/notmuch-insert.c +++ b/notmuch-insert.c @@ -481,7 +481,6 @@ notmuch_insert_command (unused(notmuch_config_t *config),notmuch_database_t *not notmuch_process_shared_options (argv[0]); - /* XXX TODO replace this use of DATABASE_PATH with something specific to hooks */ db_path = notmuch_config_get (notmuch, NOTMUCH_CONFIG_DATABASE_PATH); if (! db_path) @@ -570,7 +569,7 @@ notmuch_insert_command (unused(notmuch_config_t *config),notmuch_database_t *not status = add_file (notmuch, newpath, tag_ops, synchronize_flags, keep, indexing_cli_choices.opts); /* Commit changes. */ - close_status = notmuch_database_destroy (notmuch); + close_status = notmuch_database_close (notmuch); if (close_status) { /* Hold on to the first error, if any. */ if (! status) @@ -595,9 +594,11 @@ notmuch_insert_command (unused(notmuch_config_t *config),notmuch_database_t *not if (hooks && status == NOTMUCH_STATUS_SUCCESS) { /* Ignore hook failures. */ - notmuch_run_hook (db_path, "post-insert"); + notmuch_run_hook (notmuch, "post-insert"); } + notmuch_database_destroy (notmuch); + talloc_free (local); return status_to_exit (status); diff --git a/notmuch-new.c b/notmuch-new.c index 0f416939..21e66af1 100644 --- a/notmuch-new.c +++ b/notmuch-new.c @@ -1105,7 +1105,6 @@ notmuch_new_command (unused(notmuch_config_t *config), notmuch_database_t *notmu struct timeval tv_start; int ret = 0; const char *db_path; - char *dot_notmuch_path; struct sigaction action; _filename_node_t *f; int opt_index; @@ -1167,13 +1166,11 @@ notmuch_new_command (unused(notmuch_config_t *config), notmuch_database_t *notmu } if (hooks) { - ret = notmuch_run_hook (db_path, "pre-new"); + ret = notmuch_run_hook (notmuch, "pre-new"); if (ret) return EXIT_FAILURE; } - dot_notmuch_path = talloc_asprintf (notmuch, "%s/%s", db_path, ".notmuch"); - notmuch_exit_if_unmatched_db_uuid (notmuch); if (notmuch_database_get_revision (notmuch, NULL) == 0) { @@ -1212,9 +1209,6 @@ notmuch_new_command (unused(notmuch_config_t *config), notmuch_database_t *notmu action.sa_flags = SA_RESTART; sigaction (SIGINT, &action, NULL); - talloc_free (dot_notmuch_path); - dot_notmuch_path = NULL; - gettimeofday (&add_files_state.tv_start, NULL); add_files_state.removed_files = _filename_list_create (notmuch); @@ -1284,7 +1278,7 @@ notmuch_new_command (unused(notmuch_config_t *config), notmuch_database_t *notmu notmuch_database_close (notmuch); if (hooks && ! ret && ! interrupted) - ret = notmuch_run_hook (db_path, "post-new"); + ret = notmuch_run_hook (notmuch, "post-new"); notmuch_database_destroy (notmuch); diff --git a/test/T400-hooks.sh b/test/T400-hooks.sh index 49c690eb..a3dd4c63 100755 --- a/test/T400-hooks.sh +++ b/test/T400-hooks.sh @@ -2,8 +2,6 @@ test_description='hooks' . $(dirname "$0")/test-lib.sh || exit 1 -HOOK_DIR=${MAIL_DIR}/.notmuch/hooks - create_echo_hook () { local TOKEN="${RANDOM}" mkdir -p ${HOOK_DIR} @@ -16,6 +14,7 @@ EOF } create_failing_hook () { + local HOOK_DIR=${2} mkdir -p ${HOOK_DIR} cat <"${HOOK_DIR}/${1}" #!/bin/sh @@ -24,98 +23,120 @@ EOF chmod +x "${HOOK_DIR}/${1}" } -rm_hooks () { - rm -rf ${HOOK_DIR} -} - # add a message to generate mail dir and database add_message # create maildir structure for notmuch-insert mkdir -p "$MAIL_DIR"/{cur,new,tmp} -test_begin_subtest "pre-new is run" -rm_hooks -generate_message -create_echo_hook "pre-new" expected output -notmuch new > /dev/null -test_expect_equal_file expected output - -test_begin_subtest "post-new is run" -rm_hooks -generate_message -create_echo_hook "post-new" expected output -notmuch new > /dev/null -test_expect_equal_file expected output - -test_begin_subtest "post-insert hook is run" -rm_hooks -generate_message -create_echo_hook "post-insert" expected output -notmuch insert < "$gen_msg_filename" -test_expect_equal_file expected output - -test_begin_subtest "pre-new is run before post-new" -rm_hooks -generate_message -create_echo_hook "pre-new" pre-new.expected pre-new.output -create_echo_hook "post-new" post-new.expected post-new.output -notmuch new > /dev/null -test_expect_equal_file post-new.expected post-new.output - -test_begin_subtest "pre-new non-zero exit status (hook status)" -rm_hooks -generate_message -create_failing_hook "pre-new" -output=`notmuch new 2>&1` -test_expect_equal "$output" "Error: pre-new hook failed with status 13" - -# depends on the previous subtest leaving broken hook behind -test_begin_subtest "pre-new non-zero exit status (notmuch status)" -test_expect_code 1 "notmuch new" - -# depends on the previous subtests leaving 1 new message behind -test_begin_subtest "pre-new non-zero exit status aborts new" -rm_hooks -output=$(NOTMUCH_NEW) -test_expect_equal "$output" "Added 1 new message to the database." - -test_begin_subtest "post-new non-zero exit status (hook status)" -rm_hooks -generate_message -create_failing_hook "post-new" -NOTMUCH_NEW 2>output.stderr >output -cat output.stderr >> output -echo "Added 1 new message to the database." > expected -echo "Error: post-new hook failed with status 13" >> expected -test_expect_equal_file expected output - -# depends on the previous subtest leaving broken hook behind -test_begin_subtest "post-new non-zero exit status (notmuch status)" -test_expect_code 1 "notmuch new" - -test_begin_subtest "post-insert hook does not affect insert status" -rm_hooks -generate_message -create_failing_hook "post-insert" -test_expect_success "notmuch insert < \"$gen_msg_filename\" > /dev/null" - -test_begin_subtest "hook without executable permissions" -rm_hooks -mkdir -p ${HOOK_DIR} -cat <"${HOOK_DIR}/pre-new" -#!/bin/sh -echo foo +for config in traditional profile explicit XDG; do + unset NOTMUCH_PROFILE + notmuch config set database.hook_dir + case $config in + traditional) + HOOK_DIR=${MAIL_DIR}/.notmuch/hooks + ;; + profile) + dir=${HOME}/.config/notmuch/other + mkdir -p ${dir} + HOOK_DIR=${dir}/hooks + cp ${NOTMUCH_CONFIG} ${dir}/config + export NOTMUCH_PROFILE=other + ;; + explicit) + HOOK_DIR=${HOME}/.notmuch-hooks + mkdir -p $HOOK_DIR + notmuch config set database.hook_dir $HOOK_DIR + ;; + XDG) + HOOK_DIR=${HOME}/.config/notmuch/default/hooks + ;; + esac + + test_begin_subtest "pre-new is run [${config}]" + rm -rf ${HOOK_DIR} + generate_message + create_echo_hook "pre-new" expected output $HOOK_DIR + notmuch new > /dev/null + test_expect_equal_file expected output + + test_begin_subtest "post-new is run [${config}]" + rm -rf ${HOOK_DIR} + generate_message + create_echo_hook "post-new" expected output $HOOK_DIR + notmuch new > /dev/null + test_expect_equal_file expected output + + test_begin_subtest "post-insert hook is run [${config}]" + rm -rf ${HOOK_DIR} + generate_message + create_echo_hook "post-insert" expected output $HOOK_DIR + notmuch insert < "$gen_msg_filename" + test_expect_equal_file expected output + + test_begin_subtest "pre-new is run before post-new [${config}]" + rm -rf ${HOOK_DIR} + generate_message + create_echo_hook "pre-new" pre-new.expected pre-new.output $HOOK_DIR + create_echo_hook "post-new" post-new.expected post-new.output $HOOK_DIR + notmuch new > /dev/null + test_expect_equal_file post-new.expected post-new.output + + test_begin_subtest "pre-new non-zero exit status (hook status) [${config}]" + rm -rf ${HOOK_DIR} + generate_message + create_failing_hook "pre-new" $HOOK_DIR + output=`notmuch new 2>&1` + test_expect_equal "$output" "Error: pre-new hook failed with status 13" + + # depends on the previous subtest leaving broken hook behind + test_begin_subtest "pre-new non-zero exit status (notmuch status) [${config}]" + test_expect_code 1 "notmuch new" + + # depends on the previous subtests leaving 1 new message behind + test_begin_subtest "pre-new non-zero exit status aborts new [${config}]" + rm -rf ${HOOK_DIR} + output=$(NOTMUCH_NEW) + test_expect_equal "$output" "Added 1 new message to the database." + + test_begin_subtest "post-new non-zero exit status (hook status) [${config}]" + rm -rf ${HOOK_DIR} + generate_message + create_failing_hook "post-new" $HOOK_DIR + NOTMUCH_NEW 2>output.stderr >output + cat output.stderr >> output + echo "Added 1 new message to the database." > expected + echo "Error: post-new hook failed with status 13" >> expected + test_expect_equal_file expected output + + # depends on the previous subtest leaving broken hook behind + test_begin_subtest "post-new non-zero exit status (notmuch status) [${config}]" + test_expect_code 1 "notmuch new" + + test_begin_subtest "post-insert hook does not affect insert status [${config}]" + rm -rf ${HOOK_DIR} + generate_message + create_failing_hook "post-insert" $HOOK_DIR + test_expect_success "notmuch insert < \"$gen_msg_filename\" > /dev/null" + + test_begin_subtest "hook without executable permissions [${config}]" + rm -rf ${HOOK_DIR} + mkdir -p ${HOOK_DIR} + cat <"${HOOK_DIR}/pre-new" + #!/bin/sh + echo foo EOF -output=`notmuch new 2>&1` -test_expect_code 1 "notmuch new" - -test_begin_subtest "hook execution failure" -rm_hooks -mkdir -p ${HOOK_DIR} -cat <"${HOOK_DIR}/pre-new" -no hashbang, execl fails + output=`notmuch new 2>&1` + test_expect_code 1 "notmuch new" + + test_begin_subtest "hook execution failure [${config}]" + rm -rf ${HOOK_DIR} + mkdir -p ${HOOK_DIR} + cat <"${HOOK_DIR}/pre-new" + no hashbang, execl fails EOF -chmod +x "${HOOK_DIR}/pre-new" -test_expect_code 1 "notmuch new" + chmod +x "${HOOK_DIR}/pre-new" + test_expect_code 1 "notmuch new" + rm -rf ${HOOK_DIR} +done test_done -- 2.30.0