--- /dev/null
+Return-Path: <bremner@tethera.net>\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 6BDAD6DE092B\r
+ for <notmuch@notmuchmail.org>; Tue, 22 Mar 2016 03:56:08 -0700 (PDT)\r
+X-Virus-Scanned: Debian amavisd-new at cworth.org\r
+X-Spam-Flag: NO\r
+X-Spam-Score: -0.029\r
+X-Spam-Level: \r
+X-Spam-Status: No, score=-0.029 tagged_above=-999 required=5\r
+ tests=[AWL=-0.018, SPF_PASS=-0.001, T_RP_MATCHES_RCVD=-0.01]\r
+ 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 c5M-Iw1F0ae5 for <notmuch@notmuchmail.org>;\r
+ Tue, 22 Mar 2016 03:56:00 -0700 (PDT)\r
+Received: from fethera.tethera.net (fethera.tethera.net [198.245.60.197])\r
+ by arlo.cworth.org (Postfix) with ESMTPS id D4D7E6DE0297\r
+ for <notmuch@notmuchmail.org>; Tue, 22 Mar 2016 03:55:25 -0700 (PDT)\r
+Received: from remotemail by fethera.tethera.net with local (Exim 4.84)\r
+ (envelope-from <bremner@tethera.net>)\r
+ id 1aiJyj-00015k-9C; Tue, 22 Mar 2016 06:56:01 -0400\r
+Received: (nullmailer pid 14089 invoked by uid 1000);\r
+ Tue, 22 Mar 2016 10:55:11 -0000\r
+From: David Bremner <david@tethera.net>\r
+To: notmuch@notmuchmail.org\r
+Subject: [PATCH 11/13] CLI: add notmuch-config support for named queries\r
+Date: Tue, 22 Mar 2016 07:54:52 -0300\r
+Message-Id: <1458644094-13951-12-git-send-email-david@tethera.net>\r
+X-Mailer: git-send-email 2.7.0\r
+In-Reply-To: <1458644094-13951-1-git-send-email-david@tethera.net>\r
+References: <1458644094-13951-1-git-send-email-david@tethera.net>\r
+X-BeenThere: notmuch@notmuchmail.org\r
+X-Mailman-Version: 2.1.20\r
+Precedence: list\r
+List-Id: "Use and development of the notmuch mail system."\r
+ <notmuch.notmuchmail.org>\r
+List-Unsubscribe: <https://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: <https://notmuchmail.org/mailman/listinfo/notmuch>,\r
+ <mailto:notmuch-request@notmuchmail.org?subject=subscribe>\r
+X-List-Received-Date: Tue, 22 Mar 2016 10:56:08 -0000\r
+\r
+Most of the infrastructure here is general, only the validation/dispatch\r
+is hardcoded to a particular prefix.\r
+\r
+A notable change in behaviour is that notmuch-config now opens the\r
+database e.g. on every call to list, which fails with an error message\r
+if the database doesn't exit yet.\r
+---\r
+ doc/man1/notmuch-config.rst | 5 +++\r
+ notmuch-config.c | 88 ++++++++++++++++++++++++++++++++++++++++++++-\r
+ test/Makefile.local | 2 +-\r
+ test/T030-config.sh | 12 ++++---\r
+ test/T600-named-queries.sh | 53 +++++++++++++++++++++++++++\r
+ test/test-lib.sh | 5 +++\r
+ 6 files changed, 158 insertions(+), 7 deletions(-)\r
+ create mode 100755 test/T600-named-queries.sh\r
+\r
+diff --git a/doc/man1/notmuch-config.rst b/doc/man1/notmuch-config.rst\r
+index 40c1272..98b3c1a 100644\r
+--- a/doc/man1/notmuch-config.rst\r
++++ b/doc/man1/notmuch-config.rst\r
+@@ -132,6 +132,11 @@ The available configuration items are described below.\r
+ \r
+ Default: ``gpg``.\r
+ \r
++ **query.<name>**\r
++\r
++ Expansion for named query called <name>. See\r
++ **notmuch-search-terms(7)** for more information about named\r
++ queries.\r
+ \r
+ ENVIRONMENT\r
+ ===========\r
+diff --git a/notmuch-config.c b/notmuch-config.c\r
+index cfc549d..121fec6 100644\r
+--- a/notmuch-config.c\r
++++ b/notmuch-config.c\r
+@@ -751,6 +751,28 @@ _item_split (char *item, char **group, char **key)\r
+ }\r
+ \r
+ #define OPTION_PREFIX "options."\r
++#define QUERY_PREFIX "query."\r
++\r
++static int\r
++_print_db_config(notmuch_config_t *config, const char *name)\r
++{\r
++ notmuch_database_t *notmuch;\r
++ char *val;\r
++\r
++ if (notmuch_database_open (notmuch_config_get_database_path (config),\r
++ NOTMUCH_DATABASE_MODE_READ_ONLY, ¬much))\r
++ return EXIT_FAILURE;\r
++\r
++ /* XXX Handle UUID mismatch? */\r
++\r
++ if (print_status_database ("notmuch config", notmuch,\r
++ notmuch_database_get_config (notmuch, name, &val)))\r
++ return EXIT_FAILURE;\r
++\r
++ puts (val);\r
++\r
++ return EXIT_SUCCESS;\r
++}\r
+ \r
+ static int\r
+ notmuch_config_command_get (notmuch_config_t *config, char *item)\r
+@@ -778,6 +800,8 @@ notmuch_config_command_get (notmuch_config_t *config, char *item)\r
+ } else if (STRNCMP_LITERAL (item, OPTION_PREFIX) == 0) {\r
+ printf ("%s\n",\r
+ notmuch_options_get (item + strlen (OPTION_PREFIX)) ? "true" : "false");\r
++ } else if (STRNCMP_LITERAL (item, QUERY_PREFIX) == 0) {\r
++ return _print_db_config (config, item);\r
+ } else {\r
+ char **value;\r
+ size_t i, length;\r
+@@ -805,6 +829,39 @@ notmuch_config_command_get (notmuch_config_t *config, char *item)\r
+ }\r
+ \r
+ static int\r
++_set_db_config(notmuch_config_t *config, const char *key, int argc, char **argv)\r
++{\r
++ notmuch_database_t *notmuch;\r
++ const char *val = "";\r
++\r
++ if (argc > 1) {\r
++ /* XXX handle lists? */\r
++ fprintf (stderr, "notmuch config set: at most one value expected for %s\n", key);\r
++ return EXIT_FAILURE;\r
++ }\r
++\r
++ if (argc > 0) {\r
++ val = argv[0];\r
++ }\r
++\r
++ if (notmuch_database_open (notmuch_config_get_database_path (config),\r
++ NOTMUCH_DATABASE_MODE_READ_WRITE, ¬much))\r
++ return EXIT_FAILURE;\r
++\r
++ /* XXX Handle UUID mismatch? */\r
++\r
++ if (print_status_database ("notmuch config", notmuch,\r
++ notmuch_database_set_config (notmuch, key, val)))\r
++ return EXIT_FAILURE;\r
++\r
++ if (print_status_database ("notmuch config", notmuch,\r
++ notmuch_database_close (notmuch)))\r
++ return EXIT_FAILURE;\r
++\r
++ return EXIT_SUCCESS;\r
++}\r
++\r
++static int\r
+ notmuch_config_command_set (notmuch_config_t *config, char *item, int argc, char *argv[])\r
+ {\r
+ char *group, *key;\r
+@@ -814,6 +871,10 @@ notmuch_config_command_set (notmuch_config_t *config, char *item, int argc, char\r
+ return 1;\r
+ }\r
+ \r
++ if (STRNCMP_LITERAL (item, QUERY_PREFIX) == 0) {\r
++ return _set_db_config (config, item, argc, argv);\r
++ }\r
++\r
+ if (_item_split (item, &group, &key))\r
+ return 1;\r
+ \r
+@@ -850,6 +911,31 @@ _notmuch_config_list_options () {\r
+ }\r
+ \r
+ static int\r
++_list_db_config (notmuch_config_t *config)\r
++{\r
++ notmuch_database_t *notmuch;\r
++ notmuch_config_list_t *list;\r
++\r
++ if (notmuch_database_open (notmuch_config_get_database_path (config),\r
++ NOTMUCH_DATABASE_MODE_READ_ONLY, ¬much))\r
++ return EXIT_FAILURE;\r
++\r
++ /* XXX Handle UUID mismatch? */\r
++\r
++\r
++ if (print_status_database ("notmuch config", notmuch,\r
++ notmuch_database_get_config_list (notmuch, "", &list)))\r
++ return EXIT_FAILURE;\r
++\r
++ for (; notmuch_config_list_valid (list); notmuch_config_list_move_to_next (list)) {\r
++ printf("%s=%s\n", notmuch_config_list_key (list), notmuch_config_list_value(list));\r
++ }\r
++ notmuch_config_list_destroy (list);\r
++\r
++ return EXIT_SUCCESS;\r
++}\r
++\r
++static int\r
+ notmuch_config_command_list (notmuch_config_t *config)\r
+ {\r
+ char **groups;\r
+@@ -885,7 +971,7 @@ notmuch_config_command_list (notmuch_config_t *config)\r
+ g_strfreev (groups);\r
+ \r
+ _notmuch_config_list_options ();\r
+- return 0;\r
++ return _list_db_config (config);\r
+ }\r
+ \r
+ int\r
+diff --git a/test/Makefile.local b/test/Makefile.local\r
+index 30d420e..8c55441 100644\r
+--- a/test/Makefile.local\r
++++ b/test/Makefile.local\r
+@@ -19,7 +19,7 @@ $(dir)/hex-xcode: $(dir)/hex-xcode.o command-line-arguments.o util/libutil.a\r
+ $(call quiet,CC) $^ -o $@ $(LDFLAGS) $(TALLOC_LDFLAGS)\r
+ \r
+ random_corpus_deps = $(dir)/random-corpus.o $(dir)/database-test.o \\r
+- notmuch-config.o command-line-arguments.o \\r
++ notmuch-config.o status.o command-line-arguments.o \\r
+ lib/libnotmuch.a util/libutil.a \\r
+ parse-time-string/libparse-time-string.a\r
+ \r
+diff --git a/test/T030-config.sh b/test/T030-config.sh\r
+index c37ba21..39ee885 100755\r
+--- a/test/T030-config.sh\r
++++ b/test/T030-config.sh\r
+@@ -43,10 +43,10 @@ notmuch config set foo.nonexistent\r
+ test_expect_equal "$(notmuch config get foo.nonexistent)" ""\r
+ \r
+ test_begin_subtest "List all items"\r
+-notmuch config set database.path "/canonical/path"\r
+-output=$(notmuch config list | notmuch_options_sanitize)\r
+-test_expect_equal "$output" "\\r
+-database.path=/canonical/path\r
++notmuch config list 2>&1 | notmuch_config_sanitize > OUTPUT\r
++cat <<EOF > EXPECTED\r
++Error opening database at MAIL_DIR/.notmuch: No such file or directory\r
++database.path=MAIL_DIR\r
+ user.name=Notmuch Test Suite\r
+ user.primary_email=test_suite@notmuchmail.org\r
+ user.other_email=test_suite_other@notmuchmail.org;test_suite@otherdomain.org\r
+@@ -58,7 +58,9 @@ crypto.gpg_path=gpg\r
+ foo.string=this is another string value\r
+ foo.list=this;is another;list value;\r
+ options.compact=something\r
+-options.field_processor=something"\r
++options.field_processor=something\r
++EOF\r
++test_expect_equal_file EXPECTED OUTPUT\r
+ \r
+ test_begin_subtest "Top level --config=FILE option"\r
+ cp "${NOTMUCH_CONFIG}" alt-config\r
+diff --git a/test/T600-named-queries.sh b/test/T600-named-queries.sh\r
+new file mode 100755\r
+index 0000000..0922620\r
+--- /dev/null\r
++++ b/test/T600-named-queries.sh\r
+@@ -0,0 +1,53 @@\r
++#!/usr/bin/env bash\r
++test_description='named queries'\r
++. ./test-lib.sh || exit 1\r
++\r
++QUERYSTR="date:2009-11-18..2009-11-18 and tag:unread"\r
++\r
++test_expect_code 1 "error adding named query before initializing DB" \\r
++ "notmuch config set query.test \"$QUERYSTR\""\r
++\r
++add_email_corpus\r
++\r
++test_expect_success "adding named query" \\r
++ "notmuch config set query.test \"$QUERYSTR\""\r
++\r
++QUERYSTR2="query:test and subject:Maildir"\r
++test_expect_success "adding nested named query" \\r
++ "notmuch config set query.test2 \"$QUERYSTR2\""\r
++\r
++test_begin_subtest "retrieve named query"\r
++output=$(notmuch config get query.test)\r
++test_expect_equal "$QUERYSTR" "$output"\r
++\r
++test_begin_subtest "List all queries"\r
++notmuch config list | grep ^query | notmuch_config_sanitize > OUTPUT\r
++cat <<EOF > EXPECTED\r
++query.test=date:2009-11-18..2009-11-18 and tag:unread\r
++query.test2=query:test and subject:Maildir\r
++EOF\r
++test_expect_equal_file EXPECTED OUTPUT\r
++\r
++test_begin_subtest "dump named queries"\r
++notmuch dump | grep '^#@' > OUTPUT\r
++cat<<EOF > QUERIES.BEFORE\r
++#@ query.test date%3a2009-11-18..2009-11-18%20and%20tag%3aunread\r
++#@ query.test2 query%3atest%20and%20subject%3aMaildir\r
++EOF\r
++test_expect_equal_file QUERIES.BEFORE OUTPUT\r
++\r
++test_begin_subtest "delete named queries"\r
++notmuch dump > BEFORE\r
++notmuch config set query.test\r
++notmuch dump | grep '^#@' > OUTPUT\r
++cat<<EOF > EXPECTED\r
++#@ query.test2 query%3atest%20and%20subject%3aMaildir\r
++EOF\r
++test_expect_equal_file EXPECTED OUTPUT\r
++\r
++test_begin_subtest "restore named queries"\r
++notmuch restore < BEFORE\r
++notmuch dump | grep '^#@' > OUTPUT\r
++test_expect_equal_file QUERIES.BEFORE OUTPUT\r
++\r
++test_done\r
+diff --git a/test/test-lib.sh b/test/test-lib.sh\r
+index 98abbe2..00df2bd 100644\r
+--- a/test/test-lib.sh\r
++++ b/test/test-lib.sh\r
+@@ -745,6 +745,11 @@ notmuch_options_sanitize ()\r
+ sed 's/^options[.]\(.*\)=.*$/options.\1=something/'\r
+ }\r
+ \r
++notmuch_config_sanitize ()\r
++{\r
++ notmuch_dir_sanitize | notmuch_options_sanitize\r
++}\r
++\r
+ # End of notmuch helper functions\r
+ \r
+ # Use test_set_prereq to tell that a particular prerequisite is available.\r
+-- \r
+2.7.0\r
+\r