From 45b7d2f329f5bb92dae55d6890729228d9dcecb1 Mon Sep 17 00:00:00 2001 From: David Bremner Date: Fri, 14 Aug 2015 18:47:57 +0200 Subject: [PATCH] [PATCH 4/5] cli: add global option "--uuid" --- c4/0d4403ab48aeac8f86fd99a308121d23c4dd19 | 375 ++++++++++++++++++++++ 1 file changed, 375 insertions(+) create mode 100644 c4/0d4403ab48aeac8f86fd99a308121d23c4dd19 diff --git a/c4/0d4403ab48aeac8f86fd99a308121d23c4dd19 b/c4/0d4403ab48aeac8f86fd99a308121d23c4dd19 new file mode 100644 index 000000000..614719986 --- /dev/null +++ b/c4/0d4403ab48aeac8f86fd99a308121d23c4dd19 @@ -0,0 +1,375 @@ +Return-Path: +X-Original-To: notmuch@notmuchmail.org +Delivered-To: notmuch@notmuchmail.org +Received: from localhost (localhost [127.0.0.1]) + by arlo.cworth.org (Postfix) with ESMTP id C4ABD6DE190D + for ; Fri, 14 Aug 2015 09:49:31 -0700 (PDT) +X-Virus-Scanned: Debian amavisd-new at cworth.org +X-Spam-Flag: NO +X-Spam-Score: 0.134 +X-Spam-Level: +X-Spam-Status: No, score=0.134 tagged_above=-999 required=5 tests=[AWL=0.124, + T_HEADER_FROM_DIFFERENT_DOMAINS=0.01] autolearn=disabled +Received: from arlo.cworth.org ([127.0.0.1]) + by localhost (arlo.cworth.org [127.0.0.1]) (amavisd-new, port 10024) + with ESMTP id XichQvwJyqfN for ; + Fri, 14 Aug 2015 09:49:30 -0700 (PDT) +Received: from gitolite.debian.net (gitolite.debian.net [87.98.215.224]) + by arlo.cworth.org (Postfix) with ESMTPS id F099F6DE18FD + for ; Fri, 14 Aug 2015 09:49:29 -0700 (PDT) +Received: from remotemail by gitolite.debian.net with local (Exim 4.80) + (envelope-from ) + id 1ZQI9v-0003eC-OJ; Fri, 14 Aug 2015 16:48:47 +0000 +Received: (nullmailer pid 15758 invoked by uid 1000); Fri, 14 Aug 2015 + 16:48:02 -0000 +From: David Bremner +To: notmuch@notmuchmail.org +Subject: [PATCH 4/5] cli: add global option "--uuid" +Date: Fri, 14 Aug 2015 18:47:57 +0200 +Message-Id: <1439570878-15165-5-git-send-email-david@tethera.net> +X-Mailer: git-send-email 2.5.0 +In-Reply-To: <1439570878-15165-1-git-send-email-david@tethera.net> +References: <1439570878-15165-1-git-send-email-david@tethera.net> +X-BeenThere: notmuch@notmuchmail.org +X-Mailman-Version: 2.1.18 +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: Fri, 14 Aug 2015 16:49:31 -0000 + +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. +--- + doc/man1/notmuch.rst | 11 +++++++++-- + notmuch-client.h | 4 ++++ + notmuch-compact.c | 5 +++++ + notmuch-config.c | 4 ++++ + notmuch-count.c | 2 ++ + notmuch-dump.c | 2 ++ + notmuch-insert.c | 2 ++ + notmuch-new.c | 3 ++- + notmuch-reply.c | 2 ++ + notmuch-restore.c | 2 ++ + notmuch-search.c | 2 ++ + notmuch-setup.c | 4 ++++ + notmuch-show.c | 2 ++ + notmuch-tag.c | 2 ++ + notmuch.c | 18 ++++++++++++++++++ + test/T570-revision-tracking.sh | 27 +++++++++++++++++++++++++++ + test/random-corpus.c | 2 ++ + 17 files changed, 91 insertions(+), 3 deletions(-) + +diff --git a/doc/man1/notmuch.rst b/doc/man1/notmuch.rst +index 0401c91..3acfbdb 100644 +--- a/doc/man1/notmuch.rst ++++ b/doc/man1/notmuch.rst +@@ -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 + ======== +diff --git a/notmuch-client.h b/notmuch-client.h +index 78680aa..4a4f86c 100644 +--- a/notmuch-client.h ++++ b/notmuch-client.h +@@ -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); +diff --git a/notmuch-compact.c b/notmuch-compact.c +index 5be551d..9373721 100644 +--- a/notmuch-compact.c ++++ b/notmuch-compact.c +@@ -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) +diff --git a/notmuch-config.c b/notmuch-config.c +index 9348278..d252bb2 100644 +--- a/notmuch-config.c ++++ b/notmuch-config.c +@@ -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; +diff --git a/notmuch-count.c b/notmuch-count.c +index 182710a..f26e726 100644 +--- a/notmuch-count.c ++++ b/notmuch-count.c +@@ -189,6 +189,8 @@ notmuch_count_command (notmuch_config_t *config, int argc, char *argv[]) + NOTMUCH_DATABASE_MODE_READ_ONLY, ¬much)) + 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"); +diff --git a/notmuch-dump.c b/notmuch-dump.c +index fab22bd..24fc2f2 100644 +--- a/notmuch-dump.c ++++ b/notmuch-dump.c +@@ -215,6 +215,8 @@ notmuch_dump_command (notmuch_config_t *config, int argc, char *argv[]) + NOTMUCH_DATABASE_MODE_READ_WRITE, ¬much)) + return EXIT_FAILURE; + ++ notmuch_exit_if_unmatched_db_uuid (notmuch); ++ + char *output_file_name = NULL; + int opt_index; + +diff --git a/notmuch-insert.c b/notmuch-insert.c +index c277d62..5205c17 100644 +--- a/notmuch-insert.c ++++ b/notmuch-insert.c +@@ -536,6 +536,8 @@ notmuch_insert_command (notmuch_config_t *config, int argc, char *argv[]) + NOTMUCH_DATABASE_MODE_READ_WRITE, ¬much)) + 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) { +diff --git a/notmuch-new.c b/notmuch-new.c +index ee786a3..514e06a 100644 +--- a/notmuch-new.c ++++ b/notmuch-new.c +@@ -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); +diff --git a/notmuch-reply.c b/notmuch-reply.c +index 4464741..7c5c28f 100644 +--- a/notmuch-reply.c ++++ b/notmuch-reply.c +@@ -831,6 +831,8 @@ notmuch_reply_command (notmuch_config_t *config, int argc, char *argv[]) + NOTMUCH_DATABASE_MODE_READ_ONLY, ¬much)) + 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"); +diff --git a/notmuch-restore.c b/notmuch-restore.c +index 2a534dc..9abc64f 100644 +--- a/notmuch-restore.c ++++ b/notmuch-restore.c +@@ -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) +diff --git a/notmuch-search.c b/notmuch-search.c +index b89a17e..3076c3f 100644 +--- a/notmuch-search.c ++++ b/notmuch-search.c +@@ -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"); +diff --git a/notmuch-setup.c b/notmuch-setup.c +index 7dd5822..9aaf928 100644 +--- a/notmuch-setup.c ++++ b/notmuch-setup.c +@@ -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 (); + +diff --git a/notmuch-show.c b/notmuch-show.c +index b80933a..6ef3308 100644 +--- a/notmuch-show.c ++++ b/notmuch-show.c +@@ -1213,6 +1213,8 @@ notmuch_show_command (notmuch_config_t *config, int argc, char *argv[]) + NOTMUCH_DATABASE_MODE_READ_ONLY, ¬much)) + 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"); +diff --git a/notmuch-tag.c b/notmuch-tag.c +index 38d99aa..7ae98f6 100644 +--- a/notmuch-tag.c ++++ b/notmuch-tag.c +@@ -261,6 +261,8 @@ notmuch_tag_command (notmuch_config_t *config, int argc, char *argv[]) + NOTMUCH_DATABASE_MODE_READ_WRITE, ¬much)) + return EXIT_FAILURE; + ++ notmuch_exit_if_unmatched_db_uuid (notmuch); ++ + if (notmuch_config_get_maildir_synchronize_flags (config)) + tag_flags |= TAG_FLAG_MAILDIR_SYNC; + +diff --git a/notmuch.c b/notmuch.c +index 9580c3f..ce6c575 100644 +--- a/notmuch.c ++++ b/notmuch.c +@@ -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, ¬much_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) + { +diff --git a/test/T570-revision-tracking.sh b/test/T570-revision-tracking.sh +index 4fff689..20b44cb 100755 +--- a/test/T570-revision-tracking.sh ++++ b/test/T570-revision-tracking.sh +@@ -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 +diff --git a/test/random-corpus.c b/test/random-corpus.c +index b377eb4..d74271d 100644 +--- a/test/random-corpus.c ++++ b/test/random-corpus.c +@@ -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)) + { +-- +2.5.0 + -- 2.26.2