"rhizome add file" manifest field=value varargs

Now a new manifest can be formed, and an existing manifest modified, by
giving "field=value" or "!field" command-line arguments at the end of
the "rhizome add file" command (after the <bsk> argument).

This makes it easier to script rhizome operations.
This commit is contained in:
Andrew Bettison 2014-11-19 13:26:50 +10:30
parent c95807b002
commit e633c0fa0a
3 changed files with 154 additions and 4 deletions

View File

@ -988,6 +988,31 @@ rhizome_manifest_parse_field(rhizome_manifest *m, const char *field_label, size_
return status;
}
/* Remove the field with the given label from the manifest.
*
* @author Andrew Bettison <andrew@servalproject.com>
*/
int rhizome_manifest_remove_field(rhizome_manifest *m, const char *field_label, size_t field_label_len)
{
if (!rhizome_manifest_field_label_is_valid(field_label, field_label_len)) {
if (config.debug.rhizome_manifest)
DEBUGF("Invalid manifest field name: %s", alloca_toprint(100, field_label, field_label_len));
return 0;
}
const char *label = alloca_strndup(field_label, field_label_len);
struct rhizome_manifest_field_descriptor *desc = NULL;
unsigned i;
for (i = 0; desc == NULL && i < NELS(rhizome_manifest_fields); ++i)
if (strcasecmp(label, rhizome_manifest_fields[i].label) == 0)
desc = &rhizome_manifest_fields[i];
if (!desc)
return rhizome_manifest_del(m, label);
if (!desc->test(m))
return 0;
desc->unset(m);
return 1;
}
/* If all essential (transport) fields are present and well formed then sets the m->finalised field
* and returns 1, otherwise returns 0.
*

View File

@ -104,7 +104,7 @@ static int app_rhizome_hash_file(const struct cli_parsed *parsed, struct cli_con
DEFINE_CMD(app_rhizome_add_file, 0,
"Add a file to Rhizome and optionally write its manifest to the given path",
"rhizome","add","file" KEYRING_PIN_OPTIONS,"[--force-new]","<author_sid>","<filepath>","[<manifestpath>]","[<bsk>]");
"rhizome","add","file" KEYRING_PIN_OPTIONS,"[--force-new]","<author_sid>","<filepath>","[<manifestpath>]","[<bsk>]","...");
DEFINE_CMD(app_rhizome_add_file, 0,
"Append content to a journal bundle",
"rhizome", "journal", "append" KEYRING_PIN_OPTIONS, "<author_sid>", "<manifestid>", "<filepath>", "[<bsk>]");
@ -134,6 +134,42 @@ static int app_rhizome_add_file(const struct cli_parsed *parsed, struct cli_cont
if (bsktext && str_to_rhizome_bsk_t(&bsk, bsktext) == -1)
return WHYF("invalid bsk: \"%s\"", bsktext);
unsigned nfields = (parsed->varargi == -1) ? 0 : parsed->argc - (unsigned)parsed->varargi;
struct field {
const char *label;
size_t labellen;
const char *value;
size_t valuelen;
}
fields[nfields];
if (nfields) {
assert(parsed->varargi >= 0);
unsigned i;
for (i = 0; i < nfields; ++i) {
struct field *field = &fields[i];
unsigned n = (unsigned)parsed->varargi + i;
assert(n < parsed->argc);
const char *arg = parsed->args[n];
size_t arglen = strlen(arg);
const char *eq;
if (arglen > 0 && arg[0] == '!') {
field->label = arg + 1;
field->labellen = arglen - 1;
field->value = NULL;
} else if ((eq = strchr(arg, '='))) {
field->label = arg;
field->labellen = eq - arg;
field->value = eq + 1;
field->valuelen = (arg + arglen) - field->value;
} else
return WHYF("invalid manifest field argument: %s", alloca_str_toprint(arg));
if (!rhizome_manifest_field_label_is_valid(field->label, field->labellen))
return WHYF("invalid manifest field label: %s", alloca_toprint(-1, field->label, field->labellen));
if (field->value && !rhizome_manifest_field_value_is_valid(field->value, field->valuelen))
return WHYF("invalid manifest field value: %s", alloca_toprint(-1, field->value, field->valuelen));
}
}
int journal = strcasecmp(parsed->args[1], "journal")==0;
if (create_serval_instance_dir() == -1)
@ -194,6 +230,43 @@ static int app_rhizome_add_file(const struct cli_parsed *parsed, struct cli_cont
goto finish;
}
if (nfields) {
unsigned i;
for (i = 0; i != nfields; ++i) {
struct field *field = &fields[i];
rhizome_manifest_remove_field(m, field->label, field->labellen);
if (field->value) {
const char *label = alloca_strndup(field->label, field->labellen);
enum rhizome_manifest_parse_status status = rhizome_manifest_parse_field(m, field->label, field->labellen, field->value, field->valuelen);
int status_ok = 0;
switch (status) {
case RHIZOME_MANIFEST_ERROR:
ret = WHY("Fatal error while updating manifest field");
goto finish;
case RHIZOME_MANIFEST_OK:
status_ok = 1;
break;
case RHIZOME_MANIFEST_SYNTAX_ERROR:
ret = WHYF("Manifest syntax error: %s=%s", label, alloca_toprint(-1, field->value, field->valuelen));
goto finish;
case RHIZOME_MANIFEST_DUPLICATE_FIELD:
abort(); // should not happen, field was removed first
case RHIZOME_MANIFEST_INVALID:
ret = WHYF("Manifest invalid field: %s=%s", label, alloca_toprint(-1, field->value, field->valuelen));
goto finish;
case RHIZOME_MANIFEST_MALFORMED:
ret = WHYF("Manifest malformed field: %s=%s", label, alloca_toprint(-1, field->value, field->valuelen));
goto finish;
case RHIZOME_MANIFEST_OVERFLOW:
ret = WHYF("Too many fields in manifest at: %s=%s", label, alloca_toprint(-1, field->value, field->valuelen));
goto finish;
}
if (!status_ok)
FATALF("status = %d", status);
}
}
}
if (bsktext) {
if (m->has_id) {
if (!rhizome_apply_bundle_secret(m, &bsk)) {

View File

@ -1,8 +1,8 @@
#!/bin/bash
# Tests for Serval rhizome operations.
# Tests for Serval rhizome command-line operations.
#
# Copyright 2012 Serval Project, Inc.
# Copyright 2012-2014 Serval Project, Inc.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
@ -107,6 +107,23 @@ test_AddManifestFieldUnsupported() {
assert_manifest_fields file1.manifest bogus=one
}
doc_AddManifestFieldUnsupportedArgs="Add with unsupported manifest field argument"
setup_AddManifestFieldUnsupportedArgs() {
setup_servald
setup_rhizome
executeOk_servald rhizome list
assert_rhizome_list
echo "A test file" >file1
echo "Another test file" >file2
}
test_AddManifestFieldUnsupportedArgs() {
executeOk_servald rhizome add file $SIDB1 file1 file1.manifest '' bogus=two
assert_stdout_add_file file1
tfw_cat -v file1.manifest
assert_manifest_complete file1.manifest
assert_manifest_fields file1.manifest bogus=two
}
doc_AddNoAuthor="Add with no author makes manifest without BK"
setup_AddNoAuthor() {
setup_servald
@ -190,6 +207,22 @@ test_AddManifest() {
assert_manifest_fields file1.manifest service=file name=wah date=12345
}
doc_AddManifestArgs="Add with minimal manifest from arguments"
setup_AddManifestArgs() {
setup_servald
setup_rhizome
executeOk_servald rhizome list
assert_rhizome_list
echo "A test file" >file1
}
test_AddManifestArgs() {
executeOk_servald rhizome add file $SIDB1 file1 file1.manifest '' name=wah date=12345
tfw_cat --stdout --stderr -v file1.manifest
assert_stdout_add_file file1 name=wah
assert_manifest_complete file1.manifest
assert_manifest_fields file1.manifest service=file name=wah date=12345
}
doc_AddEmpty="Add with empty payload"
setup_AddEmpty() {
setup_servald
@ -389,7 +422,7 @@ test_LargePayload() {
assert diff file1 file1x
}
doc_CorruptExternalBlob="A corrupted payload should fail to export"
doc_CorruptExternalBlob="Corrupted payload fails to export"
setup_CorruptExternalBlob() {
setup_servald
setup_rhizome
@ -775,6 +808,25 @@ test_AddUpdateAutoVersion() {
assert_rhizome_list --fromhere=1 file1_2 file2
}
doc_AddUpdateArgs="Update existing bundle using manifest args"
setup_AddUpdateArgs() {
setup_AddDeDuplicate
extract_manifest_id BID file1.manifest
cp file1.manifest file1_2.manifest
}
test_AddUpdateArgs() {
sleep 0.001 # Ensure that at least one millisecond has elapsed
executeOk_servald rhizome add file $SIDB1 file1_2 file1_2.manifest '' !version !filesize !filehash !date
assert_stdout_add_file file1_2 name=file1
assert_manifest_fields file1_2.manifest name=file1
extract_manifest_id BID2 file1_2.manifest
assert [ $BID = $BID2 ]
assert_manifest_newer file1.manifest file1_2.manifest
# Rhizome store contents reflect new payload.
executeOk_servald rhizome list
assert_rhizome_list --fromhere=1 file1_2 file2
}
doc_AddServiceInvalid="Add with invalid service fails"
setup_AddServiceInvalid() {
setup_servald