cli: add global option "--uuid"

The function notmuch_exit_if_unmatched_db_uuid is split from
notmuch_process_shared_options because it needs an open notmuch
database.

There are two exceptional cases in uuid handling.

1) notmuch config and notmuch setup don't currently open the database,
   so it doesn't make sense to check the UUID.

2) notmuch compact opens the database inside the library, so we either
   need to open the database just to check uuid, or change the API.
This commit is contained in:
David Bremner 2015-04-06 07:39:55 +09:00
parent 5a3b42fb8c
commit f76d8f82dd
17 changed files with 91 additions and 3 deletions

View file

@ -51,9 +51,16 @@ Supported global options for ``notmuch`` include
Specify the configuration file to use. This overrides any
configuration file specified by ${NOTMUCH\_CONFIG}.
``--uuid=HEX``
Enforce that the database UUID (a unique identifier which
persists until e.g. the database is compacted)
is HEX; exit with an error if it is not. This is useful to
detect rollover in modification counts on messages. You can
find this UUID using e.g. ``notmuch count --lastmod``
All global options except ``--config`` can also be specified after the
command. For example, ``notmuch subcommand --version`` is equivalent to
``notmuch --version subcommand``.
command. For example, ``notmuch subcommand --uuid=HEX`` is
equivalent to ``notmuch --uuid=HEX subcommand``.
COMMANDS
========

View file

@ -466,7 +466,11 @@ notmuch_database_dump (notmuch_database_t *notmuch,
notmuch_bool_t gzip_output);
#include "command-line-arguments.h"
extern char *notmuch_requested_db_uuid;
extern const notmuch_opt_desc_t notmuch_shared_options [];
void notmuch_exit_if_unmatched_db_uuid (notmuch_database_t *notmuch);
void notmuch_process_shared_options (const char* subcommand_name);
int notmuch_minimal_options (const char* subcommand_name,
int argc, char **argv);

View file

@ -46,6 +46,11 @@ notmuch_compact_command (notmuch_config_t *config, int argc, char *argv[])
if (opt_index < 0)
return EXIT_FAILURE;
if (notmuch_requested_db_uuid) {
fprintf (stderr, "Error: --uuid not implemented for compact\n");
return EXIT_FAILURE;
}
notmuch_process_shared_options (argv[0]);
if (! quiet)

View file

@ -878,6 +878,10 @@ notmuch_config_command (notmuch_config_t *config, int argc, char *argv[])
if (opt_index < 0)
return EXIT_FAILURE;
if (notmuch_requested_db_uuid)
fprintf (stderr, "Warning: ignoring --uuid=%s\n",
notmuch_requested_db_uuid);
/* skip at least subcommand argument */
argc-= opt_index;
argv+= opt_index;

View file

@ -189,6 +189,8 @@ notmuch_count_command (notmuch_config_t *config, int argc, char *argv[])
NOTMUCH_DATABASE_MODE_READ_ONLY, &notmuch))
return EXIT_FAILURE;
notmuch_exit_if_unmatched_db_uuid (notmuch);
query_str = query_string_from_args (config, argc-opt_index, argv+opt_index);
if (query_str == NULL) {
fprintf (stderr, "Out of memory.\n");

View file

@ -215,6 +215,8 @@ notmuch_dump_command (notmuch_config_t *config, int argc, char *argv[])
NOTMUCH_DATABASE_MODE_READ_WRITE, &notmuch))
return EXIT_FAILURE;
notmuch_exit_if_unmatched_db_uuid (notmuch);
char *output_file_name = NULL;
int opt_index;

View file

@ -536,6 +536,8 @@ notmuch_insert_command (notmuch_config_t *config, int argc, char *argv[])
NOTMUCH_DATABASE_MODE_READ_WRITE, &notmuch))
return EXIT_FAILURE;
notmuch_exit_if_unmatched_db_uuid (notmuch);
/* Write the message to the Maildir new directory. */
newpath = maildir_write_new (config, STDIN_FILENO, maildir);
if (! newpath) {

View file

@ -1009,10 +1009,11 @@ notmuch_new_command (notmuch_config_t *config, int argc, char *argv[])
fputs (status_string, stderr);
free (status_string);
}
return EXIT_FAILURE;
}
notmuch_exit_if_unmatched_db_uuid (notmuch);
if (notmuch_database_needs_upgrade (notmuch)) {
time_t now = time (NULL);
struct tm *gm_time = gmtime (&now);

View file

@ -831,6 +831,8 @@ notmuch_reply_command (notmuch_config_t *config, int argc, char *argv[])
NOTMUCH_DATABASE_MODE_READ_ONLY, &notmuch))
return EXIT_FAILURE;
notmuch_exit_if_unmatched_db_uuid (notmuch);
query = notmuch_query_create (notmuch, query_string);
if (query == NULL) {
fprintf (stderr, "Out of memory\n");

View file

@ -165,6 +165,8 @@ notmuch_restore_command (notmuch_config_t *config, int argc, char *argv[])
}
notmuch_process_shared_options (argv[0]);
notmuch_exit_if_unmatched_db_uuid (notmuch);
name_for_error = input_file_name ? input_file_name : "stdin";
if (! accumulate)

View file

@ -583,6 +583,8 @@ _notmuch_search_prepare (search_context_t *ctx, notmuch_config_t *config, int ar
return EXIT_FAILURE;
}
notmuch_exit_if_unmatched_db_uuid (ctx->notmuch);
query_str = query_string_from_args (ctx->notmuch, argc, argv);
if (query_str == NULL) {
fprintf (stderr, "Out of memory.\n");

View file

@ -148,6 +148,10 @@ notmuch_setup_command (notmuch_config_t *config,
if (notmuch_minimal_options ("setup", argc, argv) < 0)
return EXIT_FAILURE;
if (notmuch_requested_db_uuid)
fprintf (stderr, "Warning: ignoring --uuid=%s\n",
notmuch_requested_db_uuid);
if (notmuch_config_is_new (config))
welcome_message_pre_setup ();

View file

@ -1213,6 +1213,8 @@ notmuch_show_command (notmuch_config_t *config, int argc, char *argv[])
NOTMUCH_DATABASE_MODE_READ_ONLY, &notmuch))
return EXIT_FAILURE;
notmuch_exit_if_unmatched_db_uuid (notmuch);
query = notmuch_query_create (notmuch, query_string);
if (query == NULL) {
fprintf (stderr, "Out of memory\n");

View file

@ -261,6 +261,8 @@ notmuch_tag_command (notmuch_config_t *config, int argc, char *argv[])
NOTMUCH_DATABASE_MODE_READ_WRITE, &notmuch))
return EXIT_FAILURE;
notmuch_exit_if_unmatched_db_uuid (notmuch);
if (notmuch_config_get_maildir_synchronize_flags (config))
tag_flags |= TAG_FLAG_MAILDIR_SYNC;

View file

@ -47,10 +47,12 @@ static int
_help_for (const char *topic);
static notmuch_bool_t print_version = FALSE, print_help = FALSE;
char *notmuch_requested_db_uuid = NULL;
const notmuch_opt_desc_t notmuch_shared_options [] = {
{ NOTMUCH_OPT_BOOLEAN, &print_version, "version", 'v', 0 },
{ NOTMUCH_OPT_BOOLEAN, &print_help, "help", 'h', 0 },
{ NOTMUCH_OPT_STRING, &notmuch_requested_db_uuid, "uuid", 'u', 0 },
{0, 0, 0, 0, 0}
};
@ -218,6 +220,22 @@ be supported in the future.\n", notmuch_format_version);
}
}
void
notmuch_exit_if_unmatched_db_uuid (notmuch_database_t *notmuch)
{
const char *uuid = NULL;
if (!notmuch_requested_db_uuid)
return;
IGNORE_RESULT (notmuch_database_get_revision (notmuch, &uuid));
if (strcmp (notmuch_requested_db_uuid, uuid) != 0){
fprintf (stderr, "Error: requested database revision %s does not match %s\n",
notmuch_requested_db_uuid, uuid);
exit (1);
}
}
static void
exec_man (const char *page)
{

View file

@ -46,4 +46,31 @@ notmuch tag +a-random-tag-8743632 '*'
after=$(notmuch count --lastmod '*' | cut -f3)
result=$(($before < $after))
test_expect_equal 1 ${result}
notmuch count --lastmod '*' | cut -f2 > UUID
test_expect_success 'search succeeds with correct uuid' \
"notmuch search --uuid=$(cat UUID) '*'"
test_expect_success 'uuid works as global option ' \
"notmuch --uuid=$(cat UUID) search '*'"
test_expect_code 1 'uuid works as global option II' \
"notmuch --uuid=this-is-no-uuid search '*'"
test_expect_code 1 'search fails with incorrect uuid' \
"notmuch search --uuid=this-is-no-uuid '*'"
test_expect_success 'show succeeds with correct uuid' \
"notmuch show --uuid=$(cat UUID) '*'"
test_expect_code 1 'show fails with incorrect uuid' \
"notmuch show --uuid=this-is-no-uuid '*'"
test_expect_success 'tag succeeds with correct uuid' \
"notmuch tag --uuid=$(cat UUID) +test '*'"
test_expect_code 1 'tag fails with incorrect uuid' \
"notmuch tag --uuid=this-is-no-uuid '*' +test2"
test_done

View file

@ -119,6 +119,8 @@ const notmuch_opt_desc_t notmuch_shared_options[] = {
{ 0, 0, 0, 0, 0 }
};
char *notmuch_requested_db_uuid = NULL;
void
notmuch_process_shared_options (unused (const char *dummy))
{