From a498a8fbb6c1835c083053d5de5730e9ce06d1b7 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Wed, 12 Apr 2017 11:05:02 +0200 Subject: WIP: cli: move nmc_setting_get_valid_properties It looks at GObject properties to determine which properties are valid. That is not correct, because certain properties are not native GObject properties: - vpn.data - bond.options - user.data Instead, that is why we have meta data. --- clients/cli/connections.c | 33 +++- clients/cli/settings.c | 31 ---- clients/cli/settings.h | 1 - clients/common/nm-meta-setting-access.c | 296 +++++++++++++++++++++++++++++--- clients/common/nm-meta-setting-access.h | 19 +- clients/common/nm-meta-setting-desc.c | 217 +++++++++++++++++++++++ clients/common/nm-meta-setting-desc.h | 41 +++++ clients/common/tests/test-general.c | 2 +- 8 files changed, 576 insertions(+), 64 deletions(-) diff --git a/clients/cli/connections.c b/clients/cli/connections.c index 48454099f2..d65dbcc6a9 100644 --- a/clients/cli/connections.c +++ b/clients/cli/connections.c @@ -3214,6 +3214,31 @@ is_setting_valid (NMConnection *connection, const NMMetaSettingValidPartItem *co return nm_connection_get_setting_by_name (connection, setting_name); } +static char ** +_get_valid_properties (NMSetting *setting) +{ + char **valid_props = NULL; + GParamSpec **props, **iter; + guint num; + int i; + + /* Iterate through properties */ + i = 0; + props = g_object_class_list_properties (G_OBJECT_GET_CLASS (G_OBJECT (setting)), &num); + valid_props = g_malloc0 (sizeof (char*) * (num + 1)); + for (iter = props; iter && *iter; iter++) { + const char *key_name = g_param_spec_get_name (*iter); + + /* Add all properties except for "name" that is non-editable */ + if (g_strcmp0 (key_name, "name") != 0) + valid_props[i++] = g_strdup (key_name); + } + valid_props[i] = NULL; + g_free (props); + + return valid_props; +} + static char * is_property_valid (NMSetting *setting, const char *property, GError **error) { @@ -3221,7 +3246,7 @@ is_property_valid (NMSetting *setting, const char *property, GError **error) const char *prop_name; char *ret; - valid_props = nmc_setting_get_valid_properties (setting); + valid_props = _get_valid_properties (setting); prop_name = nmc_string_is_valid (property, (const char **) valid_props, error); ret = g_strdup (prop_name); g_strfreev (valid_props); @@ -5052,7 +5077,7 @@ gen_property_names (const char *text, int state) } if (setting) { - valid_props = nmc_setting_get_valid_properties (setting); + valid_props = _get_valid_properties (setting); ret = nmc_rl_gen_func_basic (text, state, (const char **) valid_props); } @@ -6222,7 +6247,7 @@ print_setting_description (NMSetting *setting) char **all_props; int i; - all_props = nmc_setting_get_valid_properties (setting); + all_props = _get_valid_properties (setting); g_print (("<<< %s >>>\n"), nm_setting_get_name (setting)); for (i = 0; all_props && all_props[i]; i++) print_property_description (setting, all_props[i]); @@ -6695,7 +6720,7 @@ menu_switch_to_level1 (NmcColorOption color_option, "nmcli %s> ", setting_name); menu_ctx->curr_setting = setting; g_strfreev (menu_ctx->valid_props); - menu_ctx->valid_props = nmc_setting_get_valid_properties (menu_ctx->curr_setting); + menu_ctx->valid_props = _get_valid_properties (menu_ctx->curr_setting); g_free (menu_ctx->valid_props_str); menu_ctx->valid_props_str = g_strjoinv (", ", menu_ctx->valid_props); } diff --git a/clients/cli/settings.c b/clients/cli/settings.c index 0f18ec7f67..939f82a91c 100644 --- a/clients/cli/settings.c +++ b/clients/cli/settings.c @@ -646,37 +646,6 @@ nmc_setting_remove_property_option (NMSetting *setting, return TRUE; } -/* - * Get valid property names for a setting. - * - * Returns: string array with the properties or NULL on failure. - * The returned value should be freed with g_strfreev() - */ -char ** -nmc_setting_get_valid_properties (NMSetting *setting) -{ - char **valid_props = NULL; - GParamSpec **props, **iter; - guint num; - int i; - - /* Iterate through properties */ - i = 0; - props = g_object_class_list_properties (G_OBJECT_GET_CLASS (G_OBJECT (setting)), &num); - valid_props = g_malloc0 (sizeof (char*) * (num + 1)); - for (iter = props; iter && *iter; iter++) { - const char *key_name = g_param_spec_get_name (*iter); - - /* Add all properties except for "name" that is non-editable */ - if (g_strcmp0 (key_name, "name") != 0) - valid_props[i++] = g_strdup (key_name); - } - valid_props[i] = NULL; - g_free (props); - - return valid_props; -} - const char *const* nmc_setting_get_property_allowed_values (NMSetting *setting, const char *prop, char ***out_to_free) { diff --git a/clients/cli/settings.h b/clients/cli/settings.h index 7dad622bf8..88b715f0a7 100644 --- a/clients/cli/settings.h +++ b/clients/cli/settings.h @@ -33,7 +33,6 @@ void nmc_setting_proxy_connect_handlers (NMSettingProxy *setting); void nmc_setting_wireless_connect_handlers (NMSettingWireless *setting); void nmc_setting_connection_connect_handlers (NMSettingConnection *setting, NMConnection *connection); -char **nmc_setting_get_valid_properties (NMSetting *setting); char *nmc_setting_get_property_desc (NMSetting *setting, const char *prop); const char *const*nmc_setting_get_property_allowed_values (NMSetting *setting, const char *prop, char ***out_to_free); char *nmc_setting_get_property (NMSetting *setting, diff --git a/clients/common/nm-meta-setting-access.c b/clients/common/nm-meta-setting-access.c index 7a0cefde9d..ebaf6e7ebc 100644 --- a/clients/common/nm-meta-setting-access.c +++ b/clients/common/nm-meta-setting-access.c @@ -21,36 +21,67 @@ #include "nm-meta-setting-access.h" +#include + /*****************************************************************************/ const NMMetaSettingInfoEditor * -nm_meta_setting_info_editor_find_by_name (const char *setting_name, gboolean use_alias) +nm_meta_setting_info_editor_find_by_fuzzyname (const char *setting_name, gboolean use_alias, + gboolean fuzzy_match, gboolean *out_unique) { - const NMMetaSettingInfo *meta_setting_info; - const NMMetaSettingInfoEditor *setting_info; + const NMMetaSettingInfoEditor *best_match = NULL; + guint found = 0; + gsize l; guint i; g_return_val_if_fail (setting_name, NULL); - meta_setting_info = nm_meta_setting_infos_by_name (setting_name); - setting_info = NULL; - if (meta_setting_info) { - nm_assert (nm_streq0 (meta_setting_info->setting_name, setting_name)); - if (meta_setting_info->meta_type < G_N_ELEMENTS (nm_meta_setting_infos_editor)) { - setting_info = &nm_meta_setting_infos_editor[meta_setting_info->meta_type]; - nm_assert (setting_info->general == meta_setting_info); + if (!*setting_name) + goto out; + + l = strlen (setting_name); + + for (i = 0; i < _NM_META_SETTING_TYPE_NUM; i++) { + const NMMetaSettingInfoEditor *si = &nm_meta_setting_infos_editor[i]; + + if (nm_streq (si->general->setting_name, setting_name)) { + NM_SET_OUT (out_unique, TRUE); + return si; } - } - if (!setting_info && use_alias) { - for (i = 0; i < _NM_META_SETTING_TYPE_NUM; i++) { - if (nm_streq0 (nm_meta_setting_infos_editor[i].alias, setting_name)) { - setting_info = &nm_meta_setting_infos_editor[i]; - break; - } + if ( fuzzy_match + && g_ascii_strncasecmp (si->general->setting_name, setting_name, l)) + goto found_fuzzy; + + if (use_alias) { + if (nm_streq0 (si->alias, setting_name)) + goto found_fuzzy; + if ( fuzzy_match + && g_ascii_strncasecmp (si->alias, setting_name, l)) + goto found_fuzzy; } + + continue; +found_fuzzy: + if (!best_match) + best_match = si; + found++; + if (found >= 2) + break; } - return setting_info; +out: + /* a non-unique match may not seem interesting at first. It is however + * because we need to distinguish between no setting-for-the-name + * (and search the property-aliases), or have-a-non-unique-match (and + * don't check proerty-aliases). */ + NM_SET_OUT (out_unique, found <= 1); + return best_match; +} + +const NMMetaSettingInfoEditor * +nm_meta_setting_info_editor_find_by_name (const char *setting_name, gboolean use_alias) +{ + return nm_meta_setting_info_editor_find_by_fuzzyname (setting_name, use_alias, FALSE, NULL); } const NMMetaSettingInfoEditor * @@ -93,21 +124,46 @@ nm_meta_setting_info_editor_find_by_setting (NMSetting *setting) } const NMMetaPropertyInfo * -nm_meta_setting_info_editor_get_property_info (const NMMetaSettingInfoEditor *setting_info, const char *property_name) +nm_meta_setting_info_editor_get_property_info (const NMMetaSettingInfoEditor *setting_info, + const char *property_name, + gboolean fuzzy_match) { + const NMMetaPropertyInfo *best_match = NULL; + gsize l; guint i; g_return_val_if_fail (setting_info, NULL); g_return_val_if_fail (property_name, NULL); + if (!property_name) + return NULL; + + if (setting_info->get_property_info) { + return setting_info->get_property_info (setting_info, + property_name, + fuzzy_match); + } + + l = strlen (property_name); + for (i = 0; i < setting_info->properties_num; i++) { - nm_assert (setting_info->properties[i]->property_name); - nm_assert (setting_info->properties[i]->setting_info == setting_info); - if (nm_streq (setting_info->properties[i]->property_name, property_name)) - return setting_info->properties[i]; + const NMMetaPropertyInfo *si = setting_info->properties[i]; + + nm_assert (si->property_name); + nm_assert (si->setting_info == setting_info); + + if (nm_streq (si->property_name, property_name)) + return si; + + if ( fuzzy_match + && g_ascii_strncasecmp (si->property_name, property_name, l)) { + if (best_match) + return NULL; + best_match = si; + } } - return NULL; + return best_match; } const NMMetaPropertyInfo * @@ -120,7 +176,7 @@ nm_meta_property_info_find_by_name (const char *setting_name, const char *proper if (!setting_info) return NULL; - property_info = nm_meta_setting_info_editor_get_property_info (setting_info, property_name); + property_info = nm_meta_setting_info_editor_get_property_info (setting_info, property_name, FALSE); if (!property_info) return NULL; @@ -138,7 +194,7 @@ nm_meta_property_info_find_by_setting (NMSetting *setting, const char *property_ setting_info = nm_meta_setting_info_editor_find_by_setting (setting); if (!setting_info) return NULL; - property_info = nm_meta_setting_info_editor_get_property_info (setting_info, property_name); + property_info = nm_meta_setting_info_editor_get_property_info (setting_info, property_name, FALSE); if (!property_info) return NULL; @@ -325,6 +381,73 @@ nm_meta_abstract_info_complete (const NMMetaAbstractInfo *abstract_info, } } +/** + * nm_meta_abstract_info_get_property_names: + * @abstract_info: the meta data + * @target: (allow none): an optional target instance. The result + * of property names may or may not depend on the target. + * If present, @target must be valid for @abstract_info. + * @get_property_names_flags: flags argument to control the result. + * + * Returns: (transfer full): the list of valid property names for target. + * For most setting types, this is just the static list of GObject property + * names. + * For some types this may be a type dependent list of properties (bond.options). + * For other types, it may even be a list of properties that are generated based + * on the current @setting (user.data). */ +char ** +nm_meta_abstract_info_get_property_names (const NMMetaAbstractInfo *abstract_info, + gpointer target, + NMMetaAccessorGetPropertyNamesFlags get_property_names_flags) +{ + GPtrArray *result; + + g_return_val_if_fail (abstract_info, NULL); + + if (!abstract_info->meta_type->get_property_names) + return NULL; + + if (!NM_FLAGS_ANY (get_property_names_flags, + NM_META_ACCESSOR_GET_PROPERTY_NAMES_FLAGS_WITH_THIS_LEVEL + | NM_META_ACCESSOR_GET_PROPERTY_NAMES_FLAGS_WITH_TOPLEVEL_LEVEL)) + get_property_names_flags |= NM_META_ACCESSOR_GET_PROPERTY_NAMES_FLAGS_WITH_THIS_LEVEL; + + result = g_ptr_array_new (); + abstract_info->meta_type->get_property_names (abstract_info, + target, + get_property_names_flags, + result); + if (!result->len) { + g_ptr_array_free (result, TRUE); + return NULL; + } + + g_ptr_array_sort (result, nm_strcmp_p); + g_ptr_array_add (result, NULL); + return _nm_utils_strv_cleanup ((char **) g_ptr_array_free (result, FALSE), + FALSE, FALSE, TRUE); +} + +gboolean +nm_meta_abstract_info_set_property (const NMMetaAbstractInfo *abstract_info, + gpointer target, + const char *property_name, + const char *value, + GError **error) +{ + g_return_val_if_fail (target, FALSE); + g_return_val_if_fail (property_name, FALSE); + g_return_val_if_fail (!error || !*error, FALSE); + g_return_val_if_fail (abstract_info, FALSE); + g_return_val_if_fail (abstract_info->meta_type->set_property, FALSE); + + return abstract_info->meta_type->set_property (abstract_info, + target, + property_name, + value, + error); +} + /*****************************************************************************/ char * @@ -373,6 +496,45 @@ nm_meta_abstract_infos_get_names_str (const NMMetaAbstractInfo *const*fields_arr /*****************************************************************************/ +static void +_parse_name (const char *name, + const char **out_toplevel, + const char **out_nested, + NMMetaPropertyNameModifier *out_modifier, + char **out_to_free) +{ + const char *toplevel = NULL; + const char *nested = NULL; + NMMetaPropertyNameModifier modifier = NM_META_PROPERTY_NAME_MODIFIER_NONE; + const char *s; + char *t; + + if (name) { + if (NM_IN_SET (name[0], '+', '-')) { + modifier = name[0] == '+' + ? NM_META_PROPERTY_NAME_MODIFIER_PLUS + : NM_META_PROPERTY_NAME_MODIFIER_MINUS; + name++; + } + + s = strchr (name, '.'); + if (!s) + toplevel = name; + else { + t = g_strdup (name); + *out_to_free = t; + toplevel = t; + t = &t[s - name]; + *t = '\0'; + nested = t+1; + } + } + + *out_toplevel = toplevel; + *out_nested = nested; + *out_modifier = modifier; +} + typedef struct { guint idx; gsize self_offset_plus_1; @@ -619,3 +781,85 @@ nm_meta_selection_create_parse_list (const NMMetaAbstractInfo *const* fields_arr return _output_selection_pack (fields_array, array, str); } + +NMMetaSelectionResultList * +nm_meta_selection_parse_connection_property_name (NMConnection *connection, + const char *property_name, + GError **error) +{ + const char *const property_name_orig = property_name; + gs_free char *parsed_name_tmp = NULL; + const char *nested_name; + NMMetaPropertyNameModifier modifier; + const NMMetaSettingInfoEditor *setting_info = NULL; + const NMMetaPropertyInfo *property_info = NULL; + + g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); + + _parse_name (property_name, + &property_name, + &nested_name, + &modifier, + &parsed_name_tmp); + + if (property_name || !property_name[0]) + goto out_invalid_toplevel_name; + + { + gboolean unique_match; + + setting_info = nm_meta_setting_info_editor_find_by_fuzzyname (property_name, TRUE, TRUE, &unique_match); + if (!unique_match) + goto out_invalid_toplevel_name; + } + + if (setting_info) { + if (!nested_name) { + gs_strfreev char **v = NULL; + gs_free char *t = NULL; + + v = nm_meta_abstract_info_get_property_names ((const NMMetaAbstractInfo *) setting_info, + nm_connection_get_setting_by_name (connection, setting_info->general->setting_name), + NM_META_ACCESSOR_GET_PROPERTY_NAMES_FLAGS_WITH_THIS_LEVEL); + g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_INVALID_ARGUMENT, + _("invalid property name \"%s\". Requires a property name like [%s]"), + property_name_orig, (t = g_strjoinv (",", v))); + return FALSE; + } + + property_info = nm_meta_setting_info_editor_get_property_info (setting_info, + nested_name, + TRUE); + if (!property_info) { + gs_strfreev char **v = NULL; + gs_free char *t = NULL; + + v = nm_meta_abstract_info_get_property_names ((const NMMetaAbstractInfo *) setting_info, + nm_connection_get_setting_by_name (connection, setting_info->general->setting_name), + NM_META_ACCESSOR_GET_PROPERTY_NAMES_FLAGS_WITH_THIS_LEVEL); + g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_INVALID_ARGUMENT, + _("invalid property name \"%s\". \"%s\" requires a property name like [%s]"), + property_name_orig, setting_info->general->setting_name, + (t = g_strjoinv (",", v))); + return FALSE; + } + + } else { + if (nested_name) + goto out_invalid_toplevel_name; + + /* lookup the property name by toplevel alias. */ + } + +out_invalid_toplevel_name: + { + gs_free char *t = NULL; + + g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_INVALID_ARGUMENT, + _("invalid property name \"%s\". Valid names are [%s]"), + property_name_orig, (t = g_strjoinv (",", nm_meta_abstract_info_get_property_names (&nm_meta_connection_info, connection, 0)))); + } + return FALSE; +} + + diff --git a/clients/common/nm-meta-setting-access.h b/clients/common/nm-meta-setting-access.h index 54fc6c84d6..ecedf499b1 100644 --- a/clients/common/nm-meta-setting-access.h +++ b/clients/common/nm-meta-setting-access.h @@ -29,11 +29,14 @@ NMSetting *nm_meta_setting_info_editor_new_setting (const NMMetaSettingInfoEdito NMMetaAccessorSettingInitType init_type); const NMMetaSettingInfoEditor *nm_meta_setting_info_editor_find_by_name (const char *setting_name, gboolean use_alias); +const NMMetaSettingInfoEditor *nm_meta_setting_info_editor_find_by_fuzzyname (const char *setting_name, gboolean use_alias, + gboolean fuzzy_match, gboolean *out_unique); const NMMetaSettingInfoEditor *nm_meta_setting_info_editor_find_by_gtype (GType gtype); const NMMetaSettingInfoEditor *nm_meta_setting_info_editor_find_by_setting (NMSetting *setting); const NMMetaPropertyInfo *nm_meta_setting_info_editor_get_property_info (const NMMetaSettingInfoEditor *setting_info, - const char *property_name); + const char *property_name, + gboolean fuzzy_match); const NMMetaPropertyInfo *nm_meta_property_info_find_by_name (const char *setting_name, const char *property_name); const NMMetaPropertyInfo *nm_meta_property_info_find_by_setting (NMSetting *setting, @@ -67,6 +70,16 @@ const char *const*nm_meta_abstract_info_complete (const NMMetaAbstractInfo *abst const char *text, char ***out_to_free); +char **nm_meta_abstract_info_get_property_names (const NMMetaAbstractInfo *abstract_info, + gpointer target, + NMMetaAccessorGetPropertyNamesFlags get_property_names_flags); + +gboolean nm_meta_abstract_info_set_property (const NMMetaAbstractInfo *abstract_info, + gpointer target, + const char *property_name, + const char *value, + GError **error); + /*****************************************************************************/ char *nm_meta_abstract_info_get_nested_names_str (const NMMetaAbstractInfo *abstract_info, const char *name_prefix); @@ -98,4 +111,8 @@ NMMetaSelectionResultList *nm_meta_selection_create_parse_list (const NMMetaAbst gboolean validate_nested, GError **error); +NMMetaSelectionResultList *nm_meta_selection_parse_connection_property_name (NMConnection *connection, + const char *property_name, + GError **error); + #endif /* _NM_META_SETTING_ACCESS_H__ */ diff --git a/clients/common/nm-meta-setting-desc.c b/clients/common/nm-meta-setting-desc.c index a55d03700b..2d3f38ef5d 100644 --- a/clients/common/nm-meta-setting-desc.c +++ b/clients/common/nm-meta-setting-desc.c @@ -7545,11 +7545,214 @@ _meta_type_property_info_complete_fcn (const NMMetaAbstractInfo *abstract_info, return NULL; } +static void +_meta_type_setting_info_get_property_names (const NMMetaAbstractInfo *abstract_info, + gpointer target, + NMMetaAccessorGetPropertyNamesFlags get_property_names_flags, + GPtrArray *result) +{ + const NMMetaSettingInfoEditor *setting_info = (NMMetaSettingInfoEditor *) abstract_info; + NMSetting *setting = NM_SETTING (target); + guint i, j; + + nm_assert ( !setting + || ( NM_IS_SETTING (setting) + && G_TYPE_CHECK_INSTANCE_TYPE (setting, setting_info->general->get_setting_gtype ()))); + + if (!setting_info->properties_num) + return; + + for (i = 0; i < setting_info->properties_num; i++) { + const NMMetaPropertyInfo *pi = setting_info->properties[i]; + const NMMetaPropertyTypDataNested *nested_data; + + if (NM_FLAGS_HAS (get_property_names_flags, NM_META_ACCESSOR_GET_PROPERTY_NAMES_FLAGS_WITH_THIS_LEVEL)) + g_ptr_array_add (result, g_strdup (pi->property_name)); + + if ( NM_FLAGS_HAS (get_property_names_flags, NM_META_ACCESSOR_GET_PROPERTY_NAMES_FLAGS_WITH_TOPLEVEL_LEVEL) + && pi->property_alias) + g_ptr_array_add (result, g_strdup (pi->property_alias)); + + if ( pi->property_typ_data + && (nested_data = pi->property_typ_data->nested)) { + for (j = 0; j < nested_data->nested_len; j++) { + const NMMetaNestedPropertyInfo *n_pi = &nested_data->nested[j]; + + if (n_pi->base.property_name) { + /* the field-name itself is a valid property name and a top-level + * alias. */ + if (NM_FLAGS_HAS (get_property_names_flags, NM_META_ACCESSOR_GET_PROPERTY_NAMES_FLAGS_WITH_TOPLEVEL_LEVEL)) + g_ptr_array_add (result, g_strdup (n_pi->base.property_name)); + } + } + } + } +} + +static const NMMetaSettingValidPartItem * +_valid_part_item_find (const NMMetaSettingValidPartItem *const*items, const NMMetaSettingInfoEditor *setting_info) +{ + if (items) { + for (; *items; items++) { + if ((*items)->setting_info == setting_info) + return *items; + } + } + return NULL; +} + +static void +_meta_type_connection_info_get_property_names (const NMMetaAbstractInfo *abstract_info, + gpointer target, + NMMetaAccessorGetPropertyNamesFlags get_property_names_flags, + GPtrArray *result) +{ + NMConnection *connection = NM_CONNECTION (target); + guint s; + const NMMetaSettingValidPartItem *const*setting_info_type = NULL; + const NMMetaSettingValidPartItem *const*setting_info_slave = NULL; + const NMMetaSettingInfoEditor *setting_info; + + nm_assert (!connection || NM_IS_CONNECTION (connection)); + + if (connection) { + NMSettingConnection *s_con; + + s_con = nm_connection_get_setting_connection (connection); + setting_info_type = nm_meta_setting_info_valid_parts_default; + if (s_con) { + const char *c_type = nm_setting_connection_get_connection_type (s_con); + const char *s_type = nm_setting_connection_get_slave_type (s_con); + + if (c_type) { + setting_info = nm_meta_setting_info_editor_find_by_name (c_type, FALSE); + if (!setting_info || setting_info->valid_parts) + setting_info_type = setting_info->valid_parts; + } + setting_info_slave = nm_meta_setting_info_valid_parts_for_slave_type (s_type, NULL); + } + } + + for (s = 0; s < _NM_META_SETTING_TYPE_NUM; s++) { + NMSetting *setting = NULL; + + setting_info = &nm_meta_setting_infos_editor[s]; + + if (connection) { + setting = nm_connection_get_setting_by_name (connection, setting_info->general->setting_name); + if ( !setting + && !_valid_part_item_find (setting_info_type, setting_info) + && !_valid_part_item_find (setting_info_slave, setting_info)) + continue; + } + + g_ptr_array_add (result, g_strdup (setting_info->general->setting_name)); + + _meta_type_setting_info_get_property_names ((const NMMetaAbstractInfo *) setting_info, + setting, + NM_META_ACCESSOR_GET_PROPERTY_NAMES_FLAGS_WITH_TOPLEVEL_LEVEL, + result); + } +} + +static gboolean +_meta_type_connection_info_set_property (const NMMetaAbstractInfo *abstract_info, + gpointer target, + const char *property_name, + const char *value, + GError **error) +{ +#if 0 + NMConnection *connection = NM_CONNECTION (target); + const char *const property_name_orig = property_name; + gs_free char *parsed_name_tmp = NULL; + const char *nested_name; + NMMetaPropertyNameModifier modifier; + const NMMetaSettingInfoEditor *setting_info = NULL; + const NMMetaPropertyInfo *property_info = NULL; + + g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE); + + _parse_name (property_name, + &property_name, + &nested_name, + &modifier, + &parsed_name_tmp); + + if (property_name || !property_name[0]) + goto out_invalid_toplevel_name; + + { + gboolean unique_match; + + setting_info = nm_meta_setting_info_editor_find_by_fuzzyname (property_name, TRUE, TRUE, &unique_match); + if (!unique_match) + goto out_invalid_toplevel_name; + } + + if (setting_info) { + if (!nested_name) { + gs_strfreev char **v = NULL; + gs_free char *t = NULL; + + v = nm_meta_abstract_info_get_property_names ((const NMMetaAbstractInfo *) setting_info, + nm_connection_get_setting_by_name (connection, setting_info->general->setting_name), + NM_META_ACCESSOR_GET_PROPERTY_NAMES_FLAGS_WITH_THIS_LEVEL); + g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_INVALID_ARGUMENT, + _("invalid property name \"%s\". Requires a property name like [%s]"), + property_name_orig, (t = g_strjoinv (",", v))); + return FALSE; + } + + property_info = nm_meta_setting_info_editor_get_property_info (setting_info, + nested_name, + TRUE); + if (!property_info) { + gs_strfreev char **v = NULL; + gs_free char *t = NULL; + + v = nm_meta_abstract_info_get_property_names ((const NMMetaAbstractInfo *) setting_info, + nm_connection_get_setting_by_name (connection, setting_info->general->setting_name), + NM_META_ACCESSOR_GET_PROPERTY_NAMES_FLAGS_WITH_THIS_LEVEL); + g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_INVALID_ARGUMENT, + _("invalid property name \"%s\". Requires a property name like [%s]"), + property_name_orig, (t = g_strjoinv (",", v))); + return FALSE; + } + + } else { + if (nested_name) + goto out_invalid_toplevel_name; + + /* lookup the property name by toplevel alias. */ + } + + return abstract_info->meta_type->set_property (abstract_info, + target, + property_name, + value, + error); + +out_invalid_toplevel_name: + { + gs_free char *t = NULL; + + g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_INVALID_ARGUMENT, + _("invalid property name \"%s\". Valid names are [%s]"), + property_name_orig, (t = g_strjoinv (",", nm_meta_abstract_info_get_property_names (abstract_info, connection, 0)))); + } +#endif + return FALSE; +} + +/*****************************************************************************/ + const NMMetaType nm_meta_type_setting_info_editor = { .type_name = "setting_info_editor", .get_name = _meta_type_setting_info_editor_get_name, .get_nested = _meta_type_setting_info_editor_get_nested, .get_fcn = _meta_type_setting_info_editor_get_fcn, + .get_property_names = _meta_type_setting_info_get_property_names, }; const NMMetaType nm_meta_type_property_info = { @@ -7563,3 +7766,17 @@ const NMMetaType nm_meta_type_property_info = { const NMMetaType nm_meta_type_nested_property_info = { .type_name = "nested_property_info", }; + +static const NMMetaType meta_type_connection_info = { + .type_name = "connection_info", + .get_property_names = _meta_type_connection_info_get_property_names, + .set_property = _meta_type_connection_info_set_property, +}; + +/*****************************************************************************/ + +const NMMetaAbstractInfo nm_meta_connection_info = { + .meta_type = &meta_type_connection_info, +}; + +/*****************************************************************************/ diff --git a/clients/common/nm-meta-setting-desc.h b/clients/common/nm-meta-setting-desc.h index 38aa50f95f..fabd8b3efb 100644 --- a/clients/common/nm-meta-setting-desc.h +++ b/clients/common/nm-meta-setting-desc.h @@ -102,6 +102,12 @@ typedef enum { NM_META_TERM_FORMAT_HIDDEN = 6, } NMMetaTermFormat; +typedef enum { + NM_META_PROPERTY_NAME_MODIFIER_NONE, + NM_META_PROPERTY_NAME_MODIFIER_PLUS, + NM_META_PROPERTY_NAME_MODIFIER_MINUS, +} NMMetaPropertyNameModifier; + typedef enum { NM_META_ACCESSOR_GET_TYPE_PRETTY, NM_META_ACCESSOR_GET_TYPE_PARSABLE, @@ -150,6 +156,21 @@ typedef enum { NM_META_ACCESSOR_GET_OUT_FLAGS_STRV = (1LL << 0), } NMMetaAccessorGetOutFlags; +typedef enum { + NM_META_ACCESSOR_GET_PROPERTY_NAMES_FLAGS_NONE = 0, + + /* the name is valid on this level. For example, "stable-id" is a valid + * name for NMSettingConnection. Such a name has to be qualified by + * the parent to make "connection.stable-id". */ + NM_META_ACCESSOR_GET_PROPERTY_NAMES_FLAGS_WITH_THIS_LEVEL = (1LL << 0), + + /* the name is valid on the top level. For example, "name" is an alias + * for "connection.id" and is valid unqualified at the top-level. + * The name may still be invalid on the top level if it conflicts + * with other aliases or setting names. */ + NM_META_ACCESSOR_GET_PROPERTY_NAMES_FLAGS_WITH_TOPLEVEL_LEVEL = (1LL << 1), +} NMMetaAccessorGetPropertyNamesFlags; + typedef enum { NM_META_PROPERTY_TYP_FLAG_ENUM_GET_PRETTY_NUMERIC = (1LL << 0), NM_META_PROPERTY_TYP_FLAG_ENUM_GET_PRETTY_NUMERIC_HEX = (1LL << 1), @@ -315,6 +336,11 @@ struct _NMMetaSettingInfoEditor { void (*setting_init_fcn) (const NMMetaSettingInfoEditor *setting_info, NMSetting *setting, NMMetaAccessorSettingInitType init_type); + + const NMMetaPropertyInfo *(*get_property_info) (const NMMetaSettingInfoEditor *setting_info, + const char *property_name, + gboolean fuzzy_match); + }; struct _NMMetaType { @@ -338,6 +364,17 @@ struct _NMMetaType { const NMMetaOperationContext *operation_context, const char *text, char ***out_to_free); + void (*get_property_names) (const NMMetaAbstractInfo *abstract_info, + gpointer target, + NMMetaAccessorGetPropertyNamesFlags get_property_names_flags, + GPtrArray *result); + + gboolean (*set_property) (const NMMetaAbstractInfo *abstract_info, + gpointer target, + const char *property_name, + const char *value, + GError **error); + }; struct _NMMetaAbstractInfo { @@ -407,4 +444,8 @@ const NMMetaPropertyTypDataNested nm_meta_property_typ_data_bond; /*****************************************************************************/ +extern const NMMetaAbstractInfo nm_meta_connection_info; + +/*****************************************************************************/ + #endif /* __NM_META_SETTING_DESC_H__ */ diff --git a/clients/common/tests/test-general.c b/clients/common/tests/test-general.c index 591bcd98f0..bfe80297bd 100644 --- a/clients/common/tests/test-general.c +++ b/clients/common/tests/test-general.c @@ -133,7 +133,7 @@ test_client_meta_check (void) for (p = 0; p < info->properties_num; p++) { const NMMetaPropertyInfo *pi = info->properties[p]; - g_assert (nm_meta_setting_info_editor_get_property_info (info, pi->property_name) == pi); + g_assert (nm_meta_setting_info_editor_get_property_info (info, pi->property_name, FALSE) == pi); g_assert (nm_meta_property_info_find_by_name (info->general->setting_name, pi->property_name) == pi); } } -- cgit v1.2.1