summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2018-05-03 10:33:10 +0200
committerThomas Haller <thaller@redhat.com>2020-03-16 13:46:33 +0100
commit4bbdfd89c72c638b3645216857a991dda23d4fc0 (patch)
treed89b749438ed721b49bd5b24158133b6af24ecf6
parentc3bfd57c699ce69e7cacf04273b199fcb2acf5ef (diff)
downloadNetworkManager-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.c50
-rw-r--r--clients/cli/utils.h27
-rw-r--r--clients/common/nm-meta-setting-access.c205
-rw-r--r--clients/common/nm-meta-setting-access.h9
-rw-r--r--clients/common/nm-meta-setting-desc.h3
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);