diff --git a/src/rougail/user_data.py b/src/rougail/user_data.py index d35d50955..30290c533 100644 --- a/src/rougail/user_data.py +++ b/src/rougail/user_data.py @@ -81,11 +81,12 @@ class UserData: options = datas.get("options", {}) source = datas["source"] for name, data in datas.get("values", {}).items(): - self.values[name] = { + self.values.setdefault(name, []).append( + { "source": source, "values": data, "options": options.copy(), - } + }) self.errors.extend(datas.get("errors", [])) self.warnings.extend(datas.get("warnings", [])) @@ -114,7 +115,7 @@ class UserData: except (ConfigError, PropertiesOptionError): pass except AttributeError: - self._not_found_is_dynamic(self.config, path, cache, added, data) + self._not_found_is_dynamic(self.config, path, cache, added, data[-1]) def _not_found_is_dynamic(self, config, path, cache, added, data): """if path is not found, check if parent is a dynamic family""" @@ -182,7 +183,7 @@ class UserData: ) # do not add values in variable if has already a value if dynamic_variable not in self.values and not dyn_options_values: - self.values[dynamic_variable] = {"values": []} + self.values[dynamic_variable] = [{"values": []}] added.append(dynamic_variable) elif dynamic_variable not in added: continue @@ -191,8 +192,8 @@ class UserData: typ = CONVERT_OPTION.get(option_type, {}).get("func") if typ: identifier = typ(identifier) - if identifier not in self.values[dynamic_variable]["values"]: - self.values[dynamic_variable]["values"].append(identifier) + if identifier not in self.values[dynamic_variable][-1]["values"]: + self.values[dynamic_variable][-1]["values"].append(identifier) cache[current_path] = config, identifier break @@ -202,7 +203,7 @@ class UserData: if option.ismulti(): if options.get("multi_separator") and not isinstance(value, list): value = value.split(options["multi_separator"]) - self.values[path]["values"] = value + self.values[path][-1]["values"] = value if option.issubmulti(): value = [[val] for val in value] if option.issubmulti(): @@ -212,8 +213,8 @@ class UserData: elif isinstance(value, list): value = [convert_value(option, val, needs_convert) for val in value] if needs_convert: - self.values[path]["values"] = value - self.values[path]["options"]["needs_convert"] = needs_convert + self.values[path][-1]["values"] = value + self.values[path][-1]["options"]["needs_convert"] = needs_convert elif not isinstance(value, list): value = convert_value(option, value, needs_convert) return value @@ -230,29 +231,32 @@ class UserData: values_path = option.path(uncalculated=True) if values_path not in self.values: continue - options = self.values[values_path].get("options", {}) - if ( - options.get("allow_secrets_variables", True) is False - and option.type() == "password" - ): - self.errors.append({ - _( - 'the variable contains secrets and should not be defined in {0}' - ).format(self.values[values_path]["source"]): option._subconfig} - ) - self.values.pop(path) - continue + if option.type() == "password": + one_is_in_error = False + for values in self.values[values_path]: + if values.get("options", {}).get("allow_secrets_variables", True) is False: + one_is_in_error = True + self.errors.append({ + _( + 'the variable contains secrets and should not be defined in {0}' + ).format(values["source"]): option._subconfig} + ) + if one_is_in_error: + self.values.pop(values_path) + continue + values = self.values[values_path][-1] + options = values.get("options", {}) value = self.convert_value( - path, option, options, self.values[values_path]["values"] + path, option, options, values["values"] ) index = option.index() if index is not None: if isinstance(value, tuple): - self.values[values_path]["values"] = [] + values["values"] = [] # for i in range(len(option.parent().leader().value.get())): for i in range(option.value.len()): - self.values[values_path]["values"].append(value) - value = self.values[values_path]["values"] + values["values"].append(value) + value = values["values"] if not isinstance(value, list) or index >= len(value): continue value = value[index] @@ -269,14 +273,15 @@ class UserData: self.set_value(option, value, options, index) value_is_set = True except Exception as err: - if path != option.path(): - self.values[option.path()] = self.values.pop(values_path) + pass +# if path != option.path(): +# self.values[option.path()] = self.values.pop(values_path) else: # value is correctly set, remove variable to the set if index is not None: # if it's a follower waiting for all followers are sets - self.values[values_path]["values"][index] = undefined - for tmp_value in self.values[values_path]["values"]: + values["values"][index] = undefined + for tmp_value in values["values"]: if tmp_value != undefined: break else: @@ -305,7 +310,8 @@ class UserData: def _populate_error_warnings(self): # we don't find variable, apply value just to get error or warning messages - for path, options in self.values.items(): + for path, full_options in self.values.items(): + options = full_options[-1] value = options["values"] if options.get("secret_manager"): option = self.config.forcepermissive.option(path) @@ -388,7 +394,7 @@ class UserData: ) continue value = self.convert_value( - path, option, self.values[path].get("options", {}), value + path, option, self.values[path][-1].get("options", {}), value ) if option.isfollower(): if not isinstance(value, tuple): @@ -559,13 +565,13 @@ class UserData: if add_validation: option.property.add("validator") path = option.path() - if "source" in self.values[path]: + if "source" in self.values[path][-1]: if option.isfollower(): key = f"loaded_from_{index}" else: key = "loaded_from" value = _("loaded from {0}").format( - self.values[path]["source"] + self.values[path][-1]["source"] ) if options.get("secret_manager"): # FIXME (true_config ???)