* [PATCH 1/6] test: use keys with group 'test' in T590-libconfig
2020-08-12 22:49 David Bremner
@ 2020-08-12 22:49 ` David Bremner
0 siblings, 0 replies; 11+ messages in thread
From: David Bremner @ 2020-08-12 22:49 UTC (permalink / raw)
To: notmuch; +Cc: David Bremner
In a future commit we want to interoperate better with glib KeyFiles,
which need groups for all keys.
---
test/T590-libconfig.sh | 36 ++++++++++++++++++------------------
1 file changed, 18 insertions(+), 18 deletions(-)
diff --git a/test/T590-libconfig.sh b/test/T590-libconfig.sh
index 360e45b0..8c34acf9 100755
--- a/test/T590-libconfig.sh
+++ b/test/T590-libconfig.sh
@@ -28,18 +28,18 @@ EOF
test_begin_subtest "notmuch_database_{set,get}_config"
cat c_head - c_tail <<'EOF' | test_C ${MAIL_DIR}
{
- EXPECT0(notmuch_database_set_config (db, "testkey1", "testvalue1"));
- EXPECT0(notmuch_database_set_config (db, "testkey2", "testvalue2"));
- EXPECT0(notmuch_database_get_config (db, "testkey1", &val));
- printf("testkey1 = %s\n", val);
- EXPECT0(notmuch_database_get_config (db, "testkey2", &val));
- printf("testkey2 = %s\n", val);
+ EXPECT0(notmuch_database_set_config (db, "test.key1", "testvalue1"));
+ EXPECT0(notmuch_database_set_config (db, "test.key2", "testvalue2"));
+ EXPECT0(notmuch_database_get_config (db, "test.key1", &val));
+ printf("test.key1 = %s\n", val);
+ EXPECT0(notmuch_database_get_config (db, "test.key2", &val));
+ printf("test.key2 = %s\n", val);
}
EOF
cat <<'EOF' >EXPECTED
== stdout ==
-testkey1 = testvalue1
-testkey2 = testvalue2
+test.key1 = testvalue1
+test.key2 = testvalue2
== stderr ==
EOF
test_expect_equal_file EXPECTED OUTPUT
@@ -93,8 +93,8 @@ EOF
cat <<'EOF' >EXPECTED
== stdout ==
aaabefore beforeval
-testkey1 testvalue1
-testkey2 testvalue2
+test.key1 testvalue1
+test.key2 testvalue2
zzzafter afterval
== stderr ==
EOF
@@ -115,8 +115,8 @@ EOF
cat <<'EOF' >EXPECTED
== stdout ==
aaabefore 1
-testkey1 1
-testkey2 1
+test.key1 1
+test.key2 1
zzzafter 1
== stderr ==
EOF
@@ -126,7 +126,7 @@ test_begin_subtest "notmuch_database_get_config_list: one prefix"
cat c_head - c_tail <<'EOF' | test_C ${MAIL_DIR}
{
notmuch_config_list_t *list;
- EXPECT0(notmuch_database_get_config_list (db, "testkey", &list));
+ EXPECT0(notmuch_database_get_config_list (db, "test.key", &list));
for (; notmuch_config_list_valid (list); notmuch_config_list_move_to_next (list)) {
printf("%s %s\n", notmuch_config_list_key (list), notmuch_config_list_value(list));
}
@@ -135,8 +135,8 @@ cat c_head - c_tail <<'EOF' | test_C ${MAIL_DIR}
EOF
cat <<'EOF' >EXPECTED
== stdout ==
-testkey1 testvalue1
-testkey2 testvalue2
+test.key1 testvalue1
+test.key2 testvalue2
== stderr ==
EOF
test_expect_equal_file EXPECTED OUTPUT
@@ -152,8 +152,8 @@ cat <<'EOF' >EXPECTED
#notmuch-dump batch-tag:3 config
#@ aaabefore beforeval
#@ key%20with%20spaces value,%20with,%20spaces%21
-#@ testkey1 testvalue1
-#@ testkey2 testvalue2
+#@ test.key1 testvalue1
+#@ test.key2 testvalue2
#@ zzzafter afterval
EOF
test_expect_equal_file EXPECTED OUTPUT
@@ -162,7 +162,7 @@ test_begin_subtest "restore config"
notmuch dump --include=config >EXPECTED
cat c_head - c_tail <<'EOF' | test_C ${MAIL_DIR}
{
- EXPECT0(notmuch_database_set_config (db, "testkey1", "mutatedvalue"));
+ EXPECT0(notmuch_database_set_config (db, "test.key1", "mutatedvalue"));
}
EOF
notmuch restore --include=config <EXPECTED
--
2.28.0
^ permalink raw reply related [flat|nested] 11+ messages in thread
* v2 preliminaries for merged config
@ 2020-12-20 12:10 David Bremner
2020-12-20 12:10 ` [PATCH 1/6] test: use keys with group 'test' in T590-libconfig David Bremner
` (6 more replies)
0 siblings, 7 replies; 11+ messages in thread
From: David Bremner @ 2020-12-20 12:10 UTC (permalink / raw)
To: notmuch
This is a respin of id:20200812224931.3611801-1-david@tethera.net,
rebased against master and with one typo in a commit message
fixed.
I'm going to mark these as ready to merge since they are primarily
code movement, and recieved no feedback in the previous 4 months.
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 1/6] test: use keys with group 'test' in T590-libconfig
2020-12-20 12:10 v2 preliminaries for merged config David Bremner
@ 2020-12-20 12:10 ` David Bremner
2020-12-20 12:10 ` [PATCH 2/6] lib: factor out feature name related code David Bremner
` (5 subsequent siblings)
6 siblings, 0 replies; 11+ messages in thread
From: David Bremner @ 2020-12-20 12:10 UTC (permalink / raw)
To: notmuch; +Cc: David Bremner
In a future commit we want to interoperate better with glib KeyFiles,
which need groups for all keys.
---
test/T590-libconfig.sh | 36 ++++++++++++++++++------------------
1 file changed, 18 insertions(+), 18 deletions(-)
diff --git a/test/T590-libconfig.sh b/test/T590-libconfig.sh
index 360e45b0..8c34acf9 100755
--- a/test/T590-libconfig.sh
+++ b/test/T590-libconfig.sh
@@ -28,18 +28,18 @@ EOF
test_begin_subtest "notmuch_database_{set,get}_config"
cat c_head - c_tail <<'EOF' | test_C ${MAIL_DIR}
{
- EXPECT0(notmuch_database_set_config (db, "testkey1", "testvalue1"));
- EXPECT0(notmuch_database_set_config (db, "testkey2", "testvalue2"));
- EXPECT0(notmuch_database_get_config (db, "testkey1", &val));
- printf("testkey1 = %s\n", val);
- EXPECT0(notmuch_database_get_config (db, "testkey2", &val));
- printf("testkey2 = %s\n", val);
+ EXPECT0(notmuch_database_set_config (db, "test.key1", "testvalue1"));
+ EXPECT0(notmuch_database_set_config (db, "test.key2", "testvalue2"));
+ EXPECT0(notmuch_database_get_config (db, "test.key1", &val));
+ printf("test.key1 = %s\n", val);
+ EXPECT0(notmuch_database_get_config (db, "test.key2", &val));
+ printf("test.key2 = %s\n", val);
}
EOF
cat <<'EOF' >EXPECTED
== stdout ==
-testkey1 = testvalue1
-testkey2 = testvalue2
+test.key1 = testvalue1
+test.key2 = testvalue2
== stderr ==
EOF
test_expect_equal_file EXPECTED OUTPUT
@@ -93,8 +93,8 @@ EOF
cat <<'EOF' >EXPECTED
== stdout ==
aaabefore beforeval
-testkey1 testvalue1
-testkey2 testvalue2
+test.key1 testvalue1
+test.key2 testvalue2
zzzafter afterval
== stderr ==
EOF
@@ -115,8 +115,8 @@ EOF
cat <<'EOF' >EXPECTED
== stdout ==
aaabefore 1
-testkey1 1
-testkey2 1
+test.key1 1
+test.key2 1
zzzafter 1
== stderr ==
EOF
@@ -126,7 +126,7 @@ test_begin_subtest "notmuch_database_get_config_list: one prefix"
cat c_head - c_tail <<'EOF' | test_C ${MAIL_DIR}
{
notmuch_config_list_t *list;
- EXPECT0(notmuch_database_get_config_list (db, "testkey", &list));
+ EXPECT0(notmuch_database_get_config_list (db, "test.key", &list));
for (; notmuch_config_list_valid (list); notmuch_config_list_move_to_next (list)) {
printf("%s %s\n", notmuch_config_list_key (list), notmuch_config_list_value(list));
}
@@ -135,8 +135,8 @@ cat c_head - c_tail <<'EOF' | test_C ${MAIL_DIR}
EOF
cat <<'EOF' >EXPECTED
== stdout ==
-testkey1 testvalue1
-testkey2 testvalue2
+test.key1 testvalue1
+test.key2 testvalue2
== stderr ==
EOF
test_expect_equal_file EXPECTED OUTPUT
@@ -152,8 +152,8 @@ cat <<'EOF' >EXPECTED
#notmuch-dump batch-tag:3 config
#@ aaabefore beforeval
#@ key%20with%20spaces value,%20with,%20spaces%21
-#@ testkey1 testvalue1
-#@ testkey2 testvalue2
+#@ test.key1 testvalue1
+#@ test.key2 testvalue2
#@ zzzafter afterval
EOF
test_expect_equal_file EXPECTED OUTPUT
@@ -162,7 +162,7 @@ test_begin_subtest "restore config"
notmuch dump --include=config >EXPECTED
cat c_head - c_tail <<'EOF' | test_C ${MAIL_DIR}
{
- EXPECT0(notmuch_database_set_config (db, "testkey1", "mutatedvalue"));
+ EXPECT0(notmuch_database_set_config (db, "test.key1", "mutatedvalue"));
}
EOF
notmuch restore --include=config <EXPECTED
--
2.29.2
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 2/6] lib: factor out feature name related code.
2020-12-20 12:10 v2 preliminaries for merged config David Bremner
2020-12-20 12:10 ` [PATCH 1/6] test: use keys with group 'test' in T590-libconfig David Bremner
@ 2020-12-20 12:10 ` David Bremner
2020-12-20 12:10 ` [PATCH 3/6] lib: factor out prefix related code to its own file David Bremner
` (4 subsequent siblings)
6 siblings, 0 replies; 11+ messages in thread
From: David Bremner @ 2020-12-20 12:10 UTC (permalink / raw)
To: notmuch; +Cc: David Bremner
database.cc is uncomfortably large, and some of the static data
structures do not need to be shared as much as they are.
This is a somewhat small piece to factor out, but it will turn out to
be helpful to further refactoring.
---
lib/Makefile.local | 3 +-
lib/database-private.h | 14 +++++
lib/database.cc | 116 +----------------------------------------
lib/features.cc | 114 ++++++++++++++++++++++++++++++++++++++++
4 files changed, 131 insertions(+), 116 deletions(-)
create mode 100644 lib/features.cc
diff --git a/lib/Makefile.local b/lib/Makefile.local
index a6400126..04418fa8 100644
--- a/lib/Makefile.local
+++ b/lib/Makefile.local
@@ -59,7 +59,8 @@ libnotmuch_cxx_srcs = \
$(dir)/config.cc \
$(dir)/regexp-fields.cc \
$(dir)/thread.cc \
- $(dir)/thread-fp.cc
+ $(dir)/thread-fp.cc \
+ $(dir)/features.cc
libnotmuch_modules := $(libnotmuch_c_srcs:.c=.o) $(libnotmuch_cxx_srcs:.cc=.o)
diff --git a/lib/database-private.h b/lib/database-private.h
index 041602cd..2d220811 100644
--- a/lib/database-private.h
+++ b/lib/database-private.h
@@ -32,6 +32,8 @@
#include "notmuch-private.h"
+#define ARRAY_SIZE(arr) (sizeof (arr) / sizeof (arr[0]))
+
#ifdef SILENCE_XAPIAN_DEPRECATION_WARNINGS
#define XAPIAN_DEPRECATED(D) D
#endif
@@ -263,4 +265,16 @@ _notmuch_database_find_doc_ids (notmuch_database_t *notmuch,
const char *value,
Xapian::PostingIterator *begin,
Xapian::PostingIterator *end);
+
+#define NOTMUCH_DATABASE_VERSION 3
+
+/* features.cc */
+
+_notmuch_features
+_notmuch_database_parse_features (const void *ctx, const char *features, unsigned int version,
+ char mode, char **incompat_out);
+
+char *
+_notmuch_database_print_features (const void *ctx, unsigned int features);
+
#endif
diff --git a/lib/database.cc b/lib/database.cc
index 75189685..4a477bd7 100644
--- a/lib/database.cc
+++ b/lib/database.cc
@@ -39,8 +39,6 @@
using namespace std;
-#define ARRAY_SIZE(arr) (sizeof (arr) / sizeof (arr[0]))
-
typedef struct {
const char *name;
const char *prefix;
@@ -458,41 +456,6 @@ _notmuch_database_prefix (notmuch_database_t *notmuch, const char *name)
return NULL;
}
-static const struct {
- /* NOTMUCH_FEATURE_* value. */
- _notmuch_features value;
- /* Feature name as it appears in the database. This name should
- * be appropriate for displaying to the user if an older version
- * of notmuch doesn't support this feature. */
- const char *name;
- /* Compatibility flags when this feature is declared. */
- const char *flags;
-} feature_names[] = {
- { NOTMUCH_FEATURE_FILE_TERMS,
- "multiple paths per message", "rw" },
- { NOTMUCH_FEATURE_DIRECTORY_DOCS,
- "relative directory paths", "rw" },
- /* Header values are not required for reading a database because a
- * reader can just refer to the message file. */
- { NOTMUCH_FEATURE_FROM_SUBJECT_ID_VALUES,
- "from/subject/message-ID in database", "w" },
- { NOTMUCH_FEATURE_BOOL_FOLDER,
- "exact folder:/path: search", "rw" },
- { NOTMUCH_FEATURE_GHOSTS,
- "mail documents for missing messages", "w" },
- /* Knowledge of the index mime-types are not required for reading
- * a database because a reader will just be unable to query
- * them. */
- { NOTMUCH_FEATURE_INDEXED_MIMETYPES,
- "indexed MIME types", "w" },
- { NOTMUCH_FEATURE_LAST_MOD,
- "modification tracking", "w" },
- /* Existing databases will work fine for all queries not involving
- * 'body:' */
- { NOTMUCH_FEATURE_UNPREFIX_BODY_ONLY,
- "index body and headers separately", "w" },
-};
-
const char *
notmuch_status_to_string (notmuch_status_t status)
{
@@ -817,83 +780,6 @@ _notmuch_database_new_revision (notmuch_database_t *notmuch)
return new_revision;
}
-/* Parse a database features string from the given database version.
- * Returns the feature bit set.
- *
- * For version < 3, this ignores the features string and returns a
- * hard-coded set of features.
- *
- * If there are unrecognized features that are required to open the
- * database in mode (which should be 'r' or 'w'), return a
- * comma-separated list of unrecognized but required features in
- * *incompat_out suitable for presenting to the user. *incompat_out
- * will be allocated from ctx.
- */
-static _notmuch_features
-_parse_features (const void *ctx, const char *features, unsigned int version,
- char mode, char **incompat_out)
-{
- _notmuch_features res = static_cast<_notmuch_features>(0);
- unsigned int namelen, i;
- size_t llen = 0;
- const char *flags;
-
- /* Prior to database version 3, features were implied by the
- * version number. */
- if (version == 0)
- return NOTMUCH_FEATURES_V0;
- else if (version == 1)
- return NOTMUCH_FEATURES_V1;
- else if (version == 2)
- return NOTMUCH_FEATURES_V2;
-
- /* Parse the features string */
- while ((features = strtok_len_c (features + llen, "\n", &llen)) != NULL) {
- flags = strchr (features, '\t');
- if (! flags || flags > features + llen)
- continue;
- namelen = flags - features;
-
- for (i = 0; i < ARRAY_SIZE (feature_names); ++i) {
- if (strlen (feature_names[i].name) == namelen &&
- strncmp (feature_names[i].name, features, namelen) == 0) {
- res |= feature_names[i].value;
- break;
- }
- }
-
- if (i == ARRAY_SIZE (feature_names) && incompat_out) {
- /* Unrecognized feature */
- const char *have = strchr (flags, mode);
- if (have && have < features + llen) {
- /* This feature is required to access this database in
- * 'mode', but we don't understand it. */
- if (! *incompat_out)
- *incompat_out = talloc_strdup (ctx, "");
- *incompat_out = talloc_asprintf_append_buffer (
- *incompat_out, "%s%.*s", **incompat_out ? ", " : "",
- namelen, features);
- }
- }
- }
-
- return res;
-}
-
-static char *
-_print_features (const void *ctx, unsigned int features)
-{
- unsigned int i;
- char *res = talloc_strdup (ctx, "");
-
- for (i = 0; i < ARRAY_SIZE (feature_names); ++i)
- if (features & feature_names[i].value)
- res = talloc_asprintf_append_buffer (
- res, "%s\t%s\n", feature_names[i].name, feature_names[i].flags);
-
- return res;
-}
-
notmuch_status_t
notmuch_database_open (const char *path,
notmuch_database_mode_t mode,
@@ -1674,7 +1560,7 @@ notmuch_database_upgrade (notmuch_database_t *notmuch,
}
status = NOTMUCH_STATUS_SUCCESS;
- db->set_metadata ("features", _print_features (local, notmuch->features));
+ db->set_metadata ("features", _notmuch_database_print_features (local, notmuch->features));
db->set_metadata ("version", STRINGIFY (NOTMUCH_DATABASE_VERSION));
DONE:
diff --git a/lib/features.cc b/lib/features.cc
new file mode 100644
index 00000000..8def2461
--- /dev/null
+++ b/lib/features.cc
@@ -0,0 +1,114 @@
+#include "database-private.h"
+
+static const struct {
+ /* NOTMUCH_FEATURE_* value. */
+ _notmuch_features value;
+ /* Feature name as it appears in the database. This name should
+ * be appropriate for displaying to the user if an older version
+ * of notmuch doesn't support this feature. */
+ const char *name;
+ /* Compatibility flags when this feature is declared. */
+ const char *flags;
+} feature_names[] = {
+ { NOTMUCH_FEATURE_FILE_TERMS,
+ "multiple paths per message", "rw" },
+ { NOTMUCH_FEATURE_DIRECTORY_DOCS,
+ "relative directory paths", "rw" },
+ /* Header values are not required for reading a database because a
+ * reader can just refer to the message file. */
+ { NOTMUCH_FEATURE_FROM_SUBJECT_ID_VALUES,
+ "from/subject/message-ID in database", "w" },
+ { NOTMUCH_FEATURE_BOOL_FOLDER,
+ "exact folder:/path: search", "rw" },
+ { NOTMUCH_FEATURE_GHOSTS,
+ "mail documents for missing messages", "w" },
+ /* Knowledge of the index mime-types are not required for reading
+ * a database because a reader will just be unable to query
+ * them. */
+ { NOTMUCH_FEATURE_INDEXED_MIMETYPES,
+ "indexed MIME types", "w" },
+ { NOTMUCH_FEATURE_LAST_MOD,
+ "modification tracking", "w" },
+ /* Existing databases will work fine for all queries not involving
+ * 'body:' */
+ { NOTMUCH_FEATURE_UNPREFIX_BODY_ONLY,
+ "index body and headers separately", "w" },
+};
+
+char *
+_notmuch_database_print_features (const void *ctx, unsigned int features)
+{
+ unsigned int i;
+ char *res = talloc_strdup (ctx, "");
+
+ for (i = 0; i < ARRAY_SIZE (feature_names); ++i)
+ if (features & feature_names[i].value)
+ res = talloc_asprintf_append_buffer (
+ res, "%s\t%s\n", feature_names[i].name, feature_names[i].flags);
+
+ return res;
+}
+
+
+/* Parse a database features string from the given database version.
+ * Returns the feature bit set.
+ *
+ * For version < 3, this ignores the features string and returns a
+ * hard-coded set of features.
+ *
+ * If there are unrecognized features that are required to open the
+ * database in mode (which should be 'r' or 'w'), return a
+ * comma-separated list of unrecognized but required features in
+ * *incompat_out suitable for presenting to the user. *incompat_out
+ * will be allocated from ctx.
+ */
+_notmuch_features
+_notmuch_database_parse_features (const void *ctx, const char *features, unsigned int version,
+ char mode, char **incompat_out)
+{
+ _notmuch_features res = static_cast<_notmuch_features>(0);
+ unsigned int namelen, i;
+ size_t llen = 0;
+ const char *flags;
+
+ /* Prior to database version 3, features were implied by the
+ * version number. */
+ if (version == 0)
+ return NOTMUCH_FEATURES_V0;
+ else if (version == 1)
+ return NOTMUCH_FEATURES_V1;
+ else if (version == 2)
+ return NOTMUCH_FEATURES_V2;
+
+ /* Parse the features string */
+ while ((features = strtok_len_c (features + llen, "\n", &llen)) != NULL) {
+ flags = strchr (features, '\t');
+ if (! flags || flags > features + llen)
+ continue;
+ namelen = flags - features;
+
+ for (i = 0; i < ARRAY_SIZE (feature_names); ++i) {
+ if (strlen (feature_names[i].name) == namelen &&
+ strncmp (feature_names[i].name, features, namelen) == 0) {
+ res |= feature_names[i].value;
+ break;
+ }
+ }
+
+ if (i == ARRAY_SIZE (feature_names) && incompat_out) {
+ /* Unrecognized feature */
+ const char *have = strchr (flags, mode);
+ if (have && have < features + llen) {
+ /* This feature is required to access this database in
+ * 'mode', but we don't understand it. */
+ if (! *incompat_out)
+ *incompat_out = talloc_strdup (ctx, "");
+ *incompat_out = talloc_asprintf_append_buffer (
+ *incompat_out, "%s%.*s", **incompat_out ? ", " : "",
+ namelen, features);
+ }
+ }
+ }
+
+ return res;
+}
--
2.29.2
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 3/6] lib: factor out prefix related code to its own file
2020-12-20 12:10 v2 preliminaries for merged config David Bremner
2020-12-20 12:10 ` [PATCH 1/6] test: use keys with group 'test' in T590-libconfig David Bremner
2020-12-20 12:10 ` [PATCH 2/6] lib: factor out feature name related code David Bremner
@ 2020-12-20 12:10 ` David Bremner
2020-12-20 15:36 ` Tomi Ollila
2020-12-20 12:10 ` [PATCH 4/6] lib/config: delay setting talloc destructor David Bremner
` (3 subsequent siblings)
6 siblings, 1 reply; 11+ messages in thread
From: David Bremner @ 2020-12-20 12:10 UTC (permalink / raw)
To: notmuch; +Cc: David Bremner
Reduce the size of database.cc, and limit the scope of prefix_table,
make sure it's accessed via a well-defined internal API.
---
lib/Makefile.local | 4 +-
lib/database-private.h | 7 ++
lib/database.cc | 203 ++-------------------------------------
lib/prefix.cc | 210 +++++++++++++++++++++++++++++++++++++++++
4 files changed, 229 insertions(+), 195 deletions(-)
create mode 100644 lib/prefix.cc
diff --git a/lib/Makefile.local b/lib/Makefile.local
index 04418fa8..3aa9e80f 100644
--- a/lib/Makefile.local
+++ b/lib/Makefile.local
@@ -60,7 +60,9 @@ libnotmuch_cxx_srcs = \
$(dir)/regexp-fields.cc \
$(dir)/thread.cc \
$(dir)/thread-fp.cc \
- $(dir)/features.cc
+ $(dir)/features.cc \
+ $(dir)/prefix.cc
+
libnotmuch_modules := $(libnotmuch_c_srcs:.c=.o) $(libnotmuch_cxx_srcs:.cc=.o)
diff --git a/lib/database-private.h b/lib/database-private.h
index 2d220811..c9bc712b 100644
--- a/lib/database-private.h
+++ b/lib/database-private.h
@@ -277,4 +277,11 @@ _notmuch_database_parse_features (const void *ctx, const char *features, unsigne
char *
_notmuch_database_print_features (const void *ctx, unsigned int features);
+/* prefix.cc */
+notmuch_status_t
+_notmuch_database_setup_standard_query_fields (notmuch_database_t *notmuch);
+
+notmuch_status_t
+_notmuch_database_setup_user_query_fields (notmuch_database_t *notmuch);
+
#endif
diff --git a/lib/database.cc b/lib/database.cc
index 4a477bd7..defa3062 100644
--- a/lib/database.cc
+++ b/lib/database.cc
@@ -263,80 +263,6 @@ _notmuch_database_mode (notmuch_database_t *notmuch)
* same thread.
*/
-/* With these prefix values we follow the conventions published here:
- *
- * https://xapian.org/docs/omega/termprefixes.html
- *
- * as much as makes sense. Note that I took some liberty in matching
- * the reserved prefix values to notmuch concepts, (for example, 'G'
- * is documented as "newsGroup (or similar entity - e.g. a web forum
- * name)", for which I think the thread is the closest analogue in
- * notmuch. This in spite of the fact that we will eventually be
- * storing mailing-list messages where 'G' for "mailing list name"
- * might be even a closer analogue. I'm treating the single-character
- * prefixes preferentially for core notmuch concepts (which will be
- * nearly universal to all mail messages).
- */
-
-static const
-prefix_t prefix_table[] = {
- /* name term prefix flags */
- { "type", "T", NOTMUCH_FIELD_NO_FLAGS },
- { "reference", "XREFERENCE", NOTMUCH_FIELD_NO_FLAGS },
- { "replyto", "XREPLYTO", NOTMUCH_FIELD_NO_FLAGS },
- { "directory", "XDIRECTORY", NOTMUCH_FIELD_NO_FLAGS },
- { "file-direntry", "XFDIRENTRY", NOTMUCH_FIELD_NO_FLAGS },
- { "directory-direntry", "XDDIRENTRY", NOTMUCH_FIELD_NO_FLAGS },
- { "body", "", NOTMUCH_FIELD_EXTERNAL |
- NOTMUCH_FIELD_PROBABILISTIC },
- { "thread", "G", NOTMUCH_FIELD_EXTERNAL |
- NOTMUCH_FIELD_PROCESSOR },
- { "tag", "K", NOTMUCH_FIELD_EXTERNAL |
- NOTMUCH_FIELD_PROCESSOR },
- { "is", "K", NOTMUCH_FIELD_EXTERNAL |
- NOTMUCH_FIELD_PROCESSOR },
- { "id", "Q", NOTMUCH_FIELD_EXTERNAL },
- { "mid", "Q", NOTMUCH_FIELD_EXTERNAL |
- NOTMUCH_FIELD_PROCESSOR },
- { "path", "P", NOTMUCH_FIELD_EXTERNAL |
- NOTMUCH_FIELD_PROCESSOR },
- { "property", "XPROPERTY", NOTMUCH_FIELD_EXTERNAL },
- /*
- * Unconditionally add ':' to reduce potential ambiguity with
- * overlapping prefixes and/or terms that start with capital
- * letters. See Xapian document termprefixes.html for related
- * discussion.
- */
- { "folder", "XFOLDER:", NOTMUCH_FIELD_EXTERNAL |
- NOTMUCH_FIELD_PROCESSOR },
- { "date", NULL, NOTMUCH_FIELD_EXTERNAL |
- NOTMUCH_FIELD_PROCESSOR },
- { "query", NULL, NOTMUCH_FIELD_EXTERNAL |
- NOTMUCH_FIELD_PROCESSOR },
- { "from", "XFROM", NOTMUCH_FIELD_EXTERNAL |
- NOTMUCH_FIELD_PROBABILISTIC |
- NOTMUCH_FIELD_PROCESSOR },
- { "to", "XTO", NOTMUCH_FIELD_EXTERNAL |
- NOTMUCH_FIELD_PROBABILISTIC },
- { "attachment", "XATTACHMENT", NOTMUCH_FIELD_EXTERNAL |
- NOTMUCH_FIELD_PROBABILISTIC },
- { "mimetype", "XMIMETYPE", NOTMUCH_FIELD_EXTERNAL |
- NOTMUCH_FIELD_PROBABILISTIC },
- { "subject", "XSUBJECT", NOTMUCH_FIELD_EXTERNAL |
- NOTMUCH_FIELD_PROBABILISTIC |
- NOTMUCH_FIELD_PROCESSOR },
-};
-
-static void
-_setup_query_field_default (const prefix_t *prefix, notmuch_database_t *notmuch)
-{
- if (prefix->prefix)
- notmuch->query_parser->add_prefix ("", prefix->prefix);
- if (prefix->flags & NOTMUCH_FIELD_PROBABILISTIC)
- notmuch->query_parser->add_prefix (prefix->name, prefix->prefix);
- else
- notmuch->query_parser->add_boolean_prefix (prefix->name, prefix->prefix);
-}
notmuch_string_map_iterator_t *
_notmuch_database_user_headers (notmuch_database_t *notmuch)
@@ -344,118 +270,6 @@ _notmuch_database_user_headers (notmuch_database_t *notmuch)
return _notmuch_string_map_iterator_create (notmuch->user_header, "", false);
}
-const char *
-_user_prefix (void *ctx, const char *name)
-{
- return talloc_asprintf (ctx, "XU%s:", name);
-}
-
-static notmuch_status_t
-_setup_user_query_fields (notmuch_database_t *notmuch)
-{
- notmuch_config_list_t *list;
- notmuch_status_t status;
-
- notmuch->user_prefix = _notmuch_string_map_create (notmuch);
- if (notmuch->user_prefix == NULL)
- return NOTMUCH_STATUS_OUT_OF_MEMORY;
-
- notmuch->user_header = _notmuch_string_map_create (notmuch);
- if (notmuch->user_header == NULL)
- return NOTMUCH_STATUS_OUT_OF_MEMORY;
-
- status = notmuch_database_get_config_list (notmuch, CONFIG_HEADER_PREFIX, &list);
- if (status)
- return status;
-
- for (; notmuch_config_list_valid (list); notmuch_config_list_move_to_next (list)) {
-
- prefix_t query_field;
-
- const char *key = notmuch_config_list_key (list)
- + sizeof (CONFIG_HEADER_PREFIX) - 1;
-
- _notmuch_string_map_append (notmuch->user_prefix,
- key,
- _user_prefix (notmuch, key));
-
- _notmuch_string_map_append (notmuch->user_header,
- key,
- notmuch_config_list_value (list));
-
- query_field.name = talloc_strdup (notmuch, key);
- query_field.prefix = _user_prefix (notmuch, key);
- query_field.flags = NOTMUCH_FIELD_PROBABILISTIC
- | NOTMUCH_FIELD_EXTERNAL;
-
- _setup_query_field_default (&query_field, notmuch);
- }
-
- notmuch_config_list_destroy (list);
-
- return NOTMUCH_STATUS_SUCCESS;
-}
-
-static void
-_setup_query_field (const prefix_t *prefix, notmuch_database_t *notmuch)
-{
- if (prefix->flags & NOTMUCH_FIELD_PROCESSOR) {
- Xapian::FieldProcessor *fp;
-
- if (STRNCMP_LITERAL (prefix->name, "date") == 0)
- fp = (new DateFieldProcessor(NOTMUCH_VALUE_TIMESTAMP))->release ();
- else if (STRNCMP_LITERAL(prefix->name, "query") == 0)
- fp = (new QueryFieldProcessor (*notmuch->query_parser, notmuch))->release ();
- else if (STRNCMP_LITERAL (prefix->name, "thread") == 0)
- fp = (new ThreadFieldProcessor (*notmuch->query_parser, notmuch))->release ();
- else
- fp = (new RegexpFieldProcessor (prefix->name, prefix->flags,
- *notmuch->query_parser, notmuch))->release ();
-
- /* we treat all field-processor fields as boolean in order to get the raw input */
- if (prefix->prefix)
- notmuch->query_parser->add_prefix ("", prefix->prefix);
- notmuch->query_parser->add_boolean_prefix (prefix->name, fp);
- } else {
- _setup_query_field_default (prefix, notmuch);
- }
-}
-
-const char *
-_find_prefix (const char *name)
-{
- unsigned int i;
-
- for (i = 0; i < ARRAY_SIZE (prefix_table); i++) {
- if (strcmp (name, prefix_table[i].name) == 0)
- return prefix_table[i].prefix;
- }
-
- INTERNAL_ERROR ("No prefix exists for '%s'\n", name);
-
- return "";
-}
-
-/* Like find prefix, but include the possibility of user defined
- * prefixes specific to this database */
-
-const char *
-_notmuch_database_prefix (notmuch_database_t *notmuch, const char *name)
-{
- unsigned int i;
-
- /*XXX TODO: reduce code duplication */
- for (i = 0; i < ARRAY_SIZE (prefix_table); i++) {
- if (strcmp (name, prefix_table[i].name) == 0)
- return prefix_table[i].prefix;
- }
-
- if (notmuch->user_prefix)
- return _notmuch_string_map_get (notmuch->user_prefix, name);
-
- return NULL;
-}
-
const char *
notmuch_status_to_string (notmuch_status_t status)
{
@@ -898,7 +712,7 @@ notmuch_database_open_verbose (const char *path,
/* Check features. */
incompat_features = NULL;
- notmuch->features = _parse_features (
+ notmuch->features = _notmuch_database_parse_features (
local, notmuch->xapian_db->get_metadata ("features").c_str (),
version, mode == NOTMUCH_DATABASE_MODE_READ_WRITE ? 'w' : 'r',
&incompat_features);
@@ -952,13 +766,14 @@ notmuch_database_open_verbose (const char *path,
notmuch->query_parser->add_rangeprocessor (notmuch->date_range_processor);
notmuch->query_parser->add_rangeprocessor (notmuch->last_mod_range_processor);
- for (i = 0; i < ARRAY_SIZE (prefix_table); i++) {
- const prefix_t *prefix = &prefix_table[i];
- if (prefix->flags & NOTMUCH_FIELD_EXTERNAL) {
- _setup_query_field (prefix, notmuch);
- }
- }
- status = _setup_user_query_fields (notmuch);
+ status = _notmuch_database_setup_standard_query_fields (notmuch);
+ if (status)
+ goto DONE;
+
+ status = _notmuch_database_setup_user_query_fields (notmuch);
+ if (status)
+ goto DONE;
+
} catch (const Xapian::Error &error) {
IGNORE_RESULT (asprintf (&message, "A Xapian exception occurred opening database: %s\n",
error.get_msg ().c_str ()));
diff --git a/lib/prefix.cc b/lib/prefix.cc
new file mode 100644
index 00000000..dd7b193d
--- /dev/null
+++ b/lib/prefix.cc
@@ -0,0 +1,210 @@
+#include "database-private.h"
+#include "query-fp.h"
+#include "thread-fp.h"
+#include "regexp-fields.h"
+#include "parse-time-vrp.h"
+
+typedef struct {
+ const char *name;
+ const char *prefix;
+ notmuch_field_flag_t flags;
+} prefix_t;
+
+/* With these prefix values we follow the conventions published here:
+ *
+ * https://xapian.org/docs/omega/termprefixes.html
+ *
+ * as much as makes sense. Note that I took some liberty in matching
+ * the reserved prefix values to notmuch concepts, (for example, 'G'
+ * is documented as "newsGroup (or similar entity - e.g. a web forum
+ * name)", for which I think the thread is the closest analogue in
+ * notmuch. This in spite of the fact that we will eventually be
+ * storing mailing-list messages where 'G' for "mailing list name"
+ * might be even a closer analogue. I'm treating the single-character
+ * prefixes preferentially for core notmuch concepts (which will be
+ * nearly universal to all mail messages).
+ */
+
+static const
+prefix_t prefix_table[] = {
+ /* name term prefix flags */
+ { "type", "T", NOTMUCH_FIELD_NO_FLAGS },
+ { "reference", "XREFERENCE", NOTMUCH_FIELD_NO_FLAGS },
+ { "replyto", "XREPLYTO", NOTMUCH_FIELD_NO_FLAGS },
+ { "directory", "XDIRECTORY", NOTMUCH_FIELD_NO_FLAGS },
+ { "file-direntry", "XFDIRENTRY", NOTMUCH_FIELD_NO_FLAGS },
+ { "directory-direntry", "XDDIRENTRY", NOTMUCH_FIELD_NO_FLAGS },
+ { "body", "", NOTMUCH_FIELD_EXTERNAL |
+ NOTMUCH_FIELD_PROBABILISTIC },
+ { "thread", "G", NOTMUCH_FIELD_EXTERNAL |
+ NOTMUCH_FIELD_PROCESSOR },
+ { "tag", "K", NOTMUCH_FIELD_EXTERNAL |
+ NOTMUCH_FIELD_PROCESSOR },
+ { "is", "K", NOTMUCH_FIELD_EXTERNAL |
+ NOTMUCH_FIELD_PROCESSOR },
+ { "id", "Q", NOTMUCH_FIELD_EXTERNAL },
+ { "mid", "Q", NOTMUCH_FIELD_EXTERNAL |
+ NOTMUCH_FIELD_PROCESSOR },
+ { "path", "P", NOTMUCH_FIELD_EXTERNAL |
+ NOTMUCH_FIELD_PROCESSOR },
+ { "property", "XPROPERTY", NOTMUCH_FIELD_EXTERNAL },
+ /*
+ * Unconditionally add ':' to reduce potential ambiguity with
+ * overlapping prefixes and/or terms that start with capital
+ * letters. See Xapian document termprefixes.html for related
+ * discussion.
+ */
+ { "folder", "XFOLDER:", NOTMUCH_FIELD_EXTERNAL |
+ NOTMUCH_FIELD_PROCESSOR },
+ { "date", NULL, NOTMUCH_FIELD_EXTERNAL |
+ NOTMUCH_FIELD_PROCESSOR },
+ { "query", NULL, NOTMUCH_FIELD_EXTERNAL |
+ NOTMUCH_FIELD_PROCESSOR },
+ { "from", "XFROM", NOTMUCH_FIELD_EXTERNAL |
+ NOTMUCH_FIELD_PROBABILISTIC |
+ NOTMUCH_FIELD_PROCESSOR },
+ { "to", "XTO", NOTMUCH_FIELD_EXTERNAL |
+ NOTMUCH_FIELD_PROBABILISTIC },
+ { "attachment", "XATTACHMENT", NOTMUCH_FIELD_EXTERNAL |
+ NOTMUCH_FIELD_PROBABILISTIC },
+ { "mimetype", "XMIMETYPE", NOTMUCH_FIELD_EXTERNAL |
+ NOTMUCH_FIELD_PROBABILISTIC },
+ { "subject", "XSUBJECT", NOTMUCH_FIELD_EXTERNAL |
+ NOTMUCH_FIELD_PROBABILISTIC |
+ NOTMUCH_FIELD_PROCESSOR },
+};
+
+static const char *
+_user_prefix (void *ctx, const char *name)
+{
+ return talloc_asprintf (ctx, "XU%s:", name);
+}
+
+const char *
+_find_prefix (const char *name)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE (prefix_table); i++) {
+ if (strcmp (name, prefix_table[i].name) == 0)
+ return prefix_table[i].prefix;
+ }
+
+ INTERNAL_ERROR ("No prefix exists for '%s'\n", name);
+
+ return "";
+}
+
+/* Like find prefix, but include the possibility of user defined
+ * prefixes specific to this database */
+
+const char *
+_notmuch_database_prefix (notmuch_database_t *notmuch, const char *name)
+{
+ unsigned int i;
+
+ /*XXX TODO: reduce code duplication */
+ for (i = 0; i < ARRAY_SIZE (prefix_table); i++) {
+ if (strcmp (name, prefix_table[i].name) == 0)
+ return prefix_table[i].prefix;
+ }
+
+ if (notmuch->user_prefix)
+ return _notmuch_string_map_get (notmuch->user_prefix, name);
+
+ return NULL;
+}
+
+static void
+_setup_query_field_default (const prefix_t *prefix, notmuch_database_t *notmuch)
+{
+ if (prefix->prefix)
+ notmuch->query_parser->add_prefix ("", prefix->prefix);
+ if (prefix->flags & NOTMUCH_FIELD_PROBABILISTIC)
+ notmuch->query_parser->add_prefix (prefix->name, prefix->prefix);
+ else
+ notmuch->query_parser->add_boolean_prefix (prefix->name, prefix->prefix);
+}
+
+static void
+_setup_query_field (const prefix_t *prefix, notmuch_database_t *notmuch)
+{
+ if (prefix->flags & NOTMUCH_FIELD_PROCESSOR) {
+ Xapian::FieldProcessor *fp;
+
+ if (STRNCMP_LITERAL (prefix->name, "date") == 0)
+ fp = (new DateFieldProcessor(NOTMUCH_VALUE_TIMESTAMP))->release ();
+ else if (STRNCMP_LITERAL(prefix->name, "query") == 0)
+ fp = (new QueryFieldProcessor (*notmuch->query_parser, notmuch))->release ();
+ else if (STRNCMP_LITERAL (prefix->name, "thread") == 0)
+ fp = (new ThreadFieldProcessor (*notmuch->query_parser, notmuch))->release ();
+ else
+ fp = (new RegexpFieldProcessor (prefix->name, prefix->flags,
+ *notmuch->query_parser, notmuch))->release ();
+
+ /* we treat all field-processor fields as boolean in order to get the raw input */
+ if (prefix->prefix)
+ notmuch->query_parser->add_prefix ("", prefix->prefix);
+ notmuch->query_parser->add_boolean_prefix (prefix->name, fp);
+ } else {
+ _setup_query_field_default (prefix, notmuch);
+ }
+}
+
+notmuch_status_t
+_notmuch_database_setup_standard_query_fields (notmuch_database_t *notmuch)
+{
+ for (unsigned int i = 0; i < ARRAY_SIZE (prefix_table); i++) {
+ const prefix_t *prefix = &prefix_table[i];
+ if (prefix->flags & NOTMUCH_FIELD_EXTERNAL) {
+ _setup_query_field (prefix, notmuch);
+ }
+ }
+ return NOTMUCH_STATUS_SUCCESS;
+}
+
+notmuch_status_t
+_notmuch_database_setup_user_query_fields (notmuch_database_t *notmuch)
+{
+ notmuch_config_list_t *list;
+ notmuch_status_t status;
+
+ notmuch->user_prefix = _notmuch_string_map_create (notmuch);
+ if (notmuch->user_prefix == NULL)
+ return NOTMUCH_STATUS_OUT_OF_MEMORY;
+
+ notmuch->user_header = _notmuch_string_map_create (notmuch);
+ if (notmuch->user_header == NULL)
+ return NOTMUCH_STATUS_OUT_OF_MEMORY;
+
+ status = notmuch_database_get_config_list (notmuch, CONFIG_HEADER_PREFIX, &list);
+ if (status)
+ return status;
+
+ for (; notmuch_config_list_valid (list); notmuch_config_list_move_to_next (list)) {
+
+ prefix_t query_field;
+
+ const char *key = notmuch_config_list_key (list)
+ + sizeof (CONFIG_HEADER_PREFIX) - 1;
+
+ _notmuch_string_map_append (notmuch->user_prefix,
+ key,
+ _user_prefix (notmuch, key));
+
+ _notmuch_string_map_append (notmuch->user_header,
+ key,
+ notmuch_config_list_value (list));
+
+ query_field.name = talloc_strdup (notmuch, key);
+ query_field.prefix = _user_prefix (notmuch, key);
+ query_field.flags = NOTMUCH_FIELD_PROBABILISTIC
+ | NOTMUCH_FIELD_EXTERNAL;
+
+ _setup_query_field_default (&query_field, notmuch);
+ }
+
+ notmuch_config_list_destroy (list);
+
+ return NOTMUCH_STATUS_SUCCESS;
+}
--
2.29.2
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 4/6] lib/config: delay setting talloc destructor
2020-12-20 12:10 v2 preliminaries for merged config David Bremner
` (2 preceding siblings ...)
2020-12-20 12:10 ` [PATCH 3/6] lib: factor out prefix related code to its own file David Bremner
@ 2020-12-20 12:10 ` David Bremner
2020-12-20 12:10 ` [PATCH 5/6] test: add regression test for searching with alternate config David Bremner
` (2 subsequent siblings)
6 siblings, 0 replies; 11+ messages in thread
From: David Bremner @ 2020-12-20 12:10 UTC (permalink / raw)
To: notmuch; +Cc: David Bremner
If Xapian has thrown an exception, it is not safe to invoke the
destructor when freeing the list struct.
---
lib/config.cc | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/lib/config.cc b/lib/config.cc
index efab01e4..0b760dbc 100644
--- a/lib/config.cc
+++ b/lib/config.cc
@@ -133,8 +133,15 @@ notmuch_database_get_config_list (notmuch_database_t *notmuch,
*out = list;
DONE:
- if (status && list)
- talloc_free (list);
+ if (status) {
+ if (list) {
+ talloc_free (list);
+ if (status != NOTMUCH_STATUS_XAPIAN_EXCEPTION)
+ _notmuch_config_list_destroy (list);
+ }
+ } else {
+ talloc_set_destructor (list, _notmuch_config_list_destroy);
+ }
return status;
}
--
2.29.2
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 5/6] test: add regression test for searching with alternate config
2020-12-20 12:10 v2 preliminaries for merged config David Bremner
` (3 preceding siblings ...)
2020-12-20 12:10 ` [PATCH 4/6] lib/config: delay setting talloc destructor David Bremner
@ 2020-12-20 12:10 ` David Bremner
2020-12-20 12:10 ` [PATCH 6/6] lib: factor out notmuch_database_open* related code to own file David Bremner
2020-12-23 23:50 ` v2 preliminaries for merged config David Bremner
6 siblings, 0 replies; 11+ messages in thread
From: David Bremner @ 2020-12-20 12:10 UTC (permalink / raw)
To: notmuch; +Cc: David Bremner
Make sure upcoming changes to config handling do not break command
line specification.
---
test/T140-excludes.sh | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/test/T140-excludes.sh b/test/T140-excludes.sh
index 0cf69975..cef07095 100755
--- a/test/T140-excludes.sh
+++ b/test/T140-excludes.sh
@@ -39,6 +39,16 @@ deleted_id=$gen_msg_id
output=$(notmuch search subject:deleted | notmuch_search_sanitize)
test_expect_equal "$output" "thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Not deleted (inbox unread)"
+test_begin_subtest "Search, exclude \"deleted\" messages; alternate config file"
+cp ${NOTMUCH_CONFIG} alt-config
+notmuch config set search.exclude_tags
+notmuch --config=alt-config search subject:deleted | notmuch_search_sanitize > OUTPUT
+cp alt-config ${NOTMUCH_CONFIG}
+cat <<EOF > EXPECTED
+thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Not deleted (inbox unread)
+EOF
+test_expect_equal_file EXPECTED OUTPUT
+
test_begin_subtest "Search, exclude \"deleted\" messages from message search"
output=$(notmuch search --output=messages subject:deleted | notmuch_search_sanitize)
test_expect_equal "$output" "id:$not_deleted_id"
--
2.29.2
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 6/6] lib: factor out notmuch_database_open* related code to own file
2020-12-20 12:10 v2 preliminaries for merged config David Bremner
` (4 preceding siblings ...)
2020-12-20 12:10 ` [PATCH 5/6] test: add regression test for searching with alternate config David Bremner
@ 2020-12-20 12:10 ` David Bremner
2020-12-23 23:50 ` v2 preliminaries for merged config David Bremner
6 siblings, 0 replies; 11+ messages in thread
From: David Bremner @ 2020-12-20 12:10 UTC (permalink / raw)
To: notmuch; +Cc: David Bremner
Reduce the size of database.cc, and prepare for extending the database
opening API
---
lib/Makefile.local | 3 +-
lib/database.cc | 219 ---------------------------------------------
lib/open.cc | 218 ++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 220 insertions(+), 220 deletions(-)
create mode 100644 lib/open.cc
diff --git a/lib/Makefile.local b/lib/Makefile.local
index 3aa9e80f..ddd169dc 100644
--- a/lib/Makefile.local
+++ b/lib/Makefile.local
@@ -61,7 +61,8 @@ libnotmuch_cxx_srcs = \
$(dir)/thread.cc \
$(dir)/thread-fp.cc \
$(dir)/features.cc \
- $(dir)/prefix.cc
+ $(dir)/prefix.cc \
+ $(dir)/open.cc
libnotmuch_modules := $(libnotmuch_c_srcs:.c=.o) $(libnotmuch_cxx_srcs:.cc=.o)
diff --git a/lib/database.cc b/lib/database.cc
index defa3062..0f4e2ff9 100644
--- a/lib/database.cc
+++ b/lib/database.cc
@@ -19,10 +19,6 @@
*/
#include "database-private.h"
-#include "parse-time-vrp.h"
-#include "query-fp.h"
-#include "thread-fp.h"
-#include "regexp-fields.h"
#include "string-util.h"
#include <iostream>
@@ -50,12 +46,6 @@ typedef struct {
#define STRINGIFY(s) _SUB_STRINGIFY (s)
#define _SUB_STRINGIFY(s) #s
-#if HAVE_XAPIAN_DB_RETRY_LOCK
-#define DB_ACTION (Xapian::DB_CREATE_OR_OPEN | Xapian::DB_RETRY_LOCK)
-#else
-#define DB_ACTION Xapian::DB_CREATE_OR_OPEN
-#endif
-
#define LOG_XAPIAN_EXCEPTION(message, error) _log_xapian_exception (__location__, message, error)
static void
@@ -594,215 +584,6 @@ _notmuch_database_new_revision (notmuch_database_t *notmuch)
return new_revision;
}
-notmuch_status_t
-notmuch_database_open (const char *path,
- notmuch_database_mode_t mode,
- notmuch_database_t **database)
-{
- char *status_string = NULL;
- notmuch_status_t status;
-
- status = notmuch_database_open_verbose (path, mode, database,
- &status_string);
-
- if (status_string) {
- fputs (status_string, stderr);
- free (status_string);
- }
-
- return status;
-}
-
-notmuch_status_t
-notmuch_database_open_verbose (const char *path,
- notmuch_database_mode_t mode,
- notmuch_database_t **database,
- char **status_string)
-{
- notmuch_status_t status = NOTMUCH_STATUS_SUCCESS;
- void *local = talloc_new (NULL);
- notmuch_database_t *notmuch = NULL;
- char *notmuch_path, *xapian_path, *incompat_features;
- char *message = NULL;
- struct stat st;
- int err;
- unsigned int i, version;
- static int initialized = 0;
-
- if (path == NULL) {
- message = strdup ("Error: Cannot open a database for a NULL path.\n");
- status = NOTMUCH_STATUS_NULL_POINTER;
- goto DONE;
- }
-
- if (path[0] != '/') {
- message = strdup ("Error: Database path must be absolute.\n");
- status = NOTMUCH_STATUS_PATH_ERROR;
- goto DONE;
- }
-
- if (! (notmuch_path = talloc_asprintf (local, "%s/%s", path, ".notmuch"))) {
- message = strdup ("Out of memory\n");
- status = NOTMUCH_STATUS_OUT_OF_MEMORY;
- goto DONE;
- }
-
- err = stat (notmuch_path, &st);
- if (err) {
- IGNORE_RESULT (asprintf (&message, "Error opening database at %s: %s\n",
- notmuch_path, strerror (errno)));
- status = NOTMUCH_STATUS_FILE_ERROR;
- goto DONE;
- }
-
- if (! (xapian_path = talloc_asprintf (local, "%s/%s", notmuch_path, "xapian"))) {
- message = strdup ("Out of memory\n");
- status = NOTMUCH_STATUS_OUT_OF_MEMORY;
- goto DONE;
- }
-
- /* Initialize the GLib type system and threads */
-#if ! GLIB_CHECK_VERSION (2, 35, 1)
- g_type_init ();
-#endif
-
- /* Initialize gmime */
- if (! initialized) {
- g_mime_init ();
- initialized = 1;
- }
-
- notmuch = talloc_zero (NULL, notmuch_database_t);
- notmuch->exception_reported = false;
- notmuch->status_string = NULL;
- notmuch->path = talloc_strdup (notmuch, path);
-
- strip_trailing (notmuch->path, '/');
-
- notmuch->writable_xapian_db = NULL;
- notmuch->atomic_nesting = 0;
- notmuch->view = 1;
- try {
- string last_thread_id;
- string last_mod;
-
- if (mode == NOTMUCH_DATABASE_MODE_READ_WRITE) {
- notmuch->writable_xapian_db = new Xapian::WritableDatabase (xapian_path,
- DB_ACTION);
- notmuch->xapian_db = notmuch->writable_xapian_db;
- } else {
- notmuch->xapian_db = new Xapian::Database (xapian_path);
- }
-
- /* Check version. As of database version 3, we represent
- * changes in terms of features, so assume a version bump
- * means a dramatically incompatible change. */
- version = notmuch_database_get_version (notmuch);
- if (version > NOTMUCH_DATABASE_VERSION) {
- IGNORE_RESULT (asprintf (&message,
- "Error: Notmuch database at %s\n"
- " has a newer database format version (%u) than supported by this\n"
- " version of notmuch (%u).\n",
- notmuch_path, version, NOTMUCH_DATABASE_VERSION));
- notmuch_database_destroy (notmuch);
- notmuch = NULL;
- status = NOTMUCH_STATUS_FILE_ERROR;
- goto DONE;
- }
-
- /* Check features. */
- incompat_features = NULL;
- notmuch->features = _notmuch_database_parse_features (
- local, notmuch->xapian_db->get_metadata ("features").c_str (),
- version, mode == NOTMUCH_DATABASE_MODE_READ_WRITE ? 'w' : 'r',
- &incompat_features);
- if (incompat_features) {
- IGNORE_RESULT (asprintf (&message,
- "Error: Notmuch database at %s\n"
- " requires features (%s)\n"
- " not supported by this version of notmuch.\n",
- notmuch_path, incompat_features));
- notmuch_database_destroy (notmuch);
- notmuch = NULL;
- status = NOTMUCH_STATUS_FILE_ERROR;
- goto DONE;
- }
-
- notmuch->last_doc_id = notmuch->xapian_db->get_lastdocid ();
- last_thread_id = notmuch->xapian_db->get_metadata ("last_thread_id");
- if (last_thread_id.empty ()) {
- notmuch->last_thread_id = 0;
- } else {
- const char *str;
- char *end;
-
- str = last_thread_id.c_str ();
- notmuch->last_thread_id = strtoull (str, &end, 16);
- if (*end != '\0')
- INTERNAL_ERROR ("Malformed database last_thread_id: %s", str);
- }
-
- /* Get current highest revision number. */
- last_mod = notmuch->xapian_db->get_value_upper_bound (
- NOTMUCH_VALUE_LAST_MOD);
- if (last_mod.empty ())
- notmuch->revision = 0;
- else
- notmuch->revision = Xapian::sortable_unserialise (last_mod);
- notmuch->uuid = talloc_strdup (
- notmuch, notmuch->xapian_db->get_uuid ().c_str ());
-
- notmuch->query_parser = new Xapian::QueryParser;
- notmuch->term_gen = new Xapian::TermGenerator;
- notmuch->term_gen->set_stemmer (Xapian::Stem ("english"));
- notmuch->value_range_processor = new Xapian::NumberRangeProcessor (NOTMUCH_VALUE_TIMESTAMP);
- notmuch->date_range_processor = new ParseTimeRangeProcessor (NOTMUCH_VALUE_TIMESTAMP, "date:");
- notmuch->last_mod_range_processor = new Xapian::NumberRangeProcessor (NOTMUCH_VALUE_LAST_MOD, "lastmod:");
- notmuch->query_parser->set_default_op (Xapian::Query::OP_AND);
- notmuch->query_parser->set_database (*notmuch->xapian_db);
- notmuch->query_parser->set_stemmer (Xapian::Stem ("english"));
- notmuch->query_parser->set_stemming_strategy (Xapian::QueryParser::STEM_SOME);
- notmuch->query_parser->add_rangeprocessor (notmuch->value_range_processor);
- notmuch->query_parser->add_rangeprocessor (notmuch->date_range_processor);
- notmuch->query_parser->add_rangeprocessor (notmuch->last_mod_range_processor);
-
- status = _notmuch_database_setup_standard_query_fields (notmuch);
- if (status)
- goto DONE;
-
- status = _notmuch_database_setup_user_query_fields (notmuch);
- if (status)
- goto DONE;
-
- } catch (const Xapian::Error &error) {
- IGNORE_RESULT (asprintf (&message, "A Xapian exception occurred opening database: %s\n",
- error.get_msg ().c_str ()));
- notmuch_database_destroy (notmuch);
- notmuch = NULL;
- status = NOTMUCH_STATUS_XAPIAN_EXCEPTION;
- }
-
- DONE:
- talloc_free (local);
-
- if (message) {
- if (status_string)
- *status_string = message;
- else
- free (message);
- }
-
- if (database)
- *database = notmuch;
- else
- talloc_free (notmuch);
-
- if (notmuch)
- notmuch->open = true;
-
- return status;
-}
-
notmuch_status_t
notmuch_database_close (notmuch_database_t *notmuch)
{
diff --git a/lib/open.cc b/lib/open.cc
new file mode 100644
index 00000000..1b17e63a
--- /dev/null
+++ b/lib/open.cc
@@ -0,0 +1,218 @@
+#include <unistd.h>
+#include "database-private.h"
+#include "parse-time-vrp.h"
+
+#if HAVE_XAPIAN_DB_RETRY_LOCK
+#define DB_ACTION (Xapian::DB_CREATE_OR_OPEN | Xapian::DB_RETRY_LOCK)
+#else
+#define DB_ACTION Xapian::DB_CREATE_OR_OPEN
+#endif
+
+notmuch_status_t
+notmuch_database_open (const char *path,
+ notmuch_database_mode_t mode,
+ notmuch_database_t **database)
+{
+ char *status_string = NULL;
+ notmuch_status_t status;
+
+ status = notmuch_database_open_verbose (path, mode, database,
+ &status_string);
+
+ if (status_string) {
+ fputs (status_string, stderr);
+ free (status_string);
+ }
+
+ return status;
+}
+
+notmuch_status_t
+notmuch_database_open_verbose (const char *path,
+ notmuch_database_mode_t mode,
+ notmuch_database_t **database,
+ char **status_string)
+{
+ notmuch_status_t status = NOTMUCH_STATUS_SUCCESS;
+ void *local = talloc_new (NULL);
+ notmuch_database_t *notmuch = NULL;
+ char *notmuch_path, *xapian_path, *incompat_features;
+ char *message = NULL;
+ struct stat st;
+ int err;
+ unsigned int version;
+ static int initialized = 0;
+
+ if (path == NULL) {
+ message = strdup ("Error: Cannot open a database for a NULL path.\n");
+ status = NOTMUCH_STATUS_NULL_POINTER;
+ goto DONE;
+ }
+
+ if (path[0] != '/') {
+ message = strdup ("Error: Database path must be absolute.\n");
+ status = NOTMUCH_STATUS_PATH_ERROR;
+ goto DONE;
+ }
+
+ if (! (notmuch_path = talloc_asprintf (local, "%s/%s", path, ".notmuch"))) {
+ message = strdup ("Out of memory\n");
+ status = NOTMUCH_STATUS_OUT_OF_MEMORY;
+ goto DONE;
+ }
+
+ err = stat (notmuch_path, &st);
+ if (err) {
+ IGNORE_RESULT (asprintf (&message, "Error opening database at %s: %s\n",
+ notmuch_path, strerror (errno)));
+ status = NOTMUCH_STATUS_FILE_ERROR;
+ goto DONE;
+ }
+
+ if (! (xapian_path = talloc_asprintf (local, "%s/%s", notmuch_path, "xapian"))) {
+ message = strdup ("Out of memory\n");
+ status = NOTMUCH_STATUS_OUT_OF_MEMORY;
+ goto DONE;
+ }
+
+ /* Initialize the GLib type system and threads */
+#if ! GLIB_CHECK_VERSION (2, 35, 1)
+ g_type_init ();
+#endif
+
+ /* Initialize gmime */
+ if (! initialized) {
+ g_mime_init ();
+ initialized = 1;
+ }
+
+ notmuch = talloc_zero (NULL, notmuch_database_t);
+ notmuch->exception_reported = false;
+ notmuch->status_string = NULL;
+ notmuch->path = talloc_strdup (notmuch, path);
+
+ strip_trailing (notmuch->path, '/');
+
+ notmuch->writable_xapian_db = NULL;
+ notmuch->atomic_nesting = 0;
+ notmuch->view = 1;
+ try {
+ std::string last_thread_id;
+ std::string last_mod;
+
+ if (mode == NOTMUCH_DATABASE_MODE_READ_WRITE) {
+ notmuch->writable_xapian_db = new Xapian::WritableDatabase (xapian_path,
+ DB_ACTION);
+ notmuch->xapian_db = notmuch->writable_xapian_db;
+ } else {
+ notmuch->xapian_db = new Xapian::Database (xapian_path);
+ }
+
+ /* Check version. As of database version 3, we represent
+ * changes in terms of features, so assume a version bump
+ * means a dramatically incompatible change. */
+ version = notmuch_database_get_version (notmuch);
+ if (version > NOTMUCH_DATABASE_VERSION) {
+ IGNORE_RESULT (asprintf (&message,
+ "Error: Notmuch database at %s\n"
+ " has a newer database format version (%u) than supported by this\n"
+ " version of notmuch (%u).\n",
+ notmuch_path, version, NOTMUCH_DATABASE_VERSION));
+ notmuch_database_destroy (notmuch);
+ notmuch = NULL;
+ status = NOTMUCH_STATUS_FILE_ERROR;
+ goto DONE;
+ }
+
+ /* Check features. */
+ incompat_features = NULL;
+ notmuch->features = _notmuch_database_parse_features (
+ local, notmuch->xapian_db->get_metadata ("features").c_str (),
+ version, mode == NOTMUCH_DATABASE_MODE_READ_WRITE ? 'w' : 'r',
+ &incompat_features);
+ if (incompat_features) {
+ IGNORE_RESULT (asprintf (&message,
+ "Error: Notmuch database at %s\n"
+ " requires features (%s)\n"
+ " not supported by this version of notmuch.\n",
+ notmuch_path, incompat_features));
+ notmuch_database_destroy (notmuch);
+ notmuch = NULL;
+ status = NOTMUCH_STATUS_FILE_ERROR;
+ goto DONE;
+ }
+
+ notmuch->last_doc_id = notmuch->xapian_db->get_lastdocid ();
+ last_thread_id = notmuch->xapian_db->get_metadata ("last_thread_id");
+ if (last_thread_id.empty ()) {
+ notmuch->last_thread_id = 0;
+ } else {
+ const char *str;
+ char *end;
+
+ str = last_thread_id.c_str ();
+ notmuch->last_thread_id = strtoull (str, &end, 16);
+ if (*end != '\0')
+ INTERNAL_ERROR ("Malformed database last_thread_id: %s", str);
+ }
+
+ /* Get current highest revision number. */
+ last_mod = notmuch->xapian_db->get_value_upper_bound (
+ NOTMUCH_VALUE_LAST_MOD);
+ if (last_mod.empty ())
+ notmuch->revision = 0;
+ else
+ notmuch->revision = Xapian::sortable_unserialise (last_mod);
+ notmuch->uuid = talloc_strdup (
+ notmuch, notmuch->xapian_db->get_uuid ().c_str ());
+
+ notmuch->query_parser = new Xapian::QueryParser;
+ notmuch->term_gen = new Xapian::TermGenerator;
+ notmuch->term_gen->set_stemmer (Xapian::Stem ("english"));
+ notmuch->value_range_processor = new Xapian::NumberRangeProcessor (NOTMUCH_VALUE_TIMESTAMP);
+ notmuch->date_range_processor = new ParseTimeRangeProcessor (NOTMUCH_VALUE_TIMESTAMP, "date:");
+ notmuch->last_mod_range_processor = new Xapian::NumberRangeProcessor (NOTMUCH_VALUE_LAST_MOD, "lastmod:");
+ notmuch->query_parser->set_default_op (Xapian::Query::OP_AND);
+ notmuch->query_parser->set_database (*notmuch->xapian_db);
+ notmuch->query_parser->set_stemmer (Xapian::Stem ("english"));
+ notmuch->query_parser->set_stemming_strategy (Xapian::QueryParser::STEM_SOME);
+ notmuch->query_parser->add_rangeprocessor (notmuch->value_range_processor);
+ notmuch->query_parser->add_rangeprocessor (notmuch->date_range_processor);
+ notmuch->query_parser->add_rangeprocessor (notmuch->last_mod_range_processor);
+
+ status = _notmuch_database_setup_standard_query_fields (notmuch);
+ if (status)
+ goto DONE;
+
+ status = _notmuch_database_setup_user_query_fields (notmuch);
+ if (status)
+ goto DONE;
+
+ } catch (const Xapian::Error &error) {
+ IGNORE_RESULT (asprintf (&message, "A Xapian exception occurred opening database: %s\n",
+ error.get_msg ().c_str ()));
+ notmuch_database_destroy (notmuch);
+ notmuch = NULL;
+ status = NOTMUCH_STATUS_XAPIAN_EXCEPTION;
+ }
+
+ DONE:
+ talloc_free (local);
+
+ if (message) {
+ if (status_string)
+ *status_string = message;
+ else
+ free (message);
+ }
+
+ if (database)
+ *database = notmuch;
+ else
+ talloc_free (notmuch);
+
+ if (notmuch)
+ notmuch->open = true;
+
+ return status;
+}
--
2.29.2
^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH 3/6] lib: factor out prefix related code to its own file
2020-12-20 12:10 ` [PATCH 3/6] lib: factor out prefix related code to its own file David Bremner
@ 2020-12-20 15:36 ` Tomi Ollila
2020-12-20 20:03 ` David Bremner
0 siblings, 1 reply; 11+ messages in thread
From: Tomi Ollila @ 2020-12-20 15:36 UTC (permalink / raw)
To: David Bremner, notmuch; +Cc: David Bremner
On Sun, Dec 20 2020, David Bremner wrote:
> Reduce the size of database.cc, and limit the scope of prefix_table,
> make sure it's accessed via a well-defined internal API.
> ---
> lib/Makefile.local | 4 +-
> lib/database-private.h | 7 ++
> lib/database.cc | 203 ++-------------------------------------
> lib/prefix.cc | 210 +++++++++++++++++++++++++++++++++++++++++
> 4 files changed, 229 insertions(+), 195 deletions(-)
> create mode 100644 lib/prefix.cc
>
> diff --git a/lib/Makefile.local b/lib/Makefile.local
> index 04418fa8..3aa9e80f 100644
> --- a/lib/Makefile.local
> +++ b/lib/Makefile.local
> @@ -60,7 +60,9 @@ libnotmuch_cxx_srcs = \
> $(dir)/regexp-fields.cc \
> $(dir)/thread.cc \
> $(dir)/thread-fp.cc \
> - $(dir)/features.cc
> + $(dir)/features.cc \
> + $(dir)/prefix.cc
> +
Good stuff! is this extra line above intentional ?
(otherwise I did not find anything else, but I may have
got tired looking through the series ;/)
Tomi
>
> libnotmuch_modules := $(libnotmuch_c_srcs:.c=.o) $(libnotmuch_cxx_srcs:.cc=.o)
>
> diff --git a/lib/database-private.h b/lib/database-private.h
> index 2d220811..c9bc712b 100644
> --- a/lib/database-private.h
> +++ b/lib/database-private.h
> @@ -277,4 +277,11 @@ _notmuch_database_parse_features (const void *ctx, const char *features, unsigne
> char *
> _notmuch_database_print_features (const void *ctx, unsigned int features);
>
> +/* prefix.cc */
> +notmuch_status_t
> +_notmuch_database_setup_standard_query_fields (notmuch_database_t *notmuch);
> +
> +notmuch_status_t
> +_notmuch_database_setup_user_query_fields (notmuch_database_t *notmuch);
> +
> #endif
> diff --git a/lib/database.cc b/lib/database.cc
> index 4a477bd7..defa3062 100644
> --- a/lib/database.cc
> +++ b/lib/database.cc
> @@ -263,80 +263,6 @@ _notmuch_database_mode (notmuch_database_t *notmuch)
> * same thread.
> */
>
> -/* With these prefix values we follow the conventions published here:
> - *
> - * https://xapian.org/docs/omega/termprefixes.html
> - *
> - * as much as makes sense. Note that I took some liberty in matching
> - * the reserved prefix values to notmuch concepts, (for example, 'G'
> - * is documented as "newsGroup (or similar entity - e.g. a web forum
> - * name)", for which I think the thread is the closest analogue in
> - * notmuch. This in spite of the fact that we will eventually be
> - * storing mailing-list messages where 'G' for "mailing list name"
> - * might be even a closer analogue. I'm treating the single-character
> - * prefixes preferentially for core notmuch concepts (which will be
> - * nearly universal to all mail messages).
> - */
> -
> -static const
> -prefix_t prefix_table[] = {
> - /* name term prefix flags */
> - { "type", "T", NOTMUCH_FIELD_NO_FLAGS },
> - { "reference", "XREFERENCE", NOTMUCH_FIELD_NO_FLAGS },
> - { "replyto", "XREPLYTO", NOTMUCH_FIELD_NO_FLAGS },
> - { "directory", "XDIRECTORY", NOTMUCH_FIELD_NO_FLAGS },
> - { "file-direntry", "XFDIRENTRY", NOTMUCH_FIELD_NO_FLAGS },
> - { "directory-direntry", "XDDIRENTRY", NOTMUCH_FIELD_NO_FLAGS },
> - { "body", "", NOTMUCH_FIELD_EXTERNAL |
> - NOTMUCH_FIELD_PROBABILISTIC },
> - { "thread", "G", NOTMUCH_FIELD_EXTERNAL |
> - NOTMUCH_FIELD_PROCESSOR },
> - { "tag", "K", NOTMUCH_FIELD_EXTERNAL |
> - NOTMUCH_FIELD_PROCESSOR },
> - { "is", "K", NOTMUCH_FIELD_EXTERNAL |
> - NOTMUCH_FIELD_PROCESSOR },
> - { "id", "Q", NOTMUCH_FIELD_EXTERNAL },
> - { "mid", "Q", NOTMUCH_FIELD_EXTERNAL |
> - NOTMUCH_FIELD_PROCESSOR },
> - { "path", "P", NOTMUCH_FIELD_EXTERNAL |
> - NOTMUCH_FIELD_PROCESSOR },
> - { "property", "XPROPERTY", NOTMUCH_FIELD_EXTERNAL },
> - /*
> - * Unconditionally add ':' to reduce potential ambiguity with
> - * overlapping prefixes and/or terms that start with capital
> - * letters. See Xapian document termprefixes.html for related
> - * discussion.
> - */
> - { "folder", "XFOLDER:", NOTMUCH_FIELD_EXTERNAL |
> - NOTMUCH_FIELD_PROCESSOR },
> - { "date", NULL, NOTMUCH_FIELD_EXTERNAL |
> - NOTMUCH_FIELD_PROCESSOR },
> - { "query", NULL, NOTMUCH_FIELD_EXTERNAL |
> - NOTMUCH_FIELD_PROCESSOR },
> - { "from", "XFROM", NOTMUCH_FIELD_EXTERNAL |
> - NOTMUCH_FIELD_PROBABILISTIC |
> - NOTMUCH_FIELD_PROCESSOR },
> - { "to", "XTO", NOTMUCH_FIELD_EXTERNAL |
> - NOTMUCH_FIELD_PROBABILISTIC },
> - { "attachment", "XATTACHMENT", NOTMUCH_FIELD_EXTERNAL |
> - NOTMUCH_FIELD_PROBABILISTIC },
> - { "mimetype", "XMIMETYPE", NOTMUCH_FIELD_EXTERNAL |
> - NOTMUCH_FIELD_PROBABILISTIC },
> - { "subject", "XSUBJECT", NOTMUCH_FIELD_EXTERNAL |
> - NOTMUCH_FIELD_PROBABILISTIC |
> - NOTMUCH_FIELD_PROCESSOR },
> -};
> -
> -static void
> -_setup_query_field_default (const prefix_t *prefix, notmuch_database_t *notmuch)
> -{
> - if (prefix->prefix)
> - notmuch->query_parser->add_prefix ("", prefix->prefix);
> - if (prefix->flags & NOTMUCH_FIELD_PROBABILISTIC)
> - notmuch->query_parser->add_prefix (prefix->name, prefix->prefix);
> - else
> - notmuch->query_parser->add_boolean_prefix (prefix->name, prefix->prefix);
> -}
>
> notmuch_string_map_iterator_t *
> _notmuch_database_user_headers (notmuch_database_t *notmuch)
> @@ -344,118 +270,6 @@ _notmuch_database_user_headers (notmuch_database_t *notmuch)
> return _notmuch_string_map_iterator_create (notmuch->user_header, "", false);
> }
>
> -const char *
> -_user_prefix (void *ctx, const char *name)
> -{
> - return talloc_asprintf (ctx, "XU%s:", name);
> -}
> -
> -static notmuch_status_t
> -_setup_user_query_fields (notmuch_database_t *notmuch)
> -{
> - notmuch_config_list_t *list;
> - notmuch_status_t status;
> -
> - notmuch->user_prefix = _notmuch_string_map_create (notmuch);
> - if (notmuch->user_prefix == NULL)
> - return NOTMUCH_STATUS_OUT_OF_MEMORY;
> -
> - notmuch->user_header = _notmuch_string_map_create (notmuch);
> - if (notmuch->user_header == NULL)
> - return NOTMUCH_STATUS_OUT_OF_MEMORY;
> -
> - status = notmuch_database_get_config_list (notmuch, CONFIG_HEADER_PREFIX, &list);
> - if (status)
> - return status;
> -
> - for (; notmuch_config_list_valid (list); notmuch_config_list_move_to_next (list)) {
> -
> - prefix_t query_field;
> -
> - const char *key = notmuch_config_list_key (list)
> - + sizeof (CONFIG_HEADER_PREFIX) - 1;
> -
> - _notmuch_string_map_append (notmuch->user_prefix,
> - key,
> - _user_prefix (notmuch, key));
> -
> - _notmuch_string_map_append (notmuch->user_header,
> - key,
> - notmuch_config_list_value (list));
> -
> - query_field.name = talloc_strdup (notmuch, key);
> - query_field.prefix = _user_prefix (notmuch, key);
> - query_field.flags = NOTMUCH_FIELD_PROBABILISTIC
> - | NOTMUCH_FIELD_EXTERNAL;
> -
> - _setup_query_field_default (&query_field, notmuch);
> - }
> -
> - notmuch_config_list_destroy (list);
> -
> - return NOTMUCH_STATUS_SUCCESS;
> -}
> -
> -static void
> -_setup_query_field (const prefix_t *prefix, notmuch_database_t *notmuch)
> -{
> - if (prefix->flags & NOTMUCH_FIELD_PROCESSOR) {
> - Xapian::FieldProcessor *fp;
> -
> - if (STRNCMP_LITERAL (prefix->name, "date") == 0)
> - fp = (new DateFieldProcessor(NOTMUCH_VALUE_TIMESTAMP))->release ();
> - else if (STRNCMP_LITERAL(prefix->name, "query") == 0)
> - fp = (new QueryFieldProcessor (*notmuch->query_parser, notmuch))->release ();
> - else if (STRNCMP_LITERAL (prefix->name, "thread") == 0)
> - fp = (new ThreadFieldProcessor (*notmuch->query_parser, notmuch))->release ();
> - else
> - fp = (new RegexpFieldProcessor (prefix->name, prefix->flags,
> - *notmuch->query_parser, notmuch))->release ();
> -
> - /* we treat all field-processor fields as boolean in order to get the raw input */
> - if (prefix->prefix)
> - notmuch->query_parser->add_prefix ("", prefix->prefix);
> - notmuch->query_parser->add_boolean_prefix (prefix->name, fp);
> - } else {
> - _setup_query_field_default (prefix, notmuch);
> - }
> -}
> -
> -const char *
> -_find_prefix (const char *name)
> -{
> - unsigned int i;
> -
> - for (i = 0; i < ARRAY_SIZE (prefix_table); i++) {
> - if (strcmp (name, prefix_table[i].name) == 0)
> - return prefix_table[i].prefix;
> - }
> -
> - INTERNAL_ERROR ("No prefix exists for '%s'\n", name);
> -
> - return "";
> -}
> -
> -/* Like find prefix, but include the possibility of user defined
> - * prefixes specific to this database */
> -
> -const char *
> -_notmuch_database_prefix (notmuch_database_t *notmuch, const char *name)
> -{
> - unsigned int i;
> -
> - /*XXX TODO: reduce code duplication */
> - for (i = 0; i < ARRAY_SIZE (prefix_table); i++) {
> - if (strcmp (name, prefix_table[i].name) == 0)
> - return prefix_table[i].prefix;
> - }
> -
> - if (notmuch->user_prefix)
> - return _notmuch_string_map_get (notmuch->user_prefix, name);
> -
> - return NULL;
> -}
> -
> const char *
> notmuch_status_to_string (notmuch_status_t status)
> {
> @@ -898,7 +712,7 @@ notmuch_database_open_verbose (const char *path,
>
> /* Check features. */
> incompat_features = NULL;
> - notmuch->features = _parse_features (
> + notmuch->features = _notmuch_database_parse_features (
> local, notmuch->xapian_db->get_metadata ("features").c_str (),
> version, mode == NOTMUCH_DATABASE_MODE_READ_WRITE ? 'w' : 'r',
> &incompat_features);
> @@ -952,13 +766,14 @@ notmuch_database_open_verbose (const char *path,
> notmuch->query_parser->add_rangeprocessor (notmuch->date_range_processor);
> notmuch->query_parser->add_rangeprocessor (notmuch->last_mod_range_processor);
>
> - for (i = 0; i < ARRAY_SIZE (prefix_table); i++) {
> - const prefix_t *prefix = &prefix_table[i];
> - if (prefix->flags & NOTMUCH_FIELD_EXTERNAL) {
> - _setup_query_field (prefix, notmuch);
> - }
> - }
> - status = _setup_user_query_fields (notmuch);
> + status = _notmuch_database_setup_standard_query_fields (notmuch);
> + if (status)
> + goto DONE;
> +
> + status = _notmuch_database_setup_user_query_fields (notmuch);
> + if (status)
> + goto DONE;
> +
> } catch (const Xapian::Error &error) {
> IGNORE_RESULT (asprintf (&message, "A Xapian exception occurred opening database: %s\n",
> error.get_msg ().c_str ()));
> diff --git a/lib/prefix.cc b/lib/prefix.cc
> new file mode 100644
> index 00000000..dd7b193d
> --- /dev/null
> +++ b/lib/prefix.cc
> @@ -0,0 +1,210 @@
> +#include "database-private.h"
> +#include "query-fp.h"
> +#include "thread-fp.h"
> +#include "regexp-fields.h"
> +#include "parse-time-vrp.h"
> +
> +typedef struct {
> + const char *name;
> + const char *prefix;
> + notmuch_field_flag_t flags;
> +} prefix_t;
> +
> +/* With these prefix values we follow the conventions published here:
> + *
> + * https://xapian.org/docs/omega/termprefixes.html
> + *
> + * as much as makes sense. Note that I took some liberty in matching
> + * the reserved prefix values to notmuch concepts, (for example, 'G'
> + * is documented as "newsGroup (or similar entity - e.g. a web forum
> + * name)", for which I think the thread is the closest analogue in
> + * notmuch. This in spite of the fact that we will eventually be
> + * storing mailing-list messages where 'G' for "mailing list name"
> + * might be even a closer analogue. I'm treating the single-character
> + * prefixes preferentially for core notmuch concepts (which will be
> + * nearly universal to all mail messages).
> + */
> +
> +static const
> +prefix_t prefix_table[] = {
> + /* name term prefix flags */
> + { "type", "T", NOTMUCH_FIELD_NO_FLAGS },
> + { "reference", "XREFERENCE", NOTMUCH_FIELD_NO_FLAGS },
> + { "replyto", "XREPLYTO", NOTMUCH_FIELD_NO_FLAGS },
> + { "directory", "XDIRECTORY", NOTMUCH_FIELD_NO_FLAGS },
> + { "file-direntry", "XFDIRENTRY", NOTMUCH_FIELD_NO_FLAGS },
> + { "directory-direntry", "XDDIRENTRY", NOTMUCH_FIELD_NO_FLAGS },
> + { "body", "", NOTMUCH_FIELD_EXTERNAL |
> + NOTMUCH_FIELD_PROBABILISTIC },
> + { "thread", "G", NOTMUCH_FIELD_EXTERNAL |
> + NOTMUCH_FIELD_PROCESSOR },
> + { "tag", "K", NOTMUCH_FIELD_EXTERNAL |
> + NOTMUCH_FIELD_PROCESSOR },
> + { "is", "K", NOTMUCH_FIELD_EXTERNAL |
> + NOTMUCH_FIELD_PROCESSOR },
> + { "id", "Q", NOTMUCH_FIELD_EXTERNAL },
> + { "mid", "Q", NOTMUCH_FIELD_EXTERNAL |
> + NOTMUCH_FIELD_PROCESSOR },
> + { "path", "P", NOTMUCH_FIELD_EXTERNAL |
> + NOTMUCH_FIELD_PROCESSOR },
> + { "property", "XPROPERTY", NOTMUCH_FIELD_EXTERNAL },
> + /*
> + * Unconditionally add ':' to reduce potential ambiguity with
> + * overlapping prefixes and/or terms that start with capital
> + * letters. See Xapian document termprefixes.html for related
> + * discussion.
> + */
> + { "folder", "XFOLDER:", NOTMUCH_FIELD_EXTERNAL |
> + NOTMUCH_FIELD_PROCESSOR },
> + { "date", NULL, NOTMUCH_FIELD_EXTERNAL |
> + NOTMUCH_FIELD_PROCESSOR },
> + { "query", NULL, NOTMUCH_FIELD_EXTERNAL |
> + NOTMUCH_FIELD_PROCESSOR },
> + { "from", "XFROM", NOTMUCH_FIELD_EXTERNAL |
> + NOTMUCH_FIELD_PROBABILISTIC |
> + NOTMUCH_FIELD_PROCESSOR },
> + { "to", "XTO", NOTMUCH_FIELD_EXTERNAL |
> + NOTMUCH_FIELD_PROBABILISTIC },
> + { "attachment", "XATTACHMENT", NOTMUCH_FIELD_EXTERNAL |
> + NOTMUCH_FIELD_PROBABILISTIC },
> + { "mimetype", "XMIMETYPE", NOTMUCH_FIELD_EXTERNAL |
> + NOTMUCH_FIELD_PROBABILISTIC },
> + { "subject", "XSUBJECT", NOTMUCH_FIELD_EXTERNAL |
> + NOTMUCH_FIELD_PROBABILISTIC |
> + NOTMUCH_FIELD_PROCESSOR },
> +};
> +
> +static const char *
> +_user_prefix (void *ctx, const char *name)
> +{
> + return talloc_asprintf (ctx, "XU%s:", name);
> +}
> +
> +const char *
> +_find_prefix (const char *name)
> +{
> + unsigned int i;
> +
> + for (i = 0; i < ARRAY_SIZE (prefix_table); i++) {
> + if (strcmp (name, prefix_table[i].name) == 0)
> + return prefix_table[i].prefix;
> + }
> +
> + INTERNAL_ERROR ("No prefix exists for '%s'\n", name);
> +
> + return "";
> +}
> +
> +/* Like find prefix, but include the possibility of user defined
> + * prefixes specific to this database */
> +
> +const char *
> +_notmuch_database_prefix (notmuch_database_t *notmuch, const char *name)
> +{
> + unsigned int i;
> +
> + /*XXX TODO: reduce code duplication */
> + for (i = 0; i < ARRAY_SIZE (prefix_table); i++) {
> + if (strcmp (name, prefix_table[i].name) == 0)
> + return prefix_table[i].prefix;
> + }
> +
> + if (notmuch->user_prefix)
> + return _notmuch_string_map_get (notmuch->user_prefix, name);
> +
> + return NULL;
> +}
> +
> +static void
> +_setup_query_field_default (const prefix_t *prefix, notmuch_database_t *notmuch)
> +{
> + if (prefix->prefix)
> + notmuch->query_parser->add_prefix ("", prefix->prefix);
> + if (prefix->flags & NOTMUCH_FIELD_PROBABILISTIC)
> + notmuch->query_parser->add_prefix (prefix->name, prefix->prefix);
> + else
> + notmuch->query_parser->add_boolean_prefix (prefix->name, prefix->prefix);
> +}
> +
> +static void
> +_setup_query_field (const prefix_t *prefix, notmuch_database_t *notmuch)
> +{
> + if (prefix->flags & NOTMUCH_FIELD_PROCESSOR) {
> + Xapian::FieldProcessor *fp;
> +
> + if (STRNCMP_LITERAL (prefix->name, "date") == 0)
> + fp = (new DateFieldProcessor(NOTMUCH_VALUE_TIMESTAMP))->release ();
> + else if (STRNCMP_LITERAL(prefix->name, "query") == 0)
> + fp = (new QueryFieldProcessor (*notmuch->query_parser, notmuch))->release ();
> + else if (STRNCMP_LITERAL (prefix->name, "thread") == 0)
> + fp = (new ThreadFieldProcessor (*notmuch->query_parser, notmuch))->release ();
> + else
> + fp = (new RegexpFieldProcessor (prefix->name, prefix->flags,
> + *notmuch->query_parser, notmuch))->release ();
> +
> + /* we treat all field-processor fields as boolean in order to get the raw input */
> + if (prefix->prefix)
> + notmuch->query_parser->add_prefix ("", prefix->prefix);
> + notmuch->query_parser->add_boolean_prefix (prefix->name, fp);
> + } else {
> + _setup_query_field_default (prefix, notmuch);
> + }
> +}
> +
> +notmuch_status_t
> +_notmuch_database_setup_standard_query_fields (notmuch_database_t *notmuch)
> +{
> + for (unsigned int i = 0; i < ARRAY_SIZE (prefix_table); i++) {
> + const prefix_t *prefix = &prefix_table[i];
> + if (prefix->flags & NOTMUCH_FIELD_EXTERNAL) {
> + _setup_query_field (prefix, notmuch);
> + }
> + }
> + return NOTMUCH_STATUS_SUCCESS;
> +}
> +
> +notmuch_status_t
> +_notmuch_database_setup_user_query_fields (notmuch_database_t *notmuch)
> +{
> + notmuch_config_list_t *list;
> + notmuch_status_t status;
> +
> + notmuch->user_prefix = _notmuch_string_map_create (notmuch);
> + if (notmuch->user_prefix == NULL)
> + return NOTMUCH_STATUS_OUT_OF_MEMORY;
> +
> + notmuch->user_header = _notmuch_string_map_create (notmuch);
> + if (notmuch->user_header == NULL)
> + return NOTMUCH_STATUS_OUT_OF_MEMORY;
> +
> + status = notmuch_database_get_config_list (notmuch, CONFIG_HEADER_PREFIX, &list);
> + if (status)
> + return status;
> +
> + for (; notmuch_config_list_valid (list); notmuch_config_list_move_to_next (list)) {
> +
> + prefix_t query_field;
> +
> + const char *key = notmuch_config_list_key (list)
> + + sizeof (CONFIG_HEADER_PREFIX) - 1;
> +
> + _notmuch_string_map_append (notmuch->user_prefix,
> + key,
> + _user_prefix (notmuch, key));
> +
> + _notmuch_string_map_append (notmuch->user_header,
> + key,
> + notmuch_config_list_value (list));
> +
> + query_field.name = talloc_strdup (notmuch, key);
> + query_field.prefix = _user_prefix (notmuch, key);
> + query_field.flags = NOTMUCH_FIELD_PROBABILISTIC
> + | NOTMUCH_FIELD_EXTERNAL;
> +
> + _setup_query_field_default (&query_field, notmuch);
> + }
> +
> + notmuch_config_list_destroy (list);
> +
> + return NOTMUCH_STATUS_SUCCESS;
> +}
> --
> 2.29.2
> _______________________________________________
> notmuch mailing list -- notmuch@notmuchmail.org
> To unsubscribe send an email to notmuch-leave@notmuchmail.org
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH 3/6] lib: factor out prefix related code to its own file
2020-12-20 15:36 ` Tomi Ollila
@ 2020-12-20 20:03 ` David Bremner
0 siblings, 0 replies; 11+ messages in thread
From: David Bremner @ 2020-12-20 20:03 UTC (permalink / raw)
To: Tomi Ollila, notmuch
Tomi Ollila <tomi.ollila@iki.fi> writes:
>
> Good stuff! is this extra line above intentional ?
>
> (otherwise I did not find anything else, but I may have
> got tired looking through the series ;/)
>
> Tomi
Nope, good catch. Dropped the extra whitespace in git.
d
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: v2 preliminaries for merged config
2020-12-20 12:10 v2 preliminaries for merged config David Bremner
` (5 preceding siblings ...)
2020-12-20 12:10 ` [PATCH 6/6] lib: factor out notmuch_database_open* related code to own file David Bremner
@ 2020-12-23 23:50 ` David Bremner
6 siblings, 0 replies; 11+ messages in thread
From: David Bremner @ 2020-12-23 23:50 UTC (permalink / raw)
To: notmuch
David Bremner <david@tethera.net> writes:
> This is a respin of id:20200812224931.3611801-1-david@tethera.net,
> rebased against master and with one typo in a commit message
> fixed.
>
Series applied to master. I also cherry-picked to 43ba5ed7ec (delay
setting talloc destructor) to release to be part of the next bugfix
release.
d
^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2020-12-23 23:50 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2020-12-20 12:10 v2 preliminaries for merged config David Bremner
2020-12-20 12:10 ` [PATCH 1/6] test: use keys with group 'test' in T590-libconfig David Bremner
2020-12-20 12:10 ` [PATCH 2/6] lib: factor out feature name related code David Bremner
2020-12-20 12:10 ` [PATCH 3/6] lib: factor out prefix related code to its own file David Bremner
2020-12-20 15:36 ` Tomi Ollila
2020-12-20 20:03 ` David Bremner
2020-12-20 12:10 ` [PATCH 4/6] lib/config: delay setting talloc destructor David Bremner
2020-12-20 12:10 ` [PATCH 5/6] test: add regression test for searching with alternate config David Bremner
2020-12-20 12:10 ` [PATCH 6/6] lib: factor out notmuch_database_open* related code to own file David Bremner
2020-12-23 23:50 ` v2 preliminaries for merged config David Bremner
-- strict thread matches above, loose matches on Subject: below --
2020-08-12 22:49 David Bremner
2020-08-12 22:49 ` [PATCH 1/6] test: use keys with group 'test' in T590-libconfig David Bremner
Code repositories for project(s) associated with this public inbox
https://yhetil.org/notmuch.git/
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).