mirror of
https://github.com/morgan9e/systemd
synced 2026-04-15 00:47:10 +09:00
format-table: allow to explicitly override JSON field names
In some cases it's useful to explicitly generate the JSON field names to generate for table columns, instead of auto-mangling them from table header names that are intended for human consumption. This adds the infra and a test for it. It's intended to be used by #20544, for the first column, which in text mode should have an empty header field, but have an explicit name in json output mode.
This commit is contained in:
committed by
Luca Boccassi
parent
0d5765f7af
commit
b03803f0dc
@@ -145,6 +145,9 @@ struct Table {
|
||||
size_t *sort_map; /* The columns to order rows by, in order of preference. */
|
||||
size_t n_sort_map;
|
||||
|
||||
char **json_fields;
|
||||
size_t n_json_fields;
|
||||
|
||||
bool *reverse_map;
|
||||
|
||||
char *empty_string;
|
||||
@@ -241,6 +244,11 @@ Table *table_unref(Table *t) {
|
||||
free(t->reverse_map);
|
||||
free(t->empty_string);
|
||||
|
||||
for (size_t i = 0; i < t->n_json_fields; i++)
|
||||
free(t->json_fields[i]);
|
||||
|
||||
free(t->json_fields);
|
||||
|
||||
return mfree(t);
|
||||
}
|
||||
|
||||
@@ -2608,6 +2616,12 @@ static char* string_to_json_field_name(const char *f) {
|
||||
return c;
|
||||
}
|
||||
|
||||
static const char *table_get_json_field_name(Table *t, size_t column) {
|
||||
assert(t);
|
||||
|
||||
return column < t->n_json_fields ? t->json_fields[column] : NULL;
|
||||
}
|
||||
|
||||
int table_to_json(Table *t, JsonVariant **ret) {
|
||||
JsonVariant **rows = NULL, **elements = NULL;
|
||||
_cleanup_free_ size_t *sorted = NULL;
|
||||
@@ -2651,26 +2665,36 @@ int table_to_json(Table *t, JsonVariant **ret) {
|
||||
|
||||
for (size_t j = 0; j < display_columns; j++) {
|
||||
_cleanup_free_ char *mangled = NULL;
|
||||
const char *formatted;
|
||||
TableData *d;
|
||||
const char *n;
|
||||
size_t c;
|
||||
|
||||
assert_se(d = t->data[t->display_map ? t->display_map[j] : j]);
|
||||
c = t->display_map ? t->display_map[j] : j;
|
||||
|
||||
/* Field names must be strings, hence format whatever we got here as a string first */
|
||||
formatted = table_data_format(t, d, true, SIZE_MAX, NULL);
|
||||
if (!formatted) {
|
||||
r = -ENOMEM;
|
||||
goto finish;
|
||||
/* Use explicitly set JSON field name, if we have one. Otherwise mangle the column field value. */
|
||||
n = table_get_json_field_name(t, c);
|
||||
if (!n) {
|
||||
const char *formatted;
|
||||
TableData *d;
|
||||
|
||||
assert_se(d = t->data[c]);
|
||||
|
||||
/* Field names must be strings, hence format whatever we got here as a string first */
|
||||
formatted = table_data_format(t, d, true, SIZE_MAX, NULL);
|
||||
if (!formatted) {
|
||||
r = -ENOMEM;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
/* Arbitrary strings suck as field names, try to mangle them into something more suitable hence */
|
||||
mangled = string_to_json_field_name(formatted);
|
||||
if (!mangled) {
|
||||
r = -ENOMEM;
|
||||
goto finish;
|
||||
}
|
||||
n = mangled;
|
||||
}
|
||||
|
||||
/* Arbitrary strings suck as field names, try to mangle them into something more suitable hence */
|
||||
mangled = string_to_json_field_name(formatted);
|
||||
if (!mangled) {
|
||||
r = -ENOMEM;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
r = json_variant_new_string(elements + j*2, mangled);
|
||||
r = json_variant_new_string(elements + j*2, n);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
}
|
||||
@@ -2771,3 +2795,30 @@ int table_print_with_pager(
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int table_set_json_field_name(Table *t, size_t column, const char *name) {
|
||||
int r;
|
||||
|
||||
assert(t);
|
||||
|
||||
if (name) {
|
||||
size_t m;
|
||||
|
||||
m = MAX(column + 1, t->n_json_fields);
|
||||
if (!GREEDY_REALLOC0(t->json_fields, m))
|
||||
return -ENOMEM;
|
||||
|
||||
r = free_and_strdup(t->json_fields + column, name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
t->n_json_fields = m;
|
||||
return r;
|
||||
} else {
|
||||
if (column >= t->n_json_fields)
|
||||
return 0;
|
||||
|
||||
t->json_fields[column] = mfree(t->json_fields[column]);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,6 +130,8 @@ int table_print_json(Table *t, FILE *f, JsonFormatFlags json_flags);
|
||||
|
||||
int table_print_with_pager(Table *t, JsonFormatFlags json_format_flags, PagerFlags pager_flags, bool show_header);
|
||||
|
||||
int table_set_json_field_name(Table *t, size_t column, const char *name);
|
||||
|
||||
#define table_log_add_error(r) \
|
||||
log_error_errno(r, "Failed to add cell(s) to table: %m")
|
||||
|
||||
|
||||
@@ -366,6 +366,41 @@ static void test_strv_wrapped(void) {
|
||||
formatted = mfree(formatted);
|
||||
}
|
||||
|
||||
static void test_json(void) {
|
||||
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL, *w = NULL;
|
||||
_cleanup_(table_unrefp) Table *t = NULL;
|
||||
|
||||
log_info("/* %s */", __func__);
|
||||
|
||||
assert_se(t = table_new("foo bar", "quux", "piep miau"));
|
||||
assert_se(table_set_json_field_name(t, 2, "zzz") >= 0);
|
||||
|
||||
assert_se(table_add_many(t,
|
||||
TABLE_STRING, "v1",
|
||||
TABLE_UINT64, UINT64_C(4711),
|
||||
TABLE_BOOLEAN, true) >= 0);
|
||||
|
||||
assert_se(table_add_many(t,
|
||||
TABLE_STRV, STRV_MAKE("a", "b", "c"),
|
||||
TABLE_EMPTY,
|
||||
TABLE_MODE, 0755) >= 0);
|
||||
|
||||
assert_se(table_to_json(t, &v) >= 0);
|
||||
|
||||
assert_se(json_build(&w,
|
||||
JSON_BUILD_ARRAY(
|
||||
JSON_BUILD_OBJECT(
|
||||
JSON_BUILD_PAIR("foo_bar", JSON_BUILD_STRING("v1")),
|
||||
JSON_BUILD_PAIR("quux", JSON_BUILD_UNSIGNED(4711)),
|
||||
JSON_BUILD_PAIR("zzz", JSON_BUILD_BOOLEAN(true))),
|
||||
JSON_BUILD_OBJECT(
|
||||
JSON_BUILD_PAIR("foo_bar", JSON_BUILD_STRV(STRV_MAKE("a", "b", "c"))),
|
||||
JSON_BUILD_PAIR("quux", JSON_BUILD_NULL),
|
||||
JSON_BUILD_PAIR("zzz", JSON_BUILD_UNSIGNED(0755))))) >= 0);
|
||||
|
||||
assert_se(json_variant_equal(v, w));
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
_cleanup_(table_unrefp) Table *t = NULL;
|
||||
_cleanup_free_ char *formatted = NULL;
|
||||
@@ -509,6 +544,7 @@ int main(int argc, char *argv[]) {
|
||||
test_multiline();
|
||||
test_strv();
|
||||
test_strv_wrapped();
|
||||
test_json();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user