--- /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 B6FA16DE0937\r
+ for <notmuch@notmuchmail.org>; Sat, 30 Apr 2016 18:25:11 -0700 (PDT)\r
+X-Virus-Scanned: Debian amavisd-new at cworth.org\r
+X-Spam-Flag: NO\r
+X-Spam-Score: -0.015\r
+X-Spam-Level: \r
+X-Spam-Status: No, score=-0.015 tagged_above=-999 required=5\r
+ tests=[AWL=-0.004, 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 2G0XnXeF02tE for <notmuch@notmuchmail.org>;\r
+ Sat, 30 Apr 2016 18:25:04 -0700 (PDT)\r
+Received: from fethera.tethera.net (fethera.tethera.net [198.245.60.197])\r
+ by arlo.cworth.org (Postfix) with ESMTPS id EFEDE6DE0356\r
+ for <notmuch@notmuchmail.org>; Sat, 30 Apr 2016 18:24:49 -0700 (PDT)\r
+Received: from remotemail by fethera.tethera.net with local (Exim 4.84)\r
+ (envelope-from <bremner@tethera.net>)\r
+ id 1awg7o-0006bu-Tj; Sat, 30 Apr 2016 21:24:45 -0400\r
+Received: (nullmailer pid 29957 invoked by uid 1000);\r
+ Sun, 01 May 2016 01:24:43 -0000\r
+From: David Bremner <david@tethera.net>\r
+To: notmuch@notmuchmail.org\r
+Subject: [Patch v3 09/11] CLI: add notmuch-config support for named queries\r
+Date: Sat, 30 Apr 2016 22:24:37 -0300\r
+Message-Id: <1462065879-29860-10-git-send-email-david@tethera.net>\r
+X-Mailer: git-send-email 2.8.0.rc3\r
+In-Reply-To: <1462065879-29860-1-git-send-email-david@tethera.net>\r
+References: <1462065879-29860-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: Sun, 01 May 2016 01:25:11 -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 | 6 ++++\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, 159 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 26a8eb1..5a517eb 100644\r
+--- a/doc/man1/notmuch-config.rst\r
++++ b/doc/man1/notmuch-config.rst\r
+@@ -138,6 +138,12 @@ The available configuration items are described below.\r
+ "compact" (see **notmuch-compact(1)**)\r
+ and "field_processor" (see **notmuch-search-terms(7)**).\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
+ \r
+diff --git a/notmuch-config.c b/notmuch-config.c\r
+index 97a46fa..e4f47e4 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 BUILT_WITH_PREFIX "built_with."\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, BUILT_WITH_PREFIX) == 0) {\r
+ printf ("%s\n",\r
+ notmuch_built_with (item + strlen (BUILT_WITH_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
+@@ -852,6 +913,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
+@@ -887,7 +973,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 022f2cf..91b3693 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 a4e24c3..b8d5a86 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
+ built_with.compact=something\r
+-built_with.field_processor=something"\r
++built_with.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 68a8774..e96c184 100644\r
+--- a/test/test-lib.sh\r
++++ b/test/test-lib.sh\r
+@@ -745,6 +745,11 @@ notmuch_built_with_sanitize ()\r
+ sed 's/^built_with[.]\(.*\)=.*$/built_with.\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.8.0.rc3\r
+\r