Add semantic of YunohostValidationError for all exceptions which are related to validating stuff

This commit is contained in:
Alexandre Aubin 2021-03-11 01:39:52 +01:00
parent b85d959d7e
commit 01ccab5252
19 changed files with 187 additions and 178 deletions

View file

@ -54,7 +54,7 @@ from moulinette.utils.filesystem import (
from yunohost.service import service_status, _run_service_command from yunohost.service import service_status, _run_service_command
from yunohost.utils import packages from yunohost.utils import packages
from yunohost.utils.error import YunohostError from yunohost.utils.error import YunohostError, YunohostValidationError
from yunohost.log import is_unit_operation, OperationLogger from yunohost.log import is_unit_operation, OperationLogger
logger = getActionLogger("yunohost.app") logger = getActionLogger("yunohost.app")
@ -192,7 +192,7 @@ def app_info(app, full=False):
from yunohost.permission import user_permission_list from yunohost.permission import user_permission_list
if not _is_installed(app): if not _is_installed(app):
raise YunohostError( raise YunohostValidationError(
"app_not_installed", app=app, all_apps=_get_all_installed_apps_id() "app_not_installed", app=app, all_apps=_get_all_installed_apps_id()
) )
@ -321,7 +321,7 @@ def app_map(app=None, raw=False, user=None):
if app is not None: if app is not None:
if not _is_installed(app): if not _is_installed(app):
raise YunohostError( raise YunohostValidationError(
"app_not_installed", app=app, all_apps=_get_all_installed_apps_id() "app_not_installed", app=app, all_apps=_get_all_installed_apps_id()
) )
apps = [ apps = [
@ -421,14 +421,14 @@ def app_change_url(operation_logger, app, domain, path):
installed = _is_installed(app) installed = _is_installed(app)
if not installed: if not installed:
raise YunohostError( raise YunohostValidationError(
"app_not_installed", app=app, all_apps=_get_all_installed_apps_id() "app_not_installed", app=app, all_apps=_get_all_installed_apps_id()
) )
if not os.path.exists( if not os.path.exists(
os.path.join(APPS_SETTING_PATH, app, "scripts", "change_url") os.path.join(APPS_SETTING_PATH, app, "scripts", "change_url")
): ):
raise YunohostError("app_change_url_no_script", app_name=app) raise YunohostValidationError("app_change_url_no_script", app_name=app)
old_domain = app_setting(app, "domain") old_domain = app_setting(app, "domain")
old_path = app_setting(app, "path") old_path = app_setting(app, "path")
@ -438,7 +438,7 @@ def app_change_url(operation_logger, app, domain, path):
domain, path = _normalize_domain_path(domain, path) domain, path = _normalize_domain_path(domain, path)
if (domain, path) == (old_domain, old_path): if (domain, path) == (old_domain, old_path):
raise YunohostError( raise YunohostValidationError(
"app_change_url_identical_domains", domain=domain, path=path "app_change_url_identical_domains", domain=domain, path=path
) )
@ -551,12 +551,12 @@ def app_upgrade(app=[], url=None, file=None, force=False):
# Abort if any of those app is in fact not installed.. # Abort if any of those app is in fact not installed..
for app in [app_ for app_ in apps if not _is_installed(app_)]: for app in [app_ for app_ in apps if not _is_installed(app_)]:
raise YunohostError( raise YunohostValidationError(
"app_not_installed", app=app, all_apps=_get_all_installed_apps_id() "app_not_installed", app=app, all_apps=_get_all_installed_apps_id()
) )
if len(apps) == 0: if len(apps) == 0:
raise YunohostError("apps_already_up_to_date") raise YunohostValidationError("apps_already_up_to_date")
if len(apps) > 1: if len(apps) > 1:
logger.info(m18n.n("app_upgrade_several_apps", apps=", ".join(apps))) logger.info(m18n.n("app_upgrade_several_apps", apps=", ".join(apps)))
@ -880,11 +880,11 @@ def app_install(
confirm_install("thirdparty") confirm_install("thirdparty")
manifest, extracted_app_folder = _extract_app_from_file(app) manifest, extracted_app_folder = _extract_app_from_file(app)
else: else:
raise YunohostError("app_unknown") raise YunohostValidationError("app_unknown")
# Check ID # Check ID
if "id" not in manifest or "__" in manifest["id"]: if "id" not in manifest or "__" in manifest["id"]:
raise YunohostError("app_id_invalid") raise YunohostValidationError("app_id_invalid")
app_id = manifest["id"] app_id = manifest["id"]
label = label if label else manifest["name"] label = label if label else manifest["name"]
@ -897,7 +897,7 @@ def app_install(
instance_number = _installed_instance_number(app_id, last=True) + 1 instance_number = _installed_instance_number(app_id, last=True) + 1
if instance_number > 1: if instance_number > 1:
if "multi_instance" not in manifest or not is_true(manifest["multi_instance"]): if "multi_instance" not in manifest or not is_true(manifest["multi_instance"]):
raise YunohostError("app_already_installed", app=app_id) raise YunohostValidationError("app_already_installed", app=app_id)
# Change app_id to the forked app id # Change app_id to the forked app id
app_instance_name = app_id + "__" + str(instance_number) app_instance_name = app_id + "__" + str(instance_number)
@ -1209,7 +1209,7 @@ def app_remove(operation_logger, app):
) )
if not _is_installed(app): if not _is_installed(app):
raise YunohostError( raise YunohostValidationError(
"app_not_installed", app=app, all_apps=_get_all_installed_apps_id() "app_not_installed", app=app, all_apps=_get_all_installed_apps_id()
) )
@ -1372,10 +1372,10 @@ def app_makedefault(operation_logger, app, domain=None):
domain = app_domain domain = app_domain
operation_logger.related_to.append(("domain", domain)) operation_logger.related_to.append(("domain", domain))
elif domain not in domain_list()["domains"]: elif domain not in domain_list()["domains"]:
raise YunohostError("domain_name_unknown", domain=domain) raise YunohostValidationError("domain_name_unknown", domain=domain)
if "/" in app_map(raw=True)[domain]: if "/" in app_map(raw=True)[domain]:
raise YunohostError( raise YunohostValidationError(
"app_make_default_location_already_used", "app_make_default_location_already_used",
app=app, app=app,
domain=app_domain, domain=app_domain,
@ -1578,7 +1578,7 @@ def app_register_url(app, domain, path):
if _is_installed(app): if _is_installed(app):
settings = _get_app_settings(app) settings = _get_app_settings(app)
if "path" in settings.keys() and "domain" in settings.keys(): if "path" in settings.keys() and "domain" in settings.keys():
raise YunohostError("app_already_installed_cant_change_url") raise YunohostValidationError("app_already_installed_cant_change_url")
# Check the url is available # Check the url is available
_assert_no_conflicting_apps(domain, path) _assert_no_conflicting_apps(domain, path)
@ -1694,7 +1694,7 @@ def app_change_label(app, new_label):
installed = _is_installed(app) installed = _is_installed(app)
if not installed: if not installed:
raise YunohostError( raise YunohostValidationError(
"app_not_installed", app=app, all_apps=_get_all_installed_apps_id() "app_not_installed", app=app, all_apps=_get_all_installed_apps_id()
) )
logger.warning(m18n.n("app_label_deprecated")) logger.warning(m18n.n("app_label_deprecated"))
@ -1730,7 +1730,7 @@ def app_action_run(operation_logger, app, action, args=None):
actions = {x["id"]: x for x in actions} actions = {x["id"]: x for x in actions}
if action not in actions: if action not in actions:
raise YunohostError( raise YunohostValidationError(
"action '%s' not available for app '%s', available actions are: %s" "action '%s' not available for app '%s', available actions are: %s"
% (action, app, ", ".join(actions.keys())), % (action, app, ", ".join(actions.keys())),
raw_msg=True, raw_msg=True,
@ -1884,7 +1884,7 @@ def app_config_apply(operation_logger, app, args):
installed = _is_installed(app) installed = _is_installed(app)
if not installed: if not installed:
raise YunohostError( raise YunohostValidationError(
"app_not_installed", app=app, all_apps=_get_all_installed_apps_id() "app_not_installed", app=app, all_apps=_get_all_installed_apps_id()
) )
@ -2199,7 +2199,7 @@ def _get_app_settings(app_id):
""" """
if not _is_installed(app_id): if not _is_installed(app_id):
raise YunohostError( raise YunohostValidationError(
"app_not_installed", app=app_id, all_apps=_get_all_installed_apps_id() "app_not_installed", app=app_id, all_apps=_get_all_installed_apps_id()
) )
try: try:
@ -2546,9 +2546,9 @@ def _fetch_app_from_git(app):
app_id, _ = _parse_app_instance_name(app) app_id, _ = _parse_app_instance_name(app)
if app_id not in app_dict: if app_id not in app_dict:
raise YunohostError("app_unknown") raise YunohostValidationError("app_unknown")
elif "git" not in app_dict[app_id]: elif "git" not in app_dict[app_id]:
raise YunohostError("app_unsupported_remote_type") raise YunohostValidationError("app_unsupported_remote_type")
app_info = app_dict[app_id] app_info = app_dict[app_id]
url = app_info["git"]["url"] url = app_info["git"]["url"]
@ -2684,7 +2684,7 @@ def _check_manifest_requirements(manifest, app_instance_name):
packaging_format = int(manifest.get("packaging_format", 0)) packaging_format = int(manifest.get("packaging_format", 0))
if packaging_format not in [0, 1]: if packaging_format not in [0, 1]:
raise YunohostError("app_packaging_format_not_supported") raise YunohostValidationError("app_packaging_format_not_supported")
requirements = manifest.get("requirements", dict()) requirements = manifest.get("requirements", dict())
@ -2697,7 +2697,7 @@ def _check_manifest_requirements(manifest, app_instance_name):
for pkgname, spec in requirements.items(): for pkgname, spec in requirements.items():
if not packages.meets_version_specifier(pkgname, spec): if not packages.meets_version_specifier(pkgname, spec):
version = packages.ynh_packages_version()[pkgname]["version"] version = packages.ynh_packages_version()[pkgname]["version"]
raise YunohostError( raise YunohostValidationError(
"app_requirements_unmeet", "app_requirements_unmeet",
pkgname=pkgname, pkgname=pkgname,
version=version, version=version,
@ -2796,7 +2796,7 @@ class YunoHostArgumentFormatParser(object):
# we don't have an answer, check optional and default_value # we don't have an answer, check optional and default_value
if question.value is None or question.value == "": if question.value is None or question.value == "":
if not question.optional and question.default is None: if not question.optional and question.default is None:
raise YunohostError("app_argument_required", name=question.name) raise YunohostValidationError("app_argument_required", name=question.name)
else: else:
question.value = ( question.value = (
getattr(self, "default_value", None) getattr(self, "default_value", None)
@ -2816,7 +2816,7 @@ class YunoHostArgumentFormatParser(object):
return (question.value, self.argument_type) return (question.value, self.argument_type)
def _raise_invalid_answer(self, question): def _raise_invalid_answer(self, question):
raise YunohostError( raise YunohostValidationError(
"app_argument_choice_invalid", "app_argument_choice_invalid",
name=question.name, name=question.name,
choices=", ".join(question.choices), choices=", ".join(question.choices),
@ -2854,13 +2854,13 @@ class PasswordArgumentParser(YunoHostArgumentFormatParser):
) )
if question.default is not None: if question.default is not None:
raise YunohostError("app_argument_password_no_default", name=question.name) raise YunohostValidationError("app_argument_password_no_default", name=question.name)
return question return question
def _post_parse_value(self, question): def _post_parse_value(self, question):
if any(char in question.value for char in self.forbidden_chars): if any(char in question.value for char in self.forbidden_chars):
raise YunohostError( raise YunohostValidationError(
"pattern_password_app", forbidden_chars=self.forbidden_chars "pattern_password_app", forbidden_chars=self.forbidden_chars
) )
@ -2913,7 +2913,7 @@ class BooleanArgumentParser(YunoHostArgumentFormatParser):
if str(question.value).lower() in ["0", "no", "n", "false"]: if str(question.value).lower() in ["0", "no", "n", "false"]:
return 0 return 0
raise YunohostError( raise YunohostValidationError(
"app_argument_choice_invalid", "app_argument_choice_invalid",
name=question.name, name=question.name,
choices="yes, no, y, n, 1, 0", choices="yes, no, y, n, 1, 0",
@ -2938,7 +2938,7 @@ class DomainArgumentParser(YunoHostArgumentFormatParser):
return question return question
def _raise_invalid_answer(self, question): def _raise_invalid_answer(self, question):
raise YunohostError( raise YunohostValidationError(
"app_argument_invalid", name=question.name, error=m18n.n("domain_unknown") "app_argument_invalid", name=question.name, error=m18n.n("domain_unknown")
) )
@ -2964,7 +2964,7 @@ class UserArgumentParser(YunoHostArgumentFormatParser):
return question return question
def _raise_invalid_answer(self, question): def _raise_invalid_answer(self, question):
raise YunohostError( raise YunohostValidationError(
"app_argument_invalid", "app_argument_invalid",
name=question.name, name=question.name,
error=m18n.n("user_unknown", user=question.value), error=m18n.n("user_unknown", user=question.value),
@ -2992,7 +2992,7 @@ class NumberArgumentParser(YunoHostArgumentFormatParser):
if isinstance(question.value, str) and question.value.isdigit(): if isinstance(question.value, str) and question.value.isdigit():
return int(question.value) return int(question.value)
raise YunohostError( raise YunohostValidationError(
"app_argument_invalid", name=question.name, error=m18n.n("invalid_number") "app_argument_invalid", name=question.name, error=m18n.n("invalid_number")
) )
@ -3123,7 +3123,7 @@ def _get_conflicting_apps(domain, path, ignore_app=None):
# Abort if domain is unknown # Abort if domain is unknown
if domain not in domain_list()["domains"]: if domain not in domain_list()["domains"]:
raise YunohostError("domain_name_unknown", domain=domain) raise YunohostValidationError("domain_name_unknown", domain=domain)
# Fetch apps map # Fetch apps map
apps_map = app_map(raw=True) apps_map = app_map(raw=True)
@ -3162,9 +3162,9 @@ def _assert_no_conflicting_apps(domain, path, ignore_app=None, full_domain=False
) )
if full_domain: if full_domain:
raise YunohostError("app_full_domain_unavailable", domain=domain) raise YunohostValidationError("app_full_domain_unavailable", domain=domain)
else: else:
raise YunohostError("app_location_unavailable", apps="\n".join(apps)) raise YunohostValidationError("app_location_unavailable", apps="\n".join(apps))
def _make_environment_for_app_script(app, args={}, args_prefix="APP_ARG_"): def _make_environment_for_app_script(app, args={}, args_prefix="APP_ARG_"):
@ -3469,7 +3469,7 @@ def _assert_system_is_sane_for_app(manifest, when):
faulty_services = [s for s in services if service_status(s)["status"] != "running"] faulty_services = [s for s in services if service_status(s)["status"] != "running"]
if faulty_services: if faulty_services:
if when == "pre": if when == "pre":
raise YunohostError( raise YunohostValidationError(
"app_action_cannot_be_ran_because_required_services_down", "app_action_cannot_be_ran_because_required_services_down",
services=", ".join(faulty_services), services=", ".join(faulty_services),
) )
@ -3480,7 +3480,7 @@ def _assert_system_is_sane_for_app(manifest, when):
if packages.dpkg_is_broken(): if packages.dpkg_is_broken():
if when == "pre": if when == "pre":
raise YunohostError("dpkg_is_broken") raise YunohostValidationError("dpkg_is_broken")
elif when == "post": elif when == "post":
raise YunohostError("this_action_broke_dpkg") raise YunohostError("this_action_broke_dpkg")
@ -3659,7 +3659,7 @@ def _patch_legacy_helpers(app_folder):
# couldn't patch the deprecated helper in the previous lines. In # couldn't patch the deprecated helper in the previous lines. In
# that case, abort the install or whichever step is performed # that case, abort the install or whichever step is performed
if helper in content and infos["important"]: if helper in content and infos["important"]:
raise YunohostError( raise YunohostValidationError(
"This app is likely pretty old and uses deprecated / outdated helpers that can't be migrated easily. It can't be installed anymore.", "This app is likely pretty old and uses deprecated / outdated helpers that can't be migrated easily. It can't be installed anymore.",
raw_msg=True, raw_msg=True,
) )

View file

@ -348,7 +348,7 @@ class BackupManager:
# Try to recursively unmount stuff (from a previously failed backup ?) # Try to recursively unmount stuff (from a previously failed backup ?)
if not _recursive_umount(self.work_dir): if not _recursive_umount(self.work_dir):
raise YunohostError("backup_output_directory_not_empty") raise YunohostValidationError("backup_output_directory_not_empty")
else: else:
# If umount succeeded, remove the directory (we checked that # If umount succeeded, remove the directory (we checked that
# we're in /home/yunohost.backup/tmp so that should be okay... # we're in /home/yunohost.backup/tmp so that should be okay...
@ -1027,7 +1027,7 @@ class RestoreManager:
already_installed = [app for app in to_be_restored if _is_installed(app)] already_installed = [app for app in to_be_restored if _is_installed(app)]
if already_installed != []: if already_installed != []:
if already_installed == to_be_restored: if already_installed == to_be_restored:
raise YunohostError( raise YunohostValidationError(
"restore_already_installed_apps", apps=", ".join(already_installed) "restore_already_installed_apps", apps=", ".join(already_installed)
) )
else: else:
@ -1133,14 +1133,14 @@ class RestoreManager:
return True return True
elif free_space > needed_space: elif free_space > needed_space:
# TODO Add --force options to avoid the error raising # TODO Add --force options to avoid the error raising
raise YunohostError( raise YunohostValidationError(
"restore_may_be_not_enough_disk_space", "restore_may_be_not_enough_disk_space",
free_space=free_space, free_space=free_space,
needed_space=needed_space, needed_space=needed_space,
margin=margin, margin=margin,
) )
else: else:
raise YunohostError( raise YunohostValidationError(
"restore_not_enough_disk_space", "restore_not_enough_disk_space",
free_space=free_space, free_space=free_space,
needed_space=needed_space, needed_space=needed_space,
@ -1729,7 +1729,7 @@ class BackupMethod(object):
free_space, free_space,
backup_size, backup_size,
) )
raise YunohostError("not_enough_disk_space", path=self.repo) raise YunohostValidationError("not_enough_disk_space", path=self.repo)
def _organize_files(self): def _organize_files(self):
""" """
@ -2186,7 +2186,7 @@ def backup_create(
# Validate there is no archive with the same name # Validate there is no archive with the same name
if name and name in backup_list()["archives"]: if name and name in backup_list()["archives"]:
raise YunohostError("backup_archive_name_exists") raise YunohostValidationError("backup_archive_name_exists")
# By default we backup using the tar method # By default we backup using the tar method
if not methods: if not methods:
@ -2201,14 +2201,14 @@ def backup_create(
r"^/(|(bin|boot|dev|etc|lib|root|run|sbin|sys|usr|var)(|/.*))$", r"^/(|(bin|boot|dev|etc|lib|root|run|sbin|sys|usr|var)(|/.*))$",
output_directory, output_directory,
): ):
raise YunohostError("backup_output_directory_forbidden") raise YunohostValidationError("backup_output_directory_forbidden")
if "copy" in methods: if "copy" in methods:
if not output_directory: if not output_directory:
raise YunohostError("backup_output_directory_required") raise YunohostValidationError("backup_output_directory_required")
# Check that output directory is empty # Check that output directory is empty
elif os.path.isdir(output_directory) and os.listdir(output_directory): elif os.path.isdir(output_directory) and os.listdir(output_directory):
raise YunohostError("backup_output_directory_not_empty") raise YunohostValidationError("backup_output_directory_not_empty")
# If no --system or --apps given, backup everything # If no --system or --apps given, backup everything
if system is None and apps is None: if system is None and apps is None:
@ -2381,7 +2381,7 @@ def backup_download(name):
if not os.path.lexists(archive_file): if not os.path.lexists(archive_file):
archive_file += ".gz" archive_file += ".gz"
if not os.path.lexists(archive_file): if not os.path.lexists(archive_file):
raise YunohostError("backup_archive_name_unknown", name=name) raise YunohostValidationError("backup_archive_name_unknown", name=name)
# If symlink, retrieve the real path # If symlink, retrieve the real path
if os.path.islink(archive_file): if os.path.islink(archive_file):
@ -2389,7 +2389,7 @@ def backup_download(name):
# Raise exception if link is broken (e.g. on unmounted external storage) # Raise exception if link is broken (e.g. on unmounted external storage)
if not os.path.exists(archive_file): if not os.path.exists(archive_file):
raise YunohostError("backup_archive_broken_link", path=archive_file) raise YunohostValidationError("backup_archive_broken_link", path=archive_file)
# We return a raw bottle HTTPresponse (instead of serializable data like # We return a raw bottle HTTPresponse (instead of serializable data like
# list/dict, ...), which is gonna be picked and used directly by moulinette # list/dict, ...), which is gonna be picked and used directly by moulinette
@ -2415,7 +2415,7 @@ def backup_info(name, with_details=False, human_readable=False):
if not os.path.lexists(archive_file): if not os.path.lexists(archive_file):
archive_file += ".gz" archive_file += ".gz"
if not os.path.lexists(archive_file): if not os.path.lexists(archive_file):
raise YunohostError("backup_archive_name_unknown", name=name) raise YunohostValidationError("backup_archive_name_unknown", name=name)
# If symlink, retrieve the real path # If symlink, retrieve the real path
if os.path.islink(archive_file): if os.path.islink(archive_file):
@ -2423,7 +2423,7 @@ def backup_info(name, with_details=False, human_readable=False):
# Raise exception if link is broken (e.g. on unmounted external storage) # Raise exception if link is broken (e.g. on unmounted external storage)
if not os.path.exists(archive_file): if not os.path.exists(archive_file):
raise YunohostError("backup_archive_broken_link", path=archive_file) raise YunohostValidationError("backup_archive_broken_link", path=archive_file)
info_file = "%s/%s.info.json" % (ARCHIVES_PATH, name) info_file = "%s/%s.info.json" % (ARCHIVES_PATH, name)
@ -2531,7 +2531,7 @@ def backup_delete(name):
""" """
if name not in backup_list()["archives"]: if name not in backup_list()["archives"]:
raise YunohostError("backup_archive_name_unknown", name=name) raise YunohostValidationError("backup_archive_name_unknown", name=name)
hook_callback("pre_backup_delete", args=[name]) hook_callback("pre_backup_delete", args=[name])

View file

@ -37,7 +37,7 @@ from moulinette.utils.log import getActionLogger
from moulinette.utils.filesystem import read_file from moulinette.utils.filesystem import read_file
from yunohost.vendor.acme_tiny.acme_tiny import get_crt as sign_certificate from yunohost.vendor.acme_tiny.acme_tiny import get_crt as sign_certificate
from yunohost.utils.error import YunohostError from yunohost.utils.error import YunohostError, YunohostValidationError
from yunohost.utils.network import get_public_ip from yunohost.utils.network import get_public_ip
from yunohost.diagnosis import Diagnoser from yunohost.diagnosis import Diagnoser
@ -90,7 +90,7 @@ def certificate_status(domain_list, full=False):
for domain in domain_list: for domain in domain_list:
# Is it in Yunohost domain list? # Is it in Yunohost domain list?
if domain not in yunohost_domains_list: if domain not in yunohost_domains_list:
raise YunohostError("domain_name_unknown", domain=domain) raise YunohostValidationError("domain_name_unknown", domain=domain)
certificates = {} certificates = {}
@ -166,7 +166,7 @@ def _certificate_install_selfsigned(domain_list, force=False):
status = _get_status(domain) status = _get_status(domain)
if status["summary"]["code"] in ("good", "great"): if status["summary"]["code"] in ("good", "great"):
raise YunohostError( raise YunohostValidationError(
"certmanager_attempt_to_replace_valid_cert", domain=domain "certmanager_attempt_to_replace_valid_cert", domain=domain
) )
@ -267,12 +267,12 @@ def _certificate_install_letsencrypt(
for domain in domain_list: for domain in domain_list:
yunohost_domains_list = yunohost.domain.domain_list()["domains"] yunohost_domains_list = yunohost.domain.domain_list()["domains"]
if domain not in yunohost_domains_list: if domain not in yunohost_domains_list:
raise YunohostError("domain_name_unknown", domain=domain) raise YunohostValidationError("domain_name_unknown", domain=domain)
# Is it self-signed? # Is it self-signed?
status = _get_status(domain) status = _get_status(domain)
if not force and status["CA_type"]["code"] != "self-signed": if not force and status["CA_type"]["code"] != "self-signed":
raise YunohostError( raise YunohostValidationError(
"certmanager_domain_cert_not_selfsigned", domain=domain "certmanager_domain_cert_not_selfsigned", domain=domain
) )
@ -370,25 +370,25 @@ def certificate_renew(
# Is it in Yunohost dmomain list? # Is it in Yunohost dmomain list?
if domain not in yunohost.domain.domain_list()["domains"]: if domain not in yunohost.domain.domain_list()["domains"]:
raise YunohostError("domain_name_unknown", domain=domain) raise YunohostValidationError("domain_name_unknown", domain=domain)
status = _get_status(domain) status = _get_status(domain)
# Does it expire soon? # Does it expire soon?
if status["validity"] > VALIDITY_LIMIT and not force: if status["validity"] > VALIDITY_LIMIT and not force:
raise YunohostError( raise YunohostValidationError(
"certmanager_attempt_to_renew_valid_cert", domain=domain "certmanager_attempt_to_renew_valid_cert", domain=domain
) )
# Does it have a Let's Encrypt cert? # Does it have a Let's Encrypt cert?
if status["CA_type"]["code"] != "lets-encrypt": if status["CA_type"]["code"] != "lets-encrypt":
raise YunohostError( raise YunohostValidationError(
"certmanager_attempt_to_renew_nonLE_cert", domain=domain "certmanager_attempt_to_renew_nonLE_cert", domain=domain
) )
# Check ACME challenge configured for given domain # Check ACME challenge configured for given domain
if not _check_acme_challenge_configuration(domain): if not _check_acme_challenge_configuration(domain):
raise YunohostError( raise YunohostValidationError(
"certmanager_acme_not_configured_for_domain", domain=domain "certmanager_acme_not_configured_for_domain", domain=domain
) )
@ -898,20 +898,20 @@ def _check_domain_is_ready_for_ACME(domain):
) )
if not dnsrecords or not httpreachable: if not dnsrecords or not httpreachable:
raise YunohostError("certmanager_domain_not_diagnosed_yet", domain=domain) raise YunohostValidationError("certmanager_domain_not_diagnosed_yet", domain=domain)
# Check if IP from DNS matches public IP # Check if IP from DNS matches public IP
if not dnsrecords.get("status") in [ if not dnsrecords.get("status") in [
"SUCCESS", "SUCCESS",
"WARNING", "WARNING",
]: # Warning is for missing IPv6 record which ain't critical for ACME ]: # Warning is for missing IPv6 record which ain't critical for ACME
raise YunohostError( raise YunohostValidationError(
"certmanager_domain_dns_ip_differs_from_public_ip", domain=domain "certmanager_domain_dns_ip_differs_from_public_ip", domain=domain
) )
# Check if domain seems to be accessible through HTTP? # Check if domain seems to be accessible through HTTP?
if not httpreachable.get("status") == "SUCCESS": if not httpreachable.get("status") == "SUCCESS":
raise YunohostError("certmanager_domain_http_not_working", domain=domain) raise YunohostValidationError("certmanager_domain_http_not_working", domain=domain)
# FIXME / TODO : ideally this should not be needed. There should be a proper # FIXME / TODO : ideally this should not be needed. There should be a proper

View file

@ -23,7 +23,7 @@ class MyMigration(Migration):
return return
if not self.package_is_installed("postgresql-11"): if not self.package_is_installed("postgresql-11"):
raise YunohostError("migration_0017_postgresql_11_not_installed") raise YunohostValidationError("migration_0017_postgresql_11_not_installed")
# Make sure there's a 9.6 cluster # Make sure there's a 9.6 cluster
try: try:
@ -37,7 +37,7 @@ class MyMigration(Migration):
if not space_used_by_directory( if not space_used_by_directory(
"/var/lib/postgresql/9.6" "/var/lib/postgresql/9.6"
) > free_space_in_directory("/var/lib/postgresql"): ) > free_space_in_directory("/var/lib/postgresql"):
raise YunohostError( raise YunohostValidationError(
"migration_0017_not_enough_space", path="/var/lib/postgresql/" "migration_0017_not_enough_space", path="/var/lib/postgresql/"
) )

View file

@ -37,7 +37,7 @@ from moulinette.utils.filesystem import (
write_to_yaml, write_to_yaml,
) )
from yunohost.utils.error import YunohostError from yunohost.utils.error import YunohostError, YunohostValidationError
from yunohost.hook import hook_list, hook_exec from yunohost.hook import hook_list, hook_exec
logger = log.getActionLogger("yunohost.diagnosis") logger = log.getActionLogger("yunohost.diagnosis")
@ -59,11 +59,11 @@ def diagnosis_get(category, item):
all_categories_names = [c for c, _ in all_categories] all_categories_names = [c for c, _ in all_categories]
if category not in all_categories_names: if category not in all_categories_names:
raise YunohostError("diagnosis_unknown_categories", categories=category) raise YunohostValidationError("diagnosis_unknown_categories", categories=category)
if isinstance(item, list): if isinstance(item, list):
if any("=" not in criteria for criteria in item): if any("=" not in criteria for criteria in item):
raise YunohostError( raise YunohostValidationError(
"Criterias should be of the form key=value (e.g. domain=yolo.test)" "Criterias should be of the form key=value (e.g. domain=yolo.test)"
) )
@ -91,7 +91,7 @@ def diagnosis_show(
else: else:
unknown_categories = [c for c in categories if c not in all_categories_names] unknown_categories = [c for c in categories if c not in all_categories_names]
if unknown_categories: if unknown_categories:
raise YunohostError( raise YunohostValidationError(
"diagnosis_unknown_categories", categories=", ".join(unknown_categories) "diagnosis_unknown_categories", categories=", ".join(unknown_categories)
) )
@ -181,7 +181,7 @@ def diagnosis_run(
else: else:
unknown_categories = [c for c in categories if c not in all_categories_names] unknown_categories = [c for c in categories if c not in all_categories_names]
if unknown_categories: if unknown_categories:
raise YunohostError( raise YunohostValidationError(
"diagnosis_unknown_categories", categories=", ".join(unknown_categories) "diagnosis_unknown_categories", categories=", ".join(unknown_categories)
) )
@ -270,14 +270,14 @@ def diagnosis_ignore(add_filter=None, remove_filter=None, list=False):
# Sanity checks for the provided arguments # Sanity checks for the provided arguments
if len(filter_) == 0: if len(filter_) == 0:
raise YunohostError( raise YunohostValidationError(
"You should provide at least one criteria being the diagnosis category to ignore" "You should provide at least one criteria being the diagnosis category to ignore"
) )
category = filter_[0] category = filter_[0]
if category not in all_categories_names: if category not in all_categories_names:
raise YunohostError("%s is not a diagnosis category" % category) raise YunohostValidationError("%s is not a diagnosis category" % category)
if any("=" not in criteria for criteria in filter_[1:]): if any("=" not in criteria for criteria in filter_[1:]):
raise YunohostError( raise YunohostValidationError(
"Criterias should be of the form key=value (e.g. domain=yolo.test)" "Criterias should be of the form key=value (e.g. domain=yolo.test)"
) )
@ -331,7 +331,7 @@ def diagnosis_ignore(add_filter=None, remove_filter=None, list=False):
configuration["ignore_filters"][category] = [] configuration["ignore_filters"][category] = []
if criterias not in configuration["ignore_filters"][category]: if criterias not in configuration["ignore_filters"][category]:
raise YunohostError("This filter does not exists.") raise YunohostValidationError("This filter does not exists.")
configuration["ignore_filters"][category].remove(criterias) configuration["ignore_filters"][category].remove(criterias)
_diagnosis_write_configuration(configuration) _diagnosis_write_configuration(configuration)

View file

@ -101,16 +101,14 @@ def domain_add(operation_logger, domain, dyndns=False):
from yunohost.utils.ldap import _get_ldap_interface from yunohost.utils.ldap import _get_ldap_interface
if domain.startswith("xmpp-upload."): if domain.startswith("xmpp-upload."):
raise YunohostError("domain_cannot_add_xmpp_upload") raise YunohostValidationError("domain_cannot_add_xmpp_upload")
ldap = _get_ldap_interface() ldap = _get_ldap_interface()
try: try:
ldap.validate_uniqueness({"virtualdomain": domain}) ldap.validate_uniqueness({"virtualdomain": domain})
except MoulinetteError: except MoulinetteError:
raise YunohostError("domain_exists") raise YunohostValidationError("domain_exists")
operation_logger.start()
# Lower domain to avoid some edge cases issues # Lower domain to avoid some edge cases issues
# See: https://forum.yunohost.org/t/invalid-domain-causes-diagnosis-web-to-fail-fr-on-demand/11765 # See: https://forum.yunohost.org/t/invalid-domain-causes-diagnosis-web-to-fail-fr-on-demand/11765
@ -119,17 +117,21 @@ def domain_add(operation_logger, domain, dyndns=False):
# DynDNS domain # DynDNS domain
if dyndns: if dyndns:
from yunohost.dyndns import dyndns_subscribe, _dyndns_provides, _guess_current_dyndns_domain from yunohost.dyndns import _dyndns_provides, _guess_current_dyndns_domain
# Do not allow to subscribe to multiple dyndns domains... # Do not allow to subscribe to multiple dyndns domains...
if _guess_current_dyndns_domain("dyndns.yunohost.org") != (None, None): if _guess_current_dyndns_domain("dyndns.yunohost.org") != (None, None):
raise YunohostError('domain_dyndns_already_subscribed') raise YunohostValidationError('domain_dyndns_already_subscribed')
# Check that this domain can effectively be provided by # Check that this domain can effectively be provided by
# dyndns.yunohost.org. (i.e. is it a nohost.me / noho.st) # dyndns.yunohost.org. (i.e. is it a nohost.me / noho.st)
if not _dyndns_provides("dyndns.yunohost.org", domain): if not _dyndns_provides("dyndns.yunohost.org", domain):
raise YunohostError("domain_dyndns_root_unknown") raise YunohostValidationError("domain_dyndns_root_unknown")
operation_logger.start()
if dyndns:
from yunohost.dyndns import dndns_subscribe
# Actually subscribe # Actually subscribe
dyndns_subscribe(domain=domain) dyndns_subscribe(domain=domain)
@ -197,7 +199,7 @@ def domain_remove(operation_logger, domain, remove_apps=False, force=False):
# we don't want to check the domain exists because the ldap add may have # we don't want to check the domain exists because the ldap add may have
# failed # failed
if not force and domain not in domain_list()['domains']: if not force and domain not in domain_list()['domains']:
raise YunohostError('domain_name_unknown', domain=domain) raise YunohostValidationError('domain_name_unknown', domain=domain)
# Check domain is not the main domain # Check domain is not the main domain
if domain == _get_maindomain(): if domain == _get_maindomain():
@ -205,13 +207,13 @@ def domain_remove(operation_logger, domain, remove_apps=False, force=False):
other_domains.remove(domain) other_domains.remove(domain)
if other_domains: if other_domains:
raise YunohostError( raise YunohostValidationError(
"domain_cannot_remove_main", "domain_cannot_remove_main",
domain=domain, domain=domain,
other_domains="\n * " + ("\n * ".join(other_domains)), other_domains="\n * " + ("\n * ".join(other_domains)),
) )
else: else:
raise YunohostError("domain_cannot_remove_main_add_new_one", domain=domain) raise YunohostValidationError("domain_cannot_remove_main_add_new_one", domain=domain)
# Check if apps are installed on the domain # Check if apps are installed on the domain
apps_on_that_domain = [] apps_on_that_domain = []
@ -234,9 +236,10 @@ def domain_remove(operation_logger, domain, remove_apps=False, force=False):
for app, _ in apps_on_that_domain: for app, _ in apps_on_that_domain:
app_remove(app) app_remove(app)
else: else:
raise YunohostError('domain_uninstall_app_first', apps="\n".join([x[1] for x in apps_on_that_domain])) raise YunohostValidationError('domain_uninstall_app_first', apps="\n".join([x[1] for x in apps_on_that_domain]))
operation_logger.start() operation_logger.start()
ldap = _get_ldap_interface() ldap = _get_ldap_interface()
try: try:
ldap.remove("virtualdomain=" + domain + ",ou=domains") ldap.remove("virtualdomain=" + domain + ",ou=domains")
@ -288,7 +291,7 @@ def domain_dns_conf(domain, ttl=None):
""" """
if domain not in domain_list()["domains"]: if domain not in domain_list()["domains"]:
raise YunohostError("domain_name_unknown", domain=domain) raise YunohostValidationError("domain_name_unknown", domain=domain)
ttl = 3600 if ttl is None else ttl ttl = 3600 if ttl is None else ttl
@ -345,7 +348,7 @@ def domain_main_domain(operation_logger, new_main_domain=None):
# Check domain exists # Check domain exists
if new_main_domain not in domain_list()["domains"]: if new_main_domain not in domain_list()["domains"]:
raise YunohostError("domain_name_unknown", domain=new_main_domain) raise YunohostValidationError("domain_name_unknown", domain=new_main_domain)
operation_logger.related_to.append(("domain", new_main_domain)) operation_logger.related_to.append(("domain", new_main_domain))
operation_logger.start() operation_logger.start()

View file

@ -36,7 +36,7 @@ from moulinette.utils.log import getActionLogger
from moulinette.utils.filesystem import write_to_file, read_file from moulinette.utils.filesystem import write_to_file, read_file
from moulinette.utils.network import download_json from moulinette.utils.network import download_json
from yunohost.utils.error import YunohostError from yunohost.utils.error import YunohostError, YunohostValidationError
from yunohost.domain import _get_maindomain, _build_dns_conf from yunohost.domain import _get_maindomain, _build_dns_conf
from yunohost.utils.network import get_public_ip, dig from yunohost.utils.network import get_public_ip, dig
from yunohost.log import is_unit_operation from yunohost.log import is_unit_operation
@ -124,7 +124,7 @@ def dyndns_subscribe(
""" """
if _guess_current_dyndns_domain(subscribe_host) != (None, None): if _guess_current_dyndns_domain(subscribe_host) != (None, None):
raise YunohostError('domain_dyndns_already_subscribed') raise YunohostValidationError('domain_dyndns_already_subscribed')
if domain is None: if domain is None:
domain = _get_maindomain() domain = _get_maindomain()
@ -132,13 +132,13 @@ def dyndns_subscribe(
# Verify if domain is provided by subscribe_host # Verify if domain is provided by subscribe_host
if not _dyndns_provides(subscribe_host, domain): if not _dyndns_provides(subscribe_host, domain):
raise YunohostError( raise YunohostValidationError(
"dyndns_domain_not_provided", domain=domain, provider=subscribe_host "dyndns_domain_not_provided", domain=domain, provider=subscribe_host
) )
# Verify if domain is available # Verify if domain is available
if not _dyndns_available(subscribe_host, domain): if not _dyndns_available(subscribe_host, domain):
raise YunohostError("dyndns_unavailable", domain=domain) raise YunohostValidationError("dyndns_unavailable", domain=domain)
operation_logger.start() operation_logger.start()
@ -231,7 +231,7 @@ def dyndns_update(
(domain, key) = _guess_current_dyndns_domain(dyn_host) (domain, key) = _guess_current_dyndns_domain(dyn_host)
if domain is None: if domain is None:
raise YunohostError('dyndns_no_domain_registered') raise YunohostValidationError('dyndns_no_domain_registered')
# If key is not given, pick the first file we find with the domain given # If key is not given, pick the first file we find with the domain given
else: else:
@ -239,7 +239,7 @@ def dyndns_update(
keys = glob.glob("/etc/yunohost/dyndns/K{0}.+*.private".format(domain)) keys = glob.glob("/etc/yunohost/dyndns/K{0}.+*.private".format(domain))
if not keys: if not keys:
raise YunohostError("dyndns_key_not_found") raise YunohostValidationError("dyndns_key_not_found")
key = keys[0] key = keys[0]

View file

@ -28,7 +28,7 @@ import yaml
import miniupnpc import miniupnpc
from moulinette import m18n from moulinette import m18n
from yunohost.utils.error import YunohostError from yunohost.utils.error import YunohostError, YunohostValidationError
from moulinette.utils import process from moulinette.utils import process
from moulinette.utils.log import getActionLogger from moulinette.utils.log import getActionLogger
from moulinette.utils.text import prependlines from moulinette.utils.text import prependlines
@ -366,7 +366,7 @@ def firewall_upnp(action="status", no_refresh=False):
if action == "status": if action == "status":
no_refresh = True no_refresh = True
else: else:
raise YunohostError("action_invalid", action=action) raise YunohostValidationError("action_invalid", action=action)
# Refresh port mapping using UPnP # Refresh port mapping using UPnP
if not no_refresh: if not no_refresh:

View file

@ -32,7 +32,7 @@ from glob import iglob
from importlib import import_module from importlib import import_module
from moulinette import m18n, msettings from moulinette import m18n, msettings
from yunohost.utils.error import YunohostError from yunohost.utils.error import YunohostError, YunohostValidationError
from moulinette.utils import log from moulinette.utils import log
from moulinette.utils.filesystem import read_json from moulinette.utils.filesystem import read_json
@ -117,7 +117,7 @@ def hook_info(action, name):
) )
if not hooks: if not hooks:
raise YunohostError("hook_name_unknown", name=name) raise YunohostValidationError("hook_name_unknown", name=name)
return { return {
"action": action, "action": action,
"name": name, "name": name,
@ -186,7 +186,7 @@ def hook_list(action, list_by="name", show_info=False):
d.add(name) d.add(name)
else: else:
raise YunohostError("hook_list_by_invalid") raise YunohostValidationError("hook_list_by_invalid")
def _append_folder(d, folder): def _append_folder(d, folder):
# Iterate over and add hook from a folder # Iterate over and add hook from a folder
@ -273,7 +273,7 @@ def hook_callback(
try: try:
hl = hooks_names[n] hl = hooks_names[n]
except KeyError: except KeyError:
raise YunohostError("hook_name_unknown", n) raise YunohostValidationError("hook_name_unknown", n)
# Iterate over hooks with this name # Iterate over hooks with this name
for h in hl: for h in hl:
# Update hooks dict # Update hooks dict

View file

@ -191,7 +191,7 @@ def log_show(
log_path = base_path + LOG_FILE_EXT log_path = base_path + LOG_FILE_EXT
if not os.path.exists(md_path) and not os.path.exists(log_path): if not os.path.exists(md_path) and not os.path.exists(log_path):
raise YunohostError("log_does_exists", log=path) raise YunohostValidationError("log_does_exists", log=path)
infos = {} infos = {}

View file

@ -31,7 +31,7 @@ import random
from moulinette import m18n from moulinette import m18n
from moulinette.utils.log import getActionLogger from moulinette.utils.log import getActionLogger
from yunohost.utils.error import YunohostError from yunohost.utils.error import YunohostError, YunohostValidationError
from yunohost.log import is_unit_operation from yunohost.log import is_unit_operation
logger = getActionLogger("yunohost.user") logger = getActionLogger("yunohost.user")
@ -175,14 +175,14 @@ def user_permission_update(
# Refuse to add "visitors" to mail, xmpp ... they require an account to make sense. # Refuse to add "visitors" to mail, xmpp ... they require an account to make sense.
if add and "visitors" in add and permission.split(".")[0] in SYSTEM_PERMS: if add and "visitors" in add and permission.split(".")[0] in SYSTEM_PERMS:
raise YunohostError("permission_require_account", permission=permission) raise YunohostValidationError("permission_require_account", permission=permission)
# Refuse to add "visitors" to protected permission # Refuse to add "visitors" to protected permission
if ( if (
(add and "visitors" in add and existing_permission["protected"]) (add and "visitors" in add and existing_permission["protected"])
or (remove and "visitors" in remove and existing_permission["protected"]) or (remove and "visitors" in remove and existing_permission["protected"])
) and not force: ) and not force:
raise YunohostError("permission_protected", permission=permission) raise YunohostValidationError("permission_protected", permission=permission)
# Fetch currently allowed groups for this permission # Fetch currently allowed groups for this permission
@ -198,7 +198,7 @@ def user_permission_update(
groups_to_add = [add] if not isinstance(add, list) else add groups_to_add = [add] if not isinstance(add, list) else add
for group in groups_to_add: for group in groups_to_add:
if group not in all_existing_groups: if group not in all_existing_groups:
raise YunohostError("group_unknown", group=group) raise YunohostValidationError("group_unknown", group=group)
if group in current_allowed_groups: if group in current_allowed_groups:
logger.warning( logger.warning(
m18n.n( m18n.n(
@ -326,7 +326,7 @@ def user_permission_info(permission):
permission, None permission, None
) )
if existing_permission is None: if existing_permission is None:
raise YunohostError("permission_not_found", permission=permission) raise YunohostValidationError("permission_not_found", permission=permission)
return existing_permission return existing_permission
@ -391,7 +391,7 @@ def permission_create(
if ldap.get_conflict( if ldap.get_conflict(
{"cn": permission}, base_dn="ou=permission,dc=yunohost,dc=org" {"cn": permission}, base_dn="ou=permission,dc=yunohost,dc=org"
): ):
raise YunohostError("permission_already_exist", permission=permission) raise YunohostValidationError("permission_already_exist", permission=permission)
# Get random GID # Get random GID
all_gid = {x.gr_gid for x in grp.getgrall()} all_gid = {x.gr_gid for x in grp.getgrall()}
@ -427,7 +427,7 @@ def permission_create(
all_existing_groups = user_group_list()["groups"].keys() all_existing_groups = user_group_list()["groups"].keys()
for group in allowed or []: for group in allowed or []:
if group not in all_existing_groups: if group not in all_existing_groups:
raise YunohostError("group_unknown", group=group) raise YunohostValidationError("group_unknown", group=group)
operation_logger.related_to.append(("app", permission.split(".")[0])) operation_logger.related_to.append(("app", permission.split(".")[0]))
operation_logger.start() operation_logger.start()
@ -594,7 +594,7 @@ def permission_delete(operation_logger, permission, force=False, sync_perm=True)
permission = permission + ".main" permission = permission + ".main"
if permission.endswith(".main") and not force: if permission.endswith(".main") and not force:
raise YunohostError("permission_cannot_remove_main") raise YunohostValidationError("permission_cannot_remove_main")
from yunohost.utils.ldap import _get_ldap_interface from yunohost.utils.ldap import _get_ldap_interface
@ -861,7 +861,7 @@ def _validate_and_sanitize_permission_url(url, app_base_path, app):
try: try:
re.compile(regex) re.compile(regex)
except Exception: except Exception:
raise YunohostError("invalid_regex", regex=regex) raise YunohostValidationError("invalid_regex", regex=regex)
if url.startswith("re:"): if url.startswith("re:"):
@ -874,12 +874,12 @@ def _validate_and_sanitize_permission_url(url, app_base_path, app):
# regex with domain # regex with domain
if "/" not in url: if "/" not in url:
raise YunohostError("regex_with_only_domain") raise YunohostValidationError("regex_with_only_domain")
domain, path = url[3:].split("/", 1) domain, path = url[3:].split("/", 1)
path = "/" + path path = "/" + path
if domain.replace("%", "").replace("\\", "") not in domains: if domain.replace("%", "").replace("\\", "") not in domains:
raise YunohostError("domain_name_unknown", domain=domain) raise YunohostValidationError("domain_name_unknown", domain=domain)
validate_regex(path) validate_regex(path)
@ -914,7 +914,7 @@ def _validate_and_sanitize_permission_url(url, app_base_path, app):
sanitized_url = domain + path sanitized_url = domain + path
if domain not in domains: if domain not in domains:
raise YunohostError("domain_name_unknown", domain=domain) raise YunohostValidationError("domain_name_unknown", domain=domain)
_assert_no_conflicting_apps(domain, path, ignore_app=app) _assert_no_conflicting_apps(domain, path, ignore_app=app)

View file

@ -34,7 +34,7 @@ from glob import glob
from datetime import datetime from datetime import datetime
from moulinette import m18n from moulinette import m18n
from yunohost.utils.error import YunohostError from yunohost.utils.error import YunohostError, YunohostValidationError
from moulinette.utils.process import check_output from moulinette.utils.process import check_output
from moulinette.utils.log import getActionLogger from moulinette.utils.log import getActionLogger
from moulinette.utils.filesystem import read_file, append_to_file, write_to_file from moulinette.utils.filesystem import read_file, append_to_file, write_to_file
@ -145,7 +145,7 @@ def service_remove(name):
services = _get_services() services = _get_services()
if name not in services: if name not in services:
raise YunohostError("service_unknown", service=name) raise YunohostValidationError("service_unknown", service=name)
del services[name] del services[name]
try: try:
@ -325,7 +325,7 @@ def service_status(names=[]):
# Validate service names requested # Validate service names requested
for name in names: for name in names:
if name not in services.keys(): if name not in services.keys():
raise YunohostError("service_unknown", service=name) raise YunohostValidationError("service_unknown", service=name)
# Filter only requested servivces # Filter only requested servivces
services = {k: v for k, v in services.items() if k in names} services = {k: v for k, v in services.items() if k in names}
@ -484,7 +484,7 @@ def service_log(name, number=50):
number = int(number) number = int(number)
if name not in services.keys(): if name not in services.keys():
raise YunohostError("service_unknown", service=name) raise YunohostValidationError("service_unknown", service=name)
log_list = services[name].get("log", []) log_list = services[name].get("log", [])
@ -545,7 +545,7 @@ def service_regen_conf(
for name in names: for name in names:
if name not in services.keys(): if name not in services.keys():
raise YunohostError("service_unknown", service=name) raise YunohostValidationError("service_unknown", service=name)
if names is []: if names is []:
names = list(services.keys()) names = list(services.keys())
@ -568,7 +568,7 @@ def _run_service_command(action, service):
""" """
services = _get_services() services = _get_services()
if service not in services.keys(): if service not in services.keys():
raise YunohostError("service_unknown", service=service) raise YunohostValidationError("service_unknown", service=service)
possible_actions = [ possible_actions = [
"start", "start",

View file

@ -6,7 +6,7 @@ from datetime import datetime
from collections import OrderedDict from collections import OrderedDict
from moulinette import m18n from moulinette import m18n
from yunohost.utils.error import YunohostError from yunohost.utils.error import YunohostError, YunohostValidationError
from moulinette.utils.log import getActionLogger from moulinette.utils.log import getActionLogger
from yunohost.regenconf import regen_conf from yunohost.regenconf import regen_conf
@ -109,7 +109,7 @@ def settings_get(key, full=False):
settings = _get_settings() settings = _get_settings()
if key not in settings: if key not in settings:
raise YunohostError("global_settings_key_doesnt_exists", settings_key=key) raise YunohostValidationError("global_settings_key_doesnt_exists", settings_key=key)
if full: if full:
return settings[key] return settings[key]
@ -137,7 +137,7 @@ def settings_set(key, value):
settings = _get_settings() settings = _get_settings()
if key not in settings: if key not in settings:
raise YunohostError("global_settings_key_doesnt_exists", settings_key=key) raise YunohostValidationError("global_settings_key_doesnt_exists", settings_key=key)
key_type = settings[key]["type"] key_type = settings[key]["type"]
@ -146,7 +146,7 @@ def settings_set(key, value):
if boolean_value[0]: if boolean_value[0]:
value = boolean_value[1] value = boolean_value[1]
else: else:
raise YunohostError( raise YunohostValidationError(
"global_settings_bad_type_for_setting", "global_settings_bad_type_for_setting",
setting=key, setting=key,
received_type=type(value).__name__, received_type=type(value).__name__,
@ -158,14 +158,14 @@ def settings_set(key, value):
try: try:
value = int(value) value = int(value)
except Exception: except Exception:
raise YunohostError( raise YunohostValidationError(
"global_settings_bad_type_for_setting", "global_settings_bad_type_for_setting",
setting=key, setting=key,
received_type=type(value).__name__, received_type=type(value).__name__,
expected_type=key_type, expected_type=key_type,
) )
else: else:
raise YunohostError( raise YunohostValidationError(
"global_settings_bad_type_for_setting", "global_settings_bad_type_for_setting",
setting=key, setting=key,
received_type=type(value).__name__, received_type=type(value).__name__,
@ -173,7 +173,7 @@ def settings_set(key, value):
) )
elif key_type == "string": elif key_type == "string":
if not isinstance(value, str): if not isinstance(value, str):
raise YunohostError( raise YunohostValidationError(
"global_settings_bad_type_for_setting", "global_settings_bad_type_for_setting",
setting=key, setting=key,
received_type=type(value).__name__, received_type=type(value).__name__,
@ -181,14 +181,14 @@ def settings_set(key, value):
) )
elif key_type == "enum": elif key_type == "enum":
if value not in settings[key]["choices"]: if value not in settings[key]["choices"]:
raise YunohostError( raise YunohostValidationError(
"global_settings_bad_choice_for_enum", "global_settings_bad_choice_for_enum",
setting=key, setting=key,
choice=str(value), choice=str(value),
available_choices=", ".join(settings[key]["choices"]), available_choices=", ".join(settings[key]["choices"]),
) )
else: else:
raise YunohostError( raise YunohostValidationError(
"global_settings_unknown_type", setting=key, unknown_type=key_type "global_settings_unknown_type", setting=key, unknown_type=key_type
) )
@ -214,7 +214,7 @@ def settings_reset(key):
settings = _get_settings() settings = _get_settings()
if key not in settings: if key not in settings:
raise YunohostError("global_settings_key_doesnt_exists", settings_key=key) raise YunohostValidationError("global_settings_key_doesnt_exists", settings_key=key)
settings[key]["value"] = settings[key]["default"] settings[key]["value"] = settings[key]["default"]
_save_settings(settings) _save_settings(settings)
@ -304,7 +304,7 @@ def _get_settings():
) )
unknown_settings[key] = value unknown_settings[key] = value
except Exception as e: except Exception as e:
raise YunohostError("global_settings_cant_open_settings", reason=e) raise YunohostValidationError("global_settings_cant_open_settings", reason=e)
if unknown_settings: if unknown_settings:
try: try:

View file

@ -5,7 +5,7 @@ import os
import pwd import pwd
import subprocess import subprocess
from yunohost.utils.error import YunohostError from yunohost.utils.error import YunohostError, YunohostValidationError
from moulinette.utils.filesystem import read_file, write_to_file, chown, chmod, mkdir from moulinette.utils.filesystem import read_file, write_to_file, chown, chmod, mkdir
SSHD_CONFIG_PATH = "/etc/ssh/sshd_config" SSHD_CONFIG_PATH = "/etc/ssh/sshd_config"
@ -21,7 +21,7 @@ def user_ssh_allow(username):
# TODO it would be good to support different kind of shells # TODO it would be good to support different kind of shells
if not _get_user_for_ssh(username): if not _get_user_for_ssh(username):
raise YunohostError("user_unknown", user=username) raise YunohostValidationError("user_unknown", user=username)
from yunohost.utils.ldap import _get_ldap_interface from yunohost.utils.ldap import _get_ldap_interface
@ -43,7 +43,7 @@ def user_ssh_disallow(username):
# TODO it would be good to support different kind of shells # TODO it would be good to support different kind of shells
if not _get_user_for_ssh(username): if not _get_user_for_ssh(username):
raise YunohostError("user_unknown", user=username) raise YunohostValidationError("user_unknown", user=username)
from yunohost.utils.ldap import _get_ldap_interface from yunohost.utils.ldap import _get_ldap_interface

View file

@ -51,7 +51,7 @@ from yunohost.utils.packages import (
_list_upgradable_apt_packages, _list_upgradable_apt_packages,
ynh_packages_version, ynh_packages_version,
) )
from yunohost.utils.error import YunohostError from yunohost.utils.error import YunohostError, YunohostValidationError
from yunohost.log import is_unit_operation, OperationLogger from yunohost.log import is_unit_operation, OperationLogger
# FIXME this is a duplicate from apps.py # FIXME this is a duplicate from apps.py
@ -156,7 +156,7 @@ def tools_adminpw(new_password, check_strength=True):
# UNIX seems to not like password longer than 127 chars ... # UNIX seems to not like password longer than 127 chars ...
# e.g. SSH login gets broken (or even 'su admin' when entering the password) # e.g. SSH login gets broken (or even 'su admin' when entering the password)
if len(new_password) >= 127: if len(new_password) >= 127:
raise YunohostError("admin_password_too_long") raise YunohostValidationError("admin_password_too_long")
new_hash = _hash_user_password(new_password) new_hash = _hash_user_password(new_password)
@ -285,10 +285,10 @@ def tools_postinstall(
# Do some checks at first # Do some checks at first
if os.path.isfile("/etc/yunohost/installed"): if os.path.isfile("/etc/yunohost/installed"):
raise YunohostError("yunohost_already_installed") raise YunohostValidationError("yunohost_already_installed")
if os.path.isdir("/etc/yunohost/apps") and os.listdir("/etc/yunohost/apps") != []: if os.path.isdir("/etc/yunohost/apps") and os.listdir("/etc/yunohost/apps") != []:
raise YunohostError( raise YunohostValidationError(
"It looks like you're trying to re-postinstall a system that was already working previously ... If you recently had some bug or issues with your installation, please first discuss with the team on how to fix the situation instead of savagely re-running the postinstall ...", "It looks like you're trying to re-postinstall a system that was already working previously ... If you recently had some bug or issues with your installation, please first discuss with the team on how to fix the situation instead of savagely re-running the postinstall ...",
raw_msg=True, raw_msg=True,
) )
@ -301,7 +301,7 @@ def tools_postinstall(
) )
GB = 1024 ** 3 GB = 1024 ** 3
if not force_diskspace and main_space < 10 * GB: if not force_diskspace and main_space < 10 * GB:
raise YunohostError("postinstall_low_rootfsspace") raise YunohostValidationError("postinstall_low_rootfsspace")
# Check password # Check password
if not force_password: if not force_password:
@ -331,14 +331,14 @@ def tools_postinstall(
dyndns = True dyndns = True
# If not, abort the postinstall # If not, abort the postinstall
else: else:
raise YunohostError("dyndns_unavailable", domain=domain) raise YunohostValidationError("dyndns_unavailable", domain=domain)
else: else:
dyndns = False dyndns = False
else: else:
dyndns = False dyndns = False
if os.system("iptables -V >/dev/null 2>/dev/null") != 0: if os.system("iptables -V >/dev/null 2>/dev/null") != 0:
raise YunohostError( raise YunohostValidationError(
"iptables/nftables does not seems to be working on your setup. You may be in a container or your kernel does have the proper modules loaded. Sometimes, rebooting the machine may solve the issue.", "iptables/nftables does not seems to be working on your setup. You may be in a container or your kernel does have the proper modules loaded. Sometimes, rebooting the machine may solve the issue.",
raw_msg=True, raw_msg=True,
) )
@ -530,17 +530,17 @@ def tools_upgrade(
from yunohost.utils import packages from yunohost.utils import packages
if packages.dpkg_is_broken(): if packages.dpkg_is_broken():
raise YunohostError("dpkg_is_broken") raise YunohostValidationError("dpkg_is_broken")
# Check for obvious conflict with other dpkg/apt commands already running in parallel # Check for obvious conflict with other dpkg/apt commands already running in parallel
if not packages.dpkg_lock_available(): if not packages.dpkg_lock_available():
raise YunohostError("dpkg_lock_not_available") raise YunohostValidationError("dpkg_lock_not_available")
if system is not False and apps is not None: if system is not False and apps is not None:
raise YunohostError("tools_upgrade_cant_both") raise YunohostValidationError("tools_upgrade_cant_both")
if system is False and apps is None: if system is False and apps is None:
raise YunohostError("tools_upgrade_at_least_one") raise YunohostValidationError("tools_upgrade_at_least_one")
# #
# Apps # Apps
@ -825,7 +825,7 @@ def tools_migrations_list(pending=False, done=False):
# Check for option conflict # Check for option conflict
if pending and done: if pending and done:
raise YunohostError("migrations_list_conflict_pending_done") raise YunohostValidationError("migrations_list_conflict_pending_done")
# Get all migrations # Get all migrations
migrations = _get_migrations_list() migrations = _get_migrations_list()
@ -875,17 +875,17 @@ def tools_migrations_run(
if m.id == target or m.name == target or m.id.split("_")[0] == target: if m.id == target or m.name == target or m.id.split("_")[0] == target:
return m return m
raise YunohostError("migrations_no_such_migration", id=target) raise YunohostValidationError("migrations_no_such_migration", id=target)
# auto, skip and force are exclusive options # auto, skip and force are exclusive options
if auto + skip + force_rerun > 1: if auto + skip + force_rerun > 1:
raise YunohostError("migrations_exclusive_options") raise YunohostValidationError("migrations_exclusive_options")
# If no target specified # If no target specified
if not targets: if not targets:
# skip, revert or force require explicit targets # skip, revert or force require explicit targets
if skip or force_rerun: if skip or force_rerun:
raise YunohostError("migrations_must_provide_explicit_targets") raise YunohostValidationError("migrations_must_provide_explicit_targets")
# Otherwise, targets are all pending migrations # Otherwise, targets are all pending migrations
targets = [m for m in all_migrations if m.state == "pending"] targets = [m for m in all_migrations if m.state == "pending"]
@ -897,11 +897,11 @@ def tools_migrations_run(
pending = [t.id for t in targets if t.state == "pending"] pending = [t.id for t in targets if t.state == "pending"]
if skip and done: if skip and done:
raise YunohostError("migrations_not_pending_cant_skip", ids=", ".join(done)) raise YunohostValidationError("migrations_not_pending_cant_skip", ids=", ".join(done))
if force_rerun and pending: if force_rerun and pending:
raise YunohostError("migrations_pending_cant_rerun", ids=", ".join(pending)) raise YunohostValidationError("migrations_pending_cant_rerun", ids=", ".join(pending))
if not (skip or force_rerun) and done: if not (skip or force_rerun) and done:
raise YunohostError("migrations_already_ran", ids=", ".join(done)) raise YunohostValidationError("migrations_already_ran", ids=", ".join(done))
# So, is there actually something to do ? # So, is there actually something to do ?
if not targets: if not targets:

View file

@ -37,7 +37,7 @@ from moulinette import msignals, msettings, m18n
from moulinette.utils.log import getActionLogger from moulinette.utils.log import getActionLogger
from moulinette.utils.process import check_output from moulinette.utils.process import check_output
from yunohost.utils.error import YunohostError from yunohost.utils.error import YunohostError, YunohostValidationError
from yunohost.service import service_status from yunohost.service import service_status
from yunohost.log import is_unit_operation from yunohost.log import is_unit_operation
@ -125,7 +125,7 @@ def user_create(
# Validate domain used for email address/xmpp account # Validate domain used for email address/xmpp account
if domain is None: if domain is None:
if msettings.get("interface") == "api": if msettings.get("interface") == "api":
raise YunohostError("Invalide usage, specify domain argument") raise YunohostValidationError("Invalid usage, you should specify a domain argument")
else: else:
# On affiche les differents domaines possibles # On affiche les differents domaines possibles
msignals.display(m18n.n("domains_available")) msignals.display(m18n.n("domains_available"))
@ -141,24 +141,24 @@ def user_create(
# Check that the domain exists # Check that the domain exists
if domain not in domain_list()["domains"]: if domain not in domain_list()["domains"]:
raise YunohostError("domain_name_unknown", domain=domain) raise YunohostValidationError("domain_name_unknown", domain=domain)
mail = username + "@" + domain mail = username + "@" + domain
ldap = _get_ldap_interface() ldap = _get_ldap_interface()
if username in user_list()["users"]: if username in user_list()["users"]:
raise YunohostError("user_already_exists", user=username) raise YunohostValidationError("user_already_exists", user=username)
# Validate uniqueness of username and mail in LDAP # Validate uniqueness of username and mail in LDAP
try: try:
ldap.validate_uniqueness({"uid": username, "mail": mail, "cn": username}) ldap.validate_uniqueness({"uid": username, "mail": mail, "cn": username})
except Exception as e: except Exception as e:
raise YunohostError("user_creation_failed", user=username, error=e) raise YunohostValidationError("user_creation_failed", user=username, error=e)
# Validate uniqueness of username in system users # Validate uniqueness of username in system users
all_existing_usernames = {x.pw_name for x in pwd.getpwall()} all_existing_usernames = {x.pw_name for x in pwd.getpwall()}
if username in all_existing_usernames: if username in all_existing_usernames:
raise YunohostError("system_username_exists") raise YunohostValidationError("system_username_exists")
main_domain = _get_maindomain() main_domain = _get_maindomain()
aliases = [ aliases = [
@ -170,7 +170,7 @@ def user_create(
] ]
if mail in aliases: if mail in aliases:
raise YunohostError("mail_unavailable") raise YunohostValidationError("mail_unavailable")
operation_logger.start() operation_logger.start()
@ -264,7 +264,7 @@ def user_delete(operation_logger, username, purge=False):
from yunohost.utils.ldap import _get_ldap_interface from yunohost.utils.ldap import _get_ldap_interface
if username not in user_list()["users"]: if username not in user_list()["users"]:
raise YunohostError("user_unknown", user=username) raise YunohostValidationError("user_unknown", user=username)
operation_logger.start() operation_logger.start()
@ -347,7 +347,7 @@ def user_update(
attrs=attrs_to_fetch, attrs=attrs_to_fetch,
) )
if not result: if not result:
raise YunohostError("user_unknown", user=username) raise YunohostValidationError("user_unknown", user=username)
user = result[0] user = result[0]
env_dict = {"YNH_USER_USERNAME": username} env_dict = {"YNH_USER_USERNAME": username}
@ -396,13 +396,13 @@ def user_update(
try: try:
ldap.validate_uniqueness({"mail": mail}) ldap.validate_uniqueness({"mail": mail})
except Exception as e: except Exception as e:
raise YunohostError("user_update_failed", user=username, error=e) raise YunohostValidationError("user_update_failed", user=username, error=e)
if mail[mail.find("@") + 1 :] not in domains: if mail[mail.find("@") + 1 :] not in domains:
raise YunohostError( raise YunohostValidationError(
"mail_domain_unknown", domain=mail[mail.find("@") + 1 :] "mail_domain_unknown", domain=mail[mail.find("@") + 1 :]
) )
if mail in aliases: if mail in aliases:
raise YunohostError("mail_unavailable") raise YunohostValidationError("mail_unavailable")
del user["mail"][0] del user["mail"][0]
new_attr_dict["mail"] = [mail] + user["mail"] new_attr_dict["mail"] = [mail] + user["mail"]
@ -414,9 +414,9 @@ def user_update(
try: try:
ldap.validate_uniqueness({"mail": mail}) ldap.validate_uniqueness({"mail": mail})
except Exception as e: except Exception as e:
raise YunohostError("user_update_failed", user=username, error=e) raise YunohostValidationError("user_update_failed", user=username, error=e)
if mail[mail.find("@") + 1 :] not in domains: if mail[mail.find("@") + 1 :] not in domains:
raise YunohostError( raise YunohostValidationError(
"mail_domain_unknown", domain=mail[mail.find("@") + 1 :] "mail_domain_unknown", domain=mail[mail.find("@") + 1 :]
) )
user["mail"].append(mail) user["mail"].append(mail)
@ -429,7 +429,7 @@ def user_update(
if len(user["mail"]) > 1 and mail in user["mail"][1:]: if len(user["mail"]) > 1 and mail in user["mail"][1:]:
user["mail"].remove(mail) user["mail"].remove(mail)
else: else:
raise YunohostError("mail_alias_remove_failed", mail=mail) raise YunohostValidationError("mail_alias_remove_failed", mail=mail)
new_attr_dict["mail"] = user["mail"] new_attr_dict["mail"] = user["mail"]
if "mail" in new_attr_dict: if "mail" in new_attr_dict:
@ -451,7 +451,7 @@ def user_update(
if len(user["maildrop"]) > 1 and mail in user["maildrop"][1:]: if len(user["maildrop"]) > 1 and mail in user["maildrop"][1:]:
user["maildrop"].remove(mail) user["maildrop"].remove(mail)
else: else:
raise YunohostError("mail_forward_remove_failed", mail=mail) raise YunohostValidationError("mail_forward_remove_failed", mail=mail)
new_attr_dict["maildrop"] = user["maildrop"] new_attr_dict["maildrop"] = user["maildrop"]
if "maildrop" in new_attr_dict: if "maildrop" in new_attr_dict:
@ -500,7 +500,7 @@ def user_info(username):
if result: if result:
user = result[0] user = result[0]
else: else:
raise YunohostError("user_unknown", user=username) raise YunohostValidationError("user_unknown", user=username)
result_dict = { result_dict = {
"username": user["uid"][0], "username": user["uid"][0],
@ -638,7 +638,7 @@ def user_group_create(
{"cn": groupname}, base_dn="ou=groups,dc=yunohost,dc=org" {"cn": groupname}, base_dn="ou=groups,dc=yunohost,dc=org"
) )
if conflict: if conflict:
raise YunohostError("group_already_exist", group=groupname) raise YunohostValidationError("group_already_exist", group=groupname)
# Validate uniqueness of groupname in system group # Validate uniqueness of groupname in system group
all_existing_groupnames = {x.gr_name for x in grp.getgrall()} all_existing_groupnames = {x.gr_name for x in grp.getgrall()}
@ -651,7 +651,7 @@ def user_group_create(
"sed --in-place '/^%s:/d' /etc/group" % groupname, shell=True "sed --in-place '/^%s:/d' /etc/group" % groupname, shell=True
) )
else: else:
raise YunohostError("group_already_exist_on_system", group=groupname) raise YunohostValidationError("group_already_exist_on_system", group=groupname)
if not gid: if not gid:
# Get random GID # Get random GID
@ -705,7 +705,7 @@ def user_group_delete(operation_logger, groupname, force=False, sync_perm=True):
existing_groups = list(user_group_list()["groups"].keys()) existing_groups = list(user_group_list()["groups"].keys())
if groupname not in existing_groups: if groupname not in existing_groups:
raise YunohostError("group_unknown", group=groupname) raise YunohostValidationError("group_unknown", group=groupname)
# Refuse to delete primary groups of a user (e.g. group 'sam' related to user 'sam') # Refuse to delete primary groups of a user (e.g. group 'sam' related to user 'sam')
# without the force option... # without the force option...
@ -714,7 +714,7 @@ def user_group_delete(operation_logger, groupname, force=False, sync_perm=True):
existing_users = list(user_list()["users"].keys()) existing_users = list(user_list()["users"].keys())
undeletable_groups = existing_users + ["all_users", "visitors"] undeletable_groups = existing_users + ["all_users", "visitors"]
if groupname in undeletable_groups and not force: if groupname in undeletable_groups and not force:
raise YunohostError("group_cannot_be_deleted", group=groupname) raise YunohostValidationError("group_cannot_be_deleted", group=groupname)
operation_logger.start() operation_logger.start()
ldap = _get_ldap_interface() ldap = _get_ldap_interface()
@ -756,11 +756,11 @@ def user_group_update(
# We also can't edit "all_users" without the force option because that's a special group... # We also can't edit "all_users" without the force option because that's a special group...
if not force: if not force:
if groupname == "all_users": if groupname == "all_users":
raise YunohostError("group_cannot_edit_all_users") raise YunohostValidationError("group_cannot_edit_all_users")
elif groupname == "visitors": elif groupname == "visitors":
raise YunohostError("group_cannot_edit_visitors") raise YunohostValidationError("group_cannot_edit_visitors")
elif groupname in existing_users: elif groupname in existing_users:
raise YunohostError("group_cannot_edit_primary_group", group=groupname) raise YunohostValidationError("group_cannot_edit_primary_group", group=groupname)
# We extract the uid for each member of the group to keep a simple flat list of members # We extract the uid for each member of the group to keep a simple flat list of members
current_group = user_group_info(groupname)["members"] current_group = user_group_info(groupname)["members"]
@ -771,7 +771,7 @@ def user_group_update(
for user in users_to_add: for user in users_to_add:
if user not in existing_users: if user not in existing_users:
raise YunohostError("user_unknown", user=user) raise YunohostValidationError("user_unknown", user=user)
if user in current_group: if user in current_group:
logger.warning( logger.warning(
@ -843,7 +843,7 @@ def user_group_info(groupname):
) )
if not result: if not result:
raise YunohostError("group_unknown", group=groupname) raise YunohostValidationError("group_unknown", group=groupname)
infos = result[0] infos = result[0]

View file

@ -49,3 +49,7 @@ class YunohostError(MoulinetteError):
return super(YunohostError, self).content() return super(YunohostError, self).content()
else: else:
return {"error": self.strerror, "log_ref": self.log_ref} return {"error": self.strerror, "log_ref": self.log_ref}
class YunohostValidationError(YunohostError):
pass

View file

@ -90,11 +90,11 @@ class PasswordValidator(object):
# on top (at least not the moulinette ones) # on top (at least not the moulinette ones)
# because the moulinette needs to be correctly initialized # because the moulinette needs to be correctly initialized
# as well as modules available in python's path. # as well as modules available in python's path.
from yunohost.utils.error import YunohostError from yunohost.utils.error import YunohostValidationError
status, msg = self.validation_summary(password) status, msg = self.validation_summary(password)
if status == "error": if status == "error":
raise YunohostError(msg) raise YunohostValidationError(msg)
def validation_summary(self, password): def validation_summary(self, password):
""" """

View file

@ -25,9 +25,11 @@ def find_expected_string_keys():
# Try to find : # Try to find :
# m18n.n( "foo" # m18n.n( "foo"
# YunohostError("foo" # YunohostError("foo"
# YunohostValidationError("foo"
# # i18n: foo # # i18n: foo
p1 = re.compile(r"m18n\.n\(\n*\s*[\"\'](\w+)[\"\']") p1 = re.compile(r"m18n\.n\(\n*\s*[\"\'](\w+)[\"\']")
p2 = re.compile(r"YunohostError\(\n*\s*[\'\"](\w+)[\'\"]") p2 = re.compile(r"YunohostError\(\n*\s*[\'\"](\w+)[\'\"]")
p2 = re.compile(r"YunohostValidationError\(\n*\s*[\'\"](\w+)[\'\"]")
p3 = re.compile(r"# i18n: [\'\"]?(\w+)[\'\"]?") p3 = re.compile(r"# i18n: [\'\"]?(\w+)[\'\"]?")
python_files = glob.glob("src/yunohost/*.py") python_files = glob.glob("src/yunohost/*.py")