--- /dev/null
+Return-Path: <tomi.ollila@iki.fi>\r
+X-Original-To: notmuch@notmuchmail.org\r
+Delivered-To: notmuch@notmuchmail.org\r
+Received: from localhost (localhost [127.0.0.1])\r
+ by arlo.cworth.org (Postfix) with ESMTP id BDD036DE1579\r
+ for <notmuch@notmuchmail.org>; Mon, 10 Aug 2015 12:42:46 -0700 (PDT)\r
+X-Virus-Scanned: Debian amavisd-new at cworth.org\r
+X-Spam-Flag: NO\r
+X-Spam-Score: 1.245\r
+X-Spam-Level: *\r
+X-Spam-Status: No, score=1.245 tagged_above=-999 required=5 tests=[AWL=-0.151,\r
+ SPF_NEUTRAL=0.652, URIBL_SBL=0.644, URIBL_SBL_A=0.1] autolearn=disabled\r
+Received: from arlo.cworth.org ([127.0.0.1])\r
+ by localhost (arlo.cworth.org [127.0.0.1]) (amavisd-new, port 10024)\r
+ with ESMTP id DMaztYa2nQde for <notmuch@notmuchmail.org>;\r
+ Mon, 10 Aug 2015 12:42:45 -0700 (PDT)\r
+Received: from guru.guru-group.fi (guru.guru-group.fi [46.183.73.34])\r
+ by arlo.cworth.org (Postfix) with ESMTP id 7357F6DE0244\r
+ for <notmuch@notmuchmail.org>; Mon, 10 Aug 2015 12:42:44 -0700 (PDT)\r
+Received: from guru.guru-group.fi (localhost [IPv6:::1])\r
+ by guru.guru-group.fi (Postfix) with ESMTP id B15971000CE;\r
+ Mon, 10 Aug 2015 22:42:33 +0300 (EEST)\r
+From: Tomi Ollila <tomi.ollila@iki.fi>\r
+To: David Bremner <david@tethera.net>, notmuch@notmuchmail.org\r
+Subject: Re: [PATCH 4/5] cli: add global option "--uuid"\r
+In-Reply-To: <1439112285-6681-5-git-send-email-david@tethera.net>\r
+References: <1439112285-6681-1-git-send-email-david@tethera.net>\r
+ <1439112285-6681-5-git-send-email-david@tethera.net>\r
+User-Agent: Notmuch/0.20.2+58~ge9cd033 (http://notmuchmail.org) Emacs/24.3.1\r
+ (x86_64-unknown-linux-gnu)\r
+X-Face: HhBM'cA~<r"^Xv\KRN0P{vn'Y"Kd;zg_y3S[4)KSN~s?O\"QPoL\r
+ $[Xv_BD:i/F$WiEWax}R(MPS`^UaptOGD`*/=@\1lKoVa9tnrg0TW?"r7aRtgk[F\r
+ !)g;OY^,BjTbr)Np:%c_o'jj,Z\r
+Date: Mon, 10 Aug 2015 22:42:33 +0300\r
+Message-ID: <m2y4hj3p7a.fsf@guru.guru-group.fi>\r
+MIME-Version: 1.0\r
+Content-Type: text/plain\r
+X-BeenThere: notmuch@notmuchmail.org\r
+X-Mailman-Version: 2.1.18\r
+Precedence: list\r
+List-Id: "Use and development of the notmuch mail system."\r
+ <notmuch.notmuchmail.org>\r
+List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,\r
+ <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>\r
+List-Archive: <http://notmuchmail.org/pipermail/notmuch/>\r
+List-Post: <mailto:notmuch@notmuchmail.org>\r
+List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>\r
+List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,\r
+ <mailto:notmuch-request@notmuchmail.org?subject=subscribe>\r
+X-List-Received-Date: Mon, 10 Aug 2015 19:42:46 -0000\r
+\r
+On Sun, Aug 09 2015, David Bremner <david@tethera.net> wrote:\r
+\r
+> The function notmuch_exit_if_unmatched_db_uuid is split from\r
+> notmuch_process_shared_options because it needs an open notmuch\r
+> database.\r
+> ---\r
+> doc/man1/notmuch.rst | 12 ++++++++++--\r
+> notmuch-client.h | 4 ++++\r
+> notmuch-compact.c | 4 ++++\r
+> notmuch-config.c | 4 ++++\r
+> notmuch-count.c | 2 ++\r
+> notmuch-dump.c | 2 ++\r
+> notmuch-insert.c | 2 ++\r
+> notmuch-new.c | 3 ++-\r
+> notmuch-reply.c | 2 ++\r
+> notmuch-restore.c | 2 ++\r
+> notmuch-search.c | 2 ++\r
+> notmuch-setup.c | 4 ++++\r
+> notmuch-show.c | 2 ++\r
+> notmuch-tag.c | 2 ++\r
+> notmuch.c | 18 ++++++++++++++++++\r
+> test/T570-revision-tracking.sh | 27 +++++++++++++++++++++++++++\r
+> test/random-corpus.c | 2 ++\r
+> 17 files changed, 91 insertions(+), 3 deletions(-)\r
+>\r
+> diff --git a/doc/man1/notmuch.rst b/doc/man1/notmuch.rst\r
+> index 0401c91..0b89544 100644\r
+> --- a/doc/man1/notmuch.rst\r
+> +++ b/doc/man1/notmuch.rst\r
+> @@ -51,9 +51,17 @@ Supported global options for ``notmuch`` include\r
+> Specify the configuration file to use. This overrides any\r
+> configuration file specified by ${NOTMUCH\_CONFIG}.\r
+> \r
+> + ``--uuid=HEX``\r
+> + Enforce that the database UUID (a unique identifier which\r
+> + persists until e.g. the database is compacted)\r
+> + is HEX; exit with an error if it is not. This is useful to\r
+> + detect rollover in modification counts on messages. You can\r
+> + find this UUID in the first column of output from\r
+> + ``notmuch count --output=modifications``\r
+> +\r
+> All global options except ``--config`` can also be specified after the\r
+> -command. For example, ``notmuch subcommand --version`` is equivalent to\r
+> -``notmuch --version subcommand``.\r
+> +command. For example, ``notmuch subcommand --uuid=HEX`` is\r
+> +equivalent to ``notmuch --uuid=HEX subcommand``.\r
+> \r
+> COMMANDS\r
+> ========\r
+> diff --git a/notmuch-client.h b/notmuch-client.h\r
+> index 78680aa..4a4f86c 100644\r
+> --- a/notmuch-client.h\r
+> +++ b/notmuch-client.h\r
+> @@ -466,7 +466,11 @@ notmuch_database_dump (notmuch_database_t *notmuch,\r
+> notmuch_bool_t gzip_output);\r
+> \r
+> #include "command-line-arguments.h"\r
+> +\r
+> +extern char *notmuch_requested_db_uuid;\r
+> extern const notmuch_opt_desc_t notmuch_shared_options [];\r
+> +void notmuch_exit_if_unmatched_db_uuid (notmuch_database_t *notmuch);\r
+> +\r
+> void notmuch_process_shared_options (const char* subcommand_name);\r
+> int notmuch_minimal_options (const char* subcommand_name,\r
+> int argc, char **argv);\r
+> diff --git a/notmuch-compact.c b/notmuch-compact.c\r
+> index 5be551d..61fccd8 100644\r
+> --- a/notmuch-compact.c\r
+> +++ b/notmuch-compact.c\r
+> @@ -46,6 +46,10 @@ notmuch_compact_command (notmuch_config_t *config, int argc, char *argv[])\r
+> if (opt_index < 0)\r
+> return EXIT_FAILURE;\r
+> \r
+> + if (notmuch_requested_db_uuid)\r
+> + fprintf (stderr, "Warning: ignoring --uuid=%s\n",\r
+> + notmuch_requested_db_uuid);\r
+> +\r
+\r
+I see in these commands this warning is issued, we don't open the database\r
+(at this time, IIRC compact opens it later)...\r
+\r
+... In this case I'm wondering whether giving --uuid should be considered\r
+as error (and stopping) instead of printing warning and continuing. In\r
+some other cases we do warn and continue but here ... we're modifying\r
+the database or configurations...\r
+... later we could add database uuid check always if --uuid is given\r
+and allow continuing if it matches in these cases...\r
+\r
+One more (now the trivial thing) to go, do not stop here ;)\r
+\r
+> notmuch_process_shared_options (argv[0]);\r
+> \r
+> if (! quiet)\r
+> diff --git a/notmuch-config.c b/notmuch-config.c\r
+> index 9348278..d252bb2 100644\r
+> --- a/notmuch-config.c\r
+> +++ b/notmuch-config.c\r
+> @@ -878,6 +878,10 @@ notmuch_config_command (notmuch_config_t *config, int argc, char *argv[])\r
+> if (opt_index < 0)\r
+> return EXIT_FAILURE;\r
+> \r
+> + if (notmuch_requested_db_uuid)\r
+> + fprintf (stderr, "Warning: ignoring --uuid=%s\n",\r
+> + notmuch_requested_db_uuid);\r
+> +\r
+> /* skip at least subcommand argument */\r
+> argc-= opt_index;\r
+> argv+= opt_index;\r
+> diff --git a/notmuch-count.c b/notmuch-count.c\r
+> index 7c61ccb..091e376 100644\r
+> --- a/notmuch-count.c\r
+> +++ b/notmuch-count.c\r
+> @@ -191,6 +191,8 @@ notmuch_count_command (notmuch_config_t *config, int argc, char *argv[])\r
+> NOTMUCH_DATABASE_MODE_READ_ONLY, ¬much))\r
+> return EXIT_FAILURE;\r
+> \r
+> + notmuch_exit_if_unmatched_db_uuid (notmuch);\r
+> +\r
+> query_str = query_string_from_args (config, argc-opt_index, argv+opt_index);\r
+> if (query_str == NULL) {\r
+> fprintf (stderr, "Out of memory.\n");\r
+> diff --git a/notmuch-dump.c b/notmuch-dump.c\r
+> index fab22bd..24fc2f2 100644\r
+> --- a/notmuch-dump.c\r
+> +++ b/notmuch-dump.c\r
+> @@ -215,6 +215,8 @@ notmuch_dump_command (notmuch_config_t *config, int argc, char *argv[])\r
+> NOTMUCH_DATABASE_MODE_READ_WRITE, ¬much))\r
+> return EXIT_FAILURE;\r
+> \r
+> + notmuch_exit_if_unmatched_db_uuid (notmuch);\r
+> +\r
+> char *output_file_name = NULL;\r
+> int opt_index;\r
+> \r
+> diff --git a/notmuch-insert.c b/notmuch-insert.c\r
+> index c277d62..5205c17 100644\r
+> --- a/notmuch-insert.c\r
+> +++ b/notmuch-insert.c\r
+> @@ -536,6 +536,8 @@ notmuch_insert_command (notmuch_config_t *config, int argc, char *argv[])\r
+> NOTMUCH_DATABASE_MODE_READ_WRITE, ¬much))\r
+> return EXIT_FAILURE;\r
+> \r
+> + notmuch_exit_if_unmatched_db_uuid (notmuch);\r
+> +\r
+> /* Write the message to the Maildir new directory. */\r
+> newpath = maildir_write_new (config, STDIN_FILENO, maildir);\r
+> if (! newpath) {\r
+> diff --git a/notmuch-new.c b/notmuch-new.c\r
+> index ee786a3..514e06a 100644\r
+> --- a/notmuch-new.c\r
+> +++ b/notmuch-new.c\r
+> @@ -1009,10 +1009,11 @@ notmuch_new_command (notmuch_config_t *config, int argc, char *argv[])\r
+> fputs (status_string, stderr);\r
+> free (status_string);\r
+> }\r
+> -\r
+> return EXIT_FAILURE;\r
+> }\r
+> \r
+> + notmuch_exit_if_unmatched_db_uuid (notmuch);\r
+> +\r
+> if (notmuch_database_needs_upgrade (notmuch)) {\r
+> time_t now = time (NULL);\r
+> struct tm *gm_time = gmtime (&now);\r
+> diff --git a/notmuch-reply.c b/notmuch-reply.c\r
+> index 4464741..7c5c28f 100644\r
+> --- a/notmuch-reply.c\r
+> +++ b/notmuch-reply.c\r
+> @@ -831,6 +831,8 @@ notmuch_reply_command (notmuch_config_t *config, int argc, char *argv[])\r
+> NOTMUCH_DATABASE_MODE_READ_ONLY, ¬much))\r
+> return EXIT_FAILURE;\r
+> \r
+> + notmuch_exit_if_unmatched_db_uuid (notmuch);\r
+> +\r
+> query = notmuch_query_create (notmuch, query_string);\r
+> if (query == NULL) {\r
+> fprintf (stderr, "Out of memory\n");\r
+> diff --git a/notmuch-restore.c b/notmuch-restore.c\r
+> index 2a534dc..9abc64f 100644\r
+> --- a/notmuch-restore.c\r
+> +++ b/notmuch-restore.c\r
+> @@ -165,6 +165,8 @@ notmuch_restore_command (notmuch_config_t *config, int argc, char *argv[])\r
+> }\r
+> \r
+> notmuch_process_shared_options (argv[0]);\r
+> + notmuch_exit_if_unmatched_db_uuid (notmuch);\r
+> +\r
+> name_for_error = input_file_name ? input_file_name : "stdin";\r
+> \r
+> if (! accumulate)\r
+> diff --git a/notmuch-search.c b/notmuch-search.c\r
+> index b89a17e..3076c3f 100644\r
+> --- a/notmuch-search.c\r
+> +++ b/notmuch-search.c\r
+> @@ -583,6 +583,8 @@ _notmuch_search_prepare (search_context_t *ctx, notmuch_config_t *config, int ar\r
+> return EXIT_FAILURE;\r
+> }\r
+> \r
+> + notmuch_exit_if_unmatched_db_uuid (ctx->notmuch);\r
+> +\r
+> query_str = query_string_from_args (ctx->notmuch, argc, argv);\r
+> if (query_str == NULL) {\r
+> fprintf (stderr, "Out of memory.\n");\r
+> diff --git a/notmuch-setup.c b/notmuch-setup.c\r
+> index 7dd5822..9aaf928 100644\r
+> --- a/notmuch-setup.c\r
+> +++ b/notmuch-setup.c\r
+> @@ -148,6 +148,10 @@ notmuch_setup_command (notmuch_config_t *config,\r
+> if (notmuch_minimal_options ("setup", argc, argv) < 0)\r
+> return EXIT_FAILURE;\r
+> \r
+> + if (notmuch_requested_db_uuid)\r
+> + fprintf (stderr, "Warning: ignoring --uuid=%s\n",\r
+> + notmuch_requested_db_uuid);\r
+> +\r
+> if (notmuch_config_is_new (config))\r
+> welcome_message_pre_setup ();\r
+> \r
+> diff --git a/notmuch-show.c b/notmuch-show.c\r
+> index b80933a..6ef3308 100644\r
+> --- a/notmuch-show.c\r
+> +++ b/notmuch-show.c\r
+> @@ -1213,6 +1213,8 @@ notmuch_show_command (notmuch_config_t *config, int argc, char *argv[])\r
+> NOTMUCH_DATABASE_MODE_READ_ONLY, ¬much))\r
+> return EXIT_FAILURE;\r
+> \r
+> + notmuch_exit_if_unmatched_db_uuid (notmuch);\r
+> +\r
+> query = notmuch_query_create (notmuch, query_string);\r
+> if (query == NULL) {\r
+> fprintf (stderr, "Out of memory\n");\r
+> diff --git a/notmuch-tag.c b/notmuch-tag.c\r
+> index 38d99aa..7ae98f6 100644\r
+> --- a/notmuch-tag.c\r
+> +++ b/notmuch-tag.c\r
+> @@ -261,6 +261,8 @@ notmuch_tag_command (notmuch_config_t *config, int argc, char *argv[])\r
+> NOTMUCH_DATABASE_MODE_READ_WRITE, ¬much))\r
+> return EXIT_FAILURE;\r
+> \r
+> + notmuch_exit_if_unmatched_db_uuid (notmuch);\r
+> +\r
+> if (notmuch_config_get_maildir_synchronize_flags (config))\r
+> tag_flags |= TAG_FLAG_MAILDIR_SYNC;\r
+> \r
+> diff --git a/notmuch.c b/notmuch.c\r
+> index 9580c3f..ce6c575 100644\r
+> --- a/notmuch.c\r
+> +++ b/notmuch.c\r
+> @@ -47,10 +47,12 @@ static int\r
+> _help_for (const char *topic);\r
+> \r
+> static notmuch_bool_t print_version = FALSE, print_help = FALSE;\r
+> +char *notmuch_requested_db_uuid = NULL;\r
+> \r
+> const notmuch_opt_desc_t notmuch_shared_options [] = {\r
+> { NOTMUCH_OPT_BOOLEAN, &print_version, "version", 'v', 0 },\r
+> { NOTMUCH_OPT_BOOLEAN, &print_help, "help", 'h', 0 },\r
+> + { NOTMUCH_OPT_STRING, ¬much_requested_db_uuid, "uuid", 'u', 0 },\r
+> {0, 0, 0, 0, 0}\r
+> };\r
+> \r
+> @@ -218,6 +220,22 @@ be supported in the future.\n", notmuch_format_version);\r
+> }\r
+> }\r
+> \r
+> +void\r
+> +notmuch_exit_if_unmatched_db_uuid (notmuch_database_t *notmuch)\r
+> +{\r
+> + const char *uuid = NULL;\r
+> +\r
+> + if (!notmuch_requested_db_uuid)\r
+> + return;\r
+> + IGNORE_RESULT (notmuch_database_get_revision (notmuch, &uuid));\r
+> +\r
+> + if (strcmp (notmuch_requested_db_uuid, uuid) != 0){\r
+> + fprintf (stderr, "Error: requested database revision %s does not match %s\n",\r
+> + notmuch_requested_db_uuid, uuid);\r
+> + exit (1);\r
+> + }\r
+> +}\r
+> +\r
+> static void\r
+> exec_man (const char *page)\r
+> {\r
+> diff --git a/test/T570-revision-tracking.sh b/test/T570-revision-tracking.sh\r
+> index 008c5d0..74e3ba9 100755\r
+> --- a/test/T570-revision-tracking.sh\r
+> +++ b/test/T570-revision-tracking.sh\r
+> @@ -46,4 +46,31 @@ notmuch tag +a-random-tag-8743632 '*'\r
+> after=$(notmuch count --output=modifications '*' | cut -f2)\r
+> result=$(($before < $after))\r
+> test_expect_equal 1 ${result}\r
+> +\r
+> +notmuch count --output=modifications '*' | cut -f1 > UUID\r
+\r
+the above could be\r
+\r
+UUID=$(notmuch count --output=modifications '*' | cut -f1)\r
+\r
+> +\r
+> +test_expect_success 'search succeeds with correct uuid' \\r
+> + "notmuch search --uuid=$(cat UUID) '*'"\r
+\r
+And then these just as \r
+\r
+test_expect_success 'search succeeds with correct uuid' \\r
+ "notmuch search --uuid=${UUID} '*'"\r
+\r
+\r
+Tomi\r
+\r
+\r
+> +\r
+> +test_expect_success 'uuid works as global option ' \\r
+> + "notmuch --uuid=$(cat UUID) search '*'"\r
+> +\r
+> +test_expect_code 1 'uuid works as global option II' \\r
+> + "notmuch --uuid=this-is-no-uuid search '*'"\r
+> +\r
+> +test_expect_code 1 'search fails with incorrect uuid' \\r
+> + "notmuch search --uuid=this-is-no-uuid '*'"\r
+> +\r
+> +test_expect_success 'show succeeds with correct uuid' \\r
+> + "notmuch show --uuid=$(cat UUID) '*'"\r
+> +\r
+> +test_expect_code 1 'show fails with incorrect uuid' \\r
+> + "notmuch show --uuid=this-is-no-uuid '*'"\r
+> +\r
+> +test_expect_success 'tag succeeds with correct uuid' \\r
+> + "notmuch tag --uuid=$(cat UUID) +test '*'"\r
+> +\r
+> +test_expect_code 1 'tag fails with incorrect uuid' \\r
+> + "notmuch tag --uuid=this-is-no-uuid '*' +test2"\r
+> +\r
+> test_done\r
+> diff --git a/test/random-corpus.c b/test/random-corpus.c\r
+> index b377eb4..d74271d 100644\r
+> --- a/test/random-corpus.c\r
+> +++ b/test/random-corpus.c\r
+> @@ -119,6 +119,8 @@ const notmuch_opt_desc_t notmuch_shared_options[] = {\r
+> { 0, 0, 0, 0, 0 }\r
+> };\r
+> \r
+> +char *notmuch_requested_db_uuid = NULL;\r
+> +\r
+> void\r
+> notmuch_process_shared_options (unused (const char *dummy))\r
+> {\r
+> -- \r
+> 2.1.4\r