CLI: use configured hook directory

This enables support for hooks outside the database directory.
It relies strongly on configuration information being usable between
closing the database and destroying it.
This commit is contained in:
David Bremner 2021-01-10 07:50:14 -04:00
parent 0345bc57a0
commit f61d88c6f4
5 changed files with 109 additions and 92 deletions

View file

@ -24,14 +24,15 @@
#include <sys/wait.h>
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;

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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 <<EOF >"${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
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 "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 "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-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 "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 "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 "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 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"
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
# 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"
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 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."
# 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"
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 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."
# 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-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
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"
# 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 "hook without executable permissions"
rm_hooks
mkdir -p ${HOOK_DIR}
cat <<EOF >"${HOOK_DIR}/pre-new"
#!/bin/sh
echo foo
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 <<EOF >"${HOOK_DIR}/pre-new"
#!/bin/sh
echo foo
EOF
output=`notmuch new 2>&1`
test_expect_code 1 "notmuch new"
output=`notmuch new 2>&1`
test_expect_code 1 "notmuch new"
test_begin_subtest "hook execution failure"
rm_hooks
mkdir -p ${HOOK_DIR}
cat <<EOF >"${HOOK_DIR}/pre-new"
no hashbang, execl fails
test_begin_subtest "hook execution failure [${config}]"
rm -rf ${HOOK_DIR}
mkdir -p ${HOOK_DIR}
cat <<EOF >"${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