mirror of
https://git.notmuchmail.org/git/notmuch
synced 2024-11-21 18:38:08 +01:00
cli: optionally restore message properties from dump file
This somewhat mimics the config line parsing, except there can be arbitrarily many key value pairs, so one more level of looping is required.
This commit is contained in:
parent
b7345d277e
commit
651da30c09
3 changed files with 120 additions and 6 deletions
|
@ -50,7 +50,7 @@ Supported options for **restore** include
|
|||
format, this heuristic, based the fact that batch-tag format
|
||||
contains no parentheses, should be accurate.
|
||||
|
||||
``--include=(config|tags)``
|
||||
``--include=(config|properties|tags)``
|
||||
|
||||
Control what kind of metadata is restored.
|
||||
|
||||
|
@ -60,13 +60,20 @@ Supported options for **restore** include
|
|||
with "#@ ", followed by a space separated key-value pair.
|
||||
Both key and value are hex encoded if needed.
|
||||
|
||||
**properties**
|
||||
|
||||
Output per-message (key,value) metadata. Each line starts
|
||||
with "#= ", followed by a message id, and a space separated
|
||||
list of key=value pairs. pair. Ids, keys and values are
|
||||
hex encoded if needed.
|
||||
|
||||
**tags**
|
||||
|
||||
Output per-message metadata, namely tags. See *format* above
|
||||
for more details.
|
||||
|
||||
The default is to restore both tags and configuration
|
||||
information
|
||||
The default is to restore all available types of data. The
|
||||
option can be specified multiple times to select some subset.
|
||||
|
||||
``--input=``\ <filename>
|
||||
Read input from given file instead of stdin.
|
||||
|
|
|
@ -57,6 +57,72 @@ process_config_line (notmuch_database_t *notmuch, const char* line)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
process_properties_line (notmuch_database_t *notmuch, const char* line)
|
||||
|
||||
{
|
||||
const char *id_p, *tok;
|
||||
size_t id_len = 0, tok_len = 0;
|
||||
char *id;
|
||||
|
||||
notmuch_message_t *message = NULL;
|
||||
const char *delim = " \t\n";
|
||||
int ret = EXIT_FAILURE;
|
||||
|
||||
void *local = talloc_new (NULL);
|
||||
|
||||
id_p = strtok_len_c (line, delim, &id_len);
|
||||
id = talloc_strndup (local, id_p, id_len);
|
||||
if (hex_decode_inplace (id) != HEX_SUCCESS) {
|
||||
fprintf (stderr, "hex decoding failure on line %s\n", line);
|
||||
goto DONE;
|
||||
}
|
||||
|
||||
if (print_status_database ("notmuch restore", notmuch,
|
||||
notmuch_database_find_message (notmuch, id, &message)))
|
||||
goto DONE;
|
||||
|
||||
if (print_status_database ("notmuch restore", notmuch,
|
||||
notmuch_message_remove_all_properties (message, NULL)))
|
||||
goto DONE;
|
||||
|
||||
tok = id_p + id_len;
|
||||
|
||||
while ((tok = strtok_len_c (tok + tok_len, delim, &tok_len)) != NULL) {
|
||||
char *key, *value;
|
||||
size_t off = strcspn (tok, "=");
|
||||
if (off > tok_len) {
|
||||
fprintf (stderr, "unparsable token %s\n", tok);
|
||||
goto DONE;
|
||||
}
|
||||
|
||||
key = talloc_strndup (local, tok, off);
|
||||
value = talloc_strndup (local, tok + off + 1, tok_len - off - 1);
|
||||
|
||||
if (hex_decode_inplace (key) != HEX_SUCCESS) {
|
||||
fprintf (stderr, "hex decoding failure on key %s\n", key);
|
||||
goto DONE;
|
||||
}
|
||||
|
||||
if (hex_decode_inplace (value) != HEX_SUCCESS) {
|
||||
fprintf (stderr, "hex decoding failure on value %s\n", value);
|
||||
goto DONE;
|
||||
}
|
||||
|
||||
if (print_status_database ("notmuch restore", notmuch,
|
||||
notmuch_message_add_property (message, key, value)))
|
||||
goto DONE;
|
||||
|
||||
}
|
||||
|
||||
ret = EXIT_SUCCESS;
|
||||
|
||||
DONE:
|
||||
talloc_free (local);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static regex_t regex;
|
||||
|
||||
/* Non-zero return indicates an error in retrieving the message,
|
||||
|
@ -188,6 +254,7 @@ notmuch_restore_command (notmuch_config_t *config, int argc, char *argv[])
|
|||
{ 0, 0 } } },
|
||||
{ NOTMUCH_OPT_KEYWORD_FLAGS, &include, "include", 'I',
|
||||
(notmuch_keyword_t []){ { "config", DUMP_INCLUDE_CONFIG },
|
||||
{ "properties", DUMP_INCLUDE_PROPERTIES },
|
||||
{ "tags", DUMP_INCLUDE_TAGS} } },
|
||||
|
||||
{ NOTMUCH_OPT_STRING, &input_file_name, "input", 'i', 0 },
|
||||
|
@ -206,7 +273,7 @@ notmuch_restore_command (notmuch_config_t *config, int argc, char *argv[])
|
|||
notmuch_exit_if_unmatched_db_uuid (notmuch);
|
||||
|
||||
if (include == 0) {
|
||||
include = DUMP_INCLUDE_CONFIG | DUMP_INCLUDE_TAGS;
|
||||
include = DUMP_INCLUDE_CONFIG | DUMP_INCLUDE_PROPERTIES | DUMP_INCLUDE_TAGS;
|
||||
}
|
||||
|
||||
name_for_error = input_file_name ? input_file_name : "stdin";
|
||||
|
@ -273,13 +340,18 @@ notmuch_restore_command (notmuch_config_t *config, int argc, char *argv[])
|
|||
if (ret)
|
||||
goto DONE;
|
||||
}
|
||||
if ((include & DUMP_INCLUDE_PROPERTIES) && line_len >= 2 && line[0] == '#' && line[1] == '=') {
|
||||
ret = process_properties_line (notmuch, line + 2);
|
||||
if (ret)
|
||||
goto DONE;
|
||||
}
|
||||
|
||||
} while ((line_len == 0) ||
|
||||
(line[0] == '#') ||
|
||||
/* the cast is safe because we checked about for line_len < 0 */
|
||||
(strspn (line, " \t\n") == (unsigned)line_len));
|
||||
|
||||
if (! (include & DUMP_INCLUDE_TAGS)) {
|
||||
if (! ((include & DUMP_INCLUDE_TAGS) || (include & DUMP_INCLUDE_PROPERTIES))) {
|
||||
ret = EXIT_SUCCESS;
|
||||
goto DONE;
|
||||
}
|
||||
|
@ -306,6 +378,13 @@ notmuch_restore_command (notmuch_config_t *config, int argc, char *argv[])
|
|||
talloc_free (line_ctx);
|
||||
|
||||
line_ctx = talloc_new (config);
|
||||
|
||||
if ((include & DUMP_INCLUDE_PROPERTIES) && line_len >= 2 && line[0] == '#' && line[1] == '=') {
|
||||
ret = process_properties_line (notmuch, line + 2);
|
||||
if (ret)
|
||||
goto DONE;
|
||||
}
|
||||
|
||||
if (input_format == DUMP_FORMAT_SUP) {
|
||||
ret = parse_sup_line (line_ctx, line, &query_string, tag_ops);
|
||||
} else {
|
||||
|
@ -344,7 +423,7 @@ notmuch_restore_command (notmuch_config_t *config, int argc, char *argv[])
|
|||
break;
|
||||
|
||||
} while (! (ret = gz_getline (line_ctx, &line, &line_len, input)));
|
||||
|
||||
|
||||
|
||||
/* EOF is normal loop termination condition, UTIL_SUCCESS is
|
||||
* impossible here */
|
||||
|
|
|
@ -209,4 +209,32 @@ EOF
|
|||
notmuch dump | grep '^#=' > OUTPUT
|
||||
test_expect_equal_file PROPERTIES OUTPUT
|
||||
|
||||
|
||||
test_begin_subtest "restore missing message property (single line)"
|
||||
notmuch dump | grep '^#=' > BEFORE1
|
||||
cat c_head - c_tail <<'EOF' | test_C ${MAIL_DIR}
|
||||
EXPECT0(notmuch_message_remove_property (message, "testkey1", "bob"));
|
||||
EOF
|
||||
notmuch restore < BEFORE1
|
||||
notmuch dump | grep '^#=' > OUTPUT
|
||||
test_expect_equal_file PROPERTIES OUTPUT
|
||||
|
||||
|
||||
test_begin_subtest "restore missing message property (full dump)"
|
||||
notmuch dump > BEFORE2
|
||||
cat c_head - c_tail <<'EOF' | test_C ${MAIL_DIR}
|
||||
EXPECT0(notmuch_message_remove_property (message, "testkey1", "bob"));
|
||||
EOF
|
||||
notmuch restore < BEFORE2
|
||||
notmuch dump | grep '^#=' > OUTPUT
|
||||
test_expect_equal_file PROPERTIES OUTPUT
|
||||
|
||||
test_begin_subtest "restore clear extra message property"
|
||||
cat c_head - c_tail <<'EOF' | test_C ${MAIL_DIR}
|
||||
EXPECT0(notmuch_message_add_property (message, "testkey1", "charles"));
|
||||
EOF
|
||||
notmuch restore < BEFORE2
|
||||
notmuch dump | grep '^#=' > OUTPUT
|
||||
test_expect_equal_file PROPERTIES OUTPUT
|
||||
|
||||
test_done
|
||||
|
|
Loading…
Reference in a new issue