diff --git a/data/helpers.d/string b/data/helpers.d/string index 7036b3b3c..a96157f78 100644 --- a/data/helpers.d/string +++ b/data/helpers.d/string @@ -43,12 +43,14 @@ ynh_replace_string () { local target_file # Manage arguments with getopts ynh_handle_getopts_args "$@" + set +o xtrace # set +x local delimit=@ # Escape the delimiter if it's in the string. match_string=${match_string//${delimit}/"\\${delimit}"} replace_string=${replace_string//${delimit}/"\\${delimit}"} + set -o xtrace # set -x sed --in-place "s${delimit}${match_string}${delimit}${replace_string}${delimit}g" "$target_file" } diff --git a/data/helpers.d/utils b/data/helpers.d/utils index ef019e894..34a089eb1 100644 --- a/data/helpers.d/utils +++ b/data/helpers.d/utils @@ -1,6 +1,6 @@ #!/bin/bash -YNH_APP_BASEDIR=$(realpath $([[ "$(basename $0)" =~ ^backup|restore$ ]] && echo '../settings' || [[ -n "$YNH_ACTION" ]] && echo '.' || echo '..' )) +YNH_APP_BASEDIR=$(realpath $([[ "$(basename $0)" =~ ^backup|restore$ ]] && echo '../settings' || [[ -n "${YNH_ACTION:-}" ]] && echo '.' || echo '..' )) # Handle script crashes / failures # @@ -519,6 +519,8 @@ ynh_read_var_in_file() { [[ -f $file ]] || ynh_die --message="File $file does not exists" + set +o xtrace # set +x + # Get the line number after which we search for the variable local line_number=1 if [[ -n "$after" ]]; @@ -526,6 +528,7 @@ ynh_read_var_in_file() { line_number=$(grep -n $after $file | cut -d: -f1) if [[ -z "$line_number" ]]; then + set -o xtrace # set -x return 1 fi fi @@ -555,6 +558,7 @@ ynh_read_var_in_file() { # Extract the part after assignation sign local expression_with_comment="$(tail +$line_number ${file} | grep -i -o -P $var_part'\K.*$' || echo YNH_NULL | head -n1)" if [[ "$expression_with_comment" == "YNH_NULL" ]]; then + set -o xtrace # set -x echo YNH_NULL return 0 fi @@ -570,6 +574,7 @@ ynh_read_var_in_file() { else echo "$expression" fi + set -o xtrace # set -x } # Set a value into heterogeneous file (yaml, json, php, python...) @@ -594,6 +599,8 @@ ynh_write_var_in_file() { [[ -f $file ]] || ynh_die --message="File $file does not exists" + set +o xtrace # set +x + # Get the line number after which we search for the variable local line_number=1 if [[ -n "$after" ]]; @@ -601,6 +608,7 @@ ynh_write_var_in_file() { line_number=$(grep -n $after $file | cut -d: -f1) if [[ -z "$line_number" ]]; then + set -o xtrace # set -x return 1 fi fi @@ -631,9 +639,10 @@ ynh_write_var_in_file() { # Extract the part after assignation sign local expression_with_comment="$(tail +$line_number ${file} | grep -i -o -P $var_part'\K.*$' || echo YNH_NULL | head -n1)" if [[ "$expression_with_comment" == "YNH_NULL" ]]; then + set -o xtrace # set -x return 1 fi - + # Remove comments if needed local expression="$(echo "$expression_with_comment" | sed "s@$comments[^$string]*\$@@g" | sed "s@\s*[$endline]*\s*]*\$@@")" endline=${expression_with_comment#"$expression"} @@ -661,6 +670,7 @@ ynh_write_var_in_file() { fi sed -ri "${range}s$delimiter(^${var_part}).*\$$delimiter\1${value}${endline}${delimiter}i" ${file} fi + set -o xtrace # set -x } @@ -727,6 +737,7 @@ ynh_secure_remove () { local file # Manage arguments with getopts ynh_handle_getopts_args "$@" + set +o xtrace # set +x local forbidden_path=" \ /var/www \ @@ -754,6 +765,8 @@ ynh_secure_remove () { else ynh_print_info --message="'$file' wasn't deleted because it doesn't exist." fi + + set -o xtrace # set -x } # Extract a key from a plain command output diff --git a/src/yunohost/app.py b/src/yunohost/app.py index cfd773bd9..3ba7fd5e4 100644 --- a/src/yunohost/app.py +++ b/src/yunohost/app.py @@ -2180,6 +2180,13 @@ def _set_default_ask_questions(arguments): key = "app_manifest_%s_ask_%s" % (script_name, arg["name"]) arg["ask"] = m18n.n(key) + # Also it in fact doesn't make sense for any of those questions to have an example value nor a default value... + if arg.get("type") in ["domain", "user", "password"]: + if "example" in arg: + del arg["example"] + if "default" in arg: + del arg["domain"] + return arguments diff --git a/src/yunohost/log.py b/src/yunohost/log.py index b7b585c94..3f25d7a7d 100644 --- a/src/yunohost/log.py +++ b/src/yunohost/log.py @@ -69,7 +69,13 @@ def log_list(limit=None, with_details=False, with_suboperations=False): logs = list(reversed(sorted(logs))) if limit is not None: - logs = logs[:limit] + if with_suboperations: + logs = logs[:limit] + else: + # If we displaying only parent, we are still gonna load up to limit * 5 logs + # because many of them are suboperations which are not gonna be kept + # Yet we still want to obtain ~limit number of logs + logs = logs[:limit * 5] for log in logs: @@ -122,6 +128,9 @@ def log_list(limit=None, with_details=False, with_suboperations=False): else: operations = [o for o in operations.values()] + if limit: + operations = operations[:limit] + operations = list(reversed(sorted(operations, key=lambda o: o["name"]))) # Reverse the order of log when in cli, more comfortable to read (avoid # unecessary scrolling) @@ -151,26 +160,37 @@ def log_show( filter_irrelevant = True if filter_irrelevant: - filters = [ - r"set [+-]x$", - r"set [+-]o xtrace$", - r"local \w+$", - r"local legacy_args=.*$", - r".*Helper used in legacy mode.*", - r"args_array=.*$", - r"local -A args_array$", - r"ynh_handle_getopts_args", - r"ynh_script_progression", - ] + + def _filter(lines): + filters = [ + r"set [+-]x$", + r"set [+-]o xtrace$", + r"set [+-]o errexit$", + r"set [+-]o nounset$", + r"trap '' EXIT", + r"local \w+$", + r"local exit_code=(1|0)$", + r"local legacy_args=.*$", + r"local -A args_array$", + r"args_array=.*$", + r"ret_code=1", + r".*Helper used in legacy mode.*", + r"ynh_handle_getopts_args", + r"ynh_script_progression", + r"sleep 0.5", + r"'\[' (1|0) -eq (1|0) '\]'$", + r"\[?\['? -n '' '?\]\]?$", + r"rm -rf /var/cache/yunohost/download/$", + r"type -t ynh_clean_setup$", + r"DEBUG - \+ echo '", + r"DEBUG - \+ exit (1|0)$", + ] + filters = [re.compile(f) for f in filters] + return [line for line in lines if not any(f.search(line.strip()) for f in filters)] else: - filters = [] + def _filter(lines): + return lines - def _filter_lines(lines, filters=[]): - - filters = [re.compile(f) for f in filters] - return [ - line for line in lines if not any(f.search(line.strip()) for f in filters) - ] # Normalize log/metadata paths and filenames abs_path = path @@ -209,7 +229,7 @@ def log_show( content += "\n============\n\n" if os.path.exists(log_path): actual_log = read_file(log_path) - content += "\n".join(_filter_lines(actual_log.split("\n"), filters)) + content += "\n".join(_filter(actual_log.split("\n"))) url = yunopaste(content) @@ -282,13 +302,13 @@ def log_show( if os.path.exists(log_path): from yunohost.service import _tail - if number and filters: + if number and filter_irrelevant: logs = _tail(log_path, int(number * 4)) elif number: logs = _tail(log_path, int(number)) else: logs = read_file(log_path) - logs = _filter_lines(logs, filters) + logs = list(_filter(logs)) if number: logs = logs[-number:] infos["log_path"] = log_path diff --git a/src/yunohost/utils/config.py b/src/yunohost/utils/config.py index 3fccd8cc5..8ec198d34 100644 --- a/src/yunohost/utils/config.py +++ b/src/yunohost/utils/config.py @@ -423,7 +423,8 @@ class ConfigPanel: if services_to_reload: logger.info("Reloading services...") for service in services_to_reload: - service = service.replace("__APP__", self.app) + if hasattr(self, "app"): + service = service.replace("__APP__", self.app) service_reload_or_restart(service) def _iterate(self, trigger=["option"]): @@ -815,6 +816,14 @@ class UserQuestion(Question): super().__init__(question, user_answers) self.choices = user_list()["users"] + + if not self.choices: + raise YunohostValidationError( + "app_argument_invalid", + name=self.name, + error="You should create a YunoHost user first." + ) + if self.default is None: root_mail = "root@%s" % _get_maindomain() for user in self.choices.keys(): @@ -897,8 +906,8 @@ class DisplayTextQuestion(Question): "warning": "yellow", "danger": "red", } - text = m18n.g(self.style) if self.style != "danger" else m18n.n("danger") - return colorize(text, color[self.style]) + f" {text}" + prompt = m18n.g(self.style) if self.style != "danger" else m18n.n("danger") + return colorize(prompt, color[self.style]) + f" {text}" else: return text