diff options
author | Thomas Haller <thaller@redhat.com> | 2018-05-03 10:33:10 +0200 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2020-03-16 13:46:33 +0100 |
commit | 4bbdfd89c72c638b3645216857a991dda23d4fc0 (patch) | |
tree | d89b749438ed721b49bd5b24158133b6af24ecf6 | |
parent | c3bfd57c699ce69e7cacf04273b199fcb2acf5ef (diff) | |
download | NetworkManager-4bbdfd89c72c638b3645216857a991dda23d4fc0.tar.gz |
cli: allow marking NMMetaAbstractInfo to be excluded from get-all-fields
nmcli allows to select output fields with the --fields option.
Thereby, it recognizes the special names "all" and "common".
"all" is clear, however, for "common" we currently implement by letting
the caller replace the "common" string with a preselected list of fields,
for example
»···if (!nmc->required_fields || strcasecmp (nmc->required_fields, "common") == 0)
»···»···fields_str = NMC_FIELDS_DEV_SHOW_SECTIONS_COMMON;
Note how the list of fields is parsed by parse_output_fields() and
indirectly nm_meta_selection_create_parse_list(). However, currently
"common" is treated special, and pre-parsed outside of
create-parse-list(). That means, we cannot do something like
nmcli -f GENERAL,WIFI-PROPERTIES.COMMON device show wlan0
Allow the field descriptions to indicate themself whether they
should be included in "common" or not.
This will allow nm_meta_selection_create_parse_list() to do the parsing.
-rw-r--r-- | clients/cli/utils.c | 50 | ||||
-rw-r--r-- | clients/cli/utils.h | 27 | ||||
-rw-r--r-- | clients/common/nm-meta-setting-access.c | 205 | ||||
-rw-r--r-- | clients/common/nm-meta-setting-access.h | 9 | ||||
-rw-r--r-- | clients/common/nm-meta-setting-desc.h | 3 |
5 files changed, 269 insertions, 25 deletions
diff --git a/clients/cli/utils.c b/clients/cli/utils.c index d8524c55a1..cb946c93b9 100644 --- a/clients/cli/utils.c +++ b/clients/cli/utils.c @@ -38,6 +38,24 @@ _meta_type_nmc_generic_info_get_name (const NMMetaAbstractInfo *abstract_info, g return info->name; } +static gboolean +_meta_type_nmc_generic_info_included_in_common (const NMMetaAbstractInfo *abstract_info, + int *out_order, + gboolean *out_is_common_parent) +{ + const NmcMetaGenericInfo *info = (const NmcMetaGenericInfo *) abstract_info; + + NM_SET_OUT (out_is_common_parent, info->is_common_parent); + + if (info->common_priority < 0) { + nm_assert (info->common_priority == -1); + NM_SET_OUT (out_order, 0); + return FALSE; + } + NM_SET_OUT (out_order, info->common_priority); + return TRUE; +} + static const NMMetaAbstractInfo *const* _meta_type_nmc_generic_info_get_nested (const NMMetaAbstractInfo *abstract_info, guint *out_len, @@ -99,10 +117,11 @@ _meta_type_nmc_generic_info_get_fcn (const NMMetaAbstractInfo *abstract_info, } const NMMetaType nmc_meta_type_generic_info = { - .type_name = "nmc-generic-info", - .get_name = _meta_type_nmc_generic_info_get_name, - .get_nested = _meta_type_nmc_generic_info_get_nested, - .get_fcn = _meta_type_nmc_generic_info_get_fcn, + .type_name = "nmc-generic-info", + .get_name = _meta_type_nmc_generic_info_get_name, + .included_in_common = _meta_type_nmc_generic_info_included_in_common, + .get_nested = _meta_type_nmc_generic_info_get_nested, + .get_fcn = _meta_type_nmc_generic_info_get_fcn, }; /*****************************************************************************/ @@ -672,12 +691,13 @@ _output_selection_append (GArray *cols, .self_idx = col_idx, .is_leaf = TRUE, }; + g_array_append_val (cols, col); } - nested = nm_meta_abstract_info_get_nested (selection_item->info, NULL, &nested_to_free); - if (selection_item->sub_selection) { + nested = nm_meta_abstract_info_get_nested (selection_item->info, TRUE, NULL, &nested_to_free); + if (!nested) { gs_free char *allowed_fields = NULL; @@ -685,7 +705,7 @@ _output_selection_append (GArray *cols, const NMMetaSelectionItem *si; si = g_array_index (cols, PrintDataCol, parent_idx).selection_item; - allowed_fields = nm_meta_abstract_info_get_nested_names_str (si->info, si->self_selection); + allowed_fields = nm_meta_abstract_info_get_nested_names_str (si->info, TRUE, si->self_selection); } if (!allowed_fields) { g_set_error (error, NMCLI_ERROR, 1, _("invalid field '%s%s%s'; no such field"), @@ -705,11 +725,17 @@ _output_selection_append (GArray *cols, if (!selection) return FALSE; nm_assert (selection->num == 1); - } else if (nested) { - selection = nm_meta_selection_create_all (nested); - nm_assert (selection && selection->num > 0); - } else - selection = NULL; + } else { + nested = nm_meta_abstract_info_get_nested (selection_item->info, + FALSE, + NULL, + &nested_to_free); + if (nested) { + selection = nm_meta_selection_create_all (nested); + nm_assert (selection && selection->num > 0); + } else + selection = NULL; + } if (selection) { g_ptr_array_add (gfree_keeper, selection); diff --git a/clients/cli/utils.h b/clients/cli/utils.h index e699a641b6..d7241dfae7 100644 --- a/clients/cli/utils.h +++ b/clients/cli/utils.h @@ -253,6 +253,33 @@ struct _NmcMetaGenericInfo { gpointer *out_to_free gconstpointer (*get_fcn) (NMC_META_GENERIC_INFO_GET_FCN_ARGS); + + bool is_common_parent:1; + + /* @common_priority is used for implementing nm_meta_abstract_info_included_in_common(). + * + * Included-in-common returns two separate values: + * - whether the property is included when requesting only common fields ("common" vs. "all") + * - the sort order, in which the fields are to be sorted in the common + * case (note, that the sort order only matters when requesting "common" fields, + * because for requesting "all" fields, the order is implicitly determined by + * what nm_meta_abstract_info_get_nested() returns. + * + * Hence, to declare a field that is returned during "all" request, + * but not for a "common" request, set @common_priority to -1. + * + * To configure a field that is returned both for "all" and "common" + * requests, set @common_priority to a non-negative integer. + * Optionally, you may use the positive integer range to sort the + * values according their priority (when requesting "common" fields). + * + * So, by default, don't do anything. In this case, @common_priority + * will be zero which means to return it both for "common" and "all" + * request, and also all fields may have the same priority of zero, + * so the sort order for "common" is identical to "all" (since + * all have the same priority and we use a stable sort). + */ + int common_priority; }; #define NMC_META_GENERIC(n, ...) \ diff --git a/clients/common/nm-meta-setting-access.c b/clients/common/nm-meta-setting-access.c index 1167b55570..e706089cfd 100644 --- a/clients/common/nm-meta-setting-access.c +++ b/clients/common/nm-meta-setting-access.c @@ -191,8 +191,159 @@ nm_meta_abstract_info_get_name (const NMMetaAbstractInfo *abstract_info, gboolea return n; } +gboolean +nm_meta_abstract_info_included_in_common (const NMMetaAbstractInfo *abstract_info, + int *out_order, + gboolean *out_is_common_parent) +{ + int order = 0; + gboolean res; + + nm_assert (abstract_info); + nm_assert (abstract_info->meta_type); + + if (!abstract_info->meta_type->included_in_common) { + NM_SET_OUT (out_order, 0); + NM_SET_OUT (out_is_common_parent, FALSE); + return TRUE; + } + + res = abstract_info->meta_type->included_in_common (abstract_info, &order, out_is_common_parent); + + /* For values that are not included in "common", their order is ignored + * because for the "all" request we don't specially sort the fields. + * + * For infos that are included in "common" fields, their order matters. + * Enforce that the callee sets a non-negative sort order. */ + nm_assert ( (!res && order == 0) + || ( res && order >= 0)); + NM_SET_OUT (out_order, order); + return res; +} + +typedef struct { + const NMMetaAbstractInfo *info; + int order; +} SelectIncludedInCommonData; + +static int +_select_included_in_common_cmp (gconstpointer pa, gconstpointer pb, gpointer user_data) +{ + const SelectIncludedInCommonData *a = pa; + const SelectIncludedInCommonData *b = pb; + + NM_CMP_DIRECT (a->order, b->order); + return 0; +} + +static const NMMetaAbstractInfo *const* +nm_meta_abstract_infos_select_included_in_common (const NMMetaAbstractInfo *const*abstract_infos, + gssize in_len, + guint *out_len, + gpointer *out_to_free) +{ + guint l = 0; + gs_free gpointer f = NULL; + gs_free SelectIncludedInCommonData *infos_common = NULL; + guint i, j; + + if (in_len < 0) + l = NM_PTRARRAY_LEN (abstract_infos); + else { + nm_assert (in_len < G_MAXUINT); + l = in_len; + } + + if (l == 0) { + NM_SET_OUT (out_len, 0); + *out_to_free = NULL; + return NULL; + } + + j = 0; + for (i = 0; i < l; i++) { + int order; + gboolean included_in_common; + gboolean is_common_parent; + + included_in_common = nm_meta_abstract_info_included_in_common (abstract_infos[i], &order, &is_common_parent); + + if ( !infos_common + && (included_in_common || is_common_parent) + && order == 0) { + /* it's included and we didn't get find a value that is not included. + * Maybe we don't need to allocate an auxilary buffer after all... */ + j++; + continue; + } + + if (!infos_common) { + /* OK, we need to clone (and sort) the list. First, copy the existing + * items. */ + infos_common = g_new (SelectIncludedInCommonData, l); + for (j = 0; j < i; j++) { + infos_common[j].info = abstract_infos[j]; + infos_common[j].order = 0; + } + } + + if (included_in_common || is_common_parent) { + infos_common[j].info = abstract_infos[i]; + infos_common[j].order = order; + j++; + } + } + + if (j == 0) { + NM_SET_OUT (out_len, 0); + *out_to_free = NULL; + return NULL; + } + + if (infos_common) { + const NMMetaAbstractInfo **result; + + if (j > 1) { + g_qsort_with_data (infos_common, + j, + sizeof (SelectIncludedInCommonData), + _select_included_in_common_cmp, + NULL); + } + +#if NM_MORE_ASSERTS + /* there are two options: either the type information does not + * define any order (meaning, all order numbers are zero, and the "common" order + * is identical to "all". + * Or, the implementation sets them all to unique, positive numbers. + * + * Assert for that. */ + for (i = 1; i < j; i++) { + if (infos_common[0].order == 0) + nm_assert (infos_common[i].order == 0); + else + nm_assert (infos_common[i - 1].order < infos_common[i].order); + } +#endif + + result = g_new (const NMMetaAbstractInfo *, j + 1); + for (i = 0; i < j; i++) + result[i] = infos_common[i].info; + result[i] = NULL; + + NM_SET_OUT (out_len, j); + *out_to_free = result; + return result; + } + + NM_SET_OUT (out_len, l); + *out_to_free = NULL; + return abstract_infos; +} + const NMMetaAbstractInfo *const* nm_meta_abstract_info_get_nested (const NMMetaAbstractInfo *abstract_info, + gboolean include_all /* or only those included_in_common */, guint *out_len, gpointer *nested_to_free) { @@ -204,16 +355,44 @@ nm_meta_abstract_info_get_nested (const NMMetaAbstractInfo *abstract_info, nm_assert (abstract_info->meta_type); nm_assert (nested_to_free && !*nested_to_free); - if (abstract_info->meta_type->get_nested) { - nested = abstract_info->meta_type->get_nested (abstract_info, &l, &f); - nm_assert (NM_PTRARRAY_LEN (nested) == l); - nm_assert (!f || nested == f); - if (nested && nested[0]) { - NM_SET_OUT (out_len, l); - *nested_to_free = g_steal_pointer (&f); - return nested; + if (!abstract_info->meta_type->get_nested) + goto out_empty; + + nested = abstract_info->meta_type->get_nested (abstract_info, &l, &f); + nm_assert (NM_PTRARRAY_LEN (nested) == l); + nm_assert (!f || nested == f); + if (l == 0) + goto out_empty; + + if (!include_all) { + const NMMetaAbstractInfo *const*nested_common; + gpointer f2 = NULL; + + nested_common = nm_meta_abstract_infos_select_included_in_common (nested, l, &l, &f2); + nm_assert (NM_PTRARRAY_LEN (nested_common) == l); + + if (l == 0) { + nm_assert (!f2); + nm_assert (!nested_common); + goto out_empty; + } + + nm_assert (nested_common); + if (nested_common == f2) { + g_free (f); + f = g_steal_pointer (&f2); + nested = nested_common; + } else { + nm_assert (!f2); + nm_assert (nested_common == nested); } } + + NM_SET_OUT (out_len, l); + *nested_to_free = g_steal_pointer (&f); + return nested; + +out_empty: NM_SET_OUT (out_len, 0); return NULL; } @@ -346,12 +525,14 @@ nm_meta_abstract_info_complete (const NMMetaAbstractInfo *abstract_info, /*****************************************************************************/ char * -nm_meta_abstract_info_get_nested_names_str (const NMMetaAbstractInfo *abstract_info, const char *name_prefix) +nm_meta_abstract_info_get_nested_names_str (const NMMetaAbstractInfo *abstract_info, + gboolean include_all /* or only those included_in_common */, + const char *name_prefix) { gs_free gpointer nested_to_free = NULL; const NMMetaAbstractInfo *const*nested; - nested = nm_meta_abstract_info_get_nested (abstract_info, NULL, &nested_to_free); + nested = nm_meta_abstract_info_get_nested (abstract_info, include_all, NULL, &nested_to_free); if (!nested) return NULL; @@ -474,7 +655,7 @@ _output_selection_select_one (const NMMetaAbstractInfo *const* fields_array, break; } - nested = nm_meta_abstract_info_get_nested (fi, NULL, &nested_to_free); + nested = nm_meta_abstract_info_get_nested (fi, TRUE, NULL, &nested_to_free); if (nested) { for (j = 0; nested[j]; nested++) { if (g_ascii_strcasecmp (right, nm_meta_abstract_info_get_name (nested[j], FALSE)) == 0) { @@ -504,7 +685,7 @@ not_found: p = g_strdup_printf ("%s.%s", fields_prefix, nm_meta_abstract_info_get_name (fields_array_failure, FALSE)); } - allowed_fields = nm_meta_abstract_info_get_nested_names_str (fields_array_failure, p); + allowed_fields = nm_meta_abstract_info_get_nested_names_str (fields_array_failure, TRUE, p); } else allowed_fields = nm_meta_abstract_infos_get_names_str (fields_array, NULL); diff --git a/clients/common/nm-meta-setting-access.h b/clients/common/nm-meta-setting-access.h index 543b51fc43..5e787e70cd 100644 --- a/clients/common/nm-meta-setting-access.h +++ b/clients/common/nm-meta-setting-access.h @@ -35,7 +35,12 @@ const NMMetaSettingInfoEditor *const*nm_meta_setting_infos_editor_p (void); const char *nm_meta_abstract_info_get_name (const NMMetaAbstractInfo *abstract_info, gboolean for_header); +gboolean nm_meta_abstract_info_included_in_common (const NMMetaAbstractInfo *abstract_info, + int *out_order, + gboolean *out_is_common_parent); + const NMMetaAbstractInfo *const*nm_meta_abstract_info_get_nested (const NMMetaAbstractInfo *abstract_info, + gboolean include_all, guint *out_len, gpointer *nested_to_free); @@ -60,7 +65,9 @@ const char *const*nm_meta_abstract_info_complete (const NMMetaAbstractInfo *abst /*****************************************************************************/ -char *nm_meta_abstract_info_get_nested_names_str (const NMMetaAbstractInfo *abstract_info, const char *name_prefix); +char *nm_meta_abstract_info_get_nested_names_str (const NMMetaAbstractInfo *abstract_info, + gboolean include_all, + const char *name_prefix); char *nm_meta_abstract_infos_get_names_str (const NMMetaAbstractInfo *const*fields_array, const char *name_prefix); /*****************************************************************************/ diff --git a/clients/common/nm-meta-setting-desc.h b/clients/common/nm-meta-setting-desc.h index c728a1502c..c528d9220d 100644 --- a/clients/common/nm-meta-setting-desc.h +++ b/clients/common/nm-meta-setting-desc.h @@ -428,6 +428,9 @@ struct _NMMetaType { const char *type_name; const char *(*get_name) (const NMMetaAbstractInfo *abstract_info, gboolean for_header); + gboolean (*included_in_common) (const NMMetaAbstractInfo *abstract_info, + int *out_order, + gboolean *out_is_common_parent); const NMMetaAbstractInfo *const*(*get_nested) (const NMMetaAbstractInfo *abstract_info, guint *out_len, gpointer *out_to_free); |