diff --git a/.gitlab/ci/translation.gitlab-ci.yml b/.gitlab/ci/translation.gitlab-ci.yml
index e6365adbc..41e8c82d2 100644
--- a/.gitlab/ci/translation.gitlab-ci.yml
+++ b/.gitlab/ci/translation.gitlab-ci.yml
@@ -20,7 +20,7 @@ autofix-translated-strings:
- python3 reformat_locales.py
- '[ $(git diff -w | wc -l) != 0 ] || exit 0' # stop if there is nothing to commit
- git commit -am "[CI] Reformat / remove stale translated strings" || true
- - git push -f origin "ci-remove-stale-translated-strings-${CI_COMMIT_REF_NAME}":"ci-remove-stale-translated-strings-${CI_COMMIT_REF_NAME}"
+ - git push -f origin "HEAD":"ci-remove-stale-translated-strings-${CI_COMMIT_REF_NAME}"
- hub pull-request -m "[CI] Reformat / remove stale translated strings" -b Yunohost:dev -p || true # GITHUB_USER and GITHUB_TOKEN registered here https://gitlab.com/yunohost/yunohost/-/settings/ci_cd
only:
variables:
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 511fa52fb..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' || 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/locales/ca.json b/locales/ca.json
index 5a128ebb8..0e8d446d5 100644
--- a/locales/ca.json
+++ b/locales/ca.json
@@ -177,7 +177,7 @@
"iptables_unavailable": "No podeu modificar les iptables aquí. O bé sou en un contenidor o bé el vostre nucli no és compatible amb aquesta opció",
"log_corrupted_md_file": "El fitxer de metadades YAML associat amb els registres està malmès: « {md_file} »\nError: {error}",
"log_link_to_log": "El registre complet d'aquesta operació: «{desc}»",
- "log_help_to_get_log": "Per veure el registre de l'operació « {desc} », utilitzeu l'ordre « yunohost log show {name}{name} »",
+ "log_help_to_get_log": "Per veure el registre de l'operació « {desc} », utilitzeu l'ordre « yunohost log show {name} »",
"log_link_to_failed_log": "No s'ha pogut completar l'operació « {desc} ». Per obtenir ajuda, proveïu el registre complete de l'operació clicant aquí",
"log_help_to_get_failed_log": "No s'ha pogut completar l'operació « {desc} ». Per obtenir ajuda, compartiu el registre complete de l'operació utilitzant l'ordre « yunohost log share {name} »",
"log_does_exists": "No hi ha cap registre per l'operació amb el nom« {log} », utilitzeu « yunohost log list » per veure tots els registre d'operació disponibles",
diff --git a/locales/de.json b/locales/de.json
index dca2b034d..6ddc1284d 100644
--- a/locales/de.json
+++ b/locales/de.json
@@ -244,7 +244,7 @@
"dpkg_is_broken": "Du kannst das gerade nicht tun, weil dpkg/APT (der Systempaketmanager) in einem defekten Zustand zu sein scheint.... Du kannst versuchen, dieses Problem zu lösen, indem du dich über SSH verbindest und `sudo apt install --fix-broken` sowie/oder `sudo dpkg --configure -a` ausführst.",
"global_settings_unknown_setting_from_settings_file": "Unbekannter Schlüssel in den Einstellungen: '{setting_key}', verwerfen und speichern in /etc/yunohost/settings-unknown.json",
"log_link_to_log": "Vollständiges Log dieser Operation: '{desc}'",
- "log_help_to_get_log": "Um das Protokoll der Operation '{desc}' anzuzeigen, verwenden Sie den Befehl 'yunohost log show {name}{name}'",
+ "log_help_to_get_log": "Um das Protokoll der Operation '{desc}' anzuzeigen, verwenden Sie den Befehl 'yunohost log show {name}'",
"global_settings_setting_security_nginx_compatibility": "Kompatibilitäts- vs. Sicherheits-Kompromiss für den Webserver NGINX. Betrifft die Ciphers (und andere sicherheitsrelevante Aspekte)",
"global_settings_setting_service_ssh_allow_deprecated_dsa_hostkey": "Erlaubt die Verwendung eines (veralteten) DSA-Hostkeys für die SSH-Daemon-Konfiguration",
"log_app_remove": "Entferne die Applikation '{}'",
diff --git a/locales/en.json b/locales/en.json
index c8417e1e6..282576ee8 100644
--- a/locales/en.json
+++ b/locales/en.json
@@ -15,6 +15,8 @@
"app_already_up_to_date": "{app} is already up-to-date",
"app_argument_choice_invalid": "Use one of these choices '{choices}' for the argument '{name}' instead of '{value}'",
"app_argument_invalid": "Pick a valid value for the argument '{name}': {error}",
+ "app_argument_password_help_keep": "Press Enter to keep the current value",
+ "app_argument_password_help_optional": "Type one space to empty the password",
"app_argument_password_no_default": "Error while parsing password argument '{name}': password argument can't have a default value for security reason",
"app_argument_required": "Argument '{name}' is required",
"app_change_url_identical_domains": "The old and new domain/url_path are identical ('{domain}{path}'), nothing to do.",
@@ -424,7 +426,7 @@
"log_dyndns_subscribe": "Subscribe to a YunoHost subdomain '{}'",
"log_dyndns_update": "Update the IP associated with your YunoHost subdomain '{}'",
"log_help_to_get_failed_log": "The operation '{desc}' could not be completed. Please share the full log of this operation using the command 'yunohost log share {name}' to get help",
- "log_help_to_get_log": "To view the log of the operation '{desc}', use the command 'yunohost log show {name}{name}'",
+ "log_help_to_get_log": "To view the log of the operation '{desc}', use the command 'yunohost log show {name}'",
"log_letsencrypt_cert_install": "Install a Let's Encrypt certificate on '{}' domain",
"log_letsencrypt_cert_renew": "Renew '{}' Let's Encrypt certificate",
"log_link_to_failed_log": "Could not complete the operation '{desc}'. Please provide the full log of this operation by clicking here to get help",
diff --git a/locales/eo.json b/locales/eo.json
index f40111f04..1904cfd9a 100644
--- a/locales/eo.json
+++ b/locales/eo.json
@@ -326,7 +326,7 @@
"log_dyndns_subscribe": "Aboni al YunoHost-subdominio '{}'",
"password_too_simple_4": "La pasvorto bezonas almenaŭ 12 signojn kaj enhavas ciferon, majuskle, pli malaltan kaj specialajn signojn",
"regenconf_file_updated": "Agordodosiero '{conf}' ĝisdatigita",
- "log_help_to_get_log": "Por vidi la protokolon de la operacio '{desc}', uzu la komandon 'yunohost log show {name}{name}'",
+ "log_help_to_get_log": "Por vidi la protokolon de la operacio '{desc}', uzu la komandon 'yunohost log show {name}'",
"global_settings_setting_security_nginx_compatibility": "Kongruo vs sekureca kompromiso por la TTT-servilo NGINX. Afektas la ĉifradojn (kaj aliajn aspektojn pri sekureco)",
"restore_complete": "Restarigita",
"hook_exec_failed": "Ne povis funkcii skripto: {path}",
diff --git a/locales/es.json b/locales/es.json
index 9af875898..ecb12d912 100644
--- a/locales/es.json
+++ b/locales/es.json
@@ -325,7 +325,7 @@
"log_does_exists": "No existe ningún registro de actividades con el nombre '{log}', ejecute 'yunohost log list' para ver todos los registros de actividades disponibles",
"log_help_to_get_failed_log": "No se pudo completar la operación «{desc}». Para obtener ayuda, comparta el registro completo de esta operación ejecutando la orden «yunohost log share {name}»",
"log_link_to_failed_log": "No se pudo completar la operación «{desc}». Para obtener ayuda, proporcione el registro completo de esta operación pulsando aquí",
- "log_help_to_get_log": "Para ver el registro de la operación «{desc}», ejecute la orden «yunohost log show {name}{name}»",
+ "log_help_to_get_log": "Para ver el registro de la operación «{desc}», ejecute la orden «yunohost log show {name}»",
"log_link_to_log": "Registro completo de esta operación: «{desc}»",
"log_corrupted_md_file": "El archivo de metadatos YAML asociado con el registro está dañado: «{md_file}\nError: {error}»",
"hook_json_return_error": "No se pudo leer la respuesta del gancho {path}. Error: {msg}. Contenido sin procesar: {raw_content}",
diff --git a/locales/fa.json b/locales/fa.json
index 3e78c5de0..d9d3cb175 100644
--- a/locales/fa.json
+++ b/locales/fa.json
@@ -500,7 +500,7 @@
"log_does_exists": "هیچ گزارش عملیاتی با نام '{log}' وجود ندارد ، برای مشاهده همه گزارش عملیّات های موجود در خط فرمان از دستور 'yunohost log list' استفاده کنید",
"log_help_to_get_failed_log": "عملیات '{desc}' کامل نشد. لطفاً برای دریافت راهنمایی و کمک ، گزارش کامل این عملیات را با استفاده از دستور 'yunohost log share {name}' به اشتراک بگذارید",
"log_link_to_failed_log": "عملیّات '{desc}' کامل نشد. لطفاً گزارش کامل این عملیات را ارائه دهید بواسطه اینجا را کلیک کنید برای دریافت کمک",
- "log_help_to_get_log": "برای مشاهده گزارش عملیات '{desc}'، از دستور 'yunohost log show {name}{name}' استفاده کنید",
+ "log_help_to_get_log": "برای مشاهده گزارش عملیات '{desc}'، از دستور 'yunohost log show {name}' استفاده کنید",
"log_link_to_log": "گزارش کامل این عملیات: {desc}'",
"log_corrupted_md_file": "فایل فوق داده YAML مربوط به گزارش ها آسیب دیده است: '{md_file}\nخطا: {error} '",
"ldap_server_is_down_restart_it": "سرویس LDAP خاموش است ، سعی کنید آن را دوباره راه اندازی کنید...",
diff --git a/locales/fr.json b/locales/fr.json
index a11ef3b43..55eb4ecd4 100644
--- a/locales/fr.json
+++ b/locales/fr.json
@@ -251,7 +251,7 @@
"experimental_feature": "Attention : cette fonctionnalité est expérimentale et ne doit pas être considérée comme stable, vous ne devriez pas l'utiliser à moins que vous ne sachiez ce que vous faites.",
"log_corrupted_md_file": "Le fichier YAML de métadonnées associé aux logs est corrompu : '{md_file}'\nErreur : {error}",
"log_link_to_log": "Journal complet de cette opération : ' {desc} '",
- "log_help_to_get_log": "Pour voir le journal de cette opération '{desc}', utilisez la commande 'yunohost log show {name}{name}'",
+ "log_help_to_get_log": "Pour voir le journal de cette opération '{desc}', utilisez la commande 'yunohost log show {name}'",
"log_link_to_failed_log": "L'opération '{desc}' a échoué ! Pour obtenir de l'aide, merci de partager le journal de l'opération en cliquant ici",
"log_help_to_get_failed_log": "L'opération '{desc}' a échoué ! Pour obtenir de l'aide, merci de partager le journal de l'opération en utilisant la commande 'yunohost log share {name}'",
"log_does_exists": "Il n'y a pas de journal des opérations avec le nom '{log}', utilisez 'yunohost log list' pour voir tous les journaux d'opérations disponibles",
diff --git a/locales/gl.json b/locales/gl.json
index 1a3c570c2..7976c11e9 100644
--- a/locales/gl.json
+++ b/locales/gl.json
@@ -358,7 +358,7 @@
"global_settings_setting_security_webadmin_allowlist_enabled": "Permitir que só algúns IPs accedan á webadmin.",
"disk_space_not_sufficient_update": "Non hai espazo suficiente no disco para actualizar esta aplicación",
"disk_space_not_sufficient_install": "Non queda espazo suficiente no disco para instalar esta aplicación",
- "log_help_to_get_log": "Para ver o rexistro completo da operación '{desc}', usa o comando 'yunohost log show {name}{name}'",
+ "log_help_to_get_log": "Para ver o rexistro completo da operación '{desc}', usa o comando 'yunohost log show {name}'",
"log_link_to_log": "Rexistro completo desta operación: '{desc}'",
"log_corrupted_md_file": "O ficheiro YAML con metadatos asociado aos rexistros está danado: '{md_file}\nErro: {error}'",
"iptables_unavailable": "Non podes andar remexendo en iptables aquí. Ou ben estás nun contedor ou o teu kernel non ten soporte para isto",
diff --git a/locales/it.json b/locales/it.json
index dc998d8d4..7bd048ac7 100644
--- a/locales/it.json
+++ b/locales/it.json
@@ -249,7 +249,7 @@
"good_practices_about_admin_password": "Stai per impostare una nuova password di amministratore. La password deve essere almeno di 8 caratteri - anche se è buona pratica utilizzare password più lunghe (es. una frase, una serie di parole) e/o utilizzare vari tipi di caratteri (maiuscole, minuscole, numeri e simboli).",
"log_corrupted_md_file": "Il file dei metadati YAML associato con i registri è danneggiato: '{md_file}'\nErrore: {error}",
"log_link_to_log": "Registro completo di questa operazione: '{desc}'",
- "log_help_to_get_log": "Per vedere il registro dell'operazione '{desc}', usa il comando 'yunohost log show {name}{name}'",
+ "log_help_to_get_log": "Per vedere il registro dell'operazione '{desc}', usa il comando 'yunohost log show {name}'",
"global_settings_setting_security_postfix_compatibility": "Bilanciamento tra compatibilità e sicurezza per il server Postfix. Riguarda gli algoritmi di cifratura (e altri aspetti legati alla sicurezza)",
"log_link_to_failed_log": "Impossibile completare l'operazione '{desc}'! Per ricevere aiuto, per favore fornisci il registro completo dell'operazione cliccando qui",
"log_help_to_get_failed_log": "L'operazione '{desc}' non può essere completata. Per ottenere aiuto, per favore condividi il registro completo dell'operazione utilizzando il comando 'yunohost log share {name}'",
diff --git a/locales/nb_NO.json b/locales/nb_NO.json
index 037e09cb6..221f974ab 100644
--- a/locales/nb_NO.json
+++ b/locales/nb_NO.json
@@ -115,7 +115,7 @@
"domain_deletion_failed": "Kunne ikke slette domene",
"domain_dyndns_already_subscribed": "Du har allerede abonnement på et DynDNS-domene",
"log_link_to_log": "Full logg for denne operasjonen: '{desc}'",
- "log_help_to_get_log": "For å vise loggen for operasjonen '{desc}', bruk kommandoen 'yunohost log show {name}{name}'",
+ "log_help_to_get_log": "For å vise loggen for operasjonen '{desc}', bruk kommandoen 'yunohost log show {name}'",
"log_user_create": "Legg til '{}' bruker",
"app_change_url_success": "{app} nettadressen er nå {domain}{path}",
"app_install_failed": "Kunne ikke installere {app}: {error}"
diff --git a/locales/oc.json b/locales/oc.json
index 995c61b16..27d4aeca9 100644
--- a/locales/oc.json
+++ b/locales/oc.json
@@ -248,7 +248,7 @@
"experimental_feature": "Atencion : aquesta foncionalitat es experimentala e deu pas èsser considerada coma establa, deuriatz pas l’utilizar levat que sapiatz çò que fasètz.",
"log_corrupted_md_file": "Lo fichièr YAML de metadonadas ligat als jornals d’audit es damatjat : « {md_file} »\nError : {error}",
"log_link_to_log": "Jornal complèt d’aquesta operacion : {desc}",
- "log_help_to_get_log": "Per veire lo jornal d’aquesta operacion « {desc} », utilizatz la comanda « yunohost log show {name}{name} »",
+ "log_help_to_get_log": "Per veire lo jornal d’aquesta operacion « {desc} », utilizatz la comanda « yunohost log show {name} »",
"log_link_to_failed_log": "L’operacion « {desc} » a pas capitat ! Per obténer d’ajuda, mercés de fornir lo jornal complèt de l’operacion",
"log_help_to_get_failed_log": "L’operacion « {desc} » a pas reüssit ! Per obténer d’ajuda, mercés de partejar lo jornal d’audit complèt d’aquesta operacion en utilizant la comanda « yunohost log share {name} »",
"log_does_exists": "I a pas cap de jornal d’audit per l’operacion amb lo nom « {log} », utilizatz « yunohost log list » per veire totes los jornals d’operacion disponibles",
diff --git a/locales/uk.json b/locales/uk.json
index 0de15a830..150e8c240 100644
--- a/locales/uk.json
+++ b/locales/uk.json
@@ -248,7 +248,7 @@
"log_does_exists": "Немає журналу операцій з назвою '{log}', використовуйте 'yunohost log list', щоб подивитися всі доступні журнали операцій",
"log_help_to_get_failed_log": "Операція '{desc}' не може бути завершена. Будь ласка, поділіться повним журналом цієї операції, використовуючи команду 'yunohost log share {name}', щоб отримати допомогу",
"log_link_to_failed_log": "Не вдалося завершити операцію '{desc}'. Будь ласка, надайте повний журнал цієї операції, натиснувши тут, щоб отримати допомогу",
- "log_help_to_get_log": "Щоб переглянути журнал операції '{desc}', використовуйте команду 'yunohost log show {name}{name}'",
+ "log_help_to_get_log": "Щоб переглянути журнал операції '{desc}', використовуйте команду 'yunohost log show {name}'",
"log_link_to_log": "Повний журнал цієї операції: '{desc}'",
"log_corrupted_md_file": "Файл метаданих YAML, пов'язаний з журналами, пошкоджено: '{md_file}\nПомилка: {error}'",
"iptables_unavailable": "Ви не можете грати з iptables тут. Ви перебуваєте або в контейнері, або ваше ядро не підтримує його",
diff --git a/locales/zh_Hans.json b/locales/zh_Hans.json
index 560ee0db0..e6b4d1cc8 100644
--- a/locales/zh_Hans.json
+++ b/locales/zh_Hans.json
@@ -511,7 +511,7 @@
"log_does_exists": "没有名称为'{log}'的操作日志,请使用 'yunohost log list' 查看所有可用的操作日志",
"log_help_to_get_failed_log": "操作'{desc}'无法完成。请使用命令'yunohost log share {name}' 共享此操作的完整日志以获取帮助",
"log_link_to_failed_log": "无法完成操作 '{desc}'。请通过单击此处提供此操作的完整日志以获取帮助",
- "log_help_to_get_log": "要查看操作'{desc}'的日志,请使用命令'yunohost log show {name}{name}'",
+ "log_help_to_get_log": "要查看操作'{desc}'的日志,请使用命令'yunohost log show {name}'",
"log_link_to_log": "此操作的完整日志: '{desc}'",
"log_corrupted_md_file": "与日志关联的YAML元数据文件已损坏: '{md_file}\n错误: {error}'",
"iptables_unavailable": "你不能在这里使用iptables。你要么在一个容器中,要么你的内核不支持它",
diff --git a/src/yunohost/app.py b/src/yunohost/app.py
index cf58af597..871e3dc00 100644
--- a/src/yunohost/app.py
+++ b/src/yunohost/app.py
@@ -1652,25 +1652,34 @@ def app_action_run(operation_logger, app, action, args=None):
)
env_dict["YNH_ACTION"] = action
- _, path = tempfile.mkstemp()
+ tmp_workdir_for_app = _make_tmp_workdir_for_app(app=app)
+ _, action_script = tempfile.mkstemp(dir=tmp_workdir_for_app)
- with open(path, "w") as script:
+ with open(action_script, "w") as script:
script.write(action_declaration["command"])
- os.chmod(path, 700)
-
if action_declaration.get("cwd"):
cwd = action_declaration["cwd"].replace("$app", app)
else:
- cwd = os.path.join(APPS_SETTING_PATH, app)
+ cwd = tmp_workdir_for_app
- # FIXME: this should probably be ran in a tmp workdir...
- retcode = hook_exec(
- path,
- env=env_dict,
- chdir=cwd,
- user=action_declaration.get("user", "root"),
- )[0]
+ try:
+ retcode = hook_exec(
+ action_script,
+ env=env_dict,
+ chdir=cwd,
+ user=action_declaration.get("user", "root"),
+ )[0]
+ # Calling hook_exec could fail miserably, or get
+ # manually interrupted (by mistake or because script was stuck)
+ # In that case we still want to delete the tmp work dir
+ except (KeyboardInterrupt, EOFError, Exception):
+ retcode = -1
+ import traceback
+
+ logger.error(m18n.n("unexpected_error", error="\n" + traceback.format_exc()))
+ finally:
+ shutil.rmtree(tmp_workdir_for_app)
if retcode not in action_declaration.get("accepted_return_codes", [0]):
msg = "Error while executing action '%s' of app '%s': return code %s" % (
@@ -1681,8 +1690,6 @@ def app_action_run(operation_logger, app, action, args=None):
operation_logger.error(msg)
raise YunohostError(msg, raw_msg=True)
- os.remove(path)
-
operation_logger.success()
return logger.success("Action successed!")
@@ -1760,7 +1767,6 @@ class AppConfigPanel(ConfigPanel):
default_script = """#!/bin/bash
source /usr/share/yunohost/helpers
ynh_abort_if_errors
-final_path=$(ynh_app_setting_get $app final_path)
ynh_app_config_run $1
"""
write_to_file(config_script, default_script)
@@ -1768,11 +1774,13 @@ ynh_app_config_run $1
# Call config script to extract current values
logger.debug(f"Calling '{action}' action from config script")
app_id, app_instance_nb = _parse_app_instance_name(self.app)
+ settings = _get_app_settings(app_id)
env.update(
{
"app_id": app_id,
"app": self.app,
"app_instance_nb": str(app_instance_nb),
+ "final_path": settings.get("final_path", "")
}
)
@@ -2173,6 +2181,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/tests/test_questions.py b/src/yunohost/tests/test_questions.py
index 93149b272..67b50769b 100644
--- a/src/yunohost/tests/test_questions.py
+++ b/src/yunohost/tests/test_questions.py
@@ -552,7 +552,7 @@ def test_question_password_input_test_ask():
prompt.assert_called_with(
message=ask_text,
is_password=True,
- confirm=True,
+ confirm=False,
prefill="",
is_multiline=False,
)
diff --git a/src/yunohost/utils/config.py b/src/yunohost/utils/config.py
index abb901e84..0b6b472cd 100644
--- a/src/yunohost/utils/config.py
+++ b/src/yunohost/utils/config.py
@@ -203,7 +203,6 @@ class ConfigPanel:
"panels": {
"properties": ["name", "services", "actions", "help"],
"default": {
- "name": "",
"services": [],
"actions": {"apply": {"en": "Apply"}},
},
@@ -277,7 +276,9 @@ class ConfigPanel:
continue
subnode = convert(value, subnode_type)
subnode["id"] = key
- if node_type == "sections":
+ if node_type == "toml":
+ subnode.setdefault("name", {"en": key.capitalize()})
+ elif node_type == "sections":
subnode["name"] = key # legacy
subnode.setdefault("optional", toml_node.get("optional", True))
node.setdefault(subnode_type, []).append(subnode)
@@ -364,7 +365,8 @@ class ConfigPanel:
display_header(f"\n{'='*40}\n>>>> {name}\n{'='*40}")
continue
name = _value_for_locale(section["name"])
- display_header(f"\n# {name}")
+ if name:
+ display_header(f"\n# {name}")
# Check and ask unanswered questions
self.new_values.update(
@@ -473,6 +475,20 @@ class Question(object):
def normalize(value, option={}):
return value
+ def _prompt(self, text):
+ prefill = ""
+ if self.current_value is not None:
+ prefill = self.humanize(self.current_value, self)
+ elif self.default is not None:
+ prefill = self.humanize(self.default, self)
+ self.value = Moulinette.prompt(
+ message=text,
+ is_password=self.hide_user_input_in_prompt,
+ confirm=False, # We doesn't want to confirm this kind of password like in webadmin
+ prefill=prefill,
+ is_multiline=(self.type == "text"),
+ )
+
def ask_if_needed(self):
for i in range(5):
# Display question if no value filled or if it's a readonly message
@@ -480,20 +496,8 @@ class Question(object):
text_for_user_input_in_cli = self._format_text_for_user_input_in_cli()
if getattr(self, "readonly", False):
Moulinette.display(text_for_user_input_in_cli)
-
elif self.value is None:
- prefill = ""
- if self.current_value is not None:
- prefill = self.humanize(self.current_value, self)
- elif self.default is not None:
- prefill = self.humanize(self.default, self)
- self.value = Moulinette.prompt(
- message=text_for_user_input_in_cli,
- is_password=self.hide_user_input_in_prompt,
- confirm=self.hide_user_input_in_prompt,
- prefill=prefill,
- is_multiline=(self.type == "text"),
- )
+ self._prompt(text_for_user_input_in_cli)
# Apply default value
class_default = getattr(self, "default_value", None)
@@ -529,7 +533,7 @@ class Question(object):
raise YunohostValidationError("app_argument_required", name=self.name)
# we have an answer, do some post checks
- if self.value is not None:
+ if self.value not in [None, ""]:
if self.choices and self.value not in self.choices:
self._raise_invalid_answer()
if self.pattern and not re.match(self.pattern["regexp"], str(self.value)):
@@ -547,13 +551,13 @@ class Question(object):
choices=", ".join(self.choices),
)
- def _format_text_for_user_input_in_cli(self):
+ def _format_text_for_user_input_in_cli(self, column=False):
text_for_user_input_in_cli = _value_for_locale(self.ask)
if self.choices:
text_for_user_input_in_cli += " [{0}]".format(" | ".join(self.choices))
- if self.help:
+ if self.help or column:
text_for_user_input_in_cli += ":\033[m"
if self.help:
text_for_user_input_in_cli += "\n - "
@@ -694,6 +698,23 @@ class PasswordQuestion(Question):
assert_password_is_strong_enough("user", self.value)
+ def _format_text_for_user_input_in_cli(self):
+ need_column = self.current_value or self.optional
+ text_for_user_input_in_cli = super()._format_text_for_user_input_in_cli(need_column)
+ if self.current_value:
+ text_for_user_input_in_cli += "\n - " + m18n.n("app_argument_password_help_keep")
+ if self.optional:
+ text_for_user_input_in_cli += "\n - " + m18n.n("app_argument_password_help_optional")
+
+ return text_for_user_input_in_cli
+
+ def _prompt(self, text):
+ super()._prompt(text)
+ if self.current_value and self.value == "":
+ self.value = self.current_value
+ elif self.value == " ":
+ self.value = ""
+
class PathQuestion(Question):
argument_type = "path"
@@ -802,6 +823,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():